From 9aa6c87b72eb1c280b9ea3d0d95d44082e0a9e14 Mon Sep 17 00:00:00 2001 From: Joseph Milazzo Date: Sun, 26 Sep 2021 10:33:35 -0700 Subject: [PATCH 01/11] v0.4.6 Release (#599) * v0.4.5 Release (#539) * Bump versions by dotnet-bump-version. * Versioning Fix & Improvement (#553) * Fix UpdaterService versioning (#544) * Add "Available" to newer, non-installed updates * Add if...else logic to Available/Installed badge * Change substring to account for bigger versions (#544) * Cache BuildInfo.version into local variable (#544) * Cache BuildInfo.Version.ToString() into local variable (#544) Co-authored-by: Yovarni Yearwood * Bump versions by dotnet-bump-version. * Incognito Reader (#560) * Hooked in incognito mode into the manga reader * Bump versions by dotnet-bump-version. * Reading Lists & More (#564) * Added continous reading to the book reader. Clicking on the max pages to right of progress bar will now go to last page. * Forgot a file for continous book reading * Fixed up some code regarding transitioning between chapters. Arrows now show to represent a chapter transition. * Laid the foundation for reading lists * All foundation is laid out. Actions are wired in the UI. Backend repository is setup. Redid the migration to have ReadingList track modification so we can order them for the user. * Updated add modal to have basic skeleton * Hooked up ability to fetch reading lists from backend * Made a huge performance improvement to GetChapterIdsForSeriesAsync() by reducing a JOIN and an iteration loop. Improvement went from 2 seconds -> 200 ms. * Implemented the ability to add all chapters in a series to a reading list. * Fixed issue with adding new items to reading list not being in a logical order. Lots of work on getting all the information around the reading list view. Added some foreign keys back to chapter so delete should clean up after itself. * Added ability to open directly the series * Reading List Items now have progress attached * Hooked up list deletion and added a case where if doesn't exist on load, then redirect to library. * Lots of changes. Introduced a dashboard component for the main app. This will sit on libraries route for now and will have 3 tabs to show different sections. Moved libraries reel down to bottom as people are more likely to access recently added or in progress than explore their whole library. Note: Bundles are messed up, they need to be reoptimized and routes need to be updated. * Added pagination to the reading lists api and implemented a page to show all lists * Cleaned up old code from all-collections component so now it only handles all collections and doesn't have the old code for an individual collection * Hooked in actions and navigation on reading lists * When the user re-arranges items, they are now persisted * Implemented remove read, but performance is pretty poor. Needs to be optimized. * Lots of API fixes for adding items to a series, returning items, etc. Committing before fixing incorrect fetches of items for a readingListId. * Rewrote the joins for GetReadingListItemDtosByIdAsync() to not return extra records. * Remove bug marker now that it is fixed * Refactor update-by-series to move more of the code to a re-usable function for update-by-volume/chapter APIs * Implemented the ability to add via series, volume or chapter. * Added OPDS support for reading lists. This included adding VolumeId to the ReadingListDto. * Fixed a bug with deleting items * After we create a library inform user that a scan has started * Added some extra help information for users on directory picker, since linux users were getting confused. * Setup for the reading functionality * Fixed an issue where opening the edit series modal and pressing save without doing anything would empty collection tags. Would happen often when editing cover images. * Fixed get-next-chapter for reading list. Refactored all methods to use the new GetUserIdByUsernameAsync(), which is much faster and uses less memory. * Hooked in prev chapter for continuous reading with reading list * Hooked up the read code for manga reader and book reader to have list id passed * Manga reader now functions completely with reading lists * Implemented reading list and incognito mode into book reader * Refactored some common reading code into reader service * Added support for "Series - - Vol. 03 Ch. 023.5 - Volume 3 Extras.cbz" format that can occur with FMD2. * Implemented continuous reading with a reading list between different readers. This incurs a 3x performance hit on the book info api. * style changes. Don't emit an event if position of draggable item hasn't changed * Styling and added the edit reading list flow. * Cleaned up some extra spaces when actionables isn't shown. Lots of cleanup for promoted lists. * Refactored some filter code to a common service * Added an RBS check in getting Items for a given user. * Code smells * More smells * Bump versions by dotnet-bump-version. * Cleanup bookmarks and Reading List Items (#567) * Removed directives, ensured we delete bookmarks and reading list items when chapters are deleted. * Added parsing support for "Kimi no Koto ga Daidaidaidaidaisuki na 100-nin no Kanojo Chapter 11-10" * Bump versions by dotnet-bump-version. * Performance Improvements (#568) * Refactored the performance of GetChapter/BookInfo API to have a 10x speed improvement and to use common code, rather than duplicating code. Removed an api param that is no longer needed. * Book reader now has dedicated buttons to jump to next/prev chapter as well as through page buttons * Bump versions by dotnet-bump-version. * Fixed an issue from perf tuning where I forgot to send Pages to frontend, breaking reader. (#569) * Bump versions by dotnet-bump-version. * Fixed scaling issue (#573) * Bump versions by dotnet-bump-version. * Continuous Reading for Webtoons & I Just Couldn't Stop Coding (#574) * Fixed an issue from perf tuning where I forgot to send Pages to frontend, breaking reader. * Built out continuous reading for webtoon reader. Still has some issues with triggering. * Refactored GetUserByUsernameAsync to have a new flavor and allow the caller to pass in bitwise flags for what to include. This has a get by username or id variant. Code is much cleaner and snappier as we avoid many extra joins when not needed. * Cleanup old code from UserRepository.cs * Refactored OPDS to use faster API lookups for User * Refactored more code to be cleaner and faster. * Refactored GetNext/Prev ChapterIds to ReaderService. * Refactored Repository methods to their correct entity repos. * Refactored DTOs and overall cleanup of the code. * Added ability to press 'b' to bookmark a page * On hitting last page, save progress forcing last page to be read. Adjusted logic for the top and bottom spacers for triggering next/prev chapter load * When at top or moving between chapters, scrolling down then up will now trigger page load. Show a toastr to inform the user of a change in chapter (it can be really fast to switch) * Cleaned up scroll code * Fixed an issue where loading a chapter with last page bookmarked, we'd load lastpage - 1 * Fixed last page of webtoon reader not being resumed on loading said chapter due to a difference in how max page is handled between infinite scroller and manga reader. * Removed some comments * Book reader shouldn't look at left/right tap to paginate elems for position bookmarking. Missed a few areas for saving while in incognito mode * Added a benchmark to test out a sort code * Updated the read status on reading list to use same style as other places * Refactored GetNextChapterId to bring the average response time from 1.2 seconds to 400ms. * Added a filter to add to list when there are more than 5 reading lists * Added download reading list (will be removed, just saving for later). Fixes around styling on reading lists * Removed ability to download reading lists * Tweaked the logic for infinite scroller to be much smoother loading next/prev chapter. Added a bug marker for a concurrency bug. * Updated the top spacer so that when you hit the top, you stay at the page height and can now just scroll up. * Got the logic for scrolling up. Now just need the CSS then cont infinite scroller will be working * More polishing on infinite scroller * Removed IsSpecial on volumeDto, which is not used anywhere. * Cont Reading inf scroller edition is done. * Code smells and fixed package.json explore script * Bump versions by dotnet-bump-version. * Bump versions by dotnet-bump-version. * Bugfix/scanner issue (#576) * Refactored the scanner to hopefully fix a hard to reproduce KeyNotFoundException from GetInfosByName. * Added parsing support for "A Compendium of Ghosts - 031 - The Third Story_ Part 12 (Digital) (Cobalt001)" * Bump versions by dotnet-bump-version. * Bugs, Enhancements, and Performance (#580) * Added parser case for "The Duke of Death and His Black Maid - Ch. 177 - The Ball (3).cbz" * Removed a file that is created and modified every test run. * Fixed a bad parser case for "Batman Beyond 02 (of 6) (1999)" which was consuming too many characters * Removed a lot of "Volume" parsing for Comics that don't make sense. This is prep work for the upcoming Comic Rework release. * Reworked a lot of parsing cases for comics based on naming conventions observed from releases found online. * Added a way for external scripts to use a user api key to authenticate * Fixed an issue if the manga only had one page, the bottom menu would be missing page and chapter controls. * Fixed a bug where on small phones, nav bar could overflow due to scroll to top * Tweaked a lot of regex for manga parsing to handle some cases where poorly named files, like "Vol. 03 Ch. 21" would end up parsing as Series "Vol. 03". * Even more handling of parser cases. Manga parser should be as it was but more robust to handle bad naming. * Fixed: Don't force metadata refresh on Scan Series, only on refresh metadata * Implemented the ability to automatically refresh after a series scan based on when server finishes. Remove a duplicate API call from series detail. * Removed another API call for series metadata that isn't needed. * Refactored Message creation to a factory, hardcoded strings are centralized, and RefreshSeriesMetadata sends an event and is refactored to be async. * Fixed a bug when really poorly named files are within a folder that contains the series name, fallback couldn't occur due to it being taken as root folder. Now we detect said condition and will go one level higher, resulting in potentially more I/O, but the series will not be deleted. * Added the Read in Incognito context item for Chapter cards * Skip an additional check for series summary for series that aren't EPUB or Archive formats. * Fixed an issue where cover image generation could occur due to a bad check on LastWriteTime on the underlying file. * Added some extra comic parser tests * Added a ScanLibrary event (not hooked up in UI) * Performance improvement on metadata service. Now when we scan for cover image changes, we emit when a change occurs and only then do we update parent entities (array copy). * Removed an hr from series detail and ensure we update the cover image for series when scan series finishes. * Updated the infinite scroller to use a Flags pattern for the debug mode. Updated a few logical conditions for mobile. * Removed the concurrency check on row progress as if too many calls hit the DB, it will throw, but it doesn't matter. Fixed a bad logic code which could cause scrolling after hitting the bottom of the chapter. * Ensure prefetching uses totalPages + 1 since we pass in totalPages as - 1 from manga reader * Fixed issue where last page of webtoon wouldn't be prefetched due to a < instead of <= on prefetching code * Implemented ability to send images from archives to the UI without incurring any extra memory pressure. * Dropdown menus now have a darker background * Webtoon reader now works on mobile. * Fixed how keyboard presses for up/down/left/right work with MANGA_UD reading mode. See issue #579 * Fixed cont reader for webtoons on mobile * Fixed a small issue where top spacer would too quickly switch to prev chapter * Updated user preferences to use same slider style. Removed some css that is not used. * Added comic parser case for "Saga 001 (2012) (Digital) (Empire-Zone)" * Added accessibility toggle to reading list order and aligned sliders to all use the same style. * Removed a todo for checking on new image serving code. It works great. * Fixed a missing await * Auth guard will now check if an existing toast is present giving same message before poping the toast. * Fixed alignment on phones for reading lists * Moved sorters so they aren't resused between multiple threads. Slightly higher memory footprint. * Fixed a broken unit test * Code smells * More unit test fixing * Bump versions by dotnet-bump-version. * WebP Support (#581) * Added trackby so when series scan event comes through, cards can update too * Added chapter boundary toasts on book reader * Handle closing the reader when in a reading list * Somehow the trackby save didn't happen * Fixed an issue where after opening a chapter info modal, then trying to open another in specials tab it would fail due to a pass by reference issue with our factory. * When a series update occurs, if we loose specials tab, but we were on it, reselect volumes/chapters tab * Fixed an issue where older releases would show as available, even though they were already installed. * Converted tabs within modals to use vertical orientation (except on mobile) * Implemented webp support. Only Safari does not support this format natively. MacOS users can use an alternative browser. * Refactored ScannerService and MetadataService to be fully async * Bump versions by dotnet-bump-version. * Bugfix/manga reader (#582) * Fixed an issue where you could change paging direction then switch to Up/Down mode and paging direction would still be present * Removed some code for a feature I'm not implementing anymore * Bump versions by dotnet-bump-version. * High Res images breaking due to Canvas limits (#587) * Fixed an issue where on Safari with high resolution images, the canvas wouldn't be able to render them. Now we detect high res that might break canvas on different browsers and scale them. * Removed some code no longer needed * Bump versions by dotnet-bump-version. * Foundational Cover Image Rework (#584) * Updating wording on card item when total pages is 0, to be just "Cannot Read" since it could be a non-archive file * Refactored cover images to be stored on disk. This first commit has the extraction to disk and the metadata service to handle updating when applicable. * Refactored code to have the actual save to cover image directory done by ImageService. * Implemented the ability to override cover images. * Some cleanup on Image service * Implemented the ability to cleanup old covers nightly * Added a migration to migrate existing covers to new cover image format (files). * Refactored all CoverImages to just be the filename, leaving the Join with Cover directory to higher level code. * Ensure when getting user progress, we pick the first. * Added cleanup cover images for deleted tags. Don't pull any cover images that are blank. * After series update, clear out cover image. No change on UI, but just keeps things clear before metadata refresh hits * Refactored image formats for covers to ImageService. * Fixed an issue where after refactoring how images were stored, the cleanup service was deleting them after each scan. * Changed how ShouldUpdateCoverImage works to check if file exists or not even if cover image is locked. * Fixed unit tests * Added caching back to cover images. * Caching on series as well * Code Cleanup items * Ensure when checking if a file exists in MetadataService, that we join for cover image directory. After we scan library, do one last filter to delete any series that have 0 pages total. * Catch exceptions so we don't run cover migration if this is first time run. * After a scan, only clear out the cache directory and not do a deep clean. * Implemented the ability to backup custom locked covers only. * Fixed unit tests * Trying to figure out why GA crashes when running MetadataServiceTests.cs * Some debugging on GA tests not running * Commented out tests that were causing issues in GA. * Fixed an issue where series cover images wouldn't migrate * Fixed the updating of links to actually do all series and not just locked * Bump versions by dotnet-bump-version. * Feature/image rework cleanup (#589) * Added volume migrations. Added parser case for "Chapter 63 - The Promise Made for 520 Cenz.cbr" * Added some info statements for when full library scans occur. For image apis, return the name of the file to aid in caching. * When managing users, show the current logged in user at the top of the list. Added a message when no libraries have been setup but you are trying to add a user to a library. * Bump versions by dotnet-bump-version. * Additional Memory Pressure Enhancements (#590) * Added volume migrations. Added parser case for "Chapter 63 - The Promise Made for 520 Cenz.cbr" * Added some info statements for when full library scans occur. For image apis, return the name of the file to aid in caching. * When managing users, show the current logged in user at the top of the list. Added a message when no libraries have been setup but you are trying to add a user to a library. * Removed an extra stream operation from SharpCompress cover image work. Removed an extra ToArray() from Book Reader for extracting PDF pages. * Removed the left over comment * Added parsing case for "Batman Beyond 04 (of 6) (1999)" * Removed dead code * Bump versions by dotnet-bump-version. * Added ios detection (#591) https://stackoverflow.com/questions/9038625/detect-if-device-is-ios/9039885#9039885 *Note* navigator.platform is deprecated but still seems to work for now. * Bump versions by dotnet-bump-version. * Added entry for persistent covers folder * Bump versions by dotnet-bump-version. * Bulk Operations (#596) * Implemented the ability to perform multi-selections on cards. Basic selection code is done, CSS needed and exposing actions. * Implemented a bulk selection bar. Added logic to the card on when to force show checkboxes. * Fixed some bad parsing groups and cases for Comic Chapters. * Hooked up some bulk actions on series detail page. Not hooked up to backend yet. * Fixes #593. URI Enocde library names as sometimes they can have & in them. * Implemented the ability to mark volume/chapters as read/unread. * Hooked up mark as unread with specials as well. * Add to reading list hooked up for Series Detail * Implemented ability to add multiple series to a reading list. * Implemented bulk selection for series cards * Added comments to the new code in ReaderService.cs * Implemented proper styling on bulk operation bar and integrated for collections. * Fixed an issue with shift clicking * Cleaned up css of bulk operations bar * Code cleanup * Bump versions by dotnet-bump-version. * Feature/release cleanup (#597) * Deselect all after bulk operations complete. * Implemented a way to trigger selection code on mobile. * When selection mode is active, make the clickable area the whole image. * Series detail shouldn't use gutters for card layout as it can cause skewing on mobile * Long press on card items to trigger the selection on mobile * Code cleanup * One more * Misread the code issue * Bump versions by dotnet-bump-version. * v0.4.6 Release (#598) * Bump versions by dotnet-bump-version. * Bump versions by dotnet-bump-version. Co-authored-by: Yovarni Yearwood Co-authored-by: Yovarni Yearwood Co-authored-by: Robbie Davis Co-authored-by: Chris Plaatjes --- .gitignore | 1 + API.Benchmark/ArchiveSerivceBenchmark.cs | 8 + API.Benchmark/ParseScannedFilesBenchmarks.cs | 31 +- API.Benchmark/Program.cs | 1 + API.Benchmark/TestBenchmark.cs | 69 ++ API.Tests/API.Tests.csproj | 4 + .../Extensions/Test Data/modified on run.txt | 3 - API.Tests/Parser/ComicParserTests.cs | 60 +- API.Tests/Parser/MangaParserTests.cs | 30 +- API.Tests/Parser/ParserTest.cs | 1 + API.Tests/Services/ArchiveServiceTests.cs | 67 +- API.Tests/Services/DirectoryServiceTests.cs | 10 + API.Tests/Services/MetadataServiceTests.cs | 53 +- API.Tests/Services/ScannerServiceTests.cs | 8 +- .../Test Data/ImageService/cover.expected.jpg | Bin 0 -> 473476 bytes API/API.csproj | 56 +- API/API.csproj.DotSettings | 2 + API/Comparators/ChapterSortComparer.cs | 9 + API/Comparators/NaturalSortComparer.cs | 17 +- API/Controllers/AccountController.cs | 1 + API/Controllers/BookController.cs | 32 +- API/Controllers/CollectionController.cs | 2 +- API/Controllers/DownloadController.cs | 9 +- API/Controllers/ImageController.cs | 44 +- API/Controllers/LibraryController.cs | 6 +- API/Controllers/OPDSController.cs | 154 ++- API/Controllers/PluginController.cs | 45 + API/Controllers/ReaderController.cs | 395 +++---- API/Controllers/ReadingListController.cs | 503 ++++++++ API/Controllers/SeriesController.cs | 47 +- API/Controllers/SettingsController.cs | 2 +- API/Controllers/UploadController.cs | 30 +- API/Controllers/UsersController.cs | 12 +- API/DTOs/{ => Account}/LoginDto.cs | 0 API/DTOs/{ => Account}/ResetPasswordDto.cs | 4 +- API/DTOs/Downloads/DownloadBookmarkDto.cs | 1 + API/DTOs/ImageDto.cs | 15 - API/DTOs/InProgressChapterDto.cs | 24 - API/DTOs/Reader/BookInfoDto.cs | 18 + API/DTOs/{ => Reader}/BookmarkDto.cs | 2 +- API/DTOs/Reader/ChapterInfoDto.cs | 15 +- API/DTOs/Reader/IChapterInfoDto.cs | 19 + .../Reader/MarkMultipleSeriesAsReadDto.cs | 9 + API/DTOs/{ => Reader}/MarkReadDto.cs | 4 +- API/DTOs/{ => Reader}/MarkVolumeReadDto.cs | 4 +- API/DTOs/Reader/MarkVolumesReadDto.cs | 20 + .../RemoveBookmarkForSeriesDto.cs | 2 +- API/DTOs/ReadingLists/CreateReadingListDto.cs | 7 + API/DTOs/ReadingLists/ReadingListDto.cs | 13 + API/DTOs/ReadingLists/ReadingListItemDto.cs | 25 + .../UpdateReadingListByChapterDto.cs | 9 + .../UpdateReadingListByMultipleDto.cs | 12 + .../UpdateReadingListByMultipleSeriesDto.cs | 10 + .../UpdateReadingListBySeriesDto.cs | 8 + .../UpdateReadingListByVolumeDto.cs | 9 + API/DTOs/ReadingLists/UpdateReadingListDto.cs | 10 + .../ReadingLists/UpdateReadingListPosition.cs | 10 + API/DTOs/{ => Settings}/ServerSettingDTO.cs | 0 API/DTOs/VolumeDto.cs | 4 +- API/Data/BookmarkRepository.cs | 7 - API/Data/ChapterRepository.cs | 23 - API/Data/DataContext.cs | 3 + API/Data/MigrateCoverImages.cs | 180 +++ .../20210901150310_ReadingLists.Designer.cs | 1018 ++++++++++++++++ .../Migrations/20210901150310_ReadingLists.cs | 84 ++ ...01200442_ReadingListsAdditions.Designer.cs | 1022 ++++++++++++++++ .../20210901200442_ReadingListsAdditions.cs | 55 + ...eadingListsExtraRealationships.Designer.cs | 1050 +++++++++++++++++ ...2110705_ReadingListsExtraRealationships.cs | 67 ++ ...0906140845_ReadingListsChanges.Designer.cs | 1046 ++++++++++++++++ .../20210906140845_ReadingListsChanges.cs | 43 + ...0916142418_EntityImageRefactor.Designer.cs | 1042 ++++++++++++++++ .../20210916142418_EntityImageRefactor.cs | 97 ++ .../Migrations/DataContextModelSnapshot.cs | 138 ++- .../AppUserProgressRepository.cs | 33 +- API/Data/Repositories/ChapterRepository.cs | 191 +++ .../CollectionTagRepository.cs | 19 +- API/Data/{ => Repositories}/FileRepository.cs | 4 +- .../{ => Repositories}/LibraryRepository.cs | 4 +- .../Repositories/ReadingListRepository.cs | 178 +++ .../{ => Repositories}/SeriesRepository.cs | 106 +- .../{ => Repositories}/SettingsRepository.cs | 6 +- API/Data/{ => Repositories}/UserRepository.cs | 126 +- API/Data/Repositories/VolumeRepository.cs | 56 + API/Data/UnitOfWork.cs | 7 +- API/Data/VolumeRepository.cs | 116 -- API/Entities/AppUser.cs | 4 + API/Entities/AppUserProgress.cs | 13 +- API/Entities/Chapter.cs | 6 +- API/Entities/CollectionTag.cs | 6 +- API/Entities/MangaFile.cs | 6 +- API/Entities/ReadingList.cs | 29 + API/Entities/ReadingListItem.cs | 25 + API/Entities/Series.cs | 6 +- API/Entities/Volume.cs | 9 +- API/Extensions/FileInfoExtensions.cs | 1 - API/Extensions/HttpExtensions.cs | 21 +- API/Helpers/AutoMapperProfiles.cs | 5 + API/Helpers/SQLHelper.cs | 30 + API/Interfaces/ITaskScheduler.cs | 2 +- API/Interfaces/IUnitOfWork.cs | 1 + API/Interfaces/IVolumeRepository.cs | 19 - .../IAppUserProgressRepository.cs | 7 +- .../Repositories/IChapterRepository.cs | 17 +- .../ICollectionTagRepository.cs | 5 +- .../{ => Repositories}/IFileRepository.cs | 4 +- .../{ => Repositories}/ILibraryRepository.cs | 2 +- .../Repositories/IReadingListRepository.cs | 22 + .../{ => Repositories}/ISeriesRepository.cs | 15 +- .../{ => Repositories}/ISettingsRepository.cs | 6 +- .../{ => Repositories}/IUserRepository.cs | 15 +- .../Repositories/IVolumeRepository.cs | 15 + API/Interfaces/Services/IArchiveService.cs | 2 +- API/Interfaces/Services/IBackupService.cs | 3 +- API/Interfaces/Services/IBookService.cs | 2 +- API/Interfaces/Services/ICleanupService.cs | 9 +- API/Interfaces/Services/IImageService.cs | 11 +- API/Interfaces/Services/IMetadataService.cs | 15 +- API/Interfaces/Services/IReaderService.cs | 10 +- API/Interfaces/Services/IScannerService.cs | 4 +- API/Interfaces/Services/ReaderService.cs | 267 ++++- API/Parser/Parser.cs | 159 ++- API/Program.cs | 30 + API/Services/ArchiveService.cs | 50 +- API/Services/BookService.cs | 64 +- API/Services/CacheService.cs | 4 +- API/Services/DirectoryService.cs | 39 + API/Services/DownloadService.cs | 1 - API/Services/ImageService.cs | 97 +- API/Services/MetadataService.cs | 128 +- API/Services/TaskScheduler.cs | 7 +- API/Services/Tasks/BackupService.cs | 33 +- API/Services/Tasks/CleanupService.cs | 66 +- .../Tasks/Scanner/ParseScannedFiles.cs | 16 +- API/Services/Tasks/ScannerService.cs | 114 +- API/Services/Tasks/VersionUpdaterService.cs | 21 +- API/SignalR/MessageFactory.cs | 56 + API/SignalR/SignalREvents.cs | 11 + API/Startup.cs | 15 +- Kavita.Common/Kavita.Common.csproj | 2 +- UI/Web/package-lock.json | 148 +++ UI/Web/package.json | 4 +- UI/Web/src/app/_guards/admin.guard.ts | 2 +- UI/Web/src/app/_guards/auth.guard.ts | 4 +- .../app/_models/events/scan-library-event.ts | 4 + .../app/_models/events/scan-series-event.ts | 3 + UI/Web/src/app/_models/reading-list.ts | 23 + UI/Web/src/app/_models/series.ts | 1 - .../app/_services/action-factory.service.ts | 89 +- UI/Web/src/app/_services/action.service.ts | 218 +++- UI/Web/src/app/_services/library.service.ts | 2 +- .../src/app/_services/message-hub.service.ts | 31 +- UI/Web/src/app/_services/reader.service.ts | 71 +- .../src/app/_services/reading-list.service.ts | 110 ++ .../directory-picker.component.html | 5 +- .../library-access-modal.component.html | 3 + .../library-editor-modal.component.ts | 5 +- UI/Web/src/app/admin/admin.module.ts | 4 +- .../admin/changelog/changelog.component.html | 7 +- .../admin/dashboard/dashboard.component.html | 2 +- .../manage-users/manage-users.component.html | 2 +- .../manage-users/manage-users.component.ts | 13 +- UI/Web/src/app/app-routing.module.ts | 8 +- UI/Web/src/app/app.module.ts | 14 +- .../src/app/book-reader/_models/book-info.ts | 9 + .../book-reader/book-reader.component.html | 34 +- .../book-reader/book-reader.component.ts | 262 +++- UI/Web/src/app/book-reader/book.service.ts | 3 +- .../card-details-modal.component.html | 4 +- .../edit-collection-tags.component.html | 2 +- .../edit-series-modal.component.html | 13 +- .../edit-series-modal.component.ts | 8 +- .../bulk-operations.component.html | 8 + .../bulk-operations.component.scss | 16 + .../bulk-operations.component.ts | 39 + .../src/app/cards/bulk-selection.service.ts | 147 +++ .../card-detail-layout.component.html | 4 +- .../card-actionables.component.ts | 3 - .../cards/card-item/card-item.component.html | 14 +- .../cards/card-item/card-item.component.scss | 28 + .../cards/card-item/card-item.component.ts | 93 +- UI/Web/src/app/cards/cards.module.ts | 7 +- .../series-card/series-card.component.html | 5 +- .../series-card/series-card.component.ts | 17 +- .../all-collections.component.html | 19 +- .../all-collections.component.ts | 69 +- .../collection-detail.component.html | 13 +- .../collection-detail.component.ts | 49 +- .../src/app/collections/collections.module.ts | 3 + .../app/dashboard/dashboard.component.html | 21 + .../app/dashboard/dashboard.component.scss | 0 .../src/app/dashboard/dashboard.component.ts | 37 + .../library-detail.component.html | 3 +- .../library-detail.component.ts | 46 +- UI/Web/src/app/library/library.component.html | 51 +- UI/Web/src/app/library/library.component.ts | 50 +- .../app/manga-reader/_models/chapter-info.ts | 5 + .../app/manga-reader/_models/reader-enums.ts | 8 +- .../infinite-scroller.component.html | 40 +- .../infinite-scroller.component.scss | 24 + .../infinite-scroller.component.ts | 127 +- .../manga-reader/manga-reader.component.html | 23 +- .../manga-reader/manga-reader.component.scss | 14 - .../manga-reader/manga-reader.component.ts | 154 ++- .../manga-reader.router.module.ts | 7 +- .../app/nav-header/nav-header.component.html | 2 +- .../app/nav-header/nav-header.component.ts | 2 +- UI/Web/src/app/{admin => pipe}/filter.pipe.ts | 0 UI/Web/src/app/pipe/pipe.module.ts | 18 + .../add-to-list-modal.component.html | 46 + .../add-to-list-modal.component.scss | 7 + .../add-to-list-modal.component.ts | 137 +++ .../edit-reading-list-modal.component.html | 31 + .../edit-reading-list-modal.component.scss | 0 .../edit-reading-list-modal.component.ts | 52 + .../dragable-ordered-list.component.html | 23 + .../dragable-ordered-list.component.scss | 47 + .../dragable-ordered-list.component.ts | 63 + .../reading-list-detail.component.html | 73 ++ .../reading-list-detail.component.scss | 4 + .../reading-list-detail.component.ts | 159 +++ .../app/reading-list/reading-list.module.ts | 40 + .../reading-list.router.module.ts | 23 + .../reading-lists.component.html | 11 + .../reading-lists.component.scss | 0 .../reading-lists/reading-lists.component.ts | 96 ++ .../series-detail.component.html | 35 +- .../series-detail.component.scss | 2 +- .../series-detail/series-detail.component.ts | 127 +- .../app/shared/_services/download.service.ts | 4 +- .../app/shared/_services/utility.service.ts | 19 +- UI/Web/src/app/shared/shared.module.ts | 2 - .../user-preferences.component.html | 34 +- .../user-preferences.component.scss | 54 +- UI/Web/src/assets/themes/dark.scss | 7 + UI/Web/src/styles.scss | 48 - UI/Web/tsconfig.json | 1 + entrypoint.sh | 14 + 238 files changed, 12119 insertions(+), 1528 deletions(-) create mode 100644 API.Benchmark/ArchiveSerivceBenchmark.cs create mode 100644 API.Benchmark/TestBenchmark.cs delete mode 100644 API.Tests/Extensions/Test Data/modified on run.txt create mode 100644 API.Tests/Services/Test Data/ImageService/cover.expected.jpg create mode 100644 API/API.csproj.DotSettings create mode 100644 API/Controllers/PluginController.cs create mode 100644 API/Controllers/ReadingListController.cs rename API/DTOs/{ => Account}/LoginDto.cs (100%) rename API/DTOs/{ => Account}/ResetPasswordDto.cs (90%) delete mode 100644 API/DTOs/ImageDto.cs delete mode 100644 API/DTOs/InProgressChapterDto.cs create mode 100644 API/DTOs/Reader/BookInfoDto.cs rename API/DTOs/{ => Reader}/BookmarkDto.cs (89%) create mode 100644 API/DTOs/Reader/IChapterInfoDto.cs create mode 100644 API/DTOs/Reader/MarkMultipleSeriesAsReadDto.cs rename API/DTOs/{ => Reader}/MarkReadDto.cs (73%) rename API/DTOs/{ => Reader}/MarkVolumeReadDto.cs (81%) create mode 100644 API/DTOs/Reader/MarkVolumesReadDto.cs rename API/DTOs/{ => Reader}/RemoveBookmarkForSeriesDto.cs (78%) create mode 100644 API/DTOs/ReadingLists/CreateReadingListDto.cs create mode 100644 API/DTOs/ReadingLists/ReadingListDto.cs create mode 100644 API/DTOs/ReadingLists/ReadingListItemDto.cs create mode 100644 API/DTOs/ReadingLists/UpdateReadingListByChapterDto.cs create mode 100644 API/DTOs/ReadingLists/UpdateReadingListByMultipleDto.cs create mode 100644 API/DTOs/ReadingLists/UpdateReadingListByMultipleSeriesDto.cs create mode 100644 API/DTOs/ReadingLists/UpdateReadingListBySeriesDto.cs create mode 100644 API/DTOs/ReadingLists/UpdateReadingListByVolumeDto.cs create mode 100644 API/DTOs/ReadingLists/UpdateReadingListDto.cs create mode 100644 API/DTOs/ReadingLists/UpdateReadingListPosition.cs rename API/DTOs/{ => Settings}/ServerSettingDTO.cs (100%) delete mode 100644 API/Data/BookmarkRepository.cs delete mode 100644 API/Data/ChapterRepository.cs create mode 100644 API/Data/MigrateCoverImages.cs create mode 100644 API/Data/Migrations/20210901150310_ReadingLists.Designer.cs create mode 100644 API/Data/Migrations/20210901150310_ReadingLists.cs create mode 100644 API/Data/Migrations/20210901200442_ReadingListsAdditions.Designer.cs create mode 100644 API/Data/Migrations/20210901200442_ReadingListsAdditions.cs create mode 100644 API/Data/Migrations/20210902110705_ReadingListsExtraRealationships.Designer.cs create mode 100644 API/Data/Migrations/20210902110705_ReadingListsExtraRealationships.cs create mode 100644 API/Data/Migrations/20210906140845_ReadingListsChanges.Designer.cs create mode 100644 API/Data/Migrations/20210906140845_ReadingListsChanges.cs create mode 100644 API/Data/Migrations/20210916142418_EntityImageRefactor.Designer.cs create mode 100644 API/Data/Migrations/20210916142418_EntityImageRefactor.cs rename API/Data/{ => Repositories}/AppUserProgressRepository.cs (65%) create mode 100644 API/Data/Repositories/ChapterRepository.cs rename API/Data/{ => Repositories}/CollectionTagRepository.cs (87%) rename API/Data/{ => Repositories}/FileRepository.cs (92%) rename API/Data/{ => Repositories}/LibraryRepository.cs (98%) create mode 100644 API/Data/Repositories/ReadingListRepository.cs rename API/Data/{ => Repositories}/SeriesRepository.cs (86%) rename API/Data/{ => Repositories}/SettingsRepository.cs (94%) rename API/Data/{ => Repositories}/UserRepository.cs (56%) create mode 100644 API/Data/Repositories/VolumeRepository.cs delete mode 100644 API/Data/VolumeRepository.cs create mode 100644 API/Entities/ReadingList.cs create mode 100644 API/Entities/ReadingListItem.cs create mode 100644 API/Helpers/SQLHelper.cs delete mode 100644 API/Interfaces/IVolumeRepository.cs rename API/Interfaces/{ => Repositories}/IAppUserProgressRepository.cs (55%) rename API/Interfaces/{ => Repositories}/ICollectionTagRepository.cs (81%) rename API/Interfaces/{ => Repositories}/IFileRepository.cs (81%) rename API/Interfaces/{ => Repositories}/ILibraryRepository.cs (96%) create mode 100644 API/Interfaces/Repositories/IReadingListRepository.cs rename API/Interfaces/{ => Repositories}/ISeriesRepository.cs (85%) rename API/Interfaces/{ => Repositories}/ISettingsRepository.cs (90%) rename API/Interfaces/{ => Repositories}/IUserRepository.cs (58%) create mode 100644 API/Interfaces/Repositories/IVolumeRepository.cs create mode 100644 API/SignalR/MessageFactory.cs create mode 100644 API/SignalR/SignalREvents.cs create mode 100644 UI/Web/src/app/_models/events/scan-library-event.ts create mode 100644 UI/Web/src/app/_models/events/scan-series-event.ts create mode 100644 UI/Web/src/app/_models/reading-list.ts create mode 100644 UI/Web/src/app/_services/reading-list.service.ts create mode 100644 UI/Web/src/app/book-reader/_models/book-info.ts create mode 100644 UI/Web/src/app/cards/bulk-operations/bulk-operations.component.html create mode 100644 UI/Web/src/app/cards/bulk-operations/bulk-operations.component.scss create mode 100644 UI/Web/src/app/cards/bulk-operations/bulk-operations.component.ts create mode 100644 UI/Web/src/app/cards/bulk-selection.service.ts create mode 100644 UI/Web/src/app/dashboard/dashboard.component.html create mode 100644 UI/Web/src/app/dashboard/dashboard.component.scss create mode 100644 UI/Web/src/app/dashboard/dashboard.component.ts rename UI/Web/src/app/{admin => pipe}/filter.pipe.ts (100%) create mode 100644 UI/Web/src/app/pipe/pipe.module.ts create mode 100644 UI/Web/src/app/reading-list/_modals/add-to-list-modal/add-to-list-modal.component.html create mode 100644 UI/Web/src/app/reading-list/_modals/add-to-list-modal/add-to-list-modal.component.scss create mode 100644 UI/Web/src/app/reading-list/_modals/add-to-list-modal/add-to-list-modal.component.ts create mode 100644 UI/Web/src/app/reading-list/_modals/edit-reading-list-modal/edit-reading-list-modal.component.html create mode 100644 UI/Web/src/app/reading-list/_modals/edit-reading-list-modal/edit-reading-list-modal.component.scss create mode 100644 UI/Web/src/app/reading-list/_modals/edit-reading-list-modal/edit-reading-list-modal.component.ts create mode 100644 UI/Web/src/app/reading-list/dragable-ordered-list/dragable-ordered-list.component.html create mode 100644 UI/Web/src/app/reading-list/dragable-ordered-list/dragable-ordered-list.component.scss create mode 100644 UI/Web/src/app/reading-list/dragable-ordered-list/dragable-ordered-list.component.ts create mode 100644 UI/Web/src/app/reading-list/reading-list-detail/reading-list-detail.component.html create mode 100644 UI/Web/src/app/reading-list/reading-list-detail/reading-list-detail.component.scss create mode 100644 UI/Web/src/app/reading-list/reading-list-detail/reading-list-detail.component.ts create mode 100644 UI/Web/src/app/reading-list/reading-list.module.ts create mode 100644 UI/Web/src/app/reading-list/reading-list.router.module.ts create mode 100644 UI/Web/src/app/reading-list/reading-lists/reading-lists.component.html create mode 100644 UI/Web/src/app/reading-list/reading-lists/reading-lists.component.scss create mode 100644 UI/Web/src/app/reading-list/reading-lists/reading-lists.component.ts diff --git a/.gitignore b/.gitignore index 9f28eec22..928e1ee53 100644 --- a/.gitignore +++ b/.gitignore @@ -500,3 +500,4 @@ _output/ API/stats/ UI/Web/dist/ /API.Tests/Extensions/Test Data/modified on run.txt +/API/covers/ diff --git a/API.Benchmark/ArchiveSerivceBenchmark.cs b/API.Benchmark/ArchiveSerivceBenchmark.cs new file mode 100644 index 000000000..c60a4271f --- /dev/null +++ b/API.Benchmark/ArchiveSerivceBenchmark.cs @@ -0,0 +1,8 @@ +namespace API.Benchmark +{ + public class ArchiveSerivceBenchmark + { + // Benchmark to test default GetNumberOfPages from archive + // vs a new method where I try to open the archive and return said stream + } +} diff --git a/API.Benchmark/ParseScannedFilesBenchmarks.cs b/API.Benchmark/ParseScannedFilesBenchmarks.cs index bc0c810ce..d3fd19a4e 100644 --- a/API.Benchmark/ParseScannedFilesBenchmarks.cs +++ b/API.Benchmark/ParseScannedFilesBenchmarks.cs @@ -1,7 +1,9 @@ using System; using System.IO; +using API.Data; using API.Entities.Enums; using API.Interfaces.Services; +using API.Parser; using API.Services; using API.Services.Tasks.Scanner; using BenchmarkDotNet.Attributes; @@ -14,7 +16,7 @@ namespace API.Benchmark [MemoryDiagnoser] [Orderer(SummaryOrderPolicy.FastestToSlowest)] [RankColumn] - [SimpleJob(launchCount: 1, warmupCount: 3, targetCount: 5, invocationCount: 100, id: "Test"), ShortRunJob] + //[SimpleJob(launchCount: 1, warmupCount: 3, targetCount: 5, invocationCount: 100, id: "Test"), ShortRunJob] public class ParseScannedFilesBenchmarks { private readonly ParseScannedFiles _parseScannedFiles; @@ -27,14 +29,37 @@ namespace API.Benchmark _parseScannedFiles = new ParseScannedFiles(bookService, _logger); } + // [Benchmark] + // public void Test() + // { + // var libraryPath = Path.Join(Directory.GetCurrentDirectory(), + // "../../../Services/Test Data/ScannerService/Manga"); + // var parsedSeries = _parseScannedFiles.ScanLibrariesForSeries(LibraryType.Manga, new string[] {libraryPath}, + // out var totalFiles, out var scanElapsedTime); + // } + + /// + /// Generate a list of Series and another list with + /// [Benchmark] - public void Test() + public void MergeName() { var libraryPath = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ScannerService/Manga"); + var p1 = new ParserInfo() + { + Chapters = "0", + Edition = "", + Format = MangaFormat.Archive, + FullFilePath = Path.Join(libraryPath, "A Town Where You Live", "A_Town_Where_You_Live_v01.zip"), + IsSpecial = false, + Series = "A Town Where You Live", + Title = "A Town Where You Live", + Volumes = "1" + }; var parsedSeries = _parseScannedFiles.ScanLibrariesForSeries(LibraryType.Manga, new string[] {libraryPath}, out var totalFiles, out var scanElapsedTime); + _parseScannedFiles.MergeName(p1); } - } } diff --git a/API.Benchmark/Program.cs b/API.Benchmark/Program.cs index 05c296f8b..b308a07b7 100644 --- a/API.Benchmark/Program.cs +++ b/API.Benchmark/Program.cs @@ -13,6 +13,7 @@ namespace API.Benchmark static void Main(string[] args) { BenchmarkRunner.Run(); + //BenchmarkRunner.Run(); } } } diff --git a/API.Benchmark/TestBenchmark.cs b/API.Benchmark/TestBenchmark.cs new file mode 100644 index 000000000..a2aabdd8a --- /dev/null +++ b/API.Benchmark/TestBenchmark.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using API.Comparators; +using API.DTOs; +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Order; + +namespace API.Benchmark +{ + /// + /// This is used as a scratchpad for testing + /// + [MemoryDiagnoser] + [Orderer(SummaryOrderPolicy.FastestToSlowest)] + [RankColumn] + public class TestBenchmark + { + private readonly NaturalSortComparer _naturalSortComparer = new (); + + + private static IEnumerable GenerateVolumes(int max) + { + var random = new Random(); + var maxIterations = random.Next(max) + 1; + var list = new List(); + for (var i = 0; i < maxIterations; i++) + { + list.Add(new VolumeDto() + { + Number = random.Next(10) > 5 ? 1 : 0, + Chapters = GenerateChapters() + }); + } + + return list; + } + + private static List GenerateChapters() + { + var list = new List(); + for (var i = 1; i < 40; i++) + { + list.Add(new ChapterDto() + { + Range = i + string.Empty + }); + } + + return list; + } + + private void SortSpecialChapters(IEnumerable volumes) + { + foreach (var v in volumes.Where(vDto => vDto.Number == 0)) + { + v.Chapters = v.Chapters.OrderBy(x => x.Range, _naturalSortComparer).ToList(); + } + } + + [Benchmark] + public void TestSortSpecialChapters() + { + var volumes = GenerateVolumes(10); + SortSpecialChapters(volumes); + } + + } +} diff --git a/API.Tests/API.Tests.csproj b/API.Tests/API.Tests.csproj index 73a19fd5d..e01bab216 100644 --- a/API.Tests/API.Tests.csproj +++ b/API.Tests/API.Tests.csproj @@ -30,4 +30,8 @@ + + + + diff --git a/API.Tests/Extensions/Test Data/modified on run.txt b/API.Tests/Extensions/Test Data/modified on run.txt deleted file mode 100644 index d6a609edc..000000000 --- a/API.Tests/Extensions/Test Data/modified on run.txt +++ /dev/null @@ -1,3 +0,0 @@ -This file should be modified by the unit test08/20/2021 10:26:03 -08/20/2021 10:26:29 -08/22/2021 12:39:58 diff --git a/API.Tests/Parser/ComicParserTests.cs b/API.Tests/Parser/ComicParserTests.cs index a18ea21c9..8d25661ff 100644 --- a/API.Tests/Parser/ComicParserTests.cs +++ b/API.Tests/Parser/ComicParserTests.cs @@ -23,49 +23,63 @@ namespace API.Tests.Parser [InlineData("Amazing Man Comics chapter 25", "Amazing Man Comics")] [InlineData("Amazing Man Comics issue #25", "Amazing Man Comics")] [InlineData("Teen Titans v1 038 (1972) (c2c).cbr", "Teen Titans")] + [InlineData("Batman Beyond 02 (of 6) (1999)", "Batman Beyond")] + [InlineData("Batman Beyond - Return of the Joker (2001)", "Batman Beyond - Return of the Joker")] + [InlineData("Invincible 033.5 - Marvel Team-Up 14 (2006) (digital) (Minutemen-Slayer)", "Invincible")] + [InlineData("Batman Wayne Family Adventures - Ep. 001 - Moving In", "Batman Wayne Family Adventures")] + [InlineData("Saga 001 (2012) (Digital) (Empire-Zone).cbr", "Saga")] + [InlineData("Batman Beyond 04 (of 6) (1999)", "Batman Beyond")] public void ParseComicSeriesTest(string filename, string expected) { Assert.Equal(expected, API.Parser.Parser.ParseComicSeries(filename)); } - [Theory] - [InlineData("01 Spider-Man & Wolverine 01.cbr", "1")] - [InlineData("04 - Asterix the Gladiator (1964) (Digital-Empire) (WebP by Doc MaKS)", "4")] - [InlineData("The First Asterix Frieze (WebP by Doc MaKS)", "0")] - [InlineData("Batman & Catwoman - Trail of the Gun 01", "1")] - [InlineData("Batman & Daredevil - King of New York", "0")] - [InlineData("Batman & Grendel (1996) 01 - Devil's Bones", "1")] - [InlineData("Batman & Robin the Teen Wonder #0", "0")] - [InlineData("Batman & Wildcat (1 of 3)", "0")] - [InlineData("Batman And Superman World's Finest #01", "1")] - [InlineData("Babe 01", "1")] - [InlineData("Scott Pilgrim 01 - Scott Pilgrim's Precious Little Life (2004)", "1")] - [InlineData("Teen Titans v1 001 (1966-02) (digital) (OkC.O.M.P.U.T.O.-Novus)", "1")] - [InlineData("Scott Pilgrim 02 - Scott Pilgrim vs. The World (2005)", "2")] - [InlineData("Superman v1 024 (09-10 1943)", "1")] - [InlineData("Amazing Man Comics chapter 25", "0")] - public void ParseComicVolumeTest(string filename, string expected) - { - Assert.Equal(expected, API.Parser.Parser.ParseComicVolume(filename)); - } - [Theory] [InlineData("01 Spider-Man & Wolverine 01.cbr", "0")] [InlineData("04 - Asterix the Gladiator (1964) (Digital-Empire) (WebP by Doc MaKS)", "0")] [InlineData("The First Asterix Frieze (WebP by Doc MaKS)", "0")] [InlineData("Batman & Catwoman - Trail of the Gun 01", "0")] [InlineData("Batman & Daredevil - King of New York", "0")] + [InlineData("Batman & Grendel (1996) 01 - Devil's Bones", "0")] + [InlineData("Batman & Robin the Teen Wonder #0", "0")] + [InlineData("Batman & Wildcat (1 of 3)", "0")] + [InlineData("Batman And Superman World's Finest #01", "0")] + [InlineData("Babe 01", "0")] + [InlineData("Scott Pilgrim 01 - Scott Pilgrim's Precious Little Life (2004)", "0")] + [InlineData("Teen Titans v1 001 (1966-02) (digital) (OkC.O.M.P.U.T.O.-Novus)", "1")] + [InlineData("Scott Pilgrim 02 - Scott Pilgrim vs. The World (2005)", "0")] + [InlineData("Superman v1 024 (09-10 1943)", "1")] + [InlineData("Amazing Man Comics chapter 25", "0")] + [InlineData("Invincible 033.5 - Marvel Team-Up 14 (2006) (digital) (Minutemen-Slayer)", "0")] + [InlineData("Cyberpunk 2077 - Trauma Team 04.cbz", "0")] + public void ParseComicVolumeTest(string filename, string expected) + { + Assert.Equal(expected, API.Parser.Parser.ParseComicVolume(filename)); + } + + [Theory] + [InlineData("01 Spider-Man & Wolverine 01.cbr", "1")] + [InlineData("04 - Asterix the Gladiator (1964) (Digital-Empire) (WebP by Doc MaKS)", "0")] + [InlineData("The First Asterix Frieze (WebP by Doc MaKS)", "0")] + [InlineData("Batman & Catwoman - Trail of the Gun 01", "1")] + [InlineData("Batman & Daredevil - King of New York", "0")] [InlineData("Batman & Grendel (1996) 01 - Devil's Bones", "1")] [InlineData("Batman & Robin the Teen Wonder #0", "0")] [InlineData("Batman & Wildcat (1 of 3)", "1")] [InlineData("Batman & Wildcat (2 of 3)", "2")] - [InlineData("Batman And Superman World's Finest #01", "0")] - [InlineData("Babe 01", "0")] + [InlineData("Batman And Superman World's Finest #01", "1")] + [InlineData("Babe 01", "1")] [InlineData("Scott Pilgrim 01 - Scott Pilgrim's Precious Little Life (2004)", "1")] [InlineData("Teen Titans v1 001 (1966-02) (digital) (OkC.O.M.P.U.T.O.-Novus)", "1")] [InlineData("Superman v1 024 (09-10 1943)", "24")] [InlineData("Invincible 070.5 - Invincible Returns 1 (2010) (digital) (Minutemen-InnerDemons).cbr", "70.5")] [InlineData("Amazing Man Comics chapter 25", "25")] + [InlineData("Invincible 033.5 - Marvel Team-Up 14 (2006) (digital) (Minutemen-Slayer)", "33.5")] + [InlineData("Batman Wayne Family Adventures - Ep. 014 - Moving In", "14")] + [InlineData("Saga 001 (2012) (Digital) (Empire-Zone)", "1")] + [InlineData("Batman Beyond 04 (of 6) (1999)", "4")] + [InlineData("Invincible 052 (c2c) (2008) (Minutemen-TheCouple)", "52")] + [InlineData("Y - The Last Man #001", "1")] public void ParseComicChapterTest(string filename, string expected) { Assert.Equal(expected, API.Parser.Parser.ParseComicChapter(filename)); diff --git a/API.Tests/Parser/MangaParserTests.cs b/API.Tests/Parser/MangaParserTests.cs index d27f22dd9..917d1f467 100644 --- a/API.Tests/Parser/MangaParserTests.cs +++ b/API.Tests/Parser/MangaParserTests.cs @@ -66,6 +66,7 @@ namespace API.Tests.Parser [InlineData("Noblesse - Episode 406 (52 Pages).7z", "0")] [InlineData("X-Men v1 #201 (September 2007).cbz", "1")] [InlineData("Hentai Ouji to Warawanai Neko. - Vol. 06 Ch. 034.5", "6")] + [InlineData("The 100 Girlfriends Who Really, Really, Really, Really, Really Love You - Vol. 03 Ch. 023.5 - Volume 3 Extras.cbz", "3")] public void ParseVolumeTest(string filename, string expected) { Assert.Equal(expected, API.Parser.Parser.ParseVolume(filename)); @@ -128,7 +129,6 @@ namespace API.Tests.Parser [InlineData("Fullmetal Alchemist chapters 101-108.cbz", "Fullmetal Alchemist")] [InlineData("To Love Ru v09 Uncensored (Ch.071-079).cbz", "To Love Ru")] [InlineData("[dmntsf.net] One Piece - Digital Colored Comics Vol. 20 Ch. 177 - 30 Million vs 81 Million.cbz", "One Piece - Digital Colored Comics")] - //[InlineData("Corpse Party -The Anthology- Sachikos game of love Hysteric Birthday 2U Extra Chapter", "Corpse Party -The Anthology- Sachikos game of love Hysteric Birthday 2U")] [InlineData("Corpse Party -The Anthology- Sachikos game of love Hysteric Birthday 2U Chapter 01", "Corpse Party -The Anthology- Sachikos game of love Hysteric Birthday 2U")] [InlineData("Vol03_ch15-22.rar", "")] [InlineData("Love Hina - Special.cbz", "")] // This has to be a fallback case @@ -157,6 +157,15 @@ namespace API.Tests.Parser [InlineData("Killing Bites - Vol 11 Chapter 050 Save Me, Nunupi!.cbz", "Killing Bites")] [InlineData("Mad Chimera World - Volume 005 - Chapter 026.cbz", "Mad Chimera World")] [InlineData("Hentai Ouji to Warawanai Neko. - Vol. 06 Ch. 034.5", "Hentai Ouji to Warawanai Neko.")] + [InlineData("The 100 Girlfriends Who Really, Really, Really, Really, Really Love You - Vol. 03 Ch. 023.5 - Volume 3 Extras.cbz", "The 100 Girlfriends Who Really, Really, Really, Really, Really Love You")] + [InlineData("Kimi no Koto ga Daidaidaidaidaisuki na 100-nin no Kanojo Chapter 1-10", "Kimi no Koto ga Daidaidaidaidaisuki na 100-nin no Kanojo")] + [InlineData("The Duke of Death and His Black Maid - Ch. 177 - The Ball (3).cbz", "The Duke of Death and His Black Maid")] + [InlineData("A Compendium of Ghosts - 031 - The Third Story_ Part 12 (Digital) (Cobalt001)", "A Compendium of Ghosts")] + [InlineData("The Duke of Death and His Black Maid - Vol. 04 Ch. 054.5 - V4 Omake", "The Duke of Death and His Black Maid")] + [InlineData("Vol. 04 Ch. 054.5", "")] + [InlineData("Great_Teacher_Onizuka_v16[TheSpectrum]", "Great Teacher Onizuka")] + [InlineData("[Renzokusei]_Kimi_wa_Midara_na_Boku_no_Joou_Ch5_Final_Chapter", "Kimi wa Midara na Boku no Joou")] + [InlineData("Battle Royale, v01 (2000) [TokyoPop] [Manga-Sketchbook]", "Battle Royale")] public void ParseSeriesTest(string filename, string expected) { Assert.Equal(expected, API.Parser.Parser.ParseSeries(filename)); @@ -226,6 +235,9 @@ namespace API.Tests.Parser [InlineData("Ijousha No Ai - Vol.01 Chapter 029 8 Years Ago", "29")] [InlineData("Kedouin Makoto - Corpse Party Musume, Chapter 09.cbz", "9")] [InlineData("Hentai Ouji to Warawanai Neko. - Vol. 06 Ch. 034.5", "34.5")] + [InlineData("Kimi no Koto ga Daidaidaidaidaisuki na 100-nin no Kanojo Chapter 1-10", "1-10")] + [InlineData("Deku_&_Bakugo_-_Rising_v1_c1.1.cbz", "1.1")] + [InlineData("Chapter 63 - The Promise Made for 520 Cenz.cbr", "63")] public void ParseChaptersTest(string filename, string expected) { Assert.Equal(expected, API.Parser.Parser.ParseChapter(filename)); @@ -408,6 +420,22 @@ namespace API.Tests.Parser FullFilePath = filepath, IsSpecial = false }); + filepath = @"E:\Manga\Kono Subarashii Sekai ni Bakuen wo!\Vol. 00 Ch. 000.cbz"; + expected.Add(filepath, new ParserInfo + { + Series = "Kono Subarashii Sekai ni Bakuen wo!", Volumes = "0", Edition = "", + Chapters = "0", Filename = "Vol. 00 Ch. 000.cbz", Format = MangaFormat.Archive, + FullFilePath = filepath, IsSpecial = false + }); + + filepath = @"E:\Manga\Toukyou Akazukin\Vol. 01 Ch. 001.cbz"; + expected.Add(filepath, new ParserInfo + { + Series = "Toukyou Akazukin", Volumes = "1", Edition = "", + Chapters = "1", Filename = "Vol. 01 Ch. 001.cbz", Format = MangaFormat.Archive, + FullFilePath = filepath, IsSpecial = false + }); + // If an image is cover exclusively, ignore it filepath = @"E:\Manga\Seraph of the End\cover.png"; expected.Add(filepath, null); diff --git a/API.Tests/Parser/ParserTest.cs b/API.Tests/Parser/ParserTest.cs index 5857a50c9..6830cde0d 100644 --- a/API.Tests/Parser/ParserTest.cs +++ b/API.Tests/Parser/ParserTest.cs @@ -156,6 +156,7 @@ namespace API.Tests.Parser [InlineData("test.png", true)] [InlineData(".test.jpg", false)] [InlineData("!test.jpg", false)] + [InlineData("test.webp", true)] public void IsImageTest(string filename, bool expected) { Assert.Equal(expected, IsImage(filename)); diff --git a/API.Tests/Services/ArchiveServiceTests.cs b/API.Tests/Services/ArchiveServiceTests.cs index 50d2d0673..80f09a144 100644 --- a/API.Tests/Services/ArchiveServiceTests.cs +++ b/API.Tests/Services/ArchiveServiceTests.cs @@ -2,6 +2,7 @@ using System.IO; using System.IO.Compression; using API.Archive; +using API.Interfaces.Services; using API.Services; using Microsoft.Extensions.Logging; using NSubstitute; @@ -17,11 +18,12 @@ namespace API.Tests.Services private readonly ArchiveService _archiveService; private readonly ILogger _logger = Substitute.For>(); private readonly ILogger _directoryServiceLogger = Substitute.For>(); + private readonly IDirectoryService _directoryService = new DirectoryService(Substitute.For>()); public ArchiveServiceTests(ITestOutputHelper testOutputHelper) { _testOutputHelper = testOutputHelper; - _archiveService = new ArchiveService(_logger, new DirectoryService(_directoryServiceLogger)); + _archiveService = new ArchiveService(_logger, _directoryService); } [Theory] @@ -50,7 +52,7 @@ namespace API.Tests.Services var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ArchiveService/Archives"); Assert.Equal(expected, _archiveService.IsValidArchive(Path.Join(testDirectory, archivePath))); } - + [Theory] [InlineData("non existent file.zip", 0)] [InlineData("winrar.rar", 0)] @@ -69,7 +71,7 @@ namespace API.Tests.Services Assert.Equal(expected, _archiveService.GetNumberOfPagesFromArchive(Path.Join(testDirectory, archivePath))); _testOutputHelper.WriteLine($"Processed Original in {sw.ElapsedMilliseconds} ms"); } - + [Theory] @@ -84,12 +86,12 @@ namespace API.Tests.Services { var sw = Stopwatch.StartNew(); var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ArchiveService/Archives"); - + Assert.Equal(expected, _archiveService.CanOpen(Path.Join(testDirectory, archivePath))); _testOutputHelper.WriteLine($"Processed Original in {sw.ElapsedMilliseconds} ms"); } - - + + [Theory] [InlineData("non existent file.zip", 0)] [InlineData("winrar.rar", 0)] @@ -100,18 +102,18 @@ namespace API.Tests.Services [InlineData("file in folder_alt.zip", 1)] public void CanExtractArchive(string archivePath, int expectedFileCount) { - + var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ArchiveService/Archives"); var extractDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ArchiveService/Archives/Extraction"); DirectoryService.ClearAndDeleteDirectory(extractDirectory); - + Stopwatch sw = Stopwatch.StartNew(); _archiveService.ExtractArchive(Path.Join(testDirectory, archivePath), extractDirectory); var di1 = new DirectoryInfo(extractDirectory); Assert.Equal(expectedFileCount, di1.Exists ? di1.GetFiles().Length : 0); _testOutputHelper.WriteLine($"Processed in {sw.ElapsedMilliseconds} ms"); - + DirectoryService.ClearAndDeleteDirectory(extractDirectory); } @@ -142,14 +144,14 @@ namespace API.Tests.Services var foundFile = _archiveService.FirstFileEntry(files); Assert.Equal(expected, string.IsNullOrEmpty(foundFile) ? "" : foundFile); } - - - - [Theory] + + + + // TODO: This is broken on GA due to DirectoryService.CoverImageDirectory + //[Theory] [InlineData("v10.cbz", "v10.expected.jpg")] [InlineData("v10 - with folder.cbz", "v10 - with folder.expected.jpg")] [InlineData("v10 - nested folder.cbz", "v10 - nested folder.expected.jpg")] - //[InlineData("png.zip", "png.PNG")] [InlineData("macos_native.zip", "macos_native.jpg")] [InlineData("v10 - duplicate covers.cbz", "v10 - duplicate covers.expected.jpg")] [InlineData("sorting.zip", "sorting.expected.jpg")] @@ -159,17 +161,29 @@ namespace API.Tests.Services var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ArchiveService/CoverImages"); var expectedBytes = File.ReadAllBytes(Path.Join(testDirectory, expectedOutputFile)); archiveService.Configure().CanOpen(Path.Join(testDirectory, inputFile)).Returns(ArchiveLibrary.Default); - Stopwatch sw = Stopwatch.StartNew(); - Assert.Equal(expectedBytes, archiveService.GetCoverImage(Path.Join(testDirectory, inputFile))); + var sw = Stopwatch.StartNew(); + + var outputDir = Path.Join(testDirectory, "output"); + DirectoryService.ClearAndDeleteDirectory(outputDir); + DirectoryService.ExistOrCreate(outputDir); + + + var coverImagePath = archiveService.GetCoverImage(Path.Join(testDirectory, inputFile), + Path.GetFileNameWithoutExtension(inputFile) + "_output"); + var actual = File.ReadAllBytes(coverImagePath); + + + Assert.Equal(expectedBytes, actual); _testOutputHelper.WriteLine($"Processed in {sw.ElapsedMilliseconds} ms"); + DirectoryService.ClearAndDeleteDirectory(outputDir); } - - - [Theory] + + + // TODO: This is broken on GA due to DirectoryService.CoverImageDirectory + //[Theory] [InlineData("v10.cbz", "v10.expected.jpg")] [InlineData("v10 - with folder.cbz", "v10 - with folder.expected.jpg")] [InlineData("v10 - nested folder.cbz", "v10 - nested folder.expected.jpg")] - //[InlineData("png.zip", "png.PNG")] [InlineData("macos_native.zip", "macos_native.jpg")] [InlineData("v10 - duplicate covers.cbz", "v10 - duplicate covers.expected.jpg")] [InlineData("sorting.zip", "sorting.expected.jpg")] @@ -178,20 +192,21 @@ namespace API.Tests.Services var archiveService = Substitute.For(_logger, new DirectoryService(_directoryServiceLogger)); var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ArchiveService/CoverImages"); var expectedBytes = File.ReadAllBytes(Path.Join(testDirectory, expectedOutputFile)); - + archiveService.Configure().CanOpen(Path.Join(testDirectory, inputFile)).Returns(ArchiveLibrary.SharpCompress); Stopwatch sw = Stopwatch.StartNew(); - Assert.Equal(expectedBytes, archiveService.GetCoverImage(Path.Join(testDirectory, inputFile))); + Assert.Equal(expectedBytes, File.ReadAllBytes(archiveService.GetCoverImage(Path.Join(testDirectory, inputFile), Path.GetFileNameWithoutExtension(inputFile) + "_output"))); _testOutputHelper.WriteLine($"Processed in {sw.ElapsedMilliseconds} ms"); } - [Theory] + // TODO: This is broken on GA due to DirectoryService.CoverImageDirectory + //[Theory] [InlineData("Archives/macos_native.zip")] [InlineData("Formats/One File with DB_Supported.zip")] public void CanParseCoverImage(string inputFile) { var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ArchiveService/"); - Assert.NotEmpty(_archiveService.GetCoverImage(Path.Join(testDirectory, inputFile))); + Assert.NotEmpty(File.ReadAllBytes(_archiveService.GetCoverImage(Path.Join(testDirectory, inputFile), Path.GetFileNameWithoutExtension(inputFile) + "_output"))); } [Fact] @@ -200,9 +215,9 @@ namespace API.Tests.Services var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ArchiveService/ComicInfos"); var archive = Path.Join(testDirectory, "file in folder.zip"); var summaryInfo = "By all counts, Ryouta Sakamoto is a loser when he's not holed up in his room, bombing things into oblivion in his favorite online action RPG. But his very own uneventful life is blown to pieces when he's abducted and taken to an uninhabited island, where he soon learns the hard way that he's being pitted against others just like him in a explosives-riddled death match! How could this be happening? Who's putting them up to this? And why!? The name, not to mention the objective, of this very real survival game is eerily familiar to Ryouta, who has mastered its virtual counterpart-BTOOOM! Can Ryouta still come out on top when he's playing for his life!?"; - + Assert.Equal(summaryInfo, _archiveService.GetSummaryInfo(archive)); } } -} \ No newline at end of file +} diff --git a/API.Tests/Services/DirectoryServiceTests.cs b/API.Tests/Services/DirectoryServiceTests.cs index 4dcb77dec..db756ebab 100644 --- a/API.Tests/Services/DirectoryServiceTests.cs +++ b/API.Tests/Services/DirectoryServiceTests.cs @@ -89,6 +89,15 @@ namespace API.Tests.Services } + [Theory] + [InlineData(new string[] {"C:/Manga/"}, new string[] {"C:/Manga/Love Hina/Vol. 01.cbz"}, "C:/Manga/Love Hina")] + public void FindHighestDirectoriesFromFilesTest(string[] rootDirectories, string[] folders, string expectedDirectory) + { + var actual = DirectoryService.FindHighestDirectoriesFromFiles(rootDirectories, folders); + var expected = new Dictionary {{expectedDirectory, ""}}; + Assert.Equal(expected, actual); + } + [Theory] [InlineData("C:/Manga/", "C:/Manga/Love Hina/Specials/Omake/", "Omake,Specials,Love Hina")] [InlineData("C:/Manga/", "C:/Manga/Love Hina/Specials/Omake", "Omake,Specials,Love Hina")] @@ -102,6 +111,7 @@ namespace API.Tests.Services [InlineData(@"C:/", @"C://Btooom!/Vol.1 Chapter 2/1.cbz", "Vol.1 Chapter 2,Btooom!")] [InlineData(@"C:\\", @"C://Btooom!/Vol.1 Chapter 2/1.cbz", "Vol.1 Chapter 2,Btooom!")] [InlineData(@"C://mount/gdrive/Library/Test Library/Comics", @"C://mount/gdrive/Library/Test Library/Comics/Dragon Age/Test", "Test,Dragon Age")] + [InlineData(@"M:\", @"M:\Toukyou Akazukin\Vol. 01 Ch. 005.cbz", @"Toukyou Akazukin")] public void GetFoldersTillRoot_Test(string rootPath, string fullpath, string expectedArray) { var expected = expectedArray.Split(","); diff --git a/API.Tests/Services/MetadataServiceTests.cs b/API.Tests/Services/MetadataServiceTests.cs index 796201538..b921f74b7 100644 --- a/API.Tests/Services/MetadataServiceTests.cs +++ b/API.Tests/Services/MetadataServiceTests.cs @@ -4,6 +4,8 @@ using API.Entities; using API.Interfaces; using API.Interfaces.Services; using API.Services; +using API.SignalR; +using Microsoft.AspNetCore.SignalR; using Microsoft.Extensions.Logging; using NSubstitute; using Xunit; @@ -13,16 +15,19 @@ namespace API.Tests.Services public class MetadataServiceTests { private readonly string _testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ArchiveService/Archives"); - private readonly MetadataService _metadataService; - private readonly IUnitOfWork _unitOfWork = Substitute.For(); - private readonly IImageService _imageService = Substitute.For(); - private readonly IBookService _bookService = Substitute.For(); - private readonly IArchiveService _archiveService = Substitute.For(); - private readonly ILogger _logger = Substitute.For>(); + private const string TestCoverImageFile = "thumbnail.jpg"; + private readonly string _testCoverImageDirectory = Path.Join(Directory.GetCurrentDirectory(), @"../../../Services/Test Data/ArchiveService/CoverImages"); + //private readonly MetadataService _metadataService; + // private readonly IUnitOfWork _unitOfWork = Substitute.For(); + // private readonly IImageService _imageService = Substitute.For(); + // private readonly IBookService _bookService = Substitute.For(); + // private readonly IArchiveService _archiveService = Substitute.For(); + // private readonly ILogger _logger = Substitute.For>(); + // private readonly IHubContext _messageHub = Substitute.For>(); public MetadataServiceTests() { - _metadataService = new MetadataService(_unitOfWork, _logger, _archiveService, _bookService, _imageService); + //_metadataService = new MetadataService(_unitOfWork, _logger, _archiveService, _bookService, _imageService, _messageHub); } [Fact] @@ -44,7 +49,7 @@ namespace API.Tests.Services } [Fact] - public void ShouldUpdateCoverImage_OnSecondRun_FileModified() + public void ShouldUpdateCoverImage_OnFirstRun_FileModified() { // Represents first run Assert.True(MetadataService.ShouldUpdateCoverImage(null, new MangaFile() @@ -55,10 +60,10 @@ namespace API.Tests.Services } [Fact] - public void ShouldUpdateCoverImage_OnSecondRun_CoverImageLocked() + public void ShouldUpdateCoverImage_OnFirstRun_CoverImageLocked() { // Represents first run - Assert.False(MetadataService.ShouldUpdateCoverImage(null, new MangaFile() + Assert.True(MetadataService.ShouldUpdateCoverImage(null, new MangaFile() { FilePath = Path.Join(_testDirectory, "file in folder.zip"), LastModified = new FileInfo(Path.Join(_testDirectory, "file in folder.zip")).LastWriteTime @@ -99,14 +104,36 @@ namespace API.Tests.Services } [Fact] - public void ShouldUpdateCoverImage_OnSecondRun_CoverImageSet() + public void ShouldNotUpdateCoverImage_OnSecondRun_CoverImageSet() { // Represents first run - Assert.False(MetadataService.ShouldUpdateCoverImage(new byte[] {1}, new MangaFile() + Assert.False(MetadataService.ShouldUpdateCoverImage(TestCoverImageFile, new MangaFile() { FilePath = Path.Join(_testDirectory, "file in folder.zip"), LastModified = new FileInfo(Path.Join(_testDirectory, "file in folder.zip")).LastWriteTime - }, false, false)); + }, false, false, _testCoverImageDirectory)); + } + + [Fact] + public void ShouldNotUpdateCoverImage_OnSecondRun_HasCoverImage_NoForceUpdate_NoLock() + { + + Assert.False(MetadataService.ShouldUpdateCoverImage(TestCoverImageFile, new MangaFile() + { + FilePath = Path.Join(_testDirectory, "file in folder.zip"), + LastModified = DateTime.Now + }, false, false, _testCoverImageDirectory)); + } + + [Fact] + public void ShouldUpdateCoverImage_OnSecondRun_HasCoverImage_NoForceUpdate_HasLock_CoverImageDoesntExist() + { + + Assert.True(MetadataService.ShouldUpdateCoverImage(@"doesn't_exist.jpg", new MangaFile() + { + FilePath = Path.Join(_testDirectory, "file in folder.zip"), + LastModified = DateTime.Now + }, false, true, _testCoverImageDirectory)); } } } diff --git a/API.Tests/Services/ScannerServiceTests.cs b/API.Tests/Services/ScannerServiceTests.cs index 2c7a999f0..93b254c8e 100644 --- a/API.Tests/Services/ScannerServiceTests.cs +++ b/API.Tests/Services/ScannerServiceTests.cs @@ -14,8 +14,10 @@ using API.Parser; using API.Services; using API.Services.Tasks; using API.Services.Tasks.Scanner; +using API.SignalR; using API.Tests.Helpers; using AutoMapper; +using Microsoft.AspNetCore.SignalR; using Microsoft.Data.Sqlite; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; @@ -34,6 +36,7 @@ namespace API.Tests.Services private readonly IImageService _imageService = Substitute.For(); private readonly ILogger _metadataLogger = Substitute.For>(); private readonly ICacheService _cacheService = Substitute.For(); + private readonly IHubContext _messageHub = Substitute.For>(); private readonly DbConnection _connection; private readonly DataContext _context; @@ -52,8 +55,8 @@ namespace API.Tests.Services IUnitOfWork unitOfWork = new UnitOfWork(_context, Substitute.For(), null); - IMetadataService metadataService = Substitute.For(unitOfWork, _metadataLogger, _archiveService, _bookService, _imageService); - _scannerService = new ScannerService(unitOfWork, _logger, _archiveService, metadataService, _bookService, _cacheService); + IMetadataService metadataService = Substitute.For(unitOfWork, _metadataLogger, _archiveService, _bookService, _imageService, _messageHub); + _scannerService = new ScannerService(unitOfWork, _logger, _archiveService, metadataService, _bookService, _cacheService, _messageHub); } private async Task SeedDb() @@ -111,6 +114,7 @@ namespace API.Tests.Services Assert.Empty(_scannerService.FindSeriesNotOnDisk(existingSeries, infos)); } + // TODO: Figure out how to do this with ParseScannedFiles // [Theory] // [InlineData(new [] {"Darker than Black"}, "Darker than Black", "Darker than Black")] diff --git a/API.Tests/Services/Test Data/ImageService/cover.expected.jpg b/API.Tests/Services/Test Data/ImageService/cover.expected.jpg new file mode 100644 index 0000000000000000000000000000000000000000..73da78f507cfdcc45ee6db3742e06276e7bd3c9e GIT binary patch literal 473476 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%0DA*Gv3BS2H4l5B2|z&~!Oyza2QGanpt zdSC~Em?U`>2IbH~RxhMyJ9ocKr0&Uj5kfqLUt(M_rK@PbJH@8aB%Wo9KWAuT$Gt(0 zDjmrIVLIYLg)tXStLCIao{uR+To!Q##F>ltq_iU;#N7y^+xNP_JfW)22uE3^sr$)y z*gZzNPWgW}%m<;Iog)c74R(56j{qTi2ca8T8ermxIq_!EgWj{`fo)CF_7m{GWV&t2 z4!7HTne-vv+@v!L#mFg%JN6jagechg*C_UbmxCL1vTaBQgz>%W{f1`8;Gs9Uyk~32 z*ktm6(A6FH=_B9<-|yejlSe=w-F7<7WcPcA>ua8<6xE!jp(9l8FZ`%@`}&$@?b-pd zgqfAKJ)g^bNIW_nM)IByg&~C-LjBH-mn8|YSkQeNQ{sjgN)8dm;y>s_Y%|`rqn498 zw{FI|)v(V!>UelnGVb=p+Q=WIGY0M1hcJ19ShR?pNfeirqgY(>|YHA zX(b;N9EsC=P)1?w6#WiS&|*jOKh59shNMjkE_rVTYA)})X4jii*Y!2WO{*s~Ac$z= zFda3C4B(G|2cK~v^gU^!`=0lD3Rq*g3k`W2VADqdSq!@PM|U<<+s)q(qH>K)oAzwz zk`I3N2uQlE&tDHbOG>+2geDsYM*ZUh6-{}zAy;;gQxxV#F^SI4>T(0$sxRK4ynP*;aUGjbN`JECLF_ZZ4zu8%+99GXwy~9N zv-OE>DkOx#?}|OiBXSR1k0V_&G?F_#^5Lf1tt^wWtLAxf7fD9m9YdU>0ACBDk16IB zB^N+f1j;m+cWBCvCVb9no6$17Z5?pflwd3)5H;4#jqT>`UvwW8x!!bO-9WqpP8ww< z-Y-VLc2My_WSN*_;4DFp0z`K{VZRj4Y5>DZU9Xq12P167rYU(c5dqf9wP{+Gyx<+$ zM{G%rmkfo7k`C2m;&mMuX47wH+|ly1BYB=i!GwCL9s#z#^8cdtRZF39BnN@<ortznf3LXLTw;DR*p_fla553wDn|J;~iaU4PvS`x{;kpC|J7Vr5ZQS`#8CUj? z0Je$MM&4n?yn+4VPM8MS@-e&pi1(jqo{NJzN?Dq`0e5J_j>Uun3(H$_je+u zmi}#NakyoiyRjRD$y^9u^g;0I76R{XG0NWNzeKsq4bh=fbcIO6*0!u40k3R%dA%sX zVO|!(ds`-;Pku$I3aB__-!(W4#*E|v3vbfQ54=4%?c-Ejo49R7r~iZjQD4{97;_h{ zu=tSR{_?9nMq`t}UZIgY>AndN0g`_R@_UPAbM=CW;V$QNuLr$`#Wr8wYhgSBR{BIA z0n33TZH0R_K4B#G8`YH}?{nk!+dFymOjl}5=O(ptuyGontr0$dX;(fxc+@p|>hSTD zIj4{Ii5ufbrjfO`hXbVU$SFIYq1{U%^-eYu1yYZgRFU#k0R~9pcwmLvBLFY{^HOG^HC!GN&K*g` zbP1vEK(u#v4JCr^y5D=SM>X3eub*3}$4kb$bJL!_7ao>*@20-#_%v)7K&aW_ z2ZZzfmSpCP?VkH+kV-7-r0~hUnm4Koq!8Y@nJc+SRdWyS46P-V+mOD5s-JzH>Us!4-CVPB4Qn*^r1(#Bz&3()CkA~^f@ z>R3njFdUm3$(}R0XSlSTj*6lXPY!uI4hKihBFS|j>`}<&l=mQcW;<{gNh0zzDsI~( zL~(p0NR9}ZXvxaPj*L{kAla2OffS6uAp-X9?(MWY!^fqzHieS?U7tEjwPdgEw~2c$ zAre{RXSMP|`|ggY&qpMIpAlLz?MQq(NKTWtnB};UQTr6+AiiKpeWs6Tb`N?j7bJR- z82I&oJN{a4Q05nWqHb3I1uDxE9D$bnt(PujI1+mRzHG-<*M}9m4xU7pTA)}W>x*0` zStaTx$v3BHDI&SGFxt@MhgHb9Nz&befpgbzAHK!4_jX3#wfvC$?+0OaN6Gzv!t%*7 z4o4GSeM$BN7SH%Sp-_`i?LEyyw!ovP$<_5M8IOniU32$7Y{=NqBj9hJC=7D3#k%y1 zdwIxiW&QId6_Z$_f^0MZq-! z+I+1CG&`tyu!PUTvMOL>5cEukL_&Tsrw_=zhaZ}&9*{o*hGiU?uh)yHdMG!bhc)rK z_4s7Ioca#AvLmeqIOY;cmy;VUK!R{DZY#}&saWk8~n@7OQM?lK6lsvkWDf9#V zzRj2rY^3hl7Q>bJ)IDUkKIcZrsk?862L;81JOU_S9eVM%1R6~6mp|K=dxz@2l_!fGcIMG2 zNK;{t-ycLKvAEOolOsw8KH8JNVW8>$Sh^?pHT+$ULlu4avGKMJ!FbZWX}w_Pj$3;Aw%2_mp?rwtHVkPjlC} zxY#0WW5I`$RCHZN`x+kO4bWt@(PKyHGj`_<$slR##POt?#t`{}ZHfu_YKHB%MiXX? z#xBslnS4q&-_az~NQlq`O~nKI%vd=pASF#ip3E_X4btBPeRy**+QA;U9J=EU_8_~% z8!AJdypt!tBUG~#M}Z*8y_b&wn53&)dEZ_iYa27d{2-HvW+%ix$}u%WYFa4=Q8Y@$ z6Wm6FXfs?Uycm6W=T)e;BZ*(ZFysX_c9ULPrNMu();epnog};@)UYln?D9YhgFfz=y-jGM$Hd|>BX&s?Dtcwnli;#YGlvKt37j+ z;iozK*(+dI3cm!uOcGX1s>n`Ayj6_{*n{qNv0|O#C`9sOaPr^|Qum1bhvwa1<;6ouBB)ItEqr8T`T2hGc1mo|a|*Z@TH;G^h~eyxpCmMyJ^W4O zf_H0m;i3Vlu13@M>yj$8Zd%o*{y=x+f*K=Ue(k+Kaz)&~d2l`ZY&SR@Zb>mt^Q|K! zz-DJ1m{2|JVBfQyZUK(ZXx$D{;U&l8UQMS?(lqEWpwLle0{_sJD;rA~cNULzJZjUFd*A%W^wCIJz@B+_g7e)a@j(dN|QI5{+}YrWvWJ5doK2GwhqCFqDpha6G)} z>0<8A~ytrW+TeLANuGU?* zF(8gd)1gQ>P4&_%bQlBjVa$*xz;0BeO%~j_4nN3s{bH=XVCzFOoN!=i+V*!t@H#Q^ z;JV3S+WjU^^345d0-C!4ziZ|WX4Uz?2mBdd`JH{NaQ~R3OjrHwovQA;!hhp`RN{Yr zhw}Zp!$InwD~##as9e`Vv~nzaVRWpUU)PJJOLutXH1}7#eEgD7AYaZppO=0-X>f2B zhu6|eTi)CJ^7kr09=b)i+h*)&FY@8zv>-BA?1o^Bb2qppnu`NO`+E#i+oiS1_fXmp z$eqKI9q(G^&rGZZVPodI?#TBuF3^wu2i+JlJ5=}m1JM! z=eL#oFm0>i@-#3oQmd#ojD>GEn)H@VdU;IRHf9QL*zBaFDb@a)YivVVx^8zHH-JBm zOD5_vwN*>2e=PG}sd4F^?EQDWoFX{*uvR3rs+bH-FpstiUa!3}oQ{YF4jUAdS8Eig z+icXHnlrir-L}@h`naWwy%W4_-BO$Mo|;Z8Mw+p2?Yhm+gm5niEYCng|Ft4u2i{c@ zpvFe)y;zxCzhO;zE;8g7OD)*h%Nk zH!clUO&-gMXGW5c4eM39Ge>|={H{RDQ(@s-uNSUfX?g}O91QlFaUZA1~0{YTbA4F1%>x(n3qE`y+5St$XQ*hL% z>KM0kF!>OKO;i4=0XHd8M2sE5Td&470+V3mMGTaEOmJ*>5*DE)Gbl4n84uz}nFjJK zbaDk8fLJgt{K*j8B}PnS)LFDe91|^DoQUmB@j_X^@P@Dvwz`Hd zA~@iD^b-3@;v+^}6DlU72of6@FF_t8UqCKR65fuK&ab1pjjLNX0#&yyuDe`nkr`1+ z%WS7A>{14dcEdKofr>*R^z5M#Z&{$Pd|{N363Y$j>gMDbRq;MD6` zY4#XLnW__peP~g?=eA_;^JuXLrM-3(pK!lSD12Nn*V4hQv2Nt{T6m)V=(0vXuzs{q z)hCU=$i?nHE9tf%(trC_OdP%KBndJh`7uT$i;}>RXkc0|uPKiL#XxfjfvxoAZ)1*1 zF}%9G=W%Bqy}sL0CV~ZyvphUYx)nkjHDZ7Ik`Nb3^1DmfQ}RiNEK|VL*h$&cA+OtC zGn}YU`JFq;Ug^Ce0xTbC&@FP!xna5f?na=ort$K&USQ!t3K|;-p&j5Iejp@f7VWQ;OqHhZ|Z))Rv5`wJq@Pl0cj5_c_Ihs9MRh zM^c;Im6s6*tDlg^2J!imuFNd_FWJ}H9QF~jqtg>3cKgE{iW&T_=ayW}T&yn?-*5?0 z-kCNTYOo3OHg@zfN#j9cK*6!WH`yG56hRCe$PMT!qE{LYrB`565ly`8ay_|2`nc|H ziTLil7u?#+FH!0^455xEvm&?ogpEAwS;bdv07IdP|pqtifx3Z=Kys zw?3qQlg#X@=lohQl;TF7weTZPc-E@P`fbI`M_RE$Rc8=n-!Pj;L)?h+o^4m2e7xz; z6`9ZeHRW-)(CGIIhRjB2E8?Qt9vWDXZ?uvGtH`;a=(iQh{7T}q;aJ$P%X+_MjMH?d z3LjbDgg2%Hu>rxxfebNOI370)0+Z%DNWCC>?Oj^D(JBOuCQSP*LI)wqKqC5$rJd=|VX$6b{QlF+N<3i;ZhF>h2m{Xb z4REI@WYX-pr)fiQNu8MoWk1(!^mfBvXA@U2_ zt1hz;u}Q=au~liGm=S#0C2nf|TEX__;5`t*6)kUV`KTG(4U6p_CnnR?l5C*&98P7k z&2ZTsV0+f+uQgzCdo8s0urS<^svg~u>pD9jmb@lB0Qo6``b_Jv&H5>FVjCmyG=qt9Fl%!U7zAW6V^0#;NJAznN-)TZ{Xq#(M|97(SwZ|JPe^e8n3DGmecYh zJ9pp1xRkpf>i4(c?+9wSXrBtamO6QsP8BEzKOl~2)|z;|5wOKOsx>Zn6Qq9EkVE4i zA`Fu!i&>EOqN`6C$ZZDguX1}d-Y!ogIvxRO7BaUpHZ<|mb*3YA({{WLh$#zp?%bqd zZ!!N{OVVV;>{*+AlHh7)=;p$Bp#Cc z;IXLmLNt}jWUsD~0I@AsL?$OCPutZspu)y*yTnhHIny_=3tL|g{PYO;a|^YNG&sWb zDh%{`GdM|>(~A~39!8^Xmq~xW$&FuIj_KN#CJpp1vdMcSiA^H4Vc6X?4`Etk0l+$| zkMWeQ?6#-Bk@>0srB?IiN+`s|mbR27h z%(_qVFoy&fKHdxGVv8H-w%ifc$kbgYA?d!sr^voz7GC&yq+?qgn2k#ejhxYXo{Ca-I+#2l(O^ieBbq6V+hRf5MkFWmYr#bBo2Bu z8)q$Nmrn&$Phx0qx{@(~3)8z=+k3<`wa?l~y5YoY;3R0PuJc7yHrB0Oq2EVfmi9LDhMSAF?jODTUViilLfE$f*OlKT zMHpMEK1eihP0SguXL9#FZSKrNeYE*)+ znqg<%Nu#CX<~HEq_L!==ZUd+uguvy2^yOu1^hj{Ut9R!0S=cB)1CQIAMxLat1NUN# zA@SRu)vnpgo^cEI&vK#(3sWeZEhYB25aG^#d+@?QUmE}A!C(0(p{IfMiD<}TBnZu$ z$w%X-;ejHB0#mbl)sy!Nw*eeG_mP21^eaQ|wceD;U!mk@J>!;Rqox_OjkF(;S#)ROy8O9CIdml9j=hyoY8|EdHxHSqqze`vnT~QJHj^=qJajyb0aTdWUxwGV-Zk`+ZRormqZzfs zsjC;F{FQ_2=A<0<0z^heM(#mC=)KIEm`CDW)hx#!pY)6#cl2UZC_C>R*e|dzR(1b< z6ykxJZ6ic_SgpHg*bcF~6QXsw)nr2H<$o97vf5QELqQ=YOjp0J0h{Rfs>z<^;+or4 zUPUv2jsvS!hp+ox8bwa{;rk3v2EjM`j*nHs&tqE`?8!&o?kaVN=qJ!~EvYt$bMrRA z?)Zbvo{!Uwm9*=!Gnd1b$%_p{|LC+T|DYrvX~g2Ktkr=Tkh-kKbZ?8=kGirmYo?vD zZJ->y&2&4u#EGpMn-2K{$4hcu7`gLJSYOD*ew|d>)>bZcan-Zc-$Tw)IVJuI?hI*s>?JNobpYxMn*^t-@Y2k#DE2atQG0-{D{!nT zxc2}NZQjXttbfeWwP^l}-Rx6du-M7m&W2LU)lg!Xtkc79$5Bwj%j11HMWQ6dfIGf(rF0~1q@B|Z z7FO2>7uOM&m(h}9T$Jl?=}l|x-C~86NUJ_m=#UtgV*{NOzm=rMAb&_I{V4Rj_yN=Pew5^JALbxh%EDn&0<)a*YNBEhNL3>+)^>Q7C%Do2z~0*J>R&! z26YHbdhcH9qgmSVgdtiaSO!^g1fFz`JBe(Q3|LZf*4R(geA2cJ^zBUW3MXkYzPRgo zOTIFi#$Bzf{mMP&jo9TW`nX+4d;NaZs%dI^m495od}$PMO+hZ6vfa<(>|f}-yEy{y z753RDwrLbwaT2|Xhi){PF2(M_yG;!Y_rGWVie(coCevvbX`QiY?Ktl5O(R2Y782)K?WbnWwH{uo8~+y;z@b<@wL@yN@?s#g&jaR$Wx< zOrlzYT6=EXL*HEA68fAiS2J6azu&roA<2c{tVoK1yUh%CNkQ}?dAwQ_0SnzlDnYg%b()04(?oygAe9d zyZ^DZ_Q3i4i(LoP!aStz%7L zmwfKA_j{+qMyB1>qO5;YyQod(uK!H%mpBsnpyC{5Qqwc);+%Z~GXdgBL*6RsH=Jqe z{?>iR87y{WCc<0ovi7Z3GDI)>eoL~e*5O>*wMck5;_zWUc%r+Vyur*&?%bT?n4qWq zb4_BIazzUfvFY{3txK81BGnhyv;y5VreO?R&TqB*AWB*?)8CH(*SOlmu09a2hq}Hb z`BiM|%pG4qKfZq?oKaUV89pF$@;?*ef-oO|MQ4ZZ&M&%?K7fCivnS0#@!$yalZrsQPuGe0OC`?p24gHvR z(|w`iiBre&De5hOj`qBmn5^l9?Xv+b0ng0Wi+tnSfAwV71@ZRNJ>FS*VTg0!`fVL} zaelbtR~Y_AU0eEb}-%uw5Z>@Nt9geg#I zxMtvbvT9+b^L^A~*?=+~D6MO;RyI|tHieRc0o)AZf{hpLNwOZ*tsn+$cs}UWhPa1ATd`&cY>Utx|ez;mE*0 zcj*Fme((Z*^kH}t@t{!Dl{v5~%nYHS!4s0~cA)luP#AgFU9vaJ?}L}2CQQzs-fQZ& zuH6|UW=LxGJ(>`Rqwk~FTTbg|{wZ6mYEfh9G=XT-wWff%j(6tJWDFkQ%<_xJC-io3 zX>)1btx1}m*FWwBZIlddwbQSXwx44hIk*Y2VsiquzcoK>RCT9G@#JB0GzBQH;fo1w zsis77oH3t=pJX;V$}Dk^JN(^4YEh%WyoY;yCE)R9^sWcwgAeQF7_4Z5B$9L#-QRuWVW7iisqer<9NBNzuN3u4{kGs7%RvJTuTZez2!boM16?1hRouTO7A zO7(yFwFM%1(nP?u##J|>??0xf)T*2N1j++Vi`LN2YVT+i7tXjNx~%c+hd0S5BQB{R zulD&YQzk4dO2Pkn<(-jD;J20Zg@1I(-ia;ZME1=!ZOJChhzsseo~+2zL)H=R&Jt4J z-=mBkj*M{Y84<>lrCkH7Fd2LoxAJc?>A0>II(ssMgPzMQh@xI z-FUK+S8X%4-rw*P1c03AWJkVtwf6bYBy_kIIkT?X@kFbQj)^JawuK%Ei^tx!SV%r6 zSy(q{^snmW&O49NpzQ1TF&;pJm=)hYyM~XTGH- zG0wr^Zb<07J#KhW`dNuOlD_e6X>7D}4w4P{bt%9DpCSv>ccJcpq^^zKJk`B!TxXcu z>-EEK%v4}tWADAe6)i2Z4)cJ8dh$sz&X;EvR=>p=)=^IKNEypi_H#Q5v_ZGFem`-Mz%+5ulsT@g_dG z5lXY}h1=feLoqATmNAfKkE3HguPn|Tr$XL*owkz%H(OVA^RGN-?GQ1Xa@I_!)x>TE z>FcyAQOCq`{1B**&-3`9ptNS*vZ4(lT@c#r&=^AE{`$pDZh2_mC88vyMt@gksq5wT zMisx#)~U=p4p!h5i%Xao?R(jsweFqLO7u$@je;PO9|0c+4b?o-0=s=G^xxI8RIf^5 zRU^$CBJUb*C}1o0&~MM%%+|h{>no=TeS12p0~}u$yAo60KaFxx?P7EXq`8B$QB z2{^DPCFSD|kUmZCFxvM%Z6%RYk8;yL;mLdM7oeR%ajyA_zjB~<1Hy0+(WW>lK-h07T-v92 zuIlPZ@d)sRLEiaXS4`p7u3vo4PcAfa5+7*)5Y8ax?jaH5?t2e*_gBLVnvOtSY z#`syVk>ZE-6xJc$h(AZ;sk5YvZvH!Lt?!0y%ri*!bsCkZqdD?Mf`iHBcp`r1;0Q?u zypPj{7Sg(a+myC1ZLu#t?=27zb-+{S3{bVbOwy91UMEy}V;c#4=C`zfa^K zghMEUumzE<9f<%Rogen4mH`oX(G#viJ$e(lrp(^PCA~Tui=yi-JwlZmhnKn(Ej~i>cYINc!VNAMK*h-~ z2o22PVtH1j(oQ~R;8MH2f`)l29L|#2N@|Om4F9}@b!fpoH*sW4|CH_Uuhm{sc=Nau z%6z~t!F&^E_+ykKy96ge=W^d$(AH+m&QiMGgU;8#Hm2sSwl(SlgsJcXAwp!iCtc34 zCuzu!C}bN^^dM^%xtb-pPct?8q<*8J;x>GNJ1#bJH7N`9VX*P zrPf(J(uVuUIC1^;&lHGDQ>KiH+7Dliw1N!Htv?sDr7!btknWVY#3+~QT-rCkw8;t1 z0Dm_(%XvqQRgqXi#aBMKmlNFv_uSyOx=ni!NLER?(y(0j1{P2wG;${4&I9QaDmIg+ zdFSTcwI}WQzwIl3hAD_DZb{Fqj5tgZ)WY3W%Dp?dob@Zdbw_}l27yTt)1zimfz5sG zn|zOe=G*#vuzZ?hO{X>F=t61YY`vEGL!?z7v&l_q^M@{sX5~GMva?H??WE*Fzf>sb z#GRMHm3gIrj(kmg^DS;lsIuGIj$Ti#&6d?)6PlmlE#~{|Z|paKOMf~Ho|2e;(cu`h zS{B{+vNafyKZ|aTvPo{a|_m z30ya{JJ%eV;Pz%EnZy0^Lto;vQit4|FWIdt-9^qz&?mdS@n3t)#wxs1HeG6249}}Q zH>oHdl<(DNl0$er?n4;HDCkamvrF5qK5T?_WshdiwwP2yitL_)7KHm~wbnozR$wE- zQL~{GdzAZ!zRys%+~-VdF`LQ_1_IiOI3Ef}`rS0bdrVf{G=F{uE_=Ci)@!EVPjr&w>bG6XVB8BApj(IP|rQ z>9%VJn>z2YXID`)U8+)>0xGZMnZ%}6ONZ?(6H~Hy+FfIF*(Q3|=<7Ut*nq#wncgCgvzVLDFDPA59PP01b!VFoN{WD?Q4GY-wUz z4h~S%Fiw`2*vtwAW|t!wvnpRr1*E8=(LlvuJmus4`#ISb=si)Ta0$KqqYja@&s;OjUhJN9dvm;CX-r4_#SH>jN$?VjBMvZ zgN#Cop&dSaEfo=;>K3$}JYM|ZDn_F&KL+%NNz|MbG?U$Mum9Y;SnLNnB)^qmCqjVk zknfnO+)6syg{T*e)WXfe%)KwD5p8R&L&swU3rg_o?@<0kF+J+qR-L5EFrUKGU~;S* zC=36FWLW6Q?|mGc3#Ff=B)Ad3sL%<^1Dx`FO>NTJ`M>y0_uazTen1%PLemDCURKIj zAVtaP9~P&^g7B>G>E={OJbM?sYY_o2C(XI4s;a^=J?KwV-6+lJb>-uH0-t7PdY~Nu z5oFy*i)a$U(-CU-Pha1Ug?HevYx1}FS1*Cs67<9)cWgftyc9} zlQU6AQVAWFtx z@nQAJY4;)Z5d41tt3Xu0$K&>e^YPP^0-|eFY)xWl(tFLRu@{*oYzj#Xg%!4_4h&u@ zUnIPO2<@Zi-OAWv$=^ESPjq#nhSE!uiSggJx5RQ!nFm!%`ZD*9o^Kv@>sy$m7z0>}_l{^bM;X;D2!^kt&&rar34-DIDnmjEfQ>ZO{h zS5*{r%+0oFAKZ_Q>83d@o86l9cA>%B(n;Fu+vei#E@!Z^7BO<_wxeqzEiKR>f{nFJ zg$B`0GawGQb;@fR#XZWZI#Q?#3ei_hvt(z&VWPrYdJiqi>_pc?Lbj&HO0dMb;Mmzm zY}}lbw7|>pWo*GuaMT%l-H^)TU`P+f^O8da=gzW1DUb-4BPw*M&qewkihQ&&E9>{&n>HCFjhh?DbWM8ra3(_>YKn@8HEml}HKL9e zN@B)l$M@IYTO%>hQ zVeuam7-sY9MZ7O3yQ+|NqN2C9E>@PTjY)PGoq4%Sb<*zVxoh9AR_cyacVT?dNpdw$x}dnbsgio3 zDQbSnW6%^HyNh}cLF!w$;7`n3h4;HxADIzOyNRl7i`Dha?{`-&$&6z0pAb)Z1*kql z6=Tjs(($i+i~oqHlHYG*-fc9w-PQN479Ja+!F( zQC7#g>#MrC@2akl%iA{*>^wX6sj^Oy(@nH}t>Lz~w_K=kHt{Q#+eEG(u|bc0>K2gM zsG@@!ud9Z91#7|@n+YkFsE(Hs2xt4f zqHK+LB|bpaZ!>2Z16iQkZ4_YLl=(I(BrinhMwG6N(<71WFADJg0FTeAmRc*Bl+%@U za!Qfgj*-7=?-X5Cy%!==e_KDbbn&tV{a3Hvp>blppZ09tZKQ~oH_f4RS1#(B(8#uK zbaBx^7Qka`*|f;`1H^omy$KdI)lz<=qg%OcHM(^;ZYO1|eY$zBVV9UXHiXtR9fn7I^q_O&t=N5%zLXr{nZZIpK1V1Y$z(A%fm zr@);G?JVusfLcfsdaHdWZ|_`VZLXKup@~~vNxL(2BW?}dOMA~`X6S$#i}ooVURKrY zz1G!5O6h-oA|4^*VmC1E8c95Gr)F%JqLq`klO&4a^jCAMiRhmC=uzl`swG!eAnHWM zccf?m(LcR%rIgJy^KNb}^|kYxKapz2b(^c0KBz@jHJj!6Mljo|JLJj>F3#>crkyNg z?ah(3?dw`D>ybN-zRNq3H;=(=##rKQ8-I75oZjAKWo@f(?~LkOxUp8yxW+`kR2K5x zFSpy&YDO!`TWJ*1y5dV8c*=li z_(X->G{}7u=BDmk;)dAZjLe(S7XTje^mL*+gjMbFX~E!oYR&sp6NQz|TH)ip^Gm#` z$N25!%>FEnKOu@%UR!e8z~J$~N;7pbC&;elS1wm4stL&T(!35<)pK%p2HHC|ZH8(w znEwE-cge6@H(-su@o3MF4sZ#r0u1YH)eC5`ghwRz{{T?FC9+=-zUbv?oMY2+P`Nhl zHz442B{|zyeKidrdAg19IzC2YAXIQv$nE0BPla;X_CE6>`DM4eFqy7jET43p?vEnL z9eLz8FD$xq(7l~Oad@}6TZpa}+xXNu7~Y!Q$*@%jD4PrfieJvxN@>_hU5fV zoW%AiBVJK|-j$JWWIY`dP?W+$s;Zr)SK3L8(>6!L9C3)+dMO{fP!Ue(sijrb-)vy8 z)gUGnbAKK_3Fo@<3%o8G+YB3bL@t3sTCDa0ETeEa`S8<;K|$43Mal9a?zOvN?idX{$Zc0uG{vS`j)k zuJYcP@)IUsCBZ|Jk`r&6?grh7TIVguAhw}at6RSDcfSq(QI_HII!9XlYTb@=qqBxb zUSS;)7*OR7CJ4y2fg324*x1}Jal|KM=3t84lLe)_khs6bj@_1FvK!1wXJaoEG0ANu zoW0@OOoc~onG$Sik)}qUN%JA9i(-;Gto_i&TA0g}G3{?)wbtc1f=03C+3j}ZbkCiZ zkRRN`TNxgwlS9`=`x1{-BZwy-l8?Hh92Yol~+?w@A)0FiB?H*m1J@)oO%oJ~^Q2}C(5@#a6a zW01GqaG1{*h#Y`yXmskW+Zd3aS%4bHe7WwqcU`f??vg(Q@?0?>!ndD zoRIMw5A4M}wa7M(MY~2qZSS>LmT(Pl+uw$jNbZ%wKZ?U5x46PX$sd8fb zRzoBm;;;pK;!Uf3MpC}Pabowd#I4@TN7!FF%?H_J9dSL)qKX!gAZod>dkwZh(YnLR zV|a@tX!I}bLZ8U7_G0t$3tFtP`OhmjtOceaydF)J`*arZ9k%v?%0L6tI;M(fbOmIC zW^JX6c8sEWkpAxeo9db>k5oD!6t4^ckI7GEV#_%7$)EPv+jrXT#Jz?m2#Y_iRit!k3HMWHdFN-Ccz%p4jH(E>Be760W?9XCZZeoSG4>W6^apc#JZYtr~L6=~*h*`Gr znOI+9>^;m=i-ug=8+`P!hhE!E>2fYj$Wa$Ta<;<=j7f0ld}{u6W8fDP9B+u@ap($g zm7SH@9Fto`41Kms{lt~*85%bu`!kGDmsG*|xs zxedEJQMu(+RaH%YwMOA^ZDrjgawz3YdfvApbSmfCQ$@R{{{UBX<9v!V_bY#)x6%h2 zI1FL#*xa0zb*yhOz~dXek!@G^PTCkhTLCVOy`o+hK$>Vol}va|o{6pmX&*ra(*t|z z9*zn@xN7+XZMc}vBaKuQ2F;a#=&s-sKh02JDz*mQgD&{)Tqv&fMQ(n`4i~ zW@pFT;jys6HjI_L^J2xg6akR^xIS9UbixHk3liT=p8@sIsAMRjL|fuJ#WZ z!@a15O$nm8y)&5Ev631hb;)0t6Yzbk6gCZNZ_=7nZcTD))l;0eB2~fZK9BY&aLXWI zYxgF(Fm5utVuBs%&+UtepGYi?)5|t4*6DXCT~6d=XS2v?u(`6fuXZtySyLU69Un9QDyZ76h*Zhc~x}L8&mUO}$ujp1$FQq!7MAu=di*5&ExXUdy}_iw>s)+St&{mBNhab)R~n+3z%uDV=+rGh+S-XjXZau=y47yLFAkw$I1h+hjp~#j{0*2Ovj| z+(0Jzk*8Q#J;Yzz2rjK}1*>9Wm zg%9aEIZ%9gVu|&d>9rd=#wZSlOTVsbS9T;>Ikz|>?SZm&1vO;uyJPYG zBV$0SrjoL&%pB+3*uoiWJ5$OB=ytg;YX`#XSrxJUz<^9cfQ5A*K!@sa+@c3j*~4>xC?m)`eX(0d8IGRD^a!h8l;FmrZ3eU&e<4D>8;u*sHwwb?UG_t*F1@_S0%q4z&6 zt~mw?8*@3DPU67aM}2F5YWzLR?b#y7zKF&3!}MHQ%F?299iS>gcDa&V8z}EAACa{f ze2!V2mty>Y_T0>M!J5_2R{sDUq4p3?odw0Zn&2@Edn9Wv>Kk&#I>N@*+8)ya4W^e+ ziO>HzP za6@L3>4qJ|bx(B^aIvk*Wn{coe<|s(OGo^s5gAdknn>`$EZy?iwwQomW1PchY*;vH zt4`B{$p}PQD5L`7I@Y=fDuuG_BLeIx;}A#PH}_N(6)hbX>ThgDim<j^AVH@1gZ6&*YD+w*Arok=PuicvACRvX+R=F5kFc(al_pLBpx08!%?8u^y zS09bgNXS#+wz?NMsjSp?@@0>R_!r+JwYFuPTp62RiIBHds*LVvM~2;%k?p9+L{!rK zH#Z7v;TrBwI=8nBR?gadJpTaXcTqZ2CtcOv+Mjzxn8Y3S*}d(WXxyi8dWoA`MMMI- zv5xvXd=u)a`ofT!ux3`u502(GKsvJ;HW0;ypiE?uEkq$`MiCb+hJ8zZNPPnyL7pSb8e*A%j<)>3t$rkQ1@rI zicUsPzMVB!c^iVhPfq1ga=FJrJEz9R#M@dS8Y5z81qje$4OCRrl;Vj+$<9UEZdKsB zeIc@kvm94}jgmt1Xv=$(_8VDE&x^bX@i%c7VlG^w$4L|6wD|3N+Y@gu-EfCgRBAA+ z8&S&&sgKycYK|1x7hyUCVO~jf_xz32@!2#NT|Bx=7q;db#6N)&TQ->u~$*|+xBa9mck96+E#6RX_-5h54YaTr-J6)#nS{b zcTtEl!K&4h=jXz~cMZ1}pGCUU8u0ZbJ4pHktfoUmRdgdtC$g&}i)GlkvG`LpG;I-% zp?J&bl63T6AsLqXplX6EWmJ%^&`pi1SSlP$Cf?zaDj?NON+^_EiaZrfavxGLm2lpl z=;1{#)`J{FGPm|_Z;;5O@`=;0WWF)>?1P_0eRghK;j0HlZ5L^pj!;zzvC&ac5WKrD z@T0uDj~g2VxAHUwtGkV%jp{CBg|f-L)m2TBiYba^!iwW^wU&vKsBRTgP%1|`%4lS0 zzcQ9xAKZ*=jyW9AW>Dg@SAm{44VEvkx&UX5X>c&c`r8KnUTRg z{np`K3FxA2MmpcFr<3lU@es&)2TuEt*DsN7F4HHMdTes!WqD))*F}xkP#YD*^-ubA zKHHR1roO5-QCrNTnyHeePf*$DjmnMmFKCs&3@aTJT*|#y~GtARDd+tZogvx!!-u>UTXwycTXTjzT<) zOcae?&)SC*bGh1F{{U{x);gz5jn~y$s;q_{H<=&>xJQ2Wfi*ET%W`wmIRtEt$)f;g-z4&C7eCG+!c%?lLI#{GI;*3K>P1E|JG?TZu$V ze&h8{`vx{6aX#m!soH`CGI9`-sj?`p=%cz{IjOg;au>T3^MW+rC5>hBe?84<+2dC& z1I13;yzTr}kYZ`@^&|y*!whU5v__=A<4u7%#|+LOu6$GQw^?UJ^Ty02vRZx0*Mfo$3(Z&Mvtb@tB1 zHKDvURnmy`Qd~z8y3R5+adR!%_FZ&%4OLO=`5xQ7iT>$(&ASQsQ5O=VaB8!Ut;g+I zJ=>H`-3U%?M2sv{L8+m2ObMif^0$_$ZzT!yxTiR*U6ZmGHzY}Rz{a}AF+G{P%TJJ# z$J+K|t3{FW%x*PF=2w?OS?@1Zymt2Jy%b6=s&}*7`+>VbQNqpGT&b~qk_Q}|)s`dm z15nVee?^b8l*K#V+|ga%z2vJ4qETxu1aCHP&?dPOw<7B6RM{wut1n~Nb*09|8ydtD zAGJ6qGO8C)Jgv&StEl_YS#*`X1$6Bl)AwAX`b2WKNq|oXhbuey$PNdNdD{ad&q-Ob z^U9qooR3spMBisfy15wFZ8KlVw-S6!fyKYN`-_u1=vcOOjbx+-&0?G0jJIhB0QD>e z5(15tTNc_V!YxmVs#r~BZq)^$oa0{(HL*m}_v3FGA;aWu9pZnF-)kk!#CB}Fyub39 zZE&_Ymd|rlEZdyflO{Sn^;B1vKOL@*Ysso8bVc3Ki_EvTb8+656IE*Z$L^;;MW5+= zsGe$`uBF)58tHE+h44t76J~4@m}Jv(+_!O6NCd5Xe+qkP3T%p~8i$GoovU?IimxtT z*|~-L$GUgYyUbEf$B5#ZaOmQJ7tH0=R3q+sCS1NW+`Nre`6f)7Yr&nIf_MttjFcu~ zw=J$hPpBfi_abj{63?_<&Ro_tum=Mehw5}aP51Uc)5nEfl80m1nv7z0NgJUs%b_c} zLT$qDsb(%krRq0N3bl3B?4AwdH+J(ITB}$)OK^pm8<}%A5wW(6y1WlFTo*0KNTMZf zH1|@=v1D!oQ@WChDmPTzbd)T7Thkk`Zla-Zv;7i1R;qVxGfBPa{^8q&nb@FxRz}a{ zM`L^59K5x!$YreC5PeXQ2c|o6df!36cQWKO&1}jw6y|pT!&_TJb$DKkLNrJTq16ziA*#{`-b;IfV_F&3&JBvXf22Q3c|l%}p?{%GR*$2t{{T=~OMi_ut;fi3 zD688A1Dq3NO_f6A@_~|4%CLL5A6{EJkYc^iRdtm!_D(O`K z?!)3fD$gLg@xK?f@py`Q+g0TLM-PudV{{d8q<9l~C@zw031#6{frTScSm7CeNibM3TWE`>Ixdmo~kXipkM= z2z1IeHWudI`QK}c*s>RbXG75w)7cWddTUu9lElf0xWi3H`4z8i(fdWv$L|-kw$Wd+ zCF4>=rMGlOnpw!;@5goxW*{mptI9l*A04;8$W4@=85J6OuH7_}N|&a(l1p;tGD%8` z9=8(gPIXmir=4|j!eKr(t%vszK(FxN(y1ciKa+?Yxi!2;O8~=q6>J_^o3h*RYH09j=W+ z&{Zg*JDUOP{+G7U-Jj#}O)&82=>?>IHVt$48(1oC>|jOOTq?y~jk|tOG;Q zJE3^%EV~}p&_cxL04I}qE~1uX#=3W6Fl@00R}ZPBZb3ikY=){gQ4Xv9CUJ6k`l+Cd z&iJAbv1X?)p3|zc{@*I7ooB|x^VT&K!NEDbBx#M&KX6@9wcfTw(AEH?>X{u?#3Av? z2kzTl#dK*^EObvz_KrujJ%!Fg=|I;>{{XjUuHUgb;zJ+HmFki?HXsyXv9XTc8t1gX zs>uCNn!^78)V-6Rv`1307h+LGWpUb(mnhHH_U~*Kv54cmx%qbue`%^V_T!n<0S|P@ zs%_3rCj1+cnQB^II@>yeCs9o`87uY+IJU4|2CUxOtD6rs$m5~8^IZMnejZ$jo%DD$ zSh)K1Yg$k#?ot%uRIc4DO{!>DS6fS^QcA6@WxbOXiHjJ{2PQY5ZkMj0JyTN=Q^Z)G z`ly_+HhbKvuIBj@TDPUA=;zA_kVf-tV4OWxsz!=N*EQ_{jjd2^Q)5pXQ&^c5Q^27W zF+m&(sm%`;ovUGKF7?~0dkattZB;0{&8+iuvNcz~uXocA>zMVsa10X?nE5K`mTQJ5{U^6l(X>GBj&)VsyPax2g9wmEW%4ot#t^Sx+9u#NvOl={c()vM zVl_qWqtv6Mv<+w1BSyh-bJ}a$CDE&s z`ytBEHHzX^GE+5EWvboLrFY6=3l~3a`QP~Y8-sH^c73>IW7}rvgh`F6kaafFLL`6( zSjO3%JP)^gGA2A-TigY1dX^~0)Z?@@`{sePYgyA7AMQFz3zJoSCfFD^9DHK7gP=|o zAxISEPI_98s%bky;(g?m98R71tXRgyw5lpCs)~w>^p-lI$E55j;XpdKONl#dC3Shm z*fz#8bj?WC!)!ExyIID0G*Q}u=eM%g9g08hbWp|7<6;pfD5l<=}NnhjMR3z?ycOsJ>0EKH0`c52ib<&A4y-s2f(>TYP~xc57z4yx1ab$~SR# zg`7@UE7n0AvAIM@G4%mu?l!j%Yu|iP)W7I$vpaCT`<200?%i(!v=nS0v;elC6w2mG zI(d59Kc(%@b;^}qGlgssGRb@eC7}tn|` zt%QxtHZc{$XKbx9DB41B0q*)#Oz8RO=^j{^OBL+KMG@F0cIQYwkqxe%c)M)4jnO)Le)?^} z4*SmLn3*hiSBP$|V%(;T!z=_)p0l;rR~XBF!&u#+-BrW8Y!WM(KAWe~D`CC%(NQ#4 zP5o-7_PUpI2=QO4SQIIcf-OACVFvmIxRSjWCjLE$>b8IX%@qhSg->YHg)*qX(#0OSo-#GSAj z;u#o(R%`Vgqbx>B`b*OtuWh|tt>$z~8+hBM_SBZfza7t#N9}7)#obOOLvrBc&Z0)` zQqB{lGOqss(`&V_bpub*_}@wL4y)hL$<^FnZ*dXYO2Wgrx0elak@ZzXZw}uAiz3Mp zy=x2?&bfESWllah6LE1hO#^#yNwM~B7cgY4OH&OHO>GU6X`l-JLtV=HU8^GMMTfVl zw2ZB)i*A>l8+QGv?x_Z=**?;Hc<^rj0DjA0nH3hrBx>QbQyQrOsZLj26n^L0MeJKG z5Or4I214N7&4shv`l2XozrF&>{{YF4-x}YgQ&Ov?c(&CR(OcSXR@Q9_Xp^JbEv-z- zW3?ZlSERBgEuHrV2fH%bTUq2TEFYB3eZjc+enakvE_+qzY%IY7B{FpR1#hDFUg}qd zhrX&)^s!tOBloAg(7$SB%YwI&v#GzmA*0Nl({s_s-+*Zx&uVP#r1!3JaaGc(&8imB zy*9!W#)bfzQ=Fdei^T4G*3z^+l0pJ&6MDYczfZE=MR5J{E6=XuBh=W#+m7A8PqOQ- zP|>$iRRL7i(P8lwZgy|>o-#X`fZbfxcNXC2)TzjoeC@H@%TwH5>R;8miZ^u0-fR}E z-sl)2XjhhoHD~?cvfuJTwP$V>?46Po`+-LJeZ_%CbsW5K$GH4qSmIC(q0#Sju=RKC z2Xsf>@2VeBo?0nqa~lWL>zLata>upSwubUacH6}yaW%cI%Hyl-C;09c0$}HgKJR;l z&<%!d>P?LW^-gU=owQxtZcqAKC+#iCu2`P3+&}7(-5@II+=j5Zb|g|p_6It;gyhv- z8k$p_ucqy>gQtjG_U?bu^XNO3gl2i0&?|@SVd}rqSAOiDy*0dBL~Ni8RA1;pS%*|y zCN*F%-*9!yevcqDgTrd<)}>D!Mc?hIA5!9+>MOVJWHsD@qPza$biKB{=2v21qHCy{ z@N~J4W9_Ei+{gTjiA)WLF&vGG{s~R)N8}#=0Myy&pK;bn=!ELSDZ79KBUbI|#wggD zkJ1?Lsz+{D5`u~#D925^+}U?a1bvoVOGdvPJhC#}LeAAxkUBAMZdfj3tLBqq?dNzB zO5zJc8uxULLIb38%V?bK#^wE%j)|@9wa0suYYkoVNmU`~0+gyMDlMvtii)b!x=mEp zjFn4l__P{Uh&con>LU6nrui~grG)0%;yDDY$wyT4(+?ijIn)95Q*}}Rrz-R4Si5b~ zMAZ{&fC=o-thxH9{dns)WG8|KTE}tve3SHe5Z#^NaH_~!k|(z+Mi|tFs(an<$I2ym zQaN0Hx~uu>n$F|n9k%XFHAVYc`M#?;=={?@sT*!6R;s&4MJGjCDdcexMcg?T??Hs3(y{n&pg7xH%lc;aXVAc%39n?K z8e~Dq(Uy`G6mTE|gS(KgokYu)N~N}JiSfD;s+i>0pyXVxuD(Irv<3dYJ#r_tyXc!9 z^=x}=-BevgzqluGVxC6E9b1Q3MY1@f=*Z}RPGWpTI4q&8vwpuAu=w#SgGTuqw@2Uy z{{TJ1BLjuyvmz7Ry6M-h?Zaq0(zu*`&~-zU=czOW+m15chzh4mLj}tNubw*Y!WbfYTU(`B;ePyR=0D{MYT`=7w=+01mQ$C?5P%T5u zVX>$zg~X8x8^(ir^HC>NPup{Ln|K;p+aOEv*3u{7?aH46Fj8XfqhAW)e3mGtYm0h| zi#njqrYXw|t?xJ46}d6!yfII5>ysQJ-L7(~3&k$Ga%8$IWAw!OAf`P7s4uPrYFUiV zv}X50$^e_yG-%~7>ArU9B961#H)|Eg>CT_0!X39g#pY7%fu&{L{@V=N%j7ZbI9ro6 z4>S|0{{XiPW>>L+fsI#pLO0tz*D_y@+e&Y}{{Z}ZxwpPAsGf+LEy}1BGb+oE({5-h zRg91KEh4Cj9lFA&Afn!=wMeRo&<)7Btx`Xw9`ab|-4t~*O+d;YlLJ; zJs)>0X}57srHi(qn_|3*qjCbP^eH8M%b>OFHfL275LnqvGhaMO90zI=ZB3S{N7Y^3 z3wF;lrgH+ZhhiS>HBCVj;-!DnG&|hbDJ(yr`%n6Fp57#TdA=_-nzwP4k%iO2V`=f3 zle;&|1}Pi;rc~UZgfRfJc@K;l435QHi+0@4-+4_dF?HFuRtz#tkdL%Uu9ZNqadFVv zv{Epz@b$Kc0jml_c0RqDQ#b{Qy&iV-;g)rxBIUQ4qw=t7ve$ zwKnG3_qMws;@Ykg0LdLFXshm>YhW!IEQ!XtRX6oU?S>h9_K=;X>V1a7=eXHt5w`B^ z&h~|D%DNQKa1&5EKiY3@+7Z>zpQX=Jbs5pqA17w$b=2hT1GMrMTkmypEn|{HE3r18A=kHE#lLEG*a{1Vx!L=Q>En=hC(O(o^|=D7fvU)l z+_fqthbFPfwFzpsAZnTIRDGgul5_MHwkwYR5={vSILsztj z3#2Y}IzOT=qAo8^G(fL$S|}niI@Z-SlvGsG=d6!+)Cbc=C%upM_=imz;u9xZ+akNN z?JH}i+Lz?v5lK45VrI*_JY*J8-<^TZsv$c_$JIrLxuk4ARrKUP8*{PO_tj9S`m1*B z5ss0HCe<-*R8o6R5ecm847*W!nf)`r+H0s{^9v^1U3rD{%6qG;#UxEJ_=lKwo>k?+ zxwwPbuH17o87^^|583$*E4UmSR1N5|cU|criPsOKY@m`_C(Bhc!&dZMT(>L)eXD!Y z=T7@a#}?!rpjVFG`&Ou8bum#G!#aghn#2#r_~FxaE~+~2qODXh85N5_BcQJZ*XotOyZ->y zN$+8D8hC>@BMDuywv@DdL3f?}f3NETXsi<_-{Zz4{)aKDhXc=-sbcM?=`;ZlkKkXyAWUi{0^hDm`@xLvu zHr$dsy|HUAPaudDWiH7bXDgJ3SXX|kE9SIZWEdmuI#*a&3n=cVFL5eKL}R#RAg3BA zSZ9BCV}6MaM&NdoWd!$a5_MKg+Oe_jR=@zoRMMF6)Ym4tR;n>YcwE-K^)t>D{rR@P z$jD&3j{T6yahNV>mCjLu&@wKCMSB#BA)6TYOF2=`*g`=mo_Oq=J;Ux_r4x}vsK-bg zSS$@l;HtTH=TH*=0A{CkGQ{ZHV{_bZ2x_K<;Tejla(C{mb%b_mH;OCC1TkFC+;vl{ zwABS@I;Osc+3P3$;N8WlHmi2k1}H@oNCXscO6%8y`~#L1iheoQ8~YXsQh8i-=5-HN=+m7xx=l z`Tm=mwzXeQZl$=G&8GS;_yXP@@C>~QGYro#PYT}R*WE_c$H?Vy_e}2DUALlWw`lXE zL+RcXl%h1pZf$j)`x@uf$mw3J{n#v6*D!H+HlpHm0;g#z7~2wncQg}GXENU*#zfbv zYp&S4*&}u)eJgiR+N(~dEfoxLD43Yl6Lz81Mxaeh3X5u@duoGJ>{0~S)fCLDWCR>^ zk~vsatsPb0>3non4en1N+9iJTXxads10_bWEy_#i;ZDv#6xruENtU^CeZ$^&la7bd=nS$8XTnIyOO%71DvcwDX9+BS`FYYh}-SD$6nRsO7$(Z(w7}LP}q{|rU;kN)jZ^``@xa!l$S4b;QQ>xL2Zv zWAtJ=O?>^WR{sE@p-U|U_br4^m3+zDoTQblPLz~fw`uO8vzA3Iv!F#p(F9V-upX$b zwNCf7J7%x%WctMudbBKNX^dnBAjb7k`&DnDY^@2qXm&7nzC>5|y_V#z%&Z@{&_71Ccyl&{7 zBDa`?4&Vxr{{UA0miPU%$8T>OOh=$|y0PjhD5SaRaQ)8U4OCP>AcAYqDiq#{q!h|h zB+iM5D(Y9VcPOjFsbKiGG(t z^R_qDIQ?#`9VEA=E+3aY9BIpUH}kk*r}k*;P@D$muEkWX=87!BK1Gbq-*5m6-@t+A^w&(RC2*yMCh zY_UkJMWvK8KfbRnpWV6}V`blFE6MFLLR`(556{CGb?lEXpXs@iVCS6WtCcpVEz9*SyFo!QMCy}2)f#KpaD^+2w3rqH zDGjxlnQnfU&UqqMn?R~`z&yaOPj5#J5zM88U(gk39OdlRLAMTx1`W+Lh?&#L-!2k zNjQkbm5*jTh1YS~3cR+)XDe(B)4H+P#$C9)mPTYQJBqMw=%--VJ>31F$8pjI?HBG= z=c7+tbY^K_x-!1q^)NM^?7mO3Fn6t$KOE;vJ*(j-qMGJFqqw)r!7y`FqiT!l4g!SH zutcSka*4f5iX}KE^c$$R61E_nMCR3ea<=VTm%65%Q-4!Ep77QgXsSz9$gFUVa0}VsP69NkmD_gSNGA_M;x-;$#07I zOC^vcq|}n5jnlgsj*i8Tk*ZsV5{K06&B%%!)K<|Oi5SrXB|C%J6I8Ny2tX=TM)Kh~ z+~#x*SaKU2Z|p04fwyip?bj%D7AG+^s*7%e+zyvL0X0#u zm`_ErvF$cf$l6VH?D6{+AEs`qTbrBKJi5`$scMekwFk0AwR=si)ifZz zv>&Jiclt_-(&9#amU>Sg#W(MY^{hSD-ZG429q2<{5_Qv>@0GoLg7FvB&WYCHcJ`)7 zSfe6Ubr4|pSFzPF)M!vqAes|VP6)LX{;g1`69SEuO>GkbV^tGEqM{8~*A26S9@BGh z9oDMeUhA%A?J^)_c0zrY%|=y=w-7~;le=|?k9=-*9e}4>ru zNi@!s+6~fWZu?W+4X$vZy16nUu-MMXf7GUXB2&xqOtuWQfPkZg(irf2So=@jxN>Ms z36Z*2L2L2V!-JnRlvwzk6}+vgxMFL{iY7fvak0~V1@7K)^ZZ%zw(gEaRc&>SvA3Vd zSt}zyB$tR&-MdJXFaRBD7%8;Ig2vm&9BVHg_+@WG5KRi53Kb3t;B+Bl1#LE_#tORe z=q?sY#rUc2n%Uuo_0Tc$7m!!LY@^08vAw0MwyK=wl_NnB&)YKG2e1_>sQm?1Za}Eh zQxj2CMXBf}1sA+32GKLwsx&nA&}rovL2zs!?8HSKHPCA@7aL{CKdgVW%Zbgy-0BQ< zpMBEIB8{%xZ6$4$ku^9;TLiZk51jml(r1}m7=%jD0M{#0*ckUZd9QjKyN$@KRxf*} zo;a1(P`O)UpKzj%8%2|q(yMDJE)BeJV_R`M?u^gvx7{=+KWfKD%LwkSoSu7Q17vbH zj$(TgqXm3nSt2`cG4W&{dmqGeo(kTji}vNWd=7FE?@~w%Hb-k5ou!;zRo+3jg79pX zGOcmYJ+ZJfQCvaZj_NZSAvH87H=!M9f}J_58z1{Y6;mQXi_Nj_F$*c29ceT{qjD`F zM=Rn!FARdzwu*{C=W5tD2^i?s^zNcoRWPl!N1|y_CZ;IcRoh*%pBYbSLApS##a#^$ z0Y=prTUW9ss46MtY!R|oWiG=N>%>Aw5+HYJ?2XgABXit-&X8Mo+{!Rzt`6z!z%W<*qO^h&h zSf;$~CrbC0#U!d`ozz6DD^)eYc9QO$_>RtdY*~C(sfQ9E$sUdG6cvIZPrs1GB#FMWHxP%XNB8a-A|p$Vr*^jwv4~Xn`T1U z8nz)IMeHb+1TI5U=89&!-8d%>*|(#V@X>oHoS32t7AD11AVSY_n-C-yFq?O^K+3Cj zC}N_Csi8*RFEhPuy_OQ&w$*h%ep2c$)a&bkYXmG?jLwEJ6K0pN$hTcwU&KBgRZ}GG zfzf_D@gKX(na07Jwa8dWjku!3xOeYmj~NrBFMWlvwu>S3Lrslxg4y>b-o`jXAzg(d z1Z|P#MAiU{XsqMf$C{GmZvlFd#xy!9;^AsAYl160-_;lQw`w{U_^+ldcs(Ws3KC0j>TZyIY8BC2J& z5YcBbY`KA+_KfLn-KaG%CIk@BYns0MzEarjW#s+1fkj&n+`4~x&Lzsy+qb4h<9f%9 z_c_b2jc-JLl*ZL~$BoV97nZinvWK$2Ao#z@v|U}o58E;ht6ii-!h4{B=p7I4MdwRs}uJSBjvz$wzifA}t5Gxo`&a>x!Dq2ddtlYj`z$jzOP9L& zw?qbm^}8L8pC><#U}5pwDroiz8{`<%hsda+bkAf024ydIsuHo-0`(1}BMoH`3Mij3 zyYVZxTgh*660nT5*-Ljs_Wfruck(5I6FcLKFiPsDyRY`ghhu&{p2e|jO^T{pbm$at zro@D3u>nTpF|g!g&-hL5F;c1z3(3iMll)}{IuQYYUpEr`OB~0?q|B>vIa%^=znDpT zj<=w-39Jezs+$@Eu4@q_ERt-&B|DY`>4ZE_l@6GxUJt{1>5T8svz2@MA;jA ziFO+CnAvid7_4k~dq=rDs(DmF$UOEO8F&SHIt3OJF02e;OejSvHHoc30H~;dMvWPa#JPvxuter{W$5}7%6Z(ZtwdU6Z;aDe?sc`S z0^#?2F?O)Gq|R1wK6!j6#F^ukydRQ{Gtt5yWr+U(m6*76F+qu*@fyS%HS{aR^YZGDI zyBkqu6QSIj1rUkLw&k?0*+qykT=;e(`fINhxqD0<$mj8B-mI}-ZM@52{`YfvVLm!V zZD%FyhD=wF+v41BvUX9?w*3?_rZ$>WPsv!0)Uke`+NX~I-9RG0s^OcRvuStI{21)kM?~LrR8>u2K1y#{*z(>#IMqy?@bEPUC59McQj0l)3np z>cT(vmUhxbahRXv&-y_H=keEuj9ffFlX_>oW{-x(!?AEbaJ8#yjjIf8_jw)Bzhsd$ z?s;olxDy<0DmkUGeSpXLWFA&_EJcaBd5dtnZ)panIK4SyqY&A#wM=SbD5#7;uGm3< zYehs_gLMGZti7GB&Au}&9!;5SwWZrxeT%SHo@qPOrhDkEZy#eWHSM^L7?dqR5nX)F z)8*nC&!xQ+n^h}O04W<+cn!bE%_=G?Dk2fl$-xxwZOS?-uH!;CDZ$g2pkzqgF{!gP z=#ZG;<#k}k86tEJwTQ~=D_Sd9c7_B3V9+PFt1lO3{{S3!HHfCFCLp>sWb#sGUf5d$ zZl>(V6O58oU7EQt2*f!yJzq;%uCC;}9YSty;x;=oeIRR7#Yf}63^x)}i}HW{{{WA= zk(l0^*+Q`sCr=9&KM`?~W$YGsTuUxZu=%i+aX2BrQr)#V?x%(2J{A6d853`vX4bX; z0JbNP-ALQnLV{mJ%1L!{{WN0MMOe()1#Bk6P$GK6w>!08BC6e?-8NC;Ih~? ze08t{=t`09ExP>}oPO5Zz?#Y?1Ue?^RaNB{`z~;fs~V@u+S{+cwMU+{Djc1ptG^n| zWZ#l|vNK~tZ?2_Ro%Y8BoueF^+bo-%5HC>M(YMex+E)$5plMLID`+LXlg57;HUh?m z4ll{4c7GqyMROw*7xB1WWaPM8YHh9Mj}>!rUSDk`%AVF(k#^N(b=FxnrrfC8MTE(H zruRK)%bPi+7tD^%O~VTzSDrg_7__mH=I$tVs3Yjn$~sXVnikc0<;k|Ok@U7F_^gw0B)1ir;DRyk0XKYsmbHKl9dI92L}*F@qtufwt?zvjw*o(Xib(Cnv+*UBerN z;FJYu;vabt*@*LJSlilK?vbqxR8crJTgPlKEx=4|Id3#u`tW{7yx((jKW_eQjI_A> zea20{8tTy2A{XN)@3XdPag1#oK5d6{+Gk?iiltGsGM@p)3oLINn2S@GyLCnd*;cNj zlO0rOpDOyKKN5BOu&A#pqkCSaj*AA+>Frxm#-P;JswM>CO*1*BJrhoj{UQQK7y zr%w#?S779~xQ^;RKgbReXKcduMAX;{ASygz-K?$qcHKND1bQi*^?RoDSZkg0mu**5 zwn;HLH`psYgm;a&&qDzoOyI0C5M`H&=A~uFEyAm|YOb&QQfcI~3*6oF4(o?^%l)LA z!koVrUTnz07#x1<$h;aG)sV+s;$F|FbY4G)pDc0qZO7a43s-G+*2*oa-}S1| z7gac@TeSz29aY+ElP!P;=ukW2O=p+43ffriMa|4sP5xDC6|a$4+!i=E9;+>$?7G7k zcV15CXvV1?*wpzJwMzF)>a1L52t(FV_iD#mwg%tbe7RzbT3awW>Or!~8_T&a+~Qoi zMvI?1juywI6%(6P;<;>|AwlO?DV}W$*YfvQ`Fj3s7)|q=LaqG28E|~ywb_<53ukl@ zN8EF5+!IrrVw)<`Zrl`yYPx>aaLupN*-4Uh)BqA~tOFpEb-La|oAn5)4Tap&xcXacvEwjnw_4bY-k=ly6u(1Mgp+iUB!Z7jWxb>qR*?mNxhC-2OSTCeQKg zVfOa%+Q+Nj*qU<^-5D8{b6=jyVwJtbcTwu&rqymL@+h8FR1oi7vJ)6eY(;*Q>4`cySwZ*FdD8eUvRPZd)7-W^52QJ7Vu>6jpO&r z0D};67OhW!H99&cHA@Q~uRL-)mt--|$HrSx6T5OSAf<15Jhh`^#?zzV-mWAPNi==N z`)g|Thqm78tHIt9)rJWhMvzyAcv(Egn7KC5Lj$I8#l{uxG2p%j z#;8_0$@9q@Lj>||61!^{@Z=-ha9%TEXBRBEG&{&K%{JMaE5}`1w(cJbo8#Os$r70_ zBazWud1NkRzBDU(yn%uz9G}&W#7mc#5skORLv8KO@=K9#V~n%-7TVrN+=kk5aTVrI zyD-H>;c|Y-bETO2MO?2WBs7^%4iproCUiSC~|WxsUH z(;PWGl@pv^ZQ-izCpL=3{{XQ(z1b~oiA1SpHv)O;hee5hVbjR#i7?h;!rJ!Zlkt%161aV3ywrX6sAVCp&6%l|{;^6kSCz+;hUV@Smpbixob{mjIb2 z)n$+|P2?7!EZd8&F_3MHwK-l%-H=1QLcthhln$G^{FIv`Vz#>Y^7!YM4wCOztxgH^;rAyoI;Sxx-C6 z@b+H<-X#mDfv-FA1f)k1t2i=vjEQ%T;0771IgR_Ro;S$t2&tB<`MacU|;`c#gB&yEMmd(%P`)IJ04Y_h?rjJ<8un+>e$i~pu_mi!= z7UQ7zSCX}Y*|CS-WMsNhIF%GsUfO|Gg2epkm;`MOS0A|?JtJgPoIZu}Rc=R0r#O`5 zb#B|HHX{L$C$Pd}m*&U4%r@5zkzsRh#~i1IoU5m_IM&oF`Re<8Z`1KWU8glpdobGr zTj%eUsHXtD7t9XsPnX`9ZTxo`_Ummjk&J#wilBbaFXXXHdzW^u@vbdk9lO_sLZIqk zYK=rxe%#;4a=2VsyM4bRdq^%1#D!bH>xVKbCPt!RDUj}05tLY3oYVrgi>uI5NLW5g zm&|ZqK87s3V9TDj5x%lGGfJXUm5ZAVwf;@hrZLkx-r73`-QGIsHVUHFMjpZwWbG$P z=@96ej+9oA?{*f);X*WV=p>-ti`L{EfkdK8sZuE)+Y`y$kkpdepdA4>LFe5=krB4X zA#nn-^V>;byB;lY*z7!VN1GfH82lTQUNLEMvfdqaYMp54)WEhxQ{LvG`-8(g$+fVUnl>wF~eZvWGr?rwMmNntA^$gk`f|4Ru#kENl z7iAciZis|*+K)wZbm>~i%%%esqc%E4y|Jk;9ERjyT_}e|)d=dgrn0LQ2<}HBYpbK( z({c{$E0BLcyqEYIzcY9MnA<%9{(dfeVA!^IUoLuZq5;f4y=o6&gZQFxoE#@v&iw7L7t65N$bAdy>8(MkyPV$=$w?i~9^pR~cNvwkTdmbj z&;>;IZaoWy#k(4BVF}lckrLv7)FGo#62(KTqy2Wda2T_>86S9u7NX3swbVI z>f_|i1e8146K`T-n<*aAkfJ#gNo6l{oUI}W@=$KBmg1)+BD6G*xj`I`a`7z3@A+m6 z?Bz+&!#4Ka#8~eQ^OF+y;>=lm>wIj^g8NS)X*Rg;_`XX!VaMOv7`$S36xL0LS2+ty zmb%$^Mi1}VMzl0?pCF01eqQ{dw}K0nvhmvzwss$E!xDc*?xKshu{cSy6Zr3n+v4Y%2F}QEc91(EdS>^l+jIDE0~E?!Mdf$nC6y+t_)NB)IX?7^wU+$ZqljNf_B%fX2Q zF@j z{Urmj)(%9~G3GaTN07fgXTjtd&hf_(FE}HKkcY9dw>|jj%sCrt+Zkl-y?D2W&7W8t zJa}79W>?0nGcKF)y_=RF#4&hBW^s+nS=;to4i`4es}tVX+b&J_S#C%xa@@Bgd|IuY zxS+9;ZIbt-z8~X%Jo!JG$Bz$X)>1)_b5}{_j!x3L1}SYa@I^L0{@*19^@KSXyq^mu z0`}6u%ym#|rBi;C=Pr^7?Fe0^wQW>X(jJMZbU_3PYH}J5s5@$n=)G>D?k?h*aTIKJ z^5hdv*IY@o9;PTv&Suz~ycKUY)sV1k(Zs^p15`{|345}CtPP`YomT+7Hwx^wN6xc@ zCx3V;Aog%r_x}L48h$AbJRU=K>wA1OcCMc4X1@21?#ABzmp_m2cPh%l418XP$siW@ zpK$w4$@9m$E4Z%iqw#+m`R(MkqUG?4hh53v-uWcK+7kw+aRAi#=uHtKxWKu%e1MQsD2G#DU zsF>;~UtJpH3J4k^PzW(Gt7;t+o}A^}Me8YYqv)K1Dp!|jYgo}POnixxkg?fN#P1uF zJF*q*g4!~oWn2Q77fEStCFGYGvxl-{l(F~YVd+I?`b0GRSjuCy@@>tPt_={t`^lI# zk5uNiL6q>h``1$EU}ihRFD~6_YaNtakW>%aT57Hh7@DjFbg^gq&keQ>n(pRImF<*G zjk3+#YX;;l`^w@_6Q8)III#G)lXoG_Sxs|qp0Sq3VLtRq-nXEdNKJANqF@hFS*a}? z)v&FUTWXq16jN>hrXH=;p$#gWDx_}IT%1##vN+b4 zXmX9x%mEE4r;Ehfd}ljy+_#`=tLsnFT2wM^biDrKHXf$KCp9RWphW^Oiv&yj2+NoQyZq=`%4nUxRs)|Z3;c_ghnTCP=NU91q zCMb~Vn#I~iDlN26G(_!3>QAFYlKjh$WnBr;y--8xatVT}Q`W{BH#0v#Xo0G;{Z|j8 z8`T1s+L0Tcpe3?pKe7TRw!@En;?@rA_{jTK+`?#$z)rafzJ!T|4_k2_(!!ck^~YrHDi-X zs%z-CgeRhH(vDU=Tv~@9^BQFwg9uD2-0n;XjZ{=p1oZW}X5=ilw06QqhobjI0YIf{ zVcZvRu}0qW+ap^Y#HM*9G*Nq5j+ahApjEp|n$fi$lVrcO7~F1$*Nz{x<2L^QD;b>VMcHl%4)mFHZberN6d1D;JHTS6VrH0+SN8<&Ht^U)rbuxfat#6}eSa0)vopj%|wK0Xs!vFwP#EMw@1Z8*06^l&Kt_rhY-T z0GaGllTiAJDxq{K%q&7xB*3UQ6_J~_8kx#4t%U{Di*k$VHsiM&T}1w~WsMtS7je(} zpJL$KZ^jUJCgOa7t0O8ix-}KyDVHQ8bx|eCmU^QiVNj@?p((oNe2yGayv^ROjj5FEK%os*VolOxewc)WrpvO&@!v@&P zI*GF`@_e;L%BhY_dWuC6G`D`4?)+~Y61+7g`Vryhkp zT)$&~T#ffYfr`Z~i?l$a96*msq6U|6isCO9-=T%!8w<9L`?BEdE zFw_}~qQS^*Euy=shUTT$O=_C|0ITk*rMaSY%~a2-+^U0?;;O2Gb<}YuW*XFUa;fj< zl?%DrzUz9o7ZdD(PkJsZ@xDEQzJs~eYlKKUL6>8YR7$3`J}YD zY=wo#=3@v>M6YxL3#xxqEnLfB7Bb-4KM&-P-?l^aXa4}?+qY`*cK+hLvyS>Z+c_*` zF@*T_38ggALn61Ds?J4sj%4FEixx*0^eb6+waA(()ktWb>MWzbVkH+s#UY>xt>|?s zsl8-ZviD?rsK3%5q(ju-$wvF2tfK71QA~fvipDd0bCY(e%RghqLo^1#VWVY@9x z^u0Rhl4mLJswF$yistpzDD*~ctK_gK{{V3|BUvcaT!ZQ)G$fMe;H^Sw2PK3&G2!pUH5850H`s zS{Kq5=Adeu6QowyqE2wOHbgf$s~3@U5AlqB=QnHZ#Ft)$u< zrH^U_1Q04YHXCP!Z75L7yk~70bq$q>h(dc$eb5KFR2@}3lqc$0d8%VfQFRl0j=V0? z$(!GhxY!9p>OSsP!|A(z=_;&X`7>R~+l-nkXm>27$4pg4)?wWmdU(~Yl|j^9)xB<2 zPAKun@2hfq(;(gVqjh*?$z--k!tbGyRaAjVUA{c%IG4*8WeFvR5tM_+88Ig zZL=qx*AI!C15~48@eG*9-uccjL3b6SzEms_$F6e_G7M>SZa-3ccA$o^%e32FQCiPc zKkhQ-H(JR1fb?9uwL)!y$9j?5TQmEwVrql*$?qE!pGX=Wh@w<1Hql&3+=?pX&cP=vy`qma6&7TETR`RN=#P4GN0IA2ML%8O&H9Cl( zh^j4HQRuv1#=het8W=gQQpm0*Pmvi>nK|KaO(-lLU*s=1@JQPcYHzz2j9a^~s)=4R zKRgI^-UiP;nC zk5pT=RRg6I52ClYEI)86;lgm}%x8Z{%C4CicCn!{DzA>+ynfP2+;c@2vUyH& z$6I%ulAJ`+Xq)vHriuu~U3PZGS}aAE$$j0xV_}E7uWzb=)5jfEmp|?!8{M=s&|KKX za;LDGHDcb6Avx*4Qlc~o-pd1sIjQZ#E!o^meN}mq8VjjZ&nUfaPI|796J5$FOizMV z-9_aejpUkp?;prx6Ky4ln42SO;_ehjUlQ`cX0rAzv$!KdRa01An=_$Jk*`3}K^MrB zcuqUFarp9Le0u{P0uMI9d?&#>;dPctw>tZ;A;bJPmsJODMTjAzN{&Rw)fp3{E7>(w z%iLs7aq&jIlMPx?9ZS$vqTN*YDA;CuBW<)-ll+M!a%iF<1#I2V$eJ?J(A~)WmNB;3 zt!>@^0C`hNFCMq;Tjd-bbK~~EBID2%b^WLtv>vFnHK?LVCV*^w@5NY0iMQ^rkfNHY zvY{YDl2z1-=0z)$oQshwpqK;<;-&?A;APTO=++BSwjWPy2I@(sK1p}W%T!5l3q9tyk zJys&qV9j39IM6g#N+1=RRO7tsSes=NBLQDu8@Fvm2Bt^2*bdFL)WPz2++B$M4dm@> zT4;&TIXM6Vn&GWpFO2w1`3cjm{S-5%Tv0M!t(A8I5(C6s0(IKBxC&`hk}cIm+zbdR z>1{m~t;^#~yphAsUR`tKUINUkvc3bB#>cF0eT3O-cHYGuj57yW#?@BBCzQ_nc#P6y zx=mFCj*ZxCv)yj%>ZaYe8%(3xuLsNzfVD`&8?pDFGAb_LO!hzIMq5R;pbe|tP_3#s z1d2;1H98^_0%U4?mRqUs4Z(ujxY&DSKFO{ESuM=Z>p;*xqW4ouqt#ei{FyJVn`aZ= zWGAWtGA+nkfS(&saeB6iw%~PFx30Z&BHAtOjl-nGiVSS^wYQGaOx8uLf++j0$Ib+v zg7WvM3u-Ovqt(UVObv&5{{Sba$wqpv7^hpzEZm)FQ({iD zaAa|85i@C;Du-?;7PMVt14RtZWNI&^uZwbqa-Le?A>1Z)P~8DQpr^JqES3?pf!LJVd$c$UQucDG2RWDgDH+fO!tOZW}B4o`>b=Vao1N8Tfsf# zP+o3p#k{G%7TsOlo0G2XuCr$5meB`MLwM-R?u*BFu1Y=Z@tfbBXR&QpR*krC+V(HD zmG+;hxboJ|jrtpE{j7+Vh_rAO(UGK2ku2V-8+IfYM%94qG-L=F2}Uo#qV*{ zR8g{}rLhTaRlTdOR4@jqpR`FSxh(;z*4g(?jwV|&?=BjPobsB}A%r#|?yZd_JkYN$ zzB4VOQhPAaJfZCW0BgIR*lSGAuz*`ctEEs?K&Ck|MHI=iCeDPZ_W+3|Qa-8fPAHXL zJ9AXsBZ$327R4V#I=5hZSo@C*%voK>kbrA6G2Axi#%S!kq~u~@3?)0RfK^HKEH8#n ze`fJjkCYY{FLVV{8_@Jb2e-s8J6BZGYB7S0U@p*Iu%x%%ooFlZ6qxYwcZb|(u+If!a7!O5&d6T&k+ER({TKe3$9g3y;IRz_&TQr78VzKB2MMQp-{FSt8?~F{y zzEr|i<=moV>6a8NxL+X|ljKiwE=3Zn!Zfw_ZkE>_hc=D@G|(?6z%w@=k9kb~D<&t% zY%@*Q%RHJ78?@f%oL7fOdxFaN-S!~%*K90*i``_FBgZT;3L0+8T6_!09_WwBbCfOI z7}_R;ecG|)TIE^P5U6x06+}~;Q?*Iaf34NHdYaHyTU8`GRBh`-=TS;i^{}=11~#_V zJL{8h^jw;Ym6kL{9OEI4n^r>iy1kW#Jl!js=G!!q;^n-P1~j55sHlPmuQF-dZr!iE zGc}>DsUe$DXlgoSURE~Cc-;vJCzdpRU zZbQd2S$m8pf&6KsC8QXxW6gMVypmY>e`-dW0@}9TO{?-2H?eyYHwLv>{Y??|4Wjt< zL{VHueq0};gKmx$(DY9g3Bs!G4xObuAg5dGYuog=&`49zU#QsI{B~up6?Kh{nbvsr zTBpclF~qW0yAbHH`0tRfFY3M1T%)rysBKwpig#WHkEm!zCGrTz)qf~%!Ep5x6-8t{ z3Zl3MWou~LR!}uw+&*O)>m5xi$`|kXVips zQAFi?360Z&ZkQ-FD!RIf@HU z$WvXTXECYfbj1ds)p9yRaOhtYjgdW}ev?`)%geDQQD-ougKMCE_Si$cL5%Jf3oW1 zYlwT-?OQS%=&l|G74`FN8Qd}(9BW_~c}L8vxW#7qO|`2nn^n50;Sjc?pa?dq(c7X# zuXXLkeR;LkP=+<-6}30q1t+;XL@~*H_TGzD^UkgnLyRM%V@+ssZL>k!wFJ~c_Fw7U z*y!e}4qvGhT}0W!@3bq6rWJN-t?rCTw{gl0prZYAzCLXXFA}H?6^#A2e7cOK+k1W? zigm-~fVBH6=t6nok*Zp4JyVbrPYbm}+6@=h?z)!l4$8*ah}KH$ylAcQ63(KxgC5(Q z%93ZwalM-urp~cNYc@&U+iZHC<_G5O zD1tUl>86TLq@Bu|HK-?h-V*m*yW+DO8RSt>ZB$Ka+O{fixemOYr7+Oy5GsW^Ki(-i zKx!Hl?aWqD%jLE~TzO{YYm>RWZS~yt(PU9x3^?! z=P1}z^T}{&t+WB^=OF1qw7^Rpk?5edvhQG2HiPL)wfv0Ghl3~~cWhSCnX*^42x zi)v*;+*fj|pbc^etWC47t|oY;n+qbR9TwHuU6O^m5F-k6D2PLB^wi%1)?#%fM2*lY3$Zhjk3mGBu8%)esEipP9heBt_OO(i}q190Z`iUc8p;9qCA`^Yf(L_~V z#Och;5Hv(ee?=>t+NKDnwyEPr zoeE$@$OPb1n^fj)PFp|-lzOQm4_8Dr?iEsm<|OvuOUO6GVw6wH*SGp8V zl}%B_xkqo-D|)MYU=w1Zb+{|xG^b;l2q*-`RK&$^ z8iG2evYdk$DBG~3Xwsi#DJ%)lQFhRcHIzZ2ZB)^W+=PZDDBLQWB4f&PRBzh5yPI_& ziDhpKxy9xf-6;_{vgCf4NZlC)h7a1gd<01inO2`dU`_TSsQoFfK&w}E z7m!;;j?3BP*7_-KXl1yne8CrPMe4c_r9J!8(QruJF2Qrpif=#KDbfqS~pXh;`CP+beG|FSRkqgVj@;RU=g>f}(0~T^rCgMGKHRf2jzy z76ODU8UtNkb_joV=d`WnW^I$k>uGySv{PXzkf`ILwv9yEA0+7incAD(&RS{<%k!9@T}0r2gg2-|ku38nQQTiu%+O zd5xI9%B*g{6I`NxkA|hOrbD?x!yBy(PE3L*mCXIMHNrO)UFF#8-beq+E~S78EV>qTTu#&Z(49)VjDVs_8#F) zbyR^kCpL&_8um?fSF&fbbUIN|sm!9H9apxO6$1?3<-~ERtc%+f`#hLIbn7_;VnN!X zY)P1jjaw5vx6wJu)_&8ZYfC|*Z&3uB3%<7G8{8K|_Ydm6 zw=+T8TbpNP8Qk5~Y%+lMN^$d;n=}zhB~EO%<&udLW9b-Qr5QGh8_2JbZq@Qj19F+M zFWx1k&OoUzs=jJ%=UTgnnS$7=g)5> ztHwHca)9JZ<|YjJB8({AzdS}nvT$Q+#1TDGbtx`>dPo7FJ% z9>PG2>bF${6)Ls`uq~;E#&lL77alFTv*=oS~WVG7b z+eK>cksdYfgh>N#112n6Kvwq*D{6n~Yn8RUaG72Jl48dTz~LpuRE(NMc?7X1IJHM~ zTB68Cqm{2rdL2*!2@|D5sCJd0?k2vW(slPv3gA>nCs#<|qIo9~LcqiV4Ni`iF6|iQD%`SB z7hUDx+H55d$1U#lb8*~Kj=1Z=a3-}eqh?`ssBOz)=+{KqhiX_9Gsfh?DNV>SiZ{?) z%dt&x9GNjw+)Bgp2X5~9^P>8uOx705XCZd9`eypy0cpAtIluAWJozJ0pTM6IRtlCK@Yj2y1&}{oQyXudtB7% zcPRdqNZy4QtS_5zB(?39HjcNZ;|&qqn9xuGsjpoMs9?<9ya?`G(%Dmjw#eQ+RJm-bWI!$LVtvEjrFO>GxVjMcY)_MHt|fOHI+2^! z`D1i<8`D4vE5{L!eFd|3AlfFiIv`ZAsUuPVqP+OGd8?LO%oTX@xSrx=Qp`SE!s?jbVnqav0^E2lb-ldE4u*_h-YYtXW&gB-~b z$H!RW>?xsZllR0~b-PL`Dj@nR+tC=GEZNx`gOg8f2mED{0z(C)cQLufut`SuqXpD1lXT0t_oyaf`3zu|_)MW48`V!)8u#x^muYiUlc{D8Mzv#z7OixT z#@mvu=3Uk4Pt3f|Him@(PkCCqqac|3QM@b98*n~>^& z(zd>V-li_Njg7)IrHvP{KTE!^(SgvoXpb4j=?t5w%han{! zdp^W2h2%!%(HP|JHKjz|=L?T%HnzY9h1)_jew5}HE0r)PghHaCrz0_k?bfH4 zgy}w%6q7bEZ(n@x9>&V&SlIU659wZEYa126kiONweY}+T{$S-Jdjx|q9G)|iwtH?E zI&pa)h>Mvqv&nifo?mTyHlLLu!^?m1JXw5C7GDp=m&5U8@Vs4oFBe}2#uvfyh44IK zeZR(6;;U>-7x}*v&Ddo8JH>Btms~9Xt&Lr!+jv{(x*&?86k8Pb&5=t1h1+VQic*;s z$!s>o$)}+j3Mqw7>LyUFx=-yb+hSMH+ujG;%K(o0NE9AO)|mt{##(IT%z+~fycevS z9M&l<)VAaa1DIPVP~BRE_vnB*8DtEJ%Ft~tnyT*PZnvNJTIGEH;B4ipXZHoPyHgxq zakiz-##+Y{7{CQJb9A0QvbL$rqS}Z=EvlT1hB^YDVS49%mE}7OSREDA3AfTG-Q7Jy zik|S|Jbm*iyrUQ6Egz5>ImdZ%h)k>Qxm(LOeg5LdBjz_)>_p#xuwQ+!Uwg1$ddIK4V^`g= zi|)9^_gq>zTu@#Me`R-fl<-X5?ca-dmQx3N!w=MpD7v8~6N_X{wxV$?N2=VZR4+ti z5b*eWiME?n1ZYg+nE4u_FM0-x-%oV*6w}*5+mYy`>M!kF)ccOfidrcc$&JhgH$^Fl z&|R|S1MpdAdh1qQW#3n2q-q&u-Hzp4N82?)lx!~~!7-WJfNP)Hifgjx*<8`rlJ+iT ze&FLm9rVKBv2lrAjKvuhv<$ZmHQ{$dGb*LGPk|U0WjTno5Q?V&6;e;zHh3pUU50T} zc=V;#UNR$hkYw>z*0bfHY}jjCeEPKUOG{JcerVZMwWF?G4l)SCSoqp*E-Tuabm+qs z6^uyL)-Co^jJ2jB+w2Wt4jf)}k2veQ%iq8F$Kvblw>g|0u6i716B~dYbKrl; zrT+j8O25N53;Z#1zrz(o;to(!i(i`_)@6r5^dZR5?jc-5fpZ?7oh8!hZ4Pz>!IA_ zVkIyZj*d?X<~_pvm|RN~mmMOwHT#PgW3;rpPLZ}Qxv`Emm~8ALxnu8MaeW^YmgSdw zgSs8n4RH^Gk%nA%AA5V;FMi_`+gW#W-h4MzQphV>h|0s>{1t-Ay7ow-f-~F+qkxK{ z)g*OJg&0@IQ$n8|6Pk;7J(OL`vy8<@Y#9XrZ4=$KWgR@h-aPAtoxr}y>~yx0WpoTstR*AAs}LP9;qZ|!rAxII}rqJFhUn@ z0D~hbmaGN8LibSzF{zyw(ot%rlvfRLA23#Ci55p1Li(B;x-$*qN$y&`%$DV38tX-J z`D2P(mq@C&5ur`}HKDHH9$ML-K!dtgs5*;!4px!XT0~s17{fTV#_UnVBjYWqbX8rd zEvi`5tqN|5=<6iL?p$kG11&o6O&dyyfIG@#XUDv=dmV7yiYsTzVgfYBD*ZjZqKKha zA03I->&U!TEZU0G?NVT8n(2AgKz!dHxpm$1$Yx!Ej=Kkj{c;w%4;Bnqr`40?JZ#ML9ol1V- zsVG73PU?f4(#`6D>5#pOJfzVkWFnO}X%5_>c`bX|RR}4Y5r{cbiK3~@ElrhIrfV8y zPrA9sJ}moQu1r!F%Rw7c)e<32rYo3-*^8yFX&DWpvQ0A^LD zCg$=PVwML;?c}zc0YJ^m$9ziXFx+2&M{KR_Vzg%}i)x*UR?%F0zg(s7#E%hgvN#q$ z>VA^Rv0UXF8|KV*r1E!H8#GlH)@`T5pRm`}M&UsEuBwU7s=`^DnXH(C&41b8Wn`9q zMS{MPe-XHfd{-3Bt=uuf{{SSpk|<)b@c#fB%rD3oSaLTX#O>GdOLhEO75rW${9+~i zUN!t-i}=$Q@wTtWc%hHIpBsendyF0`%I7J=Zw}Pgkc7p2l-s&4=y2P;J-bf+vCUOi z6}CW`7jXy#XhXR`1+r``dIC7pigc|_k*-agDJ~k-^BNGy?Oo{PMnKgp&5&R3f=j5a zBtk;P{qY^n#di3dZEvKrlICvv-zUbLP9dJ+(s;ZGiLI)eXDczLw2y&M=>>q^5C6|%;CR+gS@(+=(@)waW z@+Xk5@-BUUk@L&^kDXuSoZ9~YC1#iTD>S@Q%Wu4b;}eIq^3N;q+eYAgvxYfZx3Dje z(wj6v8@4Z;5V@jt?NhF5S$Osq~NskN2Q&?drT7`u3(ZXR~`;IOxaSDN*7t_pUU`_9Z* zVceZtord!@Gt;i#RhN=o*rt|U!<5AwRGa9orv%9@O~L)Y3byQF`*l~iJ6xo4em1*n z{{YAN0_z_Fh65F=AZue$wGBM%vcb5FrQ~DAF5Tl-R#))kBjEBp%Q28*eye{P-u#wl z$Z`HY%+KWx=|f8<5n{D`~1kr#jRBKaSY7s>pHzE|Wm^8WxKubKG`c&*2j zOL1x9_LiAkLB!knKMQm^1Pu|Y*cW~_F0W1KplNZpjy5SKXi>kmn{?-(=9Kdz%IGu> zRjS)m==Y~VwGX6Ea*4NclEg@#j&lLG+Fs_>rZqb|ZmNqS@UCv*xo+j$C0kj`c<69X zv~?!ONLxiDjCHwjc_F>KR_>Mm0H_M6peolLad5HTCwr4vyivl*iusuo*6rrVRm+s$ zQ6W)f?v2&%79FXsMpXG0^|?Pec<7xfnsZ5}qHDL9;&t`KoC4AS5YfdwrOULN8f!K4 zE9W~mgtCg>4CG9GpM=iIBi4C4F+%%~B*gWe46;# zG;Q*0<7HRH%P)?TOUU}g)Q8al3ARkW0V1I za96j5>D4HNY80JS6C-oYkBUz)J~Ltj*48mPE4gDf_pw~5?F?*uF0pn>P%M?KEx0#Q z+uP{UTA;XXEpiWPump05qc*|t;$z6HabH| zH%jM8uy`+wzTC7bQ3XBRR_WOnIXe1wsB#dNxD;`*v}C zuR6ZhoL_6sFScga+cRtJd8ObMxA0x4@s^O>aQ8@E>Z;LKK;+M`YmcZrk;tF2fs^2uGQ7r^A6n=#*!A9xjKJHX+ zrYZ9|MIBRd!c}jMwPKI$%x~ReV{b2?Fm!V`!HbR{W44iF-6f*9wPS`x-ORVAO(RTw zQ!QHc+y({EsDy z!&_n^ylhT~5#xs;kOG=yEbQmG&Ul6=BQKs~JaYbD*B)=Zv@VMK@`CdW`uLaL$CA{J4i&o-#$hlQjOz;El8rI@4 zH#w7!u(!uY7^+~RxS!*;XZD!lZKIk)-IE~sC;3mgklN0zq>@M2RgBlkaq;9WG0{hh zeWlYcBhF8@8*HG*Onko8T;`>}m5mGK8RgV z8Q$a~d($k!J*bhpc}%yGRU9!c&g9DkZ5R}ff+E|HR8UBnYW60^(4`DgUbV%~YLf7j z`=^x0F@m9OdzWk=&B`ks%YC(~xX1)=WR%B)y}1qXtCT!>?NTw;uZPI*U=eu}?uGP* z&UasRx~}qfDA~D3X}MwI>`RKvk9`^$rogYBK5rvh?R0( zBd}f`$l4+dOk!kc1(iD+DQ>}bP1~+y23S7bX%m}aJLipp*`?B3b(2yz42~7{#~*v~ z24gZNI9wOr!2EZNRvtHLkAAs4)s7ft{{SN6Y+L0v{zH*>*}VCEo6lF-y!CyT&llNz z?R}Td*V(-7eV5MH*?j4EWJVFZl9wlACJ7?F`itUIbUu91ia z)8fBX#f_sFBW}^SDubm_xr8QMMIq;9EQUtbNFQl52jxIT7gZSO59D^dq+d^({*>0n5#_*ds98HC*lyNc^@Z?`( z3~*+=UMzikJd^MLKcY}XHp(f7FcYPmOQDUZjoEI>9EyZF4>^=_408%2ImIw@3n_C> zlCusD8^tJxl|zI#k`ABW-S_dk|FFlf>)w5D*Y$c{&)4(yd~rWz$+!*{e#myTtx>m^ zY;+y_<~o%|Tpx^#`3*@OXHxPo*8D(T|$8ID{2%+~ymE0bhsctgaUnt3$cBSlIo)3G{@ywX$l=s~4w z(C|oQLhY{k+>xJz;PFk$Rek1$6(*_m^wjW9$Je38p)S|fnA=B%U9PWXZyywdp2cq;6oMW?KIeXyf7a5l zzWnm|yPeutP8j$5fkGSCRY?X%w!qQ^@FNzq*7G;_out<>zU>badPa9KOy&{?8kl=~ zZI*9UYL${QzggYLC;dEDdS>4E$4MjKGAEu!!v$02*DHhgCh5|9m;r0wEt_`>n5;+S z<-rWyw$MY*Mo&j9S3H6FxfeNndKsu$Rg#^l*}u9ZAB{A0WWy&p&-BwXuauh(9?5Cx zZhyU@J7{;bullrd&bFTUmwWQxPjq}a?&Ldn_4bzA=L6U4>tebK3V!?!m+sH|?Np*H z?dyjFQ%{{bLwZ8ZLu2M;PvEf*QIMEu``Kvaiwk2%f*W*;h%=JcP z>iX06<+)3%MLO+^bC+KGt?Nr2zOwFoCaeCf+s45e@0brGXS|6y23y&waRTQej3c zwGz0U5DZ*?@U;7ke{tb>+_`8w-?^*kjr?upr<XN&v>Yru}Yka7m7Ok;xT}TZc-1n|^dHw{ow3*Y|UkiDj=th~!Lu!!x9cFcc7PQoe1i|VFsDOxwcfe(=xTtjN#IzU7ivy-t^_Tw6-CQcRVLDDU z+`@bDf!?k!9+*n9Z#{_LD_NVN4Zo8#^f2GiF+d~v^_kWZ!>!>O=Yt;6eRYphpMsN} z>yoqs=)$M@67FQqr`aa1{<#y`J!iaQf*v34eJ6iU*2QpWH+x|q)C&-1p$!?wZIq>w&@89qLQx2Is>8AE}_TFKSFYjD+Hr|Xs znDe`r6W;RI>C52HdwI3oY0sBAKl7lc8b9yl)^h(|d-?Du<*y5Ox$E?!Cr`Goww*hz zG4u1ui7c13C`mT+U^yIEP4Rx#D(G-1KG8*fZ*{{fyD14joVW0b0^6!)&`Pp$s8n=* zhmj2PhWiQYX_DGfhx(6N5P$JJdvI$$srBvKjK;%HP=-~qMOt?*7j|=q;{j^e)^}tN zl<;a!Z+WnQsdlRC%VX}^sdc|=)3Z-+s0u8$2gU>>46Oa&7qc58G^}Gkw(Z}i-7{Mq zD7Ks0KQep?nFAcJd_Prg$K|a|3fDR}r{b;>x4L2e(fwpf478!@sXOQI5qa&;^)*HiXW&SF2!v?Jd*Gp$VygmE8N98T&9#4}?hoAl0nfTw5Gxr3VU0$u)uO(;y zR^{FkYIf;deVBBO-o**meEsy<4m*E#11m`#*GifKkPXk`p9m+ml7jm<#)jR?q?MWx zrDV`=tGPd2qZ$24z{u-LyO;SYXtAnLE7!Ew`)5tD)PMVnhpJ!XKCAQdjXQ6Lds&zA zMqkEj%dx5fEv9L=z4N1Up=I03?UtG$5&bD-o@NoylPkdEiAggQIa~-M`aBQ6Ex3N3 zdWGu|>Hi=-_vb?EVoj}<7r)y)VB~%rw3L`C8OgR`Pz7~)Yai_VY0SF%`DxByWA_?s zgm&zad42tl^2E;+e7$|bTsE{BCxd$vA8Mv+xQ&e)9=?cqmeHTv*eoMhV(opwQ7pb& zPhWsJ5HErH=rHo*wbF{D)-s_^+vgz4SI>5v+j~jmjnso@a6vG-{<3{FXVRddAoowA z0z917{IF#U4WvH1W#&_nn&{S87u%>g=V{F&lwr6atuSv?ViTKH&Uu1d``iztu6*Hh zIlK{ehaxJycBm|eVzK4MvIb?J*l<|z`CqedRWZ_0jHoNW zJ_c@B=61WIijEK7?{^FJyws`j93Z`tvA~~Qjhj79o~;R(M!OZHfsFQqmXueF%XzzC zr3+f8>Mr+CBE2cFnT5?uop697`XI$~z8HrH0-?rP$f(ydM+(x5$S>jTk^ zDBXHpaNO(8was51Jw>mJuUz_1@Xb{I;%7=USZ}RsV&jOOHoT~ub~%}K**mKR(jGub z6XHa>yCl*Q_8_-l7`+ToMJ()&-Lo6Ny&lQD(K;l1?5gaYBSi1>l4;Xl73UxX`Bfw# zLCC*$et-Vp?Z?gT4>>{mR}Hg&92oeO<`vni*FINZZ{IArldO41)qDru)oAceo6X0^ zY4n1WK8!*=_$E_`(TdHs)l>JI*i+*??`Xxb+i0Y!1h}ZrSY#-oc52Yv)(M*{%_1_0 zB#6_gK9HR*O6Bhj-9N>2aO~w||C(>gf1wf#A}N%_c(l8xpY!2K^9cuB({H)=4>(f} z*6G<`2`_5srn6yD`Y|WbZr$?g&Ct8z5?Av(=e575vh1h<6Y?A_vbAhTjg@SiJDZph zF&)=8&}xm1>6%>L|+EKSlo)|aJZcI-pemC838;gbg* z>*;RHY0R6qt~m8jWjn#{xc~9QebRj0@KsUM`80>Qe;16TI!; zdP}UjC~2wSB#Va{_^&iTURau!tAP4H+s+Oxdw}$ZJ~^T>yJt)5#sVG8uBU9-v^G5E zv_-PZB!4vTZ&-AK6g`P?P|KVvM%?ue&*h{%QCiP4-?Rl8>Zfx)&DH(AeLb_wakk=k z5I!PVaz$USusddBR3YP)rJ{Oo*t@VqyAh*(uQa^w@^y1>_PmErdUyo-6aV47L$O1U zvMFfTG@x~H-13KcmgAv9D?_|)aqH>ovmfw>*K$k?9Wx=s78K(obd&S#P!VZJ%m8HX#~ zFYZRD$5I8_lo3KB&5*Dc4F@3i{jFwPxnUIIX0SkJ^8G23!wxI-Gx%`v^^KlC?YppL z`_9s|^0bE6rr|-Vv+PN51wKI({?Jg|X_I<^m)vE9nABgj%xw)G;qQ)q=XA}(C+xlc z^S5E=oIgJEj~=tQ`{)uw$ywj*mM<;Gr>|=iZm%WZ1OR(0 z5L^%zHC@acz7w}NpwC}nETx1q1rhp3@8f;Ov%_xPHVpjitew~KvO6Grp?t#;o}J2S zm%4s5`TCu(pORkTdRji^4cO!D{t{80)*dqbzSsNk!%2;AhgG%@ApaUCXzYAZzjw6z_wGclR)(G>Bx>j@pZrk{0m?h*I=>~iLlm+s*Qo9wc&;*zBB2;j2=Jg5PdBXV&POoRLH!yVdLGJqDq(Sz>SHK)q-*FLya z*98Vz@{>29X5a@!?dEnO^Zv?_UdB(>&ggLu3Pj)IkG{93(OKih%rY|~aSXt1vt1K1D#o@$X0fZ0`1Z(Of;ewIR(|eoKh!z5F_l&cu{}Y>1yQw*M zpecBH?rqrd-yu&gpDSnHqTFY{vzhS4Sv1~nxg>GZKX2zqgJOJz?9A0mw8M9jPi=cr zstSPW$+NG!k4809z*qUH?5JGVQ}4T*YY&OK+W^3fP_!;Mt$QFC<62DWcdtJAt?w%_ zy&aGyzzG+nul?uy4($M@8t?pG){gJy+|yiF`Te}he&dsv%fN5Ld&o8B?~2Zc8|lJV zJOl4ufYun9owX}ZFg22*dPXfPSiva%jd(S}c7<}UGeFRqm5HGX zv$%U|^0)2v%Hw$lUz@SwO%K>lx^L4u2%MPD#;UZhrOi|=q zL)dS>TY7WyM*x-5*V(J7$yD8|6(tmgRTLsHA63-mHD{`;t^# z`jLb+*Kg+5?|vsve%A8cM+w`OwtV{2=goLz?O~q}pVT0Eex{@B%lZAx-+x!`88^GU z*P{Fl34U2Hb>geN)u4Jv2<2t_#_{-;CTd@cWnTAsxpyU>aTI^mrs$0)}|h$B*+nbBX;@hpsngc6zG# zc14H-A=3Rj4{om>>zgZ7y`gIvHvRB zoJ$g34`Yst#O>Fed35{d^>uHH*>CHTwOktQ1z%SNX{Tx#6#q5gK+1_ z^!wKVA9kMpRikwDd(0UO?sv3Kc75v89Y)s>IzFwL+(bE!E|bdpX?MEMpZiz;Yx2(b zq7!rNVePNJR(+F?fF2m1&#s64VQy8&8yY)Q2WcglKA^a_$q4~iyhR(v6S=cZUhamW zzY5F-%@@u&Yk1#JOVl5^Yu{`5CjJ*ob2XiRBRys6W}LAl-yN&4s|o{QJ`zU)kLa5w zKg$`=3Rh&<7DpW}EygjrZAkREQM2t-Azphc$eM4Zf8*0$dEop`NY(GNFJBM-K4-rZ zJ^0&f>#t(QHEjzaxBei{Ng!__-M`_k)LqPN8-chZQkzRAy0w*3ckApgWSe%#=l z$ERB|eiH5a{r%J>^ZhY^X z+o+zt?iCVxgQKkFAupqKLFxP6j1RvP%BzV?ej>pQ2!iRygVWzGrW4%2VBw2|x)p1h z3Sb}8f;%+@6)FhXeALsCLGjVnUn-q!Q70lc+k-y${B&sRRVi83`z7-t>|y>L{@wqB1DXuTWRe_8e1yEFchU8j!URPB`z@0im% zelTI?81w1##_m@l@zpQhOsgj}wKT2&4w<7pryN#Z_i;2E?a{u4dEW71j$6O>8=cCz zdm<&?_0DOD*rM;f>pw;ucT}ZU=DO=*21Z|NOWOOa-8mlgva8PaxJ9zt)657w;3WOM z>M3FY-|<8yw|ZX7RIUA4@%a$=GFG`LylpN8RYu@hx;{?~(xLUbaxtTIV z%!@P&PchRD%0GN_N2J-dckuq5pSh}TYBAe)&S&<|j!beaLgX`~bc^yo}T_*uOhIE*&Rd5W$C+Hw$H@qZXE)Y>+2pymK5I<5Kx*vaw{4Mw8VRu9az} zxiucV!aY?`Q4wL2hljcIkE_B)?x!KGZ#C~L_Fg{!zX={eUOpaP0lqCZU~Z+giDyKrn)KzLYIhswvekH17Rn_|$LJcjKCa zEeV3tS&6{X__6Zj`%Qp#wX)=)P{ z9CDi_R$t1g6bqEcE7oMX^4{J{%A{PtL(4jZ_RW zg^;me8N%#wiPnKG?n{s9Ygvo*_XDT$NxK_Qaxwd~yZKKh?( zkyBdzq=%c`D*<@pip(TBXfYH^upaLs6#f2bpjTYgbA;gLRPT@*we-ID{mQ4^W1+*c z(ffuSL^E5G?#F-ix{*YW;jElGvmCb-olmv!t`WFU2G#~NPNhxckv@A8*{>!qSCof( zK@IO(7c+ELFaKex)hn0A<3cf8F6D2QikGC%RgSt4#)DIWo3>Z;OpNxeoag8Z6|q*0 zB+vozuGYHb$D3^JR*2BPwD+r{bn%&+_dFwOBFnbZi+}Q7T)IDKs{BLs7d||C!2ece z*FAf2+uQ$fS%E84H{|Rk_ymqc_}k z^WInakM9!XUvFKGg&GMv^g{gzGaC4N*l+(l4_awSP06XA^1$AlY4pP1%|SPzc9F{g z(@%x>$=8IF|6ro0w1hJXl_F7ZMX-OwMIQ>SmR?z@On6eXahmM$Qrvp;kU*U;;j@tr zQb7jC-Ut~mYNgo*8=+A0aL{2X&t10v-^Q}d(g6uXUrQKzcwL`gQ#Y>%meN{*_bAEmcgKapvv zaH1DuQ$=S8)T}HW$N3WNAZzT)u6NXjVAnLB+Fzr0*k3D=iAjThKy-Rd(o!qe=_s2- zdY4&ryrBV&2035MKsxN3e;Obi%I5qq#KGFj?b(Feyw zubom;hNeXY%Xt0V@P(~;KcnmgSb-x_s+*TXLcpS>q|sI91zrA*Ms;_Km^NO6AXV6q zuxc@Yf3O835H7G_n` z?t|;k6&C}wX~2+eYOcczNL9!=csBAS%~s>51g)fk1*S>gbwejwXM|#;9}b7c z9O460I<$5$k$`>h|GhHW4|;itA2u_&MOeic{tOJf@MKT*tEFn^GQZI`oRlpm8aLc` z63R8t^F7*9Jq6t@1{GR%?N*NNCO~eISKd-A!P1mw1783bLu3hD^2G7_?uW=gt?UVn zLqQ9)03R#1{|vD5R%#_1YSV(N?%3wxqZPtqnPp7O<-Nx$3*u8NxUF~VIk5NaRc#gzEU zT>qmZ<0+A+@l^4!`6qHnJNv0-%#(ET4rQ{~-eV!iQxM~c2qAi!*wJJ1lM_bP8Y&Lb zUp5d&KTfSld}?NuG83xY)9DS#Fba~HTrA4`$_`Ifff{xy%a`` zMu%BOx$gmM-Lb=s3hGb(cEvZ@!4*NB;s8ciNf@!yqb`8h>DDc~R8sX;u8HuNKK}9i zR`ZM$(;prbukc4p+1DX9-)Y7m-rpElzWWdtTwS|F&$h?zx>yqd(`Zl8NLUmCUfyR^2Y%p)A zOr6jz!Z7ldW%R|~wn@-7ZgJ*+=@$GM?JKs!jTdy?l4> zZ{}@5w2+KXezOyCuU0aRu_p`@;uOeE4>0|l@4_yz_gK95Jh5s{XdYK5(8TNiO+-8l zV)+>@ViJoMcZ;YY`{Vfn_d`Z(4b^Dl$+QPAy)x>JhJSe-n;((;3dqOfg8ddEqJ@uUyjeJUTiGMXA!sB^SYof74vq5q2 zgB2yzjm0T5;K)R4u~+ZZ zUjYF8EHON=zfO0u$xmf$TGQ&$ue1_kH%8bCJwd(Uyp#wBoRDCn=5kAG|9jAT$OyMr zk#DEu4tiax3zJORX{Flu5WtXJ7oj`4YgFxTBj$cC@ckqbzBAa{e{V+=?E_Q^gVc=1 z`Rw<^P%5MNO)*PxZe|gEq_C@oBz?3YmotkST0#?2CI|0h+9WWIS6ruFo!L&?AI3zs z_yNF>sO60JsFhG9BS0*_7XX}oU>#G(_`~!n)eQ*2U(xcRsVaIpf zefjRo4L%c(f*(HvZ)>soQ=GRTK)5`i3tigN3(dY20&rawe@sNJ!Wtal;IO%Q34&j# zt3eq!N_A2pY{Z5v4HxI~H2fQPeNdA7?Ir$7sNm#qC+#9baeMeJ7%<^hcu93OZ-6l~ z`Rep`s%ttqsnw44Mae)kP3Y}cIpKt{~JA7nI3DTT8@Z8}ABVW6sCl$afcU_d-( zLxTdF2}leS>F#;JhpJh;ty|GV%CwytL`6CUtuFdJVA@n{1F&)9nPzPPotsA3y)og*k+#4>6h@2LDh z#372Z1^MVnQeNb)spR|zXsE6+&(I!huI)teDr!S<{gBb+^V_7Z6LmLaJI&iU_plqfLHFa~o4-l@5oBk%ggPnFj$%$ah7B zi8qNMDM!WW2&N*dvyAuT%v*s78l$rMO+EHj&Ql0@N}zrYMdGja{VP!;BO8&s54dW~ z#+Tw~;@|26A?SKchLA3;LI{h7WB9;>pJ_BCg|R5HP`v&1#i2$eZfjhn2krK9Ss-Jf z!w=VljRXjqoUjhUNYba_W5${qwo|b_F+q!Tz|@B4+NE`tNt8v@pieZ5j#x0Tf>(u z$(l|ki<(ZzSt&wz41ntjgDvbmGDH^{^EgCBbwYX%>nh$3=y&xr7#F7u14zy$g9!KE-V8;aj zf|bglq@iqGws=){6(j0;+8#_eiv{pqD zPCm??tPg1Qei07@04%KMsdyWA<(1q&As)$mgSjvCQt-YO<%6`~AW|Y3)Te&VT z$B3IZqtW9Q-OU{K;13E7(YVci#B68`z>tOKKuzU8ELKah(I^33db!D#%aZMFhd_hU z@`@#E;eyY2dD$`Q$9CRRf>?j?i!k~flg1GChJY$`V3gEn z^I%=)%ZBl(RC1HwuvfSG;=gg^c(5epv;xJGL!4)Aybka{|K@W_5()f)tJ;$*rfp~# zZZ;D`xq2WeV=cO4OrdLg6Qg6hAoVPjJ^xU18JZu+-D0TRG*yx$fV-@tUkx&6o3}^a zZz<8X$pJGo>Cq^v`{JuT3kifT0=f)xNXh;=nC3uZtcL=Pa`x0n3|_p#uTUwHnlSP8UvuZw1uNKLs2G3CD!($w9zFMbR&Ft?ERM4A@x`C z(nzHVrF4~YGm~q3Z5yMI!{*-QT@i&Q zU@*Ex?-W6@Pc#rMMp40>SCX`Ucn0}ssG=K?f$Cd}3W95*b+fU)220TN>-m52_I?GM3dbBAy57RP&RqrhD;4VV1O_)ufS!WFGLoaeI8X z6mqQ>svC~?#lq&iE)3Oa^LFA;nv6Pe)VAMI@jFWK(Fix;Uv3XOA|jJWhd1mets3jJ zi`4W$^A$w{HDuL2ma+QhoOxXg+405Clf4U$^K)HeY<)TtV=a4Ke~76qdMFWUc!^d9 zBphOG1W7wT5c4Z9Q?fbuGvsQimhh1g9b@(3ceJKfG@E+?9x0^$HIDyq15QL3yqP9z zdeCerHvtZZ>qLk^blyIJ!M{y%&23m=D%KjuFVoa8K{wd`uMxSHO|Z(F*S!?%ST#T~ zqEjM{IK4*o4UwQbaL;5KR4nb4i4>5K&J&xbnoUFz2%lRXUsDA~H`iYK(9FG+W?>7fG1iPInw%_HVDRYeL<3aP&pW7M87AHSIscB-ASrUrEOV3U z>{Lnw_?3?R>JWeFVnBa5knhtf2vpY88glo7o(Cl)2J$epS<-*X?)W3tCepDIlW6rZ zRRGQB{cp+HW;Hvu#OSe&!NUt`i#I)l)7ozTpi}c zinIX$F&n}hII>)r@x#D9f-MM0VG$_ zoT>9_*}%xj>PKCUWf4jsN?U+^GzB0VOqE0Sfl^TXSkOuF#Lb*r0{^apZ4KH)Q`F~VyqgvVYL8(e749dB zZCva|qxeX|Ur>Me8r?4m7`S}vKGV`;biSDBfAy2e+>-*$3ud?o2qbW-s^NxdA@Dc9 zQgK5H-5Bpq;e#~akHTk$@He1H393L>WC)>Vz@#`=qjHw~Kb}jidHamo8kj`Wnt_td zidHg2mVkzOm98B1j=fZZ>BU`jCql5NUBn1`Z|73Yrew1K^UZ!*QfMc?clJe=E(_S%WziDtXStGstEyn=Gh&_caIfeCMFKMDw&>f<{+- zrLj<^%hJ8tlOP0<)0`xXu`?;rwxy-$biXKVb!{|;Sj;}&nvFwHvGoLiH&jB^Y2IA` zfNWv*mP}X#p|p6NJ{Jav7cul0dIiVfmtg>;{MG9|mfwsK*7L)mpGO7!gD7Uu#5eGh zV5Sf{CwN~gk8ugGXp|VKDN?86Fyx6)K-uuCK_sE2kkx(J1ktqNr;38sGB!j8P1o8F zYGY4e=`l=fqJ1l5_fUcLrEmpR=%aZWAd1ng5b3N^yQ!B_6U_PFT}Xw!v&asPfXyZmOh`J=S14F01;7lI z_CrP^AtA|A_)LpSO)bN`uTf)+s~y5gfT;2yatAt^U{N@jujg4YofNh%e|IMDN1Xi;l zP8*I!87%~p74gweocn8_`|Ve6ijNb(n5D4fEwREgg~2p$yaE{W)-XRTZ%OT61S?-C zjqtL_I!la=H;^t35sJhODHdx$X_*u+<%Ob6Y^t#MK#ozV^kg-31pwih4Qy3-5xvrh zk(hGwj2a5YSbv^qSkrE^>nYx_Le4PgObb!29PI}5jl}9g(`q6Y5StAOReg;Tu9bs} z3t!1$%@mu^3oQh61O<*!v5{fQz69S2M4X#bwo1!4NU=Id=2VbX0AqX8S4oBrKanc&stPd;d#v zn(6#$-(JF4#CRqWxZ3~LDj$egX5t_GWRyG(5UTv`VFkt1eMlr(SW6QViGM`+A5ZxO z-AG&|4>$F+aj3N#ee3oa~=g$$z z&0mp>M(W}o!bA9ox*ns9Q;MB45;0|MFv{HVcjKEcPux!}Pe%>wvcJBloJ(Ug3)D$2 z?VXcQe-p$gYj(0aKr~RBtvDhGc`_(ld10>ou$vw~_kIoxuE#!-0!zwleQk`27lw)q z5R51ypd$dtUlsZWZWE(z_3odF29*-e7Z6@UbmQsp@Vw#k&eJyApq_%V3w>9UNSsYT65JO2S;jNOK zpPwy@45>XVYxnB(hySdNppaKt1JK--=Ed>ewH`|;LFwIbpyQ3P$;wPCX4OHoi~rjb|k zK1~)j5@%P-9aLpmAA`);?X4>0_AqFXA$M+PL56TTNTD!2CHRMBemK6-|FEr^YTnYk z9I9WVQ*0&&tyCdV?+qA0ZAh!a8blTQ&;Dp&bQKLCs|Og_2l6l70QXU#Pr-(LJU`3& z$Pxnt8;3(5MhYz@5p%X=7NTn!wa3k2WFZ{ozfhj-%Cx^|Z-RLuF zi8GMjLj64@M%oj_&)3jcp+L4Srrk!CQwp@(De7WI50#N8w5;#>oWm^8^AuK<6@*6r z$;~8bY%>W*LOL z=mIeD;eo1%6M$*|bDU9Re~qa`Da?<^q%|#!-`+r`u^c5=4)P$3%{Pykqi$TVkarRj zHu!EsX$?G@Bu67=>3`#0=sj z??lL33e7o`GSCoz))re;iP-4C^}axhzO&h4;d|2e$e|X8LvUjh%E__?GkV;@S2e^( z)NB+MAZDP};%rO>phdVBx#s-Ke4xT%=xF4{iajw(d2%L0OA>e-)*?=^gU_2(oa}Kt z;%AHzj<*B}Q5S$tg&sp#$!^{%Xc*T}*^~4FKM#T6;IoQyGM(@+tx}F==@M~dhN^tg z_s70&8;3&36fypE*cFNQJQzWKd{d09-uf`Kza40c9+c0Sd0|7qj!^Rah*?f0*`Zn3 z8uUqi z$JPhEXizJNP1&j*!-}Ck$o?#YO)v%I5R7Dd-@R-+=?)vJWrN~iX}3f~rF<1egE2x$ zEa@~Pu)lH2nG+3&8a)PA3mXOVHIuw62_AnY|4Zk-{Nl^VA1i0#(!6SS`>O!x$P!p{U;5))MH ziZo{B?_s?*Et&OrUQiH58=?gZ6=Rr@m@EE9-|fgJaZ7h6nOSqewax5O}Jg zPvbk4l3L_>awX?~1a_AIrn;w-(x3!D1ZB+tk~k`N8GsZTO%W%chH{Pu<^>2{qJ??F zTTrUpj-`x-NPrQ~ni}s)+c<-~7*NHYVl2NRotNJw?49KhwaK;eEWNcNTeRs2Rt=~~ zAr}d<6fJNY|3XB)ALQf$t)WusWxv*lC&fSReo>=HX#qXt6QHPR{}u_DX3oMOeJO{*{}XH%^MjfJZ+@D&*E3wetVlV zY4RYW#t;A4nXl+Rl_g@WU}$egr%s>I9%a2N9&t^Y2lhbDS!qlnQ+*&Q8n+ijA_H)H z5sIdXYU&m^#!^X={zK<|ebO~rcX&`a6-9>IE1H(g$X_%9 zq?G=scX3f;n#ryZ=zyG5hM$0GQ>Tnb+!O6j>{e?HnlGJW8?z<8aPo^ykZPVGP(TfT zWuBKWuHMl9G^(MpdNa``C~1rl_@+b{v`trGC{>l~KzWBn6!)-6Al?GT7e`;STv2Oc zgGcn}Ms1xH1-jND1Z>6vOWb_);vwpjnU(Vu=j2?eqGe%{J0)#{s0gHn zUx(HVCSq5vf1~0Y!%(+Rn%+<#pgVCfzqB(yi^>1BwA^N-MRGy90jV&h2O^b1kV$mP zC&t*~A07FLeFy=3_*J3p1jxrimXrq@Np5;?5MW*%9#=gWF`bh5!Vk5e)96>uSFkyC z?D8-d(}OoJQ)aL$U-_CW?Bhi;3OyN&>Vp{J7S?Trg6^A3@)+PF=MqjhDFw<;7v%<+ zA*=JT9xXI2bYHW*6(DG7ZVV=+7LO&;J?CGQegrhEg%B?QUBmtoL&HP)H7x0dnu!%0 zZZ8c4(+M^+!b6*2%|p#aH1l4uk!`VR$o$I*7c#VA8(!+ELj$rfT$<_lCrc4YuCt&U zJqvz#xg%KGP~YNdB`K}Odbq@&R&9ee_8|uQMIk+BV>1Xt#RZk!2PW|~R%tVOHWfKw z%RPFAJVigaIXB*4bp}#nc%+pfkr5p+X+~9^2u7a4a%Y6Pi}PVOke((KlQ(W5=TMXv zjP$E~1@Qk777)wJqXaB58t6=(D)b8}5ZJrmRBou?iI)YzykJ4PG?IRfa>3s8dzV?u z%@Iar2X3Uzqk!)|+@Fsgn~6=e?MnhKfIb>?^k;bnHM5-j$`EmcXV>OiS^Pw~FI+rh z55P2R;foP0Ef&s`LKf%gBGQDxbx~=$9A5_C{md$lNXJl{Ra77>5-}nOv|J}eq`9QnG-{zP8zU$pn_tR?cX{pV_LrZf#Rz(#nL0Qa#7tF|132{H z6b@%xKj*5Pl*T|TuyDE;XkK%Qj;FmoBNoER})QjeHY+xadY7C3DbH4+7Bw9(;`YZG|)|I z@<)^M^n_cT|ko z&Pxcds+MX-JkysLrcsqMpl=!$c2uxCg6sZ6cZbn?lew4}k0y1Qp+LJT!p*{!;e%cL8g!d@DrW3aQw z(Q-=L5EELzg03IQbNCfFZuy}=y<^4t2)7=%(p#_ChX6sk`aCE07Gt-%WluQ}B7$1j zcLYkK$Z@ObX^29riH3?^=EXmkBK&C*CqhtgoH|!ZbASThN6-OPoEnoDR2vKuf`|RJ z_M*6oEnMB{2f<3<7oC4_;aurItioMij*!0jMQWP zPXo7Yy%ZyqR1Vlbz)u3lgITnKbOF3v374mCtypYc?pO$1A{FMtDUXB$KpO`JpqC>& zYmde&8UQ=${@AhZap5xFNRR^+PMwI$H`{cn99Z5rZX{z<=3C7ADDbOX8&no8*Jt-~bwk~Py;&xMSK_rv7QR!9LSiIX9q^*;>cu|t; zBwH2&JI)Eoo?t_ztQm+RzKI$(TqnO+%XBhYnrWDQIoaFyqe&6~uxASvzDyKuDTr~Y z&V_8N0p-%HjIYDG;K%eyW{Y8~Kb(_C%Uj@edq>UiUz{oo_XF!@A)v3T zW<*W8JHeM;etrr%6O`S6_UuM#CZ#vKl|$8@KlwHa5&4B^g3dii>Nx*n-8{mglhAF3i258Hf_>t}@Pw`yvAa*#uy2qs z9*+_c(+Dv|6df^`+d6ci86(e{pG}tu`4_%uwEB9`O|PWKv2aVP#2;B>qAoGjd$j)S zX$)$j?S7!+vy!xhar&B}q2W=JxuLEG)sy_688IHun<&NxrQ9@MU}kBfAp8Ja*DG07@J=tj95fX{JDt=+k%4h64e?NokTdK<{y6};J)&Wx!MV*4du2)Sh zN+HTx&ahZLUWZKjgc8k)fj`xS7zj#*iLeiBcA`Zyil*LsQ2UM0_GkLUiIhU0$E4J} z`o;;UL$*w+m~^{e32c>ONyt(PD;ueTrW_}hWq%vU?)fW)__QVBXdqJwM<=^(+aKEe z()~SXwXj$w%j||#h?O#O%H_gJhm*5`1+t1f5gR6az(lPjxg`N^-~QaP-sElf8Co9U zr$*=3>cv`X#5ztOIYjp09_rhYRQ3gXZM?atRIu%3YyIo!_&w;raSOFyL_{wTuq$yY z4N~nXzfWaq>CPSiE-bNQsb-UXdA^L74#cfk2~74Ch2B@7er47AMD} zDzB783Ub>346kg*@Zq4PM=G!s+Q9`VKBkuEVfJ#@2E6rX>E}MmOBx6qYu$8XKn}(D zVS{1G%+h#X#_&c|-pW8;8(pvBqa%iCsS@TqZ>=Y_qL;=o5VY-hbdJ>@O762iNiO!k z>e93@U2=PYZzAu0JPc=1=>6^cT{I9Ds>zvv{PEy;M^&8{+WA26ZAMBzBqKV3pK6Wo zHXdmE@CffAKip{+tk^$Rrus1c#d6EmRK!nF9Ea_1G9DEl=--%iux{)`=r873n^X<- zG;zQ!18UF^*~)PF{#NDiQY%)_aL zO*!q!4imy=-=@DAgEWS}x_*JQr43{f_Usqod_>E^3ug$2R%eu*Y zKX0W@G&BCY>Wlhb&T~xS!t>}f6n=<0T2+WX)=GHpXEGd0@mav;ZaE#xB1Miw4t$5$ zRAYN8bk95_=OjFh_h-MfSmV6Hs{YCtHSw%$7DmYu8~|8&)UeL#P@clt*4Z;*$9yeH z&Rb$bV2wiShKs3->v^r3_-^!5$X``9n@HUNE~$heW3$8FWm^>RJx$e5DgKM6G%o!; zgsf5i5T=l1xzaU?I);jKdUvBd`3vl4GSz<~l2x}dBwRCfWWinVw&NRGI{6yGM2Y24 z(6zmSxyABW)R}C01pvrpk)|On%Fcj0_3#Zz=^VLWysYNNlq_*N-0mBfAIK_1TGXFX6aPjoA%!)qObf) z@owL07UYblpya(!W-p2giLaN%`Vxj{5_A8!LPP3T9Sw6E{hXcG8I6}kg{uNhXvkRg z{^lR-nu+*{9H;;BjKnq{YDw(JKdWp@${%$XlcD}Umc9j^>HYs7nb09Js)gecW)7t` zmqi(y#WBqGNfF)8naO?br$VliOGTHt#Kvr&9dqiqewY+veRynj$eIMdNb{=kpzI~$K`_`(^9zF}Q@w_0boV265FJw<<5c!#uA z%8KfZw#o1wSI|2B0|h0a(o(oN-jE-K7!l!HqRl_<)+Ob<+#tIW1j-Jh3l?K3 zcP^GCc<$c@Oc~H00t?)T1Avbk6IV8phQLRc5vko`^21l7##GB3>ec34vUZZR{_Q=|3MslTA4Lt6-heb?^`t0(kNSksyro)% zO}u{AEs4webPEyJ8V>wwC)$Z6sm!5`sxrwWdvCTPj9 zOK<0GYCegcAf&{k5Cpg|7YruE3Q5x9lvD{qu*n^*UkrnK?6;5y*$FgG_KYLW&|Gwc zy8jj!YPTu$WO%jmIAQJu-idY-d3+^>qN)MLkd#zi;bsQZ3ab&u6E{$T-Lpu~(91v1 z@r$JySdT}vD=-FLdDwl6?4D06P4$UIhK-){LLG2dU%OrFCjBy2pQuG@28DBs>q(a= z+in3*LXPB2a8~DJ|J~N~d$?f6S*mhcBzr$vTkVI>sS}HtH=G6OWGo_dTV5OY$b$SU zw4ZAtV9Yisb{=GZUA_O|Zpn31z!J))(`WxM&v%x4`6nJEjZ>0FYY{%mzf&J%8}6$P zg2j*D6^|Gz`hE$cb_JacpP3{kA}2K9G{Zlh6E|c0(T@|Ucd4|r(yYH2>`%$BR?oDRebL`Nk^98eGR<|a}Bf? z%I$8nwBQ3Q@w_g)oe5nJKEN92FZxPV8FU3_^X-XIU-$LQo$>iGW2Bfwx{sE6_c)+& zZ!CZ$+5pM+z6zUrk-a#_ebR{m+3K_?nD-$dvzBCG~I)lZecRQhZ59n3X)@a3yh z{1RqmBb+~Keve%mD;0~4Tf*j!kHtN`_P(!s`jloJR@77Eot1)!Q296zHU&B|S^yys zT=r#dDqT`)ypi)??Nlr6%JNmOIm&o29c8?4 zw9?7uf_5`pWRd>#rDvg~5+3xpK(2aYW)RKyx{X_CBf@f>HT0Re2QIRxi@BmFyT0rS zX}w(R+iKj-jy+IB-BT4`lDn&{OcyE z@Oj;C=Htsn(R>dm$Z&?mpwDeIYsP3*b(qI*+j3@?glETnb|IkOlc5Vyevu8h&E|iT z#?21W=Rq|issJTqiPwu!)H-b8pZe&yg`uz1x~tB&*^bog0Q1u&FJlBXtz6D@be(m< zP;Gef<&2ME{`(_v(3B!UoyquIQcSykUx~?Ym4j4pTaz3sF6^wy33OJT35La4u8ssv zgrc zFX(eiqGK49w+-R!Reu%XOQNY@HeG$R{W7YgQ(SkAo!nya;&|!8+Lm4QxR#qIZD6PK zYVEpBC*+&2FkAr-j)M#k5~bq`v|j_SpG9|G$?0%(Fs*h>g*IEu0tLL;aSvk938IEZ z-uQaNc!7zzMfo3gm#>2B0kr?ifR+g`{feN83d7KVs(yt5`aPvlVtJZs`Ns&uWKQ!1^oMFEG$jrS7wCaT*W3Ag=kVj53t$;XRGOLVx@zm^Ry% zd%bjn{(C4*aKJ+-Lpy2EW9$63wxEH1Bd9o?XuIJYwK!fYuD1_@Y zr2)AR4i9D%+EB1=zNNX$Mx(~smi}~OAsR$jf}2ZPp1mK{>9&z3El`iQP&+Nm$D7!h zU z-=EAn!3J?OzZyxUOrELdXI*Jf08#IVY!?F-@z}691CTC_Qs})#TKGZFjbi}M(+z_6 zVZ=+?b3pt;?_=-f$<-z@nU<6AuhQKG5h8RtYr`0PL;y})v^cBq85B1l^RyOdDru|# zD@~%glvHaGsGz(4?+y{l+PYNrXjT6sjK5v#ZE(Fph8aE?RA;I8 z)qT-T%aWYYtk_V4W+$5L8qAJ~byD;%)bhe)H+jmFtUD_*F9UAw<;Pg3lNB@iV8tKR zh&9gfTDS25f?*n`G>&I!^?Dy(xLdm>*k)}Xm(@robDa~lTLdiDgBzSYARmIj#5yRL zLBMUQ#YRr(w}4YA$2qYp0N<0)X=so9x`K;maF#mR;&JIRJCtL&d#qy%W1t3?Y~7lr zqoE@$A1|7R+P9mq_mI}8v{D^ceG6Btek@?E4>xk-xXTo9XHwkKYl;$73Ux_)NX{Kp zCojOBMh!}mg-SUGu8@1bCAmsjk)*KRn!I@HML-~$dA4j?>xfu&8N7m##B1Z;)>qIH zj?VyVvZp4#$uh^1^bcX!sfLULhozTA$IG4_@(9~Cub)jaP%_pk)jkcf04^U;pf^rF zQ3+U5NOuuIcYbq9{x)`^Fe@)jDB*5)Fy}8!RTb~GP@etMy+THEk|I19 zD^*j&90GLcbax=u`~z(g&7h)_H?pwZ$qrn4&QfG>xLhsfbf_| zU%6uhK)jb9>J+jNJnljrQL>mX>f86Fl0s}q#e zKw~Ob77L5PnV7(^vuj)S!%O_Tv=nRkUlL_?7_H$EII#K@B`7n~$)iryC{COr3ryJB zvJcBa86!2qYU*hxU5HM~p1%vC42aEu2(k!zdmmL@jC{$yQdH?1PyO3~t-dX{kfN67 z#{I2ZP~?5t6N8Z%wjdLZu9E0p-0~n%3$^f$uK`4-s;)rcy-l8rBySA72m}!x#1)VT zmg*jvc|MrV`1AxQ3d^7S7SX!l(|K@_pI4K0XSqgajd@WL29A=2e?BSM%x@1@&v_CM z5{$xNOdLR;6cAB@)j>Qkt;AYa^77BY7`P%KWZ^Ma@&5>S|0d5htLicC8UA^*+tScQ zgZ-ZT!yFdZI4n^6Gz)N`^|~!kD;a>J1L=(`E-I;FFxGH(I`y-3^_=!odPX>fbl`9| z+7T!9x*>252LN_7tVnepW!Hjh;QspAaNsVicl*R!H^!o=Wn*kVq1&`ry+&bH~|sEBPm*5!=Ag*1}6RhJDsehs*K_| zfIlU-7@{5;r~X-y7{p5~3L)usiC~K|p<=KX+v%{(4`qig3j^TllLy}SfN4lfYI=kUV z(5=&@va{VU(_HhiL+HnI$X6-q8vv8GAUdBSz(1($aDe}(aF{#H(b~c^cGN1U7N=Va zY?Wor;Q;1L1Y(UgB&nW6-D?!bKlq@COJg7E3-DE|R7fF->RU0tP=E9Ywg%8f6Xw&_ zT}d^M8~NM?zJVag6};~?5W&}Ee30RH2MFaUtIvJEs}yOL=u8Ca^TM1pSZ3S6dj!IY z!t@@t&Dxp8O7GLQJd`#4t%_{lxFFEdT4Gqv(Ymz|sg!1zzi~UAm|vBNx%mMAc60zvH#Ue*$kgo<_GYflf1Xpu*=JHUb;{f3cM9KS$rEkeRsFfX{RT4LN z)@CTsSO4}-`j>tgEu(rXjp$ypcE-%w>*9M#Kvn+ z655c!{tFVg4Hb5vP%!#n8;NcQXgr` z%tnA@(>Gr*j68)7xM`|JD5f;-e$erfaxdm)=&4K4u)ES`22V{712jy0G5h*)sg^5RDR$#W&8I~jAPr&l;* zPoELAuLUyZERAg|6;B`*r||aznlDebYm-h|?QS}s_j*fY$IkQA^Z84S=hu5A8WkIN@BL$m1J%H_7p#J6jhn=$KAQ8BUPJEJh?mc&w>0B(R=FylqTJau6v&k z{mHs%dvW@7zI2P=7b?|$Q4d*fiQmOID73!FFBogiTOx^nYR3{GyzxlZS5wZ&7cn{T)|1=6^xwNA!B(e5 zjOM={3DQ?^l*G~g`g8v-t2n)mhI{TqUr57y*srTRpE+jG$d9MK#k2%wAAkBKet1wT zVmuxzvD0|Jcj?-AU4ByIfy?eWTYokDIq#{@>DvVuVDowD>o3o9e!PAuxa-E2go{RZ z4^;p4eOCC-hqIew@821;8@Zc*iiz1H{pRv1IchBK&+n^yzrWZak8kU=DG6Kqc&E-_ zeQ2a*+GxFRi=%o|$l04m4CVrk#swv=_x$=B<6e~P)JqL1r6v5(YSdO&N92H@9S^lf z9C^PcJ{9HleN^kdmixEB_I!hLoH6-m-0R;uLJg;0PrcdFx~(JrTcN>w_TjGFFC$Uk z9y1Pbr>^eR#l1Y!c7MF@(l1M^v>>(9_v8B(?}7{Arz0P3&73cjlC~#MJ=FGO$T*?o zy@3Jk`FFnEoLi(G@7sR-`^!JSJdgVJvU%O~o5N>Z>+p{;!}ip7u~}dDcx*d+sqyQL zk)H3%KVAB2W4cUx{vH$?4;?uRrnRcUSzZ0u6h_ zrc0FKUuAh=!Ck_rYv~PN>e+Ay51}(t0Sxux6C+h_uq)$^FfoQUCMOn;$MZ~Jxc6ljOf=QGcO1)f8~hD|}oS9d~p!=TU6Mp~0*+eD(Rwt@yl zBGig5t^QF0=FZ(@;tu&~)NH=%9UYpWN}0(3p)@F@mIV%kI78(_QS7O=`7oQLEkAx| zaRK}iW@{2QB031`uo*x^fDZ0>lgZ3f8p;tHDKX69ww+k)0^42dCu+gcv zScwAn9Q_J6!MpE{%vEg``vK>;cSWo56XPc+PbmA9u0EaJAhQJh*eO+edh zDjmv7o>7=Ix-CW?L24|k-2x|YBCgt=gJZisITvTHFB%D#-_G1mcMxRW7$~{kK7Hq` z>Zpp_uiK-(+H(~(T9?Nn6mnW--nX8Hca7zxy}v*4HGF)%?oQ)K^3>OzGZrylT6C;- zs%6yOAY-BUD)HRAlLvy@54`#LSG}kI33k(8o_)XId#rikU7=iU-x6l_sYmkKT-iJ4 z=iz^@jnwn*n~$pq#GH@wn&0O~#(wy96oq_N9Z*m^7{2v`o{9pBL|LI-8i-_xxMQkF96EjM>ZU+4;ODg7sE2 z!P$yF&sh4!g+rkwW+%4--^UBqi^FjXKJ%-)2l5Kno8h-_&L->E4khQe#mx^-o4ZH`n)X}`!(<#!J9|E2)HLSI zz4eHkZ-VtEm+XedbwAu#kMAsEQv5ug-)JgB26ZgKCd!F<$O>l?rY3xD&= zam2t>eAm&Y^Z4>@4(bPUcU|haw)ew@Uth=T**p(V|Gn%hYaZ$DYJ2aeb2rb1{8WNi zdXtb&!`G$;YHfYGuyg2Ff2)|!za9K*OZCw3NQCgt=4!h;S%Z@(d^fx+{IyBT$o}7c zdC@;*@VHAFdtDg6JvOsbP@8Lb>G&Vp|1w*<`?lbp%)it|F6xLhnsdHxC#j)-pW9cE zzSNZW+OYABaNyORw9Q13+o$rc=s*-%S{;)!KD-D#=s)}tVsNginj|4 za%geCkGDj>wBnJ~K%w<3Z;Qc&zi!5co1O2yRiLu3=e|q7<%OopTf-XaWv{rM;}N|K zpmB!364*r$8D0>G>RKuTJu6*I#uT~Z{*mGjK_6RZe@knf4G;QQy55P}Q|RAiHB!8KJ=mb`{wwuhp$I<#*dfm=RElN>isC_gjrA0e{9?*JHm|}m*di{J2l;9 zKAwYNcK&HmwNS!6yPydY?$3t(Ee=nVI)mdjm9+*klErx??#;XEV?lLKc#yg@`=g8F zWDyBD$1jj;d7rZTl*7p_vj2OzQKBk2@uZ*?MqpQ;)>`*#+X7N_22#v=y*DeV)->|`pgEu1I%R^)qOZRbm1rQ zH_gzmSvtyJUo3efOwfTvbYthuu4~`lUhO<%_et&b)w@fju{Rl(X4<*$a!S%vTg5pg zDmUYmjIm`;AUc+dfd$CH+RjC&d6S4b!A&5vtM>j+fq1^&CvJ5Ja->fI@&Gh503 z)_QNdBInW#T{E8kWf?&g?|Xmmy{uX`a%#K(FEQ1%!qVp%>f;@Si{LUFdsJAav{8sZ zJto4T=jrNW70~2x+MOZ!@;Q)EZq%*45>57l!s3ly|7{&+n7O9k(Yp&%hW$768~^MW zJ%42=M0~*XZt&S%S~t#E4(dkS<=mH?-E$zzmy<#eHI{9&6~ELQ!-#5eC=Jc@3T!h8 zGCayWqs2^yoE3CGd#`F2b=ipy~gl$+&mrF7I|z_d+CiN2VhJ9C`X?d7Nq!VuRD$P-1ldRCj*;5JPYR55B>Olo{e5p zpxq&b#+|nHwAg-Q{pQD&fmPH@MDnRufQZb@PZ9LfXh&r4N}sN9}yPz=lbs2%Ur#AVJ8r{ z2OXVxt)tJAz4T*|Xs#@-#)g!T>R>Ir>}ifjG#?mvkP=gS-rn4ONBNpnk9cnN519Qd zSQzCU_03KC&sU&CM||FjVj~KMXn_vAP`}uTjQ}qDF?7Dd)7*KB>xHK4-1bo`CX= z)DX71naieRK6~E=jKfE!AKQCntg9P48d!qsu?t<<>`I@r)TYzDAqvLAyj_PLZfE|o z`M9|*1nn;J`|(&<1P>(+f1)$9XJSO&z0n%w)>I7(eh)tS-=;7BtSnWO@7n$Y2sSf7@1c-WZ6P-M~01Z z2WF15BS<>|vEv-QeXCQni*JBTljDE7fhouc&i4E>P_JscFt0U`s?vD?^?vB)suIQ1!{icDjl($w070}PFFz)KjZ|G@3 zGTWjcxWkvC(ixA-478Y-rDvtxpdkRnq9g-RDYrqx6}zL6D{Dx$k*kg>e|v~*>iW3- z61Cus)w=knz)+LU|0zVIR@&i4xK?pR?s#$ck|c}*a!>$Gy5xylo zkpu*ZqNENV6bkMM2fBYgt#f8HgZqw3*?Z;i`tzIKR>=X3;3o6KoYi@q()_B0WjKzu zR^t5e4KG)3?C$S3zx=Z!Yd1HW+EuNKg-0ujH;bpvrgj%o(s8=KO>G)Ip1rCOM%NqB zj@=%$i3eJnI}Pd=qr3kH(98#ct5E?>p?W{BM!FxFZM{ajUP9U~#d3`!6!&H9mG2H~ zVMiIUDy(JpdyvJ3$vc88Q{3;E0Nxx2)Bytkj|kW5y3d&T;I{65=(nc%$!zEaa*Np- z4nbsX_5^KRrPASC|0R5(I4yIU+0=}%%l8`z54tDa1+5Xk2Ij;jzWe2~jxyn+zbAJ_ z2VC8>Sq;CSZ6%h11p#l(uj#R15Jv}UZw9%09OUVD@;_uJ(b{1dvy7OffuXHQ)iRs#AAmAft zxJ+5o@>^v7y(G<5l&P}Z)55)`r7eZ$yoY?)z_%uB>!tusAB4!j5`IyS&k zvq{whYCqm1xfgcAwyWeL8u{F+{a;thKG)2>Ovu7LiMxjvC5YRm4U?5%6uG$oInY7g*uf zlD3ugsKae>wQJ$K8b)3CEka?XS84@o)vxQXeuO@vt59Vj!Sd0&s*CU4b|sW9n9TIc z{ubxy26tcB5gW}QAof(E*A65!>8<)-66J}xAwW=-==Y*2dI2ofKYbs(i?mb=#j2NX z^Jwj@_s@C7jVY#IfRc)t-NLQMR@GV@?OkfVXAp-LZvVo&V(a{km_HgjEPQA{8bv>7 z`$Ie41QwvDY^cN?AOz-s0$lR5*##X3HFsjLsLCU&uKCyAVd<;1*OD4n4i>%?91HHH z#FOTMH}_;y8?2^_tUbIM6jc-}v9z9cyP=|=1|J9RM8!USZ%Q^9k8zD_O^SLtENEeR z)~OD#kA=!Ha4JPw^p!gs6tJLLq#@)4-&m(FFYbWj{~*v(cz;{m7>VXJaZ$inHO*{W z`Ph7+iaZ#_Z}pB%us407XjrPT@B^cfQ?>)B7}3Hm6aqV*mmO+M{6OTb(d($|#;@Rv zBQ5&{1F+yzmd#iRd&_6jRbEA4Jr`yb`LuW!wMtUT9=v(%=Q}JTIh%+7w&)y}M4985iF1W${OsShRIdQY?)J^l0fv$(9wS z+o~Nhv)uSgf$x+ekNjaI?8FFvhwpPZgPx(mXOvKFHIeC`m5M%R(??ONBSA`uaC+~3 zxi2}uNO}}FB?+G)=zAqp1z}}eUZ8(i+>MTrKphU-Hm&S@E?W5P32?oL{ARLYIANNG zBPky!M9w0gS>=4;i2?vnC^e+HGA3@1X0~tw8jc_2+er}KMbvcnN<&59Kg6`2sxd<7 zqm{8{d&6BNcCxs%p=_TC6Tw}*J?C6zf5OgaUYX!V<1Z84msJGE+8SCDaX?O09wdAv z{$1^PuPw}J?wY%%bdncDct+QWfxFLril>tO*c$z-;9r*@GE zGn+8FiUmDrp1ulC;^7hygp5+Oz?8ETM4OC@M@n!BQ?(*umC$rERw!>JYJJ`u~ z)L&?zreqAGT|M(BB*1OEKcX4 zRY%k3bEe}-!B9yOGZrtig{Oi>7e1P}`PW3IaI|{`(mMDIlede050*cx!RJOtLEPVZ zT6{|@qcgg7ltfRUARpy0Sc9L}YmuiO0YJMLxSUa9>18R39-;pu7uMpUFq95M7aG2; zq5>J7mBNL2y0o5W2};hoiBw}z|NWy_GY3AGk#@zRheTK3XY&E-VU*rVCm{bx3uSQ6`KJD?%8c)SMAwJeqm5~0N--f%bqX-HvIoHK3e9KN z{B_z%!L)Kh_2U#+$%=Aseu;l$iX;Lknd0xM0kWQicU8oCpluSwyhIBLHTK=~DJfu%-f`@d)))8ix-b&D~icn_o z1m0F}2tex@BdYKMDvFeno~%)GzFjs)h`jiU%uhvV)~Q=a@B!kfMA$N)-djxaw%CjO z=gR_h);17WEpIEOTf_G+X-}WV8+uu!)WrIP-^DpC2HAxW$8+Y6DEA7=%Q~46Hb~hf z>N(o&yBE1S5?#8>yxJoDxCr>KS{)g#6@)ewBw;O=Mk>8$5nJRyRzsYbK~OLDQWD8W z(`;*O4Sx((x9cSRc30ZB6~}A9PKEBCnr)jcMM}c3CJzp@W(ak7pQqg>zvT z->i@`p$Z!*!4@t$0UWHEXClQay3WY{u#}neK^8VrN#=$Qw#4|x>M((Gl8bDF%spRG zlQL_SWD6PWGSj}m5?}k7NJ%)S-xF`Hv73|A4>@*ql|nPm)&-+7oo>YD+U~ZkauLWo zh^SnuSD5c<5Qz?eG7`v<<8`okuyLigY#555{u!;r!Pz=?y;#-@R1uyTE?>(m4puMH zESs4Qwsh6M&jxP97GTI2;Qu5R(dVGeMyp$u#S*LdQNHz zh*`MYe?ruto(k$+Pjm@|nMxFHb+9hAJ{{@{1r|kHca|~X%Y~rOAK)mjR1x9%=FPS9 zeG*66jGJ0?xj{=l$U7qmt=C^u6ul!V;B7WjPP%~S#8OoD&LX#Dmxl%d-?GP#=%@mU zRRyrzSj7kcvnK#!EyxJ4UO36#!_~3=JZraaR+p>9W;9uz8TQnFxEw~?%}oRqITx+` zw!d79d?lpW|HL`d<|3~QKR~(A`j*DFAP9Qp>Ifw`)h&xT#8(xrPrDU%{#+E78!n?$ z{W>7ixT}@3gJrF00^J9K23qOkvL_q*ugvmp@+VX`pN*04Xg#jY@V=ZO03uH`Qe6|M ztXf^Eg_bi!A&Jf~eMIbup4Ano+HrIqx^k?$UH~%yCDBV&9P;gAOLj}!TZ?E8ho0F6 zW6a4=Q+NZ#DqfkflAeSS$Y zbiVDj-+IQdn2OJI?-WerHt{6=^C_u|%vq49z8N@5q>yQk@ioNkiKYloizZ)y{XczG z8r~;`oM<<`*8D}QAP`>)iaq&F*?Z0fE9g!+eff0K@+IJMX=M|r+As8VA@VgH9;xMt zwN~`SN@%C+epAe{bx(quxa6O*>f4L^Lm&3$Ivg*Lb<&f_&U=S9K!Z$kcAJ7_u<16R z*3#Gr+iKirzzwG|xoS^t49LQ2Fr|w2uERC=IQKk_mL8XG+n+M8bi>o!V3eeLp5YlO z%eFM_YeB9QY}pBIB{dKQ$J>Mc}0JVA=F`y?mh@&o&Wc((*XzRcTMfOC~uB^mS3)T=W9r;aC$uV{!SD(r}R{^rG5$p>TO{s zbJhrQMOP?*i&c&Fv*S>qh~W7&kj2$#nj5H+-D@&X(W5lLDBMN1VxpIzA#NP2oXSD7>-^AmKi14K>Wk{ zr@3&5m)fZE0(By}QOJMuEHQnJQN=Yg)DUO__do^z_A0dAHG^b_whArkHPhlY>QaRX${yi4*>C6>e+G#ndH$W zP9OX^o~!MHMn0G9BmSp_Y;m+6wcUKB*^9xcR2wzZU|gok4VjFMTO{FGmRrT@NoxUu z5-RfTWkI90ON?yqJdX%yza{T@0kOAz@E()V3x@=07J(s^QG-+g*3}aRt`BVMo|Y>z z%7q_n1n`v_`O|69ReyEdCdQpd#HB#++&wSzOV;jE8$G2X>`hX~m_KXm&uq~^Y5RV= z<<`;8@84bIh3@376~7B*0yQC>?iGPR=a<}AQpqFVX^$YMSVf%eFqY&DH|s{yH7N43 zYAy8~c~LL#obC&FYkYa>=5%BtuUsb}*U<~*=*~E`P+h`YhSaoilxyr?-Uq?fpaTNN zQ>O4Abbj`hR#sBJtp4$5RPH=QvP{7F`>_+?G%OWwe+-)ehalO?|5NCHm{5R?5u`=z zW@yWE;48+_3any6SDiaiAI=7;y>7F=D+>=9Dil;V{UU4LEB8c&yHp@kohqI_qG(3r(jK8z)6XAFDA+Qqc@^#vn`GTX+NjSOh$qZv>%>OTL(;9 zpt}{lO54pkMezYujtgISM7pbz>;l8(w`GU87-*;Wmr1U%V|Pn3Z(fO+(3h?3xJsw@ zhHMHIvEe!$*WnTk+AvBSba#`~Fq_dQ9(Ubu^TBme?eQ|=uiK;_aD*cA;aqM(~S-fv@2 zW}EzLjMA1&)aI=wji!UTOl2nV3n*v@lTvmaLdU(Bk_0bX{Vl7#XSulUoi22r>~4_TGd*GO z67yW8&nmRu7MoXkGOA-CEXvSGiwUY79Mt=1vxc6GNDHiD+Q4>}X;+~L5-`HqX5pyw zSPOWfd`f~twzOQ!IkDi%AYp5OnqwF;bOB~eWTzUyTU>`dJSOx{De@9Zmrw=!1V$kA zA-%>bUGXr@U7)^SJV`o?PQ#~^I%Fxh@J09Sjg?r6aZ+0Ybv(G2qsw*MAR4*;17d3f zfcag)6H~)du6gePJ4Ey%6v8qlqxhAE3?RHU|90P;gR#!3_sdiCxI5+aWiOd<8eWts38zF4mrB?2jF0>kIKFJ&fc!e>l4V`(*lpS3zSR8|IT+@3apr9e3z|?= zv0xD^IG3sUIgb=ti@alfEkB9;KToR1LfQnpuU5;JSlT4~#VdNuH4qwh-7S~j>CB#| zxH46Z<-kfbo+%^O3bE5#%k^Opj&)Q#yw z_&B8)WFE^J)Q~UM--lc%+X*6|d8ND?6N0Y7&FDP- z+(7e$d5@LU-uK%3inIZ)+ddy+*^V|rXXfO{txWMePXDCIphEUN52(uQP z-qHk2ll5mW0^&jTXHvEai_7qRe!tPVWhYwv_pvl5y}zd}-D9eKU&|n&qKw@Sd*9^c zB@*1ft5l@v>rMa)OvO~Ol-AN#cXq3`bir53F8t%5FpYjkT^h}gObL38Cs7xqS53B01kwG=luAs%v&WA!)x ze6uF%dW9sdO#^lHAxn|!AkldhVT9DlV>L?N0yeMqHExruW(CITMj`Kd^vwnP)1?X_ zTUPPPI>UlW5Y33RF}EM7w!=AfXoCP>e1knr=we~0kfmtZ;kCfcQgcG=r5$M$e7MHJ z#z^og;=U!DVSH-k!PIMEu2XOWA@DDe0y*ZyuEIXwvQ@#XsP0GF<9?z69du)KuFG_^ zr&xhSZYOV0=5Aossx?q0)d`lo2GvO96u-=$@X$Mt8FyKnf&s=j<{2$HfA=bPu8xCY zo{t3$8e8rMy*i%`v}(8GNxMfn+TNP|u#_~)zlHTNj?P~4iJR_FBOm=6?LnLyECFR_ zS2ebRlUAonI^>(Bh?$zoc_rrgu^2EnE)Rt@eTvL3*K5o!3Kmto2f4#mF5Ato z19?t3`J8N2K32mvbzKUqps@_g#MB}w4zBy59jCq#_NKywug0Dem6SMPfvhd7A2KWu zIy>0W0CvH`7I`X_KazgDe;ZFcYlh{fm5fFyC*`4h3CF)BW$Pr6mBAFEvs@j-nCf8| zq%4O5Vsss{w3uIJls|)sEUDXai&?;G9LqA@6a2-q!D`Jv#Jg2cEZHlot4qF` z<}2jY+@2dXqv9z*g-T*|cG3H5np9O06m*HMZ$td zgxBwp_=6R5NLY0N8fp3DgGOI~QztZmTZg~D@MHJ{Y8#CEO44xY6V}3KLG|~u0pzH7 zz&~XBpZ})|>RC~$R)0tP8W%X+7iMHMCGQEyAV%5dzc~R9qsuJ8}BM)3i z+Y%>>ilt8ns~hw3uc&n(-V0FAHRw_Op1{BQntP+$Y38Qt6HaDdoO*D{)W;MOfaedDT>DtrMrA{!3l8CnyTbME+@dp1+fiOZBebD3Y&D(N7k z9s`%`^x1Xc)Z4)nL~D2+lV7dDXs?gXY49@;#1e4u4qe=qFyxtN<1j9M!<$(2LD;(| za-xJkqYu!R70p%57OmgNokUAg^POq)eivGzv zJP%x(E%_?tw0;r}e-~J|uaT426dbmKCnvUU%XJen*9P9?f@w6}>6J=et?h292P2!J zime1@2MV-e^;QFP0lf<_z1XELgV&ZfiEs>y4a1;6}rBDY8xrbXw%baF3;zdwPu$ zwpO5&%5jQzW=nj~!j8m3szq^~uG`OB=e(p(a=D;B^9nE8s3GVRPTT#$$Pxs4YIAnw zlVwi%kzv@V>dS0Vk`X9+QYRv~c!gWt)}6)e5fr>*aUa_beY!@CX}z&+uX%;8)|_L| z!J6z(C``2zLSyrm(voKe&`6-C2KVYnb9F-?Hd352=$o|WFr0fedaRnJuGyO|fe;Ts zk^zxGFDX@!q&7yd6wWAR*CuH@ktrF)WxficQU`omE6&Tt} zEGm`fX-4XOZU(joDoVIc%Tf#l7QP+tEWikw2v3MXoe|0$tpC6b405O3`-&IpFz6vV zpk|OX2_WFXqE0S9wbL2Gb=BPXO7&X1-czgh9rZCwaZBUnkaY~la8nfn(QL5UaG|ab zST@42KAWMA!14{L{?Rq%rzY^4hrd@r4w{AXWg1o2>!S3v)kF0an)<0)!pF`$pWbNo5FebEJe9CYS?m_4GoDjz|C?4< zUVx1R^C+^i1<#E;Ha7Mz>ilZ{un`jyvv$E&b)~f;!=s10#6{ntT{j!%U0he3=Bf)| zzO$`tI$2N?>+v>UPo4lU>YQ?~mk7gH2#T%K?ltAnnm74zm?gZ1OiBw_Wr~3+#S%b`;S*8*-sD>jCA_~CR4e6Y z)DMLpZ`wuUTigMeNy+L`N)^@J|)DR6}LG|thlcCp3f)4|j2xVT@%?SBDd^i=>KUv{Rpl%FvuyFLh z;gFv$->l}P>o>Awm}12!PFM!Bm%$52!NAd(O_$0S%21J{Y+y*@qgouS2s$VPm*s8y z!}Ct(UQ-V(^gEtuDUP=|oCB?rU9eWsFd7lI{n)YlhhMg>R5k?qws*|Mwz}@jX@x*yG;)kv7-l;HqM?89Jh+U57 zTE1$$>{*ee-1pAs;&K$aJeg&=G-(Z_CQp2EYHWx8X|gBA{Bt0K1MZFlHJ__MCaJGn z*@Lc-suYeadz}o=@0&Up)^?y+mla;=0Q{3b!lJ+NDV#A+CoCyj`McKk@H8`RKa0q{ z9}sjZQp&rzmeo4Ogd!hxY+tSfy<&f3hN_z3t(UHn;Q)>>cyI{>DPC+CZMRay;#haG zqfh2W|1gv))o?8j;*yu8I4b1dZ*V5OS_{a_w8Lvvaay_CpL=C;ijwqVi54r$pZtF`opn?jUHi4uQlNM#?xnQ26nD24 zw-k4GNpW{~cL>GZ9g0hEcP&!fUA}qV-}+dAKUgyf6V9C6=iGZ=TU4>)fG(Ajgtqh` zDq@2g+5km{nw4166cNiCt1v<7SALs<6fbX}y#Pas5c{%Qib{d4!iRcmCC@JeU9{e= zB#FOG)>;MA3bCXRN9AIY>tV}Bc7tXGzFx+fjR(|f7G~F6vS!SxxDirv{;_nBrpsEG z9n1v{%3lGgN&$Arys#3kn~TgYHuv~IE^CIF3?t}4F`0^dIdTZQasZSKPN*pS=S=^n z*)L}O#l^@8LMKXnMM&)*s7WkJVGhpPw2f3G(y@*T7Ep(U_Bu=D&m~qrB9@0~MmL-N z{oXgmjOMO5V7nE!cncAm`Z0r-WCN{`BH;1k7czQx&wNTUMH=86!ip#pkSp2tT`YdBRZ+bnk)n{I4A`|%{eVCC)6b`b)~=ZwJ<@&$upI;5ngBZzz<^uO zP{IZDhKj<_WG9L-B}KycM3co_&?|PhmwFgyiAu-FG0RnAoe>8Zn9+lk|0v3P13@?+ zkb&(~z%0v80)YD*O5ioC(J}LX#TMn|)d5;9{QnHdd_Xdx1MvyI$x@!D>ws^VLP}=w zW@erIU-bW|5n&nShfew6k0DcG@0~x47UwEU6{HoINg)jji~XYg&%Ndn43EP_T%3=& z^KQ?+3t%tN?OS93Nov{{@0BE*`99P1fA~B3zw8@sq8JDCxwJ`15^$TefwQbsBocLN zA_iSkYnV7#=VMX0c{h$LmBwexzg!oF=@wyo4ghPvq)my(_oU?cdzjtiJANStbTC*_ zC>NQ5v?wa}v5m=StVj|2>e#F}R}T6A;uu^G^TPOyE_#Y`fE?IcxAbVk!h`?b#VTwJ zkRo**54LKJt8THx^Y8sD7wV`?Owm}dw#9$pQHoo9cc%0TE4F)z$}w+SfL4&senW`c z?inbpJPI&;$-hs)t8t#m%eG*1py|;lDWs(!JT4E3r2X%cqol-VgD;KB4dJ^+ZtIHg z9_c5)%vqio|5)n}?APoYHo5O`nxW=$?{j}oPJ+RtVTmdX+DnC>!~O$80Y2#qPFkQo zkNO5KpF&Jiqy?U?I80RN<>Sme1wj9pd+R$vSy0q%t{Dr4o-&@%9E0Z_sG)!fvji|e zmb49*Toi?axj{ffm3HYOgr}`WC60<4aF_`1AjMNEOHTu3lbE&8f6pU4$j$z*hMe}K z;^0?Ef>vYsP@zwP3oQV1g%;-UNv2yu#L!&76qAPEtqwwIva*1U9iftfX7)jDAa4j0 zxdoWOsL!U8!8+f!_)OEm){y_!c|aXgvi3Wb`>~0nh(|d_mSpwx9z>_Xs0?7Ta*_AZQ>n11$k+aH3-V3w8 z$#GaM#{{}G69Jn;fUuBaBEc2@KecMY+@UOzFu?uoTf_&Z0T=vrs z-l0BQ{5EAkQmSQM`#2f|97Lo6lx8xm5p`a#hje zPqw4Vo@#)Z%jzWO?Cje#p9vfl;7^zW{vW`A0q-E>^v)H~1z(B%+CT<^nfP#zluOJ3 z1(`M>4puaK9+cXiw4){j`wR56;$W>cWDszbm;>naX#te9hA4s8n; zz?;1VOsKY+^Y*sjEAo>6ID@{lp_|w)2nkmJh#y)}HvuhbPxM5x2`B(&+8O1ED1ZcP z4Pa(N04&IjjN7NrvlLvC6y_>ds2grn8UQpwS^1d|XxRWQ4s49iX_*`)mj6Wz`huxH zW?(fD0syW585@7(u-k&=!-~QnfOJrE(xLELgBJ2%Jq|sJYyG7OW(RI%A>dB=m_IpG zT&AM=Kl)-p0D~_N55%H$RB&$KgD^ZXZMvehVyLwQPhp>!i?3`fNGpQQ!XYv=Qp^qk zFik>dM4%KB+~1dg^k?9!S@mH;2B|2JkU`!gp(JUQyKb`to<)O#1yZL61rRlH9iquY z4lHs0!`8!V$mG`IVfKd@pS;y9A{f$G3j$~e{h&!ej}##C>CLsFM_?Oh*H@JXOO+4G zC}-*dap81>w$~|PjPDbGZO!k!gkej0jj9Z0073Bh^RUHRTM|rhFc`rv+ajcpqol1H zSRD+J%_5?j#ihBis4S9Hd;Z0>3ownEIYzieT}ia$pfZ z=Yfpv8+pYvx*;xk5+Kcqiy?#=;S)RK3JC!*_%FIRSUIec-dm-lq!NUqfc$AkTPg-If!UiWW32~ZA43rIC)GmwjbMILADsKuh5a9y;`=8__ z-1ds~AWcDdC^TM?Wvlpdl7Ci-r=;x{Km-$Jv)F7#Oi{?JkhAcLKpH_;(o|HIkP-P9 z%osWyu&0_1paN)VDNAU*#q0t3fD2+C6lxhm6Cw#-7B4X+A!A_yLQNXq%LSCS;CVVv zrX;Rt_YTYh$w!oe7UotVU1DtI*s+LEnsQGrvYHF<71C~{A|EH^X=*0<)2Gwr6+R$mPx~QGO?iy~0_xjO z+(MHq+JxBUMYEMl0qF@XVt;Q=LD;2x9{Fh5zQfz&T_FV<6IUKcv zL|Euz{|ef`Q33MdlYy8AK#veZ+tyM(*zTetFN=Eu_fHMzSU!t7<=4wc zYvd^Wr;Utg#`{mycPclqe~n%8{nk$LLp0Eo{SRBU^S^gO_aCqT6_hH;xdu{{fGOp_ zAMHG1TBY4s@`Z+zHh&iYMWx+Z$V}b=@S*q2KM17#{O{~$Tkzky98Zah#)L0?RIi{w z+*$6rt6a|c>=*d|%Zq=DAo%v4&Kp@^R8jGoO!mf-uMHEQ+T!4>459KZJ~p=G+wf|& zB=%VqNm?-GrW*Dyl^vgL7iw0;31;t6B#;^L1^WTlv+sF=f&?)kO!7oU^9$PF1Wb-#Us9D$);$7fJKamUIi; zMSZrl=?prh7F2CY9zt$|364l~h@2_P9ywS{S1SDW8M_yfupI(bp|%VROqzFLtM5GE zJT11m+mQR4)bO%@MmHD?_^81u*OrCa?mfBIO|8AH)m^O(>IqM?G_KNy*JI^Wf=WBh zf`U4IPdA(^V}}{`W?1r*m;cBdS~}XEIXdc~Y&1GuO7CEZYSz|u_6P7JpRr#AxrIw; zj*lP0Y|G;X#T#SzdCmm$q|b)$MFxDVuSn`T^n!jqJ-zsbIHM>RJvx?KZ3*1ay z*L7riBQk9uPBlO~z7K?3|DLP%yd2a??|_fd6=7KY$(~<&;Fi^b>H;5;`;Rj;BJA#G znjwWDBIDd7Y;FnXmZR(8Ppdc+w0y1DjU3Nx%%ZnbIHTem<`mA=5aP-E{D!nf_mkp5 znLN1$TCW@RH3Keiar;r_ZUj!!G#vqoH`Kof=JqWPHzZ4H^J6=@ml&6JA27*40)4wM zUYDP~l01@ssGlNq-gp@swmYnW+#NrkV!Ipg#73QmdVU{pio~3WaJF!WR$^XVSJu$& z!aIZSh_eM(#?g&f{^5LR$dmSX*U-^9@pcWaF?r#B;Qw6t{|%`J>=F%~C?2kz{C{q= z+^)k>-2Hsi5{4yVv^piM{0eekUz;zz72fQTk;$ogU1YZ zdIhPyv4f?;OqY*+Y#&8ij|z5hPa#&XpzI>k8&+EaGYUuqNVN5r-I$$sl|pn=dgeQ# z=w%EV*rj0aY6CLzgKz(~-I#6)XLK8D(z*e0{$vkkF00jF3PH1d?+>Re>n^6$*xSM& zKWpV%j`0qjm-!zQ*vRT znfI^p&4TG0!4aD%uI;C;#-u#^VJRRL5d3kRht>)>hQ~i)tSZ0%yRajA2d?>i(USODU zEA5uiI33f|V}<aB53x;`ZrIU;<{TYAuY!#Z4S6HJnvs$lE94{Gv?#Rv9k z1X+117H&Bi*w=!GTt$UAXhkv{r)mck*%baE(2NLCM9h;6gCOs3@(Sa-?^QZ?t?fde zy7={IQPJN=T!V7n;;Us}XF-{%%{VdXX{qq78Ms9@s&bSk0z;a5iw|tDW>z*&GYks{ ze`P|PZ1RZ5$ha z?am3>|DD2R{WJFnjmjfE%ava-DWNBp$Twit;VmSqxXM!ao>X|Dj?OE9Rczux@1kKNIKP`UA1>yQPFcN9Fb&d zG6Ul>5KVK?v#5{TCc`Ppucy}x#rUvz{4M6ei)aD#&*dxVm_dx?gg0+l!VT`LhGghL zS&Niq8 zb&AR_e-f2m{{8ruZS)D#)!N+~gTX5Z+R&ga?PBg~fBziyvQBJUS-IExkKI8gC$8?Q}$TM5;qs)<6vw(LRc2$Y*G; zpexp8w5LU{rFBs3yo}OAxl_`-S^u|X`0LTC<$X|8>t7zcd3w)}-v68D-n;?kxmS?S z1V?F$_txCq+hg2U(17(%@4m80(^pU~-79Ec;}z6%gdAbfi(l2InYW0l9abxG6Wwo4 zf+7H~;$ryAyjEOrBk9U|(k2}IYxxxf@<0z9fD5+_H;85%>7k(@Jo}buP~^GNb&PJh zdY4$+E>&D3LB-ccks3mDmc~@&Jcmr&R>oqV6J;ly4|h$^DoKGbDd{m(0js~rT@ z15v3p8ayIC>lKlECr}zeJ`L+)8N)Z|&(-oIG?8lLE<)Q z9Y?)ggUh`}oEtOqy!}nk^R&&FpInw?QA*IT)eD9f^D>*#c8?~(o~6s(D_%`idGw5R z7IY{!r0?73QNT6#VK%a3H8)^VyE(-EvqOH{=P! zm1WiebRAzGE++_j#>%NV`# zqz^A>?rmAQ3Sdf6oD(w&H}vatLnhfs=qGsV|P(oQ(AI!=^nE+xKG^`QBQuTZ+HkH_Ak%(&#hmt*;>G-w^VU#~*4=I+j(g z!#3*qW8E~NyT5NrRo1p{C0P+Tk_bswzt?`-y3h6csO^d{kxr_(6F>I!scyoDL69W? zf<$~T%KUvV-RVBbor$?d(moeaS>jlLiD&c&CWE`a>pLf^(X7O&HksYo-3A5vk$Y3z z@82fEAG?IJ$G>a2sIA>%A2ohu45nUd`-E1>E7$iZO2Zw)GXFkn`zhWnnKvx{u@dV; ztvi}(o9XXgHTF8pyn0YC!!MV_e&27?Jr8M8Mw&V#dy&2>Gahk=W)P0!$j)ywJU{$7I`R2!2!d z(*L@4+bgJ1yuk3QMqRg`?g;v{ufWNmu~SoR{I}?8(am;E2>&V9hBa_`6sIkaYIV)x zV&xX|Lc|VB(v9PKMY-9Q`Au!zTOsx~ups~N!n`<9RZHdDrJp6GB{r(r@Tr4phtK5lk%oBlub?Gr7FT@DQz12(Pa2cv zCA)wRPm3NEZ7Xb9*kNQm5k3`fP=>rm$to*f!#gbRahm)Yg`2k~Z+~TdbE$@S`JoM_ zogCk&I`mh0H`_#)wKw$l>e0zv+hNM{!KfPR$M)-&6SkFIuYQQnEoU9c`sQ4--MIdS zl8j3Ql*K`JR!m?X1A=#UugY>em`+JhL|5!J3~PGKGNJfn&iSEWF#AwVb9;7AT|gGU zFSS?Wydu^c)J(?I#=0#33Q9E1-cfJQ+8y67JLQeQ`^$fPwu{ee<$QLeZZ)Ugb>8{; zJ4HQ&)H#7zrj9je7oT6%^4uE*k7~@AB#f$u2JtQ*Lc^WFm>?K{fNOXqlFk`pip~x9 z-G*2oMx9i1h^Tj${QQ*tH|})1ttcmqRWX(IqckJQGDFK+eoQ!vSO&L#U$BcM-DOT6F2181e4G6nSd+d?eEz4NxL;99fk@Zvo zM5Y$Ik$WDWFVm7DAr@Oa3DzTiw6`fem8g_`X-Bq~ex?k;3}N59&|+F(vNnaog}W~oIYdjCO@;TysG9pS-r z8(n&&xO7{=PwMNftPg!7FHB?9DpZf>Pg6PLOHWxA9P!oN51!=34l85euJa!ubvM&u z*!>+x>brG>Z9JeU(sYA4oFZ3s00o9MFlg~6R5eZ?>+KSo-_ykBAxep zRv0dFR^7J25-&|v*pF{k3)}dDM{125?Z}>HnVx$((`M6Nm@fT-1NCELt8VZ#a@`T0 zW@DcV&lK^0kJfP)1SqbvjP9|ZWB5)8B9V$e@|b;zU06A2NT}yc7JV0C57AatN+K*v zzGKj>UXpL!!9NnSp5Mz+&k{{N-C6ri%ELQ;UY0!V-P>sb(VZ#Gt;p4t@hDB?Zt&ZU zyt0mO{Tqq2<7*1u&7QlGE&-tMKccX z2;5$*=+~czUJO;#e=Zp(mR+=jbHCG`lc$gj9rnni4=0x|>dTJ3HNIe#-mb!kblCMi z!9Ojv7#uB=y1Cc9!?mpu{P&CgjCXiv71=zH)6n&jIxll3vA(Z)zTQ~PcC&RysVjrO zTUZ}&+H^42JS{klYUXzI(_(cL@$)f=jEc8TXcKa{kJSS{*QrH+eFqhj7GmW zvfnV0%d+1i?@aW_PnM6F?z)Gbrv^1sNA#n68SF2L@<)4;ja-qxPh-~UYo#eo+_7S| z_Z61Wbe!x8^y^wCJFQi2Rzn26Ty1C$me|s!iY_+>Sn04msH@!of@*Di?2+1v)uOt$ zuU5aR^Jiyd#-8?bMU#P-(d|C$N=F;5eQ;ncI3;m4&$3U8)Bvfea zh2%$bL~|cepN7cosk=7{j*CW}N%K#K%8?&m77WokabU@f0`DPIkz)uCD%qi&IISmCxIltmQ9(zk}p4{g`U)Lwvb03#97;(hJSGo1aL_X3W|X1=i=V;(!g z%Z=ZuEIWC3`@Xfexhe$1J(`;W>eLdc!#3ZhKO%m#YdmA8UeW&w;-YUg0o4W1b$+kV zN0)gCmDJCl!C1YdKO#s%BKTotS6Pw?g9sMO3(b?M+{%Y-@2F>Q0cTOyPTd+rNqSS4 z4X`-rMsw&b9oEkr&@#30p(E+rkZa5(AI;QUN?6QGP4QXNF~yFo=ta~$RP^WriQ2EA z8Npu`Yn)MePuAlf%ZLhZr?J*? zD6q9C`?M9%T=Y5iNj0oFl4jaCCyeu)qCNt&ma~iTQc8~ztu$g%8!MnSra#w&xqMM@ z*_KCw&Dz8v(UO%IbV@tq$u00H9ntw)ms)n!(GeX5tU1u$XwOQI=e&ddzQs`i_FSQa z=aKz+SEON}Kl;%3vXBF)J=Xssb7!v_E^W&}p~I|9spyHvdPTOs%@66Py*uOY`&eU* zq<@d|z#*;X*wBs2gNM;|F}%zP$7$4q8a4*KQ*doxHrGcib~au?*Y@7rrjjoQ@_Tu) zqnyMntZ>V9AE2+G^T8msJ?0*EB(A)C^L8-o71Vc+JnX$fwwsv#3WB{P`=Jpjewlj}8h()f5`q1|KsLj}*QPgvPi6Z$yE zgR1#+KVQKfH$3cX&RbidShHpW2%)^eranH0QlIZ1+#@wLYJ^dy-EEoytDkLRL?N7W z=k!UEubdSn zSlp3J)?@j(9On4*{F(EB0nS6lQhHQNC|_P^(hDQ9KGItE3^UHESP<9kEH zhI$`t7gS4T!i>*}G-H90=H708iAopy#Dw?XmTanK-5ZZV3+#1xQ<=$Bl5bdKsk}rh zvOi~^!u{0`(sGA3H5Ok|Hhd;XjX2?26?LJzA+=FkP0Q2lZ3tjHJXG*pgTX#Plr)WD2U#JdYkTJeo%YO3_n#mo8$=LVL5o+tnq|<}O z{#bN7hAmC!p4YbR#?Tgq^X;z~L%#p{(d6ipI>K!kpuVeshb1I*G{;VTVepePh5eWb zLM&uQV!;JLAD~m4*t2G9lrW^gFN?BPze+b#{L6B+HGtb%{R-NuB{;G5lNlKR*Ui~3 zg_96{=ODs0uHlXvgsnC#`5R}3t_+;i7R{?{qId7kgBw1irUC`y#=w5^TX}_izm|FQ z^tyb^T{6ct(H|9{Cq`TSrofY@uJKKxyBbshiKii8MN)H$k?yzq)(Xdg0QH8H33F_f zy`7gLrl*g|urZR6j$+WkkEfrgfBo7<(U^<5HE3cfDcmfLTgASS6|l?J6V8bcquv$? zZ=Eh`yxEgAZ-YIE=o6qNy&!f>~4atz3hWB~H~)a81)?+tXm1R)z`~ zBqyuV%vYaZ^wc{agT0wc$$?8CyG(L^Ig#HhtGh5B*>ccqIbzE>QmSPlYw;QhlbP(d z-^OkQ<1xL0@E*Pz3!Vt({4~7FW(+H_ID=#0zKOg`^q{mbA>^*+i&|nttthJ)zTbxu z7QD&QMG9kif1qYTSFN6hUN0hU3r5C_HPlWU!9z&C)gW>`t`}zFjf^ucFpFWUMPiO$ zGe@~WR}gXt`c6o!VXq`K<#>H0_gGJ%cdMA1L>t75L!e=Ku#hq6aBrHjq;nwgNVq)i zDs!S7XO%HVRb3-Ss52n(umt}QJ1h!gX_lD@jEJ%OJ0QCB(i!S~Hxm(H?792hy^w@R z+p)8^HrC`b48wU?o~wJ_ISy)$`7o zNL5D)wp07fSWHQ(pD(DRjxu;^f41Mh++Jrl$eOY*46%OOQdaf7)QDFFxi+&=O-v8P zm+(;4t@5jx+SIlu#a@R5wx|X_r1=G?&koDR_nU@WOa4+iQaS1!k0+6hhXo=j?WN{u z)-3!*jvs-emOpY=zNijn(z$xb8U12nV5;3!xYTXEhvTbA>0{Fz?~<6GBy~ij8a1K_ zy%-zJK(e#zJ+PG7NtJ1X{3NFcA8Ly?&J1V0&GRQCV|?P{NplnAfn7w*X;9~-f9Rbj zoMDTpRi__84KQ9-(D+et&Grhq8)&HwKGiwx?X{GeDn6HlEga!A?{01>CH3o%h|1W< zYob^ETAo^Wmo!Jt%Tw0VwI-V<#Y@`l8-ZwEFWzC_lO1OgJS5)F3ywZC^O0&v{#AGd zg^Wi_SU$OWXQ+N2cS~9Djj1G@W zelXWtbs9dRW4etZ0C?-HEH(A5AoI$LWafb3yEE}G+eq`oT=UFcHmcl{LtUZ087lTR zodjCb40P+N4*#@hoxHaSjN&>`7wM;Y`(H3A#;}Mler*5nwtzwSYNfY_lh4hIc#`gu zbd$z2OjOwueT1=yyImsRr5}2Bh%Ju#7J zeT%zL_UU`MZSPy>=O-XrwOS7!3Hr+9;=w$Ab4epwzhL(|DFl0>= zmhWPuE;B9Ok>`WhSS~(tq4eWXH2RZ^^|2XR_aQ?=zGTdJJ5YIbMKpBthj6HtOAb3! zLbjuEh#!7VYfDoL-mFj4W$&yTw)d?mwmyH2gB*Pn;B2fV5fD$>;;jM{Avd_iTvoTLbeU<|nF=T4I>MH*wac@&`2QeF$IQ=&$BNk1PjVN9ZK# zFS1@^FZOYk!b#>%n0%_kn5FhKmmqjXz<5+3`s!-t74!nIqqt3WM!DE4{JCIG%>kfV zzP|2Qo^SovX)oxp?xTcEbipy}0@cm-B#Hz}cF~{LJiL@IDNS>nYp+w4#s=Vfqn%8i zf4d7JWWga~vDlc5&7Ni~DWehwkKjJV#c$mwF-m8oQ60IK%AcL*#y$3SVFx!;pYZOU zS$p3YG6JLAqlJ6T^ii0?tIRu4WKZo~B-L=I%MMVFVyC922XX(6J;(aTmKKZ-t*POB z2pXWesCp{>eEzR9z&nb%mP~|c7ak~cngmDQ%PlWF>4+4LVjLPlp7OnBSZc!@JZKGY zwl;g@nNp?poGFLL-@Ndm@m;CYUp`ikb)O6`)eyYTAl{5pmJRYPWnLIh&JXk@Fg9Zq z)K%JGQ=-v~%tSQKT$|mb9QHORN(+GKaLR`gYM{ZG(#oZ`^rM|d2cCCXd`v#5+7k!|s)ydY93h`wF@>foy3#rdXP&N7_!g zLNxc($863G@fS4QR?Y8%6M0`=LCnuzM}WJg_0s#}2n50Z=xgZjYeBq`nn|qA0RmI+ z56KwcP(DM>H-|R8TZtIpXPvVx22Bw2lfq#EVB;uNycTU(oH^=-ima$IA%nUhkI%D$xc}DqO3GyS5kX#?I$oH9uHg&@4Cv=$L`X< z(1p1DU9?WsO69L$7bHw)9a`)g6?$TBNIYQ)-q9MPS}@*eZkRZR!y9aFFmRgtP9A!m z88C=A++1hl+8`lH_G0~FQ8v!{GC3OHQZD#;e9ysZE0yc6tQ`LksTvZ|c@rbK>o&NT zx@KZyg0=L9?Bn?0>5+!~oNC^XAxxYC5yPWt-j(+ibb@#fV7uo59hel0IWa;pitpzuh`_z0U79&2{uPv*;=6FDvg)F}3l>Jgx1OJZ!C*RbyDU4) zl~r84mDXW4`s1w3{EJPLQC94|#OJ~#!6SJ)>Y*0^j&wV53h}LFyVPRP1A1T9?$dYv zWmeSlD)2%OR~7QfvEs$vkHk$D2&d=LAJR&t_)`o<546Ce9?7Qpqbedl+trJw&JI>C zQ$(z)O@@3r`B=^*$lIQ8?wQSwC6s^H=1gi%7)=EJp|??g+QTq%HPfKL=qCx{nTv$0 zM|Zq+J!b5||Ffsyj}Q7_Gt>DLeu}cNNEF$XyO6QhgsCjeKFhbW$TE%F*2uM+Pyj8=5Zh&Td?Gs~1q&l^S4OYS`h zR>+Q#A9eN5`9piH!Co7y&&*hByASkeb=Y0wc8@!4GHm%b+B3PMMhnFK;(qymEWf(nDEd@S_D{FL zqlmMYbuth2bA4+-xb->F$$uOeA%r6~aalvif6gqi`pe7)#BBRVwlBURa+~v}p@7p) z4K1@dn>qUN1jt|ttvbz?&89eV6NVLI*|zcx)eB9QgTvoM*ut$HDGzkls8!vj*O3&j z{I0#qP2H+*3S9rVM-XwzC81Rm8Nfv(U0hVS$BO>-vST<~yfdf>lBL3x-_?}HJIXNE zX?@v%KNuhO1mxmXOMf}nw~CdSu;-k@wN!85`8dsnuOS+Ejc5_uHt+$G^(~mE;TM&Q zy;U4K5l#KD))f?r;Isbwv}+PJ-Dc?MPG{iHpW-;dKF%LmFUX%-UtU(naai^1wz|(Zk;qBzRz+~B)ZUI>rW{8oy&qTT>;eBoI6+xEB;>PPYT7MWSSHw+YtK^~wD~hB zlpeI8McXr75eBbLuf+vlyl_M5Uz_tZ_L0lS2}hg3E6)G}j|`DgN$x0;L2h`|aGOhE zRLmM#((Q^C7FN=WrJr5<0;lV{kjB36jM7dQ06yTnPi}dCNHv_YU7nZsMQAd}u#I2s z6?CSa(aJj(dUXsP`RjNxEI={woI6Yw%q+!SU+{(7%l?jKtZhbnOJ;EAF#`Ln4f0(N z560Xri2PfvHvVC3HNpwa5;Z6SkGTO29@zhJzC5YkZFa?gK4%8G0X4g{UO*=h zC{|-tY+=3Y4o6T7Jb}Z6cDtW1czn?s=H*I{I(}bP;W`gUEWGL$8gNv;%+U*;^NPTU zZuuV@^8Ji#a&*PcSiJ7T&dqO?=pD*E;m#dB;zxo+y_82e$C@<9KO=0Ox6S{ZJgHa> zJ^f`^UU_o=?~IhvkR25h1(six&r%BV&Dk!hweJWn``!=S1`lE-C#sKijzaQgPqdH_7hE>(Ig%lA{!#| z!mmt3Cca1;{z5fLpPP>4O?J_Un}$XMHeHMHGQ6eQL-?Drhn~E^shYfVzsH}Rdev+* zByL`l*=kI6wh8}z1FxHF5aGv@L`8^Rziv8*(gB?4*{R0(=vAe{ND5y2{|}do(gB}B zzk+u5f-tkOzh6#O+L6@e6$UldmX-6b@)NQtLtJ-thA7CR?z%3D zYDe2g@jH?_QT)D1N98oN%}MMmdJ(O8NMlg@0P90*N}%WS_BLdo*7I4iD>Ro&XIeoO zr{O!jyAzH@FW3>#RQ=g-3dB_=H~dV6?N&b5K1J|1jMw>1&8%ws$WguGRQoIFhs39o zR`=n;Fa%$P;Wx&=JxWmh1xxg7qcwtKjiQ$|Zo)@p2|tXQP(NJ;UDk6J7q7I&k=(@1 zkKPONF!!|CCaEsVP1g&Or@~>`uvJBhYvFVO56&#pWm!Ac2XD?~gVCOm)W~u_7KG0N zU(@V;wj#&T)}0Fc>y3?!82c!;Fm8hObj#f<;a3FE1?!yMKaQGk*$f~hW7G*m4mBSI z7}q9$)7Y|A_b6nxIf@J7LZO!(((}SX@?Ii3$b?;x8TO*CH4MY6rqS)uSx& zU9vb}0fuwkA|nnFgAtBpJJ3AoBfr0AXc635(SAT1vbct$U1gXC)U znelFemaNp1-L(|?kAV**`kCm}?m725g%$TPA}A*;;B-w-w3hE3@hxkuhC zcV|r{&IC!->H#MQZunN4el4r_okCdR$DKDY`fYa%Q9{6C=^*@?$_ahe)f zjmJhJByC|=4Clh``l{U<_!K_?x`SjV3;Qkx(8(c=ZWWw8B9Ej!QsXbORDnt}h=wfP zO!~MspPxwg(c6ToN#hNIV$WhnE1O&}hr;g8Z#8PO^&daRmQ&-g)U<>Ak_c%w846o{ z=rm?UN1qR*hPt`T==+84e`@kA{vGk#+8VIArFNutEshTE$LY~HgzntqukAl?dBBgV zYn_tHY&&P{uh{tqC0Q=z?Dh+gk))i>)qx4W`qf+2JDYqf9Ev}tNNRE`o`CIi#3$)6 zmp8rCw|pHO`V~nrP;A02Ht!#S-kQ0o9XGfc%IW>K3hx zSJIy#ExUX| zc7pI6De>MZ{Ng`k6BG$qzB{@0^8Vbt>_@y8&tYC0H@L7$1n(>=+n`xY0J)dx{f2(I zGVi;mF0zJB^#hmxS*1~<>&QjmRJX1cS77ETo2qp2OOv4?@wO)X49~14w7R}>_N?*1KlYExUgUE?ytprMdBL?+j=CA7Nd|t8l&)ALlZXh* za3h@PD?{Im@-pILC|S_bLJg#bE1mflu_U6xvR8diZScwUqp5Cmy$Q=o@yUi^(|2>b zLoKQ~i34+20gFP>%+RyWsLLRUq%;NV=@=LUH~5cUT<$#m$cO6cUIKzQaaTrva3zs($kWmM5N4K}Mj z|Jvv1Qc!nM3|ZV8gy1Bt(Osh@Dq{gVINAGUbC#(RB-B~LT1M)?WxtC9kHJ)zd6Jrb z4o~l@J3E9LTdvH{FLNCdNkK$^=e4fQENeGZI;RtD;js;VzW@tn?r2j`TCE5Wy+O~# zo7GJ-VQo8-zbwnrzmSdGW6-rau;s3=sZ;3b%?curU+!pZ)V3%X{9BM6pe?jU-jKuO zID*=J7VMAsJgcvbov>uHv% z#KIrOxMhpzPdT@O?v>llRqG2i$2((bq;$r`R!NKE=@Gk^Z2H!1ng>fuIU(L2d}CUZ z89n$LQWGPL`PWJ7LwnrokbV*I0TFkCCd4ap^damo5c6w((8? zb??e~{jShAH(G>K^`>C^+_lOEol&7UsSmGhw5ln=`>8A zQlT;w#>hapv}&#ByuZTufuu`nzM5;tylaaWo)J2%y4qA99NI#6Hw&hq`Lp2`SwJt% zvGljMJ~>!nHNCOO+k}_l)TdV-<-JSIa=Bc#Al+_!)EUaCEH(Xf?Cse!Vk=C`nSPLh z#{Zp*m96$qy?&OLTR*F>IjY(;TUxOF+WP^q_4)u0@+2}#8TP)pTHlv{a+EuEt3KM> z0RRO)QsXZrEG;s#wX{j+51_Obu=M8vsb70=Fbj3BI zGM(ig`bS65()yNq%$9kNx{L%m_pKM@S@|{&5VUdHwJ{X#p^T#`>si9__uCoQ`9_b~ zm2x@f@z4FlWeV@!)YN3e_Or}qeT4c&F!obI5UjVZMoIQtRz2U!!nTXM-B!%1+zdnl zK+`vFtv$-EhSL$5`>tp_iWZ^QXGVE&;Tv=vYnN&Mqt+PP=MM8!t*}20N=QvuXSfSd z50zgEmVJh_Lu4)KP<%Y(Ak~Oc+xuyj>P6WoTvnU<>l`YChf2GKMJW;w=&Z&1iyDmH zl!F6TNgB@FDH)C^~C3PrFNf~&(hKVyCDlcYU4>6hASLtjSg;%G|J^jOLD{d{`XoVDBWoI3;7`=GALDeTxH6%m+}zQQ z%Z0rsL8>WiOU$f0$f%PY-xp4)&!B2$b~?A9yk`!N7MEuG2Nln?>Vv1@pl&|=zxVOS zh>KWdZXFCdZ!U+A==F-JhqsS>S4cF7l6{+gyLQh-8Wk8ByShJ)HT;n)xc)_!#nG|L zX&JVCiG(tiyC2o{+xTJ|JF1CkfuN0kv?;kBP=h%-MTh662gb2=It{;kQ>S$A(9`pv zI+CrM39{r{G%)uE4PcdOffaWz){QCkxEquWMn*Q<;KRRu2(#`KNwZc04L?1K!JpAun0O> z8_al^Q(5g)ddw4)p7P(i{?i<@LE<43F@Jlv017n zK5v?|){Yz0!ZnBYirQ?wq|#GN3?Xm)(LbODH3j{t-5K?)nQ=#a1({49Jej9{_YcU8 zMKQ3$!7i_Z#&C@?#+G!n+?aJA0J-Z)@^ zvEFSi+Res(&PZU@R9Of=TNo>yFwPb+Uf)4wRjV|}w`qg)iG{0IeEvXTeCRLwX8r6h zCynniOdJ`dbbr`+ZjunUE3*YTh^a#s?dF%G8 z9)LbmU{rS{}m3V^+z?>}8Hb`UmAOG>7#% zF2V5LzVlg`G1>RYeiFPIG@6wZ23e$DgZ%&EHh<^-4&zwofo-;4{dW)9KAQRmM~(0) zye~(eO<9GxkI|U7Fsoe#SL|SCBvu(>GzLvNVO4w0`!j@7n6ucdEML#sJa%@T@l`+vm7)yW`FM=G431>k@sWSZsVQr9P@4O049at zz3qKGL40LPFMWBU{rrWi8?p0qZCj6li4z^<11|~h2lq9K1hfs6tYZPnnMu3sufci% zU*p9wIXLjsFO10kxd#EZp_<5FCX`91nAYDHYBDzObA&fX{gICIEo#5G$pV!zr9m<= z0`09Q%5`ogrgVUqVZLTVs|vv#y-{<@DB4Six_}`y1X$g21>Iwg+U583bnVYQ9P2!y zMJAruAw2$6rRqs0)#{da3Wk4}?*tC$+MITJ0x#97o3iLZ&=VR`tonJCxs5&xQ+)fl zH?7P_{R9;asy8Us=dCS_b%LlFfyMq&A#2+hz zI(%od+Tj1k(RIeN)xUi@P-<0U#pp!ssy%A7q19R?5qs5&Jz^KF9YtG3Q7bVs5X6YR zTRXN8wQKKHwD;rxygska=bUq$>-U}iQF;Bnwr!Gmi|cO@oUmhF_#f5PWmq!aUg}wV z;?=ay`mmdbjb}<*0k-!BRw^|5+X4t#!|dBZZ5^}VwC)|oc}p_m^hkc9H79Q*q2su? z;t6T;zN`C`H8Lr4#rzjs;nPZ2&v!8zwDL(+%a81VWx~U%)2}9*CD=>k;~p}*Sa(ZN zxRQVF=f&u(-u;;;=2B#9xe1u7d0j`7+%4F!XqypNV3b`LS1B)O`_0cE0jx_p@@_u; zseXVg6gmcAEH&@5+Fq1qwj#7U# z8SLC-v7LDu2N*>vpHm9|G@E6g7tBs<9?0e@rDZ_g7i1}lmD6&;|a5Rv%;`KX<#!-)1Ufq=BfJL zA+1>KxoC6nT23ZvN4I8-Ul{e_+Kgdls?8VLTbjJ_JX=041gP84MMv_$L}O>yH~48v z`Xw@#d>~Zu`eA?E`|xbsEr+FS>op#8wRT)+rRu&>V5;6@Uw0+|<0ve@r{6b0thfOj zS}FG#t-KT%XTCbas{wSoonEu@(E0OrAT`SLFU$iyb~gG8j5+$*gbMZb*4JL+wzM*) zV&@Q!k`PJn{Gd-G8xLYM-Z*%thJLdD&oyMd@31+OU-7TEUVl0ZTW6)-2K_lH`^VgY#q4SN1#eUDd^XO4GOh07Oy#s zyPD1XSN@|~u`1=i6qEEdo2nZAd+R-apIFU z^tywpV%pMO*V;xjvkw1@K1ZNrJm2;$rh^xMjC6mzswyak!F_T!Nw8wf?77?r7JGc*(^Zbz9PVw^wvB zzE0@-@yB`j2>eGStiY$okR#oXTAemB@$YW)0pW0NYh1`uOFLW||E(RypRK>`=ao{gabHiIyUACnW{ma5qq>lK&#qQAn)D~bLHGS}T}x{PGQn{^ zNhYiMS)||U$oV{cmc!BJ(jWGl(~t4Sj|Azh40>;F-py#<(_x&LUl0Fm>mD)e5{EZ# zH=d($YKA6zKczH1uzK8~lb-^P5p6RJw390k1P+?cG~WEBuzpW6RHi*D@8cv%FGlHp z`j!iUFm1Tc)%ud_H+L)vv76Oj=lb?#+uOX!xQZUsfE4Lp>NtnOm|Xd^?N1*~t=FU9 zu4WmQ5_v^(+IqU2ep5Ru(GHY13BK?nYK6p4$-YQhXt*Hg^gX_CtsLMUjw-@2z07*r z`Fl$KOmJ*dk$9-8k|~`Kae8g@*u^5jy|Bh1XT+pE)i`Z_LYv+=cfjz*v8RXXTF$o+ z7}2xh@4HvN)5s{=tF{F2`uM!xP_yPI9bTm}wO2sYXG{9hce_Ri9e&b9C`jjk>2$d744dzKdhd=usLVOy%#@d0BY z06Ub=XEU~DWDr8KPx42*mh}3gHi4wTUIx!_In*C=*3U|gjuD2Y_qG2~F~+N&II038 zU<)_cS^V{WWTt(a_tOjo4wC%%W6Q`U#zYfSQ}eS)Q`d5#@?VMC#|t9@TGApsA1-6S z4pdJ2&oz;a?cbWxznRVY7m~`VE`3n91rLQ1=Z=za2XH5MGtuEcR@P3>RQetX`0cG% zR+g3h972i6OL!Y7?zN%l+Ave>0i6`u0zd#Tip&-`EMVR8#}wYoX%d|3 z3oFKv9JMJdd$EkAO`YLD1Cs5m$dn=_{)TQ6v<79F@|0EpCZ+xvcjvS?OXeJ`ed7Aj ze&-)Yo}9F@vx++9LI{-RWJi;$3dQBNRFs-jE&%}GlI!O(l-UN4+%tl$-)uS zejm{9Hy|$D&<$rZFpu+sM&`C+Mh!C~=2okA;g3DY_%gfWy_qX{`5{#ON)b?rhqTp; zy9v`{0AFKJ2%p{q#?x6X`*^RbcTj1Ye+J9@CKYoqz5dD1(|LYi9=NH}hg$pzv!VXH?7aV$0b3zdF4HlEA3{iBh7ys#)pJS}p`*ZRx2s7_F8i9xXhdnQM< z`<;ln8QAgp`j574xgWTXcTN|nr$ba5e)C3^wA|#9&7`SN9Q6jx_^9)KJym#=PoMls z2?E?2ag6F&iEwk7nXy3ait0AnA_!o>^(T@$H4aOty_mtUNJrt=ZS{u#sPaQ?_73I! z<%aJDi*Vff_VDP#%|U6yak_8rB(TRb7U-1CIQxE$4tO2Io^j}00|K)ItP(l=8v!88 zgyw7Qk2@ubrzg0BxmIiRZ#2{ki9Cpu7OF@f3drOb8P1LAI#r1TBU_R@S|0wC+fv#* zQ&$v(;+rKtToWDOymlqTd=Xk6VLqANggKi&-;m$D$g?)vx58ExO8% zk0al8Wxwcupf+Yx2c2s@75V<|SM1ZU2pV2k_%;frD0+IeX?H($!hG*Psuv+dIYfI2 zh*lC|{JJ$V^-Xk|i7gPuEe_cdqOC{R5pcpUCl3{%?^MyP z(u|o}_bN9q1A|U4nVA!sX=5ZzbR+4|g4x-MI9k@`@GHL>OClPKnZAn_VQ>`mMzRza zE5aCNxhF{I59&5{Y=y-lyO9|}zA$5v1~JB;7rmbuf(PPPK#BOayeb%kmlq>*Tr_nKPWxs>@Y)iL>AWhNVyqdM=!`_P53R4777r)VLeYF~#<)4$VvMUd(CW7mf~Pw7k>}q)w?kg3IA~x~$WS17(Nj$za`Mm|j)b z55*>CA_h5TTL+c)FejXP4Jb&1``BJWe`ym*$yql22mD&X?e+YpiT`3P|MbmzGTcw7 zmO&K@wCUbCow~E>ssD~EEOSmO-Lj~8f%^&1fL}1*&F}nO0ktExuDc)h%9sO-Y&ddx zKeCo=s&d~^CW5LMW0(@<_3!V4WW(24J(4V~MxxS%|T^h7lVZLm$_Vd1aBL zKmNZK)cYEMLwzgU0dHJ&lO>$$o?@m>^!aIcRi~!dF89`lY99?|C6rilHtRg4B@S~A z^?R0}oUIpP!*5esaU99EtexND2IZ)ZlXsu!$gUQ(-gK`;+!Ir9j`MZ@!@)Y6(3{#v zmH&s%VqYk%J#Ar^Ms;(+F4QXJ(!etjbN{5IoIdZi+NDX03P#Pdu|Kfr&(Q8v^E_or zE!tm@Etis4Zt9mI3~7W7M4`vP4w+}N7*P>Ab5$wk#FVSBJMj>q9fmj&r;Q|2R)lOl zBZTU4IfJPY-hQ2Pou6A&1cB#&KhkoZ4gL4&Z+0v+D+uH2gVkB?LWxrT%*eX#6}Db| zcHcVps-_^66sY^dTW{E>tA83gPy_gnisGnH7gp&pmBgZdkZt?S-u*Nxp_~_TD$INe z+*inR+w@0ol}ss5qCPBr;r|zf`muoekBVN8Iy24qcFp?sMf}5mcmLUtq8((~v0yH# zMM@#Lx4{P7(gbW@tO_`maMnH+(I6P{0(&|gGB5_~igGE4PW5FC?NUPgo9#(>>AhLC zE@vG~v_b0GFX;HJ%da8oEVO8I0(8D}`dcC9@-qaMT5<} z(;j90=)b*v&F+(J-nwO%+HT1!Fj1H+BJJTU#>>FcAr6Y(Cg=|@6fX(kz@z2wL5-&9 z4(&WX>9=KX=H2|T7PYc}TqwLUScuTCvyHV&O>YGf}nER(<9a)SeAQ7)`gd2n5AZx8=j*ZmcaOep6y9#Bny)k)X+`s;;h4Q7lvqwu-1wUR)iW|`rjH641hC%;EnoTT#Vhm{ST;vPLzhBcA)ns z=5fX%R|qC3KIi#H(+S#SwckxyzY&HVcpokvGt+2D!oJvV!(!nLhzNMYC3R&Lx*SxF z`sB;nogP;cF4x_%@gEg+n9ZfXw8sA+bEL<BFz}m(51Kzl#4f^PE2I-(``yLZiI(zXAT={H>^m z|0E9e)Je+V(rYZ=yDe{Ui;Y;Ov^yYny^;x@NFMpFT%qCzPWB)`b$ zhm2S$XH(N@D^_Q~OEZ{90Ov|q&5GEtbjwoWV!eq6m(B}r$tR&Yh}!am_Z}Imm7xCx zW+|qy^fYgIH}(DH*P5Gb;@)m6x&&y>o)x7(Eo2X*`IvUvOj6-OI{E-KvvIfApyf~h zzKWF*eGDy6l`a)&hmJ*ISPAO|cJ!r|CsjkDY&AFTRj)Gj$=6od0H*SAa+kJicLd+( zR71@Kr*^(gpiK5y$G0IET{XWWe~u0!9tU1F@k2aPXfhxB<9`kbeZ;XUI-U3N>o8Bt zd^W{uPtFgJt~yimhoao^uc1t}hm@>38}@v)1xMofMV3anBcilK-Byi!ADNA0&+Zaz zlZou?lb5x?hjzWyRfpC0uWbS*ig6pvrhW$9Q%&R9RXpR8>~f6mH>O?>p{6UAUvOGX zHcp{#cTLpW=0XnF=5*~OorY@5DB=F5wVocY_QW4-i~D7)p=&e+KB$eO4VLS2$_M14 z)sHU27D5>LQK~`r$0|D_5?XCUfD-Icsh3(>7q*vMmrm;&HHBt0n3>Ez>#t1$v%`rF zywNBdlghu-PoE5DO1`6;*|`Jxg?jW)@K87UC__*VixzEiwH#h4t(x*PK@tzWko8t? zikm^wlO=fh8rvfEDWB4@M&h2&hlQ6~S_E`jr44j3@FU56TGjm2r4p z2Z8*L%7-giGwG4im6L|OR)%2gWVxu#JbBCk>~FYh=ia;J%PRcpABAIbG;m z-)nib+cj?_wIv%1BY{KNzy~%RBjYS934|Hh9>v(55Hho5PsSkiFPNAd>cmmzEq-k1 zs0O+h!2M%cGs+zi!z_%^3FU=VK3kb&Fv6&{i%HAzNm@|3&g2L%`e~1 zEl;8G9ZfwBY+#!-)r?-&v<@Ki9$@Sauqv}P;&Z+fNs7{qqHNxF#B4>?3K)Es>Mu`oSghm z&>X@IJ=>hu7?jKKh9V92YBaH}1VPq}z8o3s4m!;N?gt1ue0*9Nt_F7+=uG}s6Cj6o zeET02!RJCtxw+N`qewU;od&Eg!USn)K>X%H%|IuX>Th;eS*} z-(~xCpO6geK{*me8_6`P(LG-Kc{Ydnn3N*|F0OcP^W{kAT9%Tup&I&X`!q>Xy*YiV z*ssX(Nz%iWBYeH$!?TI4@9pofgx1kt?Q@ygvF`n0PA1+P*?faSy7RJi-%e0}QZE@< zsJh9=D7VDdMrRiE$uNmv%y0)r8<*kP9SD_)q*B4KoW9Lj0CfK=q*fo_lH%|1@2J!z zABV~1uY}pN0rxM6*8Ynj8CoYkA$G4n&3f<>g_Zh2iQ9GTDq2~+>oON~4tX*z4P?nP z+lAr{9u8AvrLLk=xp4hl_C_zG)taiK?Lu?VGh`!ofBom!ogC;{9^K+?r*i7K?7M(e zDZXETb~Vj)qXq~*ho?Q?fSN1vo$DYc$V6nRjEsGba1g#p4+j1?Yx z=5$#$jo%PzJWIVwsWaJCWXgHt^`n;NXAnzemtWQs{%y*hXxE6uq1G!oxsy_UWB;WQ zj^RImc&|j2@Ramh_Zquk*})CgX5c=p(Goh929Ii!!wPO@%`)(4qO?q_ zNZ@D;Lo^~q0|TmkdL6c)Ov(#xvP7yXfG36uQ}-`EVFw?j3&3`Gi`s6syD(sk=j(o! zOVvWJf;=igVDoruna{R?Yo5sQ+5tZBYw3|V8xJ_xlPu(7aoY%fscJ)`z-P{Lf~pkN z1#|PNq}WV<9<7dIdp5bZxU%p1XrG%U{0VHB73tF=lkZyHg*V9D3lrw^23}^Rc3Os4s{I3s*|{8o-;bIHadwlXNO_f-a^xtbwk1KQ zLWzXnmc2YS-Ng+9QkBSu%DGx#!{7Kgg-ux3#+j^B$)#k5@p#0-tUZjm;YMTCji1TJOR)zjy5-KRtFSVM|Q;l@7Coa9Pqu==EUb=J!E-Mn5g0 z6O=+|8=h=thpftrx=u9U8-nhXgoNEn>fS~FfZVKJeCOuEmMTXn_T2-VzmgpsLT*Q_ z)vxeVbr=X1wIGIT4?N_ZgpM)r(mPd2aW+O^T|e9%K>XbEQ>8;FZq2iQpuT1P%JKt_ zmjMh@84^xj{GV@D27j&N?A$(0YX}lO1!1m1>g>K8sXIfnkVKK86DYQ)V#;c)vMV#K zw@ONuUIt~{!gE4-u8ETwiF&W3B7yOG(=9+wVA>Q;ltDT_B4ybq#JnLGTB#|>Ol!3` zBL}ZrNb?G{Gv*33dxSrTXCkQM;YC>=vZX$nMwBev==*4p2{)hv6`AaQ}>>qh+F;UZFf7(cJwK{vo9ly-KnOqFY&cqU(YjBB?I5Y1&8Hx zt&4~`@yy{da{MpnRp|R5lxAFb(^vIrY0jzHO#cr2*8{?D^^Zup5m2O)q>EicCuB}0 z;1$@{1i6bly{?UN6WQ~-3xwykVp>RZfMd6Pv99+Ey8%!!%i+VD*0pfq`65`SLYe;R zqIV^HTH5aN6v=Q?#=*?J#;Igir`Ntqxg(OM3SJhr0{rvmdUM?9Q^Vc6R4Vl7%rTmD zt}@@ikz_NoO%0lvUY6GzWnJixLUpKsd+jA)yFFpz*%+86r!v#)*S!vaRzwXbK3GR% zLE6J*_bF-ip|erv3b+eUYK5xVkZ`_xXPra%8WkWojopgipAKhK!xl?S47skt#HZTSsh+yzalQaT6g85(t9AE~kA;+MgxJn~uPqSt7WI>GiI zj}Y@}Glr~z=B^~{KXg0aqGFjb*c{&@ymP~P&CFZe!`D|nk%&nAB>hhYf&ZihLDXIj zxhjkIc7BA8Fi#*&Ms}93r%kotiq3EIsY}0$on0ee<-{%nD;Z}*-$Z*Wc{PQ}@LbPn z2g$+ajAmu{sdh&ug{SQ-H|SGf-GuPHetWRZ>oaveAsn5adn1UZ$4k{@H;J6&o^gjP z(2ezdy?>&?6#)N3?D5m&h4lS(w0@ScQtadXH=Y?Oi^}ZhcMy9}%4aoYZx)7DCzLQ-)O%yAxdayO>u5V*_P~@bGm(Ia_NhH zlz?>}8^;upYvrmi4t(&A*adgeyz~5nP2?BLE~b|9Oe#9K(W;9IJG0`ZLGpU!%#R(d zTxsF!3D2ib+U}l@$qJvT#42aHRP@{hb{4fJ)^qTf2XUaYqm1i2k6jN^1SP}BnLvx+ z+kt_)0#cQ)b(`l5T!L{Z?%N?q5i-rw(OI43r+x1*T@~p-s;-Ue*V|#P1Ax8;a0*d2 z>s6CkJuJ+4I_x3GQchgjr>Acx72aEiXDIft;3Y?S?Fw|GLU{EBP1`8$ zI-T#9Ify5K2Om}@(Rjs!AQ#|lU{RJ7zmdU<_Hr~zBtwK3&WiCrkE{2gp8qY zgoaS}D(_ed7w^rfj00u!!0aZC(V0E#uCnX z(8|~8E~!1I`#?p@MGmj5?Xg&xniFap?4cpIDb%;oi%w68-?H~lr;(i>DSCF(uVIFx zX=TeV%^|-IIZ)B)%;P$FrK^7}me9Qf!AN`M&Gf}r^NqFlr74N(@Qq-w!to7^*-Y_x zn=qUa5Szzo;Z86#gxt#eXpvY{em|;JnGsQ7UcMA8iO!^AOL-yr(iXaw8q{A zJG4A_13t!z?rds2eLExg1`8yuLkpC83dd#`hyXJi=!XTBBAPMH>Cp%QiJrk46139V z!TT5aNrP(4u1KuXxw|LmXtA|sm?3uHWVg{XPhJo04z-kQfRQ}31vEmt1i6&`eJvDr zGJ$0LPnRrMu1+$E6p5uJVuybpMUG4uZQID!15sB)m?Z9yYY)iUZPQiVpAa*0i4`@W zW0aGS4AE8jiatBmOGAqD`$_e6qutxPgh%_C8R32e+v>kA?3LDrG2>k8z2O_x;?r@51j*VqusRHE4zy!!^r6Ns7~cw(BF++${{{!Kf>`gTl$PXE|ng zKLq2o*n@{^y}|g;9qH!NP7c6POz`ZZ{`GmP-wgAPapyY#^~6l|aa{k8%6&G)ys`Uh=;thWW_5ItUXFaF&v!jlLCuKG zyXEksJW?LiWBA`tu~I@qZr6;ol8zz(w(xYh`^%Pg#LLeo42G2w8~)lQpS5t9XvUXS z*^Pj;>7las;uHI&TuuAms43(4>#&xAmdK!^)jZv;RRG9}+Wj+F9mNK@M>&e!7_3AQvo`3Ay*364P=M6XjKU z``JrwmrL+G+EfW0`Fi!`WbL`@njJi@uDBB!e#ahvSfdki9o$5Np8gxgj zjV9mBJp()9P|pt?URRGl>}(}Ua%qS4m*#B=^@&IKcz;IUCBK)GzdVI$zBH#|i0Zw& zkX5uor}(;whW5&D{h3<4+)YQKwl$c6u1dnU@6rvWhUu3P=Rt9rYeE!cXG-EKsH$LhS&*bImsYlTF&G$I+{H~}t^6&H77{@yA z73m>obSpZBbi~e)Gbnu#d7_RXDcVR z>qT7)<^N0>Q)Y&F83M8@=Preweu8XQ7)JWI7{IPuaSo{ z^w+P@J<^-+iibvrans1oNPk30b3qj5INQ@hsg|jBUso}p0LlQf^XCY2#0@(Of zgF2W4pa-UcD+3ma(m~mgv~(Xuaftylg!!uT?$3yaKM)6hkN|ChR0%O?c4> zdNJ*o;`ugO87Neko?JgOaKbnteT))m>hsq)u0}60guCT$?&YNns_ZYn_0sLzA2?HjL3CT(a!AIG7R{Y!LdY)YFT$-_Axu?2bK7E*l zH_Y4K?Eg^`sP<(aWUmV62OWP_>9A@eXf5b^oh` zR6+|c7%!W25;8flT4%k&rMbejQFYb!uwrnlXaErC;Liq^88793(p&xFcsS3lxABij z*cZHR*UJ3SVq@?ls<4uWQFbmN@$9A=rYg50l{>7Hoiw04JndNDJ2_@gZXS#o921OO zNJ&m>gpyoXk@>nX|X}+kh4-}T!d1#z@;bT- z6g+WT0b)9h(XlsZJOls6y*MD;>=YKi8~jV803Ke;=yk`6CqAk#Z~liz$LQPTJ4k#lzi4JW=OM3MOq@-h?3Y0L zV~6H@rIxR~Amf?p;NETB*$emPOEt%Rv_nWS?_G)_FpZ9aiUuHNW9Y1c!W6!HG{aM- zhS2fCN;tO=drfZ1?Rdq@(u-i7+q*Kui^E)g$6qbCRoR_S_pXdOqo<~O;IeMq76;j@%`C;Mv=YT^u) z8f-ZmPOS5+!wM+SkoFW<-Zhz@NttTdK=+4rQoY7q>0;j|Lc5Q`5oI36m(hM`>;pe6 z8`LkVGjc8z`71p%#hKksL%DtR*JW<8@X5z=w)TzZo0cvkJ|T@|uA4IDccuFt>rOwg znMPWxaI5}^MxdFg9=L63SX6;}#&iJCY{*f0L__9H+XScF)f(wv+%CtFzWRrpf5F1< zq2W(y5K&-#-&fV5_Kb+JxV5PaL;cdK@e{j7TaJx~wq3f2wNiqy73$_)8sd>2wb76) zGcCJ0%uO#r+7(JE(H9urcPdX@vSSF*j;9QwZ0Oo0kHxoB5|!xZwB1VA7rQ)jUcf|V znZ47{WA0fGE|sV~2EC3@{;$cU>qW9`h&$^aWN**Rm~M(t4iXkRC!F~enLijZG`wf) zNRn(l9mn3H)!ateVs!}yr5&<>vru!+{%;w^{9kntIb+231x*E4zqTk%4kM=gu4T@d z+vNzeMKB{D$RSQ@yKd7bB##{^O&G zSVWQOqd(z(ua6c(w_o$EOMJ@r+b#{BpY`n>x+0q*N1JIb{TP3S2w zZ9Gsqen$KSz4#$>{yF}exLLVf(vJ}I4~r?=wiTI(YIKDn(M#c0;=_*{V7Fzjx6LhM zRPVXRc{CbO&oimd_Z(83D(i6y};`d1Pq33+I-|)&^~!x@bPdq;yyQ><@PV`))X7>d=pJs zo8TD_^PBC^*=p3c$Vm@9T|bN3aSd_$mv@@CCOEW~ zYZkygD_wrvFgN<7JHqWE5pK0$CIOrF#~W1!H@_!0OR5V3*UW+pbkNX?t^cSxL}Yxi zkX1o-hNx1^d%)Sapa?)(rm0Hrz*p3}F#GOp6>Y3wp24nS(NR=mkl6je8c|*7LnDBP zZD(>o*g_^d7x(dTR9RPes7nBfDo~^0K8|GYNE4h4FDBu*LDlC}YO1&L)dxE7VViw){9R z)C2g3TKATJLwFi3_sa;L4~+=YMT(AvP3WioEu4;rh+X7X0Z%&rV^803vymhzC6a2N z2be5f8^EJONrU-%`&UhX{GRVHKC^4O+)JwLNYL}%=c(qT|B}6=Q8byMPne!%f|vdW}!WYIdPgnV&Pd&1V~#o+JGZU6B2^KUZ&Y zV08hAYNgyY+GEGXOC>^Ps=y3-b{~Z`=ep3EGZJA6e}E?tY~uqnzO%gjDn3qs3=!M2 z9k&=w7xahQSiIvCDchaQ@s?cLIU-8^wpx`Ps4P)ZNSCjaGMmIJP5`!dXJ-G94GQa1 ztY(EX#;IbgbZ4UgfJ<)t_7krY{xDeAs70~^x221%XrF`RkP#_GLo`NG`LV@B+f!ea z`LRp7uVu0C2j^_nY9Nop*J{U*_goJj4$6Ir+=Cu(s&79fRVx_6E{Wo=(qo*n)XojJ zeYjrPOkthr}ZSaaOy3XC84H(LkOA;T3#xS>tlC(qv{fTKqAwBu@$D%R^ z!bJb~m2X-(2*IF&;EvzHAo!uY*KDz}*o}_A?`>q|tV#YF>@~xgOX@L!%br~BwxCwt z@e{;CP9^VHEV{mF*{vs2`MRRf5UC767H#H22V5Ba`DHKi2CSvW4pU?5cZuk^-}cMA zEMTP~oxh@5u$v{fB~cxii;v=>m5kh0mE)`E` zJlYd6=IER&1=FWMR$cGco7Qg98&~(#l7iJQ>t9o4e>{dG?L!4$+P?oX`OJ9%g8XUU zEm+*Y(0s`uF}w?WYOibaO?pz4zBLvd<^JXSY()u*wJ|u`anpjLM2~?mzP~yi{lQ?> zXr^4#vj$WX1)J-g84ZzW)H)XEW{iI?h8qn^G4UelNbi;qTtbx(cfz4i|T@l1AuuPo1+g32C6zkFM=1XW_vgg3LrJBc#$WO~uxXJh!Iyc2soccUMApEO zxCs$)sCnZ+*g_7S-Iwvq31Y7$f9`VRp{UXB7!V>Rb2ZquY`-JtZ=#4L{2idN$2((Rtgbf-10Ms=iZ@vc}P&=Kx& zn#AiJ+=p`_3@OYS6d;DVXuN#hax1yF$;8=Q^xD^p9r@lldH<`OC{V_@AWTcNeKRwt zrI(x4OC?KDq6@5YlV&-JNNd`jTgI1hPfr68&vrQvqT157Xmi?ZIijLYFwzEQNOTkH z7}kAYa2PiVYnXk(As#CjK=HEYha}D-HyAsc3ml*u+vOZj+$KawkvBax z#ou)Q00!2fy7HA8Z44i_k`~P_}sH&-#b8q0DUCU|1gH zF3&Tz87C_9`_a0#^X@;I=@qc86&Jdi%DI&js`sh_#yLzOLKnT21@`N`XPj^OWZJ)M zX?bYfY=$ZSWp;WIw&>Kd;Q57h@MR60Gyk2Lwn6ZKN2sA2M}vdtmD$|#nqgT#(JL!c zC{}X^bI1d`M}11ZW7aCW30b!$$ke($4n^&$c8?8*Rn%XmEpG>Bir~M$buD@}-mh9a zn4+qX;pIbd218cyrV((7TW#!gW7;j^Bbrz-LZ`ua&-UIQR{G8uN40wQH0cdq?m``G z0^^z0Js_`RR5A1eDs{b5Qw-L0m2N2H6?=v6!cW<{B6=_0)xWpb4&WJX84XS{6EG)p z^UlmG6uqBcly$h`7zTtr-Zb8XC`n(&Y&rH$ zCVI$kzER*(*3R%upr$E5DKi>JgJsr`6-PUP_${6OqcCP|%I#JC*^;67%H<(0Y@N|% zz!+mf)?Bfun(w3G`4(ZnRg{6ZwG#V6&87S>u9rYKN>zZF*OX0GQ{!#>fGQBQO}W?* z02Iq>^Tw19iKmfquc88bMj0~%rB&cqgcoxi(tWThXheo)XROma@o4i$`#7?I=d`s7 zE2a6UH05+OJ+|whr~5HBvGy)Q=&+eKixve|J%`DE`zLmxL#gyIBVvD>2_|+Jy=!z| z^UixC2r2;++0Blb39)%wdCQ|SDMT?1_!J!VAz^*UM_~v&3r*;p^{hl}4SU&R|= zBGOR!?R$d$CG1y0COqinkEV*_TkB&QhLgv3HXHRg8}Cl!hkfj5t#~se5s3xs-8&Q5 zD!{Ow3yoCj?kILey(z(sm(GSiR$};U_rS(Yrp$HaH020#7i`-mAyntZ9Q=$^zo(zg z2MXfe-xM!0ZB2P=5?VgIlfW~m*!MKBe@yloR7P0D*BGUb=jEjNeC5+-hQ6FF7IBN{QX^9*YR3NyNOzgUbum04(3w7Nr6R=AUoYNeT{9sqVj4JbY!w_ zdsmIF!-_Nzh+f0Vl}|K{AcJDY*bO77pMWfo0=p^DYJ2=vIIYO`;i#T7{6kHtlEh>J zTm-CL+(>)0MrM~S{P&~-t;p~Mqz7vf#iV5OaYPa$DY8@GH4OSD+0MS zsk}P$OV|9acgS7)o$&VXvf>qIG!FKqvuP;hfz+O4)f7d|QuhO;V}Ydyqmc%aV38q^@)7Qk)H?;b}V z#ShDgvoxFDCKvaP$*z*|=G^Q=pmF6pW>ZElf(iu$_(<{6o#U-~NAws^Zuf*a zv9qE(V|Q-PvY>P#ix<`(pzmdh;_enG@>YLnBpXJqtGL7n<*B#rWi0P>+m}#7R*#DSsF1yY-k&?%EE~wm4y- zz*&*2!Cgn1WU%xi*vQN^_T6up_(Gy6lt!kRr5$@IG-<}QM-e-W&LCHk>&{^cOR>D zxmdIT=)0z?Y`ic>(xwoFWfrZ#E0@5^+>(8U27G}6b)dn-_NJr>^Kyd0kKPnNvMfmG zhpcv>@d_M&l5LWjEIi(b(^SvKPN>CB;A}1|Xi*l*_nh(8Z$JX|SH$JAt^|zum{N#_ z3w~qarOHobb`;F`Bp3p00>;Z<^sGM`rq*CH*Z<~9U|%2BXj38!Ve+QgFnF4T;_EQH zA;{o91R?jzI?42{B}R<|0y`i?q(=%#1btD#Cbvg}vZJLpQ$KqR{X*@pZk{qCD8L>Z zN$nEU*Z`}#JnX$1oX7819M$xxkrMx_Qs=6*QQ*vx!S~aY;*9SMbPZ0-3;~ncx#RdC z?WI>(I#v{`@N}9!lsh6P;6`yo`CSVqnpG7=LMtSe0|9tXtQx}J88T*3aeDE$d*eoD zzCzk;IX;uv(;=$zDiD5eobhFa>!UIb`MY=6ozbPA`c377!EE_!en>^e3)MQWzUMm^1G3yOq)T*dRG1(cVWf@F*q{$z+%i8xWj3B)kNVJG zY`^gDG30t@k!`ok2Jk$$2y!R`HU#%HePQ4u7z@`yi@%g^s-dn;MT?l8EnyyR+ed{q~r|~`Q>$J#$d|UVyw90lIEKP#vrC!D> z-#!%q0EkZUvS=zaK>Kd069Ik=EGvwbdxNGx(7s|jVjC%3GuPb{7_)u{lE2nT4M}2H zbX816xy6jp&X{q4Bitj(23(6)Dr$+T#~uPN>qS^;Z5il{NN;eL%?7|U)6UCB|H4Sq z|Adkc2YlV~KhV=2U9*~DPx(kG7F4iN98yg29pj=`h?#XC+0uSUT+_MRbrgA5fFeB% z)>l-Sb>FQ$LLt`&|ihi8E%Z1H!Vkf zSRTVsm*|O8u42^8^1z4S5I6J;CInVqt3>e7TC#HRH6T9LS~434Xqf`CfW|a@JD@55 zApd~0_yV^LRwJXe+Y6Z%#m+@g6aKwN7s(@u)N4(%t$DK#-=xb=*tY#g^_*m^t|1wr ziDR-R*IEnBuMe@2kktCCrD;y3AJwm0Mk!xMBRVyOm41We?%wnl)i{d#IlNWOz*c1- zP2-+9Q1vJPI!1It`$?u!Hj8SbYNLjdnGbk zwNbiJ@O7|ohN#hM7Nd%DV@8O}y`7zyoTA%L^WkURyH27>4YgmO)z4?w!-hwqYzv6; zkKg4TI4RVL*NO%aoW;O8PU_QInz1!6cE_D5<+pGaE9yHG|VY&fDTu&pJ zk&sm4O>zFF1YW8;|FYR90n++d9YU1nG9f;W5eJH1T1gjJ_||Uem5ykn}zP!6gRQe8I!e0sY&sNl6_2Hstz?my3aB;I~2{@=Dh<&D5 z+7t_hCTWhvyjVBlqv>oYCoXp&#zVBR^-yz7|3M@k_6yJ_oC%CPmgt@z+y*Vy;Ryqn1d z1dAtVsNN$J2P;bgC}s_gRa4uBt0zd_TG(Y%pV7S9BSIx?z`*LbnCc1f#@P=a+lLcW z4)d}>KEi6`gywLEaRgRM5G;ZZO*X8;G6&^EInOQI-WnQ7FqG#+K}6x-nK z(c^}e1@WB{x*?Pus+4Yz*Rarnu}xn+IWife8gC=UaJ)#B_E9Awuhhp{&9cPAoGYDGD;AWyaZ%pitvsA$I(2;Ja3; z`}UiqMrtL5#T{vj(ZbsYImT~;Bp?Bs@J5L}-(d~?LX$CjF7(C= zQf*f_)Whk7uF%;0!cR!Y>!C#{iMyk$-p7drE{O)VQ zGiRsuXQTSOcb%FMjp92RbmrsX@|Yi{(7cf^oW4W*Bz|@N%J^H8!|i~_G#&JPm8t5K zs>3-jN)5C?rzAaK9V^x|ar>7a2^(Dal+8U)g`1_R1cm4-_A>VNQ#$h#y%WH-V>nez zt~?Dq@mpUt^iNKFQ(r?Ze%W~UNOD3omy~ELpuCaQx+N0i9C^8oi6RA;x;E3C@3E6Q zjVr>Ns(_=+IdrCPy3=*aWmRQjAygEf*v~8Uz! zq-N{zgMXDdX$EB9gwq@+mw+9*Swe{-41Pc+f#rj|4lh=?ZS|(vONec04=kdIz2TtV zOD^?5NdMF~kDL>Yj;Doc|3i*cP>p@&4=-H`nn|_uCg7hJp@Uu=^S{??1TovX`Kut` z4>xt?CQS*3yu!9Q^S3;_TxbrUkboL261UU$Q@i~`NWv2a0o{o-x$@{v0N+eqDstS& zjG6B5lOpyzI@RD3l+%eD&gzz5VcML~!6SKPK0{JL+GlxP8jR^aw5OEXDByz68gP?n z`f2w<8!lQfc2f~geC^;hA$FE_*hQ`Hf3sm{To>&DLSlwjFWfy3LrQz5A@0 zitkOe!2;V}eR|_csaJE(+Ki92+eVp$wu>aZqAoCtrg-@DEKPt|(dz^R2$!7rSvCi+ zP)Qx{ik}`+LS#&x&3hPz>rRbp=vv@rXoCXYICSwOikWQpn+eWO{HI%yXd(nNBP^jq zG?SViI~E*^n(+nsnV)7EVkaiDEbl5H%V$;hGy|S_{+e-rAf&U) z^U%v2T~xm*NuJ%v@e_B2=o>ig*$IaBWYye@`%_s-&NQb9hcV9#g@h}dnR^12yJHN3 ztF4_0P*9w`F;SYtT%%`L_5hi;6XrFo9ratOl-aXYKmV2BCts!npmaBN zSyR;sHdC9*8r5jx7;ZEpLT+#oaG`23_Q3sz;1ykCN2=F8F9s&+w0oa|W@$2y000T; zgJ`QwiioL9!xA>~uEX@8SL%<&~`AAG`pp0-g9hRRfmhLL!3$crTK2UeLmyP^6+V~ z`rm&)^~})Q3E=Z68{3>^Xru1r?p+=XkBOJi3*A3PXiLB_$mkxVOI&iUP|LiOm!aR zqLh#jYx)7Tk=T08`Vce0re@0T4&nU(5j4Sy|H4`udVyn!a-Yo9gz8CE>IXH{b?Q>+ ze>C$H|2i(2ehl@xweqHCE3=f^c#GZD%oG$=QJsJLqp;pgNdN8~#p2;-`pZ(rLo?(bW>ls#)wKm|L!H{C1p3iS^?%%3 z2*RmyE91imyEnjtpAa8RP4 z6}4y{4@mGlYxnbADr0CTmPMmWDm&z?Y^ULt;DMLx({X@zwH@58Fie{|@;Y+&*@ycQr&T zYk5LN_Jue@K}!Qp3L77g4UAB@pj2+sG~hUaD>c2u=WqY^Kx-pIPCSPjxxdwT`;{D{ zIO?A4X#4StG1%WMK?i4?o7loBvH^d<%CAEsa1CF|Q<$4TiobQQ^2w+xQw0Be(iY# zvk}X4rigR;a>chIg3Uy%`tyu5-YmHTgs4#L7D>%(RdNIKG7NeJI&R_MNu%Zia z*Rt+B-sN-LHx|Z%{ql+s=X1J4kDY8cxj3C(2TI-!Z6c0>Q@*^aJ0Zsdcx_YNSlA2x z{UpV5D$&C?+!x(Uj=z>d>lY#_z;^1WNX`t~RXzijcn=)REuOUZ`MEq-*SOPSAG-w4hq8lx3`E*Dz#fJW z`%TGDZ+F-{Ori@?bJ60gZ0JE2do$45lZ6YDkMAdwQjwYb-?C3)1A~-~**>hs-Wk+B z`eY$o^D1mu?gG@n>nQ#*F(N_!72YDX4}Gw!=0U|)51Itujz9YU2|K>V@H3tTlc#lrhSDpg6bcNK6Q8$9asU!ie_)g!W zsvZ>ZY5)nSWwk)c$f(tJ^A z>@Nn_SL&M8kDJ}dKyJ6&j}_G6XAb;xksCV6g>nAvxvlE=D!$*;yPFV$Jfl`X(7ZAa z{;G+nbI(KzsreSl)s8BEnH!Gt@Jgc>JJ^c%f;{{lEuL<_eSflb!jB*zjjTp8RdF|y zgV-)voQCfw9Yl#;NSFIZ?Od26!f#ilF+!=Zwe&K4&Tne38y>REBC}@^K_BfZ>ScUG z-Vc4uuXUkKB*`x;qf8bhcEoPYmfk9JQCRU6;`7bTR6H*&H&P!;WvQG_n=)!%$?EC9 zdRXS+Wazdj{Bf`|xh?THrAC@RHXaBS^VE6YG0e*@yUxTx0<}s_x>G&qzKr9V`zhzGIRPAf1d+aTr zeayzK_Tr{8rgq<3Ay22FCf4pF*wgQ1Sq)MAQDhn*y}`56SZYv9tiOC&ojZ%KzwU2s z==D|8s>!p&^EB=&^D?C>dWD`f?fBG|j5Lp!#vZ>%_TqW7b+KOxA+*oE2nXoYPXD)8 zRuvdfp}HaCR%VdIs7+non~a32fFayqiQBA0^~B1XAjvwxi;Pr2YGfiJCZLoSS zhRl!m+{0eRA{@82K2=s;+Yu@Fp3>S@M&&21zJq(4d6Uy29XAuv@qqd7LUKs>x?jP- z{yTo1JJ{n=@~PtV`th7gNG0*w^#9@=J7?Hs^Z=ISYd~dc@!FZ`;(Au~8b23`nK6i=8uh zLPrtkm^$@IrS0$638p={Ho5Q&n~gpFy8X?S=SLgv8vGw5`l|nGTo9D467+KAAXe}g za4*Tr3_xQoSK|F9aXlerm7YEZAYsi~VKL8h|62Vqd~ss!-Oc+VbH4fh?G+JnNURu3fH)+El~@eyg3&(9qE@Wiu2efFOu*;652VyXyg3#Lmi5I2T@ z4-IDtT3#BB9--JytS8J`uc1y=|i!6vv#_iyhJ2%)}ecof0W{_npFV_@kt1j-TrBVe5ks zy-tN*;=|{zQ@FBiz^zkTLp=tVy~nkQ=k&r-pKP9LddY0V6C?GDc_AEkiDN!`oSbEQ zd4mep_WoDzD~jK^If<*cpJZ3l(o*vJim(6?HG{PAln*x8iz>A#%YtV_8vMWtl0GJJ z9)&jhB7(c&Htknu6(@y%e(Z`VY?Xy|kdqwFp=cbpz|wafMUgbC4Z_{)SYHrZ5SdCC zC#`F^C!B0bS=1ylCq&(H^mf%zwxy^-7>}Y&zy6`-X!j0=`>~?Y-S_T>0izXJU`HF- z*r{LbKIHIQiQ#+QL>Oh5S$!oLM$@o&2fr7O&#o?EV>7q;VJ&%%f{hu{BOe_UeYuHY z=$3weB^^F+B7UCBLm_oGZ0i9UIvESJOQezwFLcuXdcWu6kBN4)C{3A!H~Knt9UgG< z$WHc?whf((GS7mPX^^|Eh}X)m)<1?$1!0ihjGmoWQ8C#X3vRzIss%NsvKZ5C7_W*a zWThqKQz*aCPiZG~noJ8GMk5MezIk1x6(771g6Og-i;UHMcze4?varLzJ$psj8wLFg z8it)9D_4Yl19(|sLm|Ibt0vTiB`50jrhX20%FlcZ-hQYLNWpzBTikL{ z?!i_pkK5<_elO)3`f!H-vuv-}_q^M~YFwO)%JXt&a4xFJRauSK2A%s*xv6AUYl!=6 zb45?45c#6f6`HGIm5*j3VTfD}>yv3*6jzmqj z6Mtm)BYEUgOfZjQ#1ltb*91A_Q}1cJ{wBw_EvkpPkDh)<&Tmc4@%Ke>I>e~YX3jQ} zLngU|A6l>IW&kfy7(^G#!FDKGIgep2Q2h&t`VNbK&w;?|)1A&9lUwUaG5o`2ndMF; zX`PeX&UwoYW@e!rV`xehHg9oR)Hs=Q^)cf0{k-TYH;cW$=EZu}UY(bTmJVc}%@gLY zmI>&Kh83HEOy8TU9faF8jcDZ1c>{N6|7~n$#3`oj2YoHUC93~EE%9z}X}Ny;?@G76 ze0L(Y*E?tZ<>DLX;ezawD2tv^z>n?}T6flAUSDUY37TJPw(p*F-?C6Ah`ezxMMhj| z#%g66HMin-NSlVraMWr>8enCK==SyzVsAQSe(Tr4Q~}r7H-ytWXsb)ciEWXK;Pv^B zo?pSbS*$Agw;!@)Em`z$TiU{;O%8(-NrP$f?IUC29uE_G7t=NgrY$#iw#&(AqJ_qB z(wO|Sm@YDQrbgd?6#O(Wa_-n}V?&V^>cfx?1I$U-`2N(FG$Iwm!vsF4%mYzmg9KUTP)!w1q2oOG2g=!Yf$<3rOtj2WTch8Y^^@xy;c%d zw9PIsLU;ErprXJAdy*iq28NnsiMx8< zI~$eVF*tVZlKFgO{!d{eGmO>DfJ{&DoF>r3)50EsVb_C^XuGj8>KlJlsGA}mkNs_K zq3h>EnSeA;g;Gt^r^h#CtrK&9Pn=p9k>%gU1v8UUec!6LVuA+dr0#a-C4XCK8Mup} z{)%yxq&7)tZIF-&aeEg1D&^C5o>agGNp36fKdW4?;|`ru36Jjj^Zkx9korZ{ry>6SUx-zpAmm7*LH0nN*G7APJnuE?-N?z^?pyW^sCwBi zG3>DuGcM>-?OEJiQ!E_Y)UW=solev$zlZmRN2O-eQNIT`UgIVC8XEvUFg1aI`I>*Kcs)dODWwY;h6{jf$d8) z%quKdF#;jn!%BG8o6|GpI_z}(=8b-eKjJwA22-5meNvhXnXy`RV|CejtML6!Zi98` zhEDxO*?F3lj4*u`{kt#!Zm*;nKGG%r87em2U(Y=Q=ySO*2I|SX0QUo!wmM%2vfDU; zw`K_)ex>on1`uW^(6~9rP?m%V){4zyJSO|)o=Z|1&HYo0Ao!mOAv$dQ4cOzs7IYh4 zy>vwdV<=o>{u~24x(?4iNv=M#SuU1?6f_F1bjIvqm3lzYZ37Xj8*-D)2fc}ziAiRR z&0-_1@$bv_MT8h`{JWv^CkwFSg?}qmw`_?E{ZLVtMRSZbcszLjZBXpWy~S5kz7;?P z&F(^}=O!03^cTvAJC*HOednl(H50+fyPMA#!=reJf$UJ z%dI!}0Vhx+7o$Wn7U0pHaF{9aNSvRRPGxChT+XqIc4~vmtklqOZ&?bDyV07m$@r`C zpn3u;-mewHL-mapZn&)y(n+88tpQ9e{!3n1pxApz$ur^n6_v~5V&aEw_;Q1u_1<>U zYMp-GCAUqM>F-}y1+)ZIFCF6{sR)##e`KUhb|~;jR^K4h7*=B(y)Lz;>Y4wjRTA0Y z&M200MLIQ3@5){t-`IQS+`VpPf2q4G4sY>`=HJL_JUL+%XZq_}^0)H3zX4e>6@T4K z-9i{EoqCwA?~?KOs4>|xEMBs#UI{7yC-&GJtmjUw;?<(YtaVZ+C4Za)e3$0Vj7oRhD zY+HNrublq_bIkrxvMLgtElmC-A*LI{gA#?(NCMAhDb5%;|jOsLv9ffe#mo zIP<67{!?Cc)q+~+(d66gmIZ@4Y`T|J#WxaZN%$4Bj;9`}IZ16Qk^7nTN!%~ZEB9j7 zyC$&h2-ZO7ciqpNAMN`FOaKTA11azc|n{o{q!;A~d+dQ-8-)4hAl*#%XYW7_=ZZlq=Eh4-&@b;UJGl4(z?jLy6 z)UCJaIZwr_|Bw|39Q*dH^3jO<5PsjMAT>=ETc3R2Wm`mqb-OJ6`QNWBIji)39DmE5 ziui3@y~x+{frOi)i{uTp2v8ssa%mR%!~qz0(LW-r2Th#`zz|QN$Eb8 za|c_$mpsuOh@Ny-Fn!r0=mz)EROR8bz*y^Pb2VP`p(kHE-HK8RTa?}kJQj9|runpU zVtxGP)#A6`KNn7+wd*;zn)6DZ%#J>8hIT5==_Qqk{)`5%Q;49D5ebH zf6GKJ7m`EjWJ==0abrelBhg7|CO`Af`VB|o%Ra|0~`^8*D=7f{=Hc=@jnk*l^+E3o` zY0cxi%st0$aP6?mXjy`0(JM|=bWW7I%W>Q-m!X-tphx_vN_}e|OO*|px;%RD9W1IE zx_M&1K%>@_+>?Y+_xi8z_zzKcpCn-aals4DEGtArkS1E5-C%$*H3q*{ju4Wi4y;Xw7Hp#0W`mq0U!Uw8mRsD5H zyJWUH3~&`TobYMkn@MEfHrvi{;2C~9YqY$qc-{Blq-wg~lqmg9 zq3cjGA5pk;QL+KKP?;|+nd0d~?(|%LmFQ$>r6Ma;i^nPnTFKAid|VB|e)v6*Pd48e zv)AMgc{LbSF3_FJE9n@(BQZ8BVUjt|8#lLjp>Xr%;k4&L!Aj+7h5c61#I_3nRZv*2 z?R6Df#Va4gE$AAO7EqJ3by$RVQO`3dym2$cWM`{9Y|+ui4l}iH_)KH*k|M@bux)C# zWWo5Iqqvy;PYO-?Sj)Y!?*k30Sr7DKJ(2dlpsv&toTKlv%tP1Tj7)RM#v2_)g6B!r z9fY4d@x9J_u=O%zwE0a&s75-V(Ws`y@OP6!^>9pr&zMxesOhp|e9Ww1z0E=6q)EkW zj=g|CX>_NlXhYDx5}#o|sg*TTMGh`z^eoPqN?^pHiP^r}(6Q1p9tmj?$(bN25}~;S zzhr>URGb$-2}`LXybMgP%gDS4pDKMp z+tp~FjBa%NG?BG*BNv!`VjsmYK9NNSYgi4Z%C@8x3Mhdrm6?@@gh|M}~x^;YG_hAX*8j^Y5^PWMVDdxMe5 z@<1{p;-|&v55>ADyvX5K|LjsZh4R2jj9PU7&U8T(51T0^>7F4zuP4Xnk1=yyNcR6) zm3OkdoCmY6P3Ci#q<&qQ_hV@W+zpIL%}2bm1MVjHd@io@)qQz)Vx*#l93tdb&b9Dj z>R>;pLYg6-7Nk!9X|Xh_H1$hu#UI66JFFXQGtqvyx+l z#nvtTckO*-;qBHJZ23TzzL1Jj)&3Bqe`vsNvO0gUoTHiWiz9?6r2muk8Qv*h?@iVW zT4c|N?0mVG3d5+cbdGx(?)jJ*1geV2YiFXtKF~XaSGc0L!pv3ZlEiC8dYzK>g0p9+ z4udOd$TjCqQ8P}et8wloa@Z3zwAnjry=fT_LHExEJ&4Z)qv*7A#}dw)|0E`9MM7F5 zu@d{=`5~W!f`Q&eFz4KLlcJUP=@?O%bCntn3|sr*qzgjjLS!1RH^H90;OCnhE>sCO zAZOG>>ms1H&(t8U2RX!SlrI#06`fXw0}?5IU_3IaHzX}{cDhAo3@QV|#A23ih5*be zcKoxZg50)g6|=5>i)f@e7@uvQeQvuL!bh2nO?7pk5{QR6k{6?>KmvkkpNrAtjeP-& z6QA{1{l~M{Uh}9@Lv)>*oNJt=$@>5Fr+6rO{5dXrwR5hh)iNA?Q=qEUFi0v-v)i4` z_$x8jG2v)iL#>59N_y?s&oA%X-qZO=Ima+{$KM%--q7K#);a6>={?tR(Sa0Ssw=!Z zLMxr&RqG4{hQNv!Csu2SFIH>UOjor1x-8-lwsJ={x9l_K1=3tBT`n{Z^x|bkr0%{b z-Q;GjvHF0|5rPoO)*Tkvdf5?!w(6XsrqRauuEHvmqYle9lp>6uk7NTKjePz=pc+BT zJA*O|9y;6#A>;dEH)1ey`<{Yn zt>vgAB0R-k`?0)>&FKevPZ?|7H@E(#yin-!{DRQYVxh!2c}Y4a0KeYCKe$sZ!{lsU zgq5$6$8zMeIm30Pzpd{&Ui`-_e*=%v=@$3VIa6A0M#vQ7hzapgSp`1rzr7hI$)9*T}8d*ygnK{DY) ziv!xPLV$@e+TFd?Y``ji(+E)IiE%Ti#})KC$xd%ek>h^8n%lwSl`_6gUq+~px=#w=Fx^nPHiQM;Tmal4)I2z1889*5q|u~)3T}@O-aEY zq24+UyIiMfr{eT=>$HgXjyXTV6q*3xV2kY z2t}6z(kIl>Vf%qzp@;sbtb^QU!aDzqTqEbd-JB^}a?ROo_L^&UEbBBf)if<-GQ1=g zmI-rzm%FZK zcyAoBG3t(V!9!T_P-Xm5Q{%XDAQUR6fsm6qIOSXe$H;ei*;k6KnQ^#s*&(xi)tZ>B zCSX)^LT8kaq!~coV9_rq4#%+>%+na6-_N14JnRZ8t{y+$idu?kDnzN1hw?Oo zbYU0nE+P51PzNeMo;NzJ4rN32B=aL;FvhZ*PrW+;d(`4H^=ho#jn|(aKq$v}c=?SQwVVrN(bL=iYesWeg+)878Oic5$rrNHRJxfFU2Y2QEem=`#0tDya@ zneUGJHt@DNozd_ekJORd9<`d!Xqz>Z(xTF1>e-K&;Lm^#aMPCJ=!76{`G%uaYZOA` zy@8gv?sW9ejvBS01vj8fNlQvsY_Lg#jr2`BZ{|9ajtY8?Wt{bgIc+4Vr_>~J3d?(j zo$(r(I6{}2qK7eLuKBoNeXM?mmQfV}d^25`K#m|8Rh?rm!@a~!eoJ&W6O=D;p3oc6 zv88D1=R{p=GPd|NJ5j7=)-h`_zVjh_%@Trqk8LuazrLWl3}z`Oja##ehGaF)HbJS? zyAW0RWGBh^5J`Xq#Pp|z!rMs+C$G$Vy}yq!tp1De8KMGjmFRwS^ir&~p`e|E-?FRI zSmdrX%*=?s&Pg@{Vh)b$w_564m_E#&^@#AU7QOEo_&SKdDX5 z7fLcvb^?9Bjt)uK?bxP9lBc{$9CI?mbfWGpsNpvqGRBEI2%*+GOKUS38$a^xUB#(E z|F5DPp7)b)r*tJwzXf`h8LN)t61fNIB04PYJLl5;Q3tZU+%QwrqUnIFqFMJYkzqR@ zhig}K(M9p8K?;sU9Ff0KblvN&EdYQH;xnGZN7qUl!%eMdsbHg91~vqwW#i_XtJm3W^)^)b82i?&<1(zY4-+T($`Q<(ztJ-rd+=!;8a< zuZLHUF~;Ie6__>p?ij~-dA(22AmeZLSyT$lviK)cW`5s(@UlrB#hYb+9{U?&+cpX@ z&C7HyyiVG`>j~#1f*M_i1-^B=PC$X4FE-&CZ`9lqER5(IYd~_{u6TVc&(yyay*g*- zOg+-A<%6k|FAD%}H|aXAxrQej6orX8%aN0NnyBHO7Z zvb6x}4h=K2$q-Cv{=K8Z(Hwyba11$36kP>{8qE&7 zW8>z$yNv$E_|BAHvDv{b2KvR-r1qcs^%+^(Lvh=C_1~9FPodUs$XGS?uUxeljr!Sf zs>Ef33XpOmTRjn1w$YgHeuOcU79QQBu&YIe8$kd?hr&Br2fX>60~!yWn}dZtK8F-n zc-dChM3|gX z{%5CsG}zMr{p~lq3^#_|TgJm{8S-oTgZ_x`C-$1+jv}xo6`L?pQL8GqZyH{@s?8K% zmWk2C(cHX_^8_xFJeSzO??sNj1CXgZ!>2Xby!(nDlI0fcw-TJ%2Z4D69N+AsSj$3v zK{stGMP4ykg#A1`JtazLKlOcoEM;G1BQnSE7|lqjg3Cme@73^tC2aY9t@v3@X-+bn z5TQ-9)Ao56IpovY{T2{bOd|Wd>!@`8`;oml6Es?RNF!SiB?Q6IY33W}$m{7EIGqij z-QaVt<|s;t*;X*}H{CDq9>dCAN?27P+GmebpQB+^Z;KDX!Tre@*vy#movqdqSb}gh zM*o}*Sb(F+3E_xPBEe1b3e|$B-XcqaR;>1pX<~nlQEK>L@Gh%tzjz-#CE0B^ z|6n$gBC-Pq_o&beuJ#oq3t9ry#ajcwzJk2&*5%Q45Z&yV8j((5jb|2$)&q8i4LD|g0q@Pa_;c- z!K@>FUcv`Ax}v@QwCcAJ7w}1t?(+#S^)hgRyMp}rua*$SMXvvD!s=6fnlR#0Rj#q_ zPw?J`uX@*Zi~9FJ{o8Bk5kYw>#KXlKnJ*Xdv~fhYW7NSodyQ?!*x)E>%r5jNcwz61 zPBSy0A=aAKAJ{}aRGb!dQjdAA=do$%-8q6WROD5FMyPI_hQu>)yUmQN6fqHGf=0dZ z8_lGmJ)aj&Tp+zXva|~(U3NnuNUXs+KCqvae0Uxde5^fgkM-t55#QXaNsrkSl#B>- zDu^eWHYSmbjGn72-p8IxjH12_UOcHTRG7(%uUn`Og86_K)FYGimsfAOs712upo2<-&!q{MCH3oSEDU7R(W|xF(;HHx)nb%o_hXBsxq1jJ<+EQR` zgRllhnsH(gWm4Ce2G*YYS#6B{ZZCqG&MDo&-EYT?Mp}_ZbF;rQ91eoMbQ71=lovJ& z#`Q*S`fTkP!oNf;$&4TqcC%u-Iy1%<5na2V7@c-VauG`}_qiiY*eJ-{BrOk%1PJck z6CBxqQfM94Ldy^@$3`-VSGb1cGXjQL>?@tvC6`PW#@=7-^+S!6hj$gAOQG6I)MCB9 zO)S%sV_$m_GNE^4t5Y4a|QWJh}R?576s%YC#;PM2*z7q5U1+YOBwB9c@PK@G{c$aE_txFInUu zFyBahLj-}-n}y!50Db1SU-A4N0HXG7kW$Z0xIelX;*5_Fk}!oznC4~Qkg}eF&ki!5 z-WFSIX_wF?o8}4cQbRiuP29|bKt>eTt(rGzKGL+B4qn|PGq*IClyU4|eT4R^M-fFg zP==hv6#d*H7As!~gH`pHI5qAvE9(F#X?8CNRF)4T)#z<{mPqi>krgLj=Q;((4k|Y7 zzH^vKOpDTCdmHK%g(RnK{A{i_I_Y+gE<^F|$n{*fnXpA~qMIKL2sD}Rp^lS>()ZK3 zJ?yJ=F(s_nP(gm3c^{tX(dxKZ8BKJ$H<(koHU`<6@ zHnYa@f|`_j2&h zEeEeAR|Ya<#YhaZ8tV3Z8hpL1CzOU&c|L4zS9xCS3V`v<-gcW%V%AOsQ20ZAOp3-4 zZ`8U8H+~guj~08)ZG_v<@)hW zBz&xim8>*RuqYrRI-sazcyt6`G2@M+}*6HQGmU*wP1^)riDcDaQj{KAvQ zm9GAC2|WT0sfaYaV9GltcftGLwbV=dh^U~BHA`&Z$rXHO{3=;*<1Bq!#BhnEew7>sJd!`@g`RSZi zsywp2WwV>J0c}ZHs$42FjraY1h`)CBbF;xj!mxym3oHK;Hm8Dd*^lV(uF;*svV{*} z;i9l3x8Vm;)xcmTPDh)hZ=n=#IF+tyw+*G(qRy0nnr%Pzjeuftbpvc>jH&K5WZ#}Q zOurc9pSUXTjul}@Ur$~bJQ3xsq#K0K!7UgDt;H4l=gq3qD*i>^&a$46yP;&`h?A_p z`I%!c8#=wPz976OK|_`(D5jD56m>QCmdV2Ciu!R|w`l6EiCC6CIjIu8xY{JD8YoS_ zdPV)dDd(Yp<9%!y-~{!+Ziy^yc&JAv_XayoHT84?IHs0x9|{qePu4(+_DL29x+H>t zK*r&|y~jrpu}_bu3r3=u(B(Qz9RXXKcgBbnd*Ul&%yC{AS(*PhJ1yKV(TI^`PDnp6zm zBcJ-zB67G%ZnU-ciKLjN_s#e&y^>dPr(I00?q$XkH5@z`C?H-+gziM?*mQi1rmlqT zK7FB;<&R-M)`zyeh&eK=q6y)FaU+}XY#&F*$(*p#OK0jiW0%IG`%o`~Yrv^&nTT;U z9opSMh|vg^rq4TW>vQm|DfnDT zHZ?47ZbV@LIywPK7cM|O+b$DVJ~avIqd>R2Pw!MUE{% zZ|&USO8;{4>wnjT=KCz0#Y0z2&$UjIJpL8^tNGh6d1d%c|8gahto48P_}w8{Sp50F zYZ(qYj|Tg{1jYuuVq}N}%%n;``O4ykEbZOD9Z4s-l|x%3q>C~hUO*id@6 z&Cej8Oo?ZM7vIaPDs;la0Sks+d7W!MWL?&vRIa!M$0Zt{*rZaTNtd0~q#|y&{(xck z37IDA;Ba=#j8z-3smXo%%7h0aYX8R&?1L_KnW>>tVY{7UrZL0Ld1^*Mhd3xIu8f8- zF5h7a!cuRJT!-+czn<*)I*?U%Hd$rc=`yoaJ_5B@-iBv684AgyEi-($#3 za~hp|m&@IT1*Tvq)PmsC1Cn;oMYkp8JAUn6Ta#N;hz%GXTsgIUcc^3HI&xVheRpYc z*;w1OH|pJa_QwI2f*r9^_eVfciTcNZ9`oDKc8y$ZhiY!wNTxpJQeD4qHt$ zT|k6n?QvJX4E8VJtU%9Y2fOxii58+Wnl?Kb5l0M>2bX=kK z)ggw4@Tz=Mn_h0>E^j0hQ8^wr6*jp5UKBDD)VSjo?sXV^7#M;2u!t;^esZrmh<`-` z-0s@Mh1U!iP8VkR0``)$MB#G192GQ!Ci#2MIe(_PB?rG1Z9^Z)M6&A>0j_&@8p60FeZ`aC zDZz-K*4WM}h32`F+te-)CBvuFd)qzK-6!(2Q;VfPT(tWor}Bq*P8}ZfJm_TXZW+`P zejrtv+{{Y!K9hNS+jIkwwE=r!1I#!4}3I6qZ(Qg0 zYU<9X%(lZno9n$%9z7cI0Na$oxgnL+S>NX>qR>wgXP}sk{t zDikZlIs|WgS)DUc#ejwXyS8$^et)1QilSf4O`?6}@2uEy>(S(HNYBK7*G4UIhj%Ui zy9Rl8_MMzEw_ZNaa_Mo-zMFAX|1bLQMrheHzIPW{o5{Z{TUIZY4_FW0&i!tc7SBV? zEYSl^|K>Ud#so_pW~Fwn;9ky}UjN7LTYSDtd_5}8*|G2r0kMAuEs@C!%Y|6rYkCN_0`(kjF>f=)KGPF5u5rM1K&Q_)tu~xWZL&TJh<8% zAE+FOf~v%m;@e6z@7$z4HLX&UlQ9j1*hUMP`Ehf`AdNf_PkuS`LvDde-ANN!H(zkm zu@%f%g9aoLq+V{ky+;!(p7DODx8ckoqjem%CgWPV zrvLkLafQWRL*!SlpsNU*xD=R>RBMDcb{(=zU#)@+ym)vb?A)Pe!u1hRm-6QBV9&YB z=_9d!bD?Ri-sG+L!Q_s%{rQ*wt_i>UvugPznY>rBKacz0etFe$W%_?l7ys{?$nSp3 z2HEfD4)07to>d(NDhQVebt;D))7)vdjn z?M70(IE&P1wx5MXcVy=`3a{Jt%gMbHQ=VSGG1NU*uPZ^79KPr=qqNegczW;s#wcPj z9tLi=i)lZV>OwqB6L5UO!h9nbf+Vo<`aD$Zo(abbrVJiraQj#27K>w_2VAc~_uqnG z9N5W(0?6eXmVZCqxB-c~n#p%k%*JmDJByZ1J+I;31$p`D4Pid0iZRtE8-IToFN##M z3vj&`oS?jYqYSThVj1wPU-}?@`t2h5R)6-`Uulng>EHd_^gSSyd}|Cewf?`yXaC!i zouYI8yY`s;*VVd9eXe@0`QNqwGr4vq}lS8l@*DB)fVFCHCv zGTsk}q*)7XGJX#N=!Cd@<~z0P%R%BahjX;q?4v8EF@JQ6yT$*o9c8DLBg<&|kb0tw zJO&&1g7uvd#gYWfVkdB%Ql?taT#LgXkm9f+<*%OwLUl+w6mPxEEd^gw_w9XEZPA#B zDk)w0(fBX-QW2 z-M_RL?1G`mELm+%@rO;)fMs znI5j2rpIKf_)u$#sGg2cezScJuJvZOgH|ivQ;}?ugKkZ0vxACG<&yDx>#fT5WngZ|!w7%sa;S!=y=EGT@(^9L zl~_$z`L)WLl2F+Pv6>1Qp5??<_(b`ee`>XkM}=p`lz7v)9siX}g5D%QNq`np%T z4_{=OXCkZ7-JccuT&se~50Q_~v>k<54G#EuwOf{q7P0Pq z=Yb;9*a|APzr-T!dU5fw(?z2EG?o_z!U}4Lf-7s&T?lnJSg+mm5lrRp;yj8ZbIiT* z4Sy+UJ}wb6T5tZ0A-8=FPRcOv>|S(BHWS*!Y8}g9;mHbK!N5CjUl18al1|^hY2=W3 zk4HrkG#oL{iBME~o0fO(V$A2!P`f)#R<-29@DiWnm#g_m&i~9*1R;s4g}*{U{#(AAnRyaf162(lV-)Rx$yO9{AMEs zXViHh9KPF}!B30pcG@xr4qu=QxMHwGa&d7rt`1Ez#r#Tx%i&nJdw2$36dkdV)Qr6~F6>8?i^AOH_}OSY%nAZ; zQfwlL@Yom-vA97OA~!R!N*5GJq?SbpMcySEI~3|!ohrPRrMj$11T`-$w#`1%N=~5W zl69E#XYLW4+C~2?oD6XuP+eX|lps!SLk{&O?cQn-o`oIWs?rQBCjP-K zu)`9@(Wg>9zdXKwaBASXhC`8KZ8w%)4#CCk#?2cQd6s!XOM0(I4{lR!i?Ktg0mT!U zdJhdBmdQiHm_6sLYjnd@wLYC1ejW|{Oa?MgFe=x1r*X6WjJ2NiAfO8X$Yh-H1T>CU zE-vUAm%yC>h82f(e$}UXX;2yuY^LHN$N+(Rq4Fy}DRHS2=1~dX^=E2EZl44m{6tZi zVZwWx<{!9U@7i7dAhp{{$_@UFmWpBjL4Z6@_^Ww-(>|%T1koE4QAaUqN8u@_%sU zy{j*+$Cxl&1AZ%eD}-6MI{$;K`rpC|=KqTo|HJL%|1VYs9Mkn$I(zcj@VX1*B}Oiu zUroQ6;4s=-i%E|mUy)jrILL+{Xm~BYe(H#dosm341!+|=t>KbMW~Q*8J%OR5v0WJmin+i>-0z{mvWQIA13+ zb0S+fA{q_`{r@U{A6@5923cQt@pCdE>CocoT}QDBVym-Gw*v4eFVQ$5JN^in-cRn8 zr|ml3YZRk$G^&I>b}}yb;ZIDDPh=-47v74?AdkEgQeJ9HN3p&%GZIUiBY%vbC>4#4 zflszv_a663W1(zK9je_^?2EsndyNSNM>x<+Y2Xd8PE;WiW5qtjLZSs2fWnTA>av)n z71aeAu8Ecm#|zVea!%8mj3uMY52Srn6`FiaC0xsS6J9@kMVov^2<2@PW8UU0(HP%6 z^4yifu?S#FSrMEnzWq%l*vWXMH{uGAedj>)Qg#0~SE;Wz;P;E5-2F@5;85>6<{R0! zx9xz-E0%l2e{c~$m1w>|Ed&?}i_+atH+!yb$as#j+fa5w1Eq1!Lv;VB=(yD_|AX`T zYCD9 za>|in_`vblpjIt)B)pDkN$kQ!eyjt}F2=zP+3seC3=C?oqNC9VWtSU_gxjzIqjGY@ z3e`E|I{94yiX2ZP7~Oly_><`}(H7rav^Hf?Q<+RXwIuo4c)*nccyzOSL+oRZ>WtoQ z44p0o!WzS8K56M6{L_7sCZxowLitPX)%FGh}*JS_!W zKGLe|Ch>L%a4T38hG>ZPL|z_3!8GPnV~|5RY=LEc2yft`PJ0^n*dP_VS9g~G+|J? z|JJE_(k@av{B$mN0^%1|5&S%c1pGpg>6z+{@#CS_{KksP->_?SU{rH&xfI&SR|}3Q z)&@4SpxbRf3Nqos&uC{?E=cKA?u9bV%ADv{)(QhuuMX5VJ&Xq?1{b@lf-2@)Cvk0- zngYh^&9tL(6Wg6QkV@=*xb0T!gZ88eo9zKQmbjHc0BBT**ZABn3cCP3=-2yLz?7xN zZ>TzMmBI;}Kjp(>o%=-GYYNH%v|b-|L)_i6s#YtgTt4@+#Hy_*n1bpkOml8Km5zi9 zDNNf5mlQPzfm%m#Xnl*5prlK>+&zC0^&RIZLuXA&ap589xPIFW8mkZW-OI5h3uOG5 z$ohMHiyQHQ_y=2)OhmoPj$@F}Ku*PDE2?q6gQ1#;1|^gfl~|np0GXDhw57~wv3_y> zPa_5sII7kC8X$3l`(y$Inwuo9wuSf7h}A(G8<4wZN}wq!Q{bCV<{2>`(tiu(TP^n2 zW)6f0bg1^RAC%!^)rd@588{?8B?inH*!}wd!C(Ahzn2GdpW)gdE8-geAKbUcwgAe2 z{~^E%%S8Vp{b@XO`z3|p?K-9{bX3Ywmw>nGA)mJQ#Un$2`P}FNySq{M6XRybnGd7t zHHPJS=Rr6X4LReByc-HROIWMq7c~F=raJ3WX+y0q_E__k3*PzlRkA(NK3*Q8S|rCj zVA+=S+GJ{PkS5=U@8>W*l#LQa7R4C`o#z0Zl(G&gy+1(QjtMzUjKnLPvNx#Vk zc6dwa$RD;b7S3*dsr!iW5Dqv-732s5V-vE~#IDWhwnr&sK@Z()M$G!?fx#+K!zLTu z@F7A9;0+HSp>E&BOi2Bo90lMR8uloKt@6+*P(?6v8vcO z0Z@YHWXkkcM4ouAYt3xzXj*5{+oRzMN=0|rK9$($YI+eieUO8$#o_)xkM|HXpRzCtnX*3Cj zks21gtpDJ^2Iuk@(62AeZ~K#P#!4^<{J#(ig9b3@djb6hTRoigH~$aD9R3gffk6kb zcD(x`_6>IbGoOi%=w`2H3Jd$;<0EMKmY;LZVqo2Yw@JJ13_<=pQ_PYD!UfB?j_n&%=6nxEx)+gxLI2#S@!w)IA26ldy z87Ic#*jWp3ax-qx8zts{R7rg)us1U^TGB*_j3Ody0xk@P4YcYos{1R%yH6j}%X_kU z*U-n)jDQAq=jPR%*SA*1PM*X*T-SY;a%*~USkqR~+PEuP5CA-v-Wuby7g=xM)#9L6 zNN@(~9%4x=C@bHTyG^%+i`~K(VYw4Lh>^ur7aoo*A$^y8yB_~v=&(o0kl}HM#2+`jp zj0oM+y_!&w%)D#OWfztSg-3={uXt!F%o!LsdZXqq`z&noSke2;SNK7R&OPPUjkAHapZ*6OWIr@V9Zz7{u^qf13dMqWW~h zV6=mI!6>%!2y){d9vH9Z^rW1>tNt7a&5^Wk#hm%dbgFnpp9m)m4=$k0J;}n2g`=I_$`H-MNhp}tJrO&JftRz!V27lk>hA?{$?lOU7+EwkP2db^MKL&Mwt6#m z_-$}5Z1wmE+nCz<>JATJ8Rr4CH#hAX?_yKY=JAgRrSj{47n1%!d145pdlDVD3sB%9|7MbT5R>uS`Y0R9I-;YH+F4iO z$WB;p@hiOod-X(6j{zWg9A+Qpr0yOq$V5`P85UJ0{TUFJilkaOUEigARHsDDNcm~- z%q^5M@qDMTgTZ;|`7cje4+9dd_+HPAGmCq3q-zzi>|M%mon$6cHxFMj=Pv{EG~wT6zz%uqH+M>M^yuENk1}3}(0QK9vQ*wU`Oa8 za5!7B`cs`Nnm+Q837Iz~Le*Uztd?~EazH`3RU$estLDUPTMvhUBUnCjq$b_lz|7GG z8Vzo`$YfdeU7|am<3~)7|5&Ineab0h!;^8KO(`r*anEj%;n+T$^MYQ|=3_TsICao7 zZvMWd6O}{O5mZ>56J#O$dPB_*ELAx3(bmy9H2T@Y@FHu_o#EML|Ir_rcXtzGfZGN* zdJ*ozMK@_?YEJCXq}lLHTaoka#w@RY#KAHDONTc3#-=`G{ae-)MV7mk_$!!v!Q+5s zJ?5$QrQ|uW7XYhD^*S{ki(IFjQ~OE7%2@+ju(Tq_f5%}yV6xY-^;qQ4piTFd{HAUl z5%yelc&go@U1||fJFugsTLU}^O7XP^w?=0|B8+WLYiJeXDk$KX)NW!@^?&e{!jTVA z*T!tfSyh!Nz3;JG9C zrvp%nsc;}R>29Au*|p?_hnOiobu97k{0-vYP}W;y+BP{p$;bwokg9n{WFfyrttag= zzZgHwxCjFhf0N8>ub5?i2#ta7GP3k^s=a`fS4cWj4%V_$IY?A5wu}5|P;aXzrGK^J zSpykML^qfTYJ_Cv>)1mj!FmjGXOX|oG(T%tq`2s^t9>N&&^EJC+vV&w?>RAZhNRJD z`2hc9?i}Sd&@CA|uq1~FzXm{~88!``wtW zllHPdYSyaO9W64?a#d{-vObP0u>=67-<7EV-Cy&J%}urJg_wtoVvKW!?%tVAIPk3j z5SjRSe|4YvgBDxuH5gnSJdloK>(Th#t3>J3Mb!szf2hQS+pA!sfB!!3HD`S2csbcl z)#UXFVp?pQm}4i5my5TBW+8gr_2^^FY}1_qx3Y?AK{sa1I;vyB#hv+=VDH_{9%nJu z9#yjd6}6)0bt$9mFRd6;qSZN7n|a&IpleVqQ(K}Aqt26tE3>9mX^i-R6&m&y07jmU zpK;e*DYx2L4T>{?SFe^io*mj|yJ;~d+Zk#%WKMWi zB-zdPThC{E6CruW`mt@6d=++*aChEPT-#Zx8B#jkD|+hd&l87c8|j#}qsVhp)A!ZS zm+S>a+AgvE`8rC<3XseFXxz4M1V904v4q2iwp@DF@Av=UIGOKEUYfRkb>6_Z=d5c@ z|A6Z`*sWT-7d-LEa8?52EP3|pT9aP7wtn?&DqY|Bi<^5;JBdH*{9w8v_QlQQ$*e7` z{pMYpS;?i|iv}S521rr2aRp4ybaW2u7FlmL*)ourXNqqRTrXmE6_2+sY?l8ao5{}& zG;!djhf-Um-`B6UDFZT`senkKu6^m0ZrgnXU8Vdbvg6rjjs%=`)VSWo zUTGibEqQU;7rL!;s#FRaz4r^BIYBr2!0zmD61&LjYWIMY$;h3rx5M}IAKWVVik2Gs z*=&E@r|6??Y#io!l&%i2Vf`N*C9=Pw)z>Zw7OW6v?YKpw;f=uu7^82N!wBNI^KENm z?gR1$k4Ia!r%|SAPQg^XD0y^MmtznunI%ca6&k~o^EgVHiXl%cj~wTfN7t2zR-SZ1 z?G?_+Br@uxc<)`5`NrHM_I>ANV^iU)$Z&q6$Tm(J9!zmq}+4KFQ(qr1imcW}C zo@S=p=me(&_=G%2ryB3JCfaXUHMKI6M=~lFkl4q7?k#`{(v3cwuTu7=Bo@RoB{evKbyCqCRN9k#7$;6Wt^i8Ocfq3kvf@H4pYLNn!?8l6|(< zORqyU=jSo%iBmBx{Mtax6+7%lL>u33e&cxXG26f`c3V2CnX~be)grt+^b`VRe=Of) zYo2azDp*C~x+)t+%lrDP3(VL+)P2D}o|I;h5%)m~9|xteSyQkQm=<_VZzr;)-;O?XG~@HJM^1Kvz~fj(vF{AGSJt}*P3#?vb?TNEjD@z! z=adsP-0-N)*yALaOK<O@pv>v$!m*maMbc4+w1M01ZGt`?9U%j{zY&l7Ij8Hzc3+|VHO>{8>XwZ!ZV0mgk=L`0MG zJ1~|D#Mw&YFQL7zkwdSy*#E(~4?cF)L3%e5{B0O+SnkaYZulhMPQm^bw6L$p0dj!< zT*mO2T^Qp7b_ve2o$e#uH9yX}%avL2TuJvOyJw^rI;@{vite&hNO3X1YKL%S~lpsKeLNJYtLYsKr zg|GG%iLxveYYQwl9bU0-PCDe13O{rS9Wsz3(pKJmug3`NUi)VO z9}n4h76A_`KI z*e;q)NJJ#ZGs3IJU`2OW*;mnHvJSfSXYz5$2bMIHb{-m7O^D1H+|)He^ZwL5F0I}u z{at!FIrGYUvd!aG>v5JZa7$pE2vhr>Avvqmz2#zGSo9y_Ghy zTv*Gw|ydn^`S^mz)8#@*l#jAl;!sJFPrxMsK!v?P8HZ<9trlkSR0fOt#jq9Q~CdGpe#=ayo zmoa&mZXo4_XPFXv?d7*S#q|+Y_iY;+oy8|xocUhE*M*6xoJ?)nBO>}4g<^eQ4O%a9 zk+i_|w$J?DLBZnI4h<=sCuhpnZverS9^DidCnc&MHd^SmL{;TpP2Zh){SKMZqdABT zOn@drv)+pqj9=`PxSt$HiJIYp#T@a})wS{_geDnN0gqxB$RgOF=3AJWwz+4mM)`VU zlGAs{T!GXa({tDNM`~1#7>uA_C8TgsyU`bH_%QMeCKsDWw0{z^95^a^%^4_9!}|yK zxmC>!`whxYFsU*;K{)wshVP-q?4iPZvYA}u!0BV(y-SKO?%)oZR=Az{2sQ z6U-t?S%kka8#Z8S9&@tS=TPLo;A}yt#Q=xkqxV=TBo^ zig9+KpM5BF-N%8=!}PUz=t!dVL!D+|WxLjFtIiqs3%0K&$jGm#VIdAR^+byBEbPs= z{$Q%ftcC%@DAZgstlK&+GDERO4jGHwc$dTL0I=9r3TF$zXm^)Y*Xt@8}7sI+_JCRum( zq~0(ItT*df+}{YJ?+4vYT=mh@rW5^(+wr)|In7!yJNv_$xKmv`>Q&5vN~x&0(2VMA ztWnO=Iv-strQe4HU&F=1CftT7lMk-A38V}A6|?jhB%(2>=Yj6=@M-rki4%q<74qwj zs%MJb{)b7gsz}e72DgG8uV9gLe;PLx_uOmEaNeEbj;QH{z7rs8 zx;`L}{!0orOsp!$5oG$P60D73+xCHgM?1p05XQK1Rk_Nfn_`PnC5+0fg=X52>SN&D zOlr9_2$i9Q5FKL@{eyGpykUG?diMJVmuUe@A4P8D9~Zj9m0&uSv~xZYPFU%-?cilD zfX;tE?MC6H7}BH5GI(eG6M{Ct$o@vt=kW&ScjSj zm02m^Xcm`SPPYP_^isz~%|_!Y&ehiU!2?&y@$3f!Q!?f6*UQ&5Pkjvvp=`W}72DQl zMN0p36UKn5l(KdRj~d$6CtXs}!y`Jm8L4yW z^N9BI+%o4f#xE6lAy6#Nd|hq99dk-3`?Dp7ovjofD7B%;wY`%G*npQovbBm8!FT;x z3CH2H`!bV(djp}M0=RWkHv)?r8C9e8VTtoM-+7uK*_3Otxu<+sa}&vT-2-66d38g3 zb}uXNWo?Dw4`cGXizFTFtGX_2e?6)^3~_%v4RNPWO9E&$$9NTwOVqhCkD*;%@=oA* zA9N?9vxoAYa~HulbL~dK@t!+!N>4}5iZVctmHZjEGE`G-hUZlW3flB~p4zch5x&p?iP#?wzy9-`FAb>T7PJyV|Gs-yjp| zkWS`N4H?gL8*>US1B1`|cH`z25Dbfy(M;P0LMEo+NZZz3;7xX`P^Rg6Z+f`s3|$|* zA2V<;@p;jNE!A9~?>(8k1y+etUIC6H)R}ef-5k$QO%^N5(jyB@Xai%2-eeB`3+FNi zc~FDeYmpj}{kkPS@+q4Uc5KoRL?C}Zx{CCDD5jtJNhH^>T)abIzkV#|%B3<9lLAZR$lxFT;b`_f%9RSo z2FOPTjm)s_(p>cE-!?#6%}zNpsc+4a5W|apDt$pocF*T{OUF|o?5qRk?cc}V3=w%? z-o@R1_3xk`Gqp89UNP#{Qt+!D z4D*jEPL8*l*7q0|Xy(C#VHrij2{G$nxY6fboVn=fmE{$tYnq@%-Ga27czt7IL5&X$CH)D zp+<#NKj#3qoB>>+BA zw#_7?^k9^IDh&Gek-U*_3gg%9?yU^z%&v*6V$40ajDn4f%PYLa!6nP#gONGq&~|fe zknDwQ@gu#0pd3eP8uLf5-@J`conE&!4yrDZMWxOf$U?W=O?qYqdk!jR`p9jrL zDht<$z^L!uOC@{PDTIB);*`pJ)=I1#thtx}fP7UrSYym%H{)H}6Wc-iqc$q5182^< zEHIw^bidu7SkAE?CK#S$yA6OEbaRMk!ZN|7{|j8m{{t}fr1W;hZI-N1|>l&X%LdZOcf$h%Frelds=Pocl#hm?oT$0;q zR}0zfT3@88Mk9dgYi;hwTz4&s#6v8$=rFe#^Dn>NLn(h|cr0y_5=84chIB8tr){p3 zrF20*UfHTA&$2ExpbDQla={|L;5oh`H5%kACD>jtu8(llO z*xx^F0&Rn0o!okdAC{QXzHy{GYty<+q7Qk-dD-t(JmhC-5F9{Aio3eo@8SfLNB+?1 zo|l%~YfolMe9c%v{Owc~=o8kdAyePW`kObSo!WOciDZUrSwd^B+D*^ff@@Mj_{(TG z^y>tEi^8?=WQ%Gv>-6a~A`L#uAX{wW*kJAS~6pYokQVprxDkk znHPec;(C}CX;-rGn)(~6>@s5B2y?5*A;~Iq4Fz4{W69G%G`XQ_JY1(3ULdH@p`-FA z;=$U2+9)kA-^a+UXBMB$gHhm6h_e);Dshef$RU;mC3N#F_C*FVBiC)4mPsC>TNqK~ z(8mY}kZcFe^+YE)K5(@6(vdAbQmrk1iqfTRRY@f#t-;Wq)I05dpYuZ~yoNiNbGcT- z7ey&2s6kL$H6v|Od});2QBQH461;(ip#>b*%1I2yLm}U^yFIH+V@Uxw$7Hmb_RN4} z((D1jd=)XecFc=;DP!N4S7-vRI%S$UeoZ0j{fb!t%`f{lD;(60^K7KwP?*zr#6HbA zYoiP)vqPI@AO$fWA${D^X9x$+indjx>7zq63T$>vwL}l8#_|yO^9c}WLe(R4tt-;h z#GxL&KfH8*q>*t|8nI!bX$8B^?jKy39GNcTVv9RB9}Aa_ZYY{}vR8I7uUQm)ibX*GCNjyi?SnzTMQJcPY#^LScbz^st=GAYS9QAej7$>! z4qKAjf(OMnBhqhET&6`RFZ}OHY2cm>F@c~q@(B{sr2PH>=8QHCZq3kf#1gKPM(gb@ zu-95FmFz0A>+>NI@1`hq$`#F_cA8_V1Z6<;uh22t6E@Y=()VI_UJfoeKBJ&p^p-O7 z2CU8)==R8c_aVwW8@AY`4fBjTafPNNu6S#KaX!pp#tXMbSkghfuiCmg7fyn0%OS^@ z99a;Y9Jszz3=V&~M+=hI) z7bI2w!J*U!>828#mjF;l7Q&!W!xoAQmSmF7?e;<2Ap^vi{SSQQYgF8V>MZluu#=ee zT?T;&Hv;CpR20!NFzX#UdTe1JZ0Jkl4!0+&uW$j(Wk6qqipWrxeDc)S_?-@sI6J%-lQ8m29dd;#WRt+ue@Q zYIN^2^bc&Ml)Q}fbs%Q2cdm9cy5(397sb|3`oxxI)Gn9NjIBmZS%PxLYRP!-lcxR55{fxe(eUI#)S#q<>;3@&D$qE&nd zAKE*L+(*+6Ag~ngXdPzQf!pRrqr%R`ANyThO)E+sD^?0M$|z@<=eYOL54uxW1LA=h=N#tO}DlM{|W;xS1x@7b7K;h6# zo?>lhGBuv~aByc;4$GF0v}u$&vj!i%4*p&IuYYi8VQb)gx1274yzYPs3&HJnTFsAe zvyHnY=2BIq7BM7$mQ2TAk+P^NdOis6mHK+;)5vTeE%{Sucp+d~T9B<|h}<*nCFIo-6-JZ?|Gwz{S*nw~1NjE9lu9Ct3;0EwK#AzYNvd-1g=hlzG^!^6>@@V^XxQ8|MO|A5Xm^VJ;1;oA&e+glNd7C%xy(4YDJaQRAz zumES$EXb<;7^<;n$~l8iZ*yYjaY+3w+Ko{5`%A8jMLC+0&2gHC)!q|LS(~v$aekG9 zPE-Uu(eyIipwMxysL)2z#yii;FLi4vl2fMPpvUM|kYq_pnsR1`9a6iD#!aJUsK52w z)c{(kJF5qW(7czrI6`D_DTFXJ%R40w=8xw#V|78l}>)-oTC0GkiL-&2X;5AEp$3x(xmLao*)_PIl0riZW_8Nb7+?a|p6 z5+SI~GT z;nx4q81ZW?%eFbl;o6Uqf_XW=u51BK#J*n+fA7a{d(gCj*$McAD{`@9IlC|r{`jq4 z^mPM`so#}dP0YHnXga!U9dp&2q2SNFH~%ZwzukOleN z**92UT|S^OG#P;w)k=RTm1R3I>BjgGBQowQK(~swQm3zm3fkkVpn>zS@`pm}v+day zgTQJjqTR=x`#1qVA%g(PJbgmPv1A{q-XO~iCt~p7L*YS!eA~-ExG#FLACoXV)+vPo z-f3)-O7uo#PJX10Pw;MN{jCL&iXp?i^p{nHwo#a(7bGqBdU;*Kt!uq=iOZ+;xPGQ- z`B_EvB7H?me)p?xzPBv70Q6jbABbp!GQjCyJ|wHOUUzY-uvPwNYA0k_76kNjVBKdy z$=AV5tvcp}7@(eGbwnnD?pvQ}+S1(M&D4as4P>R3BY@}yPySfQtvZSzR$lBOFkw@ z{&Om8uGk4`6%MF|TM#jNh{9Yn``Hz!v89s>EYwSWn3}oCM7#Wc|B*e{pMlRx^MVx2 zp1{Ow`#cUEX_+v@h6gXj414S;8tOdbV0O}-Uak?w*NY1VWX1-B0jTM~`00V>tl z$mo_?Fuu$#C_6TAVhT8Q|B(woh%+(7wO$ahD=|4;aXsq~u>5>F-_$0VMbX8+1-du0 z3h`kbL|lsv%MV=Ow7TAWitJxueNX}&vN%QsCm)+Pjd3MiYYux_Bu z+;Inkh{qM%gJ#R>b59aZrHd^NxrCF1KTH^VE?jWx>fdcjf`-Vu!3o{<%t<1$o39w) z3VgffO`+^9dHG)35Z^84=JCReTan_99yYxu*jdpX?OPVb7T=+^!E%OCiG3%|FDdR5 z<}afciu)kS#s56|2>Xm;FuAczGxn7LR9-!t`H`9RMBa#$6lEj%A^rYL9LJxn?}%Pw z&b!Zn+)ABJWQOubs*4q%k?_pe0egQI)9f1Hy`gM>pE$%m?TcI_WP!d(pnVVWBL3X>G~5LAwuhUzJ8as=AFM^ll}IOso?j& z{g($78ZA<9pFN1<4!`+tD2A)rMaF0m&9U`%__v;i_-1QGfu8%pNlc_6Pd-8;%AL() zKbbWRj0;aj%=Q%~i!f=fUE2U+3sj|uFC@NV;pUe+{tB=xFp}}53fEYe->sa!FiHWe zRre8C6KWL!dU8V+MYU#lzg|G^5E=GIZo5|`i%`cJ;#1uy&xyGATFdyF}~`==_h)p}O{p zqGr|y1Be%AJU3tWR+D`B)i+n$*Ak0`A@5c^&L)E8rBy9AGxfb+b}=BtM$mW8*Y%*X zy=xPBvazk*_cwXM_ZS#>tqA$<<$kOF&$)iL!R|iSoopz0<@bm0W6$3|iruChPrtR2 zjhE+VAQeoroc&e*obpg;G)ydy%9pU({twQe9m7KCEabS>V6P*Kp;W7wFLin3AI`NMk*mjn9wm!-;ix}Odu&8%yIO6HoyA7+YTo%quZ z{~J2-)S!x))@A>AWmTdcSXI`zC*C^KMdcF^Hdbkh=(X5vWo~!)d3+0T;i4D9lGcEO zrm~Z$@`*h84pyJBJ>`sTq(PfdfPbIg*9)JvYHUey`FSy!e<9C!3Z`85#&~uz$6}K= zme!}Hu{Lj3>Q?w2)*C7QzA>_n6>Nz6ZCN@7S$Unpz$Rr-zQ^294H1aE!!q_24Qu&V z3VHoquwzu2MBnX4T?yCM0|9<zW3ndl6vpo=bhJxm8Q>Q>uZorr)}M(fRX>=y?_XM{(X$GcvL+5k{@a1EL2ktLSt~EYT4|xAmYZdc27)lOaYh zy6F*BqJqh0SxaqR;S-1z)y&s?ZK1@^NG4Q(&ia{e$Ti0XuOx)-MS{kXh6+Q(y0bEh zT^g2kYhes*u}yD<4uivjq?Rm=RZ~x{rUj81hDzahnm4}r;NC%ge6A+r@2q7pIq*NY zk*tw7%5<(;@1_nsKIF@wqn`!^F3Q>6qqvRPC|Bv6Yv{lswBZrY{Y`uQS|lpn#j?sB zj*OL)+Y$3-;6g@u)QbI4Hy6$*Is!I1cN(6N`8DLxEC&T+2_9!hPL%1eVm7;Lc|Nj1 z?GVBQsA|#^P=7|d>6_SdPSp}ld8v@K3<>wq?6n;3=*FobC7v3Z>bLy(%TIt~BDfSV z6BhwN$u&aOhN|IT@=y5*8_tM*Titt)Vu(SniImT__U@^t=vf;FrK z%NxCMBaBi6OTgc<3#@|9xuirI6t?7sQ(lU;l&(-Hl)zR!juj}^FS%s*2Tn4)ZNNUW zQ>f%HxaY-Wv**)~9u1<4h|VDn+v-!?iZxV@+kpeWP>t|wt1|WRiSX|o!jBeMiV6f; zIsEvghiyw0JFV^;YUkn|2;-xi1)8Df7~|+5(<4*NaLu1;(&8(I54-I|t%>U9I6C5a z{JD#v@k5|t`*d=AmqKuecdpg>w?B!y2A0Johb!y-^hxiTo8Skmzi7$6@rCW|mw;0J{Tys$e znuKpQa5RvWqUcfBOkdX~z}#bCy%>>UZ8q&~nX0Y$?&-3_S22Q%-T?QxL|LrfvsPXm zy_)#_h2M6Zf|Gvd_8NguwSRRKbK(^e_|hOM0HxP%DeSXatlrJ{ZAzp4Iz;p89R-b( zJx>4MtUKy1Hv8mUH_Yo5+w-vPjdOV&<-9dwuMZ3)F-BS+FtVKCR*~=dbq?W7W0jQA zm>Lq=EYV^oFSPy1ssML4U$#ndd;Jh%_Nz2%kwXCBCyHk?0}NAO#Q>51z?U>=*I0s( zSz{>NS-RW_#2G$L=Gm=QMVPlzs;2Bz2GaXbl)3keP;J69WG*e%XEm#AQ+pJwujf=4 zbiB(SvHD|xD0%!l*Wo8Q-6%|dHHXc+4RCedI2`xqxR=(d$PxR!D&%ZNvm)H^(V$~T zlR%ThFx+uaC(mba5x3@Ss?nghpTp@w^Hv1M8!fXz{QdagPjtM9i8!nZHk0*n8D7Iz zdxUtxn#LxHs7p-MOUz=;wNJ~U+x2?4AH$MS_2kk1=pFBA3@2=!2eqF4%;277G#3-( z4`7#k$yk1_0Fw4`JJg`GwAKBD=R9AgcoInGLA`J|IobW>VfJ_RHP4ED>AjE5qg+m@ zu(39<#2ilI?i{zY>g9m(9sUgM3hmv~u}qukbd_)a<#8&ud%lon1h+_Sr60?xWe9qP#52TccS_f*;cz zRei|Ec>y%RJ;GnUm2z}kGgdf7cu|PfVZG#Ee>X(?5z+gzOhD1s?nAGkdYfX(2hTcZinu=F`+>IAkxM@t%32xVKk&F)Q9KT@`yHE%_|NIdeyKpCk5saA1vPDLc zv~cP}j~$A2*f1mbV+wQv-p45qIL5d*nb7s!nKnCR<1P4nz>73JD*k$>kWkQejwFk1y?%YhMfMTv+kWh|zVr%3cyZ$`_Rg2r{xiq8R^eS5 zm&?_NnRYW@2UxcrRhveaSm2SM;CwAdM52{u;I!i~_kOA#FO*`4vzt@@ARwE-*jx^S zglwltBPLchoVMviJLHFqMyrU}qqq<~hL>^1V=fS7*WLbR4r_#7XHLH0MIsj^LDZDU zQB8kixs&@R(lRl?t*c%iXY-&af7Rkr@{5rLNZEXlSD-@+0=Eh^w8t%*$E$caAKp)t4?VoRYPCX}9%9MTvdCz?YbDpYP&VzaC1a3E zXb@bT_(?qm%&Tkg!$;1_cR=icC=WbwA~H0HqZD6 z?F8_m#_N3r^)R$%rWk79ye|)w!>JXeu)1Mn&kT#`6sqaCBKEsDVbTAjhFmhX0!qF1 z9sR_7ejvW2Zz%s);qM6bxrD(}C~|Ez#>J=Y=TiS+4npbLalESNa-;SiI2KPK>DGOcv949#emq%eK10gN-SvyQN{|L#LfIkT@@^PyhE7=2i&vrFw!)CEO4{`Vpidp!FlZ4xQ=#5fD~907tw7ywi2$ zIAi!eS`L~AjBGG9-n@$-3;U!_&nw&bTvuH!mj12e)XzLnOhn0Z|E@9M2l8@Van1h$ z!$3U0YUJ%ZokvT&;$B<-0B8!?gr6i{ucO%v{+0fU)K3RozS9;W%P`9F%ck7%P+OjN zFliR$MpV96D}yw_8(_MbZYjBDp#^wY%U@o|3jPF$ScuvIM(uYWdQ0^^3|RDl(c$|4 z04PdW!_A0&;nTm+SK`Ot&;qs64zl9@WsEnrytzLR-K?i;+Wh+7G3W^#MnnB@cb}lI zd9HOT&^^zp40O<^=y7ej!x$)T^Q}Ke_lL%Vx=sWwGV;CidPLEwUOwh!+eoYob9>Ce z`5A_^g+Qhy?b0vQyi9pKf7oaH#Nr$5lBkQN^>GKVpLiI4aiibE^Yn(5^gaGBe@Oij zqoB@TTL@O}9&tTNgsx!Ea*$#fjpsvu zQfuC&jk0Y)fb#!F-5OrJeM4DEtH=Oq2G{GrR1M9KWMx!KzS9JEZ7J( z`qf%G;ZR1zkD_ay{{ZJ_{{TBL2dFC@1_I_!WuLk~x%=b$ih^P)+LL}3Aqzd9Ek-u( z_6-+$gfG$}frfS(35`!snnKFT`8<>3Ni@GTJ20?qUM_y#{^#sZ?hlNw?A#mAp`jR& z1pLGIr}G9FRtCi4=TGcDWk0t3&)DDJAA7c?W}a0OwEsH2(nSN`Jx%(uTqL5>e=TCWEm&I=sLKmS8z_(jH!3B^Zy!4c+Q) zVK=6&t;Cph!UpiQx|m349R1uXlQS&|=JdmosO+&TpE+UrZ!8cuBW-4z)TzJNq@-A^ zD`>))tTqPE(tl)k{zw8&wAGMXZS^x}+Q zE91(}y|dSt>0wig8nFz-mPw-c_K5mvn)Vrp@6?&D(2Cp|Zi(tA4gsetAsu><)%9s>UW z5;8Yh`TqdZgV1x{yFQIG1^(9zUxW286)G@{o=~;>YU!1`H)Y-54FGK;8)p5a?C;ci zK!5ic^W)wFd;tD@K2D;!*`Jja#o>ckm7^lw;yiu`82Eq5dKgZ23ZIw0So#lx1^pKNB{N@4VE#|xx7@y)BHMmn-Ow6RJMMt!IuHKmJgm81 z-vD&>KV{&MP*4)c)vy@Cy&cwJHVgo~7OKlcQj{0HwtS_p-oDYk^)CJd3s4-Eef&!H znIF`6{6n7Dhn7%$*$iOu2fY3M(#xt+jJzt}a?sM`Y_s(uV9p@s@bxv;xBoj zW`8NDdw*izx84WPL1G-y3Dirgy#E#-%(lt_X?JwlA*9hgLmKc1E4CpYgQ#&RAM#n0UPGa$~9ujE6})G z@{IX;{oul$R0t-AmvV@f{6&uI?3DJqYKlulH|-4T^kMAsUvLfprZuWm$5M+A(ECPe z@m18id_XPtWAiMLT9|N{8)}O%kb6D$1NIqlb*~bos3&ZjZCkpBXcZ)SWL6<8QqW9$ zv%o|z>-p0H&){0G4x-ePWa8@GU$nJ=EucN;s*(cm*z z6EU|mtDK}*gx(v}t;<31G2Lf5ZW9-z1EJ+rEtYw)r_*qBZC%GVyWeuZ?m-*}>Z)Md zYctfVumLPSLH$7yyWwU<@R7?93GxRepR!>HRXiPFzGZk-!0TQye)WmJ{{S2szj9a0 z=)80%&2X=jmc9;HskXN2x_-;?`lYx~17b?J!&s-Y-}mA+neD+^zC*450DO|^c8Bnu z&rm&g4lXi3+4cS&r&A;gNUcQ=LE~54T^l$^UzHYWUb5(h0|5$FiQ=Xu;uqm}{{Ye( zF0iMw4~LRN833Po;;)I~EWUN&iC0^=`wmykG`6z=$Ho z#2vm({$bY*aunI?lCsdOd+zbMhwFHyrY^i)ePDT={(a+`W`g9^S3zC_x{Sa3 zKlp#Rx$jtdyFAwNnl<*G(!Q>)yWGZFA3CqiomYB@-GTGHCXs6G0;=1qxq$MQ)phFf z>gRPKCa1c(y86I1PE)NruCK>>mOwUD@&3pm;u6l#rxxqD$xUMZBArXbTy^6Ye^|6{ zT41sqE}DIOOkFu#J5!$Sd(w9E8m%wPzfqDLud`u4T4x|vPOGWsezhl_E~Rc#irGFr z#?iHLrw{!m9ShgG9^a?+FK)tn7w%$exN^J|XShT5gWK$N`(wwYzKu*=Q>^c}50?eQ zZ2O8{6#GE0FE=rGw@VrQYJ}Za_kYyOV68hpRM1z_CvBL7($vD~&(bn@admB>c{{(v z7G{F9RWtrUj zlV8)mSuVAk7@oJQ&xa6xB35a)_x}K9{$edP2#&<-^hvp2D>~oZ`-VC%GIcx9^pK`s z&_x}1@%enbD*|#308H+Emfm=eUsu0Cm<>DH2lo3@R(10+)4ca)Sa7DuHA-*Wb3=c0-DUOE zYuV~n#5&8|>a05f#XC)0(k3QbzF+1P~&_FyT%KxcUG!wv=!7Exx0R~f-U zIaMogf!Ry%(^r0evYpHGmD%kw`SU6bp-(J)+z;%x8cI23yZ+QqpCwjnOS<=!jD>*w z$`0x{)d)5aLDJbb;#{P6*3KXwl6f=bEd*69r~nrHwA3JhTm}HeQ0yh<;Z-W&@mif! z1vSxC2%#e@My8%?a~%~*0V&g>o}jA)i*^41y$8`SIV)xS`Q-Y_8oPgR=DxExNoDGl zwOYz;7lhILLh|b4smyq0=<8utkD z#U4NUa*5sCJVN(w<}8|h2kI8$byR2F+2nzP^9U9a3z>1lvv0%k_-Cj$4^hD%lTCs$ zC&WR7fzfmx9?qYn_D@RGynT^a9=>0{z~BYCj5RU?E8F?J81v4DHYX?A%s!sLkreCS zDMvUkzvVB0AHa7D&0S;nJ>Vz=h8MThsYZIXv*dvYB%F!X82oipO8h`Hs6T|Ydkjr! zK2bLiF54An!#8~mHD~_-B5JK4#!(A9K(+Te?l$-qO{U*$4^j&0PD-<=OVdo`2I%f> z9BJG;ee)}6;ZJp3-k&Z-aN9N6KbA|_o0$O7r0cI}@!vVGG83PPnL8MYD~!~-hS)05 z{KvZtVQjs7ooF-M{qE{{M$CFo7}hIRyieD-GM@;;H)+uko$y$1$$6I^j?8w=-fI|^ zJ5tGu@loDYcD#YU8}F*SaTCf7V(|Fk;M07fG`Q% zpx#6*jr9A(HQr5%(~V+nJzCZ3mAl-pvo*$TMP{k^3 z19d)iR{~5&aRq1;5wzZS+`b7DZ+@}k4-w}q`X1sZkhPYl#La8RsWd*{vNdBz;@DM2 z5bB{dE%oNX+CyhBvzqvaUdPtqu$4{A6%zh?U}F0&uYzcJWiOOV77=_k2-Rj;2S-X- zWVDWLBVzQ;rWJ=`Z-9vl5%KL{sNt-9h1>rC$@j1jZ95O=?D{`tU$4)z)m#Bl-c0)G z`Z4^|u^L{f-fht-3l+8vy@U$E`gd=RlA}3e-tiNY`{C0ooa_#ocYT=oSzM?s)My+m zZoh4P;&hWinvx^yJb`(AyMySS8LMzs?NHhjPeU$#u-Pb5s<1Y=uA}==s-gCdwjguHwf*MCsqa1O<}FINtN#FxZB6r6 zQ{jubYC~-zZi>&yd_l=?{sZl)YjIm`r}y`jMnJ85x36xeUB#KU*}Hu%aO!U@6F#=T zYJ$ML*Xx#FGT6_^xqnv!46=2QJVvKODFkLg)guvIf2-zxPrq`#7s(WsGayn6HQ+z` zVd5M!Jz``|R%I4<*?q_8cM?;Zgzt*u0(hnSj*R%QKt{L?a_(k<@CV=V9uvXZTFd2d zB4qOM1{5=c1@&U~P4^D)Y|(f9O!3{)`ycqf65oN4S@RwtA_Ab(8-VIsas;-7%c*b+ zz++4kEU;OCI*2uHt`1?jLZM(;Cv$5%BMO>gF;&Sf6Jizii!m9QfcFN=d4$V;-1RRz zP#hzS$`|^syt0?ee?#+8+OESlFQY5ePPEI3Y97M0sQwGUZ*wNE{+a%WaPve5(DkiC zVo|@-xniZ#opI@uvFHIV@U%2Pc`+@*H`9HS{{WqFrW9_!iZUzfK$#JjGdXTZ)x# z6~Q&=Nr<4Q7w7f^pD~26PD5fqxxsd|(T?wyYkKa{#qc%r2TLM=FuL;k%mA4SLngbz z!#nN7=whuK-@j2{JwLg>rE_`D^Bxo2a(m9Q0igPRPqSxHf$fH>U7z%QRck`eq%Zcb zbHgwVs=vRqv{iu5v*qRZJLe>*e2zY&iSO>POJ()OD=kPER&>76#H$Pa-t%w}o~tqrU=bIi8k+Iiv!w5}=>6Vyj8KQ!=4th^4IVTNXzYHPB0 z<#PU&B^g+wAHGP0@bYi_jPO_H7yJl(w0yJ3nUF8@{5__Iu~_{Xn*>u(P%DO$t2zl~ zt01>9-AdWNr0;kgZ9#;7g-f5Lko~VXbVfYaX_-GE^d;pCF>8A@@#0i(xWzV7%d*vH z-*W!|JlIrgCrq*EhBqT#>M(o0iU9`0$`3BXbMC-9xgjg2=@D zjjx3d)(*^&3?JD_fhaEJ2H$K|2Z6crd0qaSDtILvB25k~L#p;;BekoRt;VJSaX%_` zR1H5%AnEUPBGXc{k?~PMiV#IzB5~$dFS@h88vn0g(_RH_UydZQ$r`mt9 zj9e%a49lo-1W;ZDX@KXgvtkmZXNF=m6DDBpcP^t9+z%5HTMuwfXPdaS0#gK?;rNcU zp3=Y@!?}RP3-bQ}WoEqUFbzbgK4*xshu%^swr(Wtf)hFe0%VzSPNPt9mh!4(2Bwdz zF5h4`_lt4L#9BIL1v0X<%Q`>?#||K1K{)+kfcClwQ1%1m2K zuN(WqN9H1Jm-8!w^qPjh(F6I2(?6N)aG+ueS)tqZXNANO`5uS3V zQD$2CPc<;qBe;`2GouD`DhQ$iJ4_!Tie|#q(8U`@J>~t-bi|wGHdL>1T}&cLI$)x< z%dpLt=LKa?PER?;pjIz`JWOFerl~S16N_eWL+m9}>9e z)qj%he+?1v=gjK-NYz`PRU|){kwGe7>NTR^?Oy>X!Z+wU>7T}~X6lXdvHt)b24N;) zmxIbnS_TY$$8mt5GEXsOcLaD?ex7I+(?KxKjL zE@)uI+2G_jjhc>p4+p#W+|Dd81EMWj4e7s=xp~Im@%5B~jaP{Ejgd(qI^4;YBdPce z4?mQTf$uOc!5O4>Ow$^QGboL$-?U$1A?i3;Gs;|oyuo&WB9BqKncUuETs9$&s%GDK z@0%OK{zPW2kv)Pl-v=thvKlCtxsP`$5l2(G@)yAKLe348HS~ z{ol0A83*A0pYhbGV#jb%Ou#)dxZwDf7igohBM#FX;_iS2YuujMs-F(j|>o?)+FHr+E?t>2&hty*@Jm}V^Fhk%guTe^yIuv5rnyd;{-do)rN}opfO9y_z8_G zuB-Ju{AzS48cmU)^1cq`Hm_DbKE8MV03(zeL47lFirELH#8F5CEL9(h&%`2{33C#u zXfJd10H!FUdyKnJm*4*YFi2ZTgifP@1{`QYcscn3N{0Qf(Bi$Shp}Jqa01zK(ChrF zAXs(#%oGIpxgd*%7jcFdv>P+1E~C6TkLS*zyIZJfLJVAB7<9}-sP`!7??4e28sF32 z6WW?3E2_cnE1`#~QO5S$vSpO~T&y&}0x!{<3-W)3P>~#;tEoVB6-oyjvKzzjX)M@>L^Zx)V1trr9 znqR~%h#x%8=y{f*-z9|>C+vS8Fwu|J!oc~GfO+!@r3{)J@e$J9T#xQddmn_$q(wRukvDc?inYAfyU2bMpk!(Ui@JurV07h{4X zVr_^_m@gIWDZWAm+lU}^%0}5Y0?fWRDNKZ#-uQoVyJg!kB@b#JD|q@hPwz*(@bPW0m9^whJ*)xlvBPC9 zAA$b>iI#mNYq*;=I_SSpnizz207{3v_P<@3S1*QF^_%YHdzao_&7uVl<{H*DnsWmE zmXp_3H}u87>Wj#sp-_*lR6SxkjQ}92B^Hx^U2pRURD9FzmQshgR%N2+*K@}o37aXj zmfQz%8r)BW!!xD z(O&V~ETOhTabT2~0@)IjZa%3~5KKmaY8tKx zVg-a`dkgs=K0fh|$F^820rT${;d_eo-c~;_qZ1qfJ@`VVLNo*qpp@`BIOy}aUq0+b zy+x(c@T41-yF(1k64IZQnbDkBt*ozfo7+z;g3axK1mFV;l?Iq&-7;W?i!r z8xg{wmLqI!OPh-6aS!l$e~7V9v_}RNtXh}kZTIz-y}1gUi~K~HguusHrXOMvNw~Ft z2j+HJ)5+ms_gMBP{{Tj@Z6OK~lkMC+Z;n2QnaT4vxG8qqifzPYadP9I)IZ?3cq-T7 zBq|kq+R}#e?=$WH0A!w{-%|P!_7?oV^)Z^9iC1uprqOcyOWdqtsx5XGpMR`n%rJs} z9K~)ADVU^J#LHEbb(OZRUeci&5qv^84 zDB*l;G?J`FrDYjq!AITux+0Xp$*Vp4e~9$F<7?-rKnCg~L|dbBi;5*_KM+^Ex*rEp zk-_aX5b{bZL*0Qrfj)A^f`c&r!_>!&OBIc9u z7Q&yaDrQQVG?xqe4W(rGKm+T%T&)e78Zzucj z{BTwBCwqvj9w?U7_C~=)GWx=}@|GGk)Y?;-lXGdc;vXssd9v@S@dbHA@8`?__X(HM zJnMaqU?hg6ud=0>3nFUpSaw*KuX4r8I0GW_>qM?Xc#R#tX5w62x;$LP`x>XG5p6ya z;`tN9i*IpcEH|A$HW%{}p}f9^ZQ za;oP^b<{G^8sejO15Czz;y3kG95O%)f_skSm*RDD0pIkDK*0!_N4R^6!exdGxV7mA z7s?C#y3$ScmEV0BgoU4s**j zka!R2FNK1oXxgSI7@G-}AXI0_6#Jt5`Vkz_k15^mUz{D*VRMZkmM3leN6yW!1asy( zl&4#Ul-w{1rbdn3z$y@(hq(5Jr76&A0qQDpw{XlWhWN9Jv6@NWQqXQ)9|(Aog#`B# z#->cekgvR^e17x(B^_uDzXZA~aa*46`3&vL0jY|MsEEQV0Eqs94CYc(ZYBwk8wp3_ zzi*BpOGh6v$~%L27LYsN;w}3?`2Bj7E1La7{tKVKc%Kz7zo_V0m~Nf+Rem^MD4uP~ zOKf0j1X&HmT6|%G^!TFUh+7gYw4Fol6II*`w~7+V6T32NQ1uEm1J)lzHkFm0&r!hH zWi_w*9}L6NjBWcqlMt`Pf2g-P_(1FC39x|SKJ3TLTav#HCJDWx2g@q3`VEeY@c=zA z1bcFgaqT)%rb&fUaDu4U;-Xf*`-#_v*VD0|APi$zeT)~pD z@r*RNV|kr|jgkfrmN!u;P1q8KweBy5V)L=--}z}gs2A}YTsJb1aSoCfZ}bwsA^kl6 z0L*&Upo@(>1FuSE1El^4mX!YhVd7&TNjFAG^bhy-N2Y!GWvSrIsl0hax&`0;7@b@a z%^4qH_-TX*+FBb{`pT_KQ_21!7qp~4JInls(Y8kB$gbVN2#+E$ZgxMpxuwJwE|(dd zF%Mut`TM2t`6l*lX2;3YIAnAxzW)G;z8=6F`CZM9^a0O$m>EDC%5(|)r$K@Vh%)I} zy)}^Rvr}EctB0pwP#-`YtoKqLK3-YufP20?5Q6)TRNn3pbV-zP#`sJT5$_g;JTZUA zz9vQ!{9{mIvlP2t=TCmk2zCS=Ap=je=Pdpl-kUnc9I&-Amr}{EI&y zAE99?i0-?Mvac*zY$2szq(2AnfzlpE{{Z7XS20S}G!fbs1`s?RUB&X?o-ixr%PxZN zs`3^^NK0kZQ{aQ@XiX>SKf?)eQt`ieSJ{uKC)^@g6oh`Z$@`NpT+CCi;Vgiu6ka9v zV*2-psh#bih-mk+I9}3$s3WwY#K{!wez7(jRy?8Xj`1lFrm%*A*%8}Jvwn1C^pD4* zL-9}FaoS_xGgrrH{zV(!E>Jz6-xwuBd?7b2%*k?@is8gP3m@C*5KFm$^`H04_L=A5 z(Jcg*JZBQQh7B6-u4SNZxtRGwy_XCF=eq3crIvdH7O!%HbCJ=nLmr$1;+2XVcx z1apWvZBH9?zv2&c52&6|J`?#=BOl&GcoprV^O@${9iWo1b$&Y^Mm!x6DEEb@-dK#_ z@)5f6J{*u_Ds9{3n=3GOf3r$JF|uQcfepm3#SkM@$?r01RTbPjL1FQkiQ%4D24jlg zk>G()-7smIRMXINz3(r79!xAXQR47Biy7?p#5bu|n74A8B|GVS{_`mLA1&Mdeu1OX zByp72RcViAtcR38rZd25z4kJ}V4qN)*#O=NMX{5=Lc=%2T!6nZe5}8iqa<4Lj>Mp5 z3DAS>{o^T>o+4_I>ReW~;8d6T=c`zS)ZG`QM%I08t$m_F7EBB*b{`YCZ5o&F{$LncXe{U^ovxmDjY zE_O8bLPrfgPcqE>%=5U^bx<~xuc$!_8z80NMObbRyk>k%n#`lPd*FGV>@S(^mt%RH zP+aex6EJX==1_7?FaGua09*KSU!rxv zxDrf3PviWA#>HsbpV}(9loW~61uQuB4gNnKhBX$WBwiwl0hf@>p=657C|yStmxT$gPX~{g@Z^hgn8bt_m97U{a>6=~ zS%ut3y%xR_`})TW_tenm#yza1FT~D*)wy78Z4BO@t%spuWJ_GIwBa|mT>N-kY5G?Q z@%y=*YW~6H`v>x&6r~(|b6*-pRk1I|4p%>S@|1QN`;pHRXhK`oRdR`jr&6$sSSQhf z^ePi^{D{y%!9AC;CC#_5?3GUb8Il=kFYqxN?E0u)0;T;*szGV8X8boWf^adwV&L~B zvj%wT3#Yi54tzQM!V)_wa3eO#UYPj^EU~ zmx;mNET`Y`6-1D(f{S~MskQ}R9`ez_k86w&+*OwmE@OpezR9F&vs?N{4h7*;$V@4G z&3C`a@d*nsZJrCyb6q>!0JnE?rMx1)_*XEQ`pkTspgqFEDTKK#M5JMvOaue2J%;{F zY^Go7Map2#g8hcpVEKSQW$u)T?hnoVp+p@3eaW=S{0p0jpCY%0DiEco7EiCzE#&UFjJ7fXl2}FzN*QN~l~+({ZYhHQ06}259MUQ+ zr1o#&pxIA}{p@>w;R!3U#M7_xlrIm;1>5l9>HNRs+|IP_tKu*+{8>1Z(_+rNCu%UO zDy4nzKg8<5H?hPF*{xwdSMZ0by%j1Rfdmom=HG-mm7+%ScC#;n3|oA;Ta6pTs6W_( z1~$aBx|T)nKwM=~*tj?I+0x_83jK0z0dnIW#6_G&Z0;zTF*DYsCGz`2TB+l!gtI8CnkN8w@3%xDjp(tEKe^}d!1}py`_Go%uwX?l_}g&ntcf3hf_Vw%(-LI z-~!{-VG9bO<5_$~LXxA(e~t&23+1`*EiU%VOBcZ(MrE|oiMD*g%B;?; zzbymh>H-22Ksx^bgB#%=ct&w>a5W#YRm>&3XSrW4ux$LyNw2hFL%P3l5RqYtY%QV& zLZD6Q+?U2_qSOUPybf7Kj2}$RJq#bzcervT_fqEJ6$+x^uY4G0f$Cwz63)Ml63rFAtixi3Um65jNO5mLcuJF+Zl?>;&(-RuzWhKlZh_h0}SZc3R_O%sxA8(ySF1~Y?E;R&q z(BW<=vJ3MAPb?GLY9gvH_wO-`9xQ$j=l&D$YCh=EDYfCn5QD%Vg?szJqMKI&=Woo) zD)p4j#>lhh=KlatU5s#wF6Ys^=20-*+^$SSpRX9IhjPzyF?|=P3c64Y{+;hA+oodv zoJ#x~nA^GX%wcDdxkfm#+XR|Ujvj;iW-PTrYPn$oQ-}mwy5ky`E#e zpjlNz+sFPe;=0th6%qS!wy3F>nOq=*aU5bjK^tnSG4IsGETdt2JpTZJjsCheo(6Pi z%QD-)d1vAlXv}b;C}vpEpzAX-Ci?FZn`V#TOqOE-NZ!ov`>)Vq~s zlykgDWsvw~`%R8~kfOhvRHh0T9f!ddG@kH@AUaRdRKvg^o#-0y@f-l1Tl)!yZ<3Gp zZ5!_>Dt+er68wj-0V(qcs^26C5a0>5YEcz}RKq>Q5D#~_BH?0G=%QZ+=3(cG!tW^l z7FPm{3=OQ?VdXxs5NJ5c=x|;soY1oUsb;?e+Fe!t)l>nAC>|t)qDPB64y}(`w@xp z9euS0UXphz!R~E+-&s$iV4nBc6)M;_*=%Cjf%5uI;>ivl%o_Cu;rbODmtla;`A256 z2(H-L1@0o|~;kt7tsUu8icb^X69C#XI-cx4zz{_!%$xMu4dPsbXlppYMnk zY=%koj#ra9{)cdcj1*d5@JuUggD?JmAp5?*ng0OfUc{v#UlP0>2Z%TYa5CqTR{<(r zt}_obYRNsQw%I!g;zxEPZ1ABGV7*5&N7`gVvc4f``P4n#QW8`{Xb&tv3n`{s2SFGU zIj{~DQT@V#iBj0sWR}do5{b9o8mDlZOMrd1QJ9a*5B@{1oqn@PQs7%@Lv1pgMp2h? z);BEfZ!BWY05)!tD@XT}Amuea$UixNq-IXYIbPE!V3Y-IDEOEJ2Y&dLp6oD_tiRe@ z7jx>gHw683M6YN}`2OyYRodgDe+q8 zr?YRqq2NkbCHa5kY5+Fu}B`7<^4MP%4#U{+#?0~i7Hg7 zP$TIN6mInrBws@SWF?&m&=3tyn8JhGUcdDy9_umEyl`Hnep?!`@-YFc=fBJ~M@ck= z{&`5XRxS?8y@{a-?t8Gx6hjOVJ#`F;7kJD>Q@Avy1k~3Y0Z~SG80vXdQ#=>HgX=3_ ze35?)6X}-%{sI~0o`TqdO zW3~pBz8!qW4j&ZyuA%86XC$iINZY2isl`V$GX?FaJ$Wx}OO;64_5muh**)K9E9d z(7N*UMdH%`0P;F#^Dh9ELA*;&mbfEx*-Af1{`S6ELin%5%dATuYv_M4Lntt!fXrpg-ai?d#2$MW$a)!s;ZB~SuL3Y+dYKU{r%v=c5I{Ke&7C~z}@6) z%Ko!5+?4zl&wnH?O(e1OToO@4yp?KTV5*=tiRNHM;yD`OeBdLYhbN;maA+*^xcUTr zM>5ZKFY^yVsr7&IU-#-~eDUx^GbF)S6b)n$oLx~j{l4+K`Ycz$^_i_H-J}vLBip>! zfe>z5_K9Z(<_I9+h_qvIoD-=7skyLpzv0miQ$ZB$q%C+4s|_A0`#?+Pn0|k&gp7`WJ^ z$}1bD8Y*49rjP_KU+(74Stx2G$RuD6f-xhd^sQxsQ}Gc3D{z-64yFg?g|;(-9PGRB z#V@-k+4B>>ZNf$M!xVkE-F>L2Phu5rZ@6B`*C*Z|r9GOIWin@P4ZrL&j!uKhcNBtC zNB;nK^(^0W{Jwr-yB%9Ie#m(qO5el}E??pqlK2TpFi#}ZLP}lt8jIED>&48Gn)ee( zn)Uuy`5tq%KQJk<%2Twqn$I47Nv7)DIL`PzA^~3bnFed{W(GOi={BgPOrGHl@FK zOxlP^L5TTMW0RNxS1gH{>&G45Swl{sjW9=i4PmTqXpnkY(8U{p2+o0z{7kTJ4J%yA z;;)FixXOcT5 z4*Xzj2e4qDb4a$x^0~1)pCiP-FIW|y;ed}{)n?WFOWer2uL{gOrzC5w`*5i&kI(^WK-+?>6b3b>sa&=7#0x zbz5Q|<@{7Mflp#RWP%BWP|&!a$GC=EC7s67nY_Pd9W<6oPyzIxdRRKLpvAqfWo3Oju!-(>IXMfES{5NC3%TruJmeAo9_qSN=^;xR8# zVVP+kQ>I+Z<;%Aed5syGZu&JURCmMUAi?EoQ^7C!p6p)?T+PYiE&Di?nZy48w7B#> z>2;PGBXkVaNs9ZOj5|OFh}Votz{THD;v~%9%w5l9aZxnkcl=75ONSS_7V3zGq9gBD zE>y~v>vz}0*Ij4(X8P>^01>-h!e3bXmk{|2y7ra*Qi5did?!^m>>Wbu1{^5=0Aj=Q zp1!bX7EreR@%^)GUjG1MAS(Jd`TqbCi1}gs)Dp4lug92^klo6lbbIp*?>%a7BL{{TPYRDQuR{{WKNVExbhm{R9&yzTjYA!P&P zAI#hS>)v0w7yke;^_kt|>-K!Z8D(8J2lg;{-tgX51#-t2!uv05HpWx)J942Tu>8zT z44_6+Y`f0}W=GrJ4H#{FzGfuL1f^$p?Gk(=(<=LB;v_MGdBvF*-B2;s-z*`;CFCEH zBV40H>lV)Ya5hRI^2Uin_foh)M=lsA*?`r`nb5o|bgOXLF++U(6R6QL*S?0xq^2XzO6(*KEK2ZuU?G%dHIcQ{_$_!2)MPxsZsI?cxSC# zv?nqnrZm)Aq`uib(q`#nD}K{r&yMAqm^Mp}H5O~AE9lEF!V54jvpchr5N%37_WAMm zn~5`QwD^+pD6!e&_nBTg^WjgqFX`+D-|yqhsJX%#HG4fQ62C9Y#P-<^j^p8x$kgTntV0YGlU~mf( z%QO9sWgCKl)xp1>9m}ZGC@zx#g(to`u{X=S#91lRD*#ql!87VIW~4H2;$jnj^>JJf zhU>J9J`tF>`NnV5x{#*yPk*QwB_&#`-QbQpkK9%lDPrTrkGQ4vi)q}$1H>TN#q(h^ za6?SncIgB;x+ng{F2%pegZEUYZ%@4uT9?}a>d>RD%R}Nsv4NG8t<}#=v36=5%2w_Y z=x$zSdG5`54rv&~~2li?nh6F~fghz1Ow>05ZGZD)5hzYW3_F@eKCSsBfXR7`Qopc1GNQ zo=6E`)1Y?0?dv1p!owW4g*EfhEMRnxHN0Q{06T%!=C*00-|;AM^#WoByC>Mx&4OQn zuDkvvB$3Uw`_FIURE6;G{Eap5Q}C9);}Tul9bu=NikY8!RwUa?eq}~J0(#s_*n|){ERi7F-Ia${E+;W`@`B=@lP1M6S(wc5x5Ak@NR#xtna#2#3}O!mZyUd z+|BxP^U)NmMmBBudqy}A3iLM1$%hs~LRYC|c%dF&S>o zcv*^`W5Kqw9LK4o+ct{JjHpIt62;16c+WEtQy@m5FWwy$S$H||{{XU&w`_Ox>I!ZZ~WErKbheC0~lv!+5QJQhUF4=5NSPY7>TCPiI8b_DKf1O{3?s z7IBq+?VNl?p)HJj#Ih6WF=6j*C*~*>Do=kB6UZMv4{j6H#XPSmYEPzsTR^k~fCr@{56&>^}qoruBUS z5~d`@nDNJUE?^5>LxSox0eB`Fip~-f8$1AK#7Za%+}gT365Hcq!)wp9P22aw@x}YT?5Fo?Ju%>A)NGJh*Nvwe>L9z&|V=K z)Oin}HP};7v-Gn-!l$wZ@A`Cw;nm&*^BU8z`J1~o~J>S*- z$#`*Y-aW(aXVC$o~LQ0yWTo<@KH+J9lsM>PBN3xT)}O_nBW5(|~@v zfw3fwWNiK=uj@-6Q~di)K@}{AKG;XVu`oCC5ei}{4yhxx=sy!`j}kaXL_DX21RkOM zIKB2R1VyQZMO5l0Fo$P=fSLdeTUJ|66sH9jb#@jb0@S_ zgg>7U>jlB!gmK1>2~7pYK;>GRm(4YanP^%tB}(SA6ruNMU0{ytZ!5#oP%Xaz(LgT0 zJMD060r4o%dX^<{`}~P%YXv zAH3IMd&D4K54}ZI?gMp4?+3ADaJ4;>#CCXu4hPVgvR%ENzMaOeEoru%d=oOi`j3Wp z1O=Z<$@FK~1|K)S-sOEU`Vzzal+>&>_nxOmVJNh@`-W%p9kl-d z66+2xe$W&-%ToD&CMA_mAF~W)U|#N@l);iOV}AD+q8|zFdG~$!M4gYsP>)k0_2LJy z7DcErPt4x9S1xqN0(5iNiS9(-7noYZ+GKN!wCsMI4EHjHX=z&QmVQTxj9#GFPh>Yc zf540fw%KK|%UP39?|ns{7)v`>@eMWx;aiJI_e-2d*8_^-TTi-c&NDFv{1KK(?%^Oz zX#Kc9e$#NZM95ryuoD~dU1kj2?+h>bFEk$Ye@WZD?xlw7+3F6%3=KWqKhW@KL zPdb|AEUY+>1#+s1a|jSwTk}ycrPI7r$_&1gw)opCj0bOhd>{5wJ1BkUiY3mjBBfO2 zzn-H(K*vahtG*xne=?zcqGyDY*@@PUpD6I1lcbyWWBU)RV2sZCcK-mVuqi6fh~E{o zwM4%R0f|9Od9pj%-8}ooD*+NcY6EkF{X3L@*oO?(B|m58bbu|d9xl9fE`@r*S;y2r zcOTw>r~d$t)=(guN_>CzI2K*fpAyyK(WEGP{Pg_KdW!2mw^a!p0Dd$3Wy!X#H2O0; zI@FDR545JTi+z*B*(s(#C3zRq$8itb{{Weu@q>r~iw{!^qzZ;SKGO@`#E`2ipnaDR zFXuReOM!BhV+6lb7gwmG*cH{D58kd*Q2_RZbUB{*u@GO3!^8o!4U(iwlPoRS!vGxt z`s?_X5g*6?%U;h zpoo(a>iIsOvIrYQvweJ*UoyA;3jhcELh%K`XBYXg_GNGEr9Pc~7`pasMCm)R%n)R$m&5iY9c9oN>9!Nf!14z;f}RrF~&u4%BzHC zd*FCrUzD&yv0L+RBqm7dm{O|p80gYQ7dvuHae6dh+2E4*Tc49ULG(0nUw3WlwPTR{vs|0w*LUs z{HbK$XgY_KxUH~9S6xg2hZn!R!9LjjB8R}5y}~=DJ*9doFp{$?jJzryScha}@hx#4 z@EH=}j89@DfasqX&IiRoaT{U5;OP1h0xjG!C(ZVrId6FkN(pwd!<&i@Pk?xj$Ou$z zM!|#p?Pq@dA#0 zh_jGyF)|4S;pV>pyL4O+c$l?N!F>jN!}SPjZF*X!j{wuJy?rN_aiI2s9@4dfJCzf} zPcq_k<^E;)D%sHr?0>ibHvLeIrV%W>{+bI&r!&3B@hLZ7g(|}JDsw*=9hl+Wk}aTj zf1h~k*|N02P5dD@@d+w2Mgm?Pcw7~BdtPJe4WF@6&i^8i^c`9l%uY&NUr7K4v5cuioGRpjWi`W(O_%;*qHDoen|EUuR!y8Y1@f3;hDfqYm4td39zR)e3fJ2NgsXf`1&jAl*%UMV9Fk+(q zL-8&|GfWxr{^#OR=)tjdkM7@pRc(b2%b&y$rrAfV(Y-;9_bT9GvE?5S>UPR%9_h+K zMco;8`+Pt)ve0yz#Kt;tY5ExE+z!%)ZYKO4#W%T#7P9=yzxe*C8Jo_ya?Hf> zD2EtSSyZx7zELfRqu{qco;D~ zwG%60v>_@VEzHWdiIVJl0wT-xf0>rrTzry>qPk2TM&L{H2W!T`AJJ)WO!&BlzVJWE znk{?qWUS-=02lp;Yh51uYgH)Pv_P*=jl2H2Cj+hF+S8+HW@BFR=DuCK?Tj; z$cQ@s0QN*Fi)+2d*O|WC!Yah7Kl;*J%nK7_vbJ}k;Px;aMB}wEM&dxnw8~z?JkCpw z5=G`$#JIfJi`-`0h|IG?5%7SO_LLaKHcK-m=m%Xskb1L5X0@0duye^8ekB@SBY>>G zIrqe>wHsNT28Z_9e*7V^%!lt8yBrdhkLA42)KMl2Y*of*8n_=g2}T?*SSr`unh zKBuUB3l;s0Lvdv~5I%=~VC?02y}rn&7%(EU+&FLI11dJzVwqq_)Mf^j0WFl;i%~9# z<0QA76GEljT#5`ld;b8l%#sEUR=2_+5TX+J`mj;gb5r6s{3#vYaF;E2L9*VrfIq2S zzLI^$9+j!?kzc+hMc05g5K3Z>loOe9s;I$avK5W?&rsWJZ?0-H>ZL=}crGc-U{~N< zTbCI09eh3*%B35ZFTYXu6JUzIC%r6}5cZeAfj5ZxN4yr78dN2Ew75TY8|>hCIQWQp zRIUaUivU5zr-M)9yo8%9Mm;x8D{tv9^vip?>**a%~|A2^j~?rR_EY+drPXXE72UM z{{SS3U6lYkrdQg9#urg??Yb~v%43N}qEfw96y~EAuvA=!uh#-^1oAE2srFCk$trXA|lK zu4a#hrEJX8&XdpiHEeqW^ArkuO`;cv#*r-Hmj3_^Lc?0VDQ&&B=F3pG@Ia#Ggs>u@ zd+%O^*9PKBnw4=YJXH5VpQ%5;h+DIQa7@Q86#;)mEfqK=8XHN`{{WqR<6n(BKAV=2)5zo;tg zVzvJO8aqdFuz`eN4|Y)6J^GfS&~abKhgZ z_=+0A!ZgkY)sJskc7+oWKMH0UjbRo_65(QUIA<$&r5V1Nuf(CdS@z<%E~1rVkB5oQ zbxOOYe)9Y&rPtJin6%1rLPi3M-?{uznQp?H?3M6egB|+^%n_;Jd>QWHj|VKeMf_7; z=2D%bFlpj!jTiSoKx*o{kEdVB@hV)GXY;e#SO$8$ZX(gYY>}%mERNB*7SO;Aw}VpU zT+~^9gzgZ1^_PVCf1APW0*FH5yhm*N=TGhNsfG=5{{VN&WvvoF%eMR91Zr$UK70NB zraskTHypArmQW--wQc5oJuxw4Q?C@RU?^^oHhA+!MsbcY**gyf$L;1>| zpWu%p-ZpSGGct(wJpChB0ErxxK2F^5&2CXFimef2cNf^PLZvbO>0Y+umu|(y30wJv z(KlL8_Mn}E&jiCUG{U%pXNv8{6+CN8o+)iF^A(qQDBfnUr_qKCn>+F_!(G3FEEji_Z(?Jyc=Nj9{zq6w306}fbn zyeD%WW-g|9ZaY2fmZqUf9c$}1M@!am2x>5UFhpgfSP{iJJYyf2>hCjn_*H$`w6p&J z$ckh4VJbASt9wcdmnY*ffPUs=dzVbg3;zIz));Rg_P!nnuZ&-r@Ua`@i~Qd}BVu2&-%ZF@{(4eZ?bgPcf&0Y8!ScaA(Vu#$T82_98JD(tvbns#njj@+<&brl$)zaQ z*gRDTzo_!Dq8^03%$}jm&~uk z8ER3#!QwuXx?ml=LNc<`Ds7Bp+55+iE)^x?X?~0DE({cCOSet7*hOZzAQL>0fSHJA zX-&D8E?x0(=J-~0sZxxv`vtQ!g2k%gB zudd&gZcMHRzPusX(Pl&{T7vM&21t3_#*}aK2TT>2;x3s%Ys3g1Vf8A|#nfpUt=VsS z=?XT#Mh?8#Ky9FL7$erLZ(#W)>bxG)J6Ks<3uQPrdOv@dbiw^*CWezS_>HpSDegs8 zL@w@MXg+2&miiH2v75}9i7K$BeY+L}*BT)mMwyU18MoyfQPemPzW^cPKD|Pr+@xB@ zRkr8Sz3oQgQ zpjKbBs!3$LJfG_`8#(~e-~RwV-_{n(-}ZDt;ZS@dDtM{c&6VvlE2w~~Y71omf4SUt zOd`=ReZbyF+C9kU+xL_$FE1Fy?^8PtuDy@!h-QZ;6L5Lc*sB-$mQZynVHES0u5=MO zi$Nm%pio9H=%rr+l=FC}EgKPWtm)9CE z<^KSY$`MU)FnEJ8H<`Nmh<;tmlr=D)T`n!=ElFE!d7Wxmq6pnYtDy&28gYD7t{xb} zcxCsyzwrX>o_)*^Yk8J^XPZ*le4GTX4hc-IEY%IM)@JS+22Ioos7s&?YP}Hy$oqs zZ{Uhrf)1bdcJurXyva5ZutUlxRMuv^+rDK7ge6-s^^esQH6yZjKLdoj3b<^dx|+kl zX0aT?V6kuI;Fc>SS)QvXQ_BLZmdU(a z4GsBDtH35(`C=D;nBA4jaXO}9mLl%iPrJ+n3uq0iFw&d-Ph<1ANNS){Gy_7Qb>N-t zE;oi}kwk4rs01*)iH5kSgn#g1;`$%=Oq0#}>wuNR!bFTt2ymAZilYW8(VLV6B&!Hc ziD;}=fxUVv62c4Fm)!WWzc4Nqa!SF*p4cxV@O|T!PD^d>kBT2+K-CKOAA(Ujcy9gY zT6b?Th0S<#aHt4T;|)E@3y4xZH4JUu)9MC^8aj4Am_4h!%MMeybLLbZ@F~~UBMl5A z94*usxs}}BK+fg(LH2n*32_qkLxOw7Mw;Qk_9l`~VC zBSt!2*mq8xRIHbXgu=6QeE!uLRzYv|m70w;D$H8h)YMMIF)CG`Ybs+?d|t{E<@r*` z_SH|I#yd>UaENg7#xa%3t9gt@rD-jHyM)HzxUECKnAx*loJLF*o39gd;5`Xo+OF3u zzq$S+2zNmpq&D`x&PkbJ;LI#b2EX+_27lPW%KRVi zm|__CgyR+@JNejRI0oJ$-t?(`cKeXUZQvjex>rK)#OVA`M&&&GZ~mp|g$NZgVgOth zQ^wnZk%}|FQ4Ez?;T!(|CE|xhpHf7i{Hz*|Uxm++kcMKZQPEM$(Nco!BaqefipSt((O}INDJ|W!e^X4C zElGFAGKEMQ1r;i6=51eY--27HB`Uu+{{S!AY>^9Xc!^h6L_VlY<0`WqFSKQl-w9qi zKy_QFmcCcGg7HMmnumuPwUb#2!@$|?@b~xOTu=!^Y;6|qE3X)r?7)?=93_mW(p`U^ zS|nd|)f^v4Vs*F&)yxX>80TN1;o+EYJTffy)}N$UhOM|GxtR=|P3IP|Wc{+fV~`%| zXnXdST|L6^p)tFswL&!_R*%fR4;j~lNTwR9_k#AFO`@3k7-o!@SRbTS#8tSj;V$tl zkU=NmDXzf|?n9-LFDK4mlAHbN3RKCu>h8QogE|$g} zwqR?eW{baQfw9lH;=;ZL9`ho!MDFN(u;-yvCiX+kf3wez+jhd$+`%t&_&9^>iFG_Y z7j-a0?R)xM33p80yZTFWMcqoNtP}Pn=%R&o=>BC6&TqL;IGedeKUN)-Fu+i6Y3CMu z#l!ix6zexG3D|cmzPw*WO>h-UQ0S%zG$qv_=CLqVi9wi*y-yt&{J^hsqU!CFW9e(ges0Jf4$lIaZ@a$ z6gqrLpnbCsQ^PJiRB;T%2$wd!)3c96XPyO2O0TQ+9_Wg=02FRyxK*dtVos%V+*=Qe z*SP!e>I5A)pxoYL;v+qADctFI0g0Lne#}aeZ&W@zzoZ0c?o->CBiMP4?yE=x?FpUa z5AVz?utZA*jBE2dVB;0P<{o+#>GqY7Tm!#ob#!;(Dldvxo|%g{4#xgs>a0)cbI6#x z_E;hW6^KXDR6V<8?dbqq1z!;Wm|!Au=)o~s5nM$f+L=Hnv6K^J17AKR4HOE2m{KTv zOKsvL_3&+&2icf2CYYV<&!o>ep7XZuaT#eX`c8l-`mu`q!G2;B+B87K2x!l98AX=P zY?=rI?4N5#iE&%w953w$mVR3$f1c8%O6Nv-%4dB?1+vEQ6WE<4Cw^5cEKp1mnRo`+ z8qlDOJ=)(Rsa*g;ik;qlY!QsPd@l1FFkBYb7q@~|87);{{pK7^!GC19zjR8infAGdxt8Y18byV}YrzTDt}CjC zVS|-nsfsIxCckBvWoXphLz0x>4XjbC(s-MiT0hy4>CCfm%Z=rJ>Xix2%C}49)p?dD zV@x%u9`wfPbxalej|`xE1@kDcME+oGv zkQ`5mk(ofx331|39VIBdOBxusE7gJ{rseUbI)ls`j!5?SJ&pkzIJ~knoIxlfxQ6Nr zxv)W5@d0fI7@o(HrAp?b!H+C>sM{{(jO8jCX>%@l zOL&Hb_vYM3!I^7WXeqb3QuT@XKy<=NDuq5EHlb7!wxrom%BfdqQnrw!P&+U2Gcxs^ z$9Cn~j0K%Q_|LQo(OZi90=}+cnlG)wd_~gUHOBJ-Ufw3Q9Ai-G04blgzcRS*VL!N) z*O13o{{Y1pDOGhZ0J~>+OjrUE{{VQZpe#nx*XW1|;BNA)5?w8Lw{2~DCeItA^ z&}=b1{66V>z?Ki97=1```=xG>(E7`@s8d`CuPLyuu_|3#nb%m%!#sa6RlY0W1>5m_ z#CBUR;uBQ`u`QJDW0>}rOiZDGa)7|5d@~C!^noSqQdMYtTlO7l_BCFxt%VE?o%bjOoF6M;HROu!H1+9ES3wx;Bmc|jD z*+W`^llqNP1_p=A5TXgs2gT)wnH`yj_B_n7fiLdkfZLadnf_)pw18p@nD@K^Hf~jv zw{UKE7T(^7hR!&tJ;_u6i*+_b!^{#d)B`PT)@lNPlFpx_ z23o|$Vchqh51H@ij?*~TU0{iomi;8lm=xTrkBcKW1x%1K z&%6~(Eohof3{0ik&pjmExttKdwE+g0>a~I}F#@eC{{RYx6lxJ;hET>>uBC2w2>_-R zCx#5?C5B4vJ4V-C%?oQj_`k!#}gpv-xum)j|^g$#Yo*t zN@h|+Ow-n&I=73If?eSu*$`21I7OMySa+}=f!hmW8i*)MWjO1^JM$YM-uC*xc=h7z zsQ5x){Km@4J4_88Wemmmji6Sr!*bU>j{tw?<`;j2ETFAlQCiBP#nD)(Mu)_1$Q1f$ zjNl?T$C`W*+|D%(O!K&P25cLA4R2>b>!aH0X5a6~4!#gT!nD{Zt;gxB9o~Dr* z7oSf6T@6R5eL3@AF%66~eaLo?ahK%3YNgd2?V6nXh)VJ*i&vqJW+i+?Zw43mpGPR* z`@teg12T|QnJ=6|SyiTN}>Mq!dh5&py}ne76{LC`;w z{c!9apz6#oYJH#miO85jE-<&l!g4CK_y?G8RL6)?oWhBpcmlmZKqZcROFnQ0TtqGP z-^A3z^nx|e_Ir~3R+W_Zh7nnh;fP<~V(tAD_bR=-L16aJyvVQwe}OBPxZB1J*^#v= zxz|(3!5xIR4MQ(!oW8MYOA2g8OYHdw1zZ(~0{XYw26I&puw2bbggn9y_~}U;7Cey0 z!e4Ps#{3;29k6Q2?8_FX*@8s8E5o)Io>1R92r#{(SC1jM`&yR*kI{k|W>qQ|suk<4(8H6Z9lCBsU?F0B@l z>ImO*EP0j_+|p`UsK#{P1p~yL4%i!)Zp05CUk86^2aRfb9zqA~6%IwqGHwcpt1g=` z&6vVW#!R`e$4GWdxC-hG(_wNXQ`X<1rk(aqGAHQhO)i>mp33B`OJ4>Uu_#5xc=%iI`dL!m74nBnQ z!w)|4p2C_hIh3YP+GAJVD|GmWN0e%OSz)(|7e$5Q0DiHCofAZ6=3Mh=BjW9rxI<}< zeE^)5KK4G6$xdh744L}(NHNXA7bIdu)NH6hN(jt6P(_J2IyONr_TdS7+JPx{)O{wB zRH?f}_kjg1`G(J&r5G17(KI|TnkD!^t}fB<7tkgO?eV*RebmKy3H;L$JpTZRVfjAJ z9*PMRkE}jI6Q*P>5kxK~V#TPuz;KxPKwN((3FJA4qyUZa83Lx^w^YADaGcYJ>n#KY zGjPV~$HWL8rW{KNfE&ZQ8`!Wwcuet~FYv}%(#jVq%wrhQM4r=me-mcQxr*h3W*QR6 zVi=iPIHuvtiQ6mqB1q$s^9)r(wiP!|Wb#Z@t{u!pPTTvzRe_8}^dR; zv{I2T3Dd*}ceJeVdrMg_N|eXylL1rVn0LxgEcEpTFh=E5C6lp@*M7IO#3HCD7;JlA z$ir^ZgoCJPajMg+JW09l#-jK7d5Ic&A+uROiI}^e5)RW82*&0)TlF&YRIU~6~FnLe7YyvXo$zK_EIk6^{P+sp46?l%&sIzBzTO91L> zK?0Tk0CFkBaH-HGW>J#_euD&*OwV*)S&b!eQkux+V<7i65L~|EtLX^ial!*pLGGA}-lJ79JkJ3#dAo`3FQGTg-Y3$D_lcuu zz!;i|g{Krsn4vg04F-zGHbV55U!X-N=7?!0+=5L7_g>0$-*aA zxtHP@mMe274$0iZcP?STYqTGfSXOvgf= z&~r|v-qQe^#IBfTVa!K-D`K0Cmeb6csHPH@Lq5zaRq}?63zy8-t-~{F7Phpy?mC0S zWdm0l_z9OC%13kGkJ3>4n0_bEGWlb3r2Nk!Qg}+uE~eRwo_f%jxZi9V0;Ums>`YO* z_=jHLd<;QnOz;jDQDT!S;FRt~u>3oj{5+HQsQH$*EioNHX?}>_Z$Uf=Lds!x9@+Gn zoGf{%y<{=+^FCux!Tcf(*FR6>XW^2hnj)Cg}2aok6Dn@x807PBlw$cRo4;v0xqeW z@a6FT0A*6`apUWBk4~Gg6f!Ne@l-SEod7>5B=@+w&!k(KV|f(qSt#WBU^ zCsVP7)K!b{Q+DPGg-Glw&BYBZ0_va9e=_7>`%k*BXt^#@li@eru^*|$ zMwcJih`Td4GcHV0&e);SJFz0rcihmdd%<5$FEX!fg?pYL5Tqr3C&#lq_xwZ`yTl>bd79E9&ni^kM5%UvZ)rudF^nNxQo;Og3$AC-S1Fz& zA%KYsy&fl?Q!rI~MzG5S!BB4!qL+ecSxm>-rA2oYt1Ui@Ku=s7!G0J7}Ftnt_ zg;|~N6T*~-m?>Layc=a9IuIFf#*l5r8g$w>BH$S<2YNmoKDz`nrsq=VIEJ%5UfEb>vfrc|(3Gr88jEmDs##`NjU#)c_|D=$2G`;zjdJ@L z-vtMyQMy>c{U^RTj^X31+LrYW`$Yn~6gts$QBWHjWy{IZKlj=+tu+WHYp-YfEm(%) z6BM%l05S=_3+2>#s8Mx0^Q9s#+KUl{W*K0++(9G=P6lKTm}@U*#ADbK6XVhogK)nj zxiuBke#AZ|4SqCvySFR>%zdc-QpxROW*RE|An2%QVLr-TH1QTNvz1BI%;+Mm%qo=< zmCVYNaAU>O4aUZ6Cbb_7a8HDy&%+nP@1@H8P)kAt18skk5e@31SB2x|XT?!}X`Wb& z_VFJ;C(cWTGFhsWgV79IBz>`WiJTuQKl;b{0ozX0!H?o0-uFA~%k%6ZToS#-v{Wtt zjHPfV;7@K!R?iZfR9LX?9Gpr_#ygtAT%nsy#A+%>J+rXkxpxh6HaGDovd(uTmMdnj zZyi8yzbT#s0~HrNU2%U8h;wIlpc%#)r1uB^0AcyAZ2tfwS{Yd~hv32hPTvUMCqy>c z`bV$rF%=Zc)f$R!QrRxp6qW~Dsoe_@z;L+BSn{F_c(8-8y})I*CHa`2(0h{(QdAhx zMp)(Xh$e%!Rq--3d*H7EYM~tQ0N2m^8j8!e0*@bbUi-|ZnNx|JHbkwj5Io3SV!Wc8 zmf(~|UKTAdCxr4uMinbmGZOKX$|37LnV$g+MuiG zLbV?I!&30=n7|$0YF_MK7$z<)X$iLe*EK^P_x2-X4%Ro_rde6w_cTUYPyJ_x7B1%H z;S5McD!#C4*2{u};z1w>oW>zlKH^}2=jF=j}}5xB`vq-O}g>1U{bXEg>aPXU=j?*V2U498>#LEe3#pw?sL^i-+TYA}Ir zC2MyY9sU$gZdq$_TSPCXXWC!D)N)!|xK3MTMMN^yc!nQTFdic5Fa#~2I{Xk z{{Rhw=3j2%*5ie2wam-eIuqt4Pt=xh+XfnPeD^elTtw%?budPgu7~nOVEKZFwkw2R zl%rwC^N;{vdg3&lQx4;S6;BwlGB*!GZ|xR6Df%fslX%5m9?%C*ReY^jCFGe?mqA@Jc@ek`z9T(FM+Yq zaWbAIMw*qZR9m{2Q#*Sij+NxN8UP2^jX^cQ+_`d$z_IX8uO1}MCb*gIE(ELO7nDI2 zOjONrMr|`B0x4AoN#`8O3}=K$-X>@evUNKm!vUUhd6jN~Dgy=l%?K4dM=tYdC&X~@ z46ur(m&%=E-gF?ZWK8OQVgatt5D%0$wl`Wf%u?glXaW-YAOJfh2x2|-AEu(4mXaMA z+bU(k$UKugg+uQI_c4V~T6EIFcu>|=2ZlDpoea+_iB^r++&{~sq$=0x;uM|#WHc+ZMpLK7EVT9L- z0At&Wo(BaPW;0>!J)lxu zAwaGZBnejmy5hTmOhbrqSHme&!G|<(sk!eiZdVREnW`fm<;cd0P@BOJaVUus|IaCnY$a6}vo5>o4b)Z7+s zehL|R>-&4o;y~t0q?HjiFeUR7e0jo&eV?^KG008m_KWxs6eU7cXld~<>{mYj05d?^ zdmaA(8JFp=e$TvY+b`89Br1;6r`lFr)&g>P#^sP}aDw_JA*G!MWx}EAWF}Y9AIdaP zKWs8a7caTL%tbrX?4Hev=_#O3kW23*rXk)*1QTo|CiuF)$fW2sEQPecl?Dh~@B%%f4aS`LUDNYpdl z{6bpKHFq`i^74}VDd(f(#JcQrFfLxskU`cdFhSpBs^|yr8D5jwH$)I`p)IPy)2OT- z7Kkb;XbX+k)&wb!Z*QRillJa1K3EH3zOJIJ$ygRfqIV1@c>*f39g_E?9L83@Z@Ddc z6r<%7v_wJs+G;1T)WqVim+ql1P1t@f;!gCY8__QS_v&9}4jL{2tXZri;4ml@1ZnEYn;IHycq*$3ha+A>a_!kgcPicY~w2sAURp zI}=30(nRmfY>a3cS(YVlv^~VSvY;&vMlHQZGN6{o)@V2B3w2KX)UNwKpBbLYmc(-C z0DH`ttdN@~4=)37T(c7nB^%)KN`!RW%0)t80W6Ijz1Gg{hh&cm;oJ~Un>6qk#H`|MjMQk z6XrBWxs*eyP}btuf`5 zogk)!uQJTDu#Y?-m}HDTZUw8jZyZa>yk5b%-6@I*H49(YQ|FD#Rd!2>@hH35f>^9y zXt<8Sr{woi+LqSy8DIehg*7elF!}qZL@`NZ7iiT~Hv;9R4ljW%)E)5Q;Ca6u;HTPW z1koTsG|6u;4>+VyOrohYJ-K7J|-L&nUgTwzeTeYf~SbKRG_Jc3xq9>1ppNvd@v2OEV{4 z@gk<1zY%j|sr)F5_KtwijY77QDd8|0FJ-!y)~4o7O0xlrG$rhS()W(~(eGv-xHfpi z-0XIy{7RI8P;X5#*qR)rHdD)AGUmn4Id|q3E<@eMmrgW&E`u&=4vXfj9^~nBB>6pTeuRtMV?agDn+sz51$g0 zPRW+?M;8ix<(9@ThwX*1+4huAGZSj*;FztWc8A^Z82V{19@u8Xdv~IHx~yAVARV(E z4!RPL2N9eoQ8O$^L)<}&CK8eO{{UvieHnt64g8g%4D+Gml~u)I+>Lz50E9N#KB~;%(81W znX#cY7O+g#9uJTHLJw&xe%bK_CgS#rUfo`9 zHJ`NY{{YA$+L@lYP>kyU5tw^#0||uEH&1XHL9s1g#JHZyWb-+cvo@wLps_!8cLc%* zQy%t5=Qd=72s|ETeAvFh{>m88SJGSMmi-!)Z$VUIK4w=^{e9hF_?r-lKoX3D^FJ;+ z<7qtV!rZs`p%m(72fh3EV-L1p2Z-V~QNY@<%~%(|@O2IxveX|~_cBZBJ*zSIB8v4rPEvLwb%D!1w6a)o}q6{lw^%Nv2!R7r% z_y_3!0PLVn(p2#Hdp;(kDq$B)*b%eP*XQ;VULFaiXG)5Bn%Ee(xd0?ceA1_Y;SR~< zK|Eyqh(5xrKOp_F9hOV!^@%#CRAo#HY?;W(rC|4jPRa@_6jjqu0@MuwGtpD~arOk$ zLOR6WJ~EKGWX|@RDYih1@Jz{?V7iK~S=14kbit^Y5j@3vm2N0S8fA_3Jae)FN`V3y ziXL1Cu-q!|1LfRn44}096H-3-u+vfx^o3tmP-|KskE;Y`9Yms{{1U5ehuz6~_SDAZ zS&m=@^#FhL_(zdiC5PxM^Qik1(y7q)c191pf5ZHqL)zc?JBb!TvY}Q>b`F`~pco32Dn0NYKjdTYEV~<5 z5byLaZj!IMV@GQF_MXy=c<~h=&rDZWBL4t!hGhshsY#qKDAwVY6R{Dob0j5}J?5eE zeqicprcxWu%iTR)LU!B)_L9uekGg7QkKlx?0T=~c`&Z@@wGgrwwN8)W^HB<=itEOF zO5Y#nDb_pr<^rKewPG4!QL9PQ-`&sFR1|7y>j8!(qe$;JEvmk>mP41DEQ!@JXCX%Y9%-o>I7$;sja%7KFm^1h7pXffmJy1 z4+Ri7d)Z5whY%(~@WPJr{$?=hn0Zva<2*W>(49)Wut3CZ=_}?OdsoYFz7#@NvJ&E5 z4ZK}UD||(3-&0tv$>w4|`!Gade~R0{6GyyPjsel-cnz%Z`ZX`L{2mT93sXqaI~lnx z^ZtdG0ZV!&GrK&!uzG`$rQ_mR-mu)0Cx5I8#);bC_nFClBSc<+`-hmu(#u))Tzqzy z9s9*Zw%>>^VpLMOjIQ41==*peq;j9+W=O@-wPcZTBhPIT%s5O;7qsn}r;CFQC7|6) z*>-pIVJ(90uh2JM<;Kb_GzRa)XY>UP8TtoN8%Akk+LE=P>H;%NF*of=`G9g3m>dIn zl;F}%T6a4GUte5dTM{Bu%oB{o-URlPK}x&qbcBtoA86Mw15w&6-*F>k2?_2J{4Sk& zvkc%^RH4!BJ93wc@_;#qX;?^Ip>_6K_=6v`()X)+JgyGm=2m{jEU~y;hcfFOOZfi) z?*p2M6p)=DIz@C(2^Sxhgc~6RM1qcZ<~Y~!(F_n__eS9*Ll6@a6-qHYW-DQ6Mo5r= zty}>I*O-di};UUHZ~*!dR}Ua!k?Y5srzaa+Cc+b`n6+MS)KN@117`F!{u3k zr<2>H3h~QliVxii6`F#MxIY%sZWy zVE8O!W>MmH%4V3KT}4lBS9xA*a5aaSmE*R8^9ICXRJ;hq4rfh!;7WGyhLffKlT;1X z&!p>VEh*eGCKOkCl`x1e2L>}VJGqAFP(vIvnQCDjl@EL=Fe_I<6H;K`v*Z5&u>8p? zcppqdqeP$=Drp)QxjKoN79QU*6u+?F;#iP>B7I|EhokvMChGa^{z@W1Eno?bT%-6O z*@#7`aL=vAfdNExj0k4YcbQ5JbuNPpOLM3OgV|8JzpZ_)5;ujX$4+ZiSll+km=X3& zcroHW3gInCcON)Y+5MhIJdv_mD@P_S*A<~`Z@o|R0J7mdjUOI<(%|kZaCjZc3FIRI zVl2{Udd)VVpD?nC?1=b0On+ns0F}b5%~F^gW-ky-b_C(fie|{=@iAvh>A$2MYhVga z?0@wx4A+%DD1UM4BL4t}v#4gV^1?+Lo7yt!i``}%R}eTRY$5gBATMd+ zbuI`?TX7ZbK07ZTCA6dCdx;uwV_Z(iFL4gDGnGeoH$Ct)-eol?<&@y&T@&d8(eli7 z-^A53eMBOg`b5MJl&O(HHd~dG%?ofKlnV1b?EciNJP>B486g8u3GW4N2++L@s~LrK zKwh9FSynRh)Nsnn_l6RL@Ij%D6xQlAC#(G(O##DR#OdK4{_IY;aDcE|uHy6}mZ$G4 zJf<5{yLJz-@P9liSEZ7{75)%H0xw5#h z-FccIe6{?+SC^swA-zT{qbSZ9xD9It$Kn#PdY!3d=KR3e!9cHw%tRK(V(FtSF!+{T zs}jocLI+Miu#7b+ZGxi?E7i9i(3LE;FO|5zc*_1HXYGpxpMLl603(r1HhVonJg$#| zb}Mq7qX5Z3Hoy5WPKZJhxe!z$d4bs%;}D?vfF;eb=4>*oH4$)>Z#MWfSk32E-wddi zFyqlFi+3FH%IYb^wp*_ZbO_A%L#KaSontx%XJta85@nyXpe&%8B|@ed(GDO& zoN9ibz7oH>m_>hSRwk#<8e`((Xh)d-E_T1eXXXdI9@%a7pzfW2s6|OCcGZ`^ctsRo z{{Vy?>Zg<9XGOgeP%OW+y!_%nb%<1#d%os{Ql29t0x>A=bX25oCnK%hNg=L6<#hrjhH>~~$n?oocsK}7T$eppf#uZ_U7*(KaE+k?kgibo-KS*f~= z+B42k6_{bS^7@|Ao_8*7EC%4Xz@V>m_pQxj$6FM>CH-x9{bH;gJ-+&f=R9U8pzjyu zxRdf*XuGe8Qv#GF2QRFrlhVPss%_vPLX#Y6U#TpOc}=xp@cPSob-1CXf4Q+8cS8LM zh5MBiMW%dz^(l_Ji~*>64Kjr%%)lXQJ+4^3;KZY-`%S;+q4IDNN{a*3AQD=7GKsvF$)Gey}*{A zL-UxX23O^|@J4Abxn4+(i_7FgP(t)FtUT-OxK1-Y2hXdQVvVhTvVg?T@@4!=<%5uS zQr_zi_#5l*F0S^wY@Ym&a4H|ApvM)c9%V%{HjRqDILr{sCHVcAf-SR3ldhuna@KTw z7&gm4zj!0AZ2Qjd?6HS-F!dld3^Yd1+SB-q+zneR;gqzc(p%NT7+fY06T5%v zTeuE_itG}q#sB5GeEGwl)1XG8A4~0_PA?wcqg8#CE;S8E?t;CY{nF>2ALfo#h9QczBq-1=oLfUzi{7 z{{S-x4<=FcH!n661Mm^@i|u^BznN+`QGVO}%U4vD0iqpw{g=Eoe)*X~oj=@XI{yG=g2{)M%P6gcV+=9@&`Y=sH$0e>Vmq*pycE<5kl|d2yFxKG z1LTO{p;=)^-di9%4Lwn2FVYObysAU<4{@2s7~XJ+uXx_mM@&F2;dw6%ztPN6>7?Om z6?~!!9zQ3aq-ZaQE}#tDU50!_0e9WNGM6P~#iK*PyZvqEKS7i5#A5He>}ao>e!MO? znjhO3K49Ify7uUg$+3UTZWU;#L7O)J00_GDhxflj^EC}#WH`>inLWMzqCbF3nwPv{ z;O0XT{{UB0;Z-2?J|5fL0ubN=gM<|AVHgg)Bh|I{n9%s<@G{aGc)FE7l31omYII5l zBkMA~%pL^8l_$Y7V?2|hzj%eSQMi~pncRS$`T%h=q+}QK4Ruc%fVRzzvc}1m7uet1 zdY(9P_ivQk`L8I5tx_m?y=5yKF42Kqjn8EbWY11SLjM! z?umUG+w_8n&1l$p5MCF_iUd*)_u zC7mUIjxgBG)ci#56H@BubLX-a7uD9{q*JHvO^YBC?Z8mci-Ff85=2F1X3oj`xH0yx%F=p{9%7d zxI5zNm48WbLJR59Uth-_TKy>YpZ$sLnN?wz#LRUMfz%asqExw@zmy^qXmb8z;75!e z-e9XEYxPg>5nl^#tMqHp?W3~X$K@?L8(!tUjax@`-IvVKyZAkyMj;MH@b`6pdhuxt zFV2DZ98CB4taP0>_{<8yE_-1H6&BI_;d>YYqrfIvL3PgNREtE?^C^KUD2k>LydGjI zeV6wTtr{ezG7pk>F19-l;#!>WW5OfM&2}H=Ccx5KodWx~wZThD5AxIefD}uiN+wI{ZiO%J?u(d1X%MzM~f|RI0Yww7kB=#E|%&WTWpkve)WV)W-DfC|s>j zpP2OF++Y*ju)eMPK~Iq^u8cFO4WA_4GaZka&?FkC`zYY~g}vjazaJ@ew~A{r=VQmg z{{XyHB9Gl7;L+UHn(k)ZOGpv_002v#>2&EIHo4Lr>@V5(sAnd>NF6xtgK&;Qer2|Djou7zss%6+zzbAirXP{lmarFm3cz6b|WM+dt*~R|==?k_- ze`onVUJ9`1?=tq9527f;7Q!FMA8%<>-&M8kaWa%mz1_~8qrYfbAEkbe;91}w%L4R^ zXL|Iqh~^lG6Xiuys8_VRq2Ro}Ro@t(BIj8Tfz#~AUSJENl+F9+`JU6P@9g`Sj|rL9 z6cT{Mq?XIqi1s>~lFNzmr0`{05grJU4b*JQrf1|Ye`#{WWZX{I*n33nwj*MoOfILK zZLWf0fbQmCo%ACe*48DC(E;^gpoT@N+O{Fm5XE2A(?fn{Fphx1k1*cPGTzvHBEoA# zzzp68_QTK+9RyfL=fIERTpk&G@YS|uE~7~1buoTsh>> zjqPW90=WwD4JCG~8-5?R<{HSbz`>!GQdVE9H=OFtX%TEMXCi#6DU%y5cHN_ zp?C+`Iw!td$c;f7F%7dzC7WfQhYh%TSh&TNf88?>%OR+ms!$6zT7?raDkW&rGidI} zdtK-2h_2L9m7e+k01^5}G_3uN6Ey9Q@rUy+>-m3C&}QKP{MYjpvFHl^A)e}3FL8f) zbNC_O3Y`y<406#_x0#sfhfoY4Pu|Y6~{6l?XfNM(Ov zpR(agHWR=D=!yDOGy+tKirBaI=TRsJ<^RuTv>x=X$rve=2O@_%3G$64~P3ME_|%+CzcZd4KWJs zo6i#zqj8k#U!6@?29Fg4W(^R^cP*$b8C*Ft zuC0{1KJ`A{2H%{1XM&lHxx$#%ZI*l>7105!k|zm7ZoGwzl9t7pFVGb?eNwAt%lK@4 zqlmdOOThmC2dK=Ix!~q7STg8!WwH} zm9ea~eyK=++{@dU(qQUo0_Fom%*=2{{FnQkU5rJ3QJrHsM2 zmMX+b%o`7AIKUSfXJ^qf))>14@&@`Cr1A1m6F~T8FbB%b$Ra-x6<4!@mz24(lrzEO zYrvOzmxy9U{a{`1!=_OxUIquhzqC+-xmR&!7E-ESI%S^XO5bOf@c7V~89h(dBjg-? zZeVVOm19r&?an5#KEpYk58Ovtg7&UQ+U^}F2>WyOmqF4DrGCTwPuVLUCYt)gN}nvv zn*L#7e80E|C}2G|>T9hZz!u7*kUGD1&GvpF?)C!xto~&LbQ;?B9#H&3IMgr`_l~|j z7)66vVxDo20+UkKwvGIKKS;5en-M-*A@!FL+LID3qLJIXAHu7}8tn0({h!1k!>+13L z>Kh_p*I_gJV3ugB?-c(4B2dyjh$Q;DB*6&2jCzXlnekL_$Lcz#d+wC%mK17L2dxG^^C%*UT6V(tl0$h3ajof4v8N~kQJaP-Tb z+*!;Z_XcN#wNja5C_;5GNH$_6e8;TrUP`)37sSymRTkn7ghiO*IPubJfcGmB)kbhf z#_-=Zd;3nHpem=?F%ed><}Zb$46K;u@=YPb}u1U51D(4g{ro1V?t=Cg3#n68V0;?($?eu*DYRAs1 z$gk%Qvc`qMbf2^D51fH!8E@`AxHN=R=q40wJ!A#?Gx}aQarsNH9b8m%G#zjV&BNt9*Pi_NjU@^LA=wB^mEibJ zr&sv)ypR>TCxJKiTpdO;vp(@liB4HaL(Iu~Pie$3?Uf}tPST-1P~ISe=-*^{#J>|J zb-*hbXPS9L>5K-*`|`P4Dl4ATOyqYi;a>gw5QxxJJK2}+>X3|s9gfJoY_coGYCH*6 z30E`^%65~%sIi^>N_{3=^5z$BroQpZ{{XHVrviyG0s2K5?0fPb$D-KeB-na?A9=sA z153-}`Ih5BF;5n=+}?d@7&<@7V;H=p{N2D9ln?LE{9BH0DY$+{ty=NvpxR+Kc$PxTnI;WD{Y1!FfVN14Q$q* zNpu(l&Q*UyF$@rC9-o%){>Qsx^aKk<1kGdV@hfi(%!9O{W?BL4e#WN zK~)f0#@&5o>mL&qj_apWSYF-RC;n}ZvAhaz6z@pFY;X7LH z`%Qh^c$NH=KT7z%#K4$SYZ#JJUt%O{-8q~WQH&$~?knwe?=owQ>n;zDtHe|l_=BiT z;KW-lv@;kph08%?f;1-90X~sHhFIPGzR%d7{ggNlU}s=r;eTs% z_cp_Xr5=>cdtU{21qG~l8)Upo7d_u;W>}NRpTRvIdH~w;d&_6XF$c1r#mi(4sKD|5 zyZuZ50J}9y65-tZh;gJpH!cAHfFQMOBSWjUul7*wnl#j+_RK4F2nFo;bU__u--)ny z1#&l)#SL`S>U$r?9kPRba;ZNj+M|Nc56=uG_d8J7K*v_*Ydo_L(?j)T^3A2F&HEYG)KZ+u;+;YE?Hf#BfWagg~6k#xR!m3AkI#G|4p>T|(7r z+pZFxyNN`_ELC>Aa1IMAydh&VYGuZYx+R@EkF=yW)YmW1>t6@o0ow;iaKHNP3(J&V zASB^jzt}Md;ec#!H7pGXcAyMFQ=%-A@|er!xQ&EK&gN+=MhlR|pjyUZ zdFAj;4;~tpK)5ZKcTwStQj*HOsr2#ql<(KD=j1^7{{YNf zF~97}+3~UUohUd6@Xo-0v}FUWN8V9SMZ?BnEE<1*GSP=&VliHsWP=?usHd_v(s-dX=*)wGH_-ER`-__yLJp z5YUD7H72RTQrz&=EWmLw!wL)t-R4o17bppqV-k;nN4rx5x*n!~X>&19hqY(=#y?^B zOH3*4zrhl(biAbmG!|YZU{-sLV@<#=<)KADJihU>Wtx|6BL;WFb`51{M`mnAdm}k~ zlIXSw1+udDKg51)QS!>Q3HC~>ZUM2p!+V9g_fPnivjn@A@!y%9%15;phtoe!4MkHq zia+DhH`*gt&;l zpJ+EKj*#dWe(>*Cn)sBU>w&A-X(F88{8^Ef(=OayLD3Xt#k+%N6CO@SNX4#8oSJ8G;r^e$$~c-1f^CK?Uy14l>A6S>fFpahr`v8Xw;?{>o!M@cdh-ISOi=PRieC3u)(B z?+jXxlEHY7ge472yO(>GmszVX!I_6&bBKWn@R)L*$cfv%zutM)O@^y$77p>Wzp7J$ zR8*fGZZU5`eH2gEA7}mxh=yzo%IU=S9w5<(Z-1Vc!(I2y!25>yJSsYvwnFz%(gU}> zp%uv7TR*O7&+wRi;!HdlP|ZM^mLgoQV1#yyxpZ4q#YTT=erKLAeWr)1Wu@hb;T#N% zKO*u)A@9&Ukr{%kCG`egS%}K|f?`~Pc^F}!m!yoN0Xk)_U9Z_DI@;qgCCQoTDW`Km zm8VpL5zxhC(M?{{aW}-SFyVK>?bN>)i7R4zw=hSGS@jOg%MiuF%VHMDyiDHHHL{-^ z2JIh2v^>2K#-Nmz;E2(iq)$}{GRpUJ%^0iPAqHOr&?7F_+)muZzL3*}byKk0?FcF` zS5PFQxsqkE-Z6$ND@;Co)l3^8T}%}B{Z^379)(QB{7Ujb?aaJfT!W*${{TJZ%3kOF zo0wWN?sUd?OtUtfoG-vv9>Ru=;DWupN}y$rYj_5{3@FT3D=Yjsg|ZL1TNoCzIs{(g zu={%kSf=S$vau3_M8L$k5!slCZHLFzR_2b2KBy2}(2VJ4Xz4FiQfTe-iw7EK0c98R1P)<2(i?97TXbYMo|X z$Aub}Z$er2VsRLLwAOFmBEnPWCjXjz}QygupIwj-cxhrpM{sc(TqBG!OJ;pGa zZsmFEVZ^~5%huesPNV!{96{MIjPaM3+z1`Gdq-QDZgdcd?u?9m1vJ7Ap3;L}5S2r((=R~`>@*%~9H%#sk zH|OGfr1ENKr;btEbK%0PF~SrXT+X|wRKZXZ{dMVM!o5SwGSZ6;ajMacoCPeNL||n^ z^sT;{iqK>on@5v=`IN;}fUH3y`E=D0M+KV|D~GZEK;)th?|&YAGrA-!jM!exHh_JZ z*7HV*_*nBWNH>{Ijj3C2&%8;5WCIo3P4|hsmV;nhehSv^C8OWms6hDicZLYl%-e1e zd7?Vu=bywa6C4zuNU>*F#IP$_Zx}3xa@IA4+G<KlvH>B2ZS`!8=Kclpi8~F~D7bAqO7l_&7#5_FFtaIJ`a|#ZiwKN814V$|jbd z2PrGlzd&%a3H>?x%P~iuu&Q$48A|qx37ZNWM<$J?ZXk8p;P-#_9&-c1HN*_A0$=Hy zFb$tf+?N@Tp9Wjuv>AdiSdI-4e2l2qmO0;0>n6Qb{_*UCSr4q%q}lwVQd^?U74w-& zDrMY9crko%-Sr<6A|qdpN+SqSY-6*`VT3Do0KT#RhUkyCIzZ$F`3&d#ug~u z57`1hO)QI&s;5qZ;ntH9sR!6ZGVHpGP&FDYpN?dk;VM#?%wzN%MU1p1h&(;CW>EhC z@+Ka3@eyj$hxWxo-j`98bl`_(RL)sHkLbbv{bRl1_QX2dEBy5q{Yfv>K8JtD_b=~L zGtyeuWTf|nl!sFyvhOPgyvrcZ-QV(4%uvEAS>@DqR^q?WRV}egT8_7yx)S{X#9;Ga z*#&J+Xh;$%Y4RtQp&Dl@81#FvE*=VmugGkc&*nGr04+Qr)L^f~h(=(ZYFXR1SK&~8 z^G}jv13K_BttGIxN&adO0$MRl%eD#x4^rieZn``{T|**6BG5AN{{Uie6xs%7L+*)X zPU2p51AsvlZdy?-GmKLVF;QEvAbFVC2y<(;e#U^OG1^A^GyF_|5rKiZU)F3R;6-Hw z$t}kZ(0}ZzZEk-PEiWz-*L+nFqRH_+;0(EW3(r$8jR&806)l3uw{eKAV1`6E{Sw4O zqrA5j@x_Ni6f(KFd@Olo@E(UPnx!vjVSU5PIwLp1#x}LpMn8`spAXMzOU%uQRg_i3 ziF+`dwFxmQ%xY!vd|cQvwO#m*9OhcuHO7l#JT7K`-*KqeeZPn^0ezt>Zr{Bi zt?|XXz{BUK+qGmG-Vxn_PmB1Mm27D|F^PMMO^|pE$}m89??;9_#2f|=rWF?oq2Hd5 z1ngP(na6<^lwzheuk#B5xtJv=GV1wMKH-{5Y_6C=Mv(L8>oT3a%O5l`l{+!OXwv6& z6=8@RsgTUORmFQVyLd0!B^s-s*UW9P(^27usLOZsX7Ba?0LBYlAx+*4-X^5F%2#nh zmyv(eP@QN;BGTbvl8DO_Am#+N9n1=r-*T{q&+wH9_Y+**AM8JJ4gQcvS zQGg*=;6LmT=w*hrYyKe2`f67-DpwZ*ZJ!_Tf3cOwq1&me)JM5~CDOPE*7n~s6z9d$ z<@A{71ikW_l`p-f67uD|6DZ8oPKR(=Semp}6H@3=?8Gg&xGR@3$lo5^{HPcpV=3lm zl%#izoWt-_8Ouz5oCS-pVEM1*5I**f$MAn~vJYWT*@lH<7S&z@#C!QQ**3e%d{1p0 z&xj^yV)h^VHV)jV>FGNwswBr^I$EG!=eJN+1)K9IkCbc)XcJ^D3>mw5z|AW?`o%Cl58nLIURZSM1E7cUf}bZ;RO& z23Xf+26Z|`FTwu+u*wHPz>M=VL(zn>1kraYZgiPXa>i1HtlAY~TFNTiN4ax%FN+>- zTz(-rn`nVPGcF>Hv+P0pJ5OM+QQ+|Z05h&GaKHex+BM|VBnmVP53tL^u8bd+iI~*S zWvqd-V0SW%zqDs^9qlQm2kd1>+9WU@=0U(*#-Jf^_>^VD?h>#md>7(8QEYuKcZBd}Y#wGkhIEfpjaBvT*Br`5@eOZ#ZUj5m4UgKX#$=s!2 zR_E4IJJsjRyi~8c{(cqu2P{_&=x`tIU3p!XYc1|E0Q}6?GV)4gF#&wTCRGU9cKfpU zTp>e*CLo%aW=kASwg}w77)Xy!0^12hZSZ`{<6eyMi5u-Yyvo%kBT*Gwi`gn1#N5Hr zexH)%{kZ(}`1RJ^~+}30HgKml0gZ}^n z-ZJ0S+w&2!tsQ-Q@DivKdi+1IfJ6htA;&?}eq*@fk>%i*!z_k+CxVRx5s7lNfk%R0 zQS{Ak1gN`}&{E_fa3Z4c9k829@n$#DzGB%c;xHYhh6{il5Vd5(Qv6SLUo%Am7~HNM zaJ~jPj%uM>;xU+T_X!LJYNis3c@GSJIu|~o5$pw`{7T}W1nmK46!3R59NmRwVAG?Q zl>G%?h~6pywE2ah-2%6MhuDI4tHe{5pAg_IC!{Hld39)33_la5jA#W6VrA^`oUV59 z5Ez@y6OG1(W%H2CI0ux(#PEb*d&4Y79ZuX*twRW54ac=@j`J=Uh|Zy6v$7*jE?rLy zygCQ~uXpR`{FjuiZsmoses6DxLwVKp_TX26;-` z*%QRCG4#}~0#x%)1GSW|nYxrFfr2OKB?I0e0ZwH=0UT9?G4A(05R6Yba#H(|N{y*tf;hFzxuDa)Vv_cSMh!jK(N92$$)=+Oe~7Z2eGSxa27P9-g^D&A=iWB z>TaW?k%K7>qFz!xH_W!Zm@0>6kCFZ-i|RZh9%${CGPG4f$H+(Q$x$qdA1HA9&F&K$ zniW&B3qy?dukJnDq)6%{OVl0T3LqpKONLfuDyS_JCYXz71+G>KI?ow{DG7MEx85=jK9`c5x``?^@^FApti~j)0?q!WP<(sT~!@i|% zIhQ;zmwXTAW?vv1anqzlBzd6;3DhqNLWm=D6M?=Ic) zC)!zD-?#1&QAN&wnQ&2m>?nvfuL4jrDiC}|QN`j_vv4MrNmdqYjGLm%PKz$G8s>4^@v<0Zc|A?Z>!hL z0c&x#SAon8aK4Sprx18tEPIkSsyBi=;V%-U;2Dm9Y*srVG~r`9|_4TaB{jRM6A1b@b`>_>82~Kzyhz zCP0O{9vvKA%2n6H|*EScEQeEZ8Eo9+HfFujla zJn`))9rrfIlOja2qBxBpDqjW1{|OSUt#@;qNRERm6v=4z^Qz%jl*#@OeIQ{3~+7^rAl&jF#+N+0Qi+$ zjgp{ErBv=<2NMO{AXer4M&lS3tb|dN3~k~wxp`Dg1iJ=jyc^3TT#9db`9ErzODa@% z#&G6n75c!dUdt$*+2wT`l_|r6JD4)KiI@`WjQ0XzlML>FNkR=*w4oVdmV^d(xojJ% zs(>f*brb&pe2Z`pkq>uoq}vB;`+cVTZ{0+>HSa#~DEtU3`Z4@Rx4!=Xz)C(Ay&u1C zyk8^1(KGL!w=?xmI(Et0?l@&W$&|k3rsio^@f>5hS%tJQ4rhm6(ECFKw6ZAusgAfR zX-?^}qxO~-0UcjZ#&tXUhwm<_s5SY-$;#h)`IWMr3}wa;j|4KFJ(E5yHxe<45<=L7 zxbS$7f;f~$jA}KHFdRcUfio&06pb-9+l5T?1rf14tZ^~);eO(Dhr&Mv{{S+l7mx03 zTJ1aFW^AK2qMI|h;F*}2t%T~a+0z=9>$~UtRDPLg*B;~-K{i8XSw+=G@DF*Et-Om5 z7I+1WRg9G~#K229qc8M=_b8KCh{hwJo-QK4Z7O<-A=|SltRw^pi`p4ixzQ~(eh5D1 z30EzxLfyW^pjrTJJ>bkWK7fB;y-K12fR{@cF=z=sf^2mXn2S=g5WGOf$SC+PiBq~2 zW4;Qwgg2INaLm;AhQ1H}#mL|*2il-V+o`^h*C?k^A-!#9w2&_it12P8bu$qEgIk|Z!%V?I!S`Q zrOsk>N*RGUlCtP?5pt}^^qb^);ngYM2eLL~$B6uz0cyGeW+X=b$G?--k0`qc^_`?N zl*_jtq7pcTF&j#$Fp1o8!_T;irImBTm?Cr!_=|^GN8gO?u!Gt$Qr$uea8;L5f|&BC z^)VhqD*o3nwb*&60nl*7;HVs3?Z#uMjuP%*Q{pJVS8=4*C5$^BBPEq8=;PwxDJ>0L z5yGZ0PlOi?VS4y@PX=8TQ@A!5X7BPbyqIGgB7QW?BtkpWNM04(b{NE7iEFqeONdIDY9;1jD30Z*3@5fb zV+&=0edPkn6RDmTMIDin)(l3?=LC7li`Vj`4hT7yjden z%_0RvtAfKhm@MN7+ZpC7E!;=M*?VAnSOV! zYNz-o)@)!^{T0AZC15Hu}U$CGTleDAi21O^StPIf{eQ z6e=K3J`UKkL5p7zOy6ioKi5bAZ-mW}P-Zsvk4;YI@d@D1Ey&Sx0zM+6*HApOarS}8 zg9_sKfW6!LlzAgOOy1B&AxKXW;St;*MiX-dO0kMu!%r!E;j3qKMXVNL#JpVY>zSr_ z5nZE9u-#0OjhEtC;dee#8gU9=sODwMrh;NQ{h!>+#YR+DQ8#WLEJk=S+@SD`d369& zadfQ3k9e9Ptjwi7$f#qrEG*v&7R(KOPUgyuh8Lt|aI!Up?JLGO%-NabxBaaCKQi#p z7sCGlyP9w=C4pFiBv>grDqX_QGoub_2E@M60Yr#U4=llP;xA$7DVw zdqzAab0QlXHv~>$y8Mx5)->(_R|ZB_6!w>31$)eg&HCmvm}KhS`et-hxqLt?BmteZ z7q>6%2G6qsUn4gw-lJsL?j~cTUZu0Ro>52QS;AUj+(j{{V?_qx*SS#-qGtEkv<|e?e=F*c0QWp6s=5jCBbI zt~CrMQHqO^8Q&I+NZKmI)1Z&9a^A$P7q+o9FcqJD&hxNny;7l72k8JQ ziXX(<0mfka15D}T`X*RT%Z_)zXr}kg!1VElR zgXiKl8CD5?9u*e85tR_KiWXmjKXlIuOpV5vh|Aol%jqjovhGx*d&VznGi(MR=x+4+ zef^=F56pjrNt<4WdELMwB_kJYwE$&UCE2?c?m4CnLem^fRRg(eJWkIsmATmx?p0Xa z@#=O%XpClw^H8%>xdK#Z0Dp4dtZDAx_J&rqKkk2fGk4)+-9G2D2H;{l>LRSE+C^EI z2&;*H{{T_8&#@lnrOgD#5}gEnvZ?GxvJK;EL_=#8Dj9}e_?p0|xB&%eD&qx9g}RF3 z$|+X=dor4i53IF-a@-$fuoJ9HOW$KD?J6s8%JRN>8849bBWp7adM~KiP|5AF zmN@2%BWF?O25NRAm$wo)lEhHV9_4PkmE6i%Q4!o}k{DK!`(m-uS@(=Is-4Ofc{-Nc zFklYfzCXV*?1v}ps8Wo9${o;A-P9C;LHe3Z$!;KUg=5(u!y+N1w4s*bpf2E(lbOaO z$R!5ZnMRHXRPnf>uQIaB69p3RXgD$>=?_#=)XcuY*t>|?99*{!|i@;fn{{UMY!7AQi$*=Rj zia^x6?oZ!*VrFH5U#U{8tf|7Mf>D@rVti#p!7sBCWdhb{@hPN9sv{&x-8cC{GyMdA z&l(3#6Bc{}xknDe=6g84?}(^1*dwQfq1TV~2XsECl6(6hZM1!vOd+AwkMs$*M`gkr zwl<+C=w>JaJ2Lg0xH!U(y98=h|YaTBBtfxM$)%683lx`yF8eoS-oPLl3buD*fD+ay#g7o=I#0pEP)n}|~fzdtse3K&0^0od(g#nPm z3s!eUo?6V@Mbj9sF>#aDAU%@(bufFCy5;Sqq}nWRWHY|gZhhy#0tn2n^HorCM|b|e zsaZHdrILFxCzyFNdu*hjj5uLaFAM-#q;!$iaUJc{Owu&u!b)4s+;}m!s9|ZVZ!NNb zSMLNA=qG89S8xm@$f7yE1g;JIfXcEYtA_`Gp@vVth_ml6!r)QOM~nRtahM3G_nA(D z4JV3UCqxdB@iNaEg6R(70hzucD^x!4iC~u#1lxe8lEYv6j+f##t=*kHd*i$(Yyz6E zvd6}u=L7SQ<>#t2fqD;s%6bVOWNR*SMYR6_ft`*NZ(JDMsm#fk9mf5NrlWwIHsq@@nQtujoT9mlS-DHDUN7DV~queEFt7JypH?HmPglo#qSyhIjmur&sF# z08q-Qjm0qAB@4Xy9m;MQ)?)zEP5FI%MzjHT8MpY05sQ~DCGn|(t8>@K-}#puZplN}2gE}t z%w)v(LkXg#k{M<_^h)ltWs=rD;xh{a-_(EhEphcnEsE~n_89^4DT1y`YP9p?+3qd@ zYz(Y)F)@2jsp4@TQQ7GK0I+8%Ya7yj_Z3(7N7&Qj;&^d5dHHw;4ip!N5bFZcAz3@Om;rvCDa+Df(v_li+xW(Dt9jP?kXwOQ>b2V^U3iQ0Ko zZH9M*iP^-bT@`%l9gwD0QrVVxh-zn;CVS(s#3zjYQ^9hCeW8hSK86@aU>$$h*2L_1 z0QC~_#IRiKV%vyU5uU}t#4p@UKhXozf#HA2aY<=V^c@3}Q22X4GYj_j@{78?A1T~e({LJSa-9?hV(3(B zd4c}`Px#8S_CLaRI4XwWh95tQ<8gJtinwSx{+%DW+`>A{4FEJF%c(M8R+`7C)WMF} zuBGtY6j`|D9Ok&thm6=-hNVUYu>pPYwhfmtUJ%_8Y|FE#wPEcq?1>APa{>wtnVOl? zi1PNR7AtJ4ul%+|+$^f8?pnfIy7q><2tH;S3OH5|h5UX00H2t*Se!9dQZcB% zm<|e666nh@e33Cjwlu?dAN-0t0a}lY6{DyqoOHHN*L@xQo+p|}aMHhOmAG~Rr_>65 zvV&B04WNHN`vS0RX&Ic9g4QoD;yLyNVFn@Td>(^X&HJIVN{^$u^YIGIDDLp(d5SYK zUPb+WlG-5cg|pguU;a8tze-gMnO_uq!MqCePwoIWN+9ti!Nv?81pojW^*@0erqR)e7=;%t@L4;{kegBmHoTV*6tm@)FXFUtAu$`la`OB>>N{mSeh96%L+OdrLjM3_Ggn_jXPHu; zq`L1?}nxSQJhn0gq#*c%y(inNs(=gkAYPKJ_3{#br{TqGt z+*Gp#kiLArSxgQ@Eut{J1W zES&xnOWT_ zxzS(!PNl|gY5o3@2obQbC|getnSHM@ZP&s3`IK64Z?*`rl*I8$d+M0+h~D1j-_$yr zP)%gn3^3`2Lhr;JCDJx}@6z4JM$hgp$_p!VKV})rTw<~w`3Kr&lG4<(K#upVU}<`K z3Jb;M68`}0A(B2RN;Sk3e)j(WF&%!}-gsnL06_8pL^f}!ccJh`w^+FX zfSBdof48ld`F%A4hjNg+g&xr?k+v|#;{i{~KFM!VfL*}WE)cf8E@GIr%Egd8jQ;>g z5P8iL3N_Xt{i*|B;fb2l>L0|y_vPlk38u%j#K*qe18Hf52kS6XI+)DvPY(de2adjk zR~O;y>mCl7Tpf;vH2IHOS^oeDtSwUa;$7u&(0%&;;UQv*kFUIU7^s-tTyb23Z7L1E!VUwm>KvZXsWR{Bdtx~Qr~j8=l>n{F#LQv8l7SLRYI zykU#`ej+3VW6_z^?Gd+79TU!`d>H37M2unr+96Kn9dRudJ2x=+Gqn(5a?Wq8c#c)` z<|hw140#eOfHBuq4-YTenwl`(dHmnvF98K&7IgMj$_T+r!!oCo%8t+_JL^ltR&KcY zFB3?PzXVm-KHlfN7K+RFY6kLpw+Yf&#{U2ki=Po0PuXHkZ{K?V03=8&ajk-pQ0&P2 zRx104R%x1qxq9FcpNU^j4EBGLAN*8!{?>dRh=uqtOVBw*((I_LKnow>&fDV}_A~ zDeMf(8N7d~VW^9pD=-R07*64Z1(L!I4&~^I?oiCC%#=c~isn?CP<=M` z&2C>pIV_$N{{WJO1~;q+!oXR#%%xysU$d`KIch`Q!Sc)_EQ| z*wS`sgXU1BT5=1k@7rFj_EfIfe(^gc9?UZ-r#pr!Et4G~{N~lw_u|ab`mLfFN|5-T|}yCwM^06 z!dC|B5prixhV&1i{{XRFR7tPg=32lO*)*{weuGflI$+)uF11pj4@dTfJY*$I!}Ji! zLaCKx=#P>1Ab32^%gD!A<1wo*x9iANL2qonBl&^Qb)PVeV5@m9VtPhkiK9_9yMk}a ziF??Uthqigw-823u9XY+{JgOKP6EbN;Ql`3!}SiUF+J7i##WsF0OY-}Eo6Irc&|%W z{{ULkDys4vGxWqllk;N5y{mGCM#`%LXs6otoBrHUD7B1YRmK52u}NOO!-d!M%{?D_ zeTH|gUa%#QkXh0S@faUu$Y8_AW5CkB z(%?51xcyPURpJ}4p;�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≫Mx{f%M%i`k%8j7@%6b_P$XJ)lYQMjJ>aU#8OcR| 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≈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 literal 0 HcmV?d00001 diff --git a/API/API.csproj b/API/API.csproj index 74bf6fbbc..fa1bcdfec 100644 --- a/API/API.csproj +++ b/API/API.csproj @@ -22,8 +22,6 @@ kareadita.github.io Copyright 2020-$([System.DateTime]::Now.ToString('yyyy')) kavitareader.com (GNU General Public v3) - - 0.4.1 $(Configuration)-dev false @@ -60,7 +58,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -75,42 +73,41 @@ - + - + - + - + - @@ -120,6 +117,7 @@ Always + @@ -244,6 +242,48 @@ <_ContentIncludedByDefault Remove="wwwroot\styles.4bd902bb3037f36f2c64.css.map" /> <_ContentIncludedByDefault Remove="wwwroot\vendor.6b2a0912ae80e6fd297f.js" /> <_ContentIncludedByDefault Remove="wwwroot\vendor.6b2a0912ae80e6fd297f.js.map" /> + <_ContentIncludedByDefault Remove="wwwroot\10.b727db78581442412e9a.js" /> + <_ContentIncludedByDefault Remove="wwwroot\10.b727db78581442412e9a.js.map" /> + <_ContentIncludedByDefault Remove="wwwroot\2.fcc031071e80d6837012.js" /> + <_ContentIncludedByDefault Remove="wwwroot\2.fcc031071e80d6837012.js.map" /> + <_ContentIncludedByDefault Remove="wwwroot\7.c30da7d2e809fa05d1e3.js" /> + <_ContentIncludedByDefault Remove="wwwroot\7.c30da7d2e809fa05d1e3.js.map" /> + <_ContentIncludedByDefault Remove="wwwroot\8.d4c77a90c95e9861656a.js" /> + <_ContentIncludedByDefault Remove="wwwroot\8.d4c77a90c95e9861656a.js.map" /> + <_ContentIncludedByDefault Remove="wwwroot\9.489b177dd1a6beeb35ad.js" /> + <_ContentIncludedByDefault Remove="wwwroot\9.489b177dd1a6beeb35ad.js.map" /> + <_ContentIncludedByDefault Remove="wwwroot\assets\fonts\Spartan\OFL.txt" /> + <_ContentIncludedByDefault Remove="wwwroot\assets\fonts\Spartan\Spartan-VariableFont_wght.ttf" /> + <_ContentIncludedByDefault Remove="wwwroot\assets\icons\android-chrome-192x192.png" /> + <_ContentIncludedByDefault Remove="wwwroot\assets\icons\android-chrome-256x256.png" /> + <_ContentIncludedByDefault Remove="wwwroot\assets\icons\apple-touch-icon.png" /> + <_ContentIncludedByDefault Remove="wwwroot\assets\icons\browserconfig.xml" /> + <_ContentIncludedByDefault Remove="wwwroot\assets\icons\favicon-16x16.png" /> + <_ContentIncludedByDefault Remove="wwwroot\assets\icons\favicon-32x32.png" /> + <_ContentIncludedByDefault Remove="wwwroot\assets\icons\favicon.ico" /> + <_ContentIncludedByDefault Remove="wwwroot\assets\icons\mstile-150x150.png" /> + <_ContentIncludedByDefault Remove="wwwroot\assets\images\image-reset-cover-min.png" /> + <_ContentIncludedByDefault Remove="wwwroot\assets\images\image-reset-cover.png" /> + <_ContentIncludedByDefault Remove="wwwroot\assets\images\kavita-book-cropped.png" /> + <_ContentIncludedByDefault Remove="wwwroot\assets\images\login-bg.jpg" /> + <_ContentIncludedByDefault Remove="wwwroot\assets\images\logo.png" /> + <_ContentIncludedByDefault Remove="wwwroot\common.fbf71de364f5a1f37413.js" /> + <_ContentIncludedByDefault Remove="wwwroot\common.fbf71de364f5a1f37413.js.map" /> + <_ContentIncludedByDefault Remove="wwwroot\login-bg.8860e6ff9d2a3598539c.jpg" /> + <_ContentIncludedByDefault Remove="wwwroot\main.a3a1e647a39145accff3.js" /> + <_ContentIncludedByDefault Remove="wwwroot\main.a3a1e647a39145accff3.js.map" /> + <_ContentIncludedByDefault Remove="wwwroot\polyfills.3dda3bf3d087e5d131ba.js" /> + <_ContentIncludedByDefault Remove="wwwroot\polyfills.3dda3bf3d087e5d131ba.js.map" /> + <_ContentIncludedByDefault Remove="wwwroot\runtime.b9818dfc90f418b3f0a7.js" /> + <_ContentIncludedByDefault Remove="wwwroot\runtime.b9818dfc90f418b3f0a7.js.map" /> + <_ContentIncludedByDefault Remove="wwwroot\scripts.7d1c78b2763c483bb699.js" /> + <_ContentIncludedByDefault Remove="wwwroot\scripts.7d1c78b2763c483bb699.js.map" /> + <_ContentIncludedByDefault Remove="wwwroot\site.webmanifest" /> + <_ContentIncludedByDefault Remove="wwwroot\Spartan-VariableFont_wght.0427aac0d980a12ae8ba.ttf" /> + <_ContentIncludedByDefault Remove="wwwroot\styles.85a58cb3e4a4b1add864.css" /> + <_ContentIncludedByDefault Remove="wwwroot\styles.85a58cb3e4a4b1add864.css.map" /> + <_ContentIncludedByDefault Remove="wwwroot\vendor.54bf44a9aa720ff8881d.js" /> + <_ContentIncludedByDefault Remove="wwwroot\vendor.54bf44a9aa720ff8881d.js.map" /> diff --git a/API/API.csproj.DotSettings b/API/API.csproj.DotSettings new file mode 100644 index 000000000..80aad93c5 --- /dev/null +++ b/API/API.csproj.DotSettings @@ -0,0 +1,2 @@ + + True \ No newline at end of file diff --git a/API/Comparators/ChapterSortComparer.cs b/API/Comparators/ChapterSortComparer.cs index a56693fca..3791e05ff 100644 --- a/API/Comparators/ChapterSortComparer.cs +++ b/API/Comparators/ChapterSortComparer.cs @@ -2,8 +2,17 @@ namespace API.Comparators { + ///

+ /// Sorts chapters based on their Number. Uses natural ordering of doubles. + /// public class ChapterSortComparer : IComparer { + /// + /// Normal sort for 2 doubles. 0 always comes before anything else + /// + /// + /// + /// public int Compare(double x, double y) { if (x == 0.0 && y == 0.0) return 0; diff --git a/API/Comparators/NaturalSortComparer.cs b/API/Comparators/NaturalSortComparer.cs index ac10e09ae..9bf79db81 100644 --- a/API/Comparators/NaturalSortComparer.cs +++ b/API/Comparators/NaturalSortComparer.cs @@ -10,7 +10,7 @@ namespace API.Comparators { private readonly bool _isAscending; private Dictionary _table = new(); - + private bool _disposed; @@ -23,9 +23,9 @@ namespace API.Comparators { if (x == y) return 0; + // Should be fixed: Operations that change non-concurrent collections must have exclusive access. A concurrent update was performed on this collection and corrupted its state. The collection's state is no longer correct. if (!_table.TryGetValue(x ?? Empty, out var x1)) { - // .Replace(" ", Empty) x1 = Regex.Split(x ?? Empty, "([0-9]+)"); _table.Add(x ?? Empty, x1); } @@ -33,6 +33,7 @@ namespace API.Comparators if (!_table.TryGetValue(y ?? Empty, out var y1)) { y1 = Regex.Split(y ?? Empty, "([0-9]+)"); + // Should be fixed: EXCEPTION: An item with the same key has already been added. Key: M:\Girls of the Wild's\Girls of the Wild's - Ep. 083 (Season 1) [LINE Webtoon].cbz _table.Add(y ?? Empty, y1); } @@ -50,8 +51,8 @@ namespace API.Comparators returnVal = 1; } else if (x1.Length > y1.Length) - { - returnVal = -1; + { + returnVal = -1; } else { @@ -78,12 +79,12 @@ namespace API.Comparators { if (disposing) { - // called via myClass.Dispose(). + // called via myClass.Dispose(). _table.Clear(); _table = null; } // Release unmanaged resources. - // Set large fields to null. + // Set large fields to null. _disposed = true; } } @@ -93,10 +94,10 @@ namespace API.Comparators Dispose(true); SuppressFinalize(this); } - + ~NaturalSortComparer() // the finalizer { Dispose(false); } } -} \ No newline at end of file +} diff --git a/API/Controllers/AccountController.cs b/API/Controllers/AccountController.cs index 8e108cd28..58478e2f8 100644 --- a/API/Controllers/AccountController.cs +++ b/API/Controllers/AccountController.cs @@ -5,6 +5,7 @@ using System.Reflection; using System.Threading.Tasks; using API.Constants; using API.DTOs; +using API.DTOs.Account; using API.Entities; using API.Errors; using API.Extensions; diff --git a/API/Controllers/BookController.cs b/API/Controllers/BookController.cs index d48b75707..448d45c02 100644 --- a/API/Controllers/BookController.cs +++ b/API/Controllers/BookController.cs @@ -2,6 +2,8 @@ using System.Linq; using System.Threading.Tasks; using API.DTOs; +using API.DTOs.Reader; +using API.Entities.Enums; using API.Extensions; using API.Interfaces; using API.Interfaces.Services; @@ -31,18 +33,36 @@ namespace API.Controllers } [HttpGet("{chapterId}/book-info")] - public async Task> GetBookInfo(int chapterId) + public async Task> GetBookInfo(int chapterId) { - var chapter = await _unitOfWork.VolumeRepository.GetChapterAsync(chapterId); - using var book = await EpubReader.OpenBookAsync(chapter.Files.ElementAt(0).FilePath); + var dto = await _unitOfWork.ChapterRepository.GetChapterInfoDtoAsync(chapterId); + var bookTitle = string.Empty; + if (dto.SeriesFormat == MangaFormat.Epub) + { + var mangaFile = (await _unitOfWork.ChapterRepository.GetFilesForChapterAsync(chapterId)).First(); + using var book = await EpubReader.OpenBookAsync(mangaFile.FilePath); + bookTitle = book.Title; + } - return book.Title; + return Ok(new BookInfoDto() + { + ChapterNumber = dto.ChapterNumber, + VolumeNumber = dto.VolumeNumber, + VolumeId = dto.VolumeId, + BookTitle = bookTitle, + SeriesName = dto.SeriesName, + SeriesFormat = dto.SeriesFormat, + SeriesId = dto.SeriesId, + LibraryId = dto.LibraryId, + IsSpecial = dto.IsSpecial, + Pages = dto.Pages, + }); } [HttpGet("{chapterId}/book-resources")] public async Task GetBookPageResources(int chapterId, [FromQuery] string file) { - var chapter = await _unitOfWork.VolumeRepository.GetChapterAsync(chapterId); + var chapter = await _unitOfWork.ChapterRepository.GetChapterAsync(chapterId); var book = await EpubReader.OpenBookAsync(chapter.Files.ElementAt(0).FilePath); var key = BookService.CleanContentKeys(file); @@ -61,7 +81,7 @@ namespace API.Controllers { // This will return a list of mappings from ID -> pagenum. ID will be the xhtml key and pagenum will be the reading order // this is used to rewrite anchors in the book text so that we always load properly in FE - var chapter = await _unitOfWork.VolumeRepository.GetChapterAsync(chapterId); + var chapter = await _unitOfWork.ChapterRepository.GetChapterAsync(chapterId); using var book = await EpubReader.OpenBookAsync(chapter.Files.ElementAt(0).FilePath); var mappings = await _bookService.CreateKeyToPageMappingAsync(book); diff --git a/API/Controllers/CollectionController.cs b/API/Controllers/CollectionController.cs index 8bf10c09a..6081f7d58 100644 --- a/API/Controllers/CollectionController.cs +++ b/API/Controllers/CollectionController.cs @@ -121,7 +121,7 @@ namespace API.Controllers if (!updateSeriesForTagDto.Tag.CoverImageLocked) { tag.CoverImageLocked = false; - tag.CoverImage = Array.Empty(); + tag.CoverImage = string.Empty; _unitOfWork.CollectionTagRepository.Update(tag); } diff --git a/API/Controllers/DownloadController.cs b/API/Controllers/DownloadController.cs index 416ffbfc5..3000e1f22 100644 --- a/API/Controllers/DownloadController.cs +++ b/API/Controllers/DownloadController.cs @@ -14,7 +14,6 @@ using API.Services; using Kavita.Common; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.StaticFiles; namespace API.Controllers { @@ -49,7 +48,7 @@ namespace API.Controllers [HttpGet("chapter-size")] public async Task> GetChapterSize(int chapterId) { - var files = await _unitOfWork.VolumeRepository.GetFilesForChapterAsync(chapterId); + var files = await _unitOfWork.ChapterRepository.GetFilesForChapterAsync(chapterId); return Ok(DirectoryService.GetTotalSize(files.Select(c => c.FilePath))); } @@ -91,8 +90,8 @@ namespace API.Controllers [HttpGet("chapter")] public async Task DownloadChapter(int chapterId) { - var files = await _unitOfWork.VolumeRepository.GetFilesForChapterAsync(chapterId); - var chapter = await _unitOfWork.VolumeRepository.GetChapterAsync(chapterId); + var files = await _unitOfWork.ChapterRepository.GetFilesForChapterAsync(chapterId); + var chapter = await _unitOfWork.ChapterRepository.GetChapterAsync(chapterId); var volume = await _unitOfWork.SeriesRepository.GetVolumeByIdAsync(chapter.VolumeId); var series = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(volume.SeriesId); try @@ -155,7 +154,7 @@ namespace API.Controllers var chapterExtractPath = Path.Join(fullExtractPath, $"{series.Id}_bookmark_{chapterId}"); var chapterPages = downloadBookmarkDto.Bookmarks.Where(b => b.ChapterId == chapterId) .Select(b => b.Page).ToList(); - var mangaFiles = await _unitOfWork.VolumeRepository.GetFilesForChapterAsync(chapterId); + var mangaFiles = await _unitOfWork.ChapterRepository.GetFilesForChapterAsync(chapterId); switch (series.Format) { case MangaFormat.Image: diff --git a/API/Controllers/ImageController.cs b/API/Controllers/ImageController.cs index 31da9c54b..f1ddb770e 100644 --- a/API/Controllers/ImageController.cs +++ b/API/Controllers/ImageController.cs @@ -1,7 +1,12 @@ -using System.Threading.Tasks; +using System; +using System.IO; +using System.Net; +using System.Threading.Tasks; using API.Extensions; using API.Interfaces; +using API.Services; using Microsoft.AspNetCore.Mvc; +using Microsoft.Net.Http.Headers; namespace API.Controllers { @@ -10,7 +15,6 @@ namespace API.Controllers /// public class ImageController : BaseApiController { - private const string Format = "jpeg"; private readonly IUnitOfWork _unitOfWork; /// @@ -27,11 +31,12 @@ namespace API.Controllers [HttpGet("chapter-cover")] public async Task GetChapterCoverImage(int chapterId) { - var content = await _unitOfWork.VolumeRepository.GetChapterCoverImageAsync(chapterId); - if (content == null) return BadRequest("No cover image"); + var path = Path.Join(DirectoryService.CoverImageDirectory, await _unitOfWork.ChapterRepository.GetChapterCoverImageAsync(chapterId)); + if (string.IsNullOrEmpty(path) || !System.IO.File.Exists(path)) return BadRequest($"No cover image"); + var format = Path.GetExtension(path).Replace(".", ""); - Response.AddCacheHeader(content); - return File(content, "image/" + Format, $"{chapterId}"); + Response.AddCacheHeader(path); + return PhysicalFile(path, "image/" + format, Path.GetFileName(path)); } /// @@ -42,11 +47,12 @@ namespace API.Controllers [HttpGet("volume-cover")] public async Task GetVolumeCoverImage(int volumeId) { - var content = await _unitOfWork.SeriesRepository.GetVolumeCoverImageAsync(volumeId); - if (content == null) return BadRequest("No cover image"); + var path = Path.Join(DirectoryService.CoverImageDirectory, await _unitOfWork.VolumeRepository.GetVolumeCoverImageAsync(volumeId)); + if (string.IsNullOrEmpty(path) || !System.IO.File.Exists(path)) return BadRequest($"No cover image"); + var format = Path.GetExtension(path).Replace(".", ""); - Response.AddCacheHeader(content); - return File(content, "image/" + Format, $"{volumeId}"); + Response.AddCacheHeader(path); + return PhysicalFile(path, "image/" + format, Path.GetFileName(path)); } /// @@ -57,11 +63,12 @@ namespace API.Controllers [HttpGet("series-cover")] public async Task GetSeriesCoverImage(int seriesId) { - var content = await _unitOfWork.SeriesRepository.GetSeriesCoverImageAsync(seriesId); - if (content == null) return BadRequest("No cover image"); + var path = Path.Join(DirectoryService.CoverImageDirectory, await _unitOfWork.SeriesRepository.GetSeriesCoverImageAsync(seriesId)); + if (string.IsNullOrEmpty(path) || !System.IO.File.Exists(path)) return BadRequest($"No cover image"); + var format = Path.GetExtension(path).Replace(".", ""); - Response.AddCacheHeader(content); - return File(content, "image/" + Format, $"{seriesId}"); + Response.AddCacheHeader(path); + return PhysicalFile(path, "image/" + format, Path.GetFileName(path)); } /// @@ -72,11 +79,12 @@ namespace API.Controllers [HttpGet("collection-cover")] public async Task GetCollectionCoverImage(int collectionTagId) { - var content = await _unitOfWork.CollectionTagRepository.GetCoverImageAsync(collectionTagId); - if (content == null) return BadRequest("No cover image"); + var path = Path.Join(DirectoryService.CoverImageDirectory, await _unitOfWork.CollectionTagRepository.GetCoverImageAsync(collectionTagId)); + if (string.IsNullOrEmpty(path) || !System.IO.File.Exists(path)) return BadRequest($"No cover image"); + var format = Path.GetExtension(path).Replace(".", ""); - Response.AddCacheHeader(content); - return File(content, "image/" + Format, $"{collectionTagId}"); + Response.AddCacheHeader(path); + return PhysicalFile(path, "image/" + format, Path.GetFileName(path)); } } } diff --git a/API/Controllers/LibraryController.cs b/API/Controllers/LibraryController.cs index 53c3953ac..25f224a28 100644 --- a/API/Controllers/LibraryController.cs +++ b/API/Controllers/LibraryController.cs @@ -225,11 +225,11 @@ namespace API.Controllers [HttpGet("search")] public async Task>> Search(string queryString) { - queryString = queryString.Replace(@"%", ""); + queryString = queryString.Trim().Replace(@"%", ""); - var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername()); + var userId = await _unitOfWork.UserRepository.GetUserIdByUsernameAsync(User.GetUsername()); // Get libraries user has access to - var libraries = (await _unitOfWork.LibraryRepository.GetLibrariesForUserIdAsync(user.Id)).ToList(); + var libraries = (await _unitOfWork.LibraryRepository.GetLibrariesForUserIdAsync(userId)).ToList(); if (!libraries.Any()) return BadRequest("User does not have access to any libraries"); diff --git a/API/Controllers/OPDSController.cs b/API/Controllers/OPDSController.cs index 438dfac77..ef83c2a69 100644 --- a/API/Controllers/OPDSController.cs +++ b/API/Controllers/OPDSController.cs @@ -93,6 +93,19 @@ namespace API.Controllers } }); feed.Entries.Add(new FeedEntry() + { + Id = "readingList", + Title = "Reading Lists", + Content = new FeedEntryContent() + { + Text = "Browse by Reading Lists" + }, + Links = new List() + { + CreateLink(FeedLinkRelation.SubSection, FeedLinkType.AtomNavigation, Prefix + $"{apiKey}/reading-list"), + } + }); + feed.Entries.Add(new FeedEntry() { Id = "allLibraries", Title = "All Libraries", @@ -128,8 +141,8 @@ namespace API.Controllers { if (!(await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).EnableOpds) return BadRequest("OPDS is not enabled on this server"); - var user = await GetUser(apiKey); - var libraries = await _unitOfWork.LibraryRepository.GetLibrariesForUserIdAsync(user.Id); + var userId = await GetUser(apiKey); + var libraries = await _unitOfWork.LibraryRepository.GetLibrariesForUserIdAsync(userId); var feed = CreateFeed("All Libraries", $"{apiKey}/libraries", apiKey); @@ -155,7 +168,8 @@ namespace API.Controllers { if (!(await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).EnableOpds) return BadRequest("OPDS is not enabled on this server"); - var user = await GetUser(apiKey); + var userId = await GetUser(apiKey); + var user = await _unitOfWork.UserRepository.GetUserByIdAsync(userId); var isAdmin = await _userManager.IsInRoleAsync(user, PolicyConstants.AdminRole); IEnumerable tags; @@ -190,13 +204,15 @@ namespace API.Controllers return CreateXmlResult(SerializeXml(feed)); } + [HttpGet("{apiKey}/collections/{collectionId}")] [Produces("application/xml")] public async Task GetCollection(int collectionId, string apiKey, [FromQuery] int pageNumber = 0) { if (!(await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).EnableOpds) return BadRequest("OPDS is not enabled on this server"); - var user = await GetUser(apiKey); + var userId = await GetUser(apiKey); + var user = await _unitOfWork.UserRepository.GetUserByIdAsync(userId); var isAdmin = await _userManager.IsInRoleAsync(user, PolicyConstants.AdminRole); IEnumerable tags; @@ -215,7 +231,7 @@ namespace API.Controllers return BadRequest("Collection does not exist or you don't have access"); } - var series = await _unitOfWork.SeriesRepository.GetSeriesDtoForCollectionAsync(collectionId, user.Id, new UserParams() + var series = await _unitOfWork.SeriesRepository.GetSeriesDtoForCollectionAsync(collectionId, userId, new UserParams() { PageNumber = pageNumber, PageSize = 20 @@ -230,6 +246,77 @@ namespace API.Controllers } + return CreateXmlResult(SerializeXml(feed)); + } + + [HttpGet("{apiKey}/reading-list")] + [Produces("application/xml")] + public async Task GetReadingLists(string apiKey, [FromQuery] int pageNumber = 0) + { + if (!(await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).EnableOpds) + return BadRequest("OPDS is not enabled on this server"); + var userId = await GetUser(apiKey); + + var readingLists = await _unitOfWork.ReadingListRepository.GetReadingListDtosForUserAsync(userId, true, new UserParams() + { + PageNumber = pageNumber + }); + + + var feed = CreateFeed("All Reading Lists", $"{apiKey}/reading-list", apiKey); + + foreach (var readingListDto in readingLists) + { + feed.Entries.Add(new FeedEntry() + { + Id = readingListDto.Id.ToString(), + Title = readingListDto.Title, + Summary = readingListDto.Summary, + Links = new List() + { + CreateLink(FeedLinkRelation.SubSection, FeedLinkType.AtomNavigation, Prefix + $"{apiKey}/reading-list/{readingListDto.Id}"), + } + }); + } + + return CreateXmlResult(SerializeXml(feed)); + } + + [HttpGet("{apiKey}/reading-list/{readingListId}")] + [Produces("application/xml")] + public async Task GetReadingListItems(int readingListId, string apiKey) + { + if (!(await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).EnableOpds) + return BadRequest("OPDS is not enabled on this server"); + var userId = await GetUser(apiKey); + var user = await _unitOfWork.UserRepository.GetUserByIdAsync(userId); + + var userWithLists = await _unitOfWork.UserRepository.GetUserWithReadingListsByUsernameAsync(user.UserName); + var readingList = userWithLists.ReadingLists.SingleOrDefault(t => t.Id == readingListId); + if (readingList == null) + { + return BadRequest("Reading list does not exist or you don't have access"); + } + + var feed = CreateFeed(readingList.Title + " Reading List", $"{apiKey}/reading-list/{readingListId}", apiKey); + + var items = await _unitOfWork.ReadingListRepository.GetReadingListItemDtosByIdAsync(readingListId, userId); + foreach (var item in items) + { + feed.Entries.Add(new FeedEntry() + { + Id = item.ChapterId.ToString(), + Title = "Chapter " + item.ChapterNumber, + Links = new List() + { + CreateLink(FeedLinkRelation.SubSection, FeedLinkType.AtomNavigation, Prefix + $"{apiKey}/series/{item.SeriesId}/volume/{item.VolumeId}/chapter/{item.ChapterId}"), + CreateLink(FeedLinkRelation.Image, FeedLinkType.Image, $"/api/image/chapter-cover?chapterId={item.ChapterId}") + } + }); + } + + + return CreateXmlResult(SerializeXml(feed)); } @@ -239,16 +326,16 @@ namespace API.Controllers { if (!(await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).EnableOpds) return BadRequest("OPDS is not enabled on this server"); - var user = await GetUser(apiKey); + var userId = await GetUser(apiKey); var library = - (await _unitOfWork.LibraryRepository.GetLibrariesForUserIdAsync(user.Id)).SingleOrDefault(l => + (await _unitOfWork.LibraryRepository.GetLibrariesForUserIdAsync(userId)).SingleOrDefault(l => l.Id == libraryId); if (library == null) { return BadRequest("User does not have access to this library"); } - var series = await _unitOfWork.SeriesRepository.GetSeriesDtoForLibraryIdAsync(libraryId, user.Id, new UserParams() + var series = await _unitOfWork.SeriesRepository.GetSeriesDtoForLibraryIdAsync(libraryId, userId, new UserParams() { PageNumber = pageNumber, PageSize = 20 @@ -271,8 +358,8 @@ namespace API.Controllers { if (!(await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).EnableOpds) return BadRequest("OPDS is not enabled on this server"); - var user = await GetUser(apiKey); - var recentlyAdded = await _unitOfWork.SeriesRepository.GetRecentlyAdded(0, user.Id, new UserParams() + var userId = await GetUser(apiKey); + var recentlyAdded = await _unitOfWork.SeriesRepository.GetRecentlyAdded(0, userId, new UserParams() { PageNumber = pageNumber, PageSize = 20 @@ -296,13 +383,13 @@ namespace API.Controllers { if (!(await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).EnableOpds) return BadRequest("OPDS is not enabled on this server"); - var user = await GetUser(apiKey); + var userId = await GetUser(apiKey); var userParams = new UserParams() { PageNumber = pageNumber, PageSize = 20 }; - var results = await _unitOfWork.SeriesRepository.GetInProgress(user.Id, 0, userParams, _filterDto); + var results = await _unitOfWork.SeriesRepository.GetInProgress(userId, 0, userParams, _filterDto); var listResults = results.DistinctBy(s => s.Name).Skip((userParams.PageNumber - 1) * userParams.PageSize) .Take(userParams.PageSize).ToList(); var pagedList = new PagedList(listResults, listResults.Count, userParams.PageNumber, userParams.PageSize); @@ -326,14 +413,14 @@ namespace API.Controllers { if (!(await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).EnableOpds) return BadRequest("OPDS is not enabled on this server"); - var user = await GetUser(apiKey); + var userId = await GetUser(apiKey); if (string.IsNullOrEmpty(query)) { return BadRequest("You must pass a query parameter"); } query = query.Replace(@"%", ""); // Get libraries user has access to - var libraries = (await _unitOfWork.LibraryRepository.GetLibrariesForUserIdAsync(user.Id)).ToList(); + var libraries = (await _unitOfWork.LibraryRepository.GetLibrariesForUserIdAsync(userId)).ToList(); if (!libraries.Any()) return BadRequest("User does not have access to any libraries"); @@ -378,9 +465,9 @@ namespace API.Controllers { if (!(await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).EnableOpds) return BadRequest("OPDS is not enabled on this server"); - var user = await GetUser(apiKey); - var series = await _unitOfWork.SeriesRepository.GetSeriesDtoByIdAsync(seriesId, user.Id); - var volumes = await _unitOfWork.SeriesRepository.GetVolumesDtoAsync(seriesId, user.Id); + var userId = await GetUser(apiKey); + var series = await _unitOfWork.SeriesRepository.GetSeriesDtoByIdAsync(seriesId, userId); + var volumes = await _unitOfWork.SeriesRepository.GetVolumesDtoAsync(seriesId, userId); var feed = CreateFeed(series.Name + " - Volumes", $"{apiKey}/series/{series.Id}", apiKey); feed.Links.Add(CreateLink(FeedLinkRelation.Image, FeedLinkType.Image, $"/api/image/series-cover?seriesId={seriesId}")); foreach (var volumeDto in volumes) @@ -397,11 +484,11 @@ namespace API.Controllers { if (!(await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).EnableOpds) return BadRequest("OPDS is not enabled on this server"); - var user = await GetUser(apiKey); - var series = await _unitOfWork.SeriesRepository.GetSeriesDtoByIdAsync(seriesId, user.Id); + var userId = await GetUser(apiKey); + var series = await _unitOfWork.SeriesRepository.GetSeriesDtoByIdAsync(seriesId, userId); var volume = await _unitOfWork.SeriesRepository.GetVolumeAsync(volumeId); var chapters = - (await _unitOfWork.VolumeRepository.GetChaptersAsync(volumeId)).OrderBy(x => double.Parse(x.Number), + (await _unitOfWork.ChapterRepository.GetChaptersAsync(volumeId)).OrderBy(x => double.Parse(x.Number), _chapterSortComparer); var feed = CreateFeed(series.Name + " - Volume " + volume.Name + " - Chapters ", $"{apiKey}/series/{seriesId}/volume/{volumeId}", apiKey); @@ -428,11 +515,11 @@ namespace API.Controllers { if (!(await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).EnableOpds) return BadRequest("OPDS is not enabled on this server"); - var user = await GetUser(apiKey); - var series = await _unitOfWork.SeriesRepository.GetSeriesDtoByIdAsync(seriesId, user.Id); + var userId = await GetUser(apiKey); + var series = await _unitOfWork.SeriesRepository.GetSeriesDtoByIdAsync(seriesId, userId); var volume = await _unitOfWork.SeriesRepository.GetVolumeAsync(volumeId); - var chapter = await _unitOfWork.VolumeRepository.GetChapterDtoAsync(chapterId); - var files = await _unitOfWork.VolumeRepository.GetFilesForChapterAsync(chapterId); + var chapter = await _unitOfWork.ChapterRepository.GetChapterDtoAsync(chapterId); + var files = await _unitOfWork.ChapterRepository.GetFilesForChapterAsync(chapterId); var feed = CreateFeed(series.Name + " - Volume " + volume.Name + " - Chapters ", $"{apiKey}/series/{seriesId}/volume/{volumeId}/chapter/{chapterId}", apiKey); foreach (var mangaFile in files) @@ -456,7 +543,7 @@ namespace API.Controllers { if (!(await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).EnableOpds) return BadRequest("OPDS is not enabled on this server"); - var files = await _unitOfWork.VolumeRepository.GetFilesForChapterAsync(chapterId); + var files = await _unitOfWork.ChapterRepository.GetFilesForChapterAsync(chapterId); var (bytes, contentType, fileDownloadName) = await _downloadService.GetFirstFileDownload(files); return File(bytes, contentType, fileDownloadName); } @@ -544,7 +631,7 @@ namespace API.Controllers return new FeedEntry() { Id = volumeDto.Id.ToString(), - Title = volumeDto.IsSpecial ? "Specials" : "Volume " + volumeDto.Name, + Title = "Volume " + volumeDto.Name, Links = new List() { CreateLink(FeedLinkRelation.SubSection, FeedLinkType.AtomNavigation, Prefix + $"{apiKey}/series/{seriesId}/volume/{volumeDto.Id}"), @@ -639,15 +726,18 @@ namespace API.Controllers /// Gets the user from the API key /// /// - private async Task GetUser(string apiKey) + private async Task GetUser(string apiKey) { - var user = await _unitOfWork.UserRepository.GetUserByApiKeyAsync(apiKey); - if (user == null) + try { - throw new KavitaException("User does not exist"); + var user = await _unitOfWork.UserRepository.GetUserIdByApiKeyAsync(apiKey); + return user; } - - return user; + catch + { + /* Do nothing */ + } + throw new KavitaException("User does not exist"); } private static FeedLink CreatePageStreamLink(int seriesId, int volumeId, int chapterId, MangaFile mangaFile, string apiKey) diff --git a/API/Controllers/PluginController.cs b/API/Controllers/PluginController.cs new file mode 100644 index 000000000..b176c0628 --- /dev/null +++ b/API/Controllers/PluginController.cs @@ -0,0 +1,45 @@ +using System.Threading.Tasks; +using API.DTOs; +using API.Interfaces; +using API.Interfaces.Services; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; + +namespace API.Controllers +{ + public class PluginController : BaseApiController + { + private readonly IUnitOfWork _unitOfWork; + private readonly ITokenService _tokenService; + private readonly ILogger _logger; + + public PluginController(IUnitOfWork unitOfWork, ITokenService tokenService, ILogger logger) + { + _unitOfWork = unitOfWork; + _tokenService = tokenService; + _logger = logger; + } + + /// + /// Authenticate with the Server given an apiKey. This will log you in by returning the user object and the JWT token. + /// + /// + /// Name of the Plugin + /// + [HttpPost("authenticate")] + public async Task> Authenticate(string apiKey, string pluginName) + { + // NOTE: In order to log information about plugins, we need some Plugin Description information for each request + // Should log into access table so we can tell the user + var userId = await _unitOfWork.UserRepository.GetUserIdByApiKeyAsync(apiKey); + var user = await _unitOfWork.UserRepository.GetUserByIdAsync(userId); + _logger.LogInformation("Plugin {PluginName} has authenticated with {UserName} ({UserId})'s API Key", pluginName, user.UserName, userId); + return new UserDto + { + Username = user.UserName, + Token = await _tokenService.CreateToken(user), + ApiKey = user.ApiKey, + }; + } + } +} diff --git a/API/Controllers/ReaderController.cs b/API/Controllers/ReaderController.cs index 9b112e5da..d1314674e 100644 --- a/API/Controllers/ReaderController.cs +++ b/API/Controllers/ReaderController.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; -using API.Comparators; +using API.Data.Repositories; using API.DTOs; using API.DTOs.Reader; using API.Entities; @@ -20,20 +20,15 @@ namespace API.Controllers /// public class ReaderController : BaseApiController { - private readonly IDirectoryService _directoryService; private readonly ICacheService _cacheService; private readonly IUnitOfWork _unitOfWork; private readonly ILogger _logger; private readonly IReaderService _readerService; - private readonly ChapterSortComparer _chapterSortComparer = new ChapterSortComparer(); - private readonly ChapterSortComparerZeroFirst _chapterSortComparerForInChapterSorting = new ChapterSortComparerZeroFirst(); - private readonly NaturalSortComparer _naturalSortComparer = new NaturalSortComparer(); /// - public ReaderController(IDirectoryService directoryService, ICacheService cacheService, + public ReaderController(ICacheService cacheService, IUnitOfWork unitOfWork, ILogger logger, IReaderService readerService) { - _directoryService = directoryService; _cacheService = cacheService; _unitOfWork = unitOfWork; _logger = logger; @@ -49,7 +44,7 @@ namespace API.Controllers [HttpGet("image")] public async Task GetImage(int chapterId, int page) { - if (page < 0) return BadRequest("Page cannot be less than 0"); + if (page < 0) page = 0; var chapter = await _cacheService.Ensure(chapterId); if (chapter == null) return BadRequest("There was an issue finding image file for reading"); @@ -57,14 +52,9 @@ namespace API.Controllers { var (path, _) = await _cacheService.GetCachedPagePath(chapter, page); if (string.IsNullOrEmpty(path) || !System.IO.File.Exists(path)) return BadRequest($"No such image for page {page}"); - - var content = await _directoryService.ReadFileAsync(path); var format = Path.GetExtension(path).Replace(".", ""); - // Calculates SHA1 Hash for byte[] - Response.AddCacheHeader(content); - - return File(content, "image/" + format); + return PhysicalFile(path, "image/" + format, Path.GetFileName(path)); } catch (Exception) { @@ -76,30 +66,29 @@ namespace API.Controllers /// /// Returns various information about a Chapter. Side effect: This will cache the chapter images for reading. /// - /// /// /// [HttpGet("chapter-info")] - public async Task> GetChapterInfo(int seriesId, int chapterId) + public async Task> GetChapterInfo(int chapterId) { - // PERF: Write this in one DB call var chapter = await _cacheService.Ensure(chapterId); if (chapter == null) return BadRequest("Could not find Chapter"); - var volume = await _unitOfWork.SeriesRepository.GetVolumeDtoAsync(chapter.VolumeId); - if (volume == null) return BadRequest("Could not find Volume"); - var mangaFile = (await _unitOfWork.VolumeRepository.GetFilesForChapterAsync(chapterId)).First(); - var series = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(seriesId); + var dto = await _unitOfWork.ChapterRepository.GetChapterInfoDtoAsync(chapterId); + var mangaFile = (await _unitOfWork.ChapterRepository.GetFilesForChapterAsync(chapterId)).First(); return Ok(new ChapterInfoDto() { - ChapterNumber = chapter.Range, - VolumeNumber = volume.Number + string.Empty, - VolumeId = volume.Id, + ChapterNumber = dto.ChapterNumber, + VolumeNumber = dto.VolumeNumber, + VolumeId = dto.VolumeId, FileName = Path.GetFileName(mangaFile.FilePath), - SeriesName = series?.Name, - IsSpecial = chapter.IsSpecial, - Pages = chapter.Pages, + SeriesName = dto.SeriesName, + SeriesFormat = dto.SeriesFormat, + SeriesId = dto.SeriesId, + LibraryId = dto.LibraryId, + IsSpecial = dto.IsSpecial, + Pages = dto.Pages, }); } @@ -107,32 +96,12 @@ namespace API.Controllers [HttpPost("mark-read")] public async Task MarkRead(MarkReadDto markReadDto) { - var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername()); + var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Progress); var volumes = await _unitOfWork.SeriesRepository.GetVolumes(markReadDto.SeriesId); user.Progresses ??= new List(); foreach (var volume in volumes) { - foreach (var chapter in volume.Chapters) - { - var userProgress = GetUserProgressForChapter(user, chapter); - - if (userProgress == null) - { - user.Progresses.Add(new AppUserProgress - { - PagesRead = chapter.Pages, - VolumeId = volume.Id, - SeriesId = markReadDto.SeriesId, - ChapterId = chapter.Id - }); - } - else - { - userProgress.PagesRead = chapter.Pages; - userProgress.SeriesId = markReadDto.SeriesId; - userProgress.VolumeId = volume.Id; - } - } + _readerService.MarkChaptersAsRead(user, markReadDto.SeriesId, volume.Chapters); } _unitOfWork.UserRepository.Update(user); @@ -146,47 +115,23 @@ namespace API.Controllers return BadRequest("There was an issue saving progress"); } - private static AppUserProgress GetUserProgressForChapter(AppUser user, Chapter chapter) - { - AppUserProgress userProgress = null; - try - { - userProgress = - user.Progresses.SingleOrDefault(x => x.ChapterId == chapter.Id && x.AppUserId == user.Id); - } - catch (Exception) - { - // There is a very rare chance that user progress will duplicate current row. If that happens delete one with less pages - var progresses = user.Progresses.Where(x => x.ChapterId == chapter.Id && x.AppUserId == user.Id).ToList(); - if (progresses.Count > 1) - { - user.Progresses = new List() - { - user.Progresses.First() - }; - userProgress = user.Progresses.First(); - } - } - - return userProgress; - } /// - /// Marks a Chapter as Unread (progress) + /// Marks a Series as Unread (progress) /// /// /// [HttpPost("mark-unread")] public async Task MarkUnread(MarkReadDto markReadDto) { - var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername()); + var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Progress); var volumes = await _unitOfWork.SeriesRepository.GetVolumes(markReadDto.SeriesId); user.Progresses ??= new List(); foreach (var volume in volumes) { foreach (var chapter in volume.Chapters) { - var userProgress = GetUserProgressForChapter(user, chapter); + var userProgress = ReaderService.GetUserProgressForChapter(user, chapter); if (userProgress == null) continue; userProgress.PagesRead = 0; @@ -206,6 +151,29 @@ namespace API.Controllers return BadRequest("There was an issue saving progress"); } + /// + /// Marks all chapters within a volume as unread + /// + /// + /// + [HttpPost("mark-volume-unread")] + public async Task MarkVolumeAsUnread(MarkVolumeReadDto markVolumeReadDto) + { + var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Progress); + + var chapters = await _unitOfWork.ChapterRepository.GetChaptersAsync(markVolumeReadDto.VolumeId); + _readerService.MarkChaptersAsUnread(user, markVolumeReadDto.SeriesId, chapters); + + _unitOfWork.UserRepository.Update(user); + + if (await _unitOfWork.CommitAsync()) + { + return Ok(); + } + + return BadRequest("Could not save progress"); + } + /// /// Marks all chapters within a volume as Read /// @@ -214,30 +182,122 @@ namespace API.Controllers [HttpPost("mark-volume-read")] public async Task MarkVolumeAsRead(MarkVolumeReadDto markVolumeReadDto) { - var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername()); + var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Progress); - var chapters = await _unitOfWork.VolumeRepository.GetChaptersAsync(markVolumeReadDto.VolumeId); - foreach (var chapter in chapters) + var chapters = await _unitOfWork.ChapterRepository.GetChaptersAsync(markVolumeReadDto.VolumeId); + _readerService.MarkChaptersAsRead(user, markVolumeReadDto.SeriesId, chapters); + + _unitOfWork.UserRepository.Update(user); + + if (await _unitOfWork.CommitAsync()) { - user.Progresses ??= new List(); - var userProgress = user.Progresses.FirstOrDefault(x => x.ChapterId == chapter.Id && x.AppUserId == user.Id); + return Ok(); + } - if (userProgress == null) - { - user.Progresses.Add(new AppUserProgress - { - PagesRead = chapter.Pages, - VolumeId = markVolumeReadDto.VolumeId, - SeriesId = markVolumeReadDto.SeriesId, - ChapterId = chapter.Id - }); - } - else - { - userProgress.PagesRead = chapter.Pages; - userProgress.SeriesId = markVolumeReadDto.SeriesId; - userProgress.VolumeId = markVolumeReadDto.VolumeId; - } + return BadRequest("Could not save progress"); + } + + + /// + /// Marks all chapters within a list of volumes as Read. All volumes must belong to the same Series. + /// + /// + /// + [HttpPost("mark-multiple-read")] + public async Task MarkMultipleAsRead(MarkVolumesReadDto dto) + { + var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Progress); + user.Progresses ??= new List(); + + var chapterIds = await _unitOfWork.VolumeRepository.GetChapterIdsByVolumeIds(dto.VolumeIds); + foreach (var chapterId in dto.ChapterIds) + { + chapterIds.Add(chapterId); + } + var chapters = await _unitOfWork.ChapterRepository.GetChaptersByIdsAsync(chapterIds); + _readerService.MarkChaptersAsRead(user, dto.SeriesId, chapters); + + _unitOfWork.UserRepository.Update(user); + + if (await _unitOfWork.CommitAsync()) + { + return Ok(); + } + + return BadRequest("Could not save progress"); + } + + /// + /// Marks all chapters within a list of volumes as Unread. All volumes must belong to the same Series. + /// + /// + /// + [HttpPost("mark-multiple-unread")] + public async Task MarkMultipleAsUnread(MarkVolumesReadDto dto) + { + var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Progress); + user.Progresses ??= new List(); + + var chapterIds = await _unitOfWork.VolumeRepository.GetChapterIdsByVolumeIds(dto.VolumeIds); + foreach (var chapterId in dto.ChapterIds) + { + chapterIds.Add(chapterId); + } + var chapters = await _unitOfWork.ChapterRepository.GetChaptersByIdsAsync(chapterIds); + _readerService.MarkChaptersAsUnread(user, dto.SeriesId, chapters); + + _unitOfWork.UserRepository.Update(user); + + if (await _unitOfWork.CommitAsync()) + { + return Ok(); + } + + return BadRequest("Could not save progress"); + } + + /// + /// Marks all chapters within a list of series as Read. + /// + /// + /// + [HttpPost("mark-multiple-series-read")] + public async Task MarkMultipleSeriesAsRead(MarkMultipleSeriesAsReadDto dto) + { + var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Progress); + user.Progresses ??= new List(); + + var volumes = await _unitOfWork.SeriesRepository.GetVolumesForSeriesAsync(dto.SeriesIds.ToArray(), true); + foreach (var volume in volumes) + { + _readerService.MarkChaptersAsRead(user, volume.SeriesId, volume.Chapters); + } + + _unitOfWork.UserRepository.Update(user); + + if (await _unitOfWork.CommitAsync()) + { + return Ok(); + } + + return BadRequest("Could not save progress"); + } + + /// + /// Marks all chapters within a list of series as Unread. + /// + /// + /// + [HttpPost("mark-multiple-series-unread")] + public async Task MarkMultipleSeriesAsUnread(MarkMultipleSeriesAsReadDto dto) + { + var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Progress); + user.Progresses ??= new List(); + + var volumes = await _unitOfWork.SeriesRepository.GetVolumesForSeriesAsync(dto.SeriesIds.ToArray(), true); + foreach (var volume in volumes) + { + _readerService.MarkChaptersAsUnread(user, volume.SeriesId, volume.Chapters); } _unitOfWork.UserRepository.Update(user); @@ -258,7 +318,7 @@ namespace API.Controllers [HttpGet("get-progress")] public async Task> GetProgress(int chapterId) { - var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername()); + var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Progress); var progressBookmark = new ProgressDto() { PageNum = 0, @@ -267,7 +327,7 @@ namespace API.Controllers SeriesId = 0 }; if (user.Progresses == null) return Ok(progressBookmark); - var progress = user.Progresses.SingleOrDefault(x => x.AppUserId == user.Id && x.ChapterId == chapterId); + var progress = user.Progresses.FirstOrDefault(x => x.AppUserId == user.Id && x.ChapterId == chapterId); if (progress != null) { @@ -288,7 +348,8 @@ namespace API.Controllers public async Task BookmarkProgress(ProgressDto progressDto) { var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername()); - if (await _readerService.SaveReadingProgress(progressDto, user)) return Ok(true); + + if (await _readerService.SaveReadingProgress(progressDto, user.Id)) return Ok(true); return BadRequest("Could not save progress"); } @@ -301,7 +362,7 @@ namespace API.Controllers [HttpGet("get-bookmarks")] public async Task>> GetBookmarks(int chapterId) { - var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername()); + var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Bookmarks); if (user.Bookmarks == null) return Ok(Array.Empty()); return Ok(await _unitOfWork.UserRepository.GetBookmarkDtosForChapter(user.Id, chapterId)); } @@ -313,7 +374,7 @@ namespace API.Controllers [HttpGet("get-all-bookmarks")] public async Task>> GetAllBookmarks() { - var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername()); + var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Bookmarks); if (user.Bookmarks == null) return Ok(Array.Empty()); return Ok(await _unitOfWork.UserRepository.GetAllBookmarkDtos(user.Id)); } @@ -326,7 +387,7 @@ namespace API.Controllers [HttpPost("remove-bookmarks")] public async Task RemoveBookmarks(RemoveBookmarkForSeriesDto dto) { - var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername()); + var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Bookmarks); if (user.Bookmarks == null) return Ok("Nothing to remove"); try { @@ -356,7 +417,7 @@ namespace API.Controllers [HttpGet("get-volume-bookmarks")] public async Task>> GetBookmarksForVolume(int volumeId) { - var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername()); + var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Bookmarks); if (user.Bookmarks == null) return Ok(Array.Empty()); return Ok(await _unitOfWork.UserRepository.GetBookmarkDtosForVolume(user.Id, volumeId)); } @@ -369,7 +430,7 @@ namespace API.Controllers [HttpGet("get-series-bookmarks")] public async Task>> GetBookmarksForSeries(int seriesId) { - var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername()); + var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Bookmarks); if (user.Bookmarks == null) return Ok(Array.Empty()); return Ok(await _unitOfWork.UserRepository.GetBookmarkDtosForSeries(user.Id, seriesId)); @@ -383,45 +444,28 @@ namespace API.Controllers [HttpPost("bookmark")] public async Task BookmarkPage(BookmarkDto bookmarkDto) { - var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername()); - // Don't let user save past total pages. - var chapter = await _unitOfWork.VolumeRepository.GetChapterAsync(bookmarkDto.ChapterId); - if (bookmarkDto.Page > chapter.Pages) - { - bookmarkDto.Page = chapter.Pages; - } - - if (bookmarkDto.Page < 0) - { - bookmarkDto.Page = 0; - } - + bookmarkDto.Page = await _readerService.CapPageToChapter(bookmarkDto.ChapterId, bookmarkDto.Page); try { - user.Bookmarks ??= new List(); - var userBookmark = - user.Bookmarks.SingleOrDefault(x => x.ChapterId == bookmarkDto.ChapterId && x.AppUserId == user.Id && x.Page == bookmarkDto.Page); + var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Bookmarks); + var userBookmark = + await _unitOfWork.UserRepository.GetBookmarkForPage(bookmarkDto.Page, bookmarkDto.ChapterId, user.Id); if (userBookmark == null) { - user.Bookmarks.Add(new AppUserBookmark() - { - Page = bookmarkDto.Page, - VolumeId = bookmarkDto.VolumeId, - SeriesId = bookmarkDto.SeriesId, - ChapterId = bookmarkDto.ChapterId, - }); - } - else - { - userBookmark.Page = bookmarkDto.Page; - userBookmark.SeriesId = bookmarkDto.SeriesId; - userBookmark.VolumeId = bookmarkDto.VolumeId; + user.Bookmarks ??= new List(); + user.Bookmarks.Add(new AppUserBookmark() + { + Page = bookmarkDto.Page, + VolumeId = bookmarkDto.VolumeId, + SeriesId = bookmarkDto.SeriesId, + ChapterId = bookmarkDto.ChapterId, + }); + _unitOfWork.UserRepository.Update(user); } - _unitOfWork.UserRepository.Update(user); if (await _unitOfWork.CommitAsync()) { @@ -444,7 +488,7 @@ namespace API.Controllers [HttpPost("unbookmark")] public async Task UnBookmarkPage(BookmarkDto bookmarkDto) { - var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername()); + var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Bookmarks); if (user.Bookmarks == null) return Ok(); try { @@ -453,7 +497,6 @@ namespace API.Controllers && x.AppUserId == user.Id && x.Page != bookmarkDto.Page).ToList(); - _unitOfWork.UserRepository.Update(user); if (await _unitOfWork.CommitAsync()) @@ -482,58 +525,10 @@ namespace API.Controllers [HttpGet("next-chapter")] public async Task> GetNextChapter(int seriesId, int volumeId, int currentChapterId) { - var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername()); - var volumes = await _unitOfWork.SeriesRepository.GetVolumesDtoAsync(seriesId, user.Id); - var currentVolume = await _unitOfWork.SeriesRepository.GetVolumeAsync(volumeId); - var currentChapter = await _unitOfWork.VolumeRepository.GetChapterAsync(currentChapterId); - if (currentVolume.Number == 0) - { - // Handle specials by sorting on their Filename aka Range - var chapterId = GetNextChapterId(currentVolume.Chapters.OrderBy(x => x.Range, _naturalSortComparer), currentChapter.Number); - if (chapterId > 0) return Ok(chapterId); - } - - foreach (var volume in volumes) - { - if (volume.Number == currentVolume.Number && volume.Chapters.Count > 1) - { - // Handle Chapters within current Volume - // In this case, i need 0 first because 0 represents a full volume file. - var chapterId = GetNextChapterId(currentVolume.Chapters.OrderBy(x => double.Parse(x.Number), _chapterSortComparerForInChapterSorting), currentChapter.Number); - if (chapterId > 0) return Ok(chapterId); - } - - if (volume.Number == currentVolume.Number + 1) - { - // Handle Chapters within next Volume - // ! When selecting the chapter for the next volume, we need to make sure a c0 comes before a c1+ - var chapters = volume.Chapters.OrderBy(x => double.Parse(x.Number), _chapterSortComparer).ToList(); - if (currentChapter.Number.Equals("0") && chapters.Last().Number.Equals("0")) - { - return chapters.Last().Id; - } - - return Ok(chapters.FirstOrDefault()?.Id); - } - } - return Ok(-1); + var userId = await _unitOfWork.UserRepository.GetUserIdByUsernameAsync(User.GetUsername()); + return await _readerService.GetNextChapterIdAsync(seriesId, volumeId, currentChapterId, userId); } - private static int GetNextChapterId(IEnumerable chapters, string currentChapterNumber) - { - var next = false; - var chaptersList = chapters.ToList(); - foreach (var chapter in chaptersList) - { - if (next) - { - return chapter.Id; - } - if (currentChapterNumber.Equals(chapter.Number)) next = true; - } - - return -1; - } /// /// Returns the previous logical chapter from the series. @@ -548,30 +543,8 @@ namespace API.Controllers [HttpGet("prev-chapter")] public async Task> GetPreviousChapter(int seriesId, int volumeId, int currentChapterId) { - var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername()); - var volumes = await _unitOfWork.SeriesRepository.GetVolumesDtoAsync(seriesId, user.Id); - var currentVolume = await _unitOfWork.SeriesRepository.GetVolumeAsync(volumeId); - var currentChapter = await _unitOfWork.VolumeRepository.GetChapterAsync(currentChapterId); - - if (currentVolume.Number == 0) - { - var chapterId = GetNextChapterId(currentVolume.Chapters.OrderBy(x => x.Range, _naturalSortComparer).Reverse(), currentChapter.Number); - if (chapterId > 0) return Ok(chapterId); - } - - foreach (var volume in volumes.Reverse()) - { - if (volume.Number == currentVolume.Number) - { - var chapterId = GetNextChapterId(currentVolume.Chapters.OrderBy(x => double.Parse(x.Number), _chapterSortComparerForInChapterSorting).Reverse(), currentChapter.Number); - if (chapterId > 0) return Ok(chapterId); - } - if (volume.Number == currentVolume.Number - 1) - { - return Ok(volume.Chapters.OrderBy(x => double.Parse(x.Number), _chapterSortComparerForInChapterSorting).LastOrDefault()?.Id); - } - } - return Ok(-1); + var userId = await _unitOfWork.UserRepository.GetUserIdByUsernameAsync(User.GetUsername()); + return await _readerService.GetPrevChapterIdAsync(seriesId, volumeId, currentChapterId, userId); } } diff --git a/API/Controllers/ReadingListController.cs b/API/Controllers/ReadingListController.cs new file mode 100644 index 000000000..1f22263c7 --- /dev/null +++ b/API/Controllers/ReadingListController.cs @@ -0,0 +1,503 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using API.Comparators; +using API.DTOs.ReadingLists; +using API.Entities; +using API.Extensions; +using API.Helpers; +using API.Interfaces; +using Microsoft.AspNetCore.Mvc; + +namespace API.Controllers +{ + public class ReadingListController : BaseApiController + { + private readonly IUnitOfWork _unitOfWork; + private readonly ChapterSortComparerZeroFirst _chapterSortComparerForInChapterSorting = new ChapterSortComparerZeroFirst(); + + public ReadingListController(IUnitOfWork unitOfWork) + { + _unitOfWork = unitOfWork; + } + + /// + /// Fetches a single Reading List + /// + /// + /// + [HttpGet] + public async Task>> GetList(int readingListId) + { + var userId = await _unitOfWork.UserRepository.GetUserIdByUsernameAsync(User.GetUsername()); + return Ok(await _unitOfWork.ReadingListRepository.GetReadingListDtoByIdAsync(readingListId, userId)); + } + + /// + /// Returns reading lists (paginated) for a given user. + /// + /// Defaults to true + /// + [HttpPost("lists")] + public async Task>> GetListsForUser([FromQuery] UserParams userParams, [FromQuery] bool includePromoted = true) + { + var userId = await _unitOfWork.UserRepository.GetUserIdByUsernameAsync(User.GetUsername()); + var items = await _unitOfWork.ReadingListRepository.GetReadingListDtosForUserAsync(userId, includePromoted, + userParams); + Response.AddPaginationHeader(items.CurrentPage, items.PageSize, items.TotalCount, items.TotalPages); + + return Ok(items); + } + + /// + /// Fetches all reading list items for a given list including rich metadata around series, volume, chapters, and progress + /// + /// This call is expensive + /// + /// + [HttpGet("items")] + public async Task>> GetListForUser(int readingListId) + { + var userId = await _unitOfWork.UserRepository.GetUserIdByUsernameAsync(User.GetUsername()); + var items = await _unitOfWork.ReadingListRepository.GetReadingListItemDtosByIdAsync(readingListId, userId); + + return Ok(await _unitOfWork.ReadingListRepository.AddReadingProgressModifiers(userId, items.ToList())); + } + + /// + /// Updates an items position + /// + /// + /// + [HttpPost("update-position")] + public async Task UpdateListItemPosition(UpdateReadingListPosition dto) + { + // Make sure UI buffers events + var items = (await _unitOfWork.ReadingListRepository.GetReadingListItemsByIdAsync(dto.ReadingListId)).ToList(); + var item = items.Find(r => r.Id == dto.ReadingListItemId); + items.Remove(item); + items.Insert(dto.ToPosition, item); + + for (var i = 0; i < items.Count; i++) + { + items[i].Order = i; + } + + if (_unitOfWork.HasChanges() && await _unitOfWork.CommitAsync()) + { + return Ok("Updated"); + } + + return BadRequest("Couldn't update position"); + } + + /// + /// Deletes a list item from the list. Will reorder all item positions afterwards + /// + /// + /// + [HttpPost("delete-item")] + public async Task DeleteListItem(UpdateReadingListPosition dto) + { + var items = (await _unitOfWork.ReadingListRepository.GetReadingListItemsByIdAsync(dto.ReadingListId)).ToList(); + var item = items.Find(r => r.Id == dto.ReadingListItemId); + items.Remove(item); + + for (var i = 0; i < items.Count; i++) + { + items[i].Order = i; + } + + if (_unitOfWork.HasChanges() && await _unitOfWork.CommitAsync()) + { + return Ok("Updated"); + } + + return BadRequest("Couldn't delete item"); + } + + /// + /// Removes all entries that are fully read from the reading list + /// + /// + /// + [HttpPost("remove-read")] + public async Task DeleteReadFromList([FromQuery] int readingListId) + { + var userId = await _unitOfWork.UserRepository.GetUserIdByUsernameAsync(User.GetUsername()); + var items = await _unitOfWork.ReadingListRepository.GetReadingListItemDtosByIdAsync(readingListId, userId); + items = await _unitOfWork.ReadingListRepository.AddReadingProgressModifiers(userId, items.ToList()); + + // Collect all Ids to remove + var itemIdsToRemove = items.Where(item => item.PagesRead == item.PagesTotal).Select(item => item.Id); + + try + { + var listItems = + (await _unitOfWork.ReadingListRepository.GetReadingListItemsByIdAsync(readingListId)).Where(r => + itemIdsToRemove.Contains(r.Id)); + _unitOfWork.ReadingListRepository.BulkRemove(listItems); + + if (_unitOfWork.HasChanges()) + { + await _unitOfWork.CommitAsync(); + return Ok("Updated"); + } + else + { + return Ok("Nothing to remove"); + } + } + catch + { + await _unitOfWork.RollbackAsync(); + } + + return BadRequest("Could not remove read items"); + } + + /// + /// Deletes a reading list + /// + /// + /// + [HttpDelete] + public async Task DeleteList([FromQuery] int readingListId) + { + var user = await _unitOfWork.UserRepository.GetUserWithReadingListsByUsernameAsync(User.GetUsername()); + var readingList = user.ReadingLists.SingleOrDefault(r => r.Id == readingListId); + if (readingList == null) + { + return BadRequest("User is not associated with this reading list"); + } + + user.ReadingLists.Remove(readingList); + + if (_unitOfWork.HasChanges() && await _unitOfWork.CommitAsync()) + { + return Ok("Deleted"); + } + + return BadRequest("There was an issue deleting reading list"); + } + + /// + /// Creates a new List with a unique title. Returns the new ReadingList back + /// + /// + /// + [HttpPost("create")] + public async Task> CreateList(CreateReadingListDto dto) + { + var user = await _unitOfWork.UserRepository.GetUserWithReadingListsByUsernameAsync(User.GetUsername()); + + // When creating, we need to make sure Title is unique + var hasExisting = user.ReadingLists.Any(l => l.Title.Equals(dto.Title)); + if (hasExisting) + { + return BadRequest("A list of this name already exists"); + } + user.ReadingLists.Add(new ReadingList() + { + Promoted = false, + Title = dto.Title, + Summary = string.Empty + }); + + if (!_unitOfWork.HasChanges()) return BadRequest("There was a problem creating list"); + + await _unitOfWork.CommitAsync(); + + return Ok(await _unitOfWork.ReadingListRepository.GetReadingListDtoByTitleAsync(dto.Title)); + } + + /// + /// Update the properites (title, summary) of a reading list + /// + /// + /// + [HttpPost("update")] + public async Task UpdateList(UpdateReadingListDto dto) + { + var readingList = await _unitOfWork.ReadingListRepository.GetReadingListByIdAsync(dto.ReadingListId); + if (readingList == null) return BadRequest("List does not exist"); + + if (!string.IsNullOrEmpty(dto.Title)) + { + readingList.Title = dto.Title; // Should I check if this is unique? + } + if (!string.IsNullOrEmpty(dto.Title)) + { + readingList.Summary = dto.Summary; + } + + readingList.Promoted = dto.Promoted; + + _unitOfWork.ReadingListRepository.Update(readingList); + + if (await _unitOfWork.CommitAsync()) + { + return Ok("Updated"); + } + return BadRequest("Could not update reading list"); + } + + /// + /// Adds all chapters from a Series to a reading list + /// + /// + /// + [HttpPost("update-by-series")] + public async Task UpdateListBySeries(UpdateReadingListBySeriesDto dto) + { + var user = await _unitOfWork.UserRepository.GetUserWithReadingListsByUsernameAsync(User.GetUsername()); + var readingList = user.ReadingLists.SingleOrDefault(l => l.Id == dto.ReadingListId); + if (readingList == null) return BadRequest("Reading List does not exist"); + var chapterIdsForSeries = + await _unitOfWork.SeriesRepository.GetChapterIdsForSeriesAsync(new [] {dto.SeriesId}); + + // If there are adds, tell tracking this has been modified + if (await AddChaptersToReadingList(dto.SeriesId, chapterIdsForSeries, readingList)) + { + _unitOfWork.ReadingListRepository.Update(readingList); + } + + try + { + if (_unitOfWork.HasChanges()) + { + await _unitOfWork.CommitAsync(); + return Ok("Updated"); + } + } + catch + { + await _unitOfWork.RollbackAsync(); + } + + return Ok("Nothing to do"); + } + + + /// + /// Adds all chapters from a list of volumes and chapters to a reading list + /// + /// + /// + [HttpPost("update-by-multiple")] + public async Task UpdateListByMultiple(UpdateReadingListByMultipleDto dto) + { + var user = await _unitOfWork.UserRepository.GetUserWithReadingListsByUsernameAsync(User.GetUsername()); + var readingList = user.ReadingLists.SingleOrDefault(l => l.Id == dto.ReadingListId); + if (readingList == null) return BadRequest("Reading List does not exist"); + + var chapterIds = await _unitOfWork.VolumeRepository.GetChapterIdsByVolumeIds(dto.VolumeIds); + foreach (var chapterId in dto.ChapterIds) + { + chapterIds.Add(chapterId); + } + + // If there are adds, tell tracking this has been modified + if (await AddChaptersToReadingList(dto.SeriesId, chapterIds, readingList)) + { + _unitOfWork.ReadingListRepository.Update(readingList); + } + + try + { + if (_unitOfWork.HasChanges()) + { + await _unitOfWork.CommitAsync(); + return Ok("Updated"); + } + } + catch + { + await _unitOfWork.RollbackAsync(); + } + + return Ok("Nothing to do"); + } + + /// + /// Adds all chapters from a list of series to a reading list + /// + /// + /// + [HttpPost("update-by-multiple-series")] + public async Task UpdateListByMultipleSeries(UpdateReadingListByMultipleSeriesDto dto) + { + var user = await _unitOfWork.UserRepository.GetUserWithReadingListsByUsernameAsync(User.GetUsername()); + var readingList = user.ReadingLists.SingleOrDefault(l => l.Id == dto.ReadingListId); + if (readingList == null) return BadRequest("Reading List does not exist"); + + var ids = await _unitOfWork.SeriesRepository.GetChapterIdWithSeriesIdForSeriesAsync(dto.SeriesIds.ToArray()); + + foreach (var seriesId in ids.Keys) + { + // If there are adds, tell tracking this has been modified + if (await AddChaptersToReadingList(seriesId, ids[seriesId], readingList)) + { + _unitOfWork.ReadingListRepository.Update(readingList); + } + } + + try + { + if (_unitOfWork.HasChanges()) + { + await _unitOfWork.CommitAsync(); + return Ok("Updated"); + } + } + catch + { + await _unitOfWork.RollbackAsync(); + } + + return Ok("Nothing to do"); + } + + [HttpPost("update-by-volume")] + public async Task UpdateListByVolume(UpdateReadingListByVolumeDto dto) + { + var user = await _unitOfWork.UserRepository.GetUserWithReadingListsByUsernameAsync(User.GetUsername()); + var readingList = user.ReadingLists.SingleOrDefault(l => l.Id == dto.ReadingListId); + if (readingList == null) return BadRequest("Reading List does not exist"); + var chapterIdsForVolume = + (await _unitOfWork.ChapterRepository.GetChaptersAsync(dto.VolumeId)).Select(c => c.Id).ToList(); + + // If there are adds, tell tracking this has been modified + if (await AddChaptersToReadingList(dto.SeriesId, chapterIdsForVolume, readingList)) + { + _unitOfWork.ReadingListRepository.Update(readingList); + } + + try + { + if (_unitOfWork.HasChanges()) + { + await _unitOfWork.CommitAsync(); + return Ok("Updated"); + } + } + catch + { + await _unitOfWork.RollbackAsync(); + } + + return Ok("Nothing to do"); + } + + [HttpPost("update-by-chapter")] + public async Task UpdateListByChapter(UpdateReadingListByChapterDto dto) + { + var user = await _unitOfWork.UserRepository.GetUserWithReadingListsByUsernameAsync(User.GetUsername()); + var readingList = user.ReadingLists.SingleOrDefault(l => l.Id == dto.ReadingListId); + if (readingList == null) return BadRequest("Reading List does not exist"); + + // If there are adds, tell tracking this has been modified + if (await AddChaptersToReadingList(dto.SeriesId, new List() { dto.ChapterId }, readingList)) + { + _unitOfWork.ReadingListRepository.Update(readingList); + } + + try + { + if (_unitOfWork.HasChanges()) + { + await _unitOfWork.CommitAsync(); + return Ok("Updated"); + } + } + catch + { + await _unitOfWork.RollbackAsync(); + } + + return Ok("Nothing to do"); + } + + /// + /// Adds a list of Chapters as reading list items to the passed reading list. + /// + /// + /// + /// + /// True if new chapters were added + private async Task AddChaptersToReadingList(int seriesId, IList chapterIds, + ReadingList readingList) + { + readingList.Items ??= new List(); + var lastOrder = 0; + if (readingList.Items.Any()) + { + lastOrder = readingList.Items.DefaultIfEmpty().Max(rli => rli.Order); + } + + var existingChapterExists = readingList.Items.Select(rli => rli.ChapterId).ToHashSet(); + var chaptersForSeries = (await _unitOfWork.ChapterRepository.GetChaptersByIdsAsync(chapterIds)) + .OrderBy(c => int.Parse(c.Volume.Name)) + .ThenBy(x => double.Parse(x.Number), _chapterSortComparerForInChapterSorting); + + var index = lastOrder + 1; + foreach (var chapter in chaptersForSeries) + { + if (existingChapterExists.Contains(chapter.Id)) continue; + + readingList.Items.Add(new ReadingListItem() + { + Order = index, + ChapterId = chapter.Id, + SeriesId = seriesId, + VolumeId = chapter.VolumeId + }); + index += 1; + } + + return index > lastOrder + 1; + } + + /// + /// Returns the next chapter within the reading list + /// + /// + /// + /// Chapter Id for next item, -1 if nothing exists + [HttpGet("next-chapter")] + public async Task> GetNextChapter(int currentChapterId, int readingListId) + { + var items = (await _unitOfWork.ReadingListRepository.GetReadingListItemsByIdAsync(readingListId)).ToList(); + var readingListItem = items.SingleOrDefault(rl => rl.ChapterId == currentChapterId); + if (readingListItem == null) return BadRequest("Id does not exist"); + var index = items.IndexOf(readingListItem) + 1; + if (items.Count > index) + { + return items[index].ChapterId; + } + + return Ok(-1); + } + + /// + /// Returns the prev chapter within the reading list + /// + /// + /// + /// Chapter Id for next item, -1 if nothing exists + [HttpGet("prev-chapter")] + public async Task> GetPrevChapter(int currentChapterId, int readingListId) + { + var items = (await _unitOfWork.ReadingListRepository.GetReadingListItemsByIdAsync(readingListId)).ToList(); + var readingListItem = items.SingleOrDefault(rl => rl.ChapterId == currentChapterId); + if (readingListItem == null) return BadRequest("Id does not exist"); + var index = items.IndexOf(readingListItem) - 1; + if (0 <= index) + { + return items[index].ChapterId; + } + + return Ok(-1); + } + } +} diff --git a/API/Controllers/SeriesController.cs b/API/Controllers/SeriesController.cs index cce70de6d..ff0fa7587 100644 --- a/API/Controllers/SeriesController.cs +++ b/API/Controllers/SeriesController.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using API.Data; +using API.Data.Repositories; using API.DTOs; using API.DTOs.Filtering; using API.Entities; @@ -32,14 +33,14 @@ namespace API.Controllers [HttpPost] public async Task>> GetSeriesForLibrary(int libraryId, [FromQuery] UserParams userParams, [FromBody] FilterDto filterDto) { - var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername()); + var userId = await _unitOfWork.UserRepository.GetUserIdByUsernameAsync(User.GetUsername()); var series = - await _unitOfWork.SeriesRepository.GetSeriesDtoForLibraryIdAsync(libraryId, user.Id, userParams, filterDto); + await _unitOfWork.SeriesRepository.GetSeriesDtoForLibraryIdAsync(libraryId, userId, userParams, filterDto); // Apply progress/rating information (I can't work out how to do this in initial query) if (series == null) return BadRequest("Could not get series for library"); - await _unitOfWork.SeriesRepository.AddSeriesModifiers(user.Id, series); + await _unitOfWork.SeriesRepository.AddSeriesModifiers(userId, series); Response.AddPaginationHeader(series.CurrentPage, series.PageSize, series.TotalCount, series.TotalPages); @@ -55,10 +56,10 @@ namespace API.Controllers [HttpGet("{seriesId}")] public async Task> GetSeries(int seriesId) { - var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername()); + var userId = await _unitOfWork.UserRepository.GetUserIdByUsernameAsync(User.GetUsername()); try { - return Ok(await _unitOfWork.SeriesRepository.GetSeriesDtoByIdAsync(seriesId, user.Id)); + return Ok(await _unitOfWork.SeriesRepository.GetSeriesDtoByIdAsync(seriesId, userId)); } catch (Exception e) { @@ -95,30 +96,28 @@ namespace API.Controllers [HttpGet("volumes")] public async Task>> GetVolumes(int seriesId) { - var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername()); - return Ok(await _unitOfWork.SeriesRepository.GetVolumesDtoAsync(seriesId, user.Id)); + var userId = await _unitOfWork.UserRepository.GetUserIdByUsernameAsync(User.GetUsername()); + return Ok(await _unitOfWork.SeriesRepository.GetVolumesDtoAsync(seriesId, userId)); } [HttpGet("volume")] public async Task> GetVolume(int volumeId) { - var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername()); - return Ok(await _unitOfWork.SeriesRepository.GetVolumeDtoAsync(volumeId, user.Id)); + var userId = await _unitOfWork.UserRepository.GetUserIdByUsernameAsync(User.GetUsername()); + return Ok(await _unitOfWork.SeriesRepository.GetVolumeDtoAsync(volumeId, userId)); } [HttpGet("chapter")] public async Task> GetChapter(int chapterId) { - return Ok(await _unitOfWork.VolumeRepository.GetChapterDtoAsync(chapterId)); + return Ok(await _unitOfWork.ChapterRepository.GetChapterDtoAsync(chapterId)); } - - [HttpPost("update-rating")] public async Task UpdateSeriesRating(UpdateSeriesRatingDto updateSeriesRatingDto) { - var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername()); + var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Ratings); var userRating = await _unitOfWork.UserRepository.GetUserRating(updateSeriesRatingDto.SeriesId, user.Id) ?? new AppUserRating(); @@ -158,10 +157,12 @@ namespace API.Controllers series.Summary = updateSeries.Summary?.Trim(); var needsRefreshMetadata = false; + // This is when you hit Reset if (series.CoverImageLocked && !updateSeries.CoverImageLocked) { // Trigger a refresh when we are moving from a locked image to a non-locked needsRefreshMetadata = true; + series.CoverImage = string.Empty; series.CoverImageLocked = updateSeries.CoverImageLocked; } @@ -182,14 +183,14 @@ namespace API.Controllers [HttpPost("recently-added")] public async Task>> GetRecentlyAdded(FilterDto filterDto, [FromQuery] UserParams userParams, [FromQuery] int libraryId = 0) { - var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername()); + var userId = await _unitOfWork.UserRepository.GetUserIdByUsernameAsync(User.GetUsername()); var series = - await _unitOfWork.SeriesRepository.GetRecentlyAdded(libraryId, user.Id, userParams, filterDto); + await _unitOfWork.SeriesRepository.GetRecentlyAdded(libraryId, userId, userParams, filterDto); // Apply progress/rating information (I can't work out how to do this in initial query) if (series == null) return BadRequest("Could not get series"); - await _unitOfWork.SeriesRepository.AddSeriesModifiers(user.Id, series); + await _unitOfWork.SeriesRepository.AddSeriesModifiers(userId, series); Response.AddPaginationHeader(series.CurrentPage, series.PageSize, series.TotalCount, series.TotalPages); @@ -200,8 +201,8 @@ namespace API.Controllers public async Task>> GetInProgress(FilterDto filterDto, [FromQuery] UserParams userParams, [FromQuery] int libraryId = 0) { // NOTE: This has to be done manually like this due to the DistinctBy requirement - var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername()); - var results = await _unitOfWork.SeriesRepository.GetInProgress(user.Id, libraryId, userParams, filterDto); + var userId = await _unitOfWork.UserRepository.GetUserIdByUsernameAsync(User.GetUsername()); + var results = await _unitOfWork.SeriesRepository.GetInProgress(userId, libraryId, userParams, filterDto); var listResults = results.DistinctBy(s => s.Name).Skip((userParams.PageNumber - 1) * userParams.PageSize) .Take(userParams.PageSize).ToList(); @@ -316,14 +317,14 @@ namespace API.Controllers [HttpGet("series-by-collection")] public async Task>> GetSeriesByCollectionTag(int collectionId, [FromQuery] UserParams userParams) { - var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername()); + var userId = await _unitOfWork.UserRepository.GetUserIdByUsernameAsync(User.GetUsername()); var series = - await _unitOfWork.SeriesRepository.GetSeriesDtoForCollectionAsync(collectionId, user.Id, userParams); + await _unitOfWork.SeriesRepository.GetSeriesDtoForCollectionAsync(collectionId, userId, userParams); // Apply progress/rating information (I can't work out how to do this in initial query) if (series == null) return BadRequest("Could not get series for collection"); - await _unitOfWork.SeriesRepository.AddSeriesModifiers(user.Id, series); + await _unitOfWork.SeriesRepository.AddSeriesModifiers(userId, series); Response.AddPaginationHeader(series.CurrentPage, series.PageSize, series.TotalCount, series.TotalPages); @@ -339,8 +340,8 @@ namespace API.Controllers public async Task>> GetAllSeriesById(SeriesByIdsDto dto) { if (dto.SeriesIds == null) return BadRequest("Must pass seriesIds"); - var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername()); - return Ok(await _unitOfWork.SeriesRepository.GetSeriesDtoForIdsAsync(dto.SeriesIds, user.Id)); + var userId = await _unitOfWork.UserRepository.GetUserIdByUsernameAsync(User.GetUsername()); + return Ok(await _unitOfWork.SeriesRepository.GetSeriesDtoForIdsAsync(dto.SeriesIds, userId)); } diff --git a/API/Controllers/SettingsController.cs b/API/Controllers/SettingsController.cs index 4d81eb22d..acd1b61e8 100644 --- a/API/Controllers/SettingsController.cs +++ b/API/Controllers/SettingsController.cs @@ -103,7 +103,7 @@ namespace API.Controllers } else { - _taskScheduler.ScheduleStatsTasks(); + await _taskScheduler.ScheduleStatsTasks(); } } } diff --git a/API/Controllers/UploadController.cs b/API/Controllers/UploadController.cs index 0d924c66d..4241a8bc6 100644 --- a/API/Controllers/UploadController.cs +++ b/API/Controllers/UploadController.cs @@ -3,9 +3,11 @@ using System.Threading.Tasks; using API.DTOs.Uploads; using API.Interfaces; using API.Interfaces.Services; +using API.Services; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; +using NetVips; namespace API.Controllers { @@ -48,12 +50,12 @@ namespace API.Controllers try { - var bytes = _imageService.CreateThumbnailFromBase64(uploadFileDto.Url); + var filePath = _imageService.CreateThumbnailFromBase64(uploadFileDto.Url, ImageService.GetSeriesFormat(uploadFileDto.Id)); var series = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(uploadFileDto.Id); - if (bytes.Length > 0) + if (!string.IsNullOrEmpty(filePath)) { - series.CoverImage = bytes; + series.CoverImage = filePath; series.CoverImageLocked = true; _unitOfWork.SeriesRepository.Update(series); } @@ -93,12 +95,12 @@ namespace API.Controllers try { - var bytes = _imageService.CreateThumbnailFromBase64(uploadFileDto.Url); + var filePath = _imageService.CreateThumbnailFromBase64(uploadFileDto.Url, $"{ImageService.GetCollectionTagFormat(uploadFileDto.Id)}"); var tag = await _unitOfWork.CollectionTagRepository.GetTagAsync(uploadFileDto.Id); - if (bytes.Length > 0) + if (!string.IsNullOrEmpty(filePath)) { - tag.CoverImage = bytes; + tag.CoverImage = filePath; tag.CoverImageLocked = true; _unitOfWork.CollectionTagRepository.Update(tag); } @@ -138,12 +140,12 @@ namespace API.Controllers try { - var bytes = _imageService.CreateThumbnailFromBase64(uploadFileDto.Url); + var chapter = await _unitOfWork.ChapterRepository.GetChapterAsync(uploadFileDto.Id); + var filePath = _imageService.CreateThumbnailFromBase64(uploadFileDto.Url, $"{ImageService.GetChapterFormat(uploadFileDto.Id, chapter.VolumeId)}"); - if (bytes.Length > 0) + if (!string.IsNullOrEmpty(filePath)) { - var chapter = await _unitOfWork.VolumeRepository.GetChapterAsync(uploadFileDto.Id); - chapter.CoverImage = bytes; + chapter.CoverImage = filePath; chapter.CoverImageLocked = true; _unitOfWork.ChapterRepository.Update(chapter); var volume = await _unitOfWork.SeriesRepository.GetVolumeAsync(chapter.VolumeId); @@ -178,8 +180,9 @@ namespace API.Controllers { try { - var chapter = await _unitOfWork.VolumeRepository.GetChapterAsync(uploadFileDto.Id); - chapter.CoverImage = Array.Empty(); + var chapter = await _unitOfWork.ChapterRepository.GetChapterAsync(uploadFileDto.Id); + var originalFile = chapter.CoverImage; + chapter.CoverImage = string.Empty; chapter.CoverImageLocked = false; _unitOfWork.ChapterRepository.Update(chapter); var volume = await _unitOfWork.SeriesRepository.GetVolumeAsync(chapter.VolumeId); @@ -190,7 +193,8 @@ namespace API.Controllers if (_unitOfWork.HasChanges()) { await _unitOfWork.CommitAsync(); - _taskScheduler.RefreshSeriesMetadata(series.LibraryId, series.Id); + System.IO.File.Delete(originalFile); + _taskScheduler.RefreshSeriesMetadata(series.LibraryId, series.Id, true); return Ok(); } diff --git a/API/Controllers/UsersController.cs b/API/Controllers/UsersController.cs index ee4c9ac66..c35e368cc 100644 --- a/API/Controllers/UsersController.cs +++ b/API/Controllers/UsersController.cs @@ -18,7 +18,7 @@ namespace API.Controllers { _unitOfWork = unitOfWork; } - + [Authorize(Policy = "RequireAdminRole")] [HttpDelete("delete-user")] public async Task DeleteUser(string username) @@ -30,7 +30,7 @@ namespace API.Controllers return BadRequest("Could not delete the user."); } - + [Authorize(Policy = "RequireAdminRole")] [HttpGet] public async Task>> GetUsers() @@ -42,8 +42,8 @@ namespace API.Controllers public async Task> HasReadingProgress(int libraryId) { var library = await _unitOfWork.LibraryRepository.GetLibraryForIdAsync(libraryId); - var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername()); - return Ok(await _unitOfWork.AppUserProgressRepository.UserHasProgress(library.Type, user.Id)); + var userId = await _unitOfWork.UserRepository.GetUserIdByUsernameAsync(User.GetUsername()); + return Ok(await _unitOfWork.AppUserProgressRepository.UserHasProgress(library.Type, userId)); } [HttpGet("has-library-access")] @@ -77,8 +77,8 @@ namespace API.Controllers { return Ok(preferencesDto); } - + return BadRequest("There was an issue saving preferences."); } } -} \ No newline at end of file +} diff --git a/API/DTOs/LoginDto.cs b/API/DTOs/Account/LoginDto.cs similarity index 100% rename from API/DTOs/LoginDto.cs rename to API/DTOs/Account/LoginDto.cs diff --git a/API/DTOs/ResetPasswordDto.cs b/API/DTOs/Account/ResetPasswordDto.cs similarity index 90% rename from API/DTOs/ResetPasswordDto.cs rename to API/DTOs/Account/ResetPasswordDto.cs index 4b3ee3580..2e7ef4d66 100644 --- a/API/DTOs/ResetPasswordDto.cs +++ b/API/DTOs/Account/ResetPasswordDto.cs @@ -1,6 +1,6 @@ using System.ComponentModel.DataAnnotations; -namespace API.DTOs +namespace API.DTOs.Account { public class ResetPasswordDto { @@ -10,4 +10,4 @@ namespace API.DTOs [StringLength(32, MinimumLength = 6)] public string Password { get; init; } } -} \ No newline at end of file +} diff --git a/API/DTOs/Downloads/DownloadBookmarkDto.cs b/API/DTOs/Downloads/DownloadBookmarkDto.cs index 5239b4aae..b7ccf9569 100644 --- a/API/DTOs/Downloads/DownloadBookmarkDto.cs +++ b/API/DTOs/Downloads/DownloadBookmarkDto.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using API.DTOs.Reader; namespace API.DTOs.Downloads { diff --git a/API/DTOs/ImageDto.cs b/API/DTOs/ImageDto.cs deleted file mode 100644 index e66591001..000000000 --- a/API/DTOs/ImageDto.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace API.DTOs -{ - public class ImageDto - { - public int Page { get; init; } - public string Filename { get; init; } - public string FullPath { get; init; } - public int Width { get; init; } - public int Height { get; init; } - public string Format { get; init; } - public byte[] Content { get; init; } - public string MangaFileName { get; init; } - public bool NeedsSplitting { get; init; } - } -} \ No newline at end of file diff --git a/API/DTOs/InProgressChapterDto.cs b/API/DTOs/InProgressChapterDto.cs deleted file mode 100644 index 08bce3fc6..000000000 --- a/API/DTOs/InProgressChapterDto.cs +++ /dev/null @@ -1,24 +0,0 @@ -namespace API.DTOs -{ - public class InProgressChapterDto - { - public int Id { get; init; } - /// - /// Range of chapters. Chapter 2-4 -> "2-4". Chapter 2 -> "2". - /// - public string Range { get; init; } - /// - /// Smallest number of the Range. - /// - public string Number { get; init; } - /// - /// Total number of pages in all MangaFiles - /// - public int Pages { get; init; } - public int SeriesId { get; init; } - public int LibraryId { get; init; } - public string SeriesName { get; init; } - public int VolumeId { get; init; } - - } -} \ No newline at end of file diff --git a/API/DTOs/Reader/BookInfoDto.cs b/API/DTOs/Reader/BookInfoDto.cs new file mode 100644 index 000000000..6705c9647 --- /dev/null +++ b/API/DTOs/Reader/BookInfoDto.cs @@ -0,0 +1,18 @@ +using API.Entities.Enums; + +namespace API.DTOs.Reader +{ + public class BookInfoDto : IChapterInfoDto + { + public string BookTitle { get; set; } + public int SeriesId { get; set; } + public int VolumeId { get; set; } + public MangaFormat SeriesFormat { get; set; } + public string SeriesName { get; set; } + public string ChapterNumber { get; set; } + public string VolumeNumber { get; set; } + public int LibraryId { get; set; } + public int Pages { get; set; } + public bool IsSpecial { get; set; } + } +} diff --git a/API/DTOs/BookmarkDto.cs b/API/DTOs/Reader/BookmarkDto.cs similarity index 89% rename from API/DTOs/BookmarkDto.cs rename to API/DTOs/Reader/BookmarkDto.cs index c45a183c3..3653bcaa0 100644 --- a/API/DTOs/BookmarkDto.cs +++ b/API/DTOs/Reader/BookmarkDto.cs @@ -1,4 +1,4 @@ -namespace API.DTOs +namespace API.DTOs.Reader { public class BookmarkDto { diff --git a/API/DTOs/Reader/ChapterInfoDto.cs b/API/DTOs/Reader/ChapterInfoDto.cs index 850149016..ec512670d 100644 --- a/API/DTOs/Reader/ChapterInfoDto.cs +++ b/API/DTOs/Reader/ChapterInfoDto.cs @@ -1,16 +1,21 @@ -namespace API.DTOs.Reader +using API.Entities.Enums; + +namespace API.DTOs.Reader { - public class ChapterInfoDto + public class ChapterInfoDto : IChapterInfoDto { - + public string ChapterNumber { get; set; } public string VolumeNumber { get; set; } public int VolumeId { get; set; } public string SeriesName { get; set; } + public MangaFormat SeriesFormat { get; set; } + public int SeriesId { get; set; } + public int LibraryId { get; set; } public string ChapterTitle { get; set; } = ""; public int Pages { get; set; } public string FileName { get; set; } public bool IsSpecial { get; set; } - + } -} \ No newline at end of file +} diff --git a/API/DTOs/Reader/IChapterInfoDto.cs b/API/DTOs/Reader/IChapterInfoDto.cs new file mode 100644 index 000000000..63b5c9a62 --- /dev/null +++ b/API/DTOs/Reader/IChapterInfoDto.cs @@ -0,0 +1,19 @@ +using API.Entities.Enums; +using Newtonsoft.Json; + +namespace API.DTOs.Reader +{ + public interface IChapterInfoDto + { + public int SeriesId { get; set; } + public int VolumeId { get; set; } + public MangaFormat SeriesFormat { get; set; } + public string SeriesName { get; set; } + public string ChapterNumber { get; set; } + public string VolumeNumber { get; set; } + public int LibraryId { get; set; } + public int Pages { get; set; } + public bool IsSpecial { get; set; } + + } +} diff --git a/API/DTOs/Reader/MarkMultipleSeriesAsReadDto.cs b/API/DTOs/Reader/MarkMultipleSeriesAsReadDto.cs new file mode 100644 index 000000000..7201658fa --- /dev/null +++ b/API/DTOs/Reader/MarkMultipleSeriesAsReadDto.cs @@ -0,0 +1,9 @@ +using System.Collections.Generic; + +namespace API.DTOs.Reader +{ + public class MarkMultipleSeriesAsReadDto + { + public IReadOnlyList SeriesIds { get; init; } + } +} diff --git a/API/DTOs/MarkReadDto.cs b/API/DTOs/Reader/MarkReadDto.cs similarity index 73% rename from API/DTOs/MarkReadDto.cs rename to API/DTOs/Reader/MarkReadDto.cs index 1b39df2a8..3d94e3a9d 100644 --- a/API/DTOs/MarkReadDto.cs +++ b/API/DTOs/Reader/MarkReadDto.cs @@ -1,7 +1,7 @@ -namespace API.DTOs +namespace API.DTOs.Reader { public class MarkReadDto { public int SeriesId { get; init; } } -} \ No newline at end of file +} diff --git a/API/DTOs/MarkVolumeReadDto.cs b/API/DTOs/Reader/MarkVolumeReadDto.cs similarity index 81% rename from API/DTOs/MarkVolumeReadDto.cs rename to API/DTOs/Reader/MarkVolumeReadDto.cs index ffae155a2..757f23aee 100644 --- a/API/DTOs/MarkVolumeReadDto.cs +++ b/API/DTOs/Reader/MarkVolumeReadDto.cs @@ -1,8 +1,8 @@ -namespace API.DTOs +namespace API.DTOs.Reader { public class MarkVolumeReadDto { public int SeriesId { get; init; } public int VolumeId { get; init; } } -} \ No newline at end of file +} diff --git a/API/DTOs/Reader/MarkVolumesReadDto.cs b/API/DTOs/Reader/MarkVolumesReadDto.cs new file mode 100644 index 000000000..7e23e721a --- /dev/null +++ b/API/DTOs/Reader/MarkVolumesReadDto.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; + +namespace API.DTOs.Reader +{ + /// + /// This is used for bulk updating a set of volume and or chapters in one go + /// + public class MarkVolumesReadDto + { + public int SeriesId { get; set; } + /// + /// A list of Volumes to mark read + /// + public IReadOnlyList VolumeIds { get; set; } + /// + /// A list of additional Chapters to mark as read + /// + public IReadOnlyList ChapterIds { get; set; } + } +} diff --git a/API/DTOs/RemoveBookmarkForSeriesDto.cs b/API/DTOs/Reader/RemoveBookmarkForSeriesDto.cs similarity index 78% rename from API/DTOs/RemoveBookmarkForSeriesDto.cs rename to API/DTOs/Reader/RemoveBookmarkForSeriesDto.cs index 7ec76b081..a269b7095 100644 --- a/API/DTOs/RemoveBookmarkForSeriesDto.cs +++ b/API/DTOs/Reader/RemoveBookmarkForSeriesDto.cs @@ -1,4 +1,4 @@ -namespace API.DTOs +namespace API.DTOs.Reader { public class RemoveBookmarkForSeriesDto { diff --git a/API/DTOs/ReadingLists/CreateReadingListDto.cs b/API/DTOs/ReadingLists/CreateReadingListDto.cs new file mode 100644 index 000000000..c32b62bea --- /dev/null +++ b/API/DTOs/ReadingLists/CreateReadingListDto.cs @@ -0,0 +1,7 @@ +namespace API.DTOs.ReadingLists +{ + public class CreateReadingListDto + { + public string Title { get; init; } + } +} diff --git a/API/DTOs/ReadingLists/ReadingListDto.cs b/API/DTOs/ReadingLists/ReadingListDto.cs new file mode 100644 index 000000000..e3837a2e3 --- /dev/null +++ b/API/DTOs/ReadingLists/ReadingListDto.cs @@ -0,0 +1,13 @@ +namespace API.DTOs.ReadingLists +{ + public class ReadingListDto + { + public int Id { get; init; } + public string Title { get; set; } + public string Summary { get; set; } + /// + /// Reading lists that are promoted are only done by admins + /// + public bool Promoted { get; set; } + } +} diff --git a/API/DTOs/ReadingLists/ReadingListItemDto.cs b/API/DTOs/ReadingLists/ReadingListItemDto.cs new file mode 100644 index 000000000..b58fdcf80 --- /dev/null +++ b/API/DTOs/ReadingLists/ReadingListItemDto.cs @@ -0,0 +1,25 @@ +using API.Entities.Enums; + +namespace API.DTOs.ReadingLists +{ + public class ReadingListItemDto + { + public int Id { get; init; } + public int Order { get; init; } + public int ChapterId { get; init; } + public int SeriesId { get; init; } + public string SeriesName { get; set; } + public MangaFormat SeriesFormat { get; set; } + public int PagesRead { get; set; } + public int PagesTotal { get; set; } + public string ChapterNumber { get; set; } + public string VolumeNumber { get; set; } + public int VolumeId { get; set; } + public int LibraryId { get; set; } + public string Title { get; set; } + /// + /// Used internally only + /// + public int ReadingListId { get; set; } + } +} diff --git a/API/DTOs/ReadingLists/UpdateReadingListByChapterDto.cs b/API/DTOs/ReadingLists/UpdateReadingListByChapterDto.cs new file mode 100644 index 000000000..887850755 --- /dev/null +++ b/API/DTOs/ReadingLists/UpdateReadingListByChapterDto.cs @@ -0,0 +1,9 @@ +namespace API.DTOs.ReadingLists +{ + public class UpdateReadingListByChapterDto + { + public int ChapterId { get; init; } + public int SeriesId { get; init; } + public int ReadingListId { get; init; } + } +} diff --git a/API/DTOs/ReadingLists/UpdateReadingListByMultipleDto.cs b/API/DTOs/ReadingLists/UpdateReadingListByMultipleDto.cs new file mode 100644 index 000000000..02a41a767 --- /dev/null +++ b/API/DTOs/ReadingLists/UpdateReadingListByMultipleDto.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; + +namespace API.DTOs.ReadingLists +{ + public class UpdateReadingListByMultipleDto + { + public int SeriesId { get; init; } + public int ReadingListId { get; init; } + public IReadOnlyList VolumeIds { get; init; } + public IReadOnlyList ChapterIds { get; init; } + } +} diff --git a/API/DTOs/ReadingLists/UpdateReadingListByMultipleSeriesDto.cs b/API/DTOs/ReadingLists/UpdateReadingListByMultipleSeriesDto.cs new file mode 100644 index 000000000..4b08f95bc --- /dev/null +++ b/API/DTOs/ReadingLists/UpdateReadingListByMultipleSeriesDto.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; + +namespace API.DTOs.ReadingLists +{ + public class UpdateReadingListByMultipleSeriesDto + { + public int ReadingListId { get; init; } + public IReadOnlyList SeriesIds { get; init; } + } +} diff --git a/API/DTOs/ReadingLists/UpdateReadingListBySeriesDto.cs b/API/DTOs/ReadingLists/UpdateReadingListBySeriesDto.cs new file mode 100644 index 000000000..1040a9218 --- /dev/null +++ b/API/DTOs/ReadingLists/UpdateReadingListBySeriesDto.cs @@ -0,0 +1,8 @@ +namespace API.DTOs.ReadingLists +{ + public class UpdateReadingListBySeriesDto + { + public int SeriesId { get; init; } + public int ReadingListId { get; init; } + } +} diff --git a/API/DTOs/ReadingLists/UpdateReadingListByVolumeDto.cs b/API/DTOs/ReadingLists/UpdateReadingListByVolumeDto.cs new file mode 100644 index 000000000..0d903d48e --- /dev/null +++ b/API/DTOs/ReadingLists/UpdateReadingListByVolumeDto.cs @@ -0,0 +1,9 @@ +namespace API.DTOs.ReadingLists +{ + public class UpdateReadingListByVolumeDto + { + public int VolumeId { get; init; } + public int SeriesId { get; init; } + public int ReadingListId { get; init; } + } +} diff --git a/API/DTOs/ReadingLists/UpdateReadingListDto.cs b/API/DTOs/ReadingLists/UpdateReadingListDto.cs new file mode 100644 index 000000000..a9f6f0d59 --- /dev/null +++ b/API/DTOs/ReadingLists/UpdateReadingListDto.cs @@ -0,0 +1,10 @@ +namespace API.DTOs.ReadingLists +{ + public class UpdateReadingListDto + { + public int ReadingListId { get; set; } + public string Title { get; set; } + public string Summary { get; set; } + public bool Promoted { get; set; } + } +} diff --git a/API/DTOs/ReadingLists/UpdateReadingListPosition.cs b/API/DTOs/ReadingLists/UpdateReadingListPosition.cs new file mode 100644 index 000000000..023849024 --- /dev/null +++ b/API/DTOs/ReadingLists/UpdateReadingListPosition.cs @@ -0,0 +1,10 @@ +namespace API.DTOs.ReadingLists +{ + public class UpdateReadingListPosition + { + public int ReadingListId { get; set; } + public int ReadingListItemId { get; set; } + public int FromPosition { get; set; } + public int ToPosition { get; set; } + } +} diff --git a/API/DTOs/ServerSettingDTO.cs b/API/DTOs/Settings/ServerSettingDTO.cs similarity index 100% rename from API/DTOs/ServerSettingDTO.cs rename to API/DTOs/Settings/ServerSettingDTO.cs diff --git a/API/DTOs/VolumeDto.cs b/API/DTOs/VolumeDto.cs index 3fc165a6d..3e719346f 100644 --- a/API/DTOs/VolumeDto.cs +++ b/API/DTOs/VolumeDto.cs @@ -13,7 +13,7 @@ namespace API.DTOs public int PagesRead { get; set; } public DateTime LastModified { get; set; } public DateTime Created { get; set; } - public bool IsSpecial { get; set; } + public int SeriesId { get; set; } public ICollection Chapters { get; set; } } -} \ No newline at end of file +} diff --git a/API/Data/BookmarkRepository.cs b/API/Data/BookmarkRepository.cs deleted file mode 100644 index af212bc72..000000000 --- a/API/Data/BookmarkRepository.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace API.Data -{ - public class BookmarkRepository - { - - } -} diff --git a/API/Data/ChapterRepository.cs b/API/Data/ChapterRepository.cs deleted file mode 100644 index e3510adc4..000000000 --- a/API/Data/ChapterRepository.cs +++ /dev/null @@ -1,23 +0,0 @@ -using API.Entities; -using API.Interfaces.Repositories; -using Microsoft.EntityFrameworkCore; - -namespace API.Data -{ - public class ChapterRepository : IChapterRepository - { - private readonly DataContext _context; - - public ChapterRepository(DataContext context) - { - _context = context; - } - - public void Update(Chapter chapter) - { - _context.Entry(chapter).State = EntityState.Modified; - } - - // TODO: Move over Chapter based queries here - } -} diff --git a/API/Data/DataContext.cs b/API/Data/DataContext.cs index 62765f607..8e4dc263e 100644 --- a/API/Data/DataContext.cs +++ b/API/Data/DataContext.cs @@ -35,6 +35,9 @@ namespace API.Data public DbSet SeriesMetadata { get; set; } public DbSet CollectionTag { get; set; } public DbSet AppUserBookmark { get; set; } + public DbSet ReadingList { get; set; } + public DbSet ReadingListItem { get; set; } + protected override void OnModelCreating(ModelBuilder builder) { diff --git a/API/Data/MigrateCoverImages.cs b/API/Data/MigrateCoverImages.cs new file mode 100644 index 000000000..87e65cb81 --- /dev/null +++ b/API/Data/MigrateCoverImages.cs @@ -0,0 +1,180 @@ +using System; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using API.Comparators; +using API.Helpers; +using API.Services; +using Microsoft.EntityFrameworkCore; + +namespace API.Data +{ + /// + /// A data structure to migrate Cover Images from byte[] to files. + /// + internal class CoverMigration + { + public string Id { get; set; } + public byte[] CoverImage { get; set; } + public string ParentId { get; set; } + } + + /// + /// In v0.4.6, Cover Images were migrated from byte[] in the DB to external files. This migration handles that work. + /// + public static class MigrateCoverImages + { + private static readonly ChapterSortComparerZeroFirst ChapterSortComparerForInChapterSorting = new (); + + /// + /// Run first. Will extract byte[]s from DB and write them to the cover directory. + /// + public static void ExtractToImages(DbContext context) + { + Console.WriteLine("Migrating Cover Images to disk. Expect delay."); + DirectoryService.ExistOrCreate(DirectoryService.CoverImageDirectory); + + Console.WriteLine("Extracting cover images for Series"); + var lockedSeries = SqlHelper.RawSqlQuery(context, "Select Id, CoverImage From Series Where CoverImage IS NOT NULL", x => + new CoverMigration() + { + Id = x[0] + string.Empty, + CoverImage = (byte[]) x[1], + ParentId = "0" + }); + foreach (var series in lockedSeries) + { + if (series.CoverImage == null || !series.CoverImage.Any()) continue; + if (File.Exists(Path.Join(DirectoryService.CoverImageDirectory, + $"{ImageService.GetSeriesFormat(int.Parse(series.Id))}.png"))) continue; + + try + { + var stream = new MemoryStream(series.CoverImage); + stream.Position = 0; + ImageService.WriteCoverThumbnail(stream, ImageService.GetSeriesFormat(int.Parse(series.Id))); + } + catch (Exception e) + { + Console.WriteLine(e); + } + } + + Console.WriteLine("Extracting cover images for Chapters"); + var chapters = SqlHelper.RawSqlQuery(context, "Select Id, CoverImage, VolumeId From Chapter Where CoverImage IS NOT NULL;", x => + new CoverMigration() + { + Id = x[0] + string.Empty, + CoverImage = (byte[]) x[1], + ParentId = x[2] + string.Empty + }); + foreach (var chapter in chapters) + { + if (chapter.CoverImage == null || !chapter.CoverImage.Any()) continue; + if (File.Exists(Path.Join(DirectoryService.CoverImageDirectory, + $"{ImageService.GetChapterFormat(int.Parse(chapter.Id), int.Parse(chapter.ParentId))}.png"))) continue; + + try + { + var stream = new MemoryStream(chapter.CoverImage); + stream.Position = 0; + ImageService.WriteCoverThumbnail(stream, $"{ImageService.GetChapterFormat(int.Parse(chapter.Id), int.Parse(chapter.ParentId))}"); + } + catch (Exception e) + { + Console.WriteLine(e); + } + } + + Console.WriteLine("Extracting cover images for Collection Tags"); + var tags = SqlHelper.RawSqlQuery(context, "Select Id, CoverImage From CollectionTag Where CoverImage IS NOT NULL;", x => + new CoverMigration() + { + Id = x[0] + string.Empty, + CoverImage = (byte[]) x[1] , + ParentId = "0" + }); + foreach (var tag in tags) + { + if (tag.CoverImage == null || !tag.CoverImage.Any()) continue; + if (File.Exists(Path.Join(DirectoryService.CoverImageDirectory, + $"{ImageService.GetCollectionTagFormat(int.Parse(tag.Id))}.png"))) continue; + try + { + var stream = new MemoryStream(tag.CoverImage); + stream.Position = 0; + ImageService.WriteCoverThumbnail(stream, $"{ImageService.GetCollectionTagFormat(int.Parse(tag.Id))}"); + } + catch (Exception e) + { + Console.WriteLine(e); + } + } + } + + /// + /// Run after . Will update the DB with names of files that were extracted. + /// + /// + public static async Task UpdateDatabaseWithImages(DataContext context) + { + Console.WriteLine("Updating Series entities"); + var seriesCovers = await context.Series.Where(s => !string.IsNullOrEmpty(s.CoverImage)).ToListAsync(); + foreach (var series in seriesCovers) + { + if (!File.Exists(Path.Join(DirectoryService.CoverImageDirectory, + $"{ImageService.GetSeriesFormat(series.Id)}.png"))) continue; + series.CoverImage = $"{ImageService.GetSeriesFormat(series.Id)}.png"; + } + + await context.SaveChangesAsync(); + + Console.WriteLine("Updating Chapter entities"); + var chapters = await context.Chapter.ToListAsync(); + foreach (var chapter in chapters) + { + if (File.Exists(Path.Join(DirectoryService.CoverImageDirectory, + $"{ImageService.GetChapterFormat(chapter.Id, chapter.VolumeId)}.png"))) + { + chapter.CoverImage = $"{ImageService.GetChapterFormat(chapter.Id, chapter.VolumeId)}.png"; + } + + } + + await context.SaveChangesAsync(); + + Console.WriteLine("Updating Volume entities"); + var volumes = await context.Volume.Include(v => v.Chapters).ToListAsync(); + foreach (var volume in volumes) + { + var firstChapter = volume.Chapters.OrderBy(x => double.Parse(x.Number), ChapterSortComparerForInChapterSorting).FirstOrDefault(); + if (firstChapter == null) continue; + if (File.Exists(Path.Join(DirectoryService.CoverImageDirectory, + $"{ImageService.GetChapterFormat(firstChapter.Id, firstChapter.VolumeId)}.png"))) + { + volume.CoverImage = $"{ImageService.GetChapterFormat(firstChapter.Id, firstChapter.VolumeId)}.png"; + } + + } + + await context.SaveChangesAsync(); + + Console.WriteLine("Updating Collection Tag entities"); + var tags = await context.CollectionTag.ToListAsync(); + foreach (var tag in tags) + { + if (File.Exists(Path.Join(DirectoryService.CoverImageDirectory, + $"{ImageService.GetCollectionTagFormat(tag.Id)}.png"))) + { + tag.CoverImage = $"{ImageService.GetCollectionTagFormat(tag.Id)}.png"; + } + + } + + await context.SaveChangesAsync(); + + Console.WriteLine("Cover Image Migration completed"); + } + + } +} diff --git a/API/Data/Migrations/20210901150310_ReadingLists.Designer.cs b/API/Data/Migrations/20210901150310_ReadingLists.Designer.cs new file mode 100644 index 000000000..fef65fdcf --- /dev/null +++ b/API/Data/Migrations/20210901150310_ReadingLists.Designer.cs @@ -0,0 +1,1018 @@ +// +using System; +using API.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +namespace API.Data.Migrations +{ + [DbContext(typeof(DataContext))] + [Migration("20210901150310_ReadingLists")] + partial class ReadingLists + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "5.0.8"); + + modelBuilder.Entity("API.Entities.AppRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles"); + }); + + modelBuilder.Entity("API.Entities.AppUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessFailedCount") + .HasColumnType("INTEGER"); + + b.Property("ApiKey") + .HasColumnType("TEXT"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("EmailConfirmed") + .HasColumnType("INTEGER"); + + b.Property("LastActive") + .HasColumnType("TEXT"); + + b.Property("LockoutEnabled") + .HasColumnType("INTEGER"); + + b.Property("LockoutEnd") + .HasColumnType("TEXT"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("PasswordHash") + .HasColumnType("TEXT"); + + b.Property("PhoneNumber") + .HasColumnType("TEXT"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SecurityStamp") + .HasColumnType("TEXT"); + + b.Property("TwoFactorEnabled") + .HasColumnType("INTEGER"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("AspNetUsers"); + }); + + modelBuilder.Entity("API.Entities.AppUserBookmark", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("Page") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("AppUserBookmark"); + }); + + modelBuilder.Entity("API.Entities.AppUserPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("AutoCloseMenu") + .HasColumnType("INTEGER"); + + b.Property("BookReaderDarkMode") + .HasColumnType("INTEGER"); + + b.Property("BookReaderFontFamily") + .HasColumnType("TEXT"); + + b.Property("BookReaderFontSize") + .HasColumnType("INTEGER"); + + b.Property("BookReaderLineSpacing") + .HasColumnType("INTEGER"); + + b.Property("BookReaderMargin") + .HasColumnType("INTEGER"); + + b.Property("BookReaderReadingDirection") + .HasColumnType("INTEGER"); + + b.Property("BookReaderTapToPaginate") + .HasColumnType("INTEGER"); + + b.Property("PageSplitOption") + .HasColumnType("INTEGER"); + + b.Property("ReaderMode") + .HasColumnType("INTEGER"); + + b.Property("ReadingDirection") + .HasColumnType("INTEGER"); + + b.Property("ScalingOption") + .HasColumnType("INTEGER"); + + b.Property("SiteDarkMode") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId") + .IsUnique(); + + b.ToTable("AppUserPreferences"); + }); + + modelBuilder.Entity("API.Entities.AppUserProgress", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("BookScrollId") + .HasColumnType("TEXT"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("PagesRead") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("AppUserProgresses"); + }); + + modelBuilder.Entity("API.Entities.AppUserRating", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("Rating") + .HasColumnType("INTEGER"); + + b.Property("Review") + .HasColumnType("TEXT"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("AppUserRating"); + }); + + modelBuilder.Entity("API.Entities.AppUserRole", b => + { + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles"); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("BLOB"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("IsSpecial") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Number") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("Range") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("VolumeId"); + + b.ToTable("Chapter"); + }); + + modelBuilder.Entity("API.Entities.CollectionTag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("BLOB"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("NormalizedTitle") + .HasColumnType("TEXT"); + + b.Property("Promoted") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Id", "Promoted") + .IsUnique(); + + b.ToTable("CollectionTag"); + }); + + modelBuilder.Entity("API.Entities.FolderPath", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("LastScanned") + .HasColumnType("TEXT"); + + b.Property("LibraryId") + .HasColumnType("INTEGER"); + + b.Property("Path") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("LibraryId"); + + b.ToTable("FolderPath"); + }); + + modelBuilder.Entity("API.Entities.Library", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Library"); + }); + + modelBuilder.Entity("API.Entities.MangaFile", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("FilePath") + .HasColumnType("TEXT"); + + b.Property("Format") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ChapterId"); + + b.ToTable("MangaFile"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Promoted") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("ReadingList"); + }); + + modelBuilder.Entity("API.Entities.ReadingListItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("LibraryId") + .HasColumnType("INTEGER"); + + b.Property("Order") + .HasColumnType("INTEGER"); + + b.Property("ReadingListId") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ReadingListId"); + + b.HasIndex("SeriesId", "VolumeId", "ChapterId", "LibraryId") + .IsUnique(); + + b.ToTable("ReadingListItem"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("BLOB"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("Format") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("LibraryId") + .HasColumnType("INTEGER"); + + b.Property("LocalizedName") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasColumnType("TEXT"); + + b.Property("OriginalName") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("SortName") + .HasColumnType("TEXT"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("LibraryId"); + + b.HasIndex("Name", "NormalizedName", "LocalizedName", "LibraryId", "Format") + .IsUnique(); + + b.ToTable("Series"); + }); + + modelBuilder.Entity("API.Entities.SeriesMetadata", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("SeriesId") + .IsUnique(); + + b.HasIndex("Id", "SeriesId") + .IsUnique(); + + b.ToTable("SeriesMetadata"); + }); + + modelBuilder.Entity("API.Entities.ServerSetting", b => + { + b.Property("Key") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("Key"); + + b.ToTable("ServerSetting"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("BLOB"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Number") + .HasColumnType("INTEGER"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("SeriesId"); + + b.ToTable("Volume"); + }); + + modelBuilder.Entity("AppUserLibrary", b => + { + b.Property("AppUsersId") + .HasColumnType("INTEGER"); + + b.Property("LibrariesId") + .HasColumnType("INTEGER"); + + b.HasKey("AppUsersId", "LibrariesId"); + + b.HasIndex("LibrariesId"); + + b.ToTable("AppUserLibrary"); + }); + + modelBuilder.Entity("CollectionTagSeriesMetadata", b => + { + b.Property("CollectionTagsId") + .HasColumnType("INTEGER"); + + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.HasKey("CollectionTagsId", "SeriesMetadatasId"); + + b.HasIndex("SeriesMetadatasId"); + + b.ToTable("CollectionTagSeriesMetadata"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("ProviderKey") + .HasColumnType("TEXT"); + + b.Property("ProviderDisplayName") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens"); + }); + + modelBuilder.Entity("API.Entities.AppUserBookmark", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Bookmarks") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserPreferences", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithOne("UserPreferences") + .HasForeignKey("API.Entities.AppUserPreferences", "AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserProgress", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Progresses") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserRating", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Ratings") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserRole", b => + { + b.HasOne("API.Entities.AppRole", "Role") + .WithMany("UserRoles") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.AppUser", "User") + .WithMany("UserRoles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.HasOne("API.Entities.Volume", "Volume") + .WithMany("Chapters") + .HasForeignKey("VolumeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Volume"); + }); + + modelBuilder.Entity("API.Entities.FolderPath", b => + { + b.HasOne("API.Entities.Library", "Library") + .WithMany("Folders") + .HasForeignKey("LibraryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Library"); + }); + + modelBuilder.Entity("API.Entities.MangaFile", b => + { + b.HasOne("API.Entities.Chapter", "Chapter") + .WithMany("Files") + .HasForeignKey("ChapterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Chapter"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("ReadingLists") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.ReadingListItem", b => + { + b.HasOne("API.Entities.ReadingList", null) + .WithMany("Items") + .HasForeignKey("ReadingListId"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.HasOne("API.Entities.Library", "Library") + .WithMany("Series") + .HasForeignKey("LibraryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Library"); + }); + + modelBuilder.Entity("API.Entities.SeriesMetadata", b => + { + b.HasOne("API.Entities.Series", "Series") + .WithOne("Metadata") + .HasForeignKey("API.Entities.SeriesMetadata", "SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.HasOne("API.Entities.Series", "Series") + .WithMany("Volumes") + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("AppUserLibrary", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("AppUsersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Library", null) + .WithMany() + .HasForeignKey("LibrariesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("CollectionTagSeriesMetadata", b => + { + b.HasOne("API.Entities.CollectionTag", null) + .WithMany() + .HasForeignKey("CollectionTagsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("API.Entities.AppRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("API.Entities.AppRole", b => + { + b.Navigation("UserRoles"); + }); + + modelBuilder.Entity("API.Entities.AppUser", b => + { + b.Navigation("Bookmarks"); + + b.Navigation("Progresses"); + + b.Navigation("Ratings"); + + b.Navigation("ReadingLists"); + + b.Navigation("UserPreferences"); + + b.Navigation("UserRoles"); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.Navigation("Files"); + }); + + modelBuilder.Entity("API.Entities.Library", b => + { + b.Navigation("Folders"); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.Navigation("Items"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.Navigation("Metadata"); + + b.Navigation("Volumes"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.Navigation("Chapters"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/API/Data/Migrations/20210901150310_ReadingLists.cs b/API/Data/Migrations/20210901150310_ReadingLists.cs new file mode 100644 index 000000000..709d3e17a --- /dev/null +++ b/API/Data/Migrations/20210901150310_ReadingLists.cs @@ -0,0 +1,84 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace API.Data.Migrations +{ + public partial class ReadingLists : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "ReadingList", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + Title = table.Column(type: "TEXT", nullable: true), + Summary = table.Column(type: "TEXT", nullable: true), + Promoted = table.Column(type: "INTEGER", nullable: false), + Created = table.Column(type: "TEXT", nullable: false), + LastModified = table.Column(type: "TEXT", nullable: false), + AppUserId = table.Column(type: "INTEGER", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ReadingList", x => x.Id); + table.ForeignKey( + name: "FK_ReadingList_AspNetUsers_AppUserId", + column: x => x.AppUserId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "ReadingListItem", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + LibraryId = table.Column(type: "INTEGER", nullable: false), + SeriesId = table.Column(type: "INTEGER", nullable: false), + VolumeId = table.Column(type: "INTEGER", nullable: false), + ChapterId = table.Column(type: "INTEGER", nullable: false), + Order = table.Column(type: "INTEGER", nullable: false), + ReadingListId = table.Column(type: "INTEGER", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_ReadingListItem", x => x.Id); + table.ForeignKey( + name: "FK_ReadingListItem_ReadingList_ReadingListId", + column: x => x.ReadingListId, + principalTable: "ReadingList", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateIndex( + name: "IX_ReadingList_AppUserId", + table: "ReadingList", + column: "AppUserId"); + + migrationBuilder.CreateIndex( + name: "IX_ReadingListItem_ReadingListId", + table: "ReadingListItem", + column: "ReadingListId"); + + migrationBuilder.CreateIndex( + name: "IX_ReadingListItem_SeriesId_VolumeId_ChapterId_LibraryId", + table: "ReadingListItem", + columns: new[] { "SeriesId", "VolumeId", "ChapterId", "LibraryId" }, + unique: true); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "ReadingListItem"); + + migrationBuilder.DropTable( + name: "ReadingList"); + } + } +} diff --git a/API/Data/Migrations/20210901200442_ReadingListsAdditions.Designer.cs b/API/Data/Migrations/20210901200442_ReadingListsAdditions.Designer.cs new file mode 100644 index 000000000..8ee5bdec8 --- /dev/null +++ b/API/Data/Migrations/20210901200442_ReadingListsAdditions.Designer.cs @@ -0,0 +1,1022 @@ +// +using System; +using API.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +namespace API.Data.Migrations +{ + [DbContext(typeof(DataContext))] + [Migration("20210901200442_ReadingListsAdditions")] + partial class ReadingListsAdditions + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "5.0.8"); + + modelBuilder.Entity("API.Entities.AppRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles"); + }); + + modelBuilder.Entity("API.Entities.AppUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessFailedCount") + .HasColumnType("INTEGER"); + + b.Property("ApiKey") + .HasColumnType("TEXT"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("EmailConfirmed") + .HasColumnType("INTEGER"); + + b.Property("LastActive") + .HasColumnType("TEXT"); + + b.Property("LockoutEnabled") + .HasColumnType("INTEGER"); + + b.Property("LockoutEnd") + .HasColumnType("TEXT"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("PasswordHash") + .HasColumnType("TEXT"); + + b.Property("PhoneNumber") + .HasColumnType("TEXT"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SecurityStamp") + .HasColumnType("TEXT"); + + b.Property("TwoFactorEnabled") + .HasColumnType("INTEGER"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("AspNetUsers"); + }); + + modelBuilder.Entity("API.Entities.AppUserBookmark", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("Page") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("AppUserBookmark"); + }); + + modelBuilder.Entity("API.Entities.AppUserPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("AutoCloseMenu") + .HasColumnType("INTEGER"); + + b.Property("BookReaderDarkMode") + .HasColumnType("INTEGER"); + + b.Property("BookReaderFontFamily") + .HasColumnType("TEXT"); + + b.Property("BookReaderFontSize") + .HasColumnType("INTEGER"); + + b.Property("BookReaderLineSpacing") + .HasColumnType("INTEGER"); + + b.Property("BookReaderMargin") + .HasColumnType("INTEGER"); + + b.Property("BookReaderReadingDirection") + .HasColumnType("INTEGER"); + + b.Property("BookReaderTapToPaginate") + .HasColumnType("INTEGER"); + + b.Property("PageSplitOption") + .HasColumnType("INTEGER"); + + b.Property("ReaderMode") + .HasColumnType("INTEGER"); + + b.Property("ReadingDirection") + .HasColumnType("INTEGER"); + + b.Property("ScalingOption") + .HasColumnType("INTEGER"); + + b.Property("SiteDarkMode") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId") + .IsUnique(); + + b.ToTable("AppUserPreferences"); + }); + + modelBuilder.Entity("API.Entities.AppUserProgress", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("BookScrollId") + .HasColumnType("TEXT"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("PagesRead") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("AppUserProgresses"); + }); + + modelBuilder.Entity("API.Entities.AppUserRating", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("Rating") + .HasColumnType("INTEGER"); + + b.Property("Review") + .HasColumnType("TEXT"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("AppUserRating"); + }); + + modelBuilder.Entity("API.Entities.AppUserRole", b => + { + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles"); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("BLOB"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("IsSpecial") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Number") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("Range") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("VolumeId"); + + b.ToTable("Chapter"); + }); + + modelBuilder.Entity("API.Entities.CollectionTag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("BLOB"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("NormalizedTitle") + .HasColumnType("TEXT"); + + b.Property("Promoted") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Id", "Promoted") + .IsUnique(); + + b.ToTable("CollectionTag"); + }); + + modelBuilder.Entity("API.Entities.FolderPath", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("LastScanned") + .HasColumnType("TEXT"); + + b.Property("LibraryId") + .HasColumnType("INTEGER"); + + b.Property("Path") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("LibraryId"); + + b.ToTable("FolderPath"); + }); + + modelBuilder.Entity("API.Entities.Library", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Library"); + }); + + modelBuilder.Entity("API.Entities.MangaFile", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("FilePath") + .HasColumnType("TEXT"); + + b.Property("Format") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ChapterId"); + + b.ToTable("MangaFile"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Promoted") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("ReadingList"); + }); + + modelBuilder.Entity("API.Entities.ReadingListItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("LibraryId") + .HasColumnType("INTEGER"); + + b.Property("Order") + .HasColumnType("INTEGER"); + + b.Property("ReadingListId") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ReadingListId"); + + b.HasIndex("SeriesId", "VolumeId", "ChapterId", "LibraryId") + .IsUnique(); + + b.ToTable("ReadingListItem"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("BLOB"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("Format") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("LibraryId") + .HasColumnType("INTEGER"); + + b.Property("LocalizedName") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasColumnType("TEXT"); + + b.Property("OriginalName") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("SortName") + .HasColumnType("TEXT"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("LibraryId"); + + b.HasIndex("Name", "NormalizedName", "LocalizedName", "LibraryId", "Format") + .IsUnique(); + + b.ToTable("Series"); + }); + + modelBuilder.Entity("API.Entities.SeriesMetadata", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("SeriesId") + .IsUnique(); + + b.HasIndex("Id", "SeriesId") + .IsUnique(); + + b.ToTable("SeriesMetadata"); + }); + + modelBuilder.Entity("API.Entities.ServerSetting", b => + { + b.Property("Key") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("Key"); + + b.ToTable("ServerSetting"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("BLOB"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Number") + .HasColumnType("INTEGER"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("SeriesId"); + + b.ToTable("Volume"); + }); + + modelBuilder.Entity("AppUserLibrary", b => + { + b.Property("AppUsersId") + .HasColumnType("INTEGER"); + + b.Property("LibrariesId") + .HasColumnType("INTEGER"); + + b.HasKey("AppUsersId", "LibrariesId"); + + b.HasIndex("LibrariesId"); + + b.ToTable("AppUserLibrary"); + }); + + modelBuilder.Entity("CollectionTagSeriesMetadata", b => + { + b.Property("CollectionTagsId") + .HasColumnType("INTEGER"); + + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.HasKey("CollectionTagsId", "SeriesMetadatasId"); + + b.HasIndex("SeriesMetadatasId"); + + b.ToTable("CollectionTagSeriesMetadata"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("ProviderKey") + .HasColumnType("TEXT"); + + b.Property("ProviderDisplayName") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens"); + }); + + modelBuilder.Entity("API.Entities.AppUserBookmark", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Bookmarks") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserPreferences", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithOne("UserPreferences") + .HasForeignKey("API.Entities.AppUserPreferences", "AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserProgress", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Progresses") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserRating", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Ratings") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserRole", b => + { + b.HasOne("API.Entities.AppRole", "Role") + .WithMany("UserRoles") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.AppUser", "User") + .WithMany("UserRoles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.HasOne("API.Entities.Volume", "Volume") + .WithMany("Chapters") + .HasForeignKey("VolumeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Volume"); + }); + + modelBuilder.Entity("API.Entities.FolderPath", b => + { + b.HasOne("API.Entities.Library", "Library") + .WithMany("Folders") + .HasForeignKey("LibraryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Library"); + }); + + modelBuilder.Entity("API.Entities.MangaFile", b => + { + b.HasOne("API.Entities.Chapter", "Chapter") + .WithMany("Files") + .HasForeignKey("ChapterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Chapter"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("ReadingLists") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.ReadingListItem", b => + { + b.HasOne("API.Entities.ReadingList", "ReadingList") + .WithMany("Items") + .HasForeignKey("ReadingListId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ReadingList"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.HasOne("API.Entities.Library", "Library") + .WithMany("Series") + .HasForeignKey("LibraryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Library"); + }); + + modelBuilder.Entity("API.Entities.SeriesMetadata", b => + { + b.HasOne("API.Entities.Series", "Series") + .WithOne("Metadata") + .HasForeignKey("API.Entities.SeriesMetadata", "SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.HasOne("API.Entities.Series", "Series") + .WithMany("Volumes") + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("AppUserLibrary", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("AppUsersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Library", null) + .WithMany() + .HasForeignKey("LibrariesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("CollectionTagSeriesMetadata", b => + { + b.HasOne("API.Entities.CollectionTag", null) + .WithMany() + .HasForeignKey("CollectionTagsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("API.Entities.AppRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("API.Entities.AppRole", b => + { + b.Navigation("UserRoles"); + }); + + modelBuilder.Entity("API.Entities.AppUser", b => + { + b.Navigation("Bookmarks"); + + b.Navigation("Progresses"); + + b.Navigation("Ratings"); + + b.Navigation("ReadingLists"); + + b.Navigation("UserPreferences"); + + b.Navigation("UserRoles"); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.Navigation("Files"); + }); + + modelBuilder.Entity("API.Entities.Library", b => + { + b.Navigation("Folders"); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.Navigation("Items"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.Navigation("Metadata"); + + b.Navigation("Volumes"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.Navigation("Chapters"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/API/Data/Migrations/20210901200442_ReadingListsAdditions.cs b/API/Data/Migrations/20210901200442_ReadingListsAdditions.cs new file mode 100644 index 000000000..b44c2ac4d --- /dev/null +++ b/API/Data/Migrations/20210901200442_ReadingListsAdditions.cs @@ -0,0 +1,55 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +namespace API.Data.Migrations +{ + public partial class ReadingListsAdditions : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_ReadingListItem_ReadingList_ReadingListId", + table: "ReadingListItem"); + + migrationBuilder.AlterColumn( + name: "ReadingListId", + table: "ReadingListItem", + type: "INTEGER", + nullable: false, + defaultValue: 0, + oldClrType: typeof(int), + oldType: "INTEGER", + oldNullable: true); + + migrationBuilder.AddForeignKey( + name: "FK_ReadingListItem_ReadingList_ReadingListId", + table: "ReadingListItem", + column: "ReadingListId", + principalTable: "ReadingList", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_ReadingListItem_ReadingList_ReadingListId", + table: "ReadingListItem"); + + migrationBuilder.AlterColumn( + name: "ReadingListId", + table: "ReadingListItem", + type: "INTEGER", + nullable: true, + oldClrType: typeof(int), + oldType: "INTEGER"); + + migrationBuilder.AddForeignKey( + name: "FK_ReadingListItem_ReadingList_ReadingListId", + table: "ReadingListItem", + column: "ReadingListId", + principalTable: "ReadingList", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + } + } +} diff --git a/API/Data/Migrations/20210902110705_ReadingListsExtraRealationships.Designer.cs b/API/Data/Migrations/20210902110705_ReadingListsExtraRealationships.Designer.cs new file mode 100644 index 000000000..566d2c5be --- /dev/null +++ b/API/Data/Migrations/20210902110705_ReadingListsExtraRealationships.Designer.cs @@ -0,0 +1,1050 @@ +// +using System; +using API.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +namespace API.Data.Migrations +{ + [DbContext(typeof(DataContext))] + [Migration("20210902110705_ReadingListsExtraRealationships")] + partial class ReadingListsExtraRealationships + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "5.0.8"); + + modelBuilder.Entity("API.Entities.AppRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles"); + }); + + modelBuilder.Entity("API.Entities.AppUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessFailedCount") + .HasColumnType("INTEGER"); + + b.Property("ApiKey") + .HasColumnType("TEXT"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("EmailConfirmed") + .HasColumnType("INTEGER"); + + b.Property("LastActive") + .HasColumnType("TEXT"); + + b.Property("LockoutEnabled") + .HasColumnType("INTEGER"); + + b.Property("LockoutEnd") + .HasColumnType("TEXT"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("PasswordHash") + .HasColumnType("TEXT"); + + b.Property("PhoneNumber") + .HasColumnType("TEXT"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SecurityStamp") + .HasColumnType("TEXT"); + + b.Property("TwoFactorEnabled") + .HasColumnType("INTEGER"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("AspNetUsers"); + }); + + modelBuilder.Entity("API.Entities.AppUserBookmark", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("Page") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("AppUserBookmark"); + }); + + modelBuilder.Entity("API.Entities.AppUserPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("AutoCloseMenu") + .HasColumnType("INTEGER"); + + b.Property("BookReaderDarkMode") + .HasColumnType("INTEGER"); + + b.Property("BookReaderFontFamily") + .HasColumnType("TEXT"); + + b.Property("BookReaderFontSize") + .HasColumnType("INTEGER"); + + b.Property("BookReaderLineSpacing") + .HasColumnType("INTEGER"); + + b.Property("BookReaderMargin") + .HasColumnType("INTEGER"); + + b.Property("BookReaderReadingDirection") + .HasColumnType("INTEGER"); + + b.Property("BookReaderTapToPaginate") + .HasColumnType("INTEGER"); + + b.Property("PageSplitOption") + .HasColumnType("INTEGER"); + + b.Property("ReaderMode") + .HasColumnType("INTEGER"); + + b.Property("ReadingDirection") + .HasColumnType("INTEGER"); + + b.Property("ScalingOption") + .HasColumnType("INTEGER"); + + b.Property("SiteDarkMode") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId") + .IsUnique(); + + b.ToTable("AppUserPreferences"); + }); + + modelBuilder.Entity("API.Entities.AppUserProgress", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("BookScrollId") + .HasColumnType("TEXT"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("PagesRead") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("AppUserProgresses"); + }); + + modelBuilder.Entity("API.Entities.AppUserRating", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("Rating") + .HasColumnType("INTEGER"); + + b.Property("Review") + .HasColumnType("TEXT"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("AppUserRating"); + }); + + modelBuilder.Entity("API.Entities.AppUserRole", b => + { + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles"); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("BLOB"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("IsSpecial") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Number") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("Range") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("VolumeId"); + + b.ToTable("Chapter"); + }); + + modelBuilder.Entity("API.Entities.CollectionTag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("BLOB"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("NormalizedTitle") + .HasColumnType("TEXT"); + + b.Property("Promoted") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Id", "Promoted") + .IsUnique(); + + b.ToTable("CollectionTag"); + }); + + modelBuilder.Entity("API.Entities.FolderPath", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("LastScanned") + .HasColumnType("TEXT"); + + b.Property("LibraryId") + .HasColumnType("INTEGER"); + + b.Property("Path") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("LibraryId"); + + b.ToTable("FolderPath"); + }); + + modelBuilder.Entity("API.Entities.Library", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Library"); + }); + + modelBuilder.Entity("API.Entities.MangaFile", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("FilePath") + .HasColumnType("TEXT"); + + b.Property("Format") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ChapterId"); + + b.ToTable("MangaFile"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Promoted") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("ReadingList"); + }); + + modelBuilder.Entity("API.Entities.ReadingListItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("LibraryId") + .HasColumnType("INTEGER"); + + b.Property("Order") + .HasColumnType("INTEGER"); + + b.Property("ReadingListId") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ChapterId"); + + b.HasIndex("ReadingListId"); + + b.HasIndex("VolumeId"); + + b.HasIndex("SeriesId", "VolumeId", "ChapterId", "LibraryId") + .IsUnique(); + + b.ToTable("ReadingListItem"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("BLOB"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("Format") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("LibraryId") + .HasColumnType("INTEGER"); + + b.Property("LocalizedName") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasColumnType("TEXT"); + + b.Property("OriginalName") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("SortName") + .HasColumnType("TEXT"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("LibraryId"); + + b.HasIndex("Name", "NormalizedName", "LocalizedName", "LibraryId", "Format") + .IsUnique(); + + b.ToTable("Series"); + }); + + modelBuilder.Entity("API.Entities.SeriesMetadata", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("SeriesId") + .IsUnique(); + + b.HasIndex("Id", "SeriesId") + .IsUnique(); + + b.ToTable("SeriesMetadata"); + }); + + modelBuilder.Entity("API.Entities.ServerSetting", b => + { + b.Property("Key") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("Key"); + + b.ToTable("ServerSetting"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("BLOB"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Number") + .HasColumnType("INTEGER"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("SeriesId"); + + b.ToTable("Volume"); + }); + + modelBuilder.Entity("AppUserLibrary", b => + { + b.Property("AppUsersId") + .HasColumnType("INTEGER"); + + b.Property("LibrariesId") + .HasColumnType("INTEGER"); + + b.HasKey("AppUsersId", "LibrariesId"); + + b.HasIndex("LibrariesId"); + + b.ToTable("AppUserLibrary"); + }); + + modelBuilder.Entity("CollectionTagSeriesMetadata", b => + { + b.Property("CollectionTagsId") + .HasColumnType("INTEGER"); + + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.HasKey("CollectionTagsId", "SeriesMetadatasId"); + + b.HasIndex("SeriesMetadatasId"); + + b.ToTable("CollectionTagSeriesMetadata"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("ProviderKey") + .HasColumnType("TEXT"); + + b.Property("ProviderDisplayName") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens"); + }); + + modelBuilder.Entity("API.Entities.AppUserBookmark", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Bookmarks") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserPreferences", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithOne("UserPreferences") + .HasForeignKey("API.Entities.AppUserPreferences", "AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserProgress", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Progresses") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserRating", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Ratings") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserRole", b => + { + b.HasOne("API.Entities.AppRole", "Role") + .WithMany("UserRoles") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.AppUser", "User") + .WithMany("UserRoles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.HasOne("API.Entities.Volume", "Volume") + .WithMany("Chapters") + .HasForeignKey("VolumeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Volume"); + }); + + modelBuilder.Entity("API.Entities.FolderPath", b => + { + b.HasOne("API.Entities.Library", "Library") + .WithMany("Folders") + .HasForeignKey("LibraryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Library"); + }); + + modelBuilder.Entity("API.Entities.MangaFile", b => + { + b.HasOne("API.Entities.Chapter", "Chapter") + .WithMany("Files") + .HasForeignKey("ChapterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Chapter"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("ReadingLists") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.ReadingListItem", b => + { + b.HasOne("API.Entities.Chapter", "Chapter") + .WithMany() + .HasForeignKey("ChapterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.ReadingList", "ReadingList") + .WithMany("Items") + .HasForeignKey("ReadingListId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Series", "Series") + .WithMany() + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Volume", "Volume") + .WithMany() + .HasForeignKey("VolumeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Chapter"); + + b.Navigation("ReadingList"); + + b.Navigation("Series"); + + b.Navigation("Volume"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.HasOne("API.Entities.Library", "Library") + .WithMany("Series") + .HasForeignKey("LibraryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Library"); + }); + + modelBuilder.Entity("API.Entities.SeriesMetadata", b => + { + b.HasOne("API.Entities.Series", "Series") + .WithOne("Metadata") + .HasForeignKey("API.Entities.SeriesMetadata", "SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.HasOne("API.Entities.Series", "Series") + .WithMany("Volumes") + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("AppUserLibrary", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("AppUsersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Library", null) + .WithMany() + .HasForeignKey("LibrariesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("CollectionTagSeriesMetadata", b => + { + b.HasOne("API.Entities.CollectionTag", null) + .WithMany() + .HasForeignKey("CollectionTagsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("API.Entities.AppRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("API.Entities.AppRole", b => + { + b.Navigation("UserRoles"); + }); + + modelBuilder.Entity("API.Entities.AppUser", b => + { + b.Navigation("Bookmarks"); + + b.Navigation("Progresses"); + + b.Navigation("Ratings"); + + b.Navigation("ReadingLists"); + + b.Navigation("UserPreferences"); + + b.Navigation("UserRoles"); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.Navigation("Files"); + }); + + modelBuilder.Entity("API.Entities.Library", b => + { + b.Navigation("Folders"); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.Navigation("Items"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.Navigation("Metadata"); + + b.Navigation("Volumes"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.Navigation("Chapters"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/API/Data/Migrations/20210902110705_ReadingListsExtraRealationships.cs b/API/Data/Migrations/20210902110705_ReadingListsExtraRealationships.cs new file mode 100644 index 000000000..9ddb1b5fc --- /dev/null +++ b/API/Data/Migrations/20210902110705_ReadingListsExtraRealationships.cs @@ -0,0 +1,67 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +namespace API.Data.Migrations +{ + public partial class ReadingListsExtraRealationships : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateIndex( + name: "IX_ReadingListItem_ChapterId", + table: "ReadingListItem", + column: "ChapterId"); + + migrationBuilder.CreateIndex( + name: "IX_ReadingListItem_VolumeId", + table: "ReadingListItem", + column: "VolumeId"); + + migrationBuilder.AddForeignKey( + name: "FK_ReadingListItem_Chapter_ChapterId", + table: "ReadingListItem", + column: "ChapterId", + principalTable: "Chapter", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_ReadingListItem_Series_SeriesId", + table: "ReadingListItem", + column: "SeriesId", + principalTable: "Series", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_ReadingListItem_Volume_VolumeId", + table: "ReadingListItem", + column: "VolumeId", + principalTable: "Volume", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_ReadingListItem_Chapter_ChapterId", + table: "ReadingListItem"); + + migrationBuilder.DropForeignKey( + name: "FK_ReadingListItem_Series_SeriesId", + table: "ReadingListItem"); + + migrationBuilder.DropForeignKey( + name: "FK_ReadingListItem_Volume_VolumeId", + table: "ReadingListItem"); + + migrationBuilder.DropIndex( + name: "IX_ReadingListItem_ChapterId", + table: "ReadingListItem"); + + migrationBuilder.DropIndex( + name: "IX_ReadingListItem_VolumeId", + table: "ReadingListItem"); + } + } +} diff --git a/API/Data/Migrations/20210906140845_ReadingListsChanges.Designer.cs b/API/Data/Migrations/20210906140845_ReadingListsChanges.Designer.cs new file mode 100644 index 000000000..836a496e0 --- /dev/null +++ b/API/Data/Migrations/20210906140845_ReadingListsChanges.Designer.cs @@ -0,0 +1,1046 @@ +// +using System; +using API.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +namespace API.Data.Migrations +{ + [DbContext(typeof(DataContext))] + [Migration("20210906140845_ReadingListsChanges")] + partial class ReadingListsChanges + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "5.0.8"); + + modelBuilder.Entity("API.Entities.AppRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles"); + }); + + modelBuilder.Entity("API.Entities.AppUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessFailedCount") + .HasColumnType("INTEGER"); + + b.Property("ApiKey") + .HasColumnType("TEXT"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("EmailConfirmed") + .HasColumnType("INTEGER"); + + b.Property("LastActive") + .HasColumnType("TEXT"); + + b.Property("LockoutEnabled") + .HasColumnType("INTEGER"); + + b.Property("LockoutEnd") + .HasColumnType("TEXT"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("PasswordHash") + .HasColumnType("TEXT"); + + b.Property("PhoneNumber") + .HasColumnType("TEXT"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SecurityStamp") + .HasColumnType("TEXT"); + + b.Property("TwoFactorEnabled") + .HasColumnType("INTEGER"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("AspNetUsers"); + }); + + modelBuilder.Entity("API.Entities.AppUserBookmark", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("Page") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("AppUserBookmark"); + }); + + modelBuilder.Entity("API.Entities.AppUserPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("AutoCloseMenu") + .HasColumnType("INTEGER"); + + b.Property("BookReaderDarkMode") + .HasColumnType("INTEGER"); + + b.Property("BookReaderFontFamily") + .HasColumnType("TEXT"); + + b.Property("BookReaderFontSize") + .HasColumnType("INTEGER"); + + b.Property("BookReaderLineSpacing") + .HasColumnType("INTEGER"); + + b.Property("BookReaderMargin") + .HasColumnType("INTEGER"); + + b.Property("BookReaderReadingDirection") + .HasColumnType("INTEGER"); + + b.Property("BookReaderTapToPaginate") + .HasColumnType("INTEGER"); + + b.Property("PageSplitOption") + .HasColumnType("INTEGER"); + + b.Property("ReaderMode") + .HasColumnType("INTEGER"); + + b.Property("ReadingDirection") + .HasColumnType("INTEGER"); + + b.Property("ScalingOption") + .HasColumnType("INTEGER"); + + b.Property("SiteDarkMode") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId") + .IsUnique(); + + b.ToTable("AppUserPreferences"); + }); + + modelBuilder.Entity("API.Entities.AppUserProgress", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("BookScrollId") + .HasColumnType("TEXT"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("PagesRead") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("AppUserProgresses"); + }); + + modelBuilder.Entity("API.Entities.AppUserRating", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("Rating") + .HasColumnType("INTEGER"); + + b.Property("Review") + .HasColumnType("TEXT"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("AppUserRating"); + }); + + modelBuilder.Entity("API.Entities.AppUserRole", b => + { + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles"); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("BLOB"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("IsSpecial") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Number") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("Range") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("VolumeId"); + + b.ToTable("Chapter"); + }); + + modelBuilder.Entity("API.Entities.CollectionTag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("BLOB"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("NormalizedTitle") + .HasColumnType("TEXT"); + + b.Property("Promoted") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Id", "Promoted") + .IsUnique(); + + b.ToTable("CollectionTag"); + }); + + modelBuilder.Entity("API.Entities.FolderPath", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("LastScanned") + .HasColumnType("TEXT"); + + b.Property("LibraryId") + .HasColumnType("INTEGER"); + + b.Property("Path") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("LibraryId"); + + b.ToTable("FolderPath"); + }); + + modelBuilder.Entity("API.Entities.Library", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Library"); + }); + + modelBuilder.Entity("API.Entities.MangaFile", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("FilePath") + .HasColumnType("TEXT"); + + b.Property("Format") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ChapterId"); + + b.ToTable("MangaFile"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Promoted") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("ReadingList"); + }); + + modelBuilder.Entity("API.Entities.ReadingListItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("Order") + .HasColumnType("INTEGER"); + + b.Property("ReadingListId") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ChapterId"); + + b.HasIndex("ReadingListId"); + + b.HasIndex("SeriesId"); + + b.HasIndex("VolumeId"); + + b.ToTable("ReadingListItem"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("BLOB"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("Format") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("LibraryId") + .HasColumnType("INTEGER"); + + b.Property("LocalizedName") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasColumnType("TEXT"); + + b.Property("OriginalName") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("SortName") + .HasColumnType("TEXT"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("LibraryId"); + + b.HasIndex("Name", "NormalizedName", "LocalizedName", "LibraryId", "Format") + .IsUnique(); + + b.ToTable("Series"); + }); + + modelBuilder.Entity("API.Entities.SeriesMetadata", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("SeriesId") + .IsUnique(); + + b.HasIndex("Id", "SeriesId") + .IsUnique(); + + b.ToTable("SeriesMetadata"); + }); + + modelBuilder.Entity("API.Entities.ServerSetting", b => + { + b.Property("Key") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("Key"); + + b.ToTable("ServerSetting"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("BLOB"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Number") + .HasColumnType("INTEGER"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("SeriesId"); + + b.ToTable("Volume"); + }); + + modelBuilder.Entity("AppUserLibrary", b => + { + b.Property("AppUsersId") + .HasColumnType("INTEGER"); + + b.Property("LibrariesId") + .HasColumnType("INTEGER"); + + b.HasKey("AppUsersId", "LibrariesId"); + + b.HasIndex("LibrariesId"); + + b.ToTable("AppUserLibrary"); + }); + + modelBuilder.Entity("CollectionTagSeriesMetadata", b => + { + b.Property("CollectionTagsId") + .HasColumnType("INTEGER"); + + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.HasKey("CollectionTagsId", "SeriesMetadatasId"); + + b.HasIndex("SeriesMetadatasId"); + + b.ToTable("CollectionTagSeriesMetadata"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("ProviderKey") + .HasColumnType("TEXT"); + + b.Property("ProviderDisplayName") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens"); + }); + + modelBuilder.Entity("API.Entities.AppUserBookmark", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Bookmarks") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserPreferences", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithOne("UserPreferences") + .HasForeignKey("API.Entities.AppUserPreferences", "AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserProgress", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Progresses") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserRating", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Ratings") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserRole", b => + { + b.HasOne("API.Entities.AppRole", "Role") + .WithMany("UserRoles") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.AppUser", "User") + .WithMany("UserRoles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.HasOne("API.Entities.Volume", "Volume") + .WithMany("Chapters") + .HasForeignKey("VolumeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Volume"); + }); + + modelBuilder.Entity("API.Entities.FolderPath", b => + { + b.HasOne("API.Entities.Library", "Library") + .WithMany("Folders") + .HasForeignKey("LibraryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Library"); + }); + + modelBuilder.Entity("API.Entities.MangaFile", b => + { + b.HasOne("API.Entities.Chapter", "Chapter") + .WithMany("Files") + .HasForeignKey("ChapterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Chapter"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("ReadingLists") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.ReadingListItem", b => + { + b.HasOne("API.Entities.Chapter", "Chapter") + .WithMany() + .HasForeignKey("ChapterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.ReadingList", "ReadingList") + .WithMany("Items") + .HasForeignKey("ReadingListId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Series", "Series") + .WithMany() + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Volume", "Volume") + .WithMany() + .HasForeignKey("VolumeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Chapter"); + + b.Navigation("ReadingList"); + + b.Navigation("Series"); + + b.Navigation("Volume"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.HasOne("API.Entities.Library", "Library") + .WithMany("Series") + .HasForeignKey("LibraryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Library"); + }); + + modelBuilder.Entity("API.Entities.SeriesMetadata", b => + { + b.HasOne("API.Entities.Series", "Series") + .WithOne("Metadata") + .HasForeignKey("API.Entities.SeriesMetadata", "SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.HasOne("API.Entities.Series", "Series") + .WithMany("Volumes") + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("AppUserLibrary", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("AppUsersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Library", null) + .WithMany() + .HasForeignKey("LibrariesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("CollectionTagSeriesMetadata", b => + { + b.HasOne("API.Entities.CollectionTag", null) + .WithMany() + .HasForeignKey("CollectionTagsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("API.Entities.AppRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("API.Entities.AppRole", b => + { + b.Navigation("UserRoles"); + }); + + modelBuilder.Entity("API.Entities.AppUser", b => + { + b.Navigation("Bookmarks"); + + b.Navigation("Progresses"); + + b.Navigation("Ratings"); + + b.Navigation("ReadingLists"); + + b.Navigation("UserPreferences"); + + b.Navigation("UserRoles"); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.Navigation("Files"); + }); + + modelBuilder.Entity("API.Entities.Library", b => + { + b.Navigation("Folders"); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.Navigation("Items"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.Navigation("Metadata"); + + b.Navigation("Volumes"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.Navigation("Chapters"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/API/Data/Migrations/20210906140845_ReadingListsChanges.cs b/API/Data/Migrations/20210906140845_ReadingListsChanges.cs new file mode 100644 index 000000000..e4ea07e2e --- /dev/null +++ b/API/Data/Migrations/20210906140845_ReadingListsChanges.cs @@ -0,0 +1,43 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +namespace API.Data.Migrations +{ + public partial class ReadingListsChanges : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "IX_ReadingListItem_SeriesId_VolumeId_ChapterId_LibraryId", + table: "ReadingListItem"); + + migrationBuilder.DropColumn( + name: "LibraryId", + table: "ReadingListItem"); + + migrationBuilder.CreateIndex( + name: "IX_ReadingListItem_SeriesId", + table: "ReadingListItem", + column: "SeriesId"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "IX_ReadingListItem_SeriesId", + table: "ReadingListItem"); + + migrationBuilder.AddColumn( + name: "LibraryId", + table: "ReadingListItem", + type: "INTEGER", + nullable: false, + defaultValue: 0); + + migrationBuilder.CreateIndex( + name: "IX_ReadingListItem_SeriesId_VolumeId_ChapterId_LibraryId", + table: "ReadingListItem", + columns: new[] { "SeriesId", "VolumeId", "ChapterId", "LibraryId" }, + unique: true); + } + } +} diff --git a/API/Data/Migrations/20210916142418_EntityImageRefactor.Designer.cs b/API/Data/Migrations/20210916142418_EntityImageRefactor.Designer.cs new file mode 100644 index 000000000..b4c6f62f1 --- /dev/null +++ b/API/Data/Migrations/20210916142418_EntityImageRefactor.Designer.cs @@ -0,0 +1,1042 @@ +// +using System; +using API.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +namespace API.Data.Migrations +{ + [DbContext(typeof(DataContext))] + [Migration("20210916142418_EntityImageRefactor")] + partial class EntityImageRefactor + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "5.0.8"); + + modelBuilder.Entity("API.Entities.AppRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles"); + }); + + modelBuilder.Entity("API.Entities.AppUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessFailedCount") + .HasColumnType("INTEGER"); + + b.Property("ApiKey") + .HasColumnType("TEXT"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("EmailConfirmed") + .HasColumnType("INTEGER"); + + b.Property("LastActive") + .HasColumnType("TEXT"); + + b.Property("LockoutEnabled") + .HasColumnType("INTEGER"); + + b.Property("LockoutEnd") + .HasColumnType("TEXT"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("PasswordHash") + .HasColumnType("TEXT"); + + b.Property("PhoneNumber") + .HasColumnType("TEXT"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SecurityStamp") + .HasColumnType("TEXT"); + + b.Property("TwoFactorEnabled") + .HasColumnType("INTEGER"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("AspNetUsers"); + }); + + modelBuilder.Entity("API.Entities.AppUserBookmark", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("Page") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("AppUserBookmark"); + }); + + modelBuilder.Entity("API.Entities.AppUserPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("AutoCloseMenu") + .HasColumnType("INTEGER"); + + b.Property("BookReaderDarkMode") + .HasColumnType("INTEGER"); + + b.Property("BookReaderFontFamily") + .HasColumnType("TEXT"); + + b.Property("BookReaderFontSize") + .HasColumnType("INTEGER"); + + b.Property("BookReaderLineSpacing") + .HasColumnType("INTEGER"); + + b.Property("BookReaderMargin") + .HasColumnType("INTEGER"); + + b.Property("BookReaderReadingDirection") + .HasColumnType("INTEGER"); + + b.Property("BookReaderTapToPaginate") + .HasColumnType("INTEGER"); + + b.Property("PageSplitOption") + .HasColumnType("INTEGER"); + + b.Property("ReaderMode") + .HasColumnType("INTEGER"); + + b.Property("ReadingDirection") + .HasColumnType("INTEGER"); + + b.Property("ScalingOption") + .HasColumnType("INTEGER"); + + b.Property("SiteDarkMode") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId") + .IsUnique(); + + b.ToTable("AppUserPreferences"); + }); + + modelBuilder.Entity("API.Entities.AppUserProgress", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("BookScrollId") + .HasColumnType("TEXT"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("PagesRead") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("AppUserProgresses"); + }); + + modelBuilder.Entity("API.Entities.AppUserRating", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("Rating") + .HasColumnType("INTEGER"); + + b.Property("Review") + .HasColumnType("TEXT"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("AppUserRating"); + }); + + modelBuilder.Entity("API.Entities.AppUserRole", b => + { + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles"); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("IsSpecial") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Number") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("Range") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("VolumeId"); + + b.ToTable("Chapter"); + }); + + modelBuilder.Entity("API.Entities.CollectionTag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("NormalizedTitle") + .HasColumnType("TEXT"); + + b.Property("Promoted") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Id", "Promoted") + .IsUnique(); + + b.ToTable("CollectionTag"); + }); + + modelBuilder.Entity("API.Entities.FolderPath", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("LastScanned") + .HasColumnType("TEXT"); + + b.Property("LibraryId") + .HasColumnType("INTEGER"); + + b.Property("Path") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("LibraryId"); + + b.ToTable("FolderPath"); + }); + + modelBuilder.Entity("API.Entities.Library", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Library"); + }); + + modelBuilder.Entity("API.Entities.MangaFile", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("FilePath") + .HasColumnType("TEXT"); + + b.Property("Format") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ChapterId"); + + b.ToTable("MangaFile"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Promoted") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("ReadingList"); + }); + + modelBuilder.Entity("API.Entities.ReadingListItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("Order") + .HasColumnType("INTEGER"); + + b.Property("ReadingListId") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ChapterId"); + + b.HasIndex("ReadingListId"); + + b.HasIndex("SeriesId"); + + b.HasIndex("VolumeId"); + + b.ToTable("ReadingListItem"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("Format") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("LibraryId") + .HasColumnType("INTEGER"); + + b.Property("LocalizedName") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasColumnType("TEXT"); + + b.Property("OriginalName") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("SortName") + .HasColumnType("TEXT"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("LibraryId"); + + b.HasIndex("Name", "NormalizedName", "LocalizedName", "LibraryId", "Format") + .IsUnique(); + + b.ToTable("Series"); + }); + + modelBuilder.Entity("API.Entities.SeriesMetadata", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("SeriesId") + .IsUnique(); + + b.HasIndex("Id", "SeriesId") + .IsUnique(); + + b.ToTable("SeriesMetadata"); + }); + + modelBuilder.Entity("API.Entities.ServerSetting", b => + { + b.Property("Key") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("Key"); + + b.ToTable("ServerSetting"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Number") + .HasColumnType("INTEGER"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("SeriesId"); + + b.ToTable("Volume"); + }); + + modelBuilder.Entity("AppUserLibrary", b => + { + b.Property("AppUsersId") + .HasColumnType("INTEGER"); + + b.Property("LibrariesId") + .HasColumnType("INTEGER"); + + b.HasKey("AppUsersId", "LibrariesId"); + + b.HasIndex("LibrariesId"); + + b.ToTable("AppUserLibrary"); + }); + + modelBuilder.Entity("CollectionTagSeriesMetadata", b => + { + b.Property("CollectionTagsId") + .HasColumnType("INTEGER"); + + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.HasKey("CollectionTagsId", "SeriesMetadatasId"); + + b.HasIndex("SeriesMetadatasId"); + + b.ToTable("CollectionTagSeriesMetadata"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("ProviderKey") + .HasColumnType("TEXT"); + + b.Property("ProviderDisplayName") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens"); + }); + + modelBuilder.Entity("API.Entities.AppUserBookmark", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Bookmarks") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserPreferences", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithOne("UserPreferences") + .HasForeignKey("API.Entities.AppUserPreferences", "AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserProgress", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Progresses") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserRating", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Ratings") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserRole", b => + { + b.HasOne("API.Entities.AppRole", "Role") + .WithMany("UserRoles") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.AppUser", "User") + .WithMany("UserRoles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.HasOne("API.Entities.Volume", "Volume") + .WithMany("Chapters") + .HasForeignKey("VolumeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Volume"); + }); + + modelBuilder.Entity("API.Entities.FolderPath", b => + { + b.HasOne("API.Entities.Library", "Library") + .WithMany("Folders") + .HasForeignKey("LibraryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Library"); + }); + + modelBuilder.Entity("API.Entities.MangaFile", b => + { + b.HasOne("API.Entities.Chapter", "Chapter") + .WithMany("Files") + .HasForeignKey("ChapterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Chapter"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("ReadingLists") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.ReadingListItem", b => + { + b.HasOne("API.Entities.Chapter", "Chapter") + .WithMany() + .HasForeignKey("ChapterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.ReadingList", "ReadingList") + .WithMany("Items") + .HasForeignKey("ReadingListId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Series", "Series") + .WithMany() + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Volume", "Volume") + .WithMany() + .HasForeignKey("VolumeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Chapter"); + + b.Navigation("ReadingList"); + + b.Navigation("Series"); + + b.Navigation("Volume"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.HasOne("API.Entities.Library", "Library") + .WithMany("Series") + .HasForeignKey("LibraryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Library"); + }); + + modelBuilder.Entity("API.Entities.SeriesMetadata", b => + { + b.HasOne("API.Entities.Series", "Series") + .WithOne("Metadata") + .HasForeignKey("API.Entities.SeriesMetadata", "SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.HasOne("API.Entities.Series", "Series") + .WithMany("Volumes") + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("AppUserLibrary", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("AppUsersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Library", null) + .WithMany() + .HasForeignKey("LibrariesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("CollectionTagSeriesMetadata", b => + { + b.HasOne("API.Entities.CollectionTag", null) + .WithMany() + .HasForeignKey("CollectionTagsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("API.Entities.AppRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("API.Entities.AppRole", b => + { + b.Navigation("UserRoles"); + }); + + modelBuilder.Entity("API.Entities.AppUser", b => + { + b.Navigation("Bookmarks"); + + b.Navigation("Progresses"); + + b.Navigation("Ratings"); + + b.Navigation("ReadingLists"); + + b.Navigation("UserPreferences"); + + b.Navigation("UserRoles"); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.Navigation("Files"); + }); + + modelBuilder.Entity("API.Entities.Library", b => + { + b.Navigation("Folders"); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.Navigation("Items"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.Navigation("Metadata"); + + b.Navigation("Volumes"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.Navigation("Chapters"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/API/Data/Migrations/20210916142418_EntityImageRefactor.cs b/API/Data/Migrations/20210916142418_EntityImageRefactor.cs new file mode 100644 index 000000000..deafb134b --- /dev/null +++ b/API/Data/Migrations/20210916142418_EntityImageRefactor.cs @@ -0,0 +1,97 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace API.Data.Migrations +{ + public partial class EntityImageRefactor : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "RowVersion", + table: "AppUserProgresses"); + + migrationBuilder.AlterColumn( + name: "CoverImage", + table: "Volume", + type: "TEXT", + nullable: true, + oldClrType: typeof(byte[]), + oldType: "BLOB", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "CoverImage", + table: "Series", + type: "TEXT", + nullable: true, + oldClrType: typeof(byte[]), + oldType: "BLOB", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "CoverImage", + table: "CollectionTag", + type: "TEXT", + nullable: true, + oldClrType: typeof(byte[]), + oldType: "BLOB", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "CoverImage", + table: "Chapter", + type: "TEXT", + nullable: true, + oldClrType: typeof(byte[]), + oldType: "BLOB", + oldNullable: true); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "CoverImage", + table: "Volume", + type: "BLOB", + nullable: true, + oldClrType: typeof(string), + oldType: "TEXT", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "CoverImage", + table: "Series", + type: "BLOB", + nullable: true, + oldClrType: typeof(string), + oldType: "TEXT", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "CoverImage", + table: "CollectionTag", + type: "BLOB", + nullable: true, + oldClrType: typeof(string), + oldType: "TEXT", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "CoverImage", + table: "Chapter", + type: "BLOB", + nullable: true, + oldClrType: typeof(string), + oldType: "TEXT", + oldNullable: true); + + migrationBuilder.AddColumn( + name: "RowVersion", + table: "AppUserProgresses", + type: "INTEGER", + nullable: false, + defaultValue: 0u); + } + } +} diff --git a/API/Data/Migrations/DataContextModelSnapshot.cs b/API/Data/Migrations/DataContextModelSnapshot.cs index 9f763c03b..38a09633e 100644 --- a/API/Data/Migrations/DataContextModelSnapshot.cs +++ b/API/Data/Migrations/DataContextModelSnapshot.cs @@ -229,10 +229,6 @@ namespace API.Data.Migrations b.Property("PagesRead") .HasColumnType("INTEGER"); - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - b.Property("SeriesId") .HasColumnType("INTEGER"); @@ -292,8 +288,8 @@ namespace API.Data.Migrations .ValueGeneratedOnAdd() .HasColumnType("INTEGER"); - b.Property("CoverImage") - .HasColumnType("BLOB"); + b.Property("CoverImage") + .HasColumnType("TEXT"); b.Property("CoverImageLocked") .HasColumnType("INTEGER"); @@ -335,8 +331,8 @@ namespace API.Data.Migrations .ValueGeneratedOnAdd() .HasColumnType("INTEGER"); - b.Property("CoverImage") - .HasColumnType("BLOB"); + b.Property("CoverImage") + .HasColumnType("TEXT"); b.Property("CoverImageLocked") .HasColumnType("INTEGER"); @@ -440,14 +436,79 @@ namespace API.Data.Migrations b.ToTable("MangaFile"); }); + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Promoted") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("ReadingList"); + }); + + modelBuilder.Entity("API.Entities.ReadingListItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("Order") + .HasColumnType("INTEGER"); + + b.Property("ReadingListId") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ChapterId"); + + b.HasIndex("ReadingListId"); + + b.HasIndex("SeriesId"); + + b.HasIndex("VolumeId"); + + b.ToTable("ReadingListItem"); + }); + modelBuilder.Entity("API.Entities.Series", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("INTEGER"); - b.Property("CoverImage") - .HasColumnType("BLOB"); + b.Property("CoverImage") + .HasColumnType("TEXT"); b.Property("CoverImageLocked") .HasColumnType("INTEGER"); @@ -542,8 +603,8 @@ namespace API.Data.Migrations .ValueGeneratedOnAdd() .HasColumnType("INTEGER"); - b.Property("CoverImage") - .HasColumnType("BLOB"); + b.Property("CoverImage") + .HasColumnType("TEXT"); b.Property("Created") .HasColumnType("TEXT"); @@ -780,6 +841,52 @@ namespace API.Data.Migrations b.Navigation("Chapter"); }); + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("ReadingLists") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.ReadingListItem", b => + { + b.HasOne("API.Entities.Chapter", "Chapter") + .WithMany() + .HasForeignKey("ChapterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.ReadingList", "ReadingList") + .WithMany("Items") + .HasForeignKey("ReadingListId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Series", "Series") + .WithMany() + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Volume", "Volume") + .WithMany() + .HasForeignKey("VolumeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Chapter"); + + b.Navigation("ReadingList"); + + b.Navigation("Series"); + + b.Navigation("Volume"); + }); + modelBuilder.Entity("API.Entities.Series", b => { b.HasOne("API.Entities.Library", "Library") @@ -892,6 +999,8 @@ namespace API.Data.Migrations b.Navigation("Ratings"); + b.Navigation("ReadingLists"); + b.Navigation("UserPreferences"); b.Navigation("UserRoles"); @@ -909,6 +1018,11 @@ namespace API.Data.Migrations b.Navigation("Series"); }); + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.Navigation("Items"); + }); + modelBuilder.Entity("API.Entities.Series", b => { b.Navigation("Metadata"); diff --git a/API/Data/AppUserProgressRepository.cs b/API/Data/Repositories/AppUserProgressRepository.cs similarity index 65% rename from API/Data/AppUserProgressRepository.cs rename to API/Data/Repositories/AppUserProgressRepository.cs index 38912b589..c91e61cd0 100644 --- a/API/Data/AppUserProgressRepository.cs +++ b/API/Data/Repositories/AppUserProgressRepository.cs @@ -1,10 +1,11 @@ using System.Linq; using System.Threading.Tasks; +using API.Entities; using API.Entities.Enums; -using API.Interfaces; +using API.Interfaces.Repositories; using Microsoft.EntityFrameworkCore; -namespace API.Data +namespace API.Data.Repositories { public class AppUserProgressRepository : IAppUserProgressRepository { @@ -15,6 +16,11 @@ namespace API.Data _context = context; } + public void Update(AppUserProgress userProgress) + { + _context.Entry(userProgress).State = EntityState.Modified; + } + /// /// This will remove any entries that have chapterIds that no longer exists. This will execute the save as well. /// @@ -25,8 +31,18 @@ namespace API.Data var rowsToRemove = await _context.AppUserProgresses .Where(progress => !chapterIds.Contains(progress.ChapterId)) .ToListAsync(); - + + var rowsToRemoveBookmarks = await _context.AppUserBookmark + .Where(progress => !chapterIds.Contains(progress.ChapterId)) + .ToListAsync(); + + var rowsToRemoveReadingLists = await _context.ReadingListItem + .Where(item => !chapterIds.Contains(item.ChapterId)) + .ToListAsync(); + _context.RemoveRange(rowsToRemove); + _context.RemoveRange(rowsToRemoveBookmarks); + _context.RemoveRange(rowsToRemoveReadingLists); return await _context.SaveChangesAsync() > 0 ? rowsToRemove.Count : 0; } @@ -45,12 +61,19 @@ namespace API.Data .ToListAsync(); if (seriesIds.Count == 0) return false; - + return await _context.Series .Include(s => s.Library) .Where(s => seriesIds.Contains(s.Id) && s.Library.Type == libraryType) .AsNoTracking() .AnyAsync(); } + + public async Task GetUserProgressAsync(int chapterId, int userId) + { + return await _context.AppUserProgresses + .Where(p => p.ChapterId == chapterId && p.AppUserId == userId) + .FirstOrDefaultAsync(); + } } -} \ No newline at end of file +} diff --git a/API/Data/Repositories/ChapterRepository.cs b/API/Data/Repositories/ChapterRepository.cs new file mode 100644 index 000000000..f1905eaa8 --- /dev/null +++ b/API/Data/Repositories/ChapterRepository.cs @@ -0,0 +1,191 @@ +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using API.DTOs; +using API.DTOs.Reader; +using API.Entities; +using API.Interfaces.Repositories; +using AutoMapper; +using AutoMapper.QueryableExtensions; +using Microsoft.EntityFrameworkCore; + +namespace API.Data.Repositories +{ + public class ChapterRepository : IChapterRepository + { + private readonly DataContext _context; + private readonly IMapper _mapper; + + public ChapterRepository(DataContext context, IMapper mapper) + { + _context = context; + _mapper = mapper; + } + + public void Update(Chapter chapter) + { + _context.Entry(chapter).State = EntityState.Modified; + } + + public async Task> GetChaptersByIdsAsync(IList chapterIds) + { + return await _context.Chapter + .Where(c => chapterIds.Contains(c.Id)) + .Include(c => c.Volume) + .ToListAsync(); + } + + /// + /// Populates a partial IChapterInfoDto + /// + /// + public async Task GetChapterInfoDtoAsync(int chapterId) + { + return await _context.Chapter + .Where(c => c.Id == chapterId) + .Join(_context.Volume, c => c.VolumeId, v => v.Id, (chapter, volume) => new + { + ChapterNumber = chapter.Range, + VolumeNumber = volume.Number, + VolumeId = volume.Id, + chapter.IsSpecial, + volume.SeriesId, + chapter.Pages + }) + .Join(_context.Series, data => data.SeriesId, series => series.Id, (data, series) => new + { + data.ChapterNumber, + data.VolumeNumber, + data.VolumeId, + data.IsSpecial, + data.SeriesId, + data.Pages, + SeriesFormat = series.Format, + SeriesName = series.Name, + series.LibraryId + }) + .Select(data => new BookInfoDto() + { + ChapterNumber = data.ChapterNumber, + VolumeNumber = data.VolumeNumber + string.Empty, + VolumeId = data.VolumeId, + IsSpecial = data.IsSpecial, + SeriesId =data.SeriesId, + SeriesFormat = data.SeriesFormat, + SeriesName = data.SeriesName, + LibraryId = data.LibraryId, + Pages = data.Pages + }) + .AsNoTracking() + .SingleAsync(); + } + + public Task GetChapterTotalPagesAsync(int chapterId) + { + return _context.Chapter + .Where(c => c.Id == chapterId) + .Select(c => c.Pages) + .SingleOrDefaultAsync(); + } + public async Task GetChapterDtoAsync(int chapterId) + { + var chapter = await _context.Chapter + .Include(c => c.Files) + .ProjectTo(_mapper.ConfigurationProvider) + .AsNoTracking() + .SingleOrDefaultAsync(c => c.Id == chapterId); + + return chapter; + } + + /// + /// Returns non-tracked files for a given chapterId + /// + /// + /// + public async Task> GetFilesForChapterAsync(int chapterId) + { + return await _context.MangaFile + .Where(c => chapterId == c.ChapterId) + .AsNoTracking() + .ToListAsync(); + } + + /// + /// Returns a Chapter for an Id. Includes linked s. + /// + /// + /// + public async Task GetChapterAsync(int chapterId) + { + return await _context.Chapter + .Include(c => c.Files) + .SingleOrDefaultAsync(c => c.Id == chapterId); + } + + /// + /// Returns Chapters for a volume id. + /// + /// + /// + public async Task> GetChaptersAsync(int volumeId) + { + return await _context.Chapter + .Where(c => c.VolumeId == volumeId) + .ToListAsync(); + } + + /// + /// Returns the cover image for a chapter id. + /// + /// + /// + public async Task GetChapterCoverImageAsync(int chapterId) + { + + return await _context.Chapter + .Where(c => c.Id == chapterId) + .Select(c => c.CoverImage) + .AsNoTracking() + .SingleOrDefaultAsync(); + } + + public async Task> GetAllCoverImagesAsync() + { + return await _context.Chapter + .Select(c => c.CoverImage) + .Where(t => !string.IsNullOrEmpty(t)) + .AsNoTracking() + .ToListAsync(); + } + + /// + /// Returns cover images for locked chapters + /// + /// + public async Task> GetCoverImagesForLockedChaptersAsync() + { + return await _context.Chapter + .Where(c => c.CoverImageLocked) + .Select(c => c.CoverImage) + .Where(t => !string.IsNullOrEmpty(t)) + .AsNoTracking() + .ToListAsync(); + } + + /// + /// Returns non-tracked files for a set of + /// + /// List of chapter Ids + /// + public async Task> GetFilesForChaptersAsync(IReadOnlyList chapterIds) + { + return await _context.MangaFile + .Where(c => chapterIds.Contains(c.ChapterId)) + .AsNoTracking() + .ToListAsync(); + } + } +} diff --git a/API/Data/CollectionTagRepository.cs b/API/Data/Repositories/CollectionTagRepository.cs similarity index 87% rename from API/Data/CollectionTagRepository.cs rename to API/Data/Repositories/CollectionTagRepository.cs index b694b0bb8..777e82788 100644 --- a/API/Data/CollectionTagRepository.cs +++ b/API/Data/Repositories/CollectionTagRepository.cs @@ -1,14 +1,15 @@ using System.Collections.Generic; +using System.IO; using System.Linq; using System.Threading.Tasks; using API.DTOs; using API.Entities; -using API.Interfaces; +using API.Interfaces.Repositories; using AutoMapper; using AutoMapper.QueryableExtensions; using Microsoft.EntityFrameworkCore; -namespace API.Data +namespace API.Data.Repositories { public class CollectionTagRepository : ICollectionTagRepository { @@ -48,11 +49,19 @@ namespace API.Data public async Task> GetAllTagsAsync() { return await _context.CollectionTag - .Select(c => c) .OrderBy(c => c.NormalizedTitle) .ToListAsync(); } + public async Task> GetAllCoverImagesAsync() + { + return await _context.CollectionTag + .Select(t => t.CoverImage) + .Where(t => !string.IsNullOrEmpty(t)) + .AsNoTracking() + .ToListAsync(); + } + public async Task> GetAllTagDtosAsync() { return await _context.CollectionTag @@ -100,9 +109,9 @@ namespace API.Data .ToListAsync(); } - public Task GetCoverImageAsync(int collectionTagId) + public async Task GetCoverImageAsync(int collectionTagId) { - return _context.CollectionTag + return await _context.CollectionTag .Where(c => c.Id == collectionTagId) .Select(c => c.CoverImage) .AsNoTracking() diff --git a/API/Data/FileRepository.cs b/API/Data/Repositories/FileRepository.cs similarity index 92% rename from API/Data/FileRepository.cs rename to API/Data/Repositories/FileRepository.cs index c3234abba..4665dac7e 100644 --- a/API/Data/FileRepository.cs +++ b/API/Data/Repositories/FileRepository.cs @@ -2,10 +2,10 @@ using System.IO; using System.Linq; using System.Threading.Tasks; -using API.Interfaces; +using API.Interfaces.Repositories; using Microsoft.EntityFrameworkCore; -namespace API.Data +namespace API.Data.Repositories { public class FileRepository : IFileRepository { diff --git a/API/Data/LibraryRepository.cs b/API/Data/Repositories/LibraryRepository.cs similarity index 98% rename from API/Data/LibraryRepository.cs rename to API/Data/Repositories/LibraryRepository.cs index 23ad6ea76..7f3544aee 100644 --- a/API/Data/LibraryRepository.cs +++ b/API/Data/Repositories/LibraryRepository.cs @@ -4,12 +4,12 @@ using System.Threading.Tasks; using API.DTOs; using API.Entities; using API.Entities.Enums; -using API.Interfaces; +using API.Interfaces.Repositories; using AutoMapper; using AutoMapper.QueryableExtensions; using Microsoft.EntityFrameworkCore; -namespace API.Data +namespace API.Data.Repositories { public class LibraryRepository : ILibraryRepository { diff --git a/API/Data/Repositories/ReadingListRepository.cs b/API/Data/Repositories/ReadingListRepository.cs new file mode 100644 index 000000000..4f44bc943 --- /dev/null +++ b/API/Data/Repositories/ReadingListRepository.cs @@ -0,0 +1,178 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using API.DTOs.ReadingLists; +using API.Entities; +using API.Helpers; +using API.Interfaces.Repositories; +using AutoMapper; +using AutoMapper.QueryableExtensions; +using Microsoft.EntityFrameworkCore; + +namespace API.Data.Repositories +{ + public class ReadingListRepository : IReadingListRepository + { + private readonly DataContext _context; + private readonly IMapper _mapper; + + public ReadingListRepository(DataContext context, IMapper mapper) + { + _context = context; + _mapper = mapper; + } + + public void Update(ReadingList list) + { + _context.Entry(list).State = EntityState.Modified; + } + + public void Remove(ReadingListItem item) + { + _context.ReadingListItem.Remove(item); + } + + public void BulkRemove(IEnumerable items) + { + _context.ReadingListItem.RemoveRange(items); + } + + + public async Task> GetReadingListDtosForUserAsync(int userId, bool includePromoted, UserParams userParams) + { + var query = _context.ReadingList + .Where(l => l.AppUserId == userId || (includePromoted && l.Promoted )) + .OrderBy(l => l.LastModified) + .ProjectTo(_mapper.ConfigurationProvider) + .AsNoTracking(); + + return await PagedList.CreateAsync(query, userParams.PageNumber, userParams.PageSize); + } + + public async Task GetReadingListByIdAsync(int readingListId) + { + return await _context.ReadingList + .Where(r => r.Id == readingListId) + .Include(r => r.Items) + .SingleOrDefaultAsync(); + } + + public async Task> GetReadingListItemDtosByIdAsync(int readingListId, int userId) + { + var userLibraries = _context.Library + .Include(l => l.AppUsers) + .Where(library => library.AppUsers.Any(user => user.Id == userId)) + .AsNoTracking() + .Select(library => library.Id) + .ToList(); + + var items = await _context.ReadingListItem + .Where(s => s.ReadingListId == readingListId) + .Join(_context.Chapter, s => s.ChapterId, chapter => chapter.Id, (data, chapter) => new + { + TotalPages = chapter.Pages, + ChapterNumber = chapter.Range, + readingListItem = data + }) + .Join(_context.Volume, s => s.readingListItem.VolumeId, volume => volume.Id, (data, volume) => new + { + data.readingListItem, + data.TotalPages, + data.ChapterNumber, + VolumeId = volume.Id, + VolumeNumber = volume.Name, + }) + .Join(_context.Series, s => s.readingListItem.SeriesId, series => series.Id, + (data, s) => new + { + SeriesName = s.Name, + SeriesFormat = s.Format, + s.LibraryId, + data.readingListItem, + data.TotalPages, + data.ChapterNumber, + data.VolumeNumber, + data.VolumeId + }) + .Select(data => new ReadingListItemDto() + { + Id = data.readingListItem.Id, + ChapterId = data.readingListItem.ChapterId, + Order = data.readingListItem.Order, + SeriesId = data.readingListItem.SeriesId, + SeriesName = data.SeriesName, + SeriesFormat = data.SeriesFormat, + PagesTotal = data.TotalPages, + ChapterNumber = data.ChapterNumber, + VolumeNumber = data.VolumeNumber, + LibraryId = data.LibraryId, + VolumeId = data.VolumeId, + ReadingListId = data.readingListItem.ReadingListId + }) + .Where(o => userLibraries.Contains(o.LibraryId)) + .OrderBy(rli => rli.Order) + .AsNoTracking() + .ToListAsync(); + + // Attach progress information + var fetchedChapterIds = items.Select(i => i.ChapterId); + var progresses = await _context.AppUserProgresses + .Where(p => fetchedChapterIds.Contains(p.ChapterId)) + .AsNoTracking() + .ToListAsync(); + + foreach (var progress in progresses) + { + var progressItem = items.SingleOrDefault(i => i.ChapterId == progress.ChapterId && i.ReadingListId == readingListId); + if (progressItem == null) continue; + + progressItem.PagesRead = progress.PagesRead; + } + + return items; + } + + public async Task GetReadingListDtoByIdAsync(int readingListId, int userId) + { + return await _context.ReadingList + .Where(r => r.Id == readingListId && (r.AppUserId == userId || r.Promoted)) + .ProjectTo(_mapper.ConfigurationProvider) + .SingleOrDefaultAsync(); + } + + public async Task> AddReadingProgressModifiers(int userId, IList items) + { + var chapterIds = items.Select(i => i.ChapterId).Distinct().ToList(); + var userProgress = await _context.AppUserProgresses + .Where(p => p.AppUserId == userId && chapterIds.Contains(p.ChapterId)) + .AsNoTracking() + .ToListAsync(); + + foreach (var item in items) + { + var progress = userProgress.Where(p => p.ChapterId == item.ChapterId); + item.PagesRead = progress.Sum(p => p.PagesRead); + } + + return items; + } + + public async Task GetReadingListDtoByTitleAsync(string title) + { + return await _context.ReadingList + .Where(r => r.Title.Equals(title)) + .ProjectTo(_mapper.ConfigurationProvider) + .SingleOrDefaultAsync(); + } + + public async Task> GetReadingListItemsByIdAsync(int readingListId) + { + return await _context.ReadingListItem + .Where(r => r.ReadingListId == readingListId) + .OrderBy(r => r.Order) + .ToListAsync(); + } + + + } +} diff --git a/API/Data/SeriesRepository.cs b/API/Data/Repositories/SeriesRepository.cs similarity index 86% rename from API/Data/SeriesRepository.cs rename to API/Data/Repositories/SeriesRepository.cs index b9e2f16cd..3ed415859 100644 --- a/API/Data/SeriesRepository.cs +++ b/API/Data/Repositories/SeriesRepository.cs @@ -1,4 +1,6 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.IO; using System.Linq; using System.Threading.Tasks; using API.Comparators; @@ -7,18 +9,17 @@ using API.DTOs.Filtering; using API.Entities; using API.Extensions; using API.Helpers; -using API.Interfaces; +using API.Interfaces.Repositories; using AutoMapper; using AutoMapper.QueryableExtensions; using Microsoft.EntityFrameworkCore; -namespace API.Data +namespace API.Data.Repositories { public class SeriesRepository : ISeriesRepository { private readonly DataContext _context; private readonly IMapper _mapper; - private readonly NaturalSortComparer _naturalSortComparer = new (); public SeriesRepository(DataContext context, IMapper mapper) { _context = context; @@ -115,16 +116,15 @@ namespace API.Data await AddVolumeModifiers(userId, volumes); SortSpecialChapters(volumes); - - return volumes; } - private void SortSpecialChapters(IEnumerable volumes) + private static void SortSpecialChapters(IEnumerable volumes) { + var sorter = new NaturalSortComparer(); foreach (var v in volumes.Where(vDto => vDto.Number == 0)) { - v.Chapters = v.Chapters.OrderBy(x => x.Range, _naturalSortComparer).ToList(); + v.Chapters = v.Chapters.OrderBy(x => x.Range, sorter).ToList(); } } @@ -189,11 +189,16 @@ namespace API.Data /// /// /// - public async Task> GetVolumesForSeriesAsync(int[] seriesIds) + public async Task> GetVolumesForSeriesAsync(IList seriesIds, bool includeChapters = false) { - return await _context.Volume - .Where(v => seriesIds.Contains(v.SeriesId)) - .ToListAsync(); + var query = _context.Volume + .Where(v => seriesIds.Contains(v.SeriesId)); + + if (includeChapters) + { + query = query.Include(v => v.Chapters); + } + return await query.ToListAsync(); } public async Task DeleteSeriesAsync(int seriesId) @@ -221,27 +226,52 @@ namespace API.Data public async Task GetChapterIdsForSeriesAsync(int[] seriesIds) { - var series = await _context.Series - .Where(s => seriesIds.Contains(s.Id)) - .Include(s => s.Volumes) - .ThenInclude(v => v.Chapters) + var volumes = await _context.Volume + .Where(v => seriesIds.Contains(v.SeriesId)) + .Include(v => v.Chapters) .ToListAsync(); IList chapterIds = new List(); - foreach (var s in series) + foreach (var v in volumes) { - foreach (var v in s.Volumes) + foreach (var c in v.Chapters) { - foreach (var c in v.Chapters) - { - chapterIds.Add(c.Id); - } + chapterIds.Add(c.Id); } } return chapterIds.ToArray(); } + /// + /// This returns a list of tuples back for each series id passed + /// + /// + /// + public async Task>> GetChapterIdWithSeriesIdForSeriesAsync(int[] seriesIds) + { + var volumes = await _context.Volume + .Where(v => seriesIds.Contains(v.SeriesId)) + .Include(v => v.Chapters) + .ToListAsync(); + + var seriesChapters = new Dictionary>(); + foreach (var v in volumes) + { + foreach (var c in v.Chapters) + { + if (!seriesChapters.ContainsKey(v.SeriesId)) + { + var list = new List(); + seriesChapters.Add(v.SeriesId, list); + } + seriesChapters[v.SeriesId].Add(c.Id); + } + } + + return seriesChapters; + } + public async Task AddSeriesModifiers(int userId, List series) { var userProgress = await _context.AppUserProgresses @@ -262,16 +292,7 @@ namespace API.Data } } - public async Task GetVolumeCoverImageAsync(int volumeId) - { - return await _context.Volume - .Where(v => v.Id == volumeId) - .Select(v => v.CoverImage) - .AsNoTracking() - .SingleOrDefaultAsync(); - } - - public async Task GetSeriesCoverImageAsync(int seriesId) + public async Task GetSeriesCoverImageAsync(int seriesId) { return await _context.Series .Where(s => s.Id == seriesId) @@ -282,8 +303,9 @@ namespace API.Data private async Task AddVolumeModifiers(int userId, IReadOnlyCollection volumes) { + var volIds = volumes.Select(s => s.Id); var userProgress = await _context.AppUserProgresses - .Where(p => p.AppUserId == userId && volumes.Select(s => s.Id).Contains(p.VolumeId)) + .Where(p => p.AppUserId == userId && volIds.Contains(p.VolumeId)) .AsNoTracking() .ToListAsync(); @@ -457,5 +479,23 @@ namespace API.Data .AsSplitQuery() .ToListAsync(); } + + public async Task> GetAllCoverImagesAsync() + { + return await _context.Series + .Select(s => s.CoverImage) + .Where(t => !string.IsNullOrEmpty(t)) + .AsNoTracking() + .ToListAsync(); + } + + public async Task> GetLockedCoverImagesAsync() + { + return await _context.Series + .Where(s => s.CoverImageLocked && !string.IsNullOrEmpty(s.CoverImage)) + .Select(s => s.CoverImage) + .AsNoTracking() + .ToListAsync(); + } } } diff --git a/API/Data/SettingsRepository.cs b/API/Data/Repositories/SettingsRepository.cs similarity index 94% rename from API/Data/SettingsRepository.cs rename to API/Data/Repositories/SettingsRepository.cs index ecacf0f87..1eb0165bb 100644 --- a/API/Data/SettingsRepository.cs +++ b/API/Data/Repositories/SettingsRepository.cs @@ -4,11 +4,11 @@ using System.Threading.Tasks; using API.DTOs; using API.Entities; using API.Entities.Enums; -using API.Interfaces; +using API.Interfaces.Repositories; using AutoMapper; using Microsoft.EntityFrameworkCore; -namespace API.Data +namespace API.Data.Repositories { public class SettingsRepository : ISettingsRepository { @@ -45,4 +45,4 @@ namespace API.Data return await _context.ServerSetting.ToListAsync(); } } -} \ No newline at end of file +} diff --git a/API/Data/UserRepository.cs b/API/Data/Repositories/UserRepository.cs similarity index 56% rename from API/Data/UserRepository.cs rename to API/Data/Repositories/UserRepository.cs index 2e0b9e7f3..4e20039c7 100644 --- a/API/Data/UserRepository.cs +++ b/API/Data/Repositories/UserRepository.cs @@ -1,17 +1,29 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using API.Constants; using API.DTOs; +using API.DTOs.Reader; using API.Entities; -using API.Interfaces; +using API.Interfaces.Repositories; using AutoMapper; using AutoMapper.QueryableExtensions; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; -namespace API.Data +namespace API.Data.Repositories { + [Flags] + public enum AppUserIncludes + { + None = 1, + Progress = 2, + Bookmarks = 4, + ReadingLists = 8, + Ratings = 16 + } + public class UserRepository : IUserRepository { private readonly DataContext _context; @@ -35,35 +47,105 @@ namespace API.Data _context.Entry(preferences).State = EntityState.Modified; } + public void Update(AppUserBookmark bookmark) + { + _context.Entry(bookmark).State = EntityState.Modified; + } + public void Delete(AppUser user) { _context.AppUser.Remove(user); } /// - /// Gets an AppUser by username. Returns back Progress information. + /// A one stop shop to get a tracked AppUser instance with any number of JOINs generated by passing bitwise flags. /// /// + /// Includes() you want. Pass multiple with flag1 | flag2 /// - public async Task GetUserByUsernameAsync(string username) + public async Task GetUserByUsernameAsync(string username, AppUserIncludes includeFlags = AppUserIncludes.None) { - return await _context.Users - .Include(u => u.Progresses) - .Include(u => u.Bookmarks) - .SingleOrDefaultAsync(x => x.UserName == username); + var query = _context.Users + .Where(x => x.UserName == username); + + query = AddIncludesToQuery(query, includeFlags); + + return await query.SingleOrDefaultAsync(); } /// - /// Gets an AppUser by id. Returns back Progress information. + /// A one stop shop to get a tracked AppUser instance with any number of JOINs generated by passing bitwise flags. + /// + /// + /// Includes() you want. Pass multiple with flag1 | flag2 + /// + public async Task GetUserByIdAsync(int userId, AppUserIncludes includeFlags = AppUserIncludes.None) + { + var query = _context.Users + .Where(x => x.Id == userId); + + query = AddIncludesToQuery(query, includeFlags); + + return await query.SingleOrDefaultAsync(); + } + + public async Task GetBookmarkForPage(int page, int chapterId, int userId) + { + return await _context.AppUserBookmark + .Where(b => b.Page == page && b.ChapterId == chapterId && b.AppUserId == userId) + .SingleOrDefaultAsync(); + } + + private static IQueryable AddIncludesToQuery(IQueryable query, AppUserIncludes includeFlags) + { + if (includeFlags.HasFlag(AppUserIncludes.Bookmarks)) + { + query = query.Include(u => u.Bookmarks); + } + + if (includeFlags.HasFlag(AppUserIncludes.Progress)) + { + query = query.Include(u => u.Progresses); + } + + if (includeFlags.HasFlag(AppUserIncludes.ReadingLists)) + { + query = query.Include(u => u.ReadingLists); + } + + if (includeFlags.HasFlag(AppUserIncludes.Ratings)) + { + query = query.Include(u => u.Ratings); + } + + return query; + } + + + /// + /// This fetches the Id for a user. Use whenever you just need an ID. /// /// /// - public async Task GetUserByIdAsync(int id) + public async Task GetUserIdByUsernameAsync(string username) { return await _context.Users - .Include(u => u.Progresses) - .Include(u => u.Bookmarks) - .SingleOrDefaultAsync(x => x.Id == id); + .Where(x => x.UserName == username) + .Select(u => u.Id) + .SingleOrDefaultAsync(); + } + + /// + /// Gets an AppUser by username. Returns back Reading List and their Items. + /// + /// + /// + public async Task GetUserWithReadingListsByUsernameAsync(string username) + { + return await _context.Users + .Include(u => u.ReadingLists) + .ThenInclude(l => l.Items) + .SingleOrDefaultAsync(x => x.UserName == username); } public async Task> GetAdminUsersAsync() @@ -77,11 +159,6 @@ namespace API.Data .SingleOrDefaultAsync(); } - public void AddRatingTracking(AppUserRating userRating) - { - _context.AppUserRating.Add(userRating); - } - public async Task GetPreferencesAsync(string username) { return await _context.AppUserPreferences @@ -129,10 +206,17 @@ namespace API.Data .ToListAsync(); } - public async Task GetUserByApiKeyAsync(string apiKey) + /// + /// Fetches the UserId by API Key. This does not include any extra information + /// + /// + /// + public async Task GetUserIdByApiKeyAsync(string apiKey) { return await _context.AppUser - .SingleOrDefaultAsync(u => u.ApiKey.Equals(apiKey)); + .Where(u => u.ApiKey.Equals(apiKey)) + .Select(u => u.Id) + .SingleOrDefaultAsync(); } diff --git a/API/Data/Repositories/VolumeRepository.cs b/API/Data/Repositories/VolumeRepository.cs new file mode 100644 index 000000000..d991a928c --- /dev/null +++ b/API/Data/Repositories/VolumeRepository.cs @@ -0,0 +1,56 @@ +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using API.DTOs; +using API.DTOs.Reader; +using API.Entities; +using API.Interfaces.Repositories; +using AutoMapper; +using AutoMapper.QueryableExtensions; +using Microsoft.EntityFrameworkCore; + +namespace API.Data.Repositories +{ + public class VolumeRepository : IVolumeRepository + { + private readonly DataContext _context; + + public VolumeRepository(DataContext context) + { + _context = context; + } + + public void Update(Volume volume) + { + _context.Entry(volume).State = EntityState.Modified; + } + + public async Task> GetFilesForVolume(int volumeId) + { + return await _context.Chapter + .Where(c => volumeId == c.VolumeId) + .Include(c => c.Files) + .SelectMany(c => c.Files) + .AsNoTracking() + .ToListAsync(); + } + + public async Task GetVolumeCoverImageAsync(int volumeId) + { + return await _context.Volume + .Where(v => v.Id == volumeId) + .Select(v => v.CoverImage) + .AsNoTracking() + .SingleOrDefaultAsync(); + } + + public async Task> GetChapterIdsByVolumeIds(IReadOnlyList volumeIds) + { + return await _context.Chapter + .Where(c => volumeIds.Contains(c.VolumeId)) + .Select(c => c.Id) + .ToListAsync(); + } + } +} diff --git a/API/Data/UnitOfWork.cs b/API/Data/UnitOfWork.cs index 25ac5654c..017293be0 100644 --- a/API/Data/UnitOfWork.cs +++ b/API/Data/UnitOfWork.cs @@ -1,4 +1,5 @@ using System.Threading.Tasks; +using API.Data.Repositories; using API.Entities; using API.Interfaces; using API.Interfaces.Repositories; @@ -24,14 +25,15 @@ namespace API.Data public IUserRepository UserRepository => new UserRepository(_context, _userManager, _mapper); public ILibraryRepository LibraryRepository => new LibraryRepository(_context, _mapper); - public IVolumeRepository VolumeRepository => new VolumeRepository(_context, _mapper); + public IVolumeRepository VolumeRepository => new VolumeRepository(_context); public ISettingsRepository SettingsRepository => new SettingsRepository(_context, _mapper); public IAppUserProgressRepository AppUserProgressRepository => new AppUserProgressRepository(_context); public ICollectionTagRepository CollectionTagRepository => new CollectionTagRepository(_context, _mapper); public IFileRepository FileRepository => new FileRepository(_context); - public IChapterRepository ChapterRepository => new ChapterRepository(_context); + public IChapterRepository ChapterRepository => new ChapterRepository(_context, _mapper); + public IReadingListRepository ReadingListRepository => new ReadingListRepository(_context, _mapper); /// /// Commits changes to the DB. Completes the open transaction. @@ -39,7 +41,6 @@ namespace API.Data /// public bool Commit() { - return _context.SaveChanges() > 0; } /// diff --git a/API/Data/VolumeRepository.cs b/API/Data/VolumeRepository.cs deleted file mode 100644 index c10a3a04e..000000000 --- a/API/Data/VolumeRepository.cs +++ /dev/null @@ -1,116 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using API.DTOs; -using API.Entities; -using API.Interfaces; -using AutoMapper; -using AutoMapper.QueryableExtensions; -using Microsoft.EntityFrameworkCore; - -namespace API.Data -{ - public class VolumeRepository : IVolumeRepository - { - private readonly DataContext _context; - private readonly IMapper _mapper; - - public VolumeRepository(DataContext context, IMapper mapper) - { - _context = context; - _mapper = mapper; - } - - public void Update(Volume volume) - { - _context.Entry(volume).State = EntityState.Modified; - } - - /// - /// Returns a Chapter for an Id. Includes linked s. - /// - /// - /// - public async Task GetChapterAsync(int chapterId) - { - return await _context.Chapter - .Include(c => c.Files) - .SingleOrDefaultAsync(c => c.Id == chapterId); - } - - /// - /// Returns Chapters for a volume id. - /// - /// - /// - public async Task> GetChaptersAsync(int volumeId) - { - return await _context.Chapter - .Where(c => c.VolumeId == volumeId) - .ToListAsync(); - } - - /// - /// Returns the cover image for a chapter id. - /// - /// - /// - public async Task GetChapterCoverImageAsync(int chapterId) - { - return await _context.Chapter - .Where(c => c.Id == chapterId) - .Select(c => c.CoverImage) - .AsNoTracking() - .SingleOrDefaultAsync(); - } - - - - - public async Task GetChapterDtoAsync(int chapterId) - { - var chapter = await _context.Chapter - .Include(c => c.Files) - .ProjectTo(_mapper.ConfigurationProvider) - .AsNoTracking() - .SingleOrDefaultAsync(c => c.Id == chapterId); - - return chapter; - } - - /// - /// Returns non-tracked files for a given chapterId - /// - /// - /// - public async Task> GetFilesForChapterAsync(int chapterId) - { - return await _context.MangaFile - .Where(c => chapterId == c.ChapterId) - .AsNoTracking() - .ToListAsync(); - } - /// - /// Returns non-tracked files for a set of chapterIds - /// - /// - /// - public async Task> GetFilesForChaptersAsync(IReadOnlyList chapterIds) - { - return await _context.MangaFile - .Where(c => chapterIds.Contains(c.ChapterId)) - .AsNoTracking() - .ToListAsync(); - } - - public async Task> GetFilesForVolume(int volumeId) - { - return await _context.Chapter - .Where(c => volumeId == c.VolumeId) - .Include(c => c.Files) - .SelectMany(c => c.Files) - .AsNoTracking() - .ToListAsync(); - } - } -} diff --git a/API/Entities/AppUser.cs b/API/Entities/AppUser.cs index c4a24e405..b959fac1a 100644 --- a/API/Entities/AppUser.cs +++ b/API/Entities/AppUser.cs @@ -18,6 +18,10 @@ namespace API.Entities public AppUserPreferences UserPreferences { get; set; } public ICollection Bookmarks { get; set; } /// + /// Reading lists associated with this user + /// + public ICollection ReadingLists { get; set; } + /// /// An API Key to interact with external services, like OPDS /// public string ApiKey { get; set; } diff --git a/API/Entities/AppUserProgress.cs b/API/Entities/AppUserProgress.cs index cb3c1b33c..08fffa540 100644 --- a/API/Entities/AppUserProgress.cs +++ b/API/Entities/AppUserProgress.cs @@ -9,7 +9,7 @@ namespace API.Entities /// Represents the progress a single user has on a given Chapter. /// //[Index(nameof(SeriesId), nameof(VolumeId), nameof(ChapterId), nameof(AppUserId), IsUnique = true)] - public class AppUserProgress : IEntityDate, IHasConcurrencyToken + public class AppUserProgress : IEntityDate { /// /// Id of Entity @@ -55,16 +55,5 @@ namespace API.Entities /// Last date this was updated /// public DateTime LastModified { get; set; } - - /// - [ConcurrencyCheck] - public uint RowVersion { get; private set; } - - - /// - public void OnSavingChanges() - { - RowVersion++; - } } } diff --git a/API/Entities/Chapter.cs b/API/Entities/Chapter.cs index 4595ba048..ef12de8ce 100644 --- a/API/Entities/Chapter.cs +++ b/API/Entities/Chapter.cs @@ -23,7 +23,11 @@ namespace API.Entities public ICollection Files { get; set; } public DateTime Created { get; set; } public DateTime LastModified { get; set; } - public byte[] CoverImage { get; set; } + /// + /// Absolute path to the (managed) image file + /// + /// The file is managed internally to Kavita's APPDIR + public string CoverImage { get; set; } public bool CoverImageLocked { get; set; } /// /// Total number of pages in all MangaFiles diff --git a/API/Entities/CollectionTag.cs b/API/Entities/CollectionTag.cs index c9dd4fa92..ee966cafc 100644 --- a/API/Entities/CollectionTag.cs +++ b/API/Entities/CollectionTag.cs @@ -14,11 +14,11 @@ namespace API.Entities /// Visible title of the Tag /// public string Title { get; set; } - /// - /// Cover Image for the collection tag + /// Absolute path to the (managed) image file /// - public byte[] CoverImage { get; set; } + /// The file is managed internally to Kavita's APPDIR + public string CoverImage { get; set; } /// /// Denotes if the CoverImage has been overridden by the user. If so, it will not be updated during normal scan operations. /// diff --git a/API/Entities/MangaFile.cs b/API/Entities/MangaFile.cs index 2376ec721..72c620ce9 100644 --- a/API/Entities/MangaFile.cs +++ b/API/Entities/MangaFile.cs @@ -30,9 +30,13 @@ namespace API.Entities public int ChapterId { get; set; } // Methods + /// + /// If the File on disk's last modified time is after what is stored in MangaFile + /// + /// public bool HasFileBeenModified() { - return !File.GetLastWriteTime(FilePath).Equals(LastModified); + return File.GetLastWriteTime(FilePath) > LastModified; } } } diff --git a/API/Entities/ReadingList.cs b/API/Entities/ReadingList.cs new file mode 100644 index 000000000..ef0b4bd9c --- /dev/null +++ b/API/Entities/ReadingList.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using API.Entities.Interfaces; + +namespace API.Entities +{ + /// + /// This is a collection of which represent individual chapters and an order. + /// + public class ReadingList : IEntityDate + { + public int Id { get; init; } + public string Title { get; set; } + public string Summary { get; set; } + /// + /// Reading lists that are promoted are only done by admins + /// + public bool Promoted { get; set; } + + public ICollection Items { get; set; } + public DateTime Created { get; set; } + public DateTime LastModified { get; set; } + + // Relationships + public int AppUserId { get; set; } + public AppUser AppUser { get; set; } + + } +} diff --git a/API/Entities/ReadingListItem.cs b/API/Entities/ReadingListItem.cs new file mode 100644 index 000000000..002911131 --- /dev/null +++ b/API/Entities/ReadingListItem.cs @@ -0,0 +1,25 @@ +namespace API.Entities +{ + //[Index(nameof(SeriesId), nameof(VolumeId), nameof(ChapterId), IsUnique = true)] + public class ReadingListItem + { + public int Id { get; init; } + public int SeriesId { get; set; } + public int VolumeId { get; set; } + public int ChapterId { get; set; } + /// + /// Order of the chapter within a Reading List + /// + public int Order { get; set; } + + // Relationship + public ReadingList ReadingList { get; set; } + public int ReadingListId { get; set; } + + // Idea, keep these for easy join statements + public Series Series { get; set; } + public Volume Volume { get; set; } + public Chapter Chapter { get; set; } + + } +} diff --git a/API/Entities/Series.cs b/API/Entities/Series.cs index b2d97751f..899e52bfd 100644 --- a/API/Entities/Series.cs +++ b/API/Entities/Series.cs @@ -36,7 +36,11 @@ namespace API.Entities public string Summary { get; set; } // TODO: Migrate into SeriesMetdata (with Metadata update) public DateTime Created { get; set; } public DateTime LastModified { get; set; } - public byte[] CoverImage { get; set; } + /// + /// Absolute path to the (managed) image file + /// + /// The file is managed internally to Kavita's APPDIR + public string CoverImage { get; set; } /// /// Denotes if the CoverImage has been overridden by the user. If so, it will not be updated during normal scan operations. /// diff --git a/API/Entities/Volume.cs b/API/Entities/Volume.cs index dab9f2e1b..3be7a4d6a 100644 --- a/API/Entities/Volume.cs +++ b/API/Entities/Volume.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using API.Entities.Interfaces; +using Microsoft.EntityFrameworkCore; namespace API.Entities { @@ -12,7 +13,11 @@ namespace API.Entities public IList Chapters { get; set; } public DateTime Created { get; set; } public DateTime LastModified { get; set; } - public byte[] CoverImage { get; set; } + /// + /// Absolute path to the (managed) image file + /// + /// The file is managed internally to Kavita's APPDIR + public string CoverImage { get; set; } public int Pages { get; set; } @@ -21,4 +26,4 @@ namespace API.Entities public Series Series { get; set; } public int SeriesId { get; set; } } -} \ No newline at end of file +} diff --git a/API/Extensions/FileInfoExtensions.cs b/API/Extensions/FileInfoExtensions.cs index a52141611..f7e1291e7 100644 --- a/API/Extensions/FileInfoExtensions.cs +++ b/API/Extensions/FileInfoExtensions.cs @@ -14,7 +14,6 @@ namespace API.Extensions public static bool HasFileBeenModifiedSince(this FileInfo fileInfo, DateTime comparison) { return DateTime.Compare(fileInfo.LastWriteTime, comparison) > 0; - //return fileInfo?.LastWriteTime > comparison; } } } diff --git a/API/Extensions/HttpExtensions.cs b/API/Extensions/HttpExtensions.cs index db7bcd370..80b52f18f 100644 --- a/API/Extensions/HttpExtensions.cs +++ b/API/Extensions/HttpExtensions.cs @@ -1,4 +1,5 @@ using System.Linq; +using System.Text; using System.Text.Json; using API.Helpers; using Microsoft.AspNetCore.Http; @@ -7,7 +8,7 @@ namespace API.Extensions { public static class HttpExtensions { - public static void AddPaginationHeader(this HttpResponse response, int currentPage, + public static void AddPaginationHeader(this HttpResponse response, int currentPage, int itemsPerPage, int totalItems, int totalPages) { var paginationHeader = new PaginationHeader(currentPage, itemsPerPage, totalItems, totalPages); @@ -15,7 +16,7 @@ namespace API.Extensions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }; - + response.Headers.Add("Pagination", JsonSerializer.Serialize(paginationHeader, options)); response.Headers.Add("Access-Control-Expose-Headers", "Pagination"); } @@ -31,6 +32,18 @@ namespace API.Extensions using var sha1 = new System.Security.Cryptography.SHA256CryptoServiceProvider(); response.Headers.Add("ETag", string.Concat(sha1.ComputeHash(content).Select(x => x.ToString("X2")))); } - + + /// + /// Calculates SHA256 hash for a cover image filename and sets as ETag. Ensures Cache-Control: private header is added. + /// + /// + /// + public static void AddCacheHeader(this HttpResponse response, string filename) + { + if (filename == null || filename.Length <= 0) return; + using var sha1 = new System.Security.Cryptography.SHA256CryptoServiceProvider(); + response.Headers.Add("ETag", string.Concat(sha1.ComputeHash(Encoding.UTF8.GetBytes(filename)).Select(x => x.ToString("X2")))); + } + } -} \ No newline at end of file +} diff --git a/API/Helpers/AutoMapperProfiles.cs b/API/Helpers/AutoMapperProfiles.cs index 084a7d28c..03445ccb2 100644 --- a/API/Helpers/AutoMapperProfiles.cs +++ b/API/Helpers/AutoMapperProfiles.cs @@ -1,6 +1,8 @@ using System.Collections.Generic; using System.Linq; using API.DTOs; +using API.DTOs.Reader; +using API.DTOs.ReadingLists; using API.Entities; using API.Helpers.Converters; using AutoMapper; @@ -31,6 +33,9 @@ namespace API.Helpers CreateMap(); + CreateMap(); + CreateMap(); + CreateMap() .ForMember(dest => dest.SeriesId, opt => opt.MapFrom(src => src.Id)) diff --git a/API/Helpers/SQLHelper.cs b/API/Helpers/SQLHelper.cs new file mode 100644 index 000000000..fcd44e7da --- /dev/null +++ b/API/Helpers/SQLHelper.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Data.Common; +using Microsoft.EntityFrameworkCore; + +namespace API.Helpers +{ + public static class SqlHelper + { + public static List RawSqlQuery(DbContext context, string query, Func map) + { + using var command = context.Database.GetDbConnection().CreateCommand(); + command.CommandText = query; + command.CommandType = CommandType.Text; + + context.Database.OpenConnection(); + + using var result = command.ExecuteReader(); + var entities = new List(); + + while (result.Read()) + { + entities.Add(map(result)); + } + + return entities; + } + } +} diff --git a/API/Interfaces/ITaskScheduler.cs b/API/Interfaces/ITaskScheduler.cs index ead76e36a..08a450ac2 100644 --- a/API/Interfaces/ITaskScheduler.cs +++ b/API/Interfaces/ITaskScheduler.cs @@ -14,7 +14,7 @@ namespace API.Interfaces void CleanupChapters(int[] chapterIds); void RefreshMetadata(int libraryId, bool forceUpdate = true); void CleanupTemp(); - void RefreshSeriesMetadata(int libraryId, int seriesId); + void RefreshSeriesMetadata(int libraryId, int seriesId, bool forceUpdate = false); void ScanSeries(int libraryId, int seriesId, bool forceUpdate = false); void CancelStatsTasks(); void RunStatCollection(); diff --git a/API/Interfaces/IUnitOfWork.cs b/API/Interfaces/IUnitOfWork.cs index 3f7b12146..06b47bbe8 100644 --- a/API/Interfaces/IUnitOfWork.cs +++ b/API/Interfaces/IUnitOfWork.cs @@ -14,6 +14,7 @@ namespace API.Interfaces ICollectionTagRepository CollectionTagRepository { get; } IFileRepository FileRepository { get; } IChapterRepository ChapterRepository { get; } + IReadingListRepository ReadingListRepository { get; } bool Commit(); Task CommitAsync(); bool HasChanges(); diff --git a/API/Interfaces/IVolumeRepository.cs b/API/Interfaces/IVolumeRepository.cs deleted file mode 100644 index 0cd703ee9..000000000 --- a/API/Interfaces/IVolumeRepository.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; -using API.DTOs; -using API.Entities; - -namespace API.Interfaces -{ - public interface IVolumeRepository - { - void Update(Volume volume); - Task GetChapterAsync(int chapterId); - Task GetChapterDtoAsync(int chapterId); - Task> GetFilesForChapterAsync(int chapterId); - Task> GetFilesForChaptersAsync(IReadOnlyList chapterIds); - Task> GetChaptersAsync(int volumeId); - Task GetChapterCoverImageAsync(int chapterId); - Task> GetFilesForVolume(int volumeId); - } -} diff --git a/API/Interfaces/IAppUserProgressRepository.cs b/API/Interfaces/Repositories/IAppUserProgressRepository.cs similarity index 55% rename from API/Interfaces/IAppUserProgressRepository.cs rename to API/Interfaces/Repositories/IAppUserProgressRepository.cs index 96ada0c50..d37198fb2 100644 --- a/API/Interfaces/IAppUserProgressRepository.cs +++ b/API/Interfaces/Repositories/IAppUserProgressRepository.cs @@ -1,11 +1,14 @@ using System.Threading.Tasks; +using API.Entities; using API.Entities.Enums; -namespace API.Interfaces +namespace API.Interfaces.Repositories { public interface IAppUserProgressRepository { + void Update(AppUserProgress userProgress); Task CleanupAbandonedChapters(); Task UserHasProgress(LibraryType libraryType, int userId); + Task GetUserProgressAsync(int chapterId, int userId); } -} \ No newline at end of file +} diff --git a/API/Interfaces/Repositories/IChapterRepository.cs b/API/Interfaces/Repositories/IChapterRepository.cs index 9f3f39a13..9ce145f4c 100644 --- a/API/Interfaces/Repositories/IChapterRepository.cs +++ b/API/Interfaces/Repositories/IChapterRepository.cs @@ -1,9 +1,24 @@ -using API.Entities; +using System.Collections.Generic; +using System.Threading.Tasks; +using API.DTOs; +using API.DTOs.Reader; +using API.Entities; namespace API.Interfaces.Repositories { public interface IChapterRepository { void Update(Chapter chapter); + Task> GetChaptersByIdsAsync(IList chapterIds); + Task GetChapterInfoDtoAsync(int chapterId); + Task GetChapterTotalPagesAsync(int chapterId); + Task GetChapterAsync(int chapterId); + Task GetChapterDtoAsync(int chapterId); + Task> GetFilesForChapterAsync(int chapterId); + Task> GetChaptersAsync(int volumeId); + Task> GetFilesForChaptersAsync(IReadOnlyList chapterIds); + Task GetChapterCoverImageAsync(int chapterId); + Task> GetAllCoverImagesAsync(); + Task> GetCoverImagesForLockedChaptersAsync(); } } diff --git a/API/Interfaces/ICollectionTagRepository.cs b/API/Interfaces/Repositories/ICollectionTagRepository.cs similarity index 81% rename from API/Interfaces/ICollectionTagRepository.cs rename to API/Interfaces/Repositories/ICollectionTagRepository.cs index 62f813c9d..03a552bd9 100644 --- a/API/Interfaces/ICollectionTagRepository.cs +++ b/API/Interfaces/Repositories/ICollectionTagRepository.cs @@ -3,19 +3,20 @@ using System.Threading.Tasks; using API.DTOs; using API.Entities; -namespace API.Interfaces +namespace API.Interfaces.Repositories { public interface ICollectionTagRepository { void Remove(CollectionTag tag); Task> GetAllTagDtosAsync(); Task> SearchTagDtosAsync(string searchQuery); - Task GetCoverImageAsync(int collectionTagId); + Task GetCoverImageAsync(int collectionTagId); Task> GetAllPromotedTagDtosAsync(); Task GetTagAsync(int tagId); Task GetFullTagAsync(int tagId); void Update(CollectionTag tag); Task RemoveTagsWithoutSeries(); Task> GetAllTagsAsync(); + Task> GetAllCoverImagesAsync(); } } diff --git a/API/Interfaces/IFileRepository.cs b/API/Interfaces/Repositories/IFileRepository.cs similarity index 81% rename from API/Interfaces/IFileRepository.cs rename to API/Interfaces/Repositories/IFileRepository.cs index cde587855..a852032d7 100644 --- a/API/Interfaces/IFileRepository.cs +++ b/API/Interfaces/Repositories/IFileRepository.cs @@ -1,10 +1,10 @@ using System.Collections.Generic; using System.Threading.Tasks; -namespace API.Interfaces +namespace API.Interfaces.Repositories { public interface IFileRepository { Task> GetFileExtensions(); } -} \ No newline at end of file +} diff --git a/API/Interfaces/ILibraryRepository.cs b/API/Interfaces/Repositories/ILibraryRepository.cs similarity index 96% rename from API/Interfaces/ILibraryRepository.cs rename to API/Interfaces/Repositories/ILibraryRepository.cs index 4977d38d5..4d9b03fe4 100644 --- a/API/Interfaces/ILibraryRepository.cs +++ b/API/Interfaces/Repositories/ILibraryRepository.cs @@ -4,7 +4,7 @@ using API.DTOs; using API.Entities; using API.Entities.Enums; -namespace API.Interfaces +namespace API.Interfaces.Repositories { public interface ILibraryRepository { diff --git a/API/Interfaces/Repositories/IReadingListRepository.cs b/API/Interfaces/Repositories/IReadingListRepository.cs new file mode 100644 index 000000000..8b5ab085d --- /dev/null +++ b/API/Interfaces/Repositories/IReadingListRepository.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using API.DTOs.ReadingLists; +using API.Entities; +using API.Helpers; + +namespace API.Interfaces.Repositories +{ + public interface IReadingListRepository + { + Task> GetReadingListDtosForUserAsync(int userId, bool includePromoted, UserParams userParams); + Task GetReadingListByIdAsync(int readingListId); + Task> GetReadingListItemDtosByIdAsync(int readingListId, int userId); + Task GetReadingListDtoByIdAsync(int readingListId, int userId); + Task> AddReadingProgressModifiers(int userId, IList items); + Task GetReadingListDtoByTitleAsync(string title); + Task> GetReadingListItemsByIdAsync(int readingListId); + void Remove(ReadingListItem item); + void BulkRemove(IEnumerable items); + void Update(ReadingList list); + } +} diff --git a/API/Interfaces/ISeriesRepository.cs b/API/Interfaces/Repositories/ISeriesRepository.cs similarity index 85% rename from API/Interfaces/ISeriesRepository.cs rename to API/Interfaces/Repositories/ISeriesRepository.cs index a5518fc60..05fe937eb 100644 --- a/API/Interfaces/ISeriesRepository.cs +++ b/API/Interfaces/Repositories/ISeriesRepository.cs @@ -1,11 +1,13 @@ -using System.Collections.Generic; +using System; +using System.Collections; +using System.Collections.Generic; using System.Threading.Tasks; using API.DTOs; using API.DTOs.Filtering; using API.Entities; using API.Helpers; -namespace API.Interfaces +namespace API.Interfaces.Repositories { public interface ISeriesRepository { @@ -43,11 +45,12 @@ namespace API.Interfaces /// /// Task GetVolumeDtoAsync(int volumeId); - Task> GetVolumesForSeriesAsync(int[] seriesIds); + Task> GetVolumesForSeriesAsync(IList seriesIds, bool includeChapters = false); Task DeleteSeriesAsync(int seriesId); Task GetVolumeByIdAsync(int volumeId); Task GetSeriesByIdAsync(int seriesId); Task GetChapterIdsForSeriesAsync(int[] seriesIds); + Task>> GetChapterIdWithSeriesIdForSeriesAsync(int[] seriesIds); /// /// Used to add Progress/Rating information to series list. /// @@ -56,13 +59,15 @@ namespace API.Interfaces /// Task AddSeriesModifiers(int userId, List series); - Task GetVolumeCoverImageAsync(int volumeId); - Task GetSeriesCoverImageAsync(int seriesId); + + Task GetSeriesCoverImageAsync(int seriesId); Task> GetInProgress(int userId, int libraryId, UserParams userParams, FilterDto filter); Task> GetRecentlyAdded(int libraryId, int userId, UserParams userParams, FilterDto filter); Task GetSeriesMetadata(int seriesId); Task> GetSeriesDtoForCollectionAsync(int collectionId, int userId, UserParams userParams); Task> GetFilesForSeries(int seriesId); Task> GetSeriesDtoForIdsAsync(IEnumerable seriesIds, int userId); + Task> GetAllCoverImagesAsync(); + Task> GetLockedCoverImagesAsync(); } } diff --git a/API/Interfaces/ISettingsRepository.cs b/API/Interfaces/Repositories/ISettingsRepository.cs similarity index 90% rename from API/Interfaces/ISettingsRepository.cs rename to API/Interfaces/Repositories/ISettingsRepository.cs index 5b0994d41..f1687743d 100644 --- a/API/Interfaces/ISettingsRepository.cs +++ b/API/Interfaces/Repositories/ISettingsRepository.cs @@ -4,7 +4,7 @@ using API.DTOs; using API.Entities; using API.Entities.Enums; -namespace API.Interfaces +namespace API.Interfaces.Repositories { public interface ISettingsRepository { @@ -12,6 +12,6 @@ namespace API.Interfaces Task GetSettingsDtoAsync(); Task GetSettingAsync(ServerSettingKey key); Task> GetSettingsAsync(); - + } -} \ No newline at end of file +} diff --git a/API/Interfaces/IUserRepository.cs b/API/Interfaces/Repositories/IUserRepository.cs similarity index 58% rename from API/Interfaces/IUserRepository.cs rename to API/Interfaces/Repositories/IUserRepository.cs index c58eafdfc..22bd9dc92 100644 --- a/API/Interfaces/IUserRepository.cs +++ b/API/Interfaces/Repositories/IUserRepository.cs @@ -1,26 +1,31 @@ using System.Collections.Generic; using System.Threading.Tasks; +using API.Data.Repositories; using API.DTOs; +using API.DTOs.Reader; using API.Entities; -namespace API.Interfaces +namespace API.Interfaces.Repositories { public interface IUserRepository { void Update(AppUser user); void Update(AppUserPreferences preferences); + void Update(AppUserBookmark bookmark); public void Delete(AppUser user); - Task GetUserByUsernameAsync(string username); - Task GetUserByIdAsync(int id); Task> GetMembersAsync(); Task> GetAdminUsersAsync(); Task GetUserRating(int seriesId, int userId); - void AddRatingTracking(AppUserRating userRating); Task GetPreferencesAsync(string username); Task> GetBookmarkDtosForSeries(int userId, int seriesId); Task> GetBookmarkDtosForVolume(int userId, int volumeId); Task> GetBookmarkDtosForChapter(int userId, int chapterId); Task> GetAllBookmarkDtos(int userId); - Task GetUserByApiKeyAsync(string apiKey); + Task GetBookmarkForPage(int page, int chapterId, int userId); + Task GetUserIdByApiKeyAsync(string apiKey); + Task GetUserByUsernameAsync(string username, AppUserIncludes includeFlags = AppUserIncludes.None); + Task GetUserByIdAsync(int userId, AppUserIncludes includeFlags = AppUserIncludes.None); + Task GetUserIdByUsernameAsync(string username); + Task GetUserWithReadingListsByUsernameAsync(string username); } } diff --git a/API/Interfaces/Repositories/IVolumeRepository.cs b/API/Interfaces/Repositories/IVolumeRepository.cs new file mode 100644 index 000000000..62ec0ef9a --- /dev/null +++ b/API/Interfaces/Repositories/IVolumeRepository.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using API.DTOs; +using API.Entities; + +namespace API.Interfaces.Repositories +{ + public interface IVolumeRepository + { + void Update(Volume volume); + Task> GetFilesForVolume(int volumeId); + Task GetVolumeCoverImageAsync(int volumeId); + Task> GetChapterIdsByVolumeIds(IReadOnlyList volumeIds); + } +} diff --git a/API/Interfaces/Services/IArchiveService.cs b/API/Interfaces/Services/IArchiveService.cs index 07c1e287d..ae9bddc98 100644 --- a/API/Interfaces/Services/IArchiveService.cs +++ b/API/Interfaces/Services/IArchiveService.cs @@ -10,7 +10,7 @@ namespace API.Interfaces.Services { void ExtractArchive(string archivePath, string extractPath); int GetNumberOfPagesFromArchive(string archivePath); - byte[] GetCoverImage(string archivePath, bool createThumbnail = false); + string GetCoverImage(string archivePath, string fileName); bool IsValidArchive(string archivePath); string GetSummaryInfo(string archivePath); ArchiveLibrary CanOpen(string archivePath); diff --git a/API/Interfaces/Services/IBackupService.cs b/API/Interfaces/Services/IBackupService.cs index eaa140e46..315b852f0 100644 --- a/API/Interfaces/Services/IBackupService.cs +++ b/API/Interfaces/Services/IBackupService.cs @@ -1,11 +1,12 @@ using System.Collections.Generic; +using System.Threading.Tasks; using Microsoft.Extensions.Configuration; namespace API.Interfaces.Services { public interface IBackupService { - void BackupDatabase(); + Task BackupDatabase(); /// /// Returns a list of full paths of the logs files detailed in . /// diff --git a/API/Interfaces/Services/IBookService.cs b/API/Interfaces/Services/IBookService.cs index b3afc13a8..cde2cad8e 100644 --- a/API/Interfaces/Services/IBookService.cs +++ b/API/Interfaces/Services/IBookService.cs @@ -8,7 +8,7 @@ namespace API.Interfaces.Services public interface IBookService { int GetNumberOfPages(string filePath); - byte[] GetCoverImage(string fileFilePath, bool createThumbnail = true); + string GetCoverImage(string fileFilePath, string fileName); Task> CreateKeyToPageMappingAsync(EpubBookRef book); /// diff --git a/API/Interfaces/Services/ICleanupService.cs b/API/Interfaces/Services/ICleanupService.cs index da61943fe..afabb9900 100644 --- a/API/Interfaces/Services/ICleanupService.cs +++ b/API/Interfaces/Services/ICleanupService.cs @@ -1,7 +1,10 @@ -namespace API.Interfaces.Services +using System.Threading.Tasks; + +namespace API.Interfaces.Services { public interface ICleanupService { - void Cleanup(); + Task Cleanup(); + void CleanupCacheDirectory(); } -} \ No newline at end of file +} diff --git a/API/Interfaces/Services/IImageService.cs b/API/Interfaces/Services/IImageService.cs index 86f6fa489..0aba07f39 100644 --- a/API/Interfaces/Services/IImageService.cs +++ b/API/Interfaces/Services/IImageService.cs @@ -1,22 +1,23 @@ using API.Entities; +using API.Services; namespace API.Interfaces.Services { public interface IImageService { - byte[] GetCoverImage(string path, bool createThumbnail = false); + string GetCoverImage(string path, string fileName); string GetCoverFile(MangaFile file); /// /// Creates a Thumbnail version of an image /// /// Path to the image file - /// - public byte[] CreateThumbnail(string path); + /// File name with extension of the file. This will always write to + public string CreateThumbnail(string path, string fileName); /// /// Creates a Thumbnail version of a base64 image /// /// base64 encoded image - /// - public byte[] CreateThumbnailFromBase64(string encodedImage); + /// File name with extension of the file. This will always write to + public string CreateThumbnailFromBase64(string encodedImage, string fileName); } } diff --git a/API/Interfaces/Services/IMetadataService.cs b/API/Interfaces/Services/IMetadataService.cs index 70b10b861..6d4d725cf 100644 --- a/API/Interfaces/Services/IMetadataService.cs +++ b/API/Interfaces/Services/IMetadataService.cs @@ -1,4 +1,5 @@ -using API.Entities; +using System.Threading.Tasks; +using API.Entities; namespace API.Interfaces.Services { @@ -9,16 +10,16 @@ namespace API.Interfaces.Services /// /// /// - void RefreshMetadata(int libraryId, bool forceUpdate = false); + Task RefreshMetadata(int libraryId, bool forceUpdate = false); - public void UpdateMetadata(Chapter chapter, bool forceUpdate); - public void UpdateMetadata(Volume volume, bool forceUpdate); - public void UpdateMetadata(Series series, bool forceUpdate); + public bool UpdateMetadata(Chapter chapter, bool forceUpdate); + public bool UpdateMetadata(Volume volume, bool forceUpdate); + public bool UpdateMetadata(Series series, bool forceUpdate); /// /// Performs a forced refresh of metatdata just for a series and it's nested entities /// /// /// - void RefreshMetadataForSeries(int libraryId, int seriesId); + Task RefreshMetadataForSeries(int libraryId, int seriesId, bool forceUpdate = false); } -} \ No newline at end of file +} diff --git a/API/Interfaces/Services/IReaderService.cs b/API/Interfaces/Services/IReaderService.cs index 5bb9baeb1..a72b90699 100644 --- a/API/Interfaces/Services/IReaderService.cs +++ b/API/Interfaces/Services/IReaderService.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +using System.Collections.Generic; +using System.Threading.Tasks; using API.DTOs; using API.Entities; @@ -6,6 +7,11 @@ namespace API.Interfaces.Services { public interface IReaderService { - Task SaveReadingProgress(ProgressDto progressDto, AppUser user); + void MarkChaptersAsRead(AppUser user, int seriesId, IEnumerable chapters); + void MarkChaptersAsUnread(AppUser user, int seriesId, IEnumerable chapters); + Task SaveReadingProgress(ProgressDto progressDto, int userId); + Task CapPageToChapter(int chapterId, int page); + Task GetNextChapterIdAsync(int seriesId, int volumeId, int currentChapterId, int userId); + Task GetPrevChapterIdAsync(int seriesId, int volumeId, int currentChapterId, int userId); } } diff --git a/API/Interfaces/Services/IScannerService.cs b/API/Interfaces/Services/IScannerService.cs index d235adfb5..b67290bfc 100644 --- a/API/Interfaces/Services/IScannerService.cs +++ b/API/Interfaces/Services/IScannerService.cs @@ -12,8 +12,8 @@ namespace API.Interfaces.Services /// /// Library to scan against /// Force overwriting for cover images - void ScanLibrary(int libraryId, bool forceUpdate); - void ScanLibraries(); + Task ScanLibrary(int libraryId, bool forceUpdate); + Task ScanLibraries(); Task ScanSeries(int libraryId, int seriesId, bool forceUpdate, CancellationToken token); } } diff --git a/API/Interfaces/Services/ReaderService.cs b/API/Interfaces/Services/ReaderService.cs index f71a10a7a..eaa3b96d7 100644 --- a/API/Interfaces/Services/ReaderService.cs +++ b/API/Interfaces/Services/ReaderService.cs @@ -1,51 +1,146 @@  using System; using System.Collections.Generic; +using System.Data; using System.Linq; using System.Threading.Tasks; +using API.Comparators; +using API.Data.Repositories; using API.DTOs; using API.Entities; +using Microsoft.Extensions.Logging; namespace API.Interfaces.Services { public class ReaderService : IReaderService { private readonly IUnitOfWork _unitOfWork; + private readonly ILogger _logger; + private readonly ChapterSortComparer _chapterSortComparer = new ChapterSortComparer(); + private readonly ChapterSortComparerZeroFirst _chapterSortComparerForInChapterSorting = new ChapterSortComparerZeroFirst(); - public ReaderService(IUnitOfWork unitOfWork) + public ReaderService(IUnitOfWork unitOfWork, ILogger logger) { _unitOfWork = unitOfWork; + _logger = logger; + } + + /// + /// Marks all Chapters as Read by creating or updating UserProgress rows. Does not commit. + /// + /// + /// + /// + public void MarkChaptersAsRead(AppUser user, int seriesId, IEnumerable chapters) + { + foreach (var chapter in chapters) + { + var userProgress = GetUserProgressForChapter(user, chapter); + + if (userProgress == null) + { + user.Progresses.Add(new AppUserProgress + { + PagesRead = chapter.Pages, + VolumeId = chapter.VolumeId, + SeriesId = seriesId, + ChapterId = chapter.Id + }); + } + else + { + userProgress.PagesRead = chapter.Pages; + userProgress.SeriesId = seriesId; + userProgress.VolumeId = chapter.VolumeId; + } + } + } + + /// + /// Marks all Chapters as Unread by creating or updating UserProgress rows. Does not commit. + /// + /// + /// + /// + public void MarkChaptersAsUnread(AppUser user, int seriesId, IEnumerable chapters) + { + foreach (var chapter in chapters) + { + var userProgress = GetUserProgressForChapter(user, chapter); + + if (userProgress == null) + { + user.Progresses.Add(new AppUserProgress + { + PagesRead = 0, + VolumeId = chapter.VolumeId, + SeriesId = seriesId, + ChapterId = chapter.Id + }); + } + else + { + userProgress.PagesRead = 0; + userProgress.SeriesId = seriesId; + userProgress.VolumeId = chapter.VolumeId; + } + } + } + + /// + /// Gets the User Progress for a given Chapter. This will handle any duplicates that might have occured in past versions and will delete them. Does not commit. + /// + /// + /// + /// + public static AppUserProgress GetUserProgressForChapter(AppUser user, Chapter chapter) + { + AppUserProgress userProgress = null; + try + { + userProgress = + user.Progresses.SingleOrDefault(x => x.ChapterId == chapter.Id && x.AppUserId == user.Id); + } + catch (Exception) + { + // There is a very rare chance that user progress will duplicate current row. If that happens delete one with less pages + var progresses = user.Progresses.Where(x => x.ChapterId == chapter.Id && x.AppUserId == user.Id).ToList(); + if (progresses.Count > 1) + { + user.Progresses = new List() + { + user.Progresses.First() + }; + userProgress = user.Progresses.First(); + } + } + + return userProgress; } /// /// Saves progress to DB /// /// - /// + /// /// - public async Task SaveReadingProgress(ProgressDto progressDto, AppUser user) + public async Task SaveReadingProgress(ProgressDto progressDto, int userId) { // Don't let user save past total pages. - var chapter = await _unitOfWork.VolumeRepository.GetChapterAsync(progressDto.ChapterId); - if (progressDto.PageNum > chapter.Pages) - { - progressDto.PageNum = chapter.Pages; - } - - if (progressDto.PageNum < 0) - { - progressDto.PageNum = 0; - } + progressDto.PageNum = await CapPageToChapter(progressDto.ChapterId, progressDto.PageNum); try { - user.Progresses ??= new List(); var userProgress = - user.Progresses.FirstOrDefault(x => x.ChapterId == progressDto.ChapterId && x.AppUserId == user.Id); + await _unitOfWork.AppUserProgressRepository.GetUserProgressAsync(progressDto.ChapterId, userId); if (userProgress == null) { - user.Progresses.Add(new AppUserProgress + // Create a user object + var userWithProgress = + await _unitOfWork.UserRepository.GetUserByIdAsync(userId, AppUserIncludes.Progress); + userWithProgress.Progresses ??= new List(); + userWithProgress.Progresses.Add(new AppUserProgress { PagesRead = progressDto.PageNum, VolumeId = progressDto.VolumeId, @@ -54,6 +149,7 @@ namespace API.Interfaces.Services BookScrollId = progressDto.BookScrollId, LastModified = DateTime.Now }); + _unitOfWork.UserRepository.Update(userWithProgress); } else { @@ -62,21 +158,154 @@ namespace API.Interfaces.Services userProgress.VolumeId = progressDto.VolumeId; userProgress.BookScrollId = progressDto.BookScrollId; userProgress.LastModified = DateTime.Now; + _unitOfWork.AppUserProgressRepository.Update(userProgress); } - _unitOfWork.UserRepository.Update(user); - if (await _unitOfWork.CommitAsync()) { return true; } } - catch (Exception) + catch (Exception exception) { + _logger.LogError(exception, "Could not save progress"); await _unitOfWork.RollbackAsync(); } return false; } + + /// + /// Ensures that the page is within 0 and total pages for a chapter. Makes one DB call. + /// + /// + /// + /// + public async Task CapPageToChapter(int chapterId, int page) + { + var totalPages = await _unitOfWork.ChapterRepository.GetChapterTotalPagesAsync(chapterId); + if (page > totalPages) + { + page = totalPages; + } + + if (page < 0) + { + page = 0; + } + + return page; + } + + /// + /// Tries to find the next logical Chapter + /// + /// + /// V1 → V2 → V3 chapter 0 → V3 chapter 10 → SP 01 → SP 02 + /// + /// + /// + /// + /// + /// -1 if nothing can be found + public async Task GetNextChapterIdAsync(int seriesId, int volumeId, int currentChapterId, int userId) + { + var volumes = (await _unitOfWork.SeriesRepository.GetVolumesDtoAsync(seriesId, userId)).ToList(); + var currentVolume = volumes.Single(v => v.Id == volumeId); + var currentChapter = currentVolume.Chapters.Single(c => c.Id == currentChapterId); + + if (currentVolume.Number == 0) + { + // Handle specials by sorting on their Filename aka Range + var chapterId = GetNextChapterId(currentVolume.Chapters.OrderBy(x => x.Range, new NaturalSortComparer()), currentChapter.Number); + if (chapterId > 0) return chapterId; + } + + foreach (var volume in volumes) + { + if (volume.Number == currentVolume.Number && volume.Chapters.Count > 1) + { + // Handle Chapters within current Volume + // In this case, i need 0 first because 0 represents a full volume file. + var chapterId = GetNextChapterId(currentVolume.Chapters.OrderBy(x => double.Parse(x.Number), _chapterSortComparerForInChapterSorting), currentChapter.Number); + if (chapterId > 0) return chapterId; + } + + if (volume.Number != currentVolume.Number + 1) continue; + + // Handle Chapters within next Volume + // ! When selecting the chapter for the next volume, we need to make sure a c0 comes before a c1+ + var chapters = volume.Chapters.OrderBy(x => double.Parse(x.Number), _chapterSortComparer).ToList(); + if (currentChapter.Number.Equals("0") && chapters.Last().Number.Equals("0")) + { + return chapters.Last().Id; + } + + var firstChapter = chapters.FirstOrDefault(); + if (firstChapter == null) return -1; + return firstChapter.Id; + + } + + return -1; + } + /// + /// Tries to find the prev logical Chapter + /// + /// + /// V1 ← V2 ← V3 chapter 0 ← V3 chapter 10 ← SP 01 ← SP 02 + /// + /// + /// + /// + /// + /// -1 if nothing can be found + public async Task GetPrevChapterIdAsync(int seriesId, int volumeId, int currentChapterId, int userId) + { + var volumes = (await _unitOfWork.SeriesRepository.GetVolumesDtoAsync(seriesId, userId)).Reverse().ToList(); + var currentVolume = volumes.Single(v => v.Id == volumeId); + var currentChapter = currentVolume.Chapters.Single(c => c.Id == currentChapterId); + + if (currentVolume.Number == 0) + { + var chapterId = GetNextChapterId(currentVolume.Chapters.OrderBy(x => x.Range, new NaturalSortComparer()).Reverse(), currentChapter.Number); + if (chapterId > 0) return chapterId; + } + + foreach (var volume in volumes) + { + if (volume.Number == currentVolume.Number) + { + var chapterId = GetNextChapterId(currentVolume.Chapters.OrderBy(x => double.Parse(x.Number), _chapterSortComparerForInChapterSorting).Reverse(), currentChapter.Number); + if (chapterId > 0) return chapterId; + } + if (volume.Number == currentVolume.Number - 1) + { + var lastChapter = volume.Chapters + .OrderBy(x => double.Parse(x.Number), _chapterSortComparerForInChapterSorting).LastOrDefault(); + if (lastChapter == null) return -1; + return lastChapter.Id; + } + } + return -1; + } + + private static int GetNextChapterId(IEnumerable chapters, string currentChapterNumber) + { + var next = false; + var chaptersList = chapters.ToList(); + foreach (var chapter in chaptersList) + { + if (next) + { + return chapter.Id; + } + if (currentChapterNumber.Equals(chapter.Number)) next = true; + } + + return -1; + } + + } } diff --git a/API/Parser/Parser.cs b/API/Parser/Parser.cs index b7b4ee8eb..0650faf4a 100644 --- a/API/Parser/Parser.cs +++ b/API/Parser/Parser.cs @@ -13,7 +13,7 @@ namespace API.Parser public const string DefaultVolume = "0"; private static readonly TimeSpan RegexTimeout = TimeSpan.FromMilliseconds(500); - public const string ImageFileExtensions = @"^(\.png|\.jpeg|\.jpg)"; + public const string ImageFileExtensions = @"^(\.png|\.jpeg|\.jpg|\.webp)"; public const string ArchiveFileExtensions = @"\.cbz|\.zip|\.rar|\.cbr|\.tar.gz|\.7zip|\.7z|\.cb7|\.cbt"; public const string BookFileExtensions = @"\.epub|\.pdf"; public const string MacOsMetadataFileStartsWith = @"._"; @@ -102,11 +102,17 @@ namespace API.Parser @"^(?.*)( |_)Vol\.?(\d+|tbd)", RegexOptions.IgnoreCase | RegexOptions.Compiled, RegexTimeout), + // Mad Chimera World - Volume 005 - Chapter 026.cbz (couldn't figure out how to get Volume negative lookaround working on below regex), + // The Duke of Death and His Black Maid - Vol. 04 Ch. 054.5 - V4 Omake + new Regex( + @"(?.+?)(\s|_|-)+(?:Vol(ume|\.)?(\s|_|-)+\d+)(\s|_|-)+(?:(Ch|Chapter|Ch)\.?)(\s|_|-)+(?\d+)", + RegexOptions.IgnoreCase | RegexOptions.Compiled, + RegexTimeout), // Ichiban_Ushiro_no_Daimaou_v04_ch34_[VISCANS].zip, VanDread-v01-c01.zip new Regex( - @"(?.*)(\b|_)v(?\d+-?\d*)(\s|_|-)", - RegexOptions.IgnoreCase | RegexOptions.Compiled, - RegexTimeout), + @"(?.*)(\b|_)v(?\d+-?\d*)(\s|_|-)", + RegexOptions.IgnoreCase | RegexOptions.Compiled, + RegexTimeout), // Gokukoku no Brynhildr - c001-008 (v01) [TrinityBAKumA], Black Bullet - v4 c17 [batoto] new Regex( @"(?.*)( - )(?:v|vo|c)\d", @@ -117,11 +123,6 @@ namespace API.Parser @"(?.*)(?:, Chapter )(?\d+)", RegexOptions.IgnoreCase | RegexOptions.Compiled, RegexTimeout), - // Mad Chimera World - Volume 005 - Chapter 026.cbz (couldn't figure out how to get Volume negative lookaround working on below regex) - new Regex( - @"(?.*)(\s|_|-)(?:Volume(\s|_|-)+\d+)(\s|_|-)+(?:Chapter)(\s|_|-)(?\d+)", - RegexOptions.IgnoreCase | RegexOptions.Compiled, - RegexTimeout), // Please Go Home, Akutsu-San! - Chapter 038.5 - Volume Announcement.cbz new Regex( @"(?.*)(\s|_|-)(?!Vol)(\s|_|-)(?:Chapter)(\s|_|-)(?\d+)", @@ -129,9 +130,14 @@ namespace API.Parser RegexTimeout), // [dmntsf.net] One Piece - Digital Colored Comics Vol. 20 Ch. 177 - 30 Million vs 81 Million.cbz new Regex( - @"(?.*) (\b|_|-)(vol)\.?", + @"(?.*) (\b|_|-)(vol)\.?(\s|-|_)?\d+", RegexOptions.IgnoreCase | RegexOptions.Compiled, RegexTimeout), + // [xPearse] Kyochuu Rettou Volume 1 [English] [Manga] [Volume Scans] + new Regex( + @"(?.*) (\b|_|-)(vol)(ume)", + RegexOptions.IgnoreCase | RegexOptions.Compiled, + RegexTimeout), //Knights of Sidonia c000 (S2 LE BD Omake - BLAME!) [Habanero Scans] new Regex( @"(?.*)(\bc\d+\b)", @@ -144,7 +150,7 @@ namespace API.Parser RegexTimeout), // Momo The Blood Taker - Chapter 027 Violent Emotion.cbz, Grand Blue Dreaming - SP02 Extra (2019) (Digital) (danke-Empire).cbz new Regex( - @"(?.*)(\b|_|-|\s)(?:(chapter(\b|_|-|\s))|sp)\d", + @"^(?(?!Vol).+?)(?:(ch(apter|\.)(\b|_|-|\s))|sp)\d", RegexOptions.IgnoreCase | RegexOptions.Compiled, RegexTimeout), // Historys Strongest Disciple Kenichi_v11_c90-98.zip, Killing Bites Vol. 0001 Ch. 0001 - Galactica Scanlations (gb) @@ -240,9 +246,9 @@ namespace API.Parser @"(?.*)(\s|_|-)#", RegexOptions.IgnoreCase | RegexOptions.Compiled, RegexTimeout), - // Baketeriya ch01-05.zip, Akiiro Bousou Biyori - 01.jpg, Beelzebub_172_RHS.zip, Cynthia the Mission 29.rar + // Baketeriya ch01-05.zip, Akiiro Bousou Biyori - 01.jpg, Beelzebub_172_RHS.zip, Cynthia the Mission 29.rar, A Compendium of Ghosts - 031 - The Third Story_ Part 12 (Digital) (Cobalt001) new Regex( - @"^(?!Vol\.?)(?.*)( |_|-)(?.+?)( |_|-)(?.*)(?: |_)i(ssue) #\d+", RegexOptions.IgnoreCase | RegexOptions.Compiled, RegexTimeout), + // Batman Wayne Family Adventures - Ep. 001 - Moving In + new Regex( + @"^(?.+?)(\s|_|-)?(?:Ep\.?)(\s|_|-)+\d+", + RegexOptions.IgnoreCase | RegexOptions.Compiled, + RegexTimeout), // Batman & Catwoman - Trail of the Gun 01, Batman & Grendel (1996) 01 - Devil's Bones, Teen Titans v1 001 (1966-02) (digital) (OkC.O.M.P.U.T.O.-Novus) new Regex( - @"^(?.*)(?: \d+)", + @"^(?.+?)(?: \d+)", RegexOptions.IgnoreCase | RegexOptions.Compiled, RegexTimeout), // Batman & Robin the Teen Wonder #0 @@ -318,78 +329,91 @@ namespace API.Parser private static readonly Regex[] ComicVolumeRegex = new[] { - // 04 - Asterix the Gladiator (1964) (Digital-Empire) (WebP by Doc MaKS) - new Regex( - @"^(?\d+) (- |_)?(?.*(\d{4})?)( |_)(\(|\d+)", - RegexOptions.IgnoreCase | RegexOptions.Compiled, - RegexTimeout), - // 01 Spider-Man & Wolverine 01.cbr - new Regex( - @"^(?\d+) (?:- )?(?.*) (\d+)?", - RegexOptions.IgnoreCase | RegexOptions.Compiled, - RegexTimeout), - // Batman & Wildcat (1 of 3) - new Regex( - @"(?.*(\d{4})?)( |_)(?:\((?\d+) of \d+)", - RegexOptions.IgnoreCase | RegexOptions.Compiled, - RegexTimeout), + // // 04 - Asterix the Gladiator (1964) (Digital-Empire) (WebP by Doc MaKS) + // new Regex( + // @"^(?\d+) (- |_)?(?.*(\d{4})?)( |_)(\(|\d+)", + // RegexOptions.IgnoreCase | RegexOptions.Compiled, + // RegexTimeout), + // // 01 Spider-Man & Wolverine 01.cbr + // new Regex( + // @"^(?\d+) (?:- )?(?.*) (\d+)?", + // RegexOptions.IgnoreCase | RegexOptions.Compiled, + // RegexTimeout), + // // Batman & Wildcat (1 of 3) + // new Regex( + // @"(?.*(\d{4})?)( |_)(?:\((?\d+) of \d+)", + // RegexOptions.IgnoreCase | RegexOptions.Compiled, + // RegexTimeout), // Teen Titans v1 001 (1966-02) (digital) (OkC.O.M.P.U.T.O.-Novus) new Regex( @"^(?.*)(?: |_)v(?\d+)", RegexOptions.IgnoreCase | RegexOptions.Compiled, RegexTimeout), // Scott Pilgrim 02 - Scott Pilgrim vs. The World (2005) - new Regex( - @"^(?.*)(?\d+)", - RegexOptions.IgnoreCase | RegexOptions.Compiled, - RegexTimeout), + // BUG: Negative lookbehind has to be fixed width + // NOTE: The case this is built for does not make much sense. + // new Regex( + // @"^(?.+?)(?\d+)", + // RegexOptions.IgnoreCase | RegexOptions.Compiled, + // RegexTimeout), + // Batman & Catwoman - Trail of the Gun 01, Batman & Grendel (1996) 01 - Devil's Bones, Teen Titans v1 001 (1966-02) (digital) (OkC.O.M.P.U.T.O.-Novus) - new Regex( - @"^(?.*)(?\d+))", - RegexOptions.IgnoreCase | RegexOptions.Compiled, - RegexTimeout), - // Batman & Robin the Teen Wonder #0 - new Regex( - @"^(?.*)(?: |_)#(?\d+)", - RegexOptions.IgnoreCase | RegexOptions.Compiled, - RegexTimeout), + // new Regex( + // @"^(?.+?)(?\d+))", + // RegexOptions.IgnoreCase | RegexOptions.Compiled, + // RegexTimeout), + // // Batman & Robin the Teen Wonder #0 + // new Regex( + // @"^(?.*)(?: |_)#(?\d+)", + // RegexOptions.IgnoreCase | RegexOptions.Compiled, + // RegexTimeout), }; private static readonly Regex[] ComicChapterRegex = new[] { - // Batman & Wildcat (1 of 3) + // Batman & Wildcat (1 of 3) new Regex( @"(?.*(\d{4})?)( |_)(?:\((?\d+) of \d+)", RegexOptions.IgnoreCase | RegexOptions.Compiled, RegexTimeout), + // Batman Beyond 04 (of 6) (1999) + new Regex( + @"(?.+?)(?\d+)(\s|_|-)?\(of", + RegexOptions.IgnoreCase | RegexOptions.Compiled, + RegexTimeout), // Teen Titans v1 001 (1966-02) (digital) (OkC.O.M.P.U.T.O.-Novus) new Regex( - @"^(?.*)(?: |_)v(?\d+)(?: |_)(c? ?)(?(\d+(\.\d)?)-?(\d+(\.\d)?)?)(c? ?)", - RegexOptions.IgnoreCase | RegexOptions.Compiled, - RegexTimeout), - // Batman & Catwoman - Trail of the Gun 01, Batman & Grendel (1996) 01 - Devil's Bones, Teen Titans v1 001 (1966-02) (digital) (OkC.O.M.P.U.T.O.-Novus) - new Regex( - @"^(?.*)(?: (?\d+))", - RegexOptions.IgnoreCase | RegexOptions.Compiled, - RegexTimeout), - // Batman & Robin the Teen Wonder #0 - new Regex( - @"^(?.*)(?: |_)#(?\d+)", + @"^(?.+?)(?: |_)v(?\d+)(?: |_)(c? ?)(?(\d+(\.\d)?)-?(\d+(\.\d)?)?)(c? ?)", RegexOptions.IgnoreCase | RegexOptions.Compiled, RegexTimeout), // Invincible 070.5 - Invincible Returns 1 (2010) (digital) (Minutemen-InnerDemons).cbr new Regex( - @"^(?.*)(?: |_)(c? ?)(?(\d+(\.\d)?)-?(\d+(\.\d)?)?)(c? ?)-", + @"^(?.+?)(?: |_)(c? ?)(?(\d+(\.\d)?)-?(\d+(\.\d)?)?)(c? ?)-", + RegexOptions.IgnoreCase | RegexOptions.Compiled, + RegexTimeout), + // Batman & Catwoman - Trail of the Gun 01, Batman & Grendel (1996) 01 - Devil's Bones, Teen Titans v1 001 (1966-02) (digital) (OkC.O.M.P.U.T.O.-Novus) + new Regex( + @"^(?.+?)(?: (?\d+))", + RegexOptions.IgnoreCase | RegexOptions.Compiled, + RegexTimeout), + // Batman & Robin the Teen Wonder #0 + new Regex( + @"^(?.+?)(?:\s|_)#(?\d+)", + RegexOptions.IgnoreCase | RegexOptions.Compiled, + RegexTimeout), + // Saga 001 (2012) (Digital) (Empire-Zone) + new Regex( + @"(?.+?)(?: |_)(c? ?)(?(\d+(\.\d)?)-?(\d+(\.\d)?)?)\s\(\d{4}", RegexOptions.IgnoreCase | RegexOptions.Compiled, RegexTimeout), // Amazing Man Comics chapter 25 new Regex( - @"^(?!Vol)(?.*)( |_)c(hapter)( |_)(?\d*)", + @"^(?!Vol)(?.+?)( |_)c(hapter)( |_)(?\d*)", RegexOptions.IgnoreCase | RegexOptions.Compiled, RegexTimeout), // Amazing Man Comics issue #25 new Regex( - @"^(?!Vol)(?.*)( |_)i(ssue)( |_) #(?\d*)", + @"^(?!Vol)(?.+?)( |_)i(ssue)( |_) #(?\d*)", RegexOptions.IgnoreCase | RegexOptions.Compiled, RegexTimeout), }; @@ -422,14 +446,14 @@ namespace API.Parser @"^(?.*)(?: |_)#(?\d+)", RegexOptions.IgnoreCase | RegexOptions.Compiled, RegexTimeout), - // Green Worldz - Chapter 027 + // Green Worldz - Chapter 027, Kimi no Koto ga Daidaidaidaidaisuki na 100-nin no Kanojo Chapter 11-10 new Regex( - @"^(?!Vol)(?.*)\s?(?\d+(?:\.?[\d-])?)", + @"^(?!Vol)(?.*)\s?(?\d+(?:\.?[\d-]+)?)", RegexOptions.IgnoreCase | RegexOptions.Compiled, RegexTimeout), // Hinowa ga CRUSH! 018 (2019) (Digital) (LuCaZ).cbz, Hinowa ga CRUSH! 018.5 (2019) (Digital) (LuCaZ).cbz new Regex( - @"^(?!Vol)(?.*)\s(?\d+(?:.\d+|-\d+)?)(?:\s\(\d{4}\))?(\b|_|-)", + @"^(?!Vol)(?.+?)\s(?\d+(?:.\d+|-\d+)?)(?:\s\(\d{4}\))?(\b|_|-)", RegexOptions.IgnoreCase | RegexOptions.Compiled, RegexTimeout), // Tower Of God S01 014 (CBT) (digital).cbz @@ -822,8 +846,14 @@ namespace API.Parser var tokens = value.Split("-"); var from = RemoveLeadingZeroes(tokens[0]); - var to = RemoveLeadingZeroes(hasChapterPart ? AddChapterPart(tokens[1]) : tokens[1]); - return $"{@from}-{to}"; + if (tokens.Length == 2) + { + var to = RemoveLeadingZeroes(hasChapterPart ? AddChapterPart(tokens[1]) : tokens[1]); + return $"{@from}-{to}"; + } + + return from; + } } @@ -919,6 +949,9 @@ namespace API.Parser /// /// Translates _ -> spaces, trims front and back of string, removes release groups + /// + /// Hippos_the_Great [Digital], -> Hippos the Great + /// /// /// /// @@ -931,7 +964,7 @@ namespace API.Parser title = RemoveSpecialTags(title); title = title.Replace("_", " ").Trim(); - if (title.EndsWith("-")) + if (title.EndsWith("-") || title.EndsWith(",")) { title = title.Substring(0, title.Length - 1); } diff --git a/API/Program.cs b/API/Program.cs index 6d91f6d98..eddc4cb4e 100644 --- a/API/Program.cs +++ b/API/Program.cs @@ -1,10 +1,17 @@ using System; +using System.Collections.Generic; +using System.Data; using System.IO; +using System.Linq; using System.Security.Cryptography; using System.Threading; +using System.Threading.Channels; using System.Threading.Tasks; using API.Data; using API.Entities; +using API.Helpers; +using API.Interfaces; +using API.Services; using Kavita.Common; using Kavita.Common.EnvironmentInfo; using Microsoft.AspNetCore.Hosting; @@ -14,6 +21,8 @@ using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; +using Microsoft.IO; +using NetVips; using Sentry; namespace API @@ -49,8 +58,29 @@ namespace API { var context = services.GetRequiredService(); var roleManager = services.GetRequiredService>(); + + var requiresCoverImageMigration = !Directory.Exists(DirectoryService.CoverImageDirectory); + try + { + // If this is a new install, tables wont exist yet + if (requiresCoverImageMigration) + { + MigrateCoverImages.ExtractToImages(context); + } + } + catch (Exception ) + { + requiresCoverImageMigration = false; + } + // Apply all migrations on startup await context.Database.MigrateAsync(); + + if (requiresCoverImageMigration) + { + await MigrateCoverImages.UpdateDatabaseWithImages(context); + } + await Seed.SeedRoles(roleManager); await Seed.SeedSettings(context); await Seed.SeedUserApiKeys(context); diff --git a/API/Services/ArchiveService.cs b/API/Services/ArchiveService.cs index d8b381b60..bfa36595c 100644 --- a/API/Services/ArchiveService.cs +++ b/API/Services/ArchiveService.cs @@ -28,7 +28,6 @@ namespace API.Services { private readonly ILogger _logger; private readonly IDirectoryService _directoryService; - private static readonly RecyclableMemoryStreamManager StreamManager = new(); private readonly NaturalSortComparer _comparer; private const string ComicInfoFilename = "comicinfo"; @@ -147,12 +146,13 @@ namespace API.Services /// /// This skips over any __MACOSX folder/file iteration. /// + /// This always creates a thumbnail /// - /// Create a smaller variant of file extracted from archive. Archive images are usually 1MB each. + /// File name to use based on context of entity. /// - public byte[] GetCoverImage(string archivePath, bool createThumbnail = false) + public string GetCoverImage(string archivePath, string fileName) { - if (archivePath == null || !IsValidArchive(archivePath)) return Array.Empty(); + if (archivePath == null || !IsValidArchive(archivePath)) return String.Empty; try { var libraryHandler = CanOpen(archivePath); @@ -168,7 +168,7 @@ namespace API.Services var entry = archive.Entries.Single(e => e.FullName == entryName); using var stream = entry.Open(); - return createThumbnail ? CreateThumbnail(entry.FullName, stream) : ConvertEntryToByteArray(entry); + return CreateThumbnail(archivePath + " - " + entry.FullName, stream, fileName); } case ArchiveLibrary.SharpCompress: { @@ -179,18 +179,16 @@ namespace API.Services var entryName = FindFolderEntry(entryNames) ?? FirstFileEntry(entryNames); var entry = archive.Entries.Single(e => e.Key == entryName); - using var ms = StreamManager.GetStream(); - entry.WriteTo(ms); - ms.Position = 0; + using var stream = entry.OpenEntryStream(); - return createThumbnail ? CreateThumbnail(entry.Key, ms, Path.GetExtension(entry.Key)) : ms.ToArray(); + return CreateThumbnail(archivePath + " - " + entry.Key, stream, fileName); } case ArchiveLibrary.NotSupported: _logger.LogWarning("[GetCoverImage] This archive cannot be read: {ArchivePath}. Defaulting to no cover image", archivePath); - return Array.Empty(); + return string.Empty; default: _logger.LogWarning("[GetCoverImage] There was an exception when reading archive stream: {ArchivePath}. Defaulting to no cover image", archivePath); - return Array.Empty(); + return string.Empty; } } catch (Exception ex) @@ -198,15 +196,7 @@ namespace API.Services _logger.LogWarning(ex, "[GetCoverImage] There was an exception when reading archive stream: {ArchivePath}. Defaulting to no cover image", archivePath); } - return Array.Empty(); - } - - private static byte[] ConvertEntryToByteArray(ZipArchiveEntry entry) - { - using var stream = entry.Open(); - using var ms = StreamManager.GetStream(); - stream.CopyTo(ms); - return ms.ToArray(); + return string.Empty; } ///
@@ -223,6 +213,7 @@ namespace API.Services archive.Entries.Any(e => e.FullName.Contains(Path.AltDirectorySeparatorChar) && !Parser.Parser.HasBlacklistedFolderInPath(e.FullName)); } + // TODO: Refactor CreateZipForDownload to return the temp file so we can stream it from temp public async Task> CreateZipForDownload(IEnumerable files, string tempFolder) { var dateString = DateTime.Now.ToShortDateString().Replace("/", "_"); @@ -254,23 +245,18 @@ namespace API.Services return Tuple.Create(fileBytes, zipPath); } - private byte[] CreateThumbnail(string entryName, Stream stream, string formatExtension = ".jpg") + private string CreateThumbnail(string entryName, Stream stream, string fileName) { - if (!formatExtension.StartsWith(".")) - { - formatExtension = $".{formatExtension}"; - } try { - using var thumbnail = Image.ThumbnailStream(stream, MetadataService.ThumbnailWidth); - return thumbnail.WriteToBuffer(formatExtension); + return ImageService.WriteCoverThumbnail(stream, fileName); } catch (Exception ex) { _logger.LogWarning(ex, "[GetCoverImage] There was an error and prevented thumbnail generation on {EntryName}. Defaulting to no cover image", entryName); } - return Array.Empty(); + return string.Empty; } /// @@ -303,9 +289,7 @@ namespace API.Services && !Parser.Parser.HasBlacklistedFolderInPath(entry.Key) && Parser.Parser.IsXml(entry.Key)) { - using var ms = StreamManager.GetStream(); - entry.WriteTo(ms); - ms.Position = 0; + using var ms = entry.OpenEntryStream(); var serializer = new XmlSerializer(typeof(ComicInfo)); var info = (ComicInfo) serializer.Deserialize(ms); @@ -332,7 +316,7 @@ namespace API.Services { case ArchiveLibrary.Default: { - _logger.LogDebug("Using default compression handling"); + _logger.LogTrace("Using default compression handling"); using var archive = ZipFile.OpenRead(archivePath); var entry = archive.Entries.SingleOrDefault(x => !Parser.Parser.HasBlacklistedFolderInPath(x.FullName) && Path.GetFileNameWithoutExtension(x.Name)?.ToLower() == ComicInfoFilename @@ -348,7 +332,7 @@ namespace API.Services } case ArchiveLibrary.SharpCompress: { - _logger.LogDebug("Using SharpCompress compression handling"); + _logger.LogTrace("Using SharpCompress compression handling"); using var archive = ArchiveFactory.Open(archivePath); info = FindComicInfoXml(archive.Entries.Where(entry => !entry.IsDirectory && !Parser.Parser.HasBlacklistedFolderInPath(Path.GetDirectoryName(entry.Key) ?? string.Empty) diff --git a/API/Services/BookService.cs b/API/Services/BookService.cs index 6c02b68db..6231de20a 100644 --- a/API/Services/BookService.cs +++ b/API/Services/BookService.cs @@ -4,6 +4,7 @@ using System.Drawing; using System.Drawing.Imaging; using System.IO; using System.Linq; +using System.Net; using System.Runtime.InteropServices; using System.Text; using System.Text.RegularExpressions; @@ -378,18 +379,25 @@ namespace API.Services for (var pageNumber = 0; pageNumber < pages; pageNumber++) { GetPdfPage(docReader, pageNumber, stream); - File.WriteAllBytes(Path.Combine(targetDirectory, "Page-" + pageNumber + ".png"), stream.ToArray()); + using var fileStream = File.Create(Path.Combine(targetDirectory, "Page-" + pageNumber + ".png")); + stream.Seek(0, SeekOrigin.Begin); + stream.CopyTo(fileStream); } } - - public byte[] GetCoverImage(string fileFilePath, bool createThumbnail = true) + /// + /// Extracts the cover image to covers directory and returns file path back + /// + /// + /// Name of the new file. + /// + public string GetCoverImage(string fileFilePath, string fileName) { - if (!IsValidFile(fileFilePath)) return Array.Empty(); + if (!IsValidFile(fileFilePath)) return String.Empty; if (Parser.Parser.IsPdf(fileFilePath)) { - return GetPdfCoverImage(fileFilePath, createThumbnail); + return GetPdfCoverImage(fileFilePath, fileName); } using var epubBook = EpubReader.OpenBook(fileFilePath); @@ -402,47 +410,41 @@ namespace API.Services ?? epubBook.Content.Images.Values.FirstOrDefault(file => Parser.Parser.IsCoverImage(file.FileName)) ?? epubBook.Content.Images.Values.FirstOrDefault(); - if (coverImageContent == null) return Array.Empty(); - - if (!createThumbnail) return coverImageContent.ReadContent(); + if (coverImageContent == null) return string.Empty; using var stream = StreamManager.GetStream("BookService.GetCoverImage", coverImageContent.ReadContent()); - using var thumbnail = NetVips.Image.ThumbnailStream(stream, MetadataService.ThumbnailWidth); - return thumbnail.WriteToBuffer(".jpg"); - + return ImageService.WriteCoverThumbnail(stream, fileName); } catch (Exception ex) { _logger.LogWarning(ex, "[BookService] There was a critical error and prevented thumbnail generation on {BookFile}. Defaulting to no cover image", fileFilePath); } - return Array.Empty(); + return string.Empty; } - private byte[] GetPdfCoverImage(string fileFilePath, bool createThumbnail) + + private string GetPdfCoverImage(string fileFilePath, string fileName) { - try - { - using var docReader = DocLib.Instance.GetDocReader(fileFilePath, new PageDimensions(1080, 1920)); - if (docReader.GetPageCount() == 0) return Array.Empty(); + try + { + using var docReader = DocLib.Instance.GetDocReader(fileFilePath, new PageDimensions(1080, 1920)); + if (docReader.GetPageCount() == 0) return string.Empty; - using var stream = StreamManager.GetStream("BookService.GetPdfPage"); - GetPdfPage(docReader, 0, stream); + using var stream = StreamManager.GetStream("BookService.GetPdfPage"); + GetPdfPage(docReader, 0, stream); - if (!createThumbnail) return stream.ToArray(); + return ImageService.WriteCoverThumbnail(stream, fileName); - using var thumbnail = NetVips.Image.ThumbnailStream(stream, MetadataService.ThumbnailWidth); - return thumbnail.WriteToBuffer(".png"); + } + catch (Exception ex) + { + _logger.LogWarning(ex, + "[BookService] There was a critical error and prevented thumbnail generation on {BookFile}. Defaulting to no cover image", + fileFilePath); + } - } - catch (Exception ex) - { - _logger.LogWarning(ex, - "[BookService] There was a critical error and prevented thumbnail generation on {BookFile}. Defaulting to no cover image", - fileFilePath); - } - - return Array.Empty(); + return string.Empty; } private static void GetPdfPage(IDocReader docReader, int pageNumber, Stream stream) diff --git a/API/Services/CacheService.cs b/API/Services/CacheService.cs index 968abaa72..8decdeccd 100644 --- a/API/Services/CacheService.cs +++ b/API/Services/CacheService.cs @@ -67,7 +67,7 @@ namespace API.Services public async Task Ensure(int chapterId) { EnsureCacheDirectory(); - var chapter = await _unitOfWork.VolumeRepository.GetChapterAsync(chapterId); + var chapter = await _unitOfWork.ChapterRepository.GetChapterAsync(chapterId); var extractPath = GetCachePath(chapterId); if (!Directory.Exists(extractPath)) @@ -192,7 +192,7 @@ namespace API.Services { // Calculate what chapter the page belongs to var pagesSoFar = 0; - var chapterFiles = chapter.Files ?? await _unitOfWork.VolumeRepository.GetFilesForChapterAsync(chapter.Id); + var chapterFiles = chapter.Files ?? await _unitOfWork.ChapterRepository.GetFilesForChapterAsync(chapter.Id); foreach (var mangaFile in chapterFiles) { if (page <= (mangaFile.Pages + pagesSoFar)) diff --git a/API/Services/DirectoryService.cs b/API/Services/DirectoryService.cs index 6d545ea21..360492303 100644 --- a/API/Services/DirectoryService.cs +++ b/API/Services/DirectoryService.cs @@ -19,6 +19,7 @@ namespace API.Services public static readonly string TempDirectory = Path.Join(Directory.GetCurrentDirectory(), "temp"); public static readonly string LogDirectory = Path.Join(Directory.GetCurrentDirectory(), "logs"); public static readonly string CacheDirectory = Path.Join(Directory.GetCurrentDirectory(), "cache"); + public static readonly string CoverImageDirectory = Path.Join(Directory.GetCurrentDirectory(), "covers"); public DirectoryService(ILogger logger) { @@ -305,6 +306,44 @@ namespace API.Services } + /// + /// Finds the highest directories from a set of MangaFiles + /// + /// List of top level folders which files belong to + /// List of file paths that belong to libraryFolders + /// + public static Dictionary FindHighestDirectoriesFromFiles(IEnumerable libraryFolders, IList filePaths) + { + var stopLookingForDirectories = false; + var dirs = new Dictionary(); + foreach (var folder in libraryFolders) + { + if (stopLookingForDirectories) break; + foreach (var file in filePaths) + { + if (!file.Contains(folder)) continue; + + var parts = GetFoldersTillRoot(folder, file).ToList(); + if (parts.Count == 0) + { + // Break from all loops, we done, just scan folder.Path (library root) + dirs.Add(folder, string.Empty); + stopLookingForDirectories = true; + break; + } + + var fullPath = Path.Join(folder, parts.Last()); + if (!dirs.ContainsKey(fullPath)) + { + dirs.Add(fullPath, string.Empty); + } + } + } + + return dirs; + } + + /// /// Recursively scans files and applies an action on them. This uses as many cores the underlying PC has to speed /// up processing. diff --git a/API/Services/DownloadService.cs b/API/Services/DownloadService.cs index 6013d5c84..7d0f56b3d 100644 --- a/API/Services/DownloadService.cs +++ b/API/Services/DownloadService.cs @@ -4,7 +4,6 @@ using System.Linq; using System.Threading.Tasks; using API.Entities; using API.Interfaces.Services; -using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.StaticFiles; namespace API.Services diff --git a/API/Services/ImageService.cs b/API/Services/ImageService.cs index cc4d92742..0f0f3aa16 100644 --- a/API/Services/ImageService.cs +++ b/API/Services/ImageService.cs @@ -14,13 +14,20 @@ namespace API.Services { private readonly ILogger _logger; private readonly IDirectoryService _directoryService; - private readonly NaturalSortComparer _naturalSortComparer; + public const string ChapterCoverImageRegex = @"v\d+_c\d+"; + public const string SeriesCoverImageRegex = @"seres\d+"; + public const string CollectionTagCoverImageRegex = @"tag\d+"; + + + /// + /// Width of the Thumbnail generation + /// + private const int ThumbnailWidth = 320; public ImageService(ILogger logger, IDirectoryService directoryService) { _logger = logger; _directoryService = directoryService; - _naturalSortComparer = new NaturalSortComparer(); } /// @@ -38,68 +45,108 @@ namespace API.Services } var firstImage = _directoryService.GetFilesWithExtension(directory, Parser.Parser.ImageFileExtensions) - .OrderBy(f => f, _naturalSortComparer).FirstOrDefault(); + .OrderBy(f => f, new NaturalSortComparer()).FirstOrDefault(); return firstImage; } - public byte[] GetCoverImage(string path, bool createThumbnail = false) + public string GetCoverImage(string path, string fileName) { - if (string.IsNullOrEmpty(path)) return Array.Empty(); + if (string.IsNullOrEmpty(path)) return string.Empty; try { - if (createThumbnail) - { - return CreateThumbnail(path); - } - - using var img = Image.NewFromFile(path); - using var stream = new MemoryStream(); - img.JpegsaveStream(stream); - stream.Position = 0; - return stream.ToArray(); + return CreateThumbnail(path, fileName); } catch (Exception ex) { _logger.LogWarning(ex, "[GetCoverImage] There was an error and prevented thumbnail generation on {ImageFile}. Defaulting to no cover image", path); } - return Array.Empty(); + return string.Empty; } - /// - public byte[] CreateThumbnail(string path) + public string CreateThumbnail(string path, string fileName) { try { - using var thumbnail = Image.Thumbnail(path, MetadataService.ThumbnailWidth); - return thumbnail.WriteToBuffer(".jpg"); + using var thumbnail = Image.Thumbnail(path, ThumbnailWidth); + var filename = fileName + ".png"; + thumbnail.WriteToFile(Path.Join(DirectoryService.CoverImageDirectory, fileName + ".png")); + return filename; } catch (Exception e) { _logger.LogError(e, "Error creating thumbnail from url"); } - return Array.Empty(); + return string.Empty; + } + + /// + /// Creates a thumbnail out of a memory stream and saves to with the passed + /// fileName and .png extension. + /// + /// Stream to write to disk. Ensure this is rewinded. + /// filename to save as without extension + /// File name with extension of the file. This will always write to + public static string WriteCoverThumbnail(Stream stream, string fileName) + { + using var thumbnail = NetVips.Image.ThumbnailStream(stream, ThumbnailWidth); + var filename = fileName + ".png"; + thumbnail.WriteToFile(Path.Join(DirectoryService.CoverImageDirectory, fileName + ".png")); + return filename; } /// - public byte[] CreateThumbnailFromBase64(string encodedImage) + public string CreateThumbnailFromBase64(string encodedImage, string fileName) { try { - using var thumbnail = Image.ThumbnailBuffer(Convert.FromBase64String(encodedImage), MetadataService.ThumbnailWidth); - return thumbnail.WriteToBuffer(".jpg"); + using var thumbnail = Image.ThumbnailBuffer(Convert.FromBase64String(encodedImage), ThumbnailWidth); + var filename = fileName + ".png"; + thumbnail.WriteToFile(Path.Join(DirectoryService.CoverImageDirectory, fileName + ".png")); + return filename; } catch (Exception e) { _logger.LogError(e, "Error creating thumbnail from url"); } - return Array.Empty(); + return string.Empty; + } + + /// + /// Returns the name format for a chapter cover image + /// + /// + /// + /// + public static string GetChapterFormat(int chapterId, int volumeId) + { + return $"v{volumeId}_c{chapterId}"; + } + + /// + /// Returns the name format for a series cover image + /// + /// + /// + public static string GetSeriesFormat(int seriesId) + { + return $"series{seriesId}"; + } + + /// + /// Returns the name format for a collection tag cover image + /// + /// + /// + public static string GetCollectionTagFormat(int tagId) + { + return $"tag{tagId}"; } } } diff --git a/API/Services/MetadataService.cs b/API/Services/MetadataService.cs index aa175c021..d443f9f23 100644 --- a/API/Services/MetadataService.cs +++ b/API/Services/MetadataService.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.IO; using System.Linq; using System.Threading.Tasks; using API.Comparators; @@ -9,6 +10,8 @@ using API.Entities.Enums; using API.Extensions; using API.Interfaces; using API.Interfaces.Services; +using API.SignalR; +using Microsoft.AspNetCore.SignalR; using Microsoft.Extensions.Logging; namespace API.Services @@ -20,58 +23,70 @@ namespace API.Services private readonly IArchiveService _archiveService; private readonly IBookService _bookService; private readonly IImageService _imageService; + private readonly IHubContext _messageHub; private readonly ChapterSortComparerZeroFirst _chapterSortComparerForInChapterSorting = new ChapterSortComparerZeroFirst(); - /// - /// Width of the Thumbnail generation - /// - public static readonly int ThumbnailWidth = 320; // 153w x 230h public MetadataService(IUnitOfWork unitOfWork, ILogger logger, - IArchiveService archiveService, IBookService bookService, IImageService imageService) + IArchiveService archiveService, IBookService bookService, IImageService imageService, IHubContext messageHub) { _unitOfWork = unitOfWork; _logger = logger; _archiveService = archiveService; _bookService = bookService; _imageService = imageService; + _messageHub = messageHub; } /// - /// Determines whether an entity should regenerate cover image + /// Determines whether an entity should regenerate cover image. /// + /// If a cover image is locked but the underlying file has been deleted, this will allow regenerating. /// /// /// /// + /// Directory where cover images are. Defaults to /// - public static bool ShouldUpdateCoverImage(byte[] coverImage, MangaFile firstFile, bool forceUpdate = false, - bool isCoverLocked = false) + public static bool ShouldUpdateCoverImage(string coverImage, MangaFile firstFile, bool forceUpdate = false, + bool isCoverLocked = false, string coverImageDirectory = null) { - if (isCoverLocked) return false; + if (string.IsNullOrEmpty(coverImageDirectory)) + { + coverImageDirectory = DirectoryService.CoverImageDirectory; + } + + var fileExists = File.Exists(Path.Join(coverImageDirectory, coverImage)); + if (isCoverLocked && fileExists) return false; if (forceUpdate) return true; - return (firstFile != null && firstFile.HasFileBeenModified()) || !HasCoverImage(coverImage); + return (firstFile != null && firstFile.HasFileBeenModified()) || !HasCoverImage(coverImage, fileExists); } - private static bool HasCoverImage(byte[] coverImage) + + private static bool HasCoverImage(string coverImage) { - return coverImage != null && coverImage.Any(); + return HasCoverImage(coverImage, File.Exists(coverImage)); } - private byte[] GetCoverImage(MangaFile file, bool createThumbnail = true) + private static bool HasCoverImage(string coverImage, bool fileExists) + { + return !string.IsNullOrEmpty(coverImage) && fileExists; + } + + private string GetCoverImage(MangaFile file, int volumeId, int chapterId) { file.LastModified = DateTime.Now; switch (file.Format) { case MangaFormat.Pdf: case MangaFormat.Epub: - return _bookService.GetCoverImage(file.FilePath, createThumbnail); + return _bookService.GetCoverImage(file.FilePath, ImageService.GetChapterFormat(chapterId, volumeId)); case MangaFormat.Image: var coverImage = _imageService.GetCoverFile(file); - return _imageService.GetCoverImage(coverImage, createThumbnail); + return _imageService.GetCoverImage(coverImage, ImageService.GetChapterFormat(chapterId, volumeId)); case MangaFormat.Archive: - return _archiveService.GetCoverImage(file.FilePath, createThumbnail); + return _archiveService.GetCoverImage(file.FilePath, ImageService.GetChapterFormat(chapterId, volumeId)); default: - return Array.Empty(); + return string.Empty; } } @@ -81,14 +96,17 @@ namespace API.Services /// /// /// Force updating cover image even if underlying file has not been modified or chapter already has a cover image - public void UpdateMetadata(Chapter chapter, bool forceUpdate) + public bool UpdateMetadata(Chapter chapter, bool forceUpdate) { var firstFile = chapter.Files.OrderBy(x => x.Chapter).FirstOrDefault(); if (ShouldUpdateCoverImage(chapter.CoverImage, firstFile, forceUpdate, chapter.CoverImageLocked)) { - chapter.CoverImage = GetCoverImage(firstFile); + chapter.CoverImage = GetCoverImage(firstFile, chapter.VolumeId, chapter.Id); + return true; } + + return false; } /// @@ -96,17 +114,18 @@ namespace API.Services /// /// /// Force updating cover image even if underlying file has not been modified or chapter already has a cover image - public void UpdateMetadata(Volume volume, bool forceUpdate) + public bool UpdateMetadata(Volume volume, bool forceUpdate) { + // We need to check if Volume coverImage matches first chapters if forceUpdate is false if (volume == null || !ShouldUpdateCoverImage(volume.CoverImage, null, forceUpdate - , false)) return; + , false)) return false; volume.Chapters ??= new List(); var firstChapter = volume.Chapters.OrderBy(x => double.Parse(x.Number), _chapterSortComparerForInChapterSorting).FirstOrDefault(); - - if (firstChapter == null) return; + if (firstChapter == null) return false; volume.CoverImage = firstChapter.CoverImage; + return true; } /// @@ -114,14 +133,15 @@ namespace API.Services /// /// /// Force updating cover image even if underlying file has not been modified or chapter already has a cover image - public void UpdateMetadata(Series series, bool forceUpdate) + public bool UpdateMetadata(Series series, bool forceUpdate) { - if (series == null) return; + var madeUpdate = false; + if (series == null) return false; if (ShouldUpdateCoverImage(series.CoverImage, null, forceUpdate, series.CoverImageLocked)) { series.Volumes ??= new List(); var firstCover = series.Volumes.GetCoverImage(series.Format); - byte[] coverImage = null; + string coverImage = null; if (firstCover == null && series.Volumes.Any()) { // If firstCover is null and one volume, the whole series is Chapters under Vol 0. @@ -129,39 +149,46 @@ namespace API.Services { coverImage = series.Volumes[0].Chapters.OrderBy(c => double.Parse(c.Number), _chapterSortComparerForInChapterSorting) .FirstOrDefault(c => !c.IsSpecial)?.CoverImage; + madeUpdate = true; } if (!HasCoverImage(coverImage)) { coverImage = series.Volumes[0].Chapters.OrderBy(c => double.Parse(c.Number), _chapterSortComparerForInChapterSorting) .FirstOrDefault()?.CoverImage; + madeUpdate = true; } } series.CoverImage = firstCover?.CoverImage ?? coverImage; } - UpdateSeriesSummary(series, forceUpdate); + return UpdateSeriesSummary(series, forceUpdate) || madeUpdate ; } - private void UpdateSeriesSummary(Series series, bool forceUpdate) + private bool UpdateSeriesSummary(Series series, bool forceUpdate) { - if (!string.IsNullOrEmpty(series.Summary) && !forceUpdate) return; + if (!string.IsNullOrEmpty(series.Summary) && !forceUpdate) return false; var isBook = series.Library.Type == LibraryType.Book; var firstVolume = series.Volumes.FirstWithChapters(isBook); var firstChapter = firstVolume?.Chapters.GetFirstChapterWithFiles(); var firstFile = firstChapter?.Files.FirstOrDefault(); - if (firstFile == null || (!forceUpdate && !firstFile.HasFileBeenModified())) return; - if (Parser.Parser.IsPdf(firstFile.FilePath)) return; + if (firstFile == null || (!forceUpdate && !firstFile.HasFileBeenModified())) return false; + if (Parser.Parser.IsPdf(firstFile.FilePath)) return false; - var summary = Parser.Parser.IsEpub(firstFile.FilePath) ? _bookService.GetSummaryInfo(firstFile.FilePath) : _archiveService.GetSummaryInfo(firstFile.FilePath); - if (string.IsNullOrEmpty(series.Summary)) + if (series.Format is MangaFormat.Archive or MangaFormat.Epub) { - series.Summary = summary; + var summary = Parser.Parser.IsEpub(firstFile.FilePath) ? _bookService.GetSummaryInfo(firstFile.FilePath) : _archiveService.GetSummaryInfo(firstFile.FilePath); + if (!string.IsNullOrEmpty(series.Summary)) + { + series.Summary = summary; + firstFile.LastModified = DateTime.Now; + return true; + } } - - firstFile.LastModified = DateTime.Now; + firstFile.LastModified = DateTime.Now; // NOTE: Should I put this here as well since it might not have actually been parsed? + return false; } @@ -171,31 +198,33 @@ namespace API.Services /// This can be heavy on memory first run /// /// Force updating cover image even if underlying file has not been modified or chapter already has a cover image - public void RefreshMetadata(int libraryId, bool forceUpdate = false) + public async Task RefreshMetadata(int libraryId, bool forceUpdate = false) { var sw = Stopwatch.StartNew(); - var library = Task.Run(() => _unitOfWork.LibraryRepository.GetFullLibraryForIdAsync(libraryId)).GetAwaiter().GetResult(); + var library = await _unitOfWork.LibraryRepository.GetFullLibraryForIdAsync(libraryId); // PERF: See if we can break this up into multiple threads that process 20 series at a time then save so we can reduce amount of memory used _logger.LogInformation("Beginning metadata refresh of {LibraryName}", library.Name); foreach (var series in library.Series) { + var volumeUpdated = false; foreach (var volume in series.Volumes) { + var chapterUpdated = false; foreach (var chapter in volume.Chapters) { - UpdateMetadata(chapter, forceUpdate); + chapterUpdated = UpdateMetadata(chapter, forceUpdate); } - UpdateMetadata(volume, forceUpdate); + volumeUpdated = UpdateMetadata(volume, chapterUpdated || forceUpdate); } - UpdateMetadata(series, forceUpdate); + UpdateMetadata(series, volumeUpdated || forceUpdate); _unitOfWork.SeriesRepository.Update(series); } - if (_unitOfWork.HasChanges() && Task.Run(() => _unitOfWork.CommitAsync()).Result) + if (_unitOfWork.HasChanges() && await _unitOfWork.CommitAsync()) { _logger.LogInformation("Updated metadata for {LibraryName} in {ElapsedMilliseconds} milliseconds", library.Name, sw.ElapsedMilliseconds); } @@ -207,10 +236,10 @@ namespace API.Services /// /// /// - public void RefreshMetadataForSeries(int libraryId, int seriesId) + public async Task RefreshMetadataForSeries(int libraryId, int seriesId, bool forceUpdate = false) { var sw = Stopwatch.StartNew(); - var library = Task.Run(() => _unitOfWork.LibraryRepository.GetFullLibraryForIdAsync(libraryId)).GetAwaiter().GetResult(); + var library = await _unitOfWork.LibraryRepository.GetFullLibraryForIdAsync(libraryId); var series = library.Series.SingleOrDefault(s => s.Id == seriesId); if (series == null) @@ -219,23 +248,26 @@ namespace API.Services return; } _logger.LogInformation("Beginning metadata refresh of {SeriesName}", series.Name); + var volumeUpdated = false; foreach (var volume in series.Volumes) { + var chapterUpdated = false; foreach (var chapter in volume.Chapters) { - UpdateMetadata(chapter, true); + chapterUpdated = UpdateMetadata(chapter, forceUpdate); } - UpdateMetadata(volume, true); + volumeUpdated = UpdateMetadata(volume, chapterUpdated || forceUpdate); } - UpdateMetadata(series, true); + UpdateMetadata(series, volumeUpdated || forceUpdate); _unitOfWork.SeriesRepository.Update(series); - if (_unitOfWork.HasChanges() && Task.Run(() => _unitOfWork.CommitAsync()).Result) + if (_unitOfWork.HasChanges() && await _unitOfWork.CommitAsync()) { _logger.LogInformation("Updated metadata for {SeriesName} in {ElapsedMilliseconds} milliseconds", series.Name, sw.ElapsedMilliseconds); + await _messageHub.Clients.All.SendAsync(SignalREvents.ScanSeries, MessageFactory.RefreshMetadataEvent(libraryId, seriesId)); } } } diff --git a/API/Services/TaskScheduler.cs b/API/Services/TaskScheduler.cs index f12926c68..2d1b25a7d 100644 --- a/API/Services/TaskScheduler.cs +++ b/API/Services/TaskScheduler.cs @@ -121,7 +121,7 @@ namespace API.Services _logger.LogInformation("Enqueuing library scan for: {LibraryId}", libraryId); BackgroundJob.Enqueue(() => _scannerService.ScanLibrary(libraryId, forceUpdate)); // When we do a scan, force cache to re-unpack in case page numbers change - BackgroundJob.Enqueue(() => _cleanupService.Cleanup()); + BackgroundJob.Enqueue(() => _cleanupService.CleanupCacheDirectory()); } public void CleanupChapters(int[] chapterIds) @@ -141,10 +141,10 @@ namespace API.Services BackgroundJob.Enqueue(() => DirectoryService.ClearDirectory(tempDirectory)); } - public void RefreshSeriesMetadata(int libraryId, int seriesId) + public void RefreshSeriesMetadata(int libraryId, int seriesId, bool forceUpdate = false) { _logger.LogInformation("Enqueuing series metadata refresh for: {SeriesId}", seriesId); - BackgroundJob.Enqueue(() => _metadataService.RefreshMetadataForSeries(libraryId, seriesId)); + BackgroundJob.Enqueue(() => _metadataService.RefreshMetadataForSeries(libraryId, seriesId, forceUpdate)); } public void ScanSeries(int libraryId, int seriesId, bool forceUpdate = false) @@ -161,6 +161,7 @@ namespace API.Services /// /// Not an external call. Only public so that we can call this for a Task /// + // ReSharper disable once MemberCanBePrivate.Global public async Task CheckForUpdate() { var update = await _versionUpdaterService.CheckForUpdate(); diff --git a/API/Services/Tasks/BackupService.cs b/API/Services/Tasks/BackupService.cs index e04e5373f..35388985a 100644 --- a/API/Services/Tasks/BackupService.cs +++ b/API/Services/Tasks/BackupService.cs @@ -59,8 +59,11 @@ namespace API.Services.Tasks return files; } + /// + /// Will backup anything that needs to be backed up. This includes logs, setting files, bare minimum cover images (just locked and first cover). + /// [AutomaticRetry(Attempts = 3, LogEvents = false, OnAttemptsExceeded = AttemptsExceededAction.Fail)] - public void BackupDatabase() + public async Task BackupDatabase() { _logger.LogInformation("Beginning backup of Database at {BackupTime}", DateTime.Now); var backupDirectory = Task.Run(() => _unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.BackupDirectory)).Result.Value; @@ -87,6 +90,9 @@ namespace API.Services.Tasks _directoryService.CopyFilesToDirectory( _backupFiles.Select(file => Path.Join(Directory.GetCurrentDirectory(), file)).ToList(), tempDirectory); + + await CopyCoverImagesToBackupDirectory(tempDirectory); + try { ZipFile.CreateFromDirectory(tempDirectory, zipPath); @@ -100,6 +106,31 @@ namespace API.Services.Tasks _logger.LogInformation("Database backup completed"); } + private async Task CopyCoverImagesToBackupDirectory(string tempDirectory) + { + var outputTempDir = Path.Join(tempDirectory, "covers"); + DirectoryService.ExistOrCreate(outputTempDir); + + try + { + var seriesImages = await _unitOfWork.SeriesRepository.GetLockedCoverImagesAsync(); + _directoryService.CopyFilesToDirectory( + seriesImages.Select(s => Path.Join(DirectoryService.CoverImageDirectory, s)), outputTempDir); + + var collectionTags = await _unitOfWork.CollectionTagRepository.GetAllCoverImagesAsync(); + _directoryService.CopyFilesToDirectory( + collectionTags.Select(s => Path.Join(DirectoryService.CoverImageDirectory, s)), outputTempDir); + + var chapterImages = await _unitOfWork.ChapterRepository.GetCoverImagesForLockedChaptersAsync(); + _directoryService.CopyFilesToDirectory( + chapterImages.Select(s => Path.Join(DirectoryService.CoverImageDirectory, s)), outputTempDir); + } + catch (IOException e) + { + // Swallow exception. This can be a duplicate cover being copied as chapter and volumes can share same file. + } + } + /// /// Removes Database backups older than 30 days. If all backups are older than 30 days, the latest is kept. /// diff --git a/API/Services/Tasks/CleanupService.cs b/API/Services/Tasks/CleanupService.cs index ae04d46bd..c1edf2e6b 100644 --- a/API/Services/Tasks/CleanupService.cs +++ b/API/Services/Tasks/CleanupService.cs @@ -1,7 +1,11 @@ using System.IO; +using System.Linq; +using System.Threading.Tasks; +using API.Interfaces; using API.Interfaces.Services; using Hangfire; using Microsoft.Extensions.Logging; +using NetVips; namespace API.Services.Tasks { @@ -13,27 +17,79 @@ namespace API.Services.Tasks private readonly ICacheService _cacheService; private readonly ILogger _logger; private readonly IBackupService _backupService; + private readonly IUnitOfWork _unitOfWork; + private readonly IDirectoryService _directoryService; - public CleanupService(ICacheService cacheService, ILogger logger, IBackupService backupService) + public CleanupService(ICacheService cacheService, ILogger logger, + IBackupService backupService, IUnitOfWork unitOfWork, IDirectoryService directoryService) { _cacheService = cacheService; _logger = logger; _backupService = backupService; + _unitOfWork = unitOfWork; + _directoryService = directoryService; + } + + public void CleanupCacheDirectory() + { + _logger.LogInformation("Cleaning cache directory"); + _cacheService.Cleanup(); } /// - /// Cleans up Temp, cache, and old database backups + /// Cleans up Temp, cache, deleted cover images, and old database backups /// [AutomaticRetry(Attempts = 3, LogEvents = false, OnAttemptsExceeded = AttemptsExceededAction.Fail)] - public void Cleanup() + public async Task Cleanup() { + _logger.LogInformation("Starting Cleanup"); _logger.LogInformation("Cleaning temp directory"); var tempDirectory = Path.Join(Directory.GetCurrentDirectory(), "temp"); DirectoryService.ClearDirectory(tempDirectory); - _logger.LogInformation("Cleaning cache directory"); - _cacheService.Cleanup(); + CleanupCacheDirectory(); _logger.LogInformation("Cleaning old database backups"); _backupService.CleanupBackups(); + _logger.LogInformation("Cleaning deleted cover images"); + await DeleteSeriesCoverImages(); + await DeleteChapterCoverImages(); + await DeleteTagCoverImages(); + _logger.LogInformation("Cleanup finished"); + } + + private async Task DeleteSeriesCoverImages() + { + var images = await _unitOfWork.SeriesRepository.GetAllCoverImagesAsync(); + var files = _directoryService.GetFiles(DirectoryService.CoverImageDirectory, ImageService.SeriesCoverImageRegex); + foreach (var file in files) + { + if (images.Contains(Path.GetFileName(file))) continue; + File.Delete(file); + + } + } + + private async Task DeleteChapterCoverImages() + { + var images = await _unitOfWork.ChapterRepository.GetAllCoverImagesAsync(); + var files = _directoryService.GetFiles(DirectoryService.CoverImageDirectory, ImageService.ChapterCoverImageRegex); + foreach (var file in files) + { + if (images.Contains(Path.GetFileName(file))) continue; + File.Delete(file); + + } + } + + private async Task DeleteTagCoverImages() + { + var images = await _unitOfWork.CollectionTagRepository.GetAllCoverImagesAsync(); + var files = _directoryService.GetFiles(DirectoryService.CoverImageDirectory, ImageService.CollectionTagCoverImageRegex); + foreach (var file in files) + { + if (images.Contains(Path.GetFileName(file))) continue; + File.Delete(file); + + } } } } diff --git a/API/Services/Tasks/Scanner/ParseScannedFiles.cs b/API/Services/Tasks/Scanner/ParseScannedFiles.cs index 9be88dfde..afcfc1c13 100644 --- a/API/Services/Tasks/Scanner/ParseScannedFiles.cs +++ b/API/Services/Tasks/Scanner/ParseScannedFiles.cs @@ -39,18 +39,18 @@ namespace API.Services.Tasks.Scanner _scannedSeries = new ConcurrentDictionary>(); } + /// + /// Gets the list of parserInfos given a Series. If the series does not exist within, return empty list. + /// + /// + /// + /// public static IList GetInfosByName(Dictionary> parsedSeries, Series series) { var existingKey = parsedSeries.Keys.FirstOrDefault(ps => - ps.Format == series.Format && ps.NormalizedName == Parser.Parser.Normalize(series.OriginalName)); - existingKey ??= new ParsedSeries() - { - Format = series.Format, - Name = series.OriginalName, - NormalizedName = Parser.Parser.Normalize(series.OriginalName) - }; + ps.Format == series.Format && ps.NormalizedName.Equals(Parser.Parser.Normalize(series.OriginalName))); - return parsedSeries[existingKey]; + return existingKey != null ? parsedSeries[existingKey] : new List(); } /// diff --git a/API/Services/Tasks/ScannerService.cs b/API/Services/Tasks/ScannerService.cs index 9fd90844c..15bb715c7 100644 --- a/API/Services/Tasks/ScannerService.cs +++ b/API/Services/Tasks/ScannerService.cs @@ -14,7 +14,9 @@ using API.Interfaces; using API.Interfaces.Services; using API.Parser; using API.Services.Tasks.Scanner; +using API.SignalR; using Hangfire; +using Microsoft.AspNetCore.SignalR; using Microsoft.Extensions.Logging; namespace API.Services.Tasks @@ -27,10 +29,11 @@ namespace API.Services.Tasks private readonly IMetadataService _metadataService; private readonly IBookService _bookService; private readonly ICacheService _cacheService; + private readonly IHubContext _messageHub; private readonly NaturalSortComparer _naturalSort = new (); public ScannerService(IUnitOfWork unitOfWork, ILogger logger, IArchiveService archiveService, - IMetadataService metadataService, IBookService bookService, ICacheService cacheService) + IMetadataService metadataService, IBookService bookService, ICacheService cacheService, IHubContext messageHub) { _unitOfWork = unitOfWork; _logger = logger; @@ -38,6 +41,7 @@ namespace API.Services.Tasks _metadataService = metadataService; _bookService = bookService; _cacheService = cacheService; + _messageHub = messageHub; } [DisableConcurrentExecution(timeoutInSeconds: 360)] @@ -47,7 +51,7 @@ namespace API.Services.Tasks var files = await _unitOfWork.SeriesRepository.GetFilesForSeries(seriesId); var series = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(seriesId); var library = await _unitOfWork.LibraryRepository.GetFullLibraryForIdAsync(libraryId, seriesId); - var dirs = FindHighestDirectoriesFromFiles(library, files); + var dirs = DirectoryService.FindHighestDirectoriesFromFiles(library.Folders.Select(f => f.Path), files.Select(f => f.FilePath).ToList()); var chapterIds = await _unitOfWork.SeriesRepository.GetChapterIdsForSeriesAsync(new []{ seriesId }); _logger.LogInformation("Beginning file scan on {SeriesName}", series.Name); @@ -63,6 +67,37 @@ namespace API.Services.Tasks parsedSeries.Remove(key); } + if (parsedSeries.Count == 0) + { + // We need to do an additional check for an edge case: If the scan ran and the files do not match the existing Series name, then it is very likely, + // the files have crap naming and if we don't correct, the series will get deleted due to the parser not being able to fallback onto folder parsing as the root + // is the series folder. + var existingFolder = dirs.Keys.FirstOrDefault(key => key.Contains(series.OriginalName)); + if (dirs.Keys.Count == 1 && !string.IsNullOrEmpty(existingFolder)) + { + dirs = new Dictionary(); + var path = Path.GetPathRoot(existingFolder); + if (!string.IsNullOrEmpty(path)) + { + dirs[path] = string.Empty; + } + } + _logger.LogDebug("{SeriesName} has bad naming convention, forcing rescan at a higher directory.", series.OriginalName); + scanner = new ParseScannedFiles(_bookService, _logger); + parsedSeries = scanner.ScanLibrariesForSeries(library.Type, dirs.Keys, out var totalFiles2, out var scanElapsedTime2); + totalFiles += totalFiles2; + scanElapsedTime += scanElapsedTime2; + + // If a root level folder scan occurs, then multiple series gets passed in and thus we get a unique constraint issue + // Hence we clear out anything but what we selected for + firstSeries = library.Series.FirstOrDefault(); + keys = parsedSeries.Keys; + foreach (var key in keys.Where(key => !firstSeries.NameInParserInfo(parsedSeries[key].FirstOrDefault()) || firstSeries?.Format != key.Format)) + { + parsedSeries.Remove(key); + } + } + var sw = new Stopwatch(); UpdateLibrary(library, parsedSeries); @@ -73,9 +108,11 @@ namespace API.Services.Tasks "Processed {TotalFiles} files and {ParsedSeriesCount} series in {ElapsedScanTime} milliseconds for {SeriesName}", totalFiles, parsedSeries.Keys.Count, sw.ElapsedMilliseconds + scanElapsedTime, series.Name); - CleanupDbEntities(); - BackgroundJob.Enqueue(() => _metadataService.RefreshMetadataForSeries(libraryId, seriesId)); + await CleanupDbEntities(); + BackgroundJob.Enqueue(() => _metadataService.RefreshMetadataForSeries(libraryId, seriesId, forceUpdate)); BackgroundJob.Enqueue(() => _cacheService.CleanupChapters(chapterIds)); + // Tell UI that this series is done + await _messageHub.Clients.All.SendAsync(SignalREvents.ScanSeries, MessageFactory.ScanSeriesEvent(seriesId), cancellationToken: token); } else { @@ -83,56 +120,21 @@ namespace API.Services.Tasks "There was a critical error that resulted in a failed scan. Please check logs and rescan"); await _unitOfWork.RollbackAsync(); } - } - /// - /// Finds the highest directories from a set of MangaFiles - /// - /// - /// - /// - private static Dictionary FindHighestDirectoriesFromFiles(Library library, IList files) - { - var stopLookingForDirectories = false; - var dirs = new Dictionary(); - foreach (var folder in library.Folders) - { - if (stopLookingForDirectories) break; - foreach (var file in files) - { - if (!file.FilePath.Contains(folder.Path)) continue; - - var parts = DirectoryService.GetFoldersTillRoot(folder.Path, file.FilePath).ToList(); - if (parts.Count == 0) - { - // Break from all loops, we done, just scan folder.Path (library root) - dirs.Add(folder.Path, string.Empty); - stopLookingForDirectories = true; - break; - } - - var fullPath = Path.Join(folder.Path, parts.Last()); - if (!dirs.ContainsKey(fullPath)) - { - dirs.Add(fullPath, string.Empty); - } - } - } - - return dirs; } [DisableConcurrentExecution(timeoutInSeconds: 360)] [AutomaticRetry(Attempts = 0, OnAttemptsExceeded = AttemptsExceededAction.Delete)] - public void ScanLibraries() + public async Task ScanLibraries() { - var libraries = Task.Run(() => _unitOfWork.LibraryRepository.GetLibrariesAsync()).Result.ToList(); + _logger.LogInformation("Starting Scan of All Libraries"); + var libraries = await _unitOfWork.LibraryRepository.GetLibrariesAsync(); foreach (var lib in libraries) { - ScanLibrary(lib.Id, false); + await ScanLibrary(lib.Id, false); } - + _logger.LogInformation("Scan of All Libraries Finished"); } @@ -145,13 +147,12 @@ namespace API.Services.Tasks /// [DisableConcurrentExecution(360)] [AutomaticRetry(Attempts = 0, OnAttemptsExceeded = AttemptsExceededAction.Delete)] - public void ScanLibrary(int libraryId, bool forceUpdate) + public async Task ScanLibrary(int libraryId, bool forceUpdate) { Library library; try { - library = Task.Run(() => _unitOfWork.LibraryRepository.GetFullLibraryForIdAsync(libraryId)).GetAwaiter() - .GetResult(); + library = await _unitOfWork.LibraryRepository.GetFullLibraryForIdAsync(libraryId); } catch (Exception ex) { @@ -173,7 +174,7 @@ namespace API.Services.Tasks UpdateLibrary(library, series); _unitOfWork.LibraryRepository.Update(library); - if (Task.Run(() => _unitOfWork.CommitAsync()).Result) + if (await _unitOfWork.CommitAsync()) { _logger.LogInformation( "Processed {TotalFiles} files and {ParsedSeriesCount} series in {ElapsedScanTime} milliseconds for {LibraryName}", @@ -185,27 +186,29 @@ namespace API.Services.Tasks "There was a critical error that resulted in a failed scan. Please check logs and rescan"); } - CleanupUserProgress(); + await CleanupAbandonedChapters(); BackgroundJob.Enqueue(() => _metadataService.RefreshMetadata(libraryId, forceUpdate)); + await _messageHub.Clients.All.SendAsync(SignalREvents.ScanLibrary, MessageFactory.ScanLibraryEvent(libraryId, "complete")); } /// /// Remove any user progress rows that no longer exist since scan library ran and deleted series/volumes/chapters /// - private void CleanupUserProgress() + private async Task CleanupAbandonedChapters() { - var cleanedUp = Task.Run(() => _unitOfWork.AppUserProgressRepository.CleanupAbandonedChapters()).Result; + var cleanedUp = await _unitOfWork.AppUserProgressRepository.CleanupAbandonedChapters(); _logger.LogInformation("Removed {Count} abandoned progress rows", cleanedUp); } + /// /// Cleans up any abandoned rows due to removals from Scan loop /// - private void CleanupDbEntities() + private async Task CleanupDbEntities() { - CleanupUserProgress(); - var cleanedUp = Task.Run( () => _unitOfWork.CollectionTagRepository.RemoveTagsWithoutSeries()).Result; + await CleanupAbandonedChapters(); + var cleanedUp = await _unitOfWork.CollectionTagRepository.RemoveTagsWithoutSeries(); _logger.LogInformation("Removed {Count} abandoned collection tags", cleanedUp); } @@ -275,6 +278,9 @@ namespace API.Services.Tasks _logger.LogError(ex, "There was an exception updating volumes for {SeriesName}", series.Name); } }); + + // Last step, remove any series that have no pages + library.Series = library.Series.Where(s => s.Pages > 0).ToList(); } public IEnumerable FindSeriesNotOnDisk(ICollection existingSeries, Dictionary> parsedSeries) diff --git a/API/Services/Tasks/VersionUpdaterService.cs b/API/Services/Tasks/VersionUpdaterService.cs index 5b3607ffc..fbd3d4f10 100644 --- a/API/Services/Tasks/VersionUpdaterService.cs +++ b/API/Services/Tasks/VersionUpdaterService.cs @@ -23,6 +23,7 @@ namespace API.Services.Tasks /// Name of the Tag /// v0.4.3 /// + // ReSharper disable once InconsistentNaming public string Tag_Name { get; init; } /// /// Name of the Release @@ -35,6 +36,7 @@ namespace API.Services.Tasks /// /// Url of the release on Github /// + // ReSharper disable once InconsistentNaming public string Html_Url { get; init; } } @@ -53,8 +55,10 @@ namespace API.Services.Tasks private readonly IHubContext _messageHub; private readonly IPresenceTracker _tracker; private readonly Markdown _markdown = new MarkdownDeep.Markdown(); +#pragma warning disable S1075 private static readonly string GithubLatestReleasesUrl = "https://api.github.com/repos/Kareadita/Kavita/releases/latest"; private static readonly string GithubAllReleasesUrl = "https://api.github.com/repos/Kareadita/Kavita/releases"; +#pragma warning restore S1075 public VersionUpdaterService(ILogger logger, IHubContext messageHub, IPresenceTracker tracker) { @@ -90,12 +94,17 @@ namespace API.Services.Tasks private UpdateNotificationDto CreateDto(GithubReleaseMetadata update) { if (update == null || string.IsNullOrEmpty(update.Tag_Name)) return null; - var version = update.Tag_Name.Replace("v", string.Empty); - var updateVersion = new Version(version); + var updateVersion = new Version(update.Tag_Name.Replace("v", string.Empty)); + var currentVersion = BuildInfo.Version.ToString(); + + if (updateVersion.Revision == -1) + { + currentVersion = currentVersion.Substring(0, currentVersion.LastIndexOf(".", StringComparison.Ordinal)); + } return new UpdateNotificationDto() { - CurrentVersion = version, + CurrentVersion = currentVersion, UpdateVersion = updateVersion.ToString(), UpdateBody = _markdown.Transform(update.Body.Trim()), UpdateTitle = update.Name, @@ -131,11 +140,7 @@ namespace API.Services.Tasks connections.AddRange(await _tracker.GetConnectionsForUser(admin)); } - await _messageHub.Clients.Users(admins).SendAsync("UpdateAvailable", new SignalRMessage - { - Name = "UpdateAvailable", - Body = update - }); + await _messageHub.Clients.Users(admins).SendAsync(SignalREvents.UpdateVersion, MessageFactory.UpdateVersionEvent(update)); } diff --git a/API/SignalR/MessageFactory.cs b/API/SignalR/MessageFactory.cs new file mode 100644 index 000000000..ad6eed5c9 --- /dev/null +++ b/API/SignalR/MessageFactory.cs @@ -0,0 +1,56 @@ +using System.Threading; +using API.DTOs.Update; + +namespace API.SignalR +{ + public static class MessageFactory + { + public static SignalRMessage ScanSeriesEvent(int seriesId) + { + return new SignalRMessage() + { + Name = SignalREvents.ScanSeries, + Body = new + { + SeriesId = seriesId + } + }; + } + + public static SignalRMessage ScanLibraryEvent(int libraryId, string stage) + { + return new SignalRMessage() + { + Name = SignalREvents.ScanLibrary, + Body = new + { + LibraryId = libraryId, + Stage = stage + } + }; + } + + public static SignalRMessage RefreshMetadataEvent(int libraryId, int seriesId) + { + return new SignalRMessage() + { + Name = SignalREvents.RefreshMetadata, + Body = new + { + SeriesId = seriesId, + LibraryId = libraryId + } + }; + } + + public static SignalRMessage UpdateVersionEvent(UpdateNotificationDto update) + { + return new SignalRMessage + { + Name = SignalREvents.UpdateVersion, + Body = update + }; + } + + } +} diff --git a/API/SignalR/SignalREvents.cs b/API/SignalR/SignalREvents.cs new file mode 100644 index 000000000..fcd077146 --- /dev/null +++ b/API/SignalR/SignalREvents.cs @@ -0,0 +1,11 @@ +namespace API.SignalR +{ + public static class SignalREvents + { + public const string UpdateVersion = "UpdateVersion"; + public const string ScanSeries = "ScanSeries"; + public const string RefreshMetadata = "RefreshMetadata"; + public const string ScanLibrary = "ScanLibrary"; + + } +} diff --git a/API/Startup.cs b/API/Startup.cs index cfdae2d9d..ee26e2d2b 100644 --- a/API/Startup.cs +++ b/API/Startup.cs @@ -2,6 +2,8 @@ using System; using System.IO; using System.IO.Compression; using System.Linq; +using System.Net; +using System.Net.Sockets; using API.Extensions; using API.Middleware; using API.Services; @@ -9,6 +11,7 @@ using API.Services.HostedServices; using API.SignalR; using Hangfire; using Hangfire.MemoryStorage; +using Kavita.Common; using Kavita.Common.EnvironmentInfo; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; @@ -109,7 +112,7 @@ namespace API .AllowAnyHeader() .AllowAnyMethod() .AllowCredentials() // For SignalR token query param - .WithOrigins("http://localhost:4200") + .WithOrigins("http://localhost:4200", $"http://{GetLocalIpAddress()}:4200") .WithExposedHeaders("Content-Disposition", "Pagination")); } @@ -132,7 +135,7 @@ namespace API new Microsoft.Net.Http.Headers.CacheControlHeaderValue() { Public = false, - MaxAge = TimeSpan.FromSeconds(10) + MaxAge = TimeSpan.FromSeconds(10), }; context.Response.Headers[Microsoft.Net.Http.Headers.HeaderNames.Vary] = new[] { "Accept-Encoding" }; @@ -164,6 +167,14 @@ namespace API Console.WriteLine("You may now close the application window."); } + private static string GetLocalIpAddress() + { + using var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, 0); + socket.Connect("8.8.8.8", 65530); + if (socket.LocalEndPoint is IPEndPoint endPoint) return endPoint.Address.ToString(); + throw new KavitaException("No network adapters with an IPv4 address in the system!"); + } + } } diff --git a/Kavita.Common/Kavita.Common.csproj b/Kavita.Common/Kavita.Common.csproj index f5e97d5f7..83192fafd 100644 --- a/Kavita.Common/Kavita.Common.csproj +++ b/Kavita.Common/Kavita.Common.csproj @@ -4,7 +4,7 @@ net5.0 kavitareader.com Kavita - 0.4.5.1 + 0.4.6.1 en diff --git a/UI/Web/package-lock.json b/UI/Web/package-lock.json index 9f8f3aafa..2ae36e55d 100644 --- a/UI/Web/package-lock.json +++ b/UI/Web/package-lock.json @@ -245,6 +245,28 @@ "tslib": "^2.0.0" } }, + "@angular/cdk": { + "version": "12.2.3", + "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-12.2.3.tgz", + "integrity": "sha512-ahY3k5X3eoQlsCX/fYiwbe1z7nfmwY15EiLpcJ8YrnUoB+ZshPm8qFIZi6gwY4tsMmUN8OfsIGcUO701bdxFpg==", + "requires": { + "parse5": "^5.0.0", + "tslib": "^2.2.0" + }, + "dependencies": { + "parse5": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", + "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==", + "optional": true + }, + "tslib": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", + "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" + } + } + }, "@angular/cli": { "version": "11.2.11", "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-11.2.11.tgz", @@ -2580,6 +2602,11 @@ } } }, + "@polka/url": { + "version": "1.0.0-next.20", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.20.tgz", + "integrity": "sha512-88p7+M0QGxKpmnkfXjS4V26AnoC/eiqZutE8GLdaI5X12NY75bXSdTY9NkmYb2Xyk1O+MmkuO6Frmsj84V6I8Q==" + }, "@schematics/angular": { "version": "11.2.11", "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-11.2.11.tgz", @@ -5762,6 +5789,11 @@ "is-obj": "^2.0.0" } }, + "duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==" + }, "duplexify": { "version": "3.7.1", "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", @@ -6957,6 +6989,14 @@ "dev": true, "optional": true }, + "gzip-size": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", + "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==", + "requires": { + "duplexer": "^0.1.2" + } + }, "handle-thing": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", @@ -11166,6 +11206,11 @@ "is-wsl": "^2.1.1" } }, + "opener": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", + "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==" + }, "opn": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz", @@ -14017,6 +14062,23 @@ } } }, + "sirv": { + "version": "1.0.17", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-1.0.17.tgz", + "integrity": "sha512-qx9go5yraB7ekT7bCMqUHJ5jEaOC/GXBxUWv+jeWnb7WzHUFdcQPGWk7YmAwFBaQBrogpuSqd/azbC2lZRqqmw==", + "requires": { + "@polka/url": "^1.0.0-next.20", + "mime": "^2.3.1", + "totalist": "^1.0.0" + }, + "dependencies": { + "mime": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz", + "integrity": "sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==" + } + } + }, "sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", @@ -15066,6 +15128,11 @@ "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", "dev": true }, + "totalist": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-1.1.0.tgz", + "integrity": "sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g==" + }, "tough-cookie": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", @@ -16220,6 +16287,87 @@ } } }, + "webpack-bundle-analyzer": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.4.2.tgz", + "integrity": "sha512-PIagMYhlEzFfhMYOzs5gFT55DkUdkyrJi/SxJp8EF3YMWhS+T9vvs2EoTetpk5qb6VsCq02eXTlRDOydRhDFAQ==", + "requires": { + "acorn": "^8.0.4", + "acorn-walk": "^8.0.0", + "chalk": "^4.1.0", + "commander": "^6.2.0", + "gzip-size": "^6.0.0", + "lodash": "^4.17.20", + "opener": "^1.5.2", + "sirv": "^1.0.7", + "ws": "^7.3.1" + }, + "dependencies": { + "acorn": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.5.0.tgz", + "integrity": "sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==" + }, + "acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==" + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "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==", + "requires": { + "color-name": "~1.1.4" + } + }, + "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==" + }, + "commander": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", + "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + }, + "ws": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.5.tgz", + "integrity": "sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w==" + } + } + }, "webpack-dev-middleware": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.7.2.tgz", diff --git a/UI/Web/package.json b/UI/Web/package.json index 42caf67ec..515c35df8 100644 --- a/UI/Web/package.json +++ b/UI/Web/package.json @@ -6,7 +6,7 @@ "start": "ng serve", "build": "ng build", "prod": "ng build --prod", - "explore": "ng build --stats-json && webpack-bundle-analyzer ../kavita/API/wwwroot/stats.json", + "explore": "ng build --stats-json && webpack-bundle-analyzer dist/stats.json", "test": "jest", "test:watch": "jest --watch", "test:coverage": "jest --coverage", @@ -17,6 +17,7 @@ "dependencies": { "@angular-slider/ngx-slider": "^2.0.3", "@angular/animations": "~11.0.0", + "@angular/cdk": "^12.2.3", "@angular/common": "~11.0.0", "@angular/compiler": "~11.0.0", "@angular/core": "~11.0.0", @@ -45,6 +46,7 @@ "rxjs": "~6.6.0", "swiper": "^6.5.8", "tslib": "^2.0.0", + "webpack-bundle-analyzer": "^4.4.2", "zone.js": "~0.10.2" }, "devDependencies": { diff --git a/UI/Web/src/app/_guards/admin.guard.ts b/UI/Web/src/app/_guards/admin.guard.ts index e9483530e..b88c8d51c 100644 --- a/UI/Web/src/app/_guards/admin.guard.ts +++ b/UI/Web/src/app/_guards/admin.guard.ts @@ -19,7 +19,7 @@ export class AdminGuard implements CanActivate { if (this.accountService.hasAdminRole(user)) { return true; } - + this.toastr.error('You are not authorized to view this page.'); return false; }) diff --git a/UI/Web/src/app/_guards/auth.guard.ts b/UI/Web/src/app/_guards/auth.guard.ts index f477290fc..924f03bf2 100644 --- a/UI/Web/src/app/_guards/auth.guard.ts +++ b/UI/Web/src/app/_guards/auth.guard.ts @@ -19,7 +19,9 @@ export class AuthGuard implements CanActivate { if (user) { return true; } - this.toastr.error('You are not authorized to view this page.'); + if (this.toastr.toasts.filter(toast => toast.message === 'Unauthorized' || toast.message === 'You are not authorized to view this page.').length === 0) { + this.toastr.error('You are not authorized to view this page.'); + } localStorage.setItem(this.urlKey, window.location.pathname); this.router.navigateByUrl('/libraries'); return false; diff --git a/UI/Web/src/app/_models/events/scan-library-event.ts b/UI/Web/src/app/_models/events/scan-library-event.ts new file mode 100644 index 000000000..b0c663502 --- /dev/null +++ b/UI/Web/src/app/_models/events/scan-library-event.ts @@ -0,0 +1,4 @@ +export interface ScanLibraryEvent { + libraryId: number; + stage: 'complete'; +} \ No newline at end of file diff --git a/UI/Web/src/app/_models/events/scan-series-event.ts b/UI/Web/src/app/_models/events/scan-series-event.ts new file mode 100644 index 000000000..45f7a07bc --- /dev/null +++ b/UI/Web/src/app/_models/events/scan-series-event.ts @@ -0,0 +1,3 @@ +export interface ScanSeriesEvent { + seriesId: number; +} \ No newline at end of file diff --git a/UI/Web/src/app/_models/reading-list.ts b/UI/Web/src/app/_models/reading-list.ts new file mode 100644 index 000000000..ad1a325b8 --- /dev/null +++ b/UI/Web/src/app/_models/reading-list.ts @@ -0,0 +1,23 @@ +import { MangaFormat } from "./manga-format"; + +export interface ReadingListItem { + pagesRead: number; + pagesTotal: number; + seriesName: string; + seriesFormat: MangaFormat; + seriesId: number; + chapterId: number; + order: number; + chapterNumber: string; + volumeNumber: string; + libraryId: number; + id: number; +} + +export interface ReadingList { + id: number; + title: string; + summary: string; + promoted: boolean; + items: Array; +} \ No newline at end of file diff --git a/UI/Web/src/app/_models/series.ts b/UI/Web/src/app/_models/series.ts index 5d163cddf..be233122b 100644 --- a/UI/Web/src/app/_models/series.ts +++ b/UI/Web/src/app/_models/series.ts @@ -8,7 +8,6 @@ export interface Series { localizedName: string; sortName: string; summary: string; - coverImage: string; // This is not passed from backend any longer. TODO: Remove this field coverImageLocked: boolean; volumes: Volume[]; pages: number; // Total pages in series diff --git a/UI/Web/src/app/_services/action-factory.service.ts b/UI/Web/src/app/_services/action-factory.service.ts index 178e72400..450b577bc 100644 --- a/UI/Web/src/app/_services/action-factory.service.ts +++ b/UI/Web/src/app/_services/action-factory.service.ts @@ -3,6 +3,7 @@ import { Chapter } from '../_models/chapter'; import { CollectionTag } from '../_models/collection-tag'; import { Library } from '../_models/library'; import { MangaFormat } from '../_models/manga-format'; +import { ReadingList } from '../_models/reading-list'; import { Series } from '../_models/series'; import { Volume } from '../_models/volume'; import { AccountService } from './account.service'; @@ -16,7 +17,9 @@ export enum Action { Info = 5, RefreshMetadata = 6, Download = 7, - Bookmarks = 8 + Bookmarks = 8, + IncognitoRead = 9, + AddToReadingList = 10 } export interface ActionItem { @@ -41,6 +44,8 @@ export class ActionFactoryService { collectionTagActions: Array> = []; + readingListActions: Array> = []; + isAdmin = false; hasDownloadRole = false; @@ -108,7 +113,7 @@ export class ActionFactoryService { this.chapterActions.push({ action: Action.Edit, - title: 'Edit', + title: 'Info', callback: this.dummyCallback, requiresAdmin: false }); @@ -133,28 +138,39 @@ export class ActionFactoryService { } getLibraryActions(callback: (action: Action, library: Library) => void) { - this.libraryActions.forEach(action => action.callback = callback); - return this.libraryActions; + const actions = this.libraryActions.map(a => {return {...a}}); + actions.forEach(action => action.callback = callback); + return actions; } getSeriesActions(callback: (action: Action, series: Series) => void) { - this.seriesActions.forEach(action => action.callback = callback); - return this.seriesActions; + const actions = this.seriesActions.map(a => {return {...a}}); + actions.forEach(action => action.callback = callback); + return actions; } getVolumeActions(callback: (action: Action, volume: Volume) => void) { - this.volumeActions.forEach(action => action.callback = callback); - return this.volumeActions; + const actions = this.volumeActions.map(a => {return {...a}}); + actions.forEach(action => action.callback = callback); + return actions; } getChapterActions(callback: (action: Action, chapter: Chapter) => void) { - this.chapterActions.forEach(action => action.callback = callback); - return this.chapterActions; + const actions = this.chapterActions.map(a => {return {...a}}); + actions.forEach(action => action.callback = callback); + return actions; } getCollectionTagActions(callback: (action: Action, collectionTag: CollectionTag) => void) { - this.collectionTagActions.forEach(action => action.callback = callback); - return this.collectionTagActions; + const actions = this.collectionTagActions.map(a => {return {...a}}); + actions.forEach(action => action.callback = callback); + return actions; + } + + getReadingListActions(callback: (action: Action, readingList: ReadingList) => void) { + const actions = this.readingListActions.map(a => {return {...a}}); + actions.forEach(action => action.callback = callback); + return actions; } filterBookmarksForFormat(action: ActionItem, series: Series) { @@ -187,7 +203,13 @@ export class ActionFactoryService { title: 'Bookmarks', callback: this.dummyCallback, requiresAdmin: false - } + }, + { + action: Action.AddToReadingList, + title: 'Add to Reading List', + callback: this.dummyCallback, + requiresAdmin: false + }, ]; this.volumeActions = [ @@ -203,6 +225,18 @@ export class ActionFactoryService { callback: this.dummyCallback, requiresAdmin: false }, + { + action: Action.AddToReadingList, + title: 'Add to Reading List', + callback: this.dummyCallback, + requiresAdmin: false + }, + { + action: Action.IncognitoRead, + title: 'Read in Incognito', + callback: this.dummyCallback, + requiresAdmin: false + }, { action: Action.Edit, title: 'Info', @@ -223,7 +257,34 @@ export class ActionFactoryService { title: 'Mark as Unread', callback: this.dummyCallback, requiresAdmin: false - } + }, + { + action: Action.IncognitoRead, + title: 'Read in Incognito', + callback: this.dummyCallback, + requiresAdmin: false + }, + { + action: Action.AddToReadingList, + title: 'Add to Reading List', + callback: this.dummyCallback, + requiresAdmin: false + }, + ]; + + this.readingListActions = [ + { + action: Action.Edit, + title: 'Edit', + callback: this.dummyCallback, + requiresAdmin: false + }, + { + action: Action.Delete, + title: 'Delete', + callback: this.dummyCallback, + requiresAdmin: false + }, ]; } } diff --git a/UI/Web/src/app/_services/action.service.ts b/UI/Web/src/app/_services/action.service.ts index 3e400a80b..0cdfb3cfe 100644 --- a/UI/Web/src/app/_services/action.service.ts +++ b/UI/Web/src/app/_services/action.service.ts @@ -1,11 +1,14 @@ import { Injectable, OnDestroy } from '@angular/core'; import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; import { ToastrService } from 'ngx-toastr'; -import { forkJoin, Subject } from 'rxjs'; -import { take, takeUntil } from 'rxjs/operators'; +import { Subject } from 'rxjs'; +import { take } from 'rxjs/operators'; import { BookmarksModalComponent } from '../cards/_modals/bookmarks-modal/bookmarks-modal.component'; +import { AddToListModalComponent, ADD_FLOW } from '../reading-list/_modals/add-to-list-modal/add-to-list-modal.component'; +import { EditReadingListModalComponent } from '../reading-list/_modals/edit-reading-list-modal/edit-reading-list-modal.component'; import { Chapter } from '../_models/chapter'; import { Library } from '../_models/library'; +import { ReadingList } from '../_models/reading-list'; import { Series } from '../_models/series'; import { Volume } from '../_models/volume'; import { LibraryService } from './library.service'; @@ -16,6 +19,8 @@ export type LibraryActionCallback = (library: Partial) => void; export type SeriesActionCallback = (series: Series) => void; export type VolumeActionCallback = (volume: Volume) => void; export type ChapterActionCallback = (chapter: Chapter) => void; +export type ReadingListActionCallback = (readingList: ReadingList) => void; +export type VoidActionCallback = () => void; /** * Responsible for executing actions @@ -27,6 +32,7 @@ export class ActionService implements OnDestroy { private readonly onDestroy = new Subject(); private bookmarkModalRef: NgbModalRef | null = null; + private readingListModalRef: NgbModalRef | null = null; constructor(private libraryService: LibraryService, private seriesService: SeriesService, private readerService: ReaderService, private toastr: ToastrService, private modalService: NgbModal) { } @@ -156,7 +162,7 @@ export class ActionService implements OnDestroy { * @param callback Optional callback to perform actions after API completes */ markVolumeAsUnread(seriesId: number, volume: Volume, callback?: VolumeActionCallback) { - this.readerService.markVolumeRead(seriesId, volume.id).subscribe(() => { + this.readerService.markVolumeUnread(seriesId, volume.id).subscribe(() => { volume.pagesRead = 0; volume.chapters?.forEach(c => c.pagesRead = 0); this.toastr.success('Marked as Unread'); @@ -198,6 +204,85 @@ export class ActionService implements OnDestroy { }); } + /** + * Mark all chapters and the volumes as Read. All volumes and chapters must belong to a series + * @param seriesId Series Id + * @param volumes Volumes, should have id, chapters and pagesRead populated + * @param chapters? Chapters, should have id + * @param callback Optional callback to perform actions after API completes + */ + markMultipleAsRead(seriesId: number, volumes: Array, chapters?: Array, callback?: VoidActionCallback) { + this.readerService.markMultipleRead(seriesId, volumes.map(v => v.id), chapters?.map(c => c.id)).pipe(take(1)).subscribe(() => { + volumes.forEach(volume => { + volume.pagesRead = volume.pages; + volume.chapters?.forEach(c => c.pagesRead = c.pages); + }); + chapters?.forEach(c => c.pagesRead = c.pages); + this.toastr.success('Marked as Read'); + + if (callback) { + callback(); + } + }); + } + + /** + * Mark all chapters and the volumes as Unread. All volumes must belong to a series + * @param seriesId Series Id + * @param volumes Volumes, should have id, chapters and pagesRead populated + * @param callback Optional callback to perform actions after API completes + */ + markMultipleAsUnread(seriesId: number, volumes: Array, chapters?: Array, callback?: VoidActionCallback) { + this.readerService.markMultipleUnread(seriesId, volumes.map(v => v.id), chapters?.map(c => c.id)).pipe(take(1)).subscribe(() => { + volumes.forEach(volume => { + volume.pagesRead = volume.pages; + volume.chapters?.forEach(c => c.pagesRead = c.pages); + }); + chapters?.forEach(c => c.pagesRead = c.pages); + this.toastr.success('Marked as Read'); + + if (callback) { + callback(); + } + }); + } + + /** + * Mark all series as Read. + * @param series Series, should have id, pagesRead populated + * @param callback Optional callback to perform actions after API completes + */ + markMultipleSeriesAsRead(series: Array, callback?: VoidActionCallback) { + this.readerService.markMultipleSeriesRead(series.map(v => v.id)).pipe(take(1)).subscribe(() => { + series.forEach(s => { + s.pagesRead = s.pages; + }); + this.toastr.success('Marked as Read'); + + if (callback) { + callback(); + } + }); + } + + /** + * Mark all series as Unread. + * @param series Series, should have id, pagesRead populated + * @param callback Optional callback to perform actions after API completes + */ + markMultipleSeriesAsUnread(series: Array, callback?: VoidActionCallback) { + this.readerService.markMultipleSeriesUnread(series.map(v => v.id)).pipe(take(1)).subscribe(() => { + series.forEach(s => { + s.pagesRead = s.pages; + }); + this.toastr.success('Marked as Unread'); + + if (callback) { + callback(); + } + }); + } + openBookmarkModal(series: Series, callback?: SeriesActionCallback) { if (this.bookmarkModalRef != null) { return; } @@ -217,4 +302,131 @@ export class ActionService implements OnDestroy { }); } + addMultipleToReadingList(seriesId: number, volumes: Array, chapters?: Array, callback?: VoidActionCallback) { + if (this.readingListModalRef != null) { return; } + this.readingListModalRef = this.modalService.open(AddToListModalComponent, { scrollable: true, size: 'md' }); + this.readingListModalRef.componentInstance.seriesId = seriesId; + this.readingListModalRef.componentInstance.volumeIds = volumes.map(v => v.id); + this.readingListModalRef.componentInstance.chapterIds = chapters?.map(c => c.id); + this.readingListModalRef.componentInstance.title = 'Multiple Selections'; + this.readingListModalRef.componentInstance.type = ADD_FLOW.Multiple; + + + this.readingListModalRef.closed.pipe(take(1)).subscribe(() => { + this.readingListModalRef = null; + if (callback) { + callback(); + } + }); + this.readingListModalRef.dismissed.pipe(take(1)).subscribe(() => { + this.readingListModalRef = null; + if (callback) { + callback(); + } + }); + } + + addMultipleSeriesToReadingList(series: Array, callback?: VoidActionCallback) { + if (this.readingListModalRef != null) { return; } + this.readingListModalRef = this.modalService.open(AddToListModalComponent, { scrollable: true, size: 'md' }); + this.readingListModalRef.componentInstance.seriesIds = series.map(v => v.id); + this.readingListModalRef.componentInstance.title = 'Multiple Selections'; + this.readingListModalRef.componentInstance.type = ADD_FLOW.Multiple_Series; + + + this.readingListModalRef.closed.pipe(take(1)).subscribe(() => { + this.readingListModalRef = null; + if (callback) { + callback(); + } + }); + this.readingListModalRef.dismissed.pipe(take(1)).subscribe(() => { + this.readingListModalRef = null; + if (callback) { + callback(); + } + }); + } + + addSeriesToReadingList(series: Series, callback?: SeriesActionCallback) { + if (this.readingListModalRef != null) { return; } + this.readingListModalRef = this.modalService.open(AddToListModalComponent, { scrollable: true, size: 'md' }); + this.readingListModalRef.componentInstance.seriesId = series.id; + this.readingListModalRef.componentInstance.title = series.name; + this.readingListModalRef.componentInstance.type = ADD_FLOW.Series; + + + this.readingListModalRef.closed.pipe(take(1)).subscribe(() => { + this.readingListModalRef = null; + if (callback) { + callback(series); + } + }); + this.readingListModalRef.dismissed.pipe(take(1)).subscribe(() => { + this.readingListModalRef = null; + if (callback) { + callback(series); + } + }); + } + + addVolumeToReadingList(volume: Volume, seriesId: number, callback?: VolumeActionCallback) { + if (this.readingListModalRef != null) { return; } + this.readingListModalRef = this.modalService.open(AddToListModalComponent, { scrollable: true, size: 'md' }); + this.readingListModalRef.componentInstance.seriesId = seriesId; + this.readingListModalRef.componentInstance.volumeId = volume.id; + this.readingListModalRef.componentInstance.type = ADD_FLOW.Volume; + + + this.readingListModalRef.closed.pipe(take(1)).subscribe(() => { + this.readingListModalRef = null; + if (callback) { + callback(volume); + } + }); + this.readingListModalRef.dismissed.pipe(take(1)).subscribe(() => { + this.readingListModalRef = null; + if (callback) { + callback(volume); + } + }); + } + + addChapterToReadingList(chapter: Chapter, seriesId: number, callback?: ChapterActionCallback) { + if (this.readingListModalRef != null) { return; } + this.readingListModalRef = this.modalService.open(AddToListModalComponent, { scrollable: true, size: 'md' }); + this.readingListModalRef.componentInstance.seriesId = seriesId; + this.readingListModalRef.componentInstance.chapterId = chapter.id; + this.readingListModalRef.componentInstance.type = ADD_FLOW.Chapter; + + + this.readingListModalRef.closed.pipe(take(1)).subscribe(() => { + this.readingListModalRef = null; + if (callback) { + callback(chapter); + } + }); + this.readingListModalRef.dismissed.pipe(take(1)).subscribe(() => { + this.readingListModalRef = null; + if (callback) { + callback(chapter); + } + }); + } + + editReadingList(readingList: ReadingList, callback?: ReadingListActionCallback) { + const readingListModalRef = this.modalService.open(EditReadingListModalComponent, { scrollable: true, size: 'md' }); + readingListModalRef.componentInstance.readingList = readingList; + readingListModalRef.closed.pipe(take(1)).subscribe((list) => { + if (callback && list !== undefined) { + callback(readingList); + } + }); + readingListModalRef.dismissed.pipe(take(1)).subscribe((list) => { + if (callback && list !== undefined) { + callback(readingList); + } + }); + } + } diff --git a/UI/Web/src/app/_services/library.service.ts b/UI/Web/src/app/_services/library.service.ts index e6991e592..2c0b06f1f 100644 --- a/UI/Web/src/app/_services/library.service.ts +++ b/UI/Web/src/app/_services/library.service.ts @@ -37,7 +37,7 @@ export class LibraryService { listDirectories(rootPath: string) { let query = ''; if (rootPath !== undefined && rootPath.length > 0) { - query = '?path=' + rootPath; + query = '?path=' + encodeURIComponent(rootPath); } return this.httpClient.get(this.baseUrl + 'library/list' + query); diff --git a/UI/Web/src/app/_services/message-hub.service.ts b/UI/Web/src/app/_services/message-hub.service.ts index 33c39f18b..f5d193f6a 100644 --- a/UI/Web/src/app/_services/message-hub.service.ts +++ b/UI/Web/src/app/_services/message-hub.service.ts @@ -1,13 +1,18 @@ -import { Injectable } from '@angular/core'; +import { EventEmitter, Injectable } from '@angular/core'; import { HubConnection, HubConnectionBuilder } from '@microsoft/signalr'; import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; import { User } from '@sentry/angular'; import { BehaviorSubject, ReplaySubject } from 'rxjs'; import { environment } from 'src/environments/environment'; import { UpdateNotificationModalComponent } from '../shared/update-notification/update-notification-modal.component'; +import { ScanLibraryEvent } from '../_models/events/scan-library-event'; +import { ScanSeriesEvent } from '../_models/events/scan-series-event'; export enum EVENTS { - UpdateAvailable = 'UpdateAvailable' + UpdateAvailable = 'UpdateAvailable', + ScanSeries = 'ScanSeries', + ScanLibrary = 'ScanLibrary', + RefreshMetadata = 'RefreshMetadata', } export interface Message { @@ -26,6 +31,9 @@ export class MessageHubService { private messagesSource = new ReplaySubject>(1); public messages$ = this.messagesSource.asObservable(); + public scanSeries: EventEmitter = new EventEmitter(); + public scanLibrary: EventEmitter = new EventEmitter(); + constructor(private modalService: NgbModal) { } createHubConnection(user: User) { @@ -44,6 +52,25 @@ export class MessageHubService { //console.log('[Hub] Body: ', body); }); + this.hubConnection.on(EVENTS.ScanSeries, resp => { + this.messagesSource.next({ + event: EVENTS.ScanSeries, + payload: resp.body + }); + this.scanSeries.emit(resp.body); + }); + + this.hubConnection.on(EVENTS.ScanLibrary, resp => { + this.messagesSource.next({ + event: EVENTS.ScanLibrary, + payload: resp.body + }); + this.scanLibrary.emit(resp.body); + // if ((resp.body as ScanLibraryEvent).stage === 'complete') { + // this.toastr. + // } + }); + this.hubConnection.on(EVENTS.UpdateAvailable, resp => { this.messagesSource.next({ event: EVENTS.UpdateAvailable, diff --git a/UI/Web/src/app/_services/reader.service.ts b/UI/Web/src/app/_services/reader.service.ts index 042eab4a0..8281ab9e9 100644 --- a/UI/Web/src/app/_services/reader.service.ts +++ b/UI/Web/src/app/_services/reader.service.ts @@ -56,8 +56,8 @@ export class ReaderService { return this.baseUrl + 'reader/image?chapterId=' + chapterId + '&page=' + page; } - getChapterInfo(seriesId: number, chapterId: number) { - return this.httpClient.get(this.baseUrl + 'reader/chapter-info?chapterId=' + chapterId + '&seriesId=' + seriesId); + getChapterInfo(chapterId: number) { + return this.httpClient.get(this.baseUrl + 'reader/chapter-info?chapterId=' + chapterId); } saveProgress(seriesId: number, volumeId: number, chapterId: number, page: number, bookScrollId: string | null = null) { @@ -68,17 +68,44 @@ export class ReaderService { return this.httpClient.post(this.baseUrl + 'reader/mark-volume-read', {seriesId, volumeId}); } - getNextChapter(seriesId: number, volumeId: number, currentChapterId: number) { + markMultipleRead(seriesId: number, volumeIds: Array, chapterIds?: Array) { + return this.httpClient.post(this.baseUrl + 'reader/mark-multiple-read', {seriesId, volumeIds, chapterIds}); + } + + markMultipleUnread(seriesId: number, volumeIds: Array, chapterIds?: Array) { + return this.httpClient.post(this.baseUrl + 'reader/mark-multiple-unread', {seriesId, volumeIds, chapterIds}); + } + + markMultipleSeriesRead(seriesIds: Array) { + return this.httpClient.post(this.baseUrl + 'reader/mark-multiple-series-read', {seriesIds}); + } + + markMultipleSeriesUnread(seriesIds: Array) { + return this.httpClient.post(this.baseUrl + 'reader/mark-multiple-series-unread', {seriesIds}); + } + + markVolumeUnread(seriesId: number, volumeId: number) { + return this.httpClient.post(this.baseUrl + 'reader/mark-volume-unread', {seriesId, volumeId}); + } + + + getNextChapter(seriesId: number, volumeId: number, currentChapterId: number, readingListId: number = -1) { + if (readingListId > 0) { + return this.httpClient.get(this.baseUrl + 'readinglist/next-chapter?seriesId=' + seriesId + '¤tChapterId=' + currentChapterId + '&readingListId=' + readingListId); + } return this.httpClient.get(this.baseUrl + 'reader/next-chapter?seriesId=' + seriesId + '&volumeId=' + volumeId + '¤tChapterId=' + currentChapterId); } - getPrevChapter(seriesId: number, volumeId: number, currentChapterId: number) { + getPrevChapter(seriesId: number, volumeId: number, currentChapterId: number, readingListId: number = -1) { + if (readingListId > 0) { + return this.httpClient.get(this.baseUrl + 'readinglist/prev-chapter?seriesId=' + seriesId + '¤tChapterId=' + currentChapterId + '&readingListId=' + readingListId); + } return this.httpClient.get(this.baseUrl + 'reader/prev-chapter?seriesId=' + seriesId + '&volumeId=' + volumeId + '¤tChapterId=' + currentChapterId); } getCurrentChapter(volumes: Array): Chapter { let currentlyReadingChapter: Chapter | undefined = undefined; - const chapters = volumes.filter(v => v.number !== 0).map(v => v.chapters || []).flat().sort(this.utilityService.sortChapters); // changed from === 0 to != 0 + const chapters = volumes.filter(v => v.number !== 0).map(v => v.chapters || []).flat().sort(this.utilityService.sortChapters); for (const c of chapters) { if (c.pagesRead < c.pages) { @@ -132,4 +159,38 @@ export class ReaderService { if (imageSrc === undefined || imageSrc === '') { return -1; } return parseInt(imageSrc.split('&page=')[1], 10); } + + getNextChapterUrl(url: string, nextChapterId: number, incognitoMode: boolean = false, readingListMode: boolean = false, readingListId: number = -1) { + const lastSlashIndex = url.lastIndexOf('/'); + let newRoute = url.substring(0, lastSlashIndex + 1) + nextChapterId + ''; + newRoute += this.getQueryParams(incognitoMode, readingListMode, readingListId); + return newRoute; + } + + + getQueryParamsObject(incognitoMode: boolean = false, readingListMode: boolean = false, readingListId: number = -1) { + let params: {[key: string]: any} = {}; + if (incognitoMode) { + params['incognitoMode'] = true; + } + if (readingListMode) { + params['readingListId'] = readingListId; + } + return params; + } + + getQueryParams(incognitoMode: boolean = false, readingListMode: boolean = false, readingListId: number = -1) { + let params = ''; + if (incognitoMode) { + params += '?incognitoMode=true'; + } + if (readingListMode) { + if (params.indexOf('?') > 0) { + params += '&readingListId=' + readingListId; + } else { + params += '?readingListId=' + readingListId; + } + } + return params; + } } diff --git a/UI/Web/src/app/_services/reading-list.service.ts b/UI/Web/src/app/_services/reading-list.service.ts new file mode 100644 index 000000000..e520154d6 --- /dev/null +++ b/UI/Web/src/app/_services/reading-list.service.ts @@ -0,0 +1,110 @@ +import { HttpClient, HttpParams } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { map } from 'rxjs/operators'; +import { environment } from 'src/environments/environment'; +import { PaginatedResult } from '../_models/pagination'; +import { ReadingList, ReadingListItem } from '../_models/reading-list'; +import { ActionItem } from './action-factory.service'; + +@Injectable({ + providedIn: 'root' +}) +export class ReadingListService { + + baseUrl = environment.apiUrl; + + constructor(private httpClient: HttpClient) { } + + getReadingList(readingListId: number) { + return this.httpClient.get(this.baseUrl + 'readinglist?readingListId=' + readingListId); + } + + getReadingLists(includePromoted: boolean = true, pageNum?: number, itemsPerPage?: number) { + let params = new HttpParams(); + params = this._addPaginationIfExists(params, pageNum, itemsPerPage); + + return this.httpClient.post>(this.baseUrl + 'readinglist/lists?includePromoted=' + includePromoted, {}, {observe: 'response', params}).pipe( + map((response: any) => { + return this._cachePaginatedResults(response, new PaginatedResult()); + }) + ); + } + + getListItems(readingListId: number) { + return this.httpClient.get(this.baseUrl + 'readinglist/items?readingListId=' + readingListId); + } + + createList(title: string) { + return this.httpClient.post(this.baseUrl + 'readinglist/create', {title}); + } + + update(model: {readingListId: number, title?: string, summary?: string, promoted: boolean}) { + return this.httpClient.post(this.baseUrl + 'readinglist/update', model, { responseType: 'text' as 'json' }); + } + + updateByMultiple(readingListId: number, seriesId: number, volumeIds: Array, chapterIds?: Array) { + return this.httpClient.post(this.baseUrl + 'readinglist/update-by-multiple', {readingListId, seriesId, volumeIds, chapterIds}); + } + + updateByMultipleSeries(readingListId: number, seriesIds: Array) { + return this.httpClient.post(this.baseUrl + 'readinglist/update-by-multiple-series', {readingListId, seriesIds}); + } + + updateBySeries(readingListId: number, seriesId: number) { + return this.httpClient.post(this.baseUrl + 'readinglist/update-by-series', {readingListId, seriesId}, { responseType: 'text' as 'json' }); + } + + updateByVolume(readingListId: number, seriesId: number, volumeId: number) { + return this.httpClient.post(this.baseUrl + 'readinglist/update-by-volume', {readingListId, seriesId, volumeId}, { responseType: 'text' as 'json' }); + } + + updateByChapter(readingListId: number, seriesId: number, chapterId: number) { + return this.httpClient.post(this.baseUrl + 'readinglist/update-by-chapter', {readingListId, seriesId, chapterId}, { responseType: 'text' as 'json' }); + } + + delete(readingListId: number) { + return this.httpClient.delete(this.baseUrl + 'readinglist?readingListId=' + readingListId, { responseType: 'text' as 'json' }); + } + + updatePosition(readingListId: number, readingListItemId: number, fromPosition: number, toPosition: number) { + return this.httpClient.post(this.baseUrl + 'readinglist/update-position', {readingListId, readingListItemId, fromPosition, toPosition}, { responseType: 'text' as 'json' }); + } + + deleteItem(readingListId: number, readingListItemId: number) { + return this.httpClient.post(this.baseUrl + 'readinglist/delete-item', {readingListId, readingListItemId}, { responseType: 'text' as 'json' }); + } + + removeRead(readingListId: number) { + return this.httpClient.post(this.baseUrl + 'readinglist/remove-read?readingListId=' + readingListId, { responseType: 'text' as 'json' }); + } + + actionListFilter(action: ActionItem, readingList: ReadingList, isAdmin: boolean) { + if (readingList?.promoted && !isAdmin) return false; + return true; + } + + _addPaginationIfExists(params: HttpParams, pageNum?: number, itemsPerPage?: number) { + // TODO: Move to utility service + if (pageNum !== null && pageNum !== undefined && itemsPerPage !== null && itemsPerPage !== undefined) { + params = params.append('pageNumber', pageNum + ''); + params = params.append('pageSize', itemsPerPage + ''); + } + return params; + } + + _cachePaginatedResults(response: any, paginatedVariable: PaginatedResult) { + // TODO: Move to utility service + if (response.body === null) { + paginatedVariable.result = []; + } else { + paginatedVariable.result = response.body; + } + + const pageHeader = response.headers.get('Pagination'); + if (pageHeader !== null) { + paginatedVariable.pagination = JSON.parse(pageHeader); + } + + return paginatedVariable; + } +} diff --git a/UI/Web/src/app/admin/_modals/directory-picker/directory-picker.component.html b/UI/Web/src/app/admin/_modals/directory-picker/directory-picker.component.html index 78440a06b..6f6d02630 100644 --- a/UI/Web/src/app/admin/_modals/directory-picker/directory-picker.component.html +++ b/UI/Web/src/app/admin/_modals/directory-picker/directory-picker.component.html @@ -9,7 +9,7 @@
- +
@@ -27,7 +27,7 @@ - +
    @@ -50,5 +50,6 @@
diff --git a/UI/Web/src/app/admin/_modals/library-access-modal/library-access-modal.component.html b/UI/Web/src/app/admin/_modals/library-access-modal/library-access-modal.component.html index 458880b5e..de4001387 100644 --- a/UI/Web/src/app/admin/_modals/library-access-modal/library-access-modal.component.html +++ b/UI/Web/src/app/admin/_modals/library-access-modal/library-access-modal.component.html @@ -14,6 +14,9 @@
+
  • + There are no libraries setup yet. +
  • /// [HttpPost("backup-db")] - public ActionResult BackupDatabase() + public async Task BackupDatabase() { _logger.LogInformation("{UserName} is backing up database of server from admin dashboard", User.GetUsername()); - _backupService.BackupDatabase(); + await _backupService.BackupDatabase(); return Ok(); } diff --git a/API/Controllers/SettingsController.cs b/API/Controllers/SettingsController.cs index ef3fe8997..c8b3248ba 100644 --- a/API/Controllers/SettingsController.cs +++ b/API/Controllers/SettingsController.cs @@ -140,7 +140,7 @@ namespace API.Controllers } } - if (!_unitOfWork.HasChanges()) return Ok("Nothing was updated"); + if (!_unitOfWork.HasChanges()) return Ok(updateSettingsDto); try { diff --git a/API/Controllers/StatsController.cs b/API/Controllers/StatsController.cs index 09fcf9738..0ce9bebed 100644 --- a/API/Controllers/StatsController.cs +++ b/API/Controllers/StatsController.cs @@ -25,7 +25,7 @@ namespace API.Controllers { try { - await _statsService.PathData(clientInfoDto); + await _statsService.RecordClientInfo(clientInfoDto); return Ok(); } diff --git a/API/DTOs/CollectionTags/CollectionTagBulkAddDto.cs b/API/DTOs/CollectionTags/CollectionTagBulkAddDto.cs new file mode 100644 index 000000000..ac28e81cb --- /dev/null +++ b/API/DTOs/CollectionTags/CollectionTagBulkAddDto.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; + +namespace API.DTOs.CollectionTags +{ + public class CollectionTagBulkAddDto + { + /// + /// Collection Tag Id + /// + /// Can be 0 which then will use Title to create a tag + public int CollectionTagId { get; init; } + public string CollectionTagTitle { get; init; } + /// + /// Series Ids to add onto Collection Tag + /// + public IEnumerable SeriesIds { get; init; } + } +} diff --git a/API/DTOs/CollectionTagDto.cs b/API/DTOs/CollectionTags/CollectionTagDto.cs similarity index 87% rename from API/DTOs/CollectionTagDto.cs rename to API/DTOs/CollectionTags/CollectionTagDto.cs index cb9870610..8612f19e0 100644 --- a/API/DTOs/CollectionTagDto.cs +++ b/API/DTOs/CollectionTags/CollectionTagDto.cs @@ -1,4 +1,4 @@ -namespace API.DTOs +namespace API.DTOs.CollectionTags { public class CollectionTagDto { diff --git a/API/DTOs/UpdateSeriesForTagDto.cs b/API/DTOs/CollectionTags/UpdateSeriesForTagDto.cs similarity index 58% rename from API/DTOs/UpdateSeriesForTagDto.cs rename to API/DTOs/CollectionTags/UpdateSeriesForTagDto.cs index 743981165..1a844ee18 100644 --- a/API/DTOs/UpdateSeriesForTagDto.cs +++ b/API/DTOs/CollectionTags/UpdateSeriesForTagDto.cs @@ -1,10 +1,10 @@ using System.Collections.Generic; -namespace API.DTOs +namespace API.DTOs.CollectionTags { public class UpdateSeriesForTagDto { public CollectionTagDto Tag { get; init; } - public ICollection SeriesIdsToRemove { get; init; } + public IEnumerable SeriesIdsToRemove { get; init; } } -} \ No newline at end of file +} diff --git a/API/DTOs/DeleteSeriesDto.cs b/API/DTOs/DeleteSeriesDto.cs new file mode 100644 index 000000000..6908c21ac --- /dev/null +++ b/API/DTOs/DeleteSeriesDto.cs @@ -0,0 +1,9 @@ +using System.Collections.Generic; + +namespace API.DTOs +{ + public class DeleteSeriesDto + { + public IList SeriesIds { get; set; } + } +} diff --git a/API/DTOs/SeriesMetadataDto.cs b/API/DTOs/SeriesMetadataDto.cs index 47d5cbee2..69dcae2d9 100644 --- a/API/DTOs/SeriesMetadataDto.cs +++ b/API/DTOs/SeriesMetadataDto.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using API.DTOs.CollectionTags; using API.Entities; namespace API.DTOs diff --git a/API/DTOs/UpdateSeriesMetadataDto.cs b/API/DTOs/UpdateSeriesMetadataDto.cs index a9c852632..dd43167c9 100644 --- a/API/DTOs/UpdateSeriesMetadataDto.cs +++ b/API/DTOs/UpdateSeriesMetadataDto.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using API.DTOs.CollectionTags; namespace API.DTOs { diff --git a/API/Data/MigrateConfigFiles.cs b/API/Data/MigrateConfigFiles.cs new file mode 100644 index 000000000..2436e3820 --- /dev/null +++ b/API/Data/MigrateConfigFiles.cs @@ -0,0 +1,166 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using API.Services; +using Kavita.Common; + +namespace API.Data +{ + public static class MigrateConfigFiles + { + private static readonly List LooseLeafFiles = new List() + { + "appsettings.json", + "appsettings.Development.json", + "kavita.db", + }; + + private static readonly List AppFolders = new List() + { + "covers", + "stats", + "logs", + "backups", + "cache", + "temp" + }; + + private static readonly string ConfigDirectory = Path.Join(Directory.GetCurrentDirectory(), "config"); + + + /// + /// In v0.4.8 we moved all config files to config/ to match with how docker was setup. This will move all config files from current directory + /// to config/ + /// + public static void Migrate(bool isDocker) + { + Console.WriteLine("Checking if migration to config/ is needed"); + + if (isDocker) + { + if (Configuration.LogPath.Contains("config")) + { + Console.WriteLine("Migration to config/ not needed"); + return; + } + + Console.WriteLine( + "Migrating files from pre-v0.4.8. All Kavita config files are now located in config/"); + + CopyAppFolders(); + DeleteAppFolders(); + + UpdateConfiguration(); + + Console.WriteLine("Migration complete. All config files are now in config/ directory"); + return; + } + + if (new FileInfo(Configuration.AppSettingsFilename).Exists) + { + Console.WriteLine("Migration to config/ not needed"); + return; + } + + Console.WriteLine( + "Migrating files from pre-v0.4.8. All Kavita config files are now located in config/"); + + Console.WriteLine($"Creating {ConfigDirectory}"); + DirectoryService.ExistOrCreate(ConfigDirectory); + + try + { + CopyLooseLeafFiles(); + + CopyAppFolders(); + + // Then we need to update the config file to point to the new DB file + UpdateConfiguration(); + } + catch (Exception) + { + Console.WriteLine("There was an exception during migration. Please move everything manually."); + return; + } + + // Finally delete everything in the source directory + Console.WriteLine("Removing old files"); + DeleteLooseFiles(); + DeleteAppFolders(); + Console.WriteLine("Removing old files...DONE"); + + Console.WriteLine("Migration complete. All config files are now in config/ directory"); + } + + private static void DeleteAppFolders() + { + foreach (var folderToDelete in AppFolders) + { + if (!new DirectoryInfo(Path.Join(Directory.GetCurrentDirectory(), folderToDelete)).Exists) continue; + + DirectoryService.ClearAndDeleteDirectory(Path.Join(Directory.GetCurrentDirectory(), folderToDelete)); + } + } + + private static void DeleteLooseFiles() + { + var configFiles = LooseLeafFiles.Select(file => new FileInfo(Path.Join(Directory.GetCurrentDirectory(), file))) + .Where(f => f.Exists); + DirectoryService.DeleteFiles(configFiles.Select(f => f.FullName)); + } + + private static void CopyAppFolders() + { + Console.WriteLine("Moving folders to config"); + + foreach (var folderToMove in AppFolders) + { + if (new DirectoryInfo(Path.Join(ConfigDirectory, folderToMove)).Exists) continue; + + try + { + DirectoryService.CopyDirectoryToDirectory( + Path.Join(Directory.GetCurrentDirectory(), folderToMove), + Path.Join(ConfigDirectory, folderToMove)); + } + catch (Exception) + { + /* Swallow Exception */ + } + } + + + Console.WriteLine("Moving folders to config...DONE"); + } + + private static void CopyLooseLeafFiles() + { + var configFiles = LooseLeafFiles.Select(file => new FileInfo(Path.Join(Directory.GetCurrentDirectory(), file))) + .Where(f => f.Exists); + // First step is to move all the files + Console.WriteLine("Moving files to config/"); + foreach (var fileInfo in configFiles) + { + try + { + fileInfo.CopyTo(Path.Join(ConfigDirectory, fileInfo.Name)); + } + catch (Exception) + { + /* Swallow exception when already exists */ + } + } + + Console.WriteLine("Moving files to config...DONE"); + } + + private static void UpdateConfiguration() + { + Console.WriteLine("Updating appsettings.json to new paths"); + Configuration.DatabasePath = "config//kavita.db"; + Configuration.LogPath = "config//logs/kavita.log"; + Console.WriteLine("Updating appsettings.json to new paths...DONE"); + } + } +} diff --git a/API/Data/Repositories/CollectionTagRepository.cs b/API/Data/Repositories/CollectionTagRepository.cs index 777e82788..f47ce721f 100644 --- a/API/Data/Repositories/CollectionTagRepository.cs +++ b/API/Data/Repositories/CollectionTagRepository.cs @@ -3,6 +3,7 @@ using System.IO; using System.Linq; using System.Threading.Tasks; using API.DTOs; +using API.DTOs.CollectionTags; using API.Entities; using API.Interfaces.Repositories; using AutoMapper; @@ -22,6 +23,11 @@ namespace API.Data.Repositories _mapper = mapper; } + public void Add(CollectionTag tag) + { + _context.CollectionTag.Add(tag); + } + public void Remove(CollectionTag tag) { _context.CollectionTag.Remove(tag); diff --git a/API/Data/Repositories/SeriesMetadataRepository.cs b/API/Data/Repositories/SeriesMetadataRepository.cs new file mode 100644 index 000000000..32ab0f4e2 --- /dev/null +++ b/API/Data/Repositories/SeriesMetadataRepository.cs @@ -0,0 +1,20 @@ +using API.Entities; +using API.Interfaces.Repositories; + +namespace API.Data.Repositories +{ + public class SeriesMetadataRepository : ISeriesMetadataRepository + { + private readonly DataContext _context; + + public SeriesMetadataRepository(DataContext context) + { + _context = context; + } + + public void Update(SeriesMetadata seriesMetadata) + { + _context.SeriesMetadata.Update(seriesMetadata); + } + } +} diff --git a/API/Data/Repositories/SeriesRepository.cs b/API/Data/Repositories/SeriesRepository.cs index 67cd83276..bed73e2f5 100644 --- a/API/Data/Repositories/SeriesRepository.cs +++ b/API/Data/Repositories/SeriesRepository.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Threading.Tasks; using API.Data.Scanner; using API.DTOs; +using API.DTOs.CollectionTags; using API.DTOs.Filtering; using API.Entities; using API.Extensions; @@ -41,6 +42,11 @@ namespace API.Data.Repositories _context.Series.Remove(series); } + public void Remove(IEnumerable series) + { + _context.Series.RemoveRange(series); + } + public async Task DoesSeriesNameExistInLibrary(string name) { var libraries = _context.Series @@ -171,6 +177,21 @@ namespace API.Data.Repositories .SingleOrDefaultAsync(); } + /// + /// Returns Volumes, Metadata, and Collection Tags + /// + /// + /// + public async Task> GetSeriesByIdsAsync(IList seriesIds) + { + return await _context.Series + .Include(s => s.Volumes) + .Include(s => s.Metadata) + .ThenInclude(m => m.CollectionTags) + .Where(s => seriesIds.Contains(s.Id)) + .ToListAsync(); + } + public async Task GetChapterIdsForSeriesAsync(int[] seriesIds) { var volumes = await _context.Volume @@ -454,15 +475,15 @@ namespace API.Data.Repositories // TODO: Think about making this bigger depending on number of files a user has in said library // and number of cores and amount of memory. We can then make an optimal choice var totalSeries = await GetSeriesCount(libraryId); - var procCount = Math.Max(Environment.ProcessorCount - 1, 1); - - if (totalSeries < procCount * 2 || totalSeries < 50) - { - return new Tuple(totalSeries, totalSeries); - } - - - return new Tuple(totalSeries, Math.Max(totalSeries / procCount, 50)); + // var procCount = Math.Max(Environment.ProcessorCount - 1, 1); + // + // if (totalSeries < procCount * 2 || totalSeries < 50) + // { + // return new Tuple(totalSeries, totalSeries); + // } + // + // return new Tuple(totalSeries, Math.Max(totalSeries / procCount, 50)); + return new Tuple(totalSeries, 50); } public async Task GetChunkInfo(int libraryId = 0) @@ -485,5 +506,13 @@ namespace API.Data.Repositories TotalChunks = totalChunks }; } + + public async Task> GetSeriesMetadataForIdsAsync(IEnumerable seriesIds) + { + return await _context.SeriesMetadata + .Where(sm => seriesIds.Contains(sm.SeriesId)) + .Include(sm => sm.CollectionTags) + .ToListAsync(); + } } } diff --git a/API/Data/Repositories/SettingsRepository.cs b/API/Data/Repositories/SettingsRepository.cs index 168b5a21e..4489cf3bd 100644 --- a/API/Data/Repositories/SettingsRepository.cs +++ b/API/Data/Repositories/SettingsRepository.cs @@ -35,15 +35,6 @@ namespace API.Data.Repositories return _mapper.Map(settings); } - public ServerSettingDto GetSettingsDto() - { - var settings = _context.ServerSetting - .Select(x => x) - .AsNoTracking() - .ToList(); - return _mapper.Map(settings); - } - public Task GetSettingAsync(ServerSettingKey key) { return _context.ServerSetting.SingleOrDefaultAsync(x => x.Key == key); diff --git a/API/Data/Seed.cs b/API/Data/Seed.cs index 6b62089d0..ae7c9e818 100644 --- a/API/Data/Seed.cs +++ b/API/Data/Seed.cs @@ -41,11 +41,11 @@ namespace API.Data IList defaultSettings = new List() { - new() {Key = ServerSettingKey.CacheDirectory, Value = CacheService.CacheDirectory}, + new() {Key = ServerSettingKey.CacheDirectory, Value = DirectoryService.CacheDirectory}, new () {Key = ServerSettingKey.TaskScan, Value = "daily"}, new () {Key = ServerSettingKey.LoggingLevel, Value = "Information"}, // Not used from DB, but DB is sync with appSettings.json new () {Key = ServerSettingKey.TaskBackup, Value = "weekly"}, - new () {Key = ServerSettingKey.BackupDirectory, Value = Path.GetFullPath(Path.Join(Directory.GetCurrentDirectory(), "backups/"))}, + new () {Key = ServerSettingKey.BackupDirectory, Value = Path.GetFullPath(DirectoryService.BackupDirectory)}, new () {Key = ServerSettingKey.Port, Value = "5000"}, // Not used from DB, but DB is sync with appSettings.json new () {Key = ServerSettingKey.AllowStatCollection, Value = "true"}, new () {Key = ServerSettingKey.EnableOpds, Value = "false"}, @@ -69,6 +69,8 @@ namespace API.Data Configuration.Port + string.Empty; context.ServerSetting.First(s => s.Key == ServerSettingKey.LoggingLevel).Value = Configuration.LogLevel + string.Empty; + context.ServerSetting.First(s => s.Key == ServerSettingKey.CacheDirectory).Value = + DirectoryService.CacheDirectory + string.Empty; await context.SaveChangesAsync(); diff --git a/API/Data/UnitOfWork.cs b/API/Data/UnitOfWork.cs index 64f9c4fe0..a1f797188 100644 --- a/API/Data/UnitOfWork.cs +++ b/API/Data/UnitOfWork.cs @@ -34,6 +34,7 @@ namespace API.Data public IFileRepository FileRepository => new FileRepository(_context); public IChapterRepository ChapterRepository => new ChapterRepository(_context, _mapper); public IReadingListRepository ReadingListRepository => new ReadingListRepository(_context, _mapper); + public ISeriesMetadataRepository SeriesMetadataRepository => new SeriesMetadataRepository(_context); /// /// Commits changes to the DB. Completes the open transaction. diff --git a/API/Entities/ServerSetting.cs b/API/Entities/ServerSetting.cs index b09ae71e0..6c4b5f21d 100644 --- a/API/Entities/ServerSetting.cs +++ b/API/Entities/ServerSetting.cs @@ -8,6 +8,9 @@ namespace API.Entities { [Key] public ServerSettingKey Key { get; set; } + /// + /// The value of the Setting. Converter knows how to convert to the correct type + /// public string Value { get; set; } /// diff --git a/API/Extensions/ServiceCollectionExtensions.cs b/API/Extensions/ServiceCollectionExtensions.cs deleted file mode 100644 index 903ed5b88..000000000 --- a/API/Extensions/ServiceCollectionExtensions.cs +++ /dev/null @@ -1,24 +0,0 @@ -using API.Interfaces.Services; -using API.Services.Clients; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; - -namespace API.Extensions -{ - public static class ServiceCollectionExtensions - { - public static IServiceCollection AddStartupTask(this IServiceCollection services) - where T : class, IStartupTask - => services.AddTransient(); - - public static IServiceCollection AddStatsClient(this IServiceCollection services, IConfiguration configuration) - { - services.AddHttpClient(client => - { - client.DefaultRequestHeaders.Add("api-key", "MsnvA2DfQqxSK5jh"); - }); - - return services; - } - } -} diff --git a/API/Helpers/AutoMapperProfiles.cs b/API/Helpers/AutoMapperProfiles.cs index ff1a30e34..74bd8d57c 100644 --- a/API/Helpers/AutoMapperProfiles.cs +++ b/API/Helpers/AutoMapperProfiles.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Linq; using API.DTOs; +using API.DTOs.CollectionTags; using API.DTOs.Reader; using API.DTOs.ReadingLists; using API.DTOs.Settings; diff --git a/API/Interfaces/IUnitOfWork.cs b/API/Interfaces/IUnitOfWork.cs index 06b47bbe8..733008192 100644 --- a/API/Interfaces/IUnitOfWork.cs +++ b/API/Interfaces/IUnitOfWork.cs @@ -15,6 +15,7 @@ namespace API.Interfaces IFileRepository FileRepository { get; } IChapterRepository ChapterRepository { get; } IReadingListRepository ReadingListRepository { get; } + ISeriesMetadataRepository SeriesMetadataRepository { get; } bool Commit(); Task CommitAsync(); bool HasChanges(); diff --git a/API/Interfaces/Repositories/ICollectionTagRepository.cs b/API/Interfaces/Repositories/ICollectionTagRepository.cs index 03a552bd9..18c9f490b 100644 --- a/API/Interfaces/Repositories/ICollectionTagRepository.cs +++ b/API/Interfaces/Repositories/ICollectionTagRepository.cs @@ -1,12 +1,14 @@ using System.Collections.Generic; using System.Threading.Tasks; using API.DTOs; +using API.DTOs.CollectionTags; using API.Entities; namespace API.Interfaces.Repositories { public interface ICollectionTagRepository { + void Add(CollectionTag tag); void Remove(CollectionTag tag); Task> GetAllTagDtosAsync(); Task> SearchTagDtosAsync(string searchQuery); diff --git a/API/Interfaces/Repositories/ISeriesMetadataRepository.cs b/API/Interfaces/Repositories/ISeriesMetadataRepository.cs new file mode 100644 index 000000000..00dd234ee --- /dev/null +++ b/API/Interfaces/Repositories/ISeriesMetadataRepository.cs @@ -0,0 +1,9 @@ +using API.Entities; + +namespace API.Interfaces.Repositories +{ + public interface ISeriesMetadataRepository + { + void Update(SeriesMetadata seriesMetadata); + } +} diff --git a/API/Interfaces/Repositories/ISeriesRepository.cs b/API/Interfaces/Repositories/ISeriesRepository.cs index 0b3ed8eeb..2129c894b 100644 --- a/API/Interfaces/Repositories/ISeriesRepository.cs +++ b/API/Interfaces/Repositories/ISeriesRepository.cs @@ -13,6 +13,7 @@ namespace API.Interfaces.Repositories void Attach(Series series); void Update(Series series); void Remove(Series series); + void Remove(IEnumerable series); Task DoesSeriesNameExistInLibrary(string name); /// /// Adds user information like progress, ratings, etc @@ -33,6 +34,7 @@ namespace API.Interfaces.Repositories Task GetSeriesDtoByIdAsync(int seriesId, int userId); Task DeleteSeriesAsync(int seriesId); Task GetSeriesByIdAsync(int seriesId); + Task> GetSeriesByIdsAsync(IList seriesIds); Task GetChapterIdsForSeriesAsync(int[] seriesIds); Task>> GetChapterIdWithSeriesIdForSeriesAsync(int[] seriesIds); /// @@ -54,5 +56,6 @@ namespace API.Interfaces.Repositories Task> GetFullSeriesForLibraryIdAsync(int libraryId, UserParams userParams); Task GetFullSeriesForSeriesIdAsync(int seriesId); Task GetChunkInfo(int libraryId = 0); + Task> GetSeriesMetadataForIdsAsync(IEnumerable seriesIds); } } diff --git a/API/Interfaces/Repositories/ISettingsRepository.cs b/API/Interfaces/Repositories/ISettingsRepository.cs index 79014dce4..95178ea79 100644 --- a/API/Interfaces/Repositories/ISettingsRepository.cs +++ b/API/Interfaces/Repositories/ISettingsRepository.cs @@ -10,7 +10,6 @@ namespace API.Interfaces.Repositories { void Update(ServerSetting settings); Task GetSettingsDtoAsync(); - ServerSettingDto GetSettingsDto(); Task GetSettingAsync(ServerSettingKey key); Task> GetSettingsAsync(); diff --git a/API/Interfaces/Services/IDirectoryService.cs b/API/Interfaces/Services/IDirectoryService.cs index 43779774c..a8ae8c05f 100644 --- a/API/Interfaces/Services/IDirectoryService.cs +++ b/API/Interfaces/Services/IDirectoryService.cs @@ -12,21 +12,9 @@ namespace API.Interfaces.Services /// Absolute path of directory to scan. /// List of folder names IEnumerable ListDirectory(string rootPath); - /// - /// Gets files in a directory. If searchPatternExpression is passed, will match the regex against for filtering. - /// - /// - /// - /// - string[] GetFilesWithExtension(string path, string searchPatternExpression = ""); Task ReadFileAsync(string path); bool CopyFilesToDirectory(IEnumerable filePaths, string directoryPath, string prepend = ""); bool Exists(string directory); - - IEnumerable GetFiles(string path, string searchPatternExpression = "", - SearchOption searchOption = SearchOption.TopDirectoryOnly); - void CopyFileToDirectory(string fullFilePath, string targetDirectory); - public bool CopyDirectoryToDirectory(string sourceDirName, string destDirName, string searchPattern = "*"); } } diff --git a/API/Interfaces/Services/IStatsService.cs b/API/Interfaces/Services/IStatsService.cs index 19d8d9f4b..9e3536e23 100644 --- a/API/Interfaces/Services/IStatsService.cs +++ b/API/Interfaces/Services/IStatsService.cs @@ -5,7 +5,7 @@ namespace API.Interfaces.Services { public interface IStatsService { - Task PathData(ClientInfoDto clientInfoDto); - Task CollectAndSendStatsData(); + Task RecordClientInfo(ClientInfoDto clientInfoDto); + Task Send(); } } diff --git a/API/Parser/Parser.cs b/API/Parser/Parser.cs index 9bd2aab82..2f8b704de 100644 --- a/API/Parser/Parser.cs +++ b/API/Parser/Parser.cs @@ -24,11 +24,25 @@ namespace API.Parser private const RegexOptions MatchOptions = RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.CultureInvariant; - public static readonly Regex FontSrcUrlRegex = new Regex(@"(src:url\(.{1})" + "([^\"']*)" + @"(.{1}\))", + /// + /// Matches against font-family css syntax. Does not match if url import has data: starting, as that is binary data + /// + /// See here for some examples https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face + public static readonly Regex FontSrcUrlRegex = new Regex(@"(?(src:\s?)?url\((?!data:).(?!data:))" + "(?(?!data:)[^\"']*)" + @"(?.{1}\))", MatchOptions, RegexTimeout); - public static readonly Regex CssImportUrlRegex = new Regex("(@import\\s[\"|'])(?[\\w\\d/\\._-]+)([\"|'];?)", + /// + /// https://developer.mozilla.org/en-US/docs/Web/CSS/@import + /// + public static readonly Regex CssImportUrlRegex = new Regex("(@import\\s([\"|']|url\\([\"|']))(?[^'\"]+)([\"|']\\)?);", + MatchOptions | RegexOptions.Multiline, RegexTimeout); + /// + /// Misc css image references, like background-image: url(), border-image, or list-style-image + /// + /// Original prepend: (background|border|list-style)-image:\s?)? + public static readonly Regex CssImageUrlRegex = new Regex(@"(url\((?!data:).(?!data:))" + "(?(?!data:)[^\"']*)" + @"(.\))", MatchOptions, RegexTimeout); + private static readonly string XmlRegexExtensions = @"\.xml"; private static readonly Regex ImageRegex = new Regex(ImageFileExtensions, MatchOptions, RegexTimeout); @@ -212,7 +226,7 @@ namespace API.Parser MatchOptions, RegexTimeout), // Baketeriya ch01-05.zip, Akiiro Bousou Biyori - 01.jpg, Beelzebub_172_RHS.zip, Cynthia the Mission 29.rar, A Compendium of Ghosts - 031 - The Third Story_ Part 12 (Digital) (Cobalt001) new Regex( - @"^(?!Vol\.?)(?.+?)( |_|-)(?.+?)(\s|_|-)(?()).IsDocker; - // Before anything, check if JWT has been generated properly or if user still has default - if (!Configuration.CheckIfJwtTokenSet() && - Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") != Environments.Development) - { - Console.WriteLine("Generating JWT TokenKey for encrypting user sessions..."); - var rBytes = new byte[128]; - using (var crypto = new RNGCryptoServiceProvider()) crypto.GetBytes(rBytes); - Configuration.JwtToken = Convert.ToBase64String(rBytes).Replace("/", string.Empty); - } + MigrateConfigFiles.Migrate(isDocker); - var host = CreateHostBuilder(args).Build(); + // Before anything, check if JWT has been generated properly or if user still has default + if (!Configuration.CheckIfJwtTokenSet() && + Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") != Environments.Development) + { + Console.WriteLine("Generating JWT TokenKey for encrypting user sessions..."); + var rBytes = new byte[128]; + using (var crypto = new RNGCryptoServiceProvider()) crypto.GetBytes(rBytes); + Configuration.JwtToken = Convert.ToBase64String(rBytes).Replace("/", string.Empty); + } - using var scope = host.Services.CreateScope(); - var services = scope.ServiceProvider; + var host = CreateHostBuilder(args).Build(); - try - { - var context = services.GetRequiredService(); - var roleManager = services.GetRequiredService>(); + using var scope = host.Services.CreateScope(); + var services = scope.ServiceProvider; - var requiresCoverImageMigration = !Directory.Exists(DirectoryService.CoverImageDirectory); try { - // If this is a new install, tables wont exist yet + var context = services.GetRequiredService(); + var roleManager = services.GetRequiredService>(); + + if (isDocker && new FileInfo("data/appsettings.json").Exists) + { + var logger = services.GetRequiredService>(); + logger.LogCritical("WARNING! Mount point is incorrect, nothing here will persist. Please change your container mount from /kavita/data to /kavita/config"); + return; + } + + + var requiresCoverImageMigration = !Directory.Exists(DirectoryService.CoverImageDirectory); + try + { + // If this is a new install, tables wont exist yet + if (requiresCoverImageMigration) + { + MigrateCoverImages.ExtractToImages(context); + } + } + catch (Exception) + { + requiresCoverImageMigration = false; + } + + // Apply all migrations on startup + await context.Database.MigrateAsync(); + if (requiresCoverImageMigration) { - MigrateCoverImages.ExtractToImages(context); + await MigrateCoverImages.UpdateDatabaseWithImages(context); } + + await Seed.SeedRoles(roleManager); + await Seed.SeedSettings(context); + await Seed.SeedUserApiKeys(context); } - catch (Exception ) + catch (Exception ex) { - requiresCoverImageMigration = false; + var logger = services.GetRequiredService>(); + logger.LogError(ex, "An error occurred during migration"); } - // Apply all migrations on startup - await context.Database.MigrateAsync(); + await host.RunAsync(); + } - if (requiresCoverImageMigration) - { - await MigrateCoverImages.UpdateDatabaseWithImages(context); - } + private static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .ConfigureAppConfiguration((hostingContext, config) => + { + config.Sources.Clear(); - await Seed.SeedRoles(roleManager); - await Seed.SeedSettings(context); - await Seed.SeedUserApiKeys(context); - } - catch (Exception ex) - { - var logger = services.GetRequiredService>(); - logger.LogError(ex, "An error occurred during migration"); - } + var env = hostingContext.HostingEnvironment; - await host.RunAsync(); - } + config.AddJsonFile("config/appsettings.json", optional: true, reloadOnChange: false) + .AddJsonFile($"config/appsettings.{env.EnvironmentName}.json", + optional: true, reloadOnChange: false); + }) + .ConfigureWebHostDefaults(webBuilder => + { + webBuilder.UseKestrel((opts) => + { + opts.ListenAnyIP(HttpPort, options => { options.Protocols = HttpProtocols.Http1AndHttp2; }); + }); - private static IHostBuilder CreateHostBuilder(string[] args) => - Host.CreateDefaultBuilder(args) - .ConfigureWebHostDefaults(webBuilder => - { - webBuilder.UseKestrel((opts) => - { - opts.ListenAnyIP(HttpPort, options => { options.Protocols = HttpProtocols.Http1AndHttp2; }); - }); + webBuilder.UseStartup(); + }); - webBuilder.UseStartup(); - }); - } + + + + } } diff --git a/API/Services/ArchiveService.cs b/API/Services/ArchiveService.cs index 621d42322..10d45f232 100644 --- a/API/Services/ArchiveService.cs +++ b/API/Services/ArchiveService.cs @@ -123,12 +123,24 @@ namespace API.Services /// /// /// Entry name of match, null if no match - public string FirstFileEntry(IEnumerable entryFullNames) + public static string FirstFileEntry(IEnumerable entryFullNames, string archiveName) { - var result = entryFullNames.OrderBy(Path.GetFileName, new NaturalSortComparer()) - .FirstOrDefault(x => !Parser.Parser.HasBlacklistedFolderInPath(x) - && Parser.Parser.IsImage(x) - && !x.StartsWith(Parser.Parser.MacOsMetadataFileStartsWith)); + // First check if there are any files that are not in a nested folder before just comparing by filename. This is needed + // because NaturalSortComparer does not work with paths and doesn't seem 001.jpg as before chapter 1/001.jpg. + var fullNames = entryFullNames.Where(x =>!Parser.Parser.HasBlacklistedFolderInPath(x) + && Parser.Parser.IsImage(x) + && !x.StartsWith(Parser.Parser.MacOsMetadataFileStartsWith)).ToList(); + if (fullNames.Count == 0) return null; + + var nonNestedFile = fullNames.Where(entry => (Path.GetDirectoryName(entry) ?? string.Empty).Equals(archiveName)) + .OrderBy(Path.GetFullPath, new NaturalSortComparer()) + .FirstOrDefault(); + + if (!string.IsNullOrEmpty(nonNestedFile)) return nonNestedFile; + + var result = fullNames + .OrderBy(Path.GetFileName, new NaturalSortComparer()) + .FirstOrDefault(); return string.IsNullOrEmpty(result) ? null : result; } @@ -158,7 +170,7 @@ namespace API.Services using var archive = ZipFile.OpenRead(archivePath); var entryNames = archive.Entries.Select(e => e.FullName).ToArray(); - var entryName = FindFolderEntry(entryNames) ?? FirstFileEntry(entryNames); + var entryName = FindFolderEntry(entryNames) ?? FirstFileEntry(entryNames, Path.GetFileName(archivePath)); var entry = archive.Entries.Single(e => e.FullName == entryName); using var stream = entry.Open(); @@ -169,7 +181,7 @@ namespace API.Services using var archive = ArchiveFactory.Open(archivePath); var entryNames = archive.Entries.Where(archiveEntry => !archiveEntry.IsDirectory).Select(e => e.Key).ToList(); - var entryName = FindFolderEntry(entryNames) ?? FirstFileEntry(entryNames); + var entryName = FindFolderEntry(entryNames) ?? FirstFileEntry(entryNames, Path.GetFileName(archivePath)); var entry = archive.Entries.Single(e => e.Key == entryName); using var stream = entry.OpenEntryStream(); diff --git a/API/Services/BookService.cs b/API/Services/BookService.cs index a114b3bd6..71f633e4c 100644 --- a/API/Services/BookService.cs +++ b/API/Services/BookService.cs @@ -140,15 +140,22 @@ namespace API.Services } stylesheetHtml = stylesheetHtml.Insert(0, importBuilder.ToString()); - stylesheetHtml = - Parser.Parser.CssImportUrlRegex.Replace(stylesheetHtml, "$1" + apiBase + prepend + "$2" + "$3"); + var importMatches = Parser.Parser.CssImportUrlRegex.Matches(stylesheetHtml); + foreach (Match match in importMatches) + { + if (!match.Success) continue; + var importFile = match.Groups["Filename"].Value; + stylesheetHtml = stylesheetHtml.Replace(importFile, apiBase + prepend + importFile); + } + + // Check if there are any background images and rewrite those urls + EscapeCssImageReferences(ref stylesheetHtml, apiBase, book); var styleContent = RemoveWhiteSpaceFromStylesheets(stylesheetHtml); - styleContent = - Parser.Parser.FontSrcUrlRegex.Replace(styleContent, "$1" + apiBase + "$2" + "$3"); - styleContent = styleContent.Replace("body", ".reading-section"); + if (string.IsNullOrEmpty(styleContent)) return string.Empty; + var stylesheet = await _cssParser.ParseAsync(styleContent); foreach (var styleRule in stylesheet.StyleRules) { @@ -165,6 +172,21 @@ namespace API.Services return RemoveWhiteSpaceFromStylesheets(stylesheet.ToCss()); } + private static void EscapeCssImageReferences(ref string stylesheetHtml, string apiBase, EpubBookRef book) + { + var matches = Parser.Parser.CssImageUrlRegex.Matches(stylesheetHtml); + foreach (Match match in matches) + { + if (!match.Success) continue; + + var importFile = match.Groups["Filename"].Value; + var key = CleanContentKeys(importFile); + if (!book.Content.AllFiles.ContainsKey(key)) continue; + + stylesheetHtml = stylesheetHtml.Replace(importFile, apiBase + key); + } + } + public ComicInfo GetComicInfo(string filePath) { if (!IsValidFile(filePath) || Parser.Parser.IsPdf(filePath)) return null; @@ -488,15 +510,29 @@ namespace API.Services private static string RemoveWhiteSpaceFromStylesheets(string body) { + if (string.IsNullOrEmpty(body)) + { + return string.Empty; + } + + // Remove comments from CSS + body = Regex.Replace(body, @"/\*[\d\D]*?\*/", string.Empty); + body = Regex.Replace(body, @"[a-zA-Z]+#", "#"); body = Regex.Replace(body, @"[\n\r]+\s*", string.Empty); body = Regex.Replace(body, @"\s+", " "); body = Regex.Replace(body, @"\s?([:,;{}])\s?", "$1"); - body = body.Replace(";}", "}"); + try + { + body = body.Replace(";}", "}"); + } + catch (Exception) + { + /* Swallow exception. Some css doesn't have style rules ending in ; */ + } + body = Regex.Replace(body, @"([\s:]0)(px|pt|%|em)", "$1"); - // Remove comments from CSS - body = Regex.Replace(body, @"/\*[\d\D]*?\*/", string.Empty); return body; } diff --git a/API/Services/CacheService.cs b/API/Services/CacheService.cs index 8decdeccd..a64bde675 100644 --- a/API/Services/CacheService.cs +++ b/API/Services/CacheService.cs @@ -21,7 +21,6 @@ namespace API.Services private readonly IDirectoryService _directoryService; private readonly IBookService _bookService; private readonly NumericComparer _numericComparer; - public static readonly string CacheDirectory = Path.GetFullPath(Path.Join(Directory.GetCurrentDirectory(), "cache/")); public CacheService(ILogger logger, IUnitOfWork unitOfWork, IArchiveService archiveService, IDirectoryService directoryService, IBookService bookService) @@ -38,7 +37,7 @@ namespace API.Services { if (!DirectoryService.ExistOrCreate(DirectoryService.CacheDirectory)) { - _logger.LogError("Cache directory {CacheDirectory} is not accessible or does not exist. Creating...", CacheDirectory); + _logger.LogError("Cache directory {CacheDirectory} is not accessible or does not exist. Creating...", DirectoryService.CacheDirectory); } } @@ -102,7 +101,7 @@ namespace API.Services } else { - _directoryService.CopyDirectoryToDirectory(Path.GetDirectoryName(files[0].FilePath), extractPath, + DirectoryService.CopyDirectoryToDirectory(Path.GetDirectoryName(files[0].FilePath), extractPath, Parser.Parser.ImageFileExtensions); } @@ -147,7 +146,7 @@ namespace API.Services try { - DirectoryService.ClearDirectory(CacheDirectory); + DirectoryService.ClearDirectory(DirectoryService.CacheDirectory); } catch (Exception ex) { @@ -198,7 +197,7 @@ namespace API.Services if (page <= (mangaFile.Pages + pagesSoFar)) { var path = GetCachePath(chapter.Id); - var files = _directoryService.GetFilesWithExtension(path, Parser.Parser.ImageFileExtensions); + var files = DirectoryService.GetFilesWithExtension(path, Parser.Parser.ImageFileExtensions); Array.Sort(files, _numericComparer); if (files.Length == 0) diff --git a/API/Services/Clients/StatsApiClient.cs b/API/Services/Clients/StatsApiClient.cs deleted file mode 100644 index 52d1c9fcf..000000000 --- a/API/Services/Clients/StatsApiClient.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System; -using System.Net.Http; -using System.Net.Http.Json; -using System.Threading.Tasks; -using API.DTOs.Stats; -using Microsoft.Extensions.Logging; - -namespace API.Services.Clients -{ - public class StatsApiClient - { - private readonly HttpClient _client; - private readonly ILogger _logger; -#pragma warning disable S1075 - private const string ApiUrl = "http://stats.kavitareader.com"; -#pragma warning restore S1075 - - public StatsApiClient(HttpClient client, ILogger logger) - { - _client = client; - _logger = logger; - _client.Timeout = TimeSpan.FromSeconds(30); - } - - public async Task SendDataToStatsServer(UsageStatisticsDto data) - { - var responseContent = string.Empty; - - try - { - using var response = await _client.PostAsJsonAsync(ApiUrl + "/api/InstallationStats", data); - - responseContent = await response.Content.ReadAsStringAsync(); - - response.EnsureSuccessStatusCode(); - } - catch (HttpRequestException e) - { - var info = new - { - dataSent = data, - response = responseContent - }; - - _logger.LogError(e, "KavitaStats did not respond successfully. {Content}", info); - throw; - } - catch (Exception e) - { - _logger.LogError(e, "An error happened during the request to KavitaStats"); - throw; - } - } - } -} diff --git a/API/Services/DirectoryService.cs b/API/Services/DirectoryService.cs index 360492303..1a067a706 100644 --- a/API/Services/DirectoryService.cs +++ b/API/Services/DirectoryService.cs @@ -16,10 +16,12 @@ namespace API.Services private static readonly Regex ExcludeDirectories = new Regex( @"@eaDir|\.DS_Store", RegexOptions.Compiled | RegexOptions.IgnoreCase); - public static readonly string TempDirectory = Path.Join(Directory.GetCurrentDirectory(), "temp"); - public static readonly string LogDirectory = Path.Join(Directory.GetCurrentDirectory(), "logs"); - public static readonly string CacheDirectory = Path.Join(Directory.GetCurrentDirectory(), "cache"); - public static readonly string CoverImageDirectory = Path.Join(Directory.GetCurrentDirectory(), "covers"); + public static readonly string TempDirectory = Path.Join(Directory.GetCurrentDirectory(), "config", "temp"); + public static readonly string LogDirectory = Path.Join(Directory.GetCurrentDirectory(), "config", "logs"); + public static readonly string CacheDirectory = Path.Join(Directory.GetCurrentDirectory(), "config", "cache"); + public static readonly string CoverImageDirectory = Path.Join(Directory.GetCurrentDirectory(), "config", "covers"); + public static readonly string BackupDirectory = Path.Join(Directory.GetCurrentDirectory(), "config", "backups"); + public static readonly string StatsDirectory = Path.Join(Directory.GetCurrentDirectory(), "config", "stats"); public DirectoryService(ILogger logger) { @@ -95,7 +97,7 @@ namespace API.Services return di.Exists; } - public IEnumerable GetFiles(string path, string searchPatternExpression = "", + public static IEnumerable GetFiles(string path, string searchPatternExpression = "", SearchOption searchOption = SearchOption.TopDirectoryOnly) { if (searchPatternExpression != string.Empty) @@ -134,13 +136,10 @@ namespace API.Services /// Defaults to *, meaning all files /// /// - public bool CopyDirectoryToDirectory(string sourceDirName, string destDirName, string searchPattern = "*") + public static bool CopyDirectoryToDirectory(string sourceDirName, string destDirName, string searchPattern = "") { if (string.IsNullOrEmpty(sourceDirName)) return false; - var di = new DirectoryInfo(sourceDirName); - if (!di.Exists) return false; - // Get the subdirectories for the specified directory. var dir = new DirectoryInfo(sourceDirName); @@ -154,7 +153,7 @@ namespace API.Services var dirs = dir.GetDirectories(); // If the destination directory doesn't exist, create it. - Directory.CreateDirectory(destDirName); + ExistOrCreate(destDirName); // Get the files in the directory and copy them to the new location. var files = GetFilesWithExtension(dir.FullName, searchPattern).Select(n => new FileInfo(n)); @@ -176,7 +175,7 @@ namespace API.Services - public string[] GetFilesWithExtension(string path, string searchPatternExpression = "") + public static string[] GetFilesWithExtension(string path, string searchPatternExpression = "") { if (searchPatternExpression != string.Empty) { diff --git a/API/Services/ImageService.cs b/API/Services/ImageService.cs index c2b3d4126..7f663c37d 100644 --- a/API/Services/ImageService.cs +++ b/API/Services/ImageService.cs @@ -13,7 +13,6 @@ namespace API.Services public class ImageService : IImageService { private readonly ILogger _logger; - private readonly IDirectoryService _directoryService; public const string ChapterCoverImageRegex = @"v\d+_c\d+"; public const string SeriesCoverImageRegex = @"seres\d+"; public const string CollectionTagCoverImageRegex = @"tag\d+"; @@ -24,10 +23,9 @@ namespace API.Services /// private const int ThumbnailWidth = 320; - public ImageService(ILogger logger, IDirectoryService directoryService) + public ImageService(ILogger logger) { _logger = logger; - _directoryService = directoryService; } /// @@ -44,9 +42,9 @@ namespace API.Services return null; } - var firstImage = _directoryService.GetFilesWithExtension(directory, Parser.Parser.ImageFileExtensions) + var firstImage = DirectoryService.GetFilesWithExtension(directory, Parser.Parser.ImageFileExtensions) .OrderBy(f => f, new NaturalSortComparer()).FirstOrDefault(); - + return firstImage; } diff --git a/API/Services/MetadataService.cs b/API/Services/MetadataService.cs index acae153c4..1b5ab0d69 100644 --- a/API/Services/MetadataService.cs +++ b/API/Services/MetadataService.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; @@ -216,37 +217,45 @@ namespace API.Services var chunkInfo = await _unitOfWork.SeriesRepository.GetChunkInfo(library.Id); var stopwatch = Stopwatch.StartNew(); var totalTime = 0L; - _logger.LogDebug($"[MetadataService] Refreshing Library {library.Name}. Total Items: {chunkInfo.TotalSize}. Total Chunks: {chunkInfo.TotalChunks} with {chunkInfo.ChunkSize} size."); + _logger.LogInformation("[MetadataService] Refreshing Library {LibraryName}. Total Items: {TotalSize}. Total Chunks: {TotalChunks} with {ChunkSize} size", library.Name, chunkInfo.TotalSize, chunkInfo.TotalChunks, chunkInfo.ChunkSize); - // This technically does for (var chunk = 1; chunk <= chunkInfo.TotalChunks; chunk++) { + if (chunkInfo.TotalChunks == 0) continue; totalTime += stopwatch.ElapsedMilliseconds; stopwatch.Restart(); - _logger.LogDebug($"[MetadataService] Processing chunk {chunk} / {chunkInfo.TotalChunks} with size {chunkInfo.ChunkSize} Series ({chunk * chunkInfo.ChunkSize} - {(chunk + 1) * chunkInfo.ChunkSize}"); + _logger.LogInformation("[MetadataService] Processing chunk {ChunkNumber} / {TotalChunks} with size {ChunkSize}. Series ({SeriesStart} - {SeriesEnd}", + chunk, chunkInfo.TotalChunks, chunkInfo.ChunkSize, chunk * chunkInfo.ChunkSize, (chunk + 1) * chunkInfo.ChunkSize); var nonLibrarySeries = await _unitOfWork.SeriesRepository.GetFullSeriesForLibraryIdAsync(library.Id, new UserParams() { PageNumber = chunk, PageSize = chunkInfo.ChunkSize }); - _logger.LogDebug($"[MetadataService] Fetched {nonLibrarySeries.Count} series for refresh"); + _logger.LogDebug("[MetadataService] Fetched {SeriesCount} series for refresh", nonLibrarySeries.Count); Parallel.ForEach(nonLibrarySeries, series => { - _logger.LogDebug("[MetadataService] Processing series {SeriesName}", series.OriginalName); - var volumeUpdated = false; - foreach (var volume in series.Volumes) + try { - var chapterUpdated = false; - foreach (var chapter in volume.Chapters) + _logger.LogDebug("[MetadataService] Processing series {SeriesName}", series.OriginalName); + var volumeUpdated = false; + foreach (var volume in series.Volumes) { - chapterUpdated = UpdateMetadata(chapter, forceUpdate); + var chapterUpdated = false; + foreach (var chapter in volume.Chapters) + { + chapterUpdated = UpdateMetadata(chapter, forceUpdate); + } + + volumeUpdated = UpdateMetadata(volume, chapterUpdated || forceUpdate); } - volumeUpdated = UpdateMetadata(volume, chapterUpdated || forceUpdate); + UpdateMetadata(series, volumeUpdated || forceUpdate); + } + catch (Exception) + { + /* Swallow exception */ } - - UpdateMetadata(series, volumeUpdated || forceUpdate); }); if (_unitOfWork.HasChanges() && await _unitOfWork.CommitAsync()) diff --git a/API/Services/TaskScheduler.cs b/API/Services/TaskScheduler.cs index e60161b61..ee68df106 100644 --- a/API/Services/TaskScheduler.cs +++ b/API/Services/TaskScheduler.cs @@ -89,7 +89,7 @@ namespace API.Services } _logger.LogDebug("Scheduling stat collection daily"); - RecurringJob.AddOrUpdate(SendDataTask, () => _statsService.CollectAndSendStatsData(), Cron.Daily, TimeZoneInfo.Local); + RecurringJob.AddOrUpdate(SendDataTask, () => _statsService.Send(), Cron.Daily, TimeZoneInfo.Local); } public void CancelStatsTasks() @@ -102,7 +102,7 @@ namespace API.Services public void RunStatCollection() { _logger.LogInformation("Enqueuing stat collection"); - BackgroundJob.Enqueue(() => _statsService.CollectAndSendStatsData()); + BackgroundJob.Enqueue(() => _statsService.Send()); } #endregion @@ -138,8 +138,7 @@ namespace API.Services public void CleanupTemp() { - var tempDirectory = Path.Join(Directory.GetCurrentDirectory(), "temp"); - BackgroundJob.Enqueue(() => DirectoryService.ClearDirectory(tempDirectory)); + BackgroundJob.Enqueue(() => DirectoryService.ClearDirectory(DirectoryService.TempDirectory)); } public void RefreshSeriesMetadata(int libraryId, int seriesId, bool forceUpdate = true) diff --git a/API/Services/Tasks/BackupService.cs b/API/Services/Tasks/BackupService.cs index b4dc3910b..e71f35e9f 100644 --- a/API/Services/Tasks/BackupService.cs +++ b/API/Services/Tasks/BackupService.cs @@ -9,6 +9,7 @@ using API.Extensions; using API.Interfaces; using API.Interfaces.Services; using Hangfire; +using Kavita.Common.EnvironmentInfo; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; @@ -19,8 +20,8 @@ namespace API.Services.Tasks private readonly IUnitOfWork _unitOfWork; private readonly ILogger _logger; private readonly IDirectoryService _directoryService; - private readonly string _tempDirectory = Path.Join(Directory.GetCurrentDirectory(), "temp"); - private readonly string _logDirectory = Path.Join(Directory.GetCurrentDirectory(), "logs"); + private readonly string _tempDirectory = DirectoryService.TempDirectory; + private readonly string _logDirectory = DirectoryService.LogDirectory; private readonly IList _backupFiles; @@ -33,15 +34,32 @@ namespace API.Services.Tasks var maxRollingFiles = config.GetMaxRollingFiles(); var loggingSection = config.GetLoggingFileName(); var files = LogFiles(maxRollingFiles, loggingSection); - _backupFiles = new List() + + if (new OsInfo(Array.Empty()).IsDocker) { - "appsettings.json", - "Hangfire.db", - "Hangfire-log.db", - "kavita.db", - "kavita.db-shm", // This wont always be there - "kavita.db-wal", // This wont always be there - }; + _backupFiles = new List() + { + "data/appsettings.json", + "data/Hangfire.db", + "data/Hangfire-log.db", + "data/kavita.db", + "data/kavita.db-shm", // This wont always be there + "data/kavita.db-wal" // This wont always be there + }; + } + else + { + _backupFiles = new List() + { + "appsettings.json", + "Hangfire.db", + "Hangfire-log.db", + "kavita.db", + "kavita.db-shm", // This wont always be there + "kavita.db-wal" // This wont always be there + }; + } + foreach (var file in files.Select(f => (new FileInfo(f)).Name).ToList()) { _backupFiles.Add(file); @@ -54,7 +72,7 @@ namespace API.Services.Tasks var fi = new FileInfo(logFileName); var files = maxRollingFiles > 0 - ? _directoryService.GetFiles(_logDirectory, $@"{Path.GetFileNameWithoutExtension(fi.Name)}{multipleFileRegex}\.log") + ? DirectoryService.GetFiles(_logDirectory, $@"{Path.GetFileNameWithoutExtension(fi.Name)}{multipleFileRegex}\.log") : new[] {"kavita.log"}; return files; } @@ -129,6 +147,11 @@ namespace API.Services.Tasks { // Swallow exception. This can be a duplicate cover being copied as chapter and volumes can share same file. } + + if (!DirectoryService.GetFiles(outputTempDir).Any()) + { + DirectoryService.ClearAndDeleteDirectory(outputTempDir); + } } /// @@ -141,7 +164,7 @@ namespace API.Services.Tasks var backupDirectory = Task.Run(() => _unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.BackupDirectory)).Result.Value; if (!_directoryService.Exists(backupDirectory)) return; var deltaTime = DateTime.Today.Subtract(TimeSpan.FromDays(dayThreshold)); - var allBackups = _directoryService.GetFiles(backupDirectory).ToList(); + var allBackups = DirectoryService.GetFiles(backupDirectory).ToList(); var expiredBackups = allBackups.Select(filename => new FileInfo(filename)) .Where(f => f.CreationTime > deltaTime) .ToList(); diff --git a/API/Services/Tasks/CleanupService.cs b/API/Services/Tasks/CleanupService.cs index 93f8ec5db..a3c63c30f 100644 --- a/API/Services/Tasks/CleanupService.cs +++ b/API/Services/Tasks/CleanupService.cs @@ -16,16 +16,14 @@ namespace API.Services.Tasks private readonly ILogger _logger; private readonly IBackupService _backupService; private readonly IUnitOfWork _unitOfWork; - private readonly IDirectoryService _directoryService; public CleanupService(ICacheService cacheService, ILogger logger, - IBackupService backupService, IUnitOfWork unitOfWork, IDirectoryService directoryService) + IBackupService backupService, IUnitOfWork unitOfWork) { _cacheService = cacheService; _logger = logger; _backupService = backupService; _unitOfWork = unitOfWork; - _directoryService = directoryService; } public void CleanupCacheDirectory() @@ -42,7 +40,7 @@ namespace API.Services.Tasks { _logger.LogInformation("Starting Cleanup"); _logger.LogInformation("Cleaning temp directory"); - var tempDirectory = Path.Join(Directory.GetCurrentDirectory(), "temp"); + var tempDirectory = DirectoryService.TempDirectory; DirectoryService.ClearDirectory(tempDirectory); CleanupCacheDirectory(); _logger.LogInformation("Cleaning old database backups"); @@ -57,7 +55,7 @@ namespace API.Services.Tasks private async Task DeleteSeriesCoverImages() { var images = await _unitOfWork.SeriesRepository.GetAllCoverImagesAsync(); - var files = _directoryService.GetFiles(DirectoryService.CoverImageDirectory, ImageService.SeriesCoverImageRegex); + var files = DirectoryService.GetFiles(DirectoryService.CoverImageDirectory, ImageService.SeriesCoverImageRegex); foreach (var file in files) { if (images.Contains(Path.GetFileName(file))) continue; @@ -69,7 +67,7 @@ namespace API.Services.Tasks private async Task DeleteChapterCoverImages() { var images = await _unitOfWork.ChapterRepository.GetAllCoverImagesAsync(); - var files = _directoryService.GetFiles(DirectoryService.CoverImageDirectory, ImageService.ChapterCoverImageRegex); + var files = DirectoryService.GetFiles(DirectoryService.CoverImageDirectory, ImageService.ChapterCoverImageRegex); foreach (var file in files) { if (images.Contains(Path.GetFileName(file))) continue; @@ -81,7 +79,7 @@ namespace API.Services.Tasks private async Task DeleteTagCoverImages() { var images = await _unitOfWork.CollectionTagRepository.GetAllCoverImagesAsync(); - var files = _directoryService.GetFiles(DirectoryService.CoverImageDirectory, ImageService.CollectionTagCoverImageRegex); + var files = DirectoryService.GetFiles(DirectoryService.CoverImageDirectory, ImageService.CollectionTagCoverImageRegex); foreach (var file in files) { if (images.Contains(Path.GetFileName(file))) continue; diff --git a/API/Services/Tasks/Scanner/ParseScannedFiles.cs b/API/Services/Tasks/Scanner/ParseScannedFiles.cs index afcfc1c13..f88caab89 100644 --- a/API/Services/Tasks/Scanner/ParseScannedFiles.cs +++ b/API/Services/Tasks/Scanner/ParseScannedFiles.cs @@ -73,9 +73,13 @@ namespace API.Services.Tasks.Scanner info = Parser.Parser.Parse(path, rootPath, type); } + // If we couldn't match, log. But don't log if the file parses as a cover image if (info == null) { - _logger.LogWarning("[Scanner] Could not parse series from {Path}", path); + if (!(Parser.Parser.IsImage(path) && Parser.Parser.IsCoverImage(path))) + { + _logger.LogWarning("[Scanner] Could not parse series from {Path}", path); + } return; } @@ -133,13 +137,11 @@ namespace API.Services.Tasks.Scanner public string MergeName(ParserInfo info) { var normalizedSeries = Parser.Parser.Normalize(info.Series); - _logger.LogDebug("Checking if we can merge {NormalizedSeries}", normalizedSeries); var existingName = _scannedSeries.SingleOrDefault(p => Parser.Parser.Normalize(p.Key.NormalizedName) == normalizedSeries && p.Key.Format == info.Format) .Key; if (existingName != null && !string.IsNullOrEmpty(existingName.Name)) { - _logger.LogDebug("Found duplicate parsed infos, merged {Original} into {Merged}", info.Series, existingName.Name); return existingName.Name; } diff --git a/API/Services/Tasks/ScannerService.cs b/API/Services/Tasks/ScannerService.cs index 7f7986eb0..d82c9579c 100644 --- a/API/Services/Tasks/ScannerService.cs +++ b/API/Services/Tasks/ScannerService.cs @@ -261,13 +261,15 @@ namespace API.Services.Tasks var totalTime = 0L; // Update existing series - _logger.LogDebug("[ScannerService] Updating existing series"); + _logger.LogInformation("[ScannerService] Updating existing series for {LibraryName}. Total Items: {TotalSize}. Total Chunks: {TotalChunks} with {ChunkSize} size", + library.Name, chunkInfo.TotalSize, chunkInfo.TotalChunks, chunkInfo.ChunkSize); for (var chunk = 1; chunk <= chunkInfo.TotalChunks; chunk++) { if (chunkInfo.TotalChunks == 0) continue; totalTime += stopwatch.ElapsedMilliseconds; stopwatch.Restart(); - _logger.LogDebug($"[ScannerService] Processing chunk {chunk} / {chunkInfo.TotalChunks} with size {chunkInfo.ChunkSize} Series ({chunk * chunkInfo.ChunkSize} - {(chunk + 1) * chunkInfo.ChunkSize}"); + _logger.LogInformation("[ScannerService] Processing chunk {ChunkNumber} / {TotalChunks} with size {ChunkSize}. Series ({SeriesStart} - {SeriesEnd}", + chunk, chunkInfo.TotalChunks, chunkInfo.ChunkSize, chunk * chunkInfo.ChunkSize, (chunk + 1) * chunkInfo.ChunkSize); var nonLibrarySeries = await _unitOfWork.SeriesRepository.GetFullSeriesForLibraryIdAsync(library.Id, new UserParams() { PageNumber = chunk, @@ -299,7 +301,21 @@ namespace API.Services.Tasks UpdateSeries(series, parsedSeries); }); - await _unitOfWork.CommitAsync(); + try + { + await _unitOfWork.CommitAsync(); + } + catch (Exception ex) + { + _logger.LogCritical(ex, "[ScannerService] There was an issue writing to the DB. Chunk {ChunkNumber} did not save to DB. If debug mode, series to check will be printed", chunk); + foreach (var series in nonLibrarySeries) + { + _logger.LogDebug("[ScannerService] There may be a constraint issue with {SeriesName}", series.OriginalName); + } + await _messageHub.Clients.All.SendAsync(SignalREvents.ScanLibraryError, + MessageFactory.ScanLibraryError(library.Id)); + continue; + } _logger.LogInformation( "[ScannerService] Processed {SeriesStart} - {SeriesEnd} series in {ElapsedScanTime} milliseconds for {LibraryName}", chunk * chunkInfo.ChunkSize, (chunk * chunkInfo.ChunkSize) + nonLibrarySeries.Count, totalTime, library.Name); @@ -320,12 +336,14 @@ namespace API.Services.Tasks _logger.LogDebug("[ScannerService] Adding new series"); var newSeries = new List(); var allSeries = (await _unitOfWork.SeriesRepository.GetSeriesForLibraryIdAsync(library.Id)).ToList(); + _logger.LogDebug("[ScannerService] Fetched {AllSeriesCount} series for comparing new series with. There should be {DeltaToParsedSeries} new series", + allSeries.Count, parsedSeries.Count - allSeries.Count); foreach (var (key, infos) in parsedSeries) { // Key is normalized already Series existingSeries; try - { + {// NOTE: Maybe use .Equals() here existingSeries = allSeries.SingleOrDefault(s => (s.NormalizedName == key.NormalizedName || Parser.Parser.Normalize(s.OriginalName) == key.NormalizedName) && (s.Format == key.Format || s.Format == MangaFormat.Unknown)); @@ -386,7 +404,7 @@ namespace API.Services.Tasks } } - _logger.LogDebug( + _logger.LogInformation( "[ScannerService] Added {NewSeries} series in {ElapsedScanTime} milliseconds for {LibraryName}", newSeries.Count, stopwatch.ElapsedMilliseconds, library.Name); } diff --git a/API/Services/Tasks/StatsService.cs b/API/Services/Tasks/StatsService.cs index 47087fc8d..62393393e 100644 --- a/API/Services/Tasks/StatsService.cs +++ b/API/Services/Tasks/StatsService.cs @@ -1,6 +1,7 @@ using System; using System.IO; using System.Linq; +using System.Net.Http; using System.Runtime.InteropServices; using System.Text.Json; using System.Threading; @@ -9,9 +10,11 @@ using API.Data; using API.DTOs.Stats; using API.Interfaces; using API.Interfaces.Services; -using API.Services.Clients; +using Flurl.Http; +using Hangfire; using Kavita.Common; using Kavita.Common.EnvironmentInfo; +using Microsoft.AspNetCore.Http; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; @@ -19,32 +22,65 @@ namespace API.Services.Tasks { public class StatsService : IStatsService { - private const string TempFilePath = "stats/"; - private const string TempFileName = "app_stats.json"; + private const string StatFileName = "app_stats.json"; - private readonly StatsApiClient _client; private readonly DataContext _dbContext; private readonly ILogger _logger; private readonly IUnitOfWork _unitOfWork; - public StatsService(StatsApiClient client, DataContext dbContext, ILogger logger, +#pragma warning disable S1075 + private const string ApiUrl = "http://stats.kavitareader.com"; +#pragma warning restore S1075 + private static readonly string StatsFilePath = Path.Combine(DirectoryService.StatsDirectory, StatFileName); + + private static bool FileExists => File.Exists(StatsFilePath); + + public StatsService(DataContext dbContext, ILogger logger, IUnitOfWork unitOfWork) { - _client = client; _dbContext = dbContext; _logger = logger; _unitOfWork = unitOfWork; } - private static string FinalPath => Path.Combine(Directory.GetCurrentDirectory(), TempFilePath, TempFileName); - private static bool FileExists => File.Exists(FinalPath); - - public async Task PathData(ClientInfoDto clientInfoDto) + /// + /// Due to all instances firing this at the same time, we can DDOS our server. This task when fired will schedule the task to be run + /// randomly over a 6 hour spread + /// + public async Task Send() { - _logger.LogDebug("Pathing client data to the file"); + var allowStatCollection = (await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).AllowStatCollection; + if (!allowStatCollection) + { + return; + } + var rnd = new Random(); + var offset = rnd.Next(0, 6); + if (offset == 0) + { + await SendData(); + } + else + { + _logger.LogInformation("KavitaStats upload has been schedule to run in {Offset} hours", offset); + BackgroundJob.Schedule(() => SendData(), DateTimeOffset.Now.AddHours(offset)); + } + } + + /// + /// This must be public for Hangfire. Do not call this directly. + /// + // ReSharper disable once MemberCanBePrivate.Global + public async Task SendData() + { + await CollectRelevantData(); + await FinalizeStats(); + } + + public async Task RecordClientInfo(ClientInfoDto clientInfoDto) + { var statisticsDto = await GetData(); - statisticsDto.AddClientInfo(clientInfoDto); await SaveFile(statisticsDto); @@ -52,12 +88,7 @@ namespace API.Services.Tasks private async Task CollectRelevantData() { - _logger.LogDebug("Collecting data from the server and database"); - - _logger.LogDebug("Collecting usage info"); var usageInfo = await GetUsageInfo(); - - _logger.LogDebug("Collecting server info"); var serverInfo = GetServerInfo(); await PathData(serverInfo, usageInfo); @@ -67,39 +98,68 @@ namespace API.Services.Tasks { try { - _logger.LogDebug("Finalizing Stats collection flow"); - var data = await GetExistingData(); + var successful = await SendDataToStatsServer(data); - _logger.LogDebug("Sending data to the Stats server"); - await _client.SendDataToStatsServer(data); - - _logger.LogDebug("Deleting the file from disk"); - if (FileExists) File.Delete(FinalPath); + if (successful) + { + ResetStats(); + } } catch (Exception ex) { - _logger.LogError(ex, "Error Finalizing Stats collection flow"); - throw; + _logger.LogError(ex, "There was an exception while sending data to KavitaStats"); } } - public async Task CollectAndSendStatsData() + private async Task SendDataToStatsServer(UsageStatisticsDto data) { - var allowStatCollection = (await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).AllowStatCollection; - if (!allowStatCollection) + var responseContent = string.Empty; + + try { - _logger.LogDebug("User has opted out of stat collection, not registering tasks"); - return; + var response = await (ApiUrl + "/api/InstallationStats") + .WithHeader("Accept", "application/json") + .WithHeader("User-Agent", "Kavita") + .WithHeader("x-api-key", "MsnvA2DfQqxSK5jh") + .WithHeader("api-key", "MsnvA2DfQqxSK5jh") + .WithHeader("x-kavita-version", BuildInfo.Version) + .WithTimeout(TimeSpan.FromSeconds(30)) + .PostJsonAsync(data); + + if (response.StatusCode != StatusCodes.Status200OK) + { + _logger.LogError("KavitaStats did not respond successfully. {Content}", response); + return false; + } + + return true; } - await CollectRelevantData(); - await FinalizeStats(); + catch (HttpRequestException e) + { + var info = new + { + dataSent = data, + response = responseContent + }; + + _logger.LogError(e, "KavitaStats did not respond successfully. {Content}", info); + } + catch (Exception e) + { + _logger.LogError(e, "An error happened during the request to KavitaStats"); + } + + return false; + } + + private static void ResetStats() + { + if (FileExists) File.Delete(StatsFilePath); } private async Task PathData(ServerInfoDto serverInfoDto, UsageInfoDto usageInfoDto) { - _logger.LogDebug("Pathing server and usage info to the file"); - var data = await GetData(); data.ServerInfo = serverInfoDto; @@ -110,7 +170,7 @@ namespace API.Services.Tasks await SaveFile(data); } - private async ValueTask GetData() + private static async ValueTask GetData() { if (!FileExists) return new UsageStatisticsDto {InstallId = HashUtil.AnonymousToken()}; @@ -156,39 +216,17 @@ namespace API.Services.Tasks return serverInfo; } - private async Task GetExistingData() + private static async Task GetExistingData() { - _logger.LogInformation("Fetching existing data from file"); - var existingDataJson = await GetFileDataAsString(); - - _logger.LogInformation("Deserializing data from file to object"); - var existingData = JsonSerializer.Deserialize(existingDataJson); - - return existingData; + var json = await File.ReadAllTextAsync(StatsFilePath); + return JsonSerializer.Deserialize(json); } - private async Task GetFileDataAsString() + private static async Task SaveFile(UsageStatisticsDto statisticsDto) { - _logger.LogInformation("Reading file from disk"); - return await File.ReadAllTextAsync(FinalPath); - } + DirectoryService.ExistOrCreate(DirectoryService.StatsDirectory); - private async Task SaveFile(UsageStatisticsDto statisticsDto) - { - _logger.LogDebug("Saving file"); - - var finalDirectory = FinalPath.Replace(TempFileName, string.Empty); - if (!Directory.Exists(finalDirectory)) - { - _logger.LogDebug("Creating tmp directory"); - Directory.CreateDirectory(finalDirectory); - } - - _logger.LogDebug("Serializing data to write"); - var dataJson = JsonSerializer.Serialize(statisticsDto); - - _logger.LogDebug("Writing file to the disk"); - await File.WriteAllTextAsync(FinalPath, dataJson); + await File.WriteAllTextAsync(StatsFilePath, JsonSerializer.Serialize(statisticsDto)); } } } diff --git a/API/SignalR/MessageFactory.cs b/API/SignalR/MessageFactory.cs index 19fd66f55..0bab0b4da 100644 --- a/API/SignalR/MessageFactory.cs +++ b/API/SignalR/MessageFactory.cs @@ -96,5 +96,17 @@ namespace API.SignalR } }; } + + public static SignalRMessage ScanLibraryError(int libraryId) + { + return new SignalRMessage + { + Name = SignalREvents.ScanLibraryError, + Body = new + { + LibraryId = libraryId, + } + }; + } } } diff --git a/API/SignalR/Presence/PresenceTracker.cs b/API/SignalR/Presence/PresenceTracker.cs index ac9bb28d1..1453bd0f7 100644 --- a/API/SignalR/Presence/PresenceTracker.cs +++ b/API/SignalR/Presence/PresenceTracker.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using API.Interfaces; @@ -27,7 +28,7 @@ namespace API.SignalR.Presence _unitOfWork = unitOfWork; } - public Task UserConnected(string username, string connectionId) + public async Task UserConnected(string username, string connectionId) { lock (OnlineUsers) { @@ -41,7 +42,10 @@ namespace API.SignalR.Presence } } - return Task.CompletedTask; + // Update the last active for the user + var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(username); + user.LastActive = DateTime.Now; + await _unitOfWork.CommitAsync(); } public Task UserDisconnected(string username, string connectionId) diff --git a/API/SignalR/SignalREvents.cs b/API/SignalR/SignalREvents.cs index d0ce5102e..0f97ad493 100644 --- a/API/SignalR/SignalREvents.cs +++ b/API/SignalR/SignalREvents.cs @@ -11,5 +11,6 @@ public const string ScanLibraryProgress = "ScanLibraryProgress"; public const string OnlineUsers = "OnlineUsers"; public const string SeriesAddedToCollection = "SeriesAddedToCollection"; + public const string ScanLibraryError = "ScanLibraryError"; } } diff --git a/API/Startup.cs b/API/Startup.cs index e04d61279..6668927b4 100644 --- a/API/Startup.cs +++ b/API/Startup.cs @@ -24,6 +24,7 @@ using Microsoft.AspNetCore.StaticFiles; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; using Microsoft.OpenApi.Models; namespace API @@ -106,7 +107,11 @@ namespace API services.AddResponseCaching(); - services.AddStatsClient(_config); + services.Configure(options => + { + options.ForwardedHeaders = + ForwardedHeaders.All; + }); services.AddHangfire(configuration => configuration .UseSimpleAssemblyNameTypeSerializer() @@ -139,7 +144,10 @@ namespace API app.UseResponseCompression(); - app.UseForwardedHeaders(); + app.UseForwardedHeaders(new ForwardedHeadersOptions + { + ForwardedHeaders = ForwardedHeaders.All + }); app.UseRouting(); @@ -210,6 +218,15 @@ namespace API applicationLifetime.ApplicationStopping.Register(OnShutdown); applicationLifetime.ApplicationStarted.Register(() => { + try + { + var logger = serviceProvider.GetRequiredService>(); + logger.LogInformation("Kavita - v{Version}", BuildInfo.Version); + } + catch (Exception) + { + /* Swallow Exception */ + } Console.WriteLine($"Kavita - v{BuildInfo.Version}"); }); } diff --git a/API/appsettings.Development.json b/API/config/appsettings.Development.json similarity index 65% rename from API/appsettings.Development.json rename to API/config/appsettings.Development.json index b5dc22df1..ac1707592 100644 --- a/API/appsettings.Development.json +++ b/API/config/appsettings.Development.json @@ -1,21 +1,21 @@ { "ConnectionStrings": { - "DefaultConnection": "Data source=kavita.db" + "DefaultConnection": "Data source=config//kavita.db" }, "TokenKey": "super secret unguessable key", "Logging": { "LogLevel": { - "Default": "Debug", + "Default": "Information", "Microsoft": "Information", "Microsoft.Hosting.Lifetime": "Error", "Hangfire": "Information", "Microsoft.AspNetCore.Hosting.Internal.WebHost": "Information" }, "File": { - "Path": "logs/kavita.log", + "Path": "config//logs/kavita.log", "Append": "True", - "FileSizeLimitBytes": 10485760, - "MaxRollingFiles": 5 + "FileSizeLimitBytes": 26214400, + "MaxRollingFiles": 2 } }, "Port": 5000 diff --git a/Dockerfile b/Dockerfile index a1d36ee56..82fd49132 100644 --- a/Dockerfile +++ b/Dockerfile @@ -20,19 +20,14 @@ COPY --from=copytask /files/wwwroot /kavita/wwwroot #Installs program dependencies RUN apt-get update \ - && apt-get install -y libicu-dev libssl1.1 pwgen libgdiplus \ + && apt-get install -y libicu-dev libssl1.1 libgdiplus \ && rm -rf /var/lib/apt/lists/* -#Creates the data directory -RUN mkdir /kavita/data - -RUN sed -i 's/Data source=kavita.db/Data source=data\/kavita.db/g' /kavita/appsettings.json - COPY entrypoint.sh /entrypoint.sh EXPOSE 5000 WORKDIR /kavita -ENTRYPOINT ["/bin/bash"] +ENTRYPOINT [ "/bin/bash" ] CMD ["/entrypoint.sh"] diff --git a/INSTALL.txt b/INSTALL.txt index a7d2bd1bc..9119da82c 100644 --- a/INSTALL.txt +++ b/INSTALL.txt @@ -2,4 +2,6 @@ 1. Unzip the archive to a directory that is writable. If on windows, do not place in Program Files. 2. (Linux only) Chmod and Chown so Kavita can write to the directory you placed in. 3. Run Kavita executable. -4. Open localhost:5000 and setup your account and libraries in the UI. \ No newline at end of file +4. Open localhost:5000 and setup your account and libraries in the UI. + +If updating, copy everything but the config/ directory over. Restart Kavita. diff --git a/Kavita.Common/AppSettingsConfig.cs b/Kavita.Common/AppSettingsConfig.cs new file mode 100644 index 000000000..c7718b230 --- /dev/null +++ b/Kavita.Common/AppSettingsConfig.cs @@ -0,0 +1,7 @@ +namespace Kavita.Common +{ + public class AppSettingsConfig + { + + } +} diff --git a/Kavita.Common/Configuration.cs b/Kavita.Common/Configuration.cs index c2967c883..6e6899f3f 100644 --- a/Kavita.Common/Configuration.cs +++ b/Kavita.Common/Configuration.cs @@ -6,236 +6,349 @@ using Microsoft.Extensions.Hosting; namespace Kavita.Common { - public static class Configuration - { - private static readonly string AppSettingsFilename = GetAppSettingFilename(); - public static string Branch - { - get => GetBranch(GetAppSettingFilename()); - set => SetBranch(GetAppSettingFilename(), value); - } + public static class Configuration + { + public static readonly string AppSettingsFilename = Path.Join("config", GetAppSettingFilename()); - public static int Port - { - get => GetPort(GetAppSettingFilename()); - set => SetPort(GetAppSettingFilename(), value); - } + public static string Branch + { + get => GetBranch(GetAppSettingFilename()); + set => SetBranch(GetAppSettingFilename(), value); + } - public static string JwtToken - { - get => GetJwtToken(GetAppSettingFilename()); - set => SetJwtToken(GetAppSettingFilename(), value); - } + public static int Port + { + get => GetPort(GetAppSettingFilename()); + set => SetPort(GetAppSettingFilename(), value); + } - public static string LogLevel - { - get => GetLogLevel(GetAppSettingFilename()); - set => SetLogLevel(GetAppSettingFilename(), value); - } + public static string JwtToken + { + get => GetJwtToken(GetAppSettingFilename()); + set => SetJwtToken(GetAppSettingFilename(), value); + } - private static string GetAppSettingFilename() - { - if (!string.IsNullOrEmpty(AppSettingsFilename)) - { - return AppSettingsFilename; - } - var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT"); - var isDevelopment = environment == Environments.Development; - return "appsettings" + (isDevelopment ? ".Development" : "") + ".json"; - } + public static string LogLevel + { + get => GetLogLevel(GetAppSettingFilename()); + set => SetLogLevel(GetAppSettingFilename(), value); + } - #region JWT Token + public static string LogPath + { + get => GetLoggingFile(GetAppSettingFilename()); + set => SetLoggingFile(GetAppSettingFilename(), value); + } - private static string GetJwtToken(string filePath) - { - try - { - var json = File.ReadAllText(filePath); - var jsonObj = JsonSerializer.Deserialize(json); - const string key = "TokenKey"; + public static string DatabasePath + { + get => GetDatabasePath(GetAppSettingFilename()); + set => SetDatabasePath(GetAppSettingFilename(), value); + } - if (jsonObj.TryGetProperty(key, out JsonElement tokenElement)) + private static string GetAppSettingFilename() + { + if (!string.IsNullOrEmpty(AppSettingsFilename)) { - return tokenElement.GetString(); + return AppSettingsFilename; + } + + var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT"); + var isDevelopment = environment == Environments.Development; + return "appsettings" + (isDevelopment ? ".Development" : string.Empty) + ".json"; + } + + #region JWT Token + + private static string GetJwtToken(string filePath) + { + try + { + var json = File.ReadAllText(filePath); + var jsonObj = JsonSerializer.Deserialize(json); + const string key = "TokenKey"; + + if (jsonObj.TryGetProperty(key, out JsonElement tokenElement)) + { + return tokenElement.GetString(); + } + + return string.Empty; + } + catch (Exception ex) + { + Console.WriteLine("Error reading app settings: " + ex.Message); } return string.Empty; - } - catch (Exception ex) - { - Console.WriteLine("Error reading app settings: " + ex.Message); - } + } - return string.Empty; - } + private static void SetJwtToken(string filePath, string token) + { + try + { + var currentToken = GetJwtToken(filePath); + var json = File.ReadAllText(filePath) + .Replace("\"TokenKey\": \"" + currentToken, "\"TokenKey\": \"" + token); + File.WriteAllText(filePath, json); + } + catch (Exception) + { + /* Swallow exception */ + } + } - private static void SetJwtToken(string filePath, string token) - { - try - { - var currentToken = GetJwtToken(filePath); - var json = File.ReadAllText(filePath) - .Replace("\"TokenKey\": \"" + currentToken, "\"TokenKey\": \"" + token); - File.WriteAllText(filePath, json); - } - catch (Exception) - { - /* Swallow exception */ - } - } + public static bool CheckIfJwtTokenSet() + { + try + { + return GetJwtToken(GetAppSettingFilename()) != "super secret unguessable key"; + } + catch (Exception ex) + { + Console.WriteLine("Error writing app settings: " + ex.Message); + } - public static bool CheckIfJwtTokenSet() - { - try - { - return GetJwtToken(GetAppSettingFilename()) != "super secret unguessable key"; - } - catch (Exception ex) - { - Console.WriteLine("Error writing app settings: " + ex.Message); - } + return false; + } - return false; - } + #endregion + #region Port - #endregion + private static void SetPort(string filePath, int port) + { + if (new OsInfo(Array.Empty()).IsDocker) + { + return; + } - #region Port + try + { + var currentPort = GetPort(filePath); + var json = File.ReadAllText(filePath).Replace("\"Port\": " + currentPort, "\"Port\": " + port); + File.WriteAllText(filePath, json); + } + catch (Exception) + { + /* Swallow Exception */ + } + } - private static void SetPort(string filePath, int port) - { - if (new OsInfo(Array.Empty()).IsDocker) - { - return; - } + private static int GetPort(string filePath) + { + const int defaultPort = 5000; + if (new OsInfo(Array.Empty()).IsDocker) + { + return defaultPort; + } - try - { - var currentPort = GetPort(filePath); - var json = File.ReadAllText(filePath).Replace("\"Port\": " + currentPort, "\"Port\": " + port); - File.WriteAllText(filePath, json); - } - catch (Exception) - { - /* Swallow Exception */ - } - } + try + { + var json = File.ReadAllText(filePath); + var jsonObj = JsonSerializer.Deserialize(json); + const string key = "Port"; + + if (jsonObj.TryGetProperty(key, out JsonElement tokenElement)) + { + return tokenElement.GetInt32(); + } + } + catch (Exception ex) + { + Console.WriteLine("Error writing app settings: " + ex.Message); + } - private static int GetPort(string filePath) - { - const int defaultPort = 5000; - if (new OsInfo(Array.Empty()).IsDocker) - { return defaultPort; - } + } - try - { - var json = File.ReadAllText(filePath); - var jsonObj = JsonSerializer.Deserialize(json); - const string key = "Port"; + #endregion - if (jsonObj.TryGetProperty(key, out JsonElement tokenElement)) + #region LogLevel + + private static void SetLogLevel(string filePath, string logLevel) + { + try { - return tokenElement.GetInt32(); + var currentLevel = GetLogLevel(filePath); + var json = File.ReadAllText(filePath) + .Replace($"\"Default\": \"{currentLevel}\"", $"\"Default\": \"{logLevel}\""); + File.WriteAllText(filePath, json); } - } - catch (Exception ex) - { - Console.WriteLine("Error writing app settings: " + ex.Message); - } - - return defaultPort; - } - - #endregion - - #region LogLevel - - private static void SetLogLevel(string filePath, string logLevel) - { - try - { - var currentLevel = GetLogLevel(filePath); - var json = File.ReadAllText(filePath) - .Replace($"\"Default\": \"{currentLevel}\"", $"\"Default\": \"{logLevel}\""); - File.WriteAllText(filePath, json); - } - catch (Exception) - { - /* Swallow Exception */ - } - } - - private static string GetLogLevel(string filePath) - { - try - { - var json = File.ReadAllText(filePath); - var jsonObj = JsonSerializer.Deserialize(json); - - if (jsonObj.TryGetProperty("Logging", out JsonElement tokenElement)) + catch (Exception) { - foreach (var property in tokenElement.EnumerateObject()) - { - if (!property.Name.Equals("LogLevel")) continue; - foreach (var logProperty in property.Value.EnumerateObject()) - { - if (logProperty.Name.Equals("Default")) - { - return logProperty.Value.GetString(); - } - } - } + /* Swallow Exception */ } - } - catch (Exception ex) - { - Console.WriteLine("Error writing app settings: " + ex.Message); - } + } - return "Information"; - } - - #endregion - - private static string GetBranch(string filePath) - { - const string defaultBranch = "main"; - - try - { - var json = File.ReadAllText(filePath); - var jsonObj = JsonSerializer.Deserialize(json); - const string key = "Branch"; - - if (jsonObj.TryGetProperty(key, out JsonElement tokenElement)) + private static string GetLogLevel(string filePath) + { + try { - return tokenElement.GetString(); + var json = File.ReadAllText(filePath); + var jsonObj = JsonSerializer.Deserialize(json); + + if (jsonObj.TryGetProperty("Logging", out JsonElement tokenElement)) + { + foreach (var property in tokenElement.EnumerateObject()) + { + if (!property.Name.Equals("LogLevel")) continue; + foreach (var logProperty in property.Value.EnumerateObject()) + { + if (logProperty.Name.Equals("Default")) + { + return logProperty.Value.GetString(); + } + } + } + } + } + catch (Exception ex) + { + Console.WriteLine("Error writing app settings: " + ex.Message); } - } - catch (Exception ex) - { - Console.WriteLine("Error reading app settings: " + ex.Message); - } - return defaultBranch; - } + return "Information"; + } - private static void SetBranch(string filePath, string updatedBranch) - { - try - { - var currentBranch = GetBranch(filePath); - var json = File.ReadAllText(filePath) - .Replace("\"Branch\": " + currentBranch, "\"Branch\": " + updatedBranch); - File.WriteAllText(filePath, json); - } - catch (Exception) - { - /* Swallow Exception */ - } - } - } + #endregion + + private static string GetBranch(string filePath) + { + const string defaultBranch = "main"; + + try + { + var json = File.ReadAllText(filePath); + var jsonObj = JsonSerializer.Deserialize(json); + const string key = "Branch"; + + if (jsonObj.TryGetProperty(key, out JsonElement tokenElement)) + { + return tokenElement.GetString(); + } + } + catch (Exception ex) + { + Console.WriteLine("Error reading app settings: " + ex.Message); + } + + return defaultBranch; + } + + private static void SetBranch(string filePath, string updatedBranch) + { + try + { + var currentBranch = GetBranch(filePath); + var json = File.ReadAllText(filePath) + .Replace("\"Branch\": " + currentBranch, "\"Branch\": " + updatedBranch); + File.WriteAllText(filePath, json); + } + catch (Exception) + { + /* Swallow Exception */ + } + } + + private static string GetLoggingFile(string filePath) + { + const string defaultFile = "config/logs/kavita.log"; + + try + { + var json = File.ReadAllText(filePath); + var jsonObj = JsonSerializer.Deserialize(json); + + if (jsonObj.TryGetProperty("Logging", out JsonElement tokenElement)) + { + foreach (var property in tokenElement.EnumerateObject()) + { + if (!property.Name.Equals("File")) continue; + foreach (var logProperty in property.Value.EnumerateObject()) + { + if (logProperty.Name.Equals("Path")) + { + return logProperty.Value.GetString(); + } + } + } + } + } + catch (Exception ex) + { + Console.WriteLine("Error writing app settings: " + ex.Message); + } + + return defaultFile; + } + + /// + /// This should NEVER be called except by + /// + /// + /// + private static void SetLoggingFile(string filePath, string directory) + { + try + { + var currentFile = GetLoggingFile(filePath); + var json = File.ReadAllText(filePath) + .Replace("\"Path\": \"" + currentFile + "\"", "\"Path\": \"" + directory + "\""); + File.WriteAllText(filePath, json); + } + catch (Exception ex) + { + /* Swallow Exception */ + Console.WriteLine(ex); + } + } + + private static string GetDatabasePath(string filePath) + { + const string defaultFile = "config/kavita.db"; + + try + { + var json = File.ReadAllText(filePath); + var jsonObj = JsonSerializer.Deserialize(json); + + if (jsonObj.TryGetProperty("ConnectionStrings", out JsonElement tokenElement)) + { + foreach (var property in tokenElement.EnumerateObject()) + { + if (!property.Name.Equals("DefaultConnection")) continue; + return property.Value.GetString(); + } + } + } + catch (Exception ex) + { + Console.WriteLine("Error writing app settings: " + ex.Message); + } + + return defaultFile; + } + + /// + /// This should NEVER be called except by + /// + /// + /// + private static void SetDatabasePath(string filePath, string updatedPath) + { + try + { + var existingString = GetDatabasePath(filePath); + var json = File.ReadAllText(filePath) + .Replace(existingString, + "Data source=" + updatedPath); + File.WriteAllText(filePath, json); + } + catch (Exception) + { + /* Swallow Exception */ + } + } + } } diff --git a/Kavita.Common/EnvironmentInfo/IOsInfo.cs b/Kavita.Common/EnvironmentInfo/IOsInfo.cs index f93e4781c..d90be9489 100644 --- a/Kavita.Common/EnvironmentInfo/IOsInfo.cs +++ b/Kavita.Common/EnvironmentInfo/IOsInfo.cs @@ -41,12 +41,13 @@ namespace Kavita.Common.EnvironmentInfo break; } } + } public OsInfo(IEnumerable versionAdapters) { OsVersionModel osInfo = null; - + foreach (var osVersionAdapter in versionAdapters.Where(c => c.Enabled)) { try @@ -57,13 +58,13 @@ namespace Kavita.Common.EnvironmentInfo { Console.WriteLine("Couldn't get OS Version info: " + e.Message); } - + if (osInfo != null) { break; } } - + if (osInfo != null) { Name = osInfo.Name; @@ -75,7 +76,7 @@ namespace Kavita.Common.EnvironmentInfo Name = Os.ToString(); FullName = Name; } - + if (IsLinux && File.Exists("/proc/1/cgroup") && File.ReadAllText("/proc/1/cgroup").Contains("/docker/")) { IsDocker = true; @@ -145,4 +146,4 @@ namespace Kavita.Common.EnvironmentInfo LinuxMusl, Bsd } -} \ No newline at end of file +} diff --git a/Kavita.Common/Kavita.Common.csproj b/Kavita.Common/Kavita.Common.csproj index 26ca78d92..dbcc50701 100644 --- a/Kavita.Common/Kavita.Common.csproj +++ b/Kavita.Common/Kavita.Common.csproj @@ -4,7 +4,7 @@ net5.0 kavitareader.com Kavita - 0.4.7.0 + 0.4.8.1 en diff --git a/Kavita.sln.DotSettings b/Kavita.sln.DotSettings index 322251617..add1b3a35 100644 --- a/Kavita.sln.DotSettings +++ b/Kavita.sln.DotSettings @@ -2,4 +2,5 @@ ExplicitlyExcluded True True - True \ No newline at end of file + True + True \ No newline at end of file diff --git a/README.md b/README.md index 0cccdd53b..0bf98f2c8 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ Password: Demouser64 - Place in a directory that is writable. If on windows, do not place in Program Files - Linux users must ensure the directory & kavita.db is writable by Kavita (might require starting server once) - Run Kavita -- If you are updating, do not copy appsettings.json from the new version over. It will override your TokenKey and you will have to reauthenticate on your devices. +- If you are updating, copy everything over into install location. All Kavita data is stored in config/, so nothing will be overwritten. - Open localhost:5000 and setup your account and libraries in the UI. ### Docker Running your Kavita server in docker is super easy! Barely an inconvenience. You can run it with this command: @@ -56,7 +56,7 @@ Running your Kavita server in docker is super easy! Barely an inconvenience. You ``` docker run --name kavita -p 5000:5000 \ -v /your/manga/directory:/manga \ --v /kavita/data/directory:/kavita/data \ +-v /kavita/data/directory:/kavita/config \ --restart unless-stopped \ -d kizaing/kavita:latest ``` @@ -64,19 +64,20 @@ docker run --name kavita -p 5000:5000 \ You can also run it via the docker-compose file: ``` -version: '3.9' +version: '3' services: kavita: image: kizaing/kavita:latest + container_name: kavita volumes: - ./manga:/manga - - ./data:/kavita/data + - ./config:/kavita/config ports: - "5000:5000" restart: unless-stopped ``` -**Note: Kavita is under heavy development and is being updated all the time, so the tag for current builds is `:nightly`. The `:latest` tag will be the latest stable release. There is also the `:alpine` tag if you want a smaller image, but it is only available for x64 systems.** +**Note: Kavita is under heavy development and is being updated all the time, so the tag for current builds is `:nightly`. The `:latest` tag will be the latest stable release.** ## Feature Requests Got a great idea? Throw it up on the FeatHub or vote on another idea. Please check the [Project Board](https://github.com/Kareadita/Kavita/projects) first for a list of planned features. diff --git a/UI/Web/src/app/_interceptors/error.interceptor.ts b/UI/Web/src/app/_interceptors/error.interceptor.ts index 20c48fd8a..575ed21d6 100644 --- a/UI/Web/src/app/_interceptors/error.interceptor.ts +++ b/UI/Web/src/app/_interceptors/error.interceptor.ts @@ -111,11 +111,7 @@ export class ErrorInterceptor implements HttpInterceptor { // NOTE: Signin has error.error or error.statusText available. // if statement is due to http/2 spec issue: https://github.com/angular/angular/issues/23334 this.accountService.currentUser$.pipe(take(1)).subscribe(user => { - if (user) { - this.toastr.error(error.statusText === 'OK' ? 'Unauthorized' : error.statusText, error.status); - } this.accountService.logout(); }); - } } diff --git a/UI/Web/src/app/_models/search-result.ts b/UI/Web/src/app/_models/search-result.ts index 96619cc0f..3026c96c3 100644 --- a/UI/Web/src/app/_models/search-result.ts +++ b/UI/Web/src/app/_models/search-result.ts @@ -6,7 +6,7 @@ export interface SearchResult { libraryName: string; name: string; originalName: string; + localizedName: string; sortName: string; - coverImage: string; // byte64 encoded (not used) format: MangaFormat; } diff --git a/UI/Web/src/app/_services/action-factory.service.ts b/UI/Web/src/app/_services/action-factory.service.ts index 450b577bc..0df929e8f 100644 --- a/UI/Web/src/app/_services/action-factory.service.ts +++ b/UI/Web/src/app/_services/action-factory.service.ts @@ -19,7 +19,8 @@ export enum Action { Download = 7, Bookmarks = 8, IncognitoRead = 9, - AddToReadingList = 10 + AddToReadingList = 10, + AddToCollection = 11 } export interface ActionItem { @@ -90,6 +91,13 @@ export class ActionFactoryService { requiresAdmin: true }); + this.seriesActions.push({ + action: Action.AddToCollection, + title: 'Add to Collection', + callback: this.dummyCallback, + requiresAdmin: true + }); + this.seriesActions.push({ action: Action.Edit, title: 'Edit', @@ -209,7 +217,7 @@ export class ActionFactoryService { title: 'Add to Reading List', callback: this.dummyCallback, requiresAdmin: false - }, + } ]; this.volumeActions = [ diff --git a/UI/Web/src/app/_services/action.service.ts b/UI/Web/src/app/_services/action.service.ts index 3d654108f..5ada05dc2 100644 --- a/UI/Web/src/app/_services/action.service.ts +++ b/UI/Web/src/app/_services/action.service.ts @@ -4,6 +4,7 @@ import { ToastrService } from 'ngx-toastr'; import { Subject } from 'rxjs'; import { take } from 'rxjs/operators'; import { BookmarksModalComponent } from '../cards/_modals/bookmarks-modal/bookmarks-modal.component'; +import { BulkAddToCollectionComponent } from '../cards/_modals/bulk-add-to-collection/bulk-add-to-collection.component'; import { AddToListModalComponent, ADD_FLOW } from '../reading-list/_modals/add-to-list-modal/add-to-list-modal.component'; import { EditReadingListModalComponent } from '../reading-list/_modals/edit-reading-list-modal/edit-reading-list-modal.component'; import { ConfirmService } from '../shared/confirm.service'; @@ -34,6 +35,7 @@ export class ActionService implements OnDestroy { private readonly onDestroy = new Subject(); private bookmarkModalRef: NgbModalRef | null = null; private readingListModalRef: NgbModalRef | null = null; + private collectionModalRef: NgbModalRef | null = null; constructor(private libraryService: LibraryService, private seriesService: SeriesService, private readerService: ReaderService, private toastr: ToastrService, private modalService: NgbModal, @@ -358,6 +360,32 @@ export class ActionService implements OnDestroy { }); } + /** + * Adds a set of series to a collection tag + * @param series + * @param callback + * @returns + */ + addMultipleSeriesToCollectionTag(series: Array, callback?: VoidActionCallback) { + if (this.collectionModalRef != null) { return; } + this.collectionModalRef = this.modalService.open(BulkAddToCollectionComponent, { scrollable: true, size: 'md' }); + this.collectionModalRef.componentInstance.seriesIds = series.map(v => v.id); + this.collectionModalRef.componentInstance.title = 'New Collection'; + + this.collectionModalRef.closed.pipe(take(1)).subscribe(() => { + this.collectionModalRef = null; + if (callback) { + callback(); + } + }); + this.collectionModalRef.dismissed.pipe(take(1)).subscribe(() => { + this.collectionModalRef = null; + if (callback) { + callback(); + } + }); + } + addSeriesToReadingList(series: Series, callback?: SeriesActionCallback) { if (this.readingListModalRef != null) { return; } this.readingListModalRef = this.modalService.open(AddToListModalComponent, { scrollable: true, size: 'md' }); @@ -439,4 +467,21 @@ export class ActionService implements OnDestroy { }); } + /** + * Mark all chapters and the volumes as Read. All volumes and chapters must belong to a series + * @param seriesId Series Id + * @param volumes Volumes, should have id, chapters and pagesRead populated + * @param chapters? Chapters, should have id + * @param callback Optional callback to perform actions after API completes + */ + deleteMultipleSeries(seriesIds: Array, callback?: VoidActionCallback) { + this.seriesService.deleteMultipleSeries(seriesIds.map(s => s.id)).pipe(take(1)).subscribe(() => { + this.toastr.success('Series deleted'); + + if (callback) { + callback(); + } + }); + } + } diff --git a/UI/Web/src/app/_services/collection-tag.service.ts b/UI/Web/src/app/_services/collection-tag.service.ts index 87d275f43..dd8571b6a 100644 --- a/UI/Web/src/app/_services/collection-tag.service.ts +++ b/UI/Web/src/app/_services/collection-tag.service.ts @@ -35,4 +35,8 @@ export class CollectionTagService { updateSeriesForTag(tag: CollectionTag, seriesIdsToRemove: Array) { return this.httpClient.post(this.baseUrl + 'collection/update-series', {tag, seriesIdsToRemove}, {responseType: 'text' as 'json'}); } + + addByMultiple(tagId: number, seriesIds: Array, tagTitle: string = '') { + return this.httpClient.post(this.baseUrl + 'collection/update-for-series', {collectionTagId: tagId, collectionTagTitle: tagTitle, seriesIds}, {responseType: 'text' as 'json'}); + } } diff --git a/UI/Web/src/app/_services/message-hub.service.ts b/UI/Web/src/app/_services/message-hub.service.ts index dc7490d74..c058e1596 100644 --- a/UI/Web/src/app/_services/message-hub.service.ts +++ b/UI/Web/src/app/_services/message-hub.service.ts @@ -18,7 +18,8 @@ export enum EVENTS { SeriesAdded = 'SeriesAdded', ScanLibraryProgress = 'ScanLibraryProgress', OnlineUsers = 'OnlineUsers', - SeriesAddedToCollection = 'SeriesAddedToCollection' + SeriesAddedToCollection = 'SeriesAddedToCollection', + ScanLibraryError = 'ScanLibraryError' } export interface Message { @@ -93,6 +94,16 @@ export class MessageHubService { }); }); + this.hubConnection.on(EVENTS.ScanLibraryError, resp => { + this.messagesSource.next({ + event: EVENTS.ScanLibraryError, + payload: resp.body + }); + if (this.isAdmin) { + this.toastr.error('Library Scan had a critical error. Some series were not saved. Check logs'); + } + }); + this.hubConnection.on(EVENTS.SeriesAdded, resp => { this.messagesSource.next({ event: EVENTS.SeriesAdded, diff --git a/UI/Web/src/app/_services/series.service.ts b/UI/Web/src/app/_services/series.service.ts index 1975fe49b..6d3693558 100644 --- a/UI/Web/src/app/_services/series.service.ts +++ b/UI/Web/src/app/_services/series.service.ts @@ -80,6 +80,10 @@ export class SeriesService { return this.httpClient.delete(this.baseUrl + 'series/' + seriesId); } + deleteMultipleSeries(seriesIds: Array) { + return this.httpClient.post(this.baseUrl + 'series/delete-multiple', {seriesIds}); + } + updateRating(seriesId: number, userRating: number, userReview: string) { return this.httpClient.post(this.baseUrl + 'series/update-rating', {seriesId, userRating, userReview}); } diff --git a/UI/Web/src/app/admin/manage-settings/manage-settings.component.ts b/UI/Web/src/app/admin/manage-settings/manage-settings.component.ts index c05464695..94509776a 100644 --- a/UI/Web/src/app/admin/manage-settings/manage-settings.component.ts +++ b/UI/Web/src/app/admin/manage-settings/manage-settings.component.ts @@ -56,13 +56,13 @@ export class ManageSettingsComponent implements OnInit { async saveSettings() { const modelSettings = this.settingsForm.value; - if (this.settingsForm.get('enableAuthentication')?.value === false) { + if (this.settingsForm.get('enableAuthentication')?.dirty && this.settingsForm.get('enableAuthentication')?.value === false) { if (!await this.confirmService.confirm('Disabling Authentication opens your server up to unauthorized access and possible hacking. Are you sure you want to continue with this?')) { return; } } - const informUserAfterAuthenticationEnabled = this.settingsForm.get('enableAuthentication')?.value && !this.serverSettings.enableAuthentication; + const informUserAfterAuthenticationEnabled = this.settingsForm.get('enableAuthentication')?.dirty && this.settingsForm.get('enableAuthentication')?.value && !this.serverSettings.enableAuthentication; this.settingsService.updateServerSettings(modelSettings).pipe(take(1)).subscribe(async (settings: ServerSettings) => { this.serverSettings = settings; diff --git a/UI/Web/src/app/admin/manage-system/manage-system.component.html b/UI/Web/src/app/admin/manage-system/manage-system.component.html index fe3549a76..2bee93f0e 100644 --- a/UI/Web/src/app/admin/manage-system/manage-system.component.html +++ b/UI/Web/src/app/admin/manage-system/manage-system.component.html @@ -2,7 +2,7 @@
    -
    +
    @@ -122,7 +125,7 @@ -
    {{bookTitle}} (Incognito Mode)
    +
    {{bookTitle}} (Incognito Mode)
    +
    + + + + + + diff --git a/UI/Web/src/app/cards/_modals/bulk-add-to-collection/bulk-add-to-collection.component.scss b/UI/Web/src/app/cards/_modals/bulk-add-to-collection/bulk-add-to-collection.component.scss new file mode 100644 index 000000000..91847160a --- /dev/null +++ b/UI/Web/src/app/cards/_modals/bulk-add-to-collection/bulk-add-to-collection.component.scss @@ -0,0 +1,7 @@ +.clickable { + cursor: pointer; +} + +.clickable:hover, .clickable:focus { + background-color: lightgreen; +} \ No newline at end of file diff --git a/UI/Web/src/app/cards/_modals/bulk-add-to-collection/bulk-add-to-collection.component.ts b/UI/Web/src/app/cards/_modals/bulk-add-to-collection/bulk-add-to-collection.component.ts new file mode 100644 index 000000000..13641550b --- /dev/null +++ b/UI/Web/src/app/cards/_modals/bulk-add-to-collection/bulk-add-to-collection.component.ts @@ -0,0 +1,79 @@ +import { Component, ElementRef, Input, OnInit, ViewChild } from '@angular/core'; +import { FormGroup, FormControl } from '@angular/forms'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; +import { ToastrService } from 'ngx-toastr'; +import { CollectionTag } from 'src/app/_models/collection-tag'; +import { ReadingList } from 'src/app/_models/reading-list'; +import { CollectionTagService } from 'src/app/_services/collection-tag.service'; + +@Component({ + selector: 'app-bulk-add-to-collection', + templateUrl: './bulk-add-to-collection.component.html', + styleUrls: ['./bulk-add-to-collection.component.scss'] +}) +export class BulkAddToCollectionComponent implements OnInit { + + @Input() title!: string; + /** + * Series Ids to add to Collection Tag + */ + @Input() seriesIds: Array = []; + + /** + * All existing collections sorted by recent use date + */ + lists: Array = []; + loading: boolean = false; + listForm: FormGroup = new FormGroup({}); + + @ViewChild('title') inputElem!: ElementRef; + + + constructor(private modal: NgbActiveModal, private collectionService: CollectionTagService, private toastr: ToastrService) { } + + ngOnInit(): void { + + this.listForm.addControl('title', new FormControl(this.title, [])); + this.listForm.addControl('filterQuery', new FormControl('', [])); + + this.loading = true; + this.collectionService.allTags().subscribe(tags => { + this.lists = tags; + this.loading = false; + }); + } + + ngAfterViewInit() { + // Shift focus to input + if (this.inputElem) { + this.inputElem.nativeElement.select(); + } + } + + close() { + this.modal.close(); + } + + create() { + const tagName = this.listForm.value.title; + this.collectionService.addByMultiple(0, this.seriesIds, tagName).subscribe(() => { + this.toastr.success('Series added to ' + tagName + ' collection'); + this.modal.close(); + }); + } + + addToCollection(tag: CollectionTag) { + if (this.seriesIds.length === 0) return; + + this.collectionService.addByMultiple(tag.id, this.seriesIds, '').subscribe(() => { + this.toastr.success('Series added to ' + tag.title + ' collection'); + this.modal.close(); + }); + + } + + filterList = (listItem: ReadingList) => { + return listItem.title.toLowerCase().indexOf((this.listForm.value.filterQuery || '').toLowerCase()) >= 0; + } + +} diff --git a/UI/Web/src/app/cards/bulk-selection.service.ts b/UI/Web/src/app/cards/bulk-selection.service.ts index 47072c014..a7f6eba70 100644 --- a/UI/Web/src/app/cards/bulk-selection.service.ts +++ b/UI/Web/src/app/cards/bulk-selection.service.ts @@ -127,7 +127,7 @@ export class BulkSelectionService { getActions(callback: (action: Action, data: any) => void) { // checks if series is present. If so, returns only series actions // else returns volume/chapter items - const allowedActions = [Action.AddToReadingList, Action.MarkAsRead, Action.MarkAsUnread]; + const allowedActions = [Action.AddToReadingList, Action.MarkAsRead, Action.MarkAsUnread, Action.AddToCollection, Action.Delete]; if (Object.keys(this.selectedCards).filter(item => item === 'series').length > 0) { return this.actionFactory.getSeriesActions(callback).filter(item => allowedActions.includes(item.action)); } diff --git a/UI/Web/src/app/cards/cards.module.ts b/UI/Web/src/app/cards/cards.module.ts index 7c7db5c54..dc1a23134 100644 --- a/UI/Web/src/app/cards/cards.module.ts +++ b/UI/Web/src/app/cards/cards.module.ts @@ -16,10 +16,11 @@ import { CardItemComponent } from './card-item/card-item.component'; import { SharedModule } from '../shared/shared.module'; import { RouterModule } from '@angular/router'; import { TypeaheadModule } from '../typeahead/typeahead.module'; -import { BrowserModule } from '@angular/platform-browser'; import { CardDetailLayoutComponent } from './card-detail-layout/card-detail-layout.component'; import { CardDetailsModalComponent } from './_modals/card-details-modal/card-details-modal.component'; import { BulkOperationsComponent } from './bulk-operations/bulk-operations.component'; +import { BulkAddToCollectionComponent } from './_modals/bulk-add-to-collection/bulk-add-to-collection.component'; +import { PipeModule } from '../pipe/pipe.module'; @@ -36,11 +37,11 @@ import { BulkOperationsComponent } from './bulk-operations/bulk-operations.compo CardActionablesComponent, CardDetailLayoutComponent, CardDetailsModalComponent, - BulkOperationsComponent + BulkOperationsComponent, + BulkAddToCollectionComponent ], imports: [ CommonModule, - //BrowserModule, RouterModule, ReactiveFormsModule, FormsModule, // EditCollectionsModal @@ -58,6 +59,7 @@ import { BulkOperationsComponent } from './bulk-operations/bulk-operations.compo NgbDropdownModule, NgbProgressbarModule, NgxFileDropModule, // Cover Chooser + PipeModule // filter for BulkAddToCollectionComponent ], exports: [ CardItemComponent, diff --git a/UI/Web/src/app/collections/collection-detail/collection-detail.component.ts b/UI/Web/src/app/collections/collection-detail/collection-detail.component.ts index 086df24a3..2593aaba8 100644 --- a/UI/Web/src/app/collections/collection-detail/collection-detail.component.ts +++ b/UI/Web/src/app/collections/collection-detail/collection-detail.component.ts @@ -55,6 +55,11 @@ export class CollectionDetailComponent implements OnInit, OnDestroy { this.bulkSelectionService.deselectAll(); }); break; + case Action.AddToCollection: + this.actionService.addMultipleSeriesToCollectionTag(selectedSeries, () => { + this.bulkSelectionService.deselectAll(); + }); + break; case Action.MarkAsRead: this.actionService.markMultipleSeriesAsRead(selectedSeries, () => { this.loadPage(); @@ -67,6 +72,12 @@ export class CollectionDetailComponent implements OnInit, OnDestroy { this.bulkSelectionService.deselectAll(); }); break; + case Action.Delete: + this.actionService.deleteMultipleSeries(selectedSeries, () => { + this.loadPage(); + this.bulkSelectionService.deselectAll(); + }); + break; } } diff --git a/UI/Web/src/app/in-progress/in-progress.component.html b/UI/Web/src/app/in-progress/in-progress.component.html index ebae6ff8b..f4ca791f0 100644 --- a/UI/Web/src/app/in-progress/in-progress.component.html +++ b/UI/Web/src/app/in-progress/in-progress.component.html @@ -1,14 +1,14 @@ - - + - - - - - \ No newline at end of file + + + + diff --git a/UI/Web/src/app/in-progress/in-progress.component.ts b/UI/Web/src/app/in-progress/in-progress.component.ts index 164309c27..88b06db0e 100644 --- a/UI/Web/src/app/in-progress/in-progress.component.ts +++ b/UI/Web/src/app/in-progress/in-progress.component.ts @@ -1,11 +1,15 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, HostListener, OnInit } from '@angular/core'; import { Title } from '@angular/platform-browser'; import { Router, ActivatedRoute } from '@angular/router'; import { take } from 'rxjs/operators'; +import { BulkSelectionService } from '../cards/bulk-selection.service'; import { UpdateFilterEvent } from '../cards/card-detail-layout/card-detail-layout.component'; +import { KEY_CODES } from '../shared/_services/utility.service'; import { Pagination } from '../_models/pagination'; import { Series } from '../_models/series'; import { FilterItem, SeriesFilter, mangaFormatFilters } from '../_models/series-filter'; +import { Action } from '../_services/action-factory.service'; +import { ActionService } from '../_services/action.service'; import { SeriesService } from '../_services/series.service'; @Component({ @@ -16,7 +20,7 @@ import { SeriesService } from '../_services/series.service'; export class InProgressComponent implements OnInit { isLoading: boolean = true; - recentlyAdded: Series[] = []; + series: Series[] = []; pagination!: Pagination; libraryId!: number; filters: Array = mangaFormatFilters; @@ -24,7 +28,8 @@ export class InProgressComponent implements OnInit { mangaFormat: null }; - constructor(private router: Router, private route: ActivatedRoute, private seriesService: SeriesService, private titleService: Title) { + constructor(private router: Router, private route: ActivatedRoute, private seriesService: SeriesService, private titleService: Title, + private actionService: ActionService, public bulkSelectionService: BulkSelectionService) { this.router.routeReuseStrategy.shouldReuseRoute = () => false; this.titleService.setTitle('Kavita - In Progress'); if (this.pagination === undefined || this.pagination === null) { @@ -33,6 +38,20 @@ export class InProgressComponent implements OnInit { this.loadPage(); } + @HostListener('document:keydown.shift', ['$event']) + handleKeypress(event: KeyboardEvent) { + if (event.key === KEY_CODES.SHIFT) { + this.bulkSelectionService.isShiftDown = true; + } + } + + @HostListener('document:keyup.shift', ['$event']) + handleKeyUp(event: KeyboardEvent) { + if (event.key === KEY_CODES.SHIFT) { + this.bulkSelectionService.isShiftDown = false; + } + } + ngOnInit() {} seriesClicked(series: Series) { @@ -61,7 +80,7 @@ export class InProgressComponent implements OnInit { } this.isLoading = true; this.seriesService.getInProgress(this.libraryId, this.pagination?.currentPage, this.pagination?.itemsPerPage, this.filter).pipe(take(1)).subscribe(series => { - this.recentlyAdded = series.result; + this.series = series.result; this.pagination = series.pagination; this.isLoading = false; window.scrollTo(0, 0); @@ -73,4 +92,40 @@ export class InProgressComponent implements OnInit { return urlParams.get('page'); } + bulkActionCallback = (action: Action, data: any) => { + const selectedSeriesIndexies = this.bulkSelectionService.getSelectedCardsForSource('series'); + const selectedSeries = this.series.filter((series, index: number) => selectedSeriesIndexies.includes(index + '')); + + switch (action) { + case Action.AddToReadingList: + this.actionService.addMultipleSeriesToReadingList(selectedSeries, () => { + this.bulkSelectionService.deselectAll(); + }); + break; + case Action.AddToCollection: + this.actionService.addMultipleSeriesToCollectionTag(selectedSeries, () => { + this.bulkSelectionService.deselectAll(); + }); + break; + case Action.MarkAsRead: + this.actionService.markMultipleSeriesAsRead(selectedSeries, () => { + this.loadPage(); + this.bulkSelectionService.deselectAll(); + }); + break; + case Action.MarkAsUnread: + this.actionService.markMultipleSeriesAsUnread(selectedSeries, () => { + this.loadPage(); + this.bulkSelectionService.deselectAll(); + }); + break; + case Action.Delete: + this.actionService.deleteMultipleSeries(selectedSeries, () => { + this.loadPage(); + this.bulkSelectionService.deselectAll(); + }); + break; + } + } + } diff --git a/UI/Web/src/app/library-detail/library-detail.component.html b/UI/Web/src/app/library-detail/library-detail.component.html index 6d7885385..d01cec915 100644 --- a/UI/Web/src/app/library-detail/library-detail.component.html +++ b/UI/Web/src/app/library-detail/library-detail.component.html @@ -9,6 +9,6 @@ (pageChange)="onPageChange($event)" > - + diff --git a/UI/Web/src/app/library-detail/library-detail.component.ts b/UI/Web/src/app/library-detail/library-detail.component.ts index 57c85d789..810f20131 100644 --- a/UI/Web/src/app/library-detail/library-detail.component.ts +++ b/UI/Web/src/app/library-detail/library-detail.component.ts @@ -46,6 +46,11 @@ export class LibraryDetailComponent implements OnInit, OnDestroy { this.bulkSelectionService.deselectAll(); }); break; + case Action.AddToCollection: + this.actionService.addMultipleSeriesToCollectionTag(selectedSeries, () => { + this.bulkSelectionService.deselectAll(); + }); + break; case Action.MarkAsRead: this.actionService.markMultipleSeriesAsRead(selectedSeries, () => { this.loadPage(); @@ -59,6 +64,12 @@ export class LibraryDetailComponent implements OnInit, OnDestroy { this.bulkSelectionService.deselectAll(); }); break; + case Action.Delete: + this.actionService.deleteMultipleSeries(selectedSeries, () => { + this.loadPage(); + this.bulkSelectionService.deselectAll(); + }); + break; } } diff --git a/UI/Web/src/app/library/library.component.html b/UI/Web/src/app/library/library.component.html index d1522bb8a..ba2003226 100644 --- a/UI/Web/src/app/library/library.component.html +++ b/UI/Web/src/app/library/library.component.html @@ -13,7 +13,7 @@ - + diff --git a/UI/Web/src/app/library/library.component.ts b/UI/Web/src/app/library/library.component.ts index bf862f730..94b1e61bc 100644 --- a/UI/Web/src/app/library/library.component.ts +++ b/UI/Web/src/app/library/library.component.ts @@ -6,6 +6,7 @@ import { Subject } from 'rxjs'; import { take, takeUntil } from 'rxjs/operators'; import { EditCollectionTagsComponent } from '../cards/_modals/edit-collection-tags/edit-collection-tags.component'; import { CollectionTag } from '../_models/collection-tag'; +import { SeriesAddedEvent } from '../_models/events/series-added-event'; import { InProgressChapter } from '../_models/in-progress-chapter'; import { Library } from '../_models/library'; import { Series } from '../_models/series'; @@ -15,6 +16,7 @@ import { Action, ActionFactoryService, ActionItem } from '../_services/action-fa import { CollectionTagService } from '../_services/collection-tag.service'; import { ImageService } from '../_services/image.service'; import { LibraryService } from '../_services/library.service'; +import { EVENTS, MessageHubService } from '../_services/message-hub.service'; import { SeriesService } from '../_services/series.service'; @Component({ @@ -32,17 +34,24 @@ export class LibraryComponent implements OnInit, OnDestroy { recentlyAdded: Series[] = []; inProgress: Series[] = []; continueReading: InProgressChapter[] = []; - // collectionTags: CollectionTag[] = []; - // collectionTagActions: ActionItem[] = []; private readonly onDestroy = new Subject(); seriesTrackBy = (index: number, item: any) => `${item.name}_${item.pagesRead}`; constructor(public accountService: AccountService, private libraryService: LibraryService, - private seriesService: SeriesService, private actionFactoryService: ActionFactoryService, - private collectionService: CollectionTagService, private router: Router, - private modalService: NgbModal, private titleService: Title, public imageService: ImageService) { } + private seriesService: SeriesService, private router: Router, + private titleService: Title, public imageService: ImageService, + private messageHub: MessageHubService) { + this.messageHub.messages$.pipe(takeUntil(this.onDestroy)).subscribe(res => { + if (res.event == EVENTS.SeriesAdded) { + const seriesAddedEvent = res.payload as SeriesAddedEvent; + this.seriesService.getSeries(seriesAddedEvent.seriesId).subscribe(series => { + this.recentlyAdded.unshift(series); + }); + } + }); + } ngOnInit(): void { this.titleService.setTitle('Kavita - Dashboard'); @@ -56,8 +65,6 @@ export class LibraryComponent implements OnInit, OnDestroy { }); }); - //this.collectionTagActions = this.actionFactoryService.getCollectionTagActions(this.handleCollectionActionCallback.bind(this)); - this.reloadSeries(); } @@ -68,10 +75,7 @@ export class LibraryComponent implements OnInit, OnDestroy { reloadSeries() { this.loadRecentlyAdded(); - this.loadInProgress(); - - this.reloadTags(); } reloadInProgress(series: Series | boolean) { @@ -85,7 +89,6 @@ export class LibraryComponent implements OnInit, OnDestroy { } this.loadInProgress(); - this.reloadTags(); } loadInProgress() { @@ -100,12 +103,6 @@ export class LibraryComponent implements OnInit, OnDestroy { }); } - reloadTags() { - // this.collectionService.allTags().pipe(takeUntil(this.onDestroy)).subscribe(tags => { - // this.collectionTags = tags; - // }); - } - handleSectionClick(sectionTitle: string) { if (sectionTitle.toLowerCase() === 'collections') { this.router.navigate(['collections']); @@ -115,26 +112,4 @@ export class LibraryComponent implements OnInit, OnDestroy { this.router.navigate(['in-progress']); } } - - loadCollection(item: CollectionTag) { - //this.router.navigate(['collections', item.id]); - } - - // handleCollectionActionCallback(action: Action, collectionTag: CollectionTag) { - // switch (action) { - // case(Action.Edit): - // const modalRef = this.modalService.open(EditCollectionTagsComponent, { size: 'lg', scrollable: true }); - // modalRef.componentInstance.tag = collectionTag; - // modalRef.closed.subscribe((results: {success: boolean, coverImageUpdated: boolean}) => { - // this.reloadTags(); - // if (results.coverImageUpdated) { - // collectionTag.coverImage = this.imageService.randomize(collectionTag.coverImage); - // } - // }); - // break; - // default: - // break; - // } - // } - } diff --git a/UI/Web/src/app/manga-reader/manga-reader.component.html b/UI/Web/src/app/manga-reader/manga-reader.component.html index 698596fb5..0c00f5b9d 100644 --- a/UI/Web/src/app/manga-reader/manga-reader.component.html +++ b/UI/Web/src/app/manga-reader/manga-reader.component.html @@ -7,7 +7,7 @@
    -
    {{title}} (Incognito Mode)
    +
    {{title}} (Incognito Mode:)
    {{subtitle}}
    diff --git a/UI/Web/src/app/manga-reader/manga-reader.component.ts b/UI/Web/src/app/manga-reader/manga-reader.component.ts index ec9c0ba90..e41d9cc30 100644 --- a/UI/Web/src/app/manga-reader/manga-reader.component.ts +++ b/UI/Web/src/app/manga-reader/manga-reader.component.ts @@ -1113,4 +1113,15 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy { } } + + /** + * Turns off Incognito mode. This can only happen once if the user clicks the icon. This will modify URL state + */ + turnOffIncognito() { + this.incognitoMode = false; + const newRoute = this.readerService.getNextChapterUrl(this.router.url, this.chapterId, this.incognitoMode, this.readingListMode, this.readingListId); + window.history.replaceState({}, '', newRoute); + this.toastr.info('Incognito mode is off. Progress will now start being tracked.'); + this.readerService.saveProgress(this.seriesId, this.volumeId, this.chapterId, this.pageNum).pipe(take(1)).subscribe(() => {/* No operation */}); + } } diff --git a/UI/Web/src/app/nav-header/nav-header.component.html b/UI/Web/src/app/nav-header/nav-header.component.html index 87bc92ec5..b96bd73f6 100644 --- a/UI/Web/src/app/nav-header/nav-header.component.html +++ b/UI/Web/src/app/nav-header/nav-header.component.html @@ -23,6 +23,7 @@ (selected)='clickSearchResult($event)' (inputChanged)='onChangeSearch($event)' [isLoading]="isLoading" + [customFilter]="customFilter" [debounceTime]="debounceTime" [itemTemplate]="itemTemplate" [notFoundTemplate]="notFoundTemplate"> @@ -35,7 +36,7 @@
    - + diff --git a/UI/Web/src/app/nav-header/nav-header.component.ts b/UI/Web/src/app/nav-header/nav-header.component.ts index d9005bc10..b2f7896e1 100644 --- a/UI/Web/src/app/nav-header/nav-header.component.ts +++ b/UI/Web/src/app/nav-header/nav-header.component.ts @@ -3,6 +3,7 @@ import { Component, HostListener, Inject, OnDestroy, OnInit, ViewChild } from '@ import { Router } from '@angular/router'; import { Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; +import { isTemplateSpan } from 'typescript'; import { ScrollService } from '../scroll.service'; import { SearchResult } from '../_models/search-result'; import { AccountService } from '../_services/account.service'; @@ -24,6 +25,16 @@ export class NavHeaderComponent implements OnInit, OnDestroy { imageStyles = {width: '24px', 'margin-top': '5px'}; searchResults: SearchResult[] = []; searchTerm = ''; + customFilter: (items: SearchResult[], query: string) => SearchResult[] = (items: SearchResult[], query: string) => { + const normalizedQuery = query.trim().toLowerCase(); + const matches = items.filter(item => { + const normalizedSeriesName = item.name.toLowerCase().trim(); + const normalizedOriginalName = item.originalName.toLowerCase().trim(); + const normalizedLocalizedName = item.localizedName.toLowerCase().trim(); + return normalizedSeriesName.indexOf(normalizedQuery) >= 0 || normalizedOriginalName.indexOf(normalizedQuery) >= 0 || normalizedLocalizedName.indexOf(normalizedQuery) >= 0; + }); + return matches; + }; backToTopNeeded = false; diff --git a/UI/Web/src/app/reading-list/_modals/add-to-list-modal/add-to-list-modal.component.ts b/UI/Web/src/app/reading-list/_modals/add-to-list-modal/add-to-list-modal.component.ts index a33d69332..3d88fcd1b 100644 --- a/UI/Web/src/app/reading-list/_modals/add-to-list-modal/add-to-list-modal.component.ts +++ b/UI/Web/src/app/reading-list/_modals/add-to-list-modal/add-to-list-modal.component.ts @@ -1,6 +1,5 @@ -import { noUndefined } from '@angular/compiler/src/util'; import { AfterViewInit, Component, ElementRef, Input, OnInit, ViewChild } from '@angular/core'; -import { FormControl, FormGroup, Validators } from '@angular/forms'; +import { FormControl, FormGroup } from '@angular/forms'; import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; import { ToastrService } from 'ngx-toastr'; import { ReadingList } from 'src/app/_models/reading-list'; diff --git a/UI/Web/src/app/recently-added/recently-added.component.html b/UI/Web/src/app/recently-added/recently-added.component.html index b9bfbec74..93952f73e 100644 --- a/UI/Web/src/app/recently-added/recently-added.component.html +++ b/UI/Web/src/app/recently-added/recently-added.component.html @@ -1,14 +1,13 @@ - - - - - - - + + + + + + \ No newline at end of file diff --git a/UI/Web/src/app/recently-added/recently-added.component.ts b/UI/Web/src/app/recently-added/recently-added.component.ts index 4615f610a..97640118d 100644 --- a/UI/Web/src/app/recently-added/recently-added.component.ts +++ b/UI/Web/src/app/recently-added/recently-added.component.ts @@ -1,11 +1,18 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, HostListener, OnDestroy, OnInit } from '@angular/core'; import { Title } from '@angular/platform-browser'; import { ActivatedRoute, Router } from '@angular/router'; -import { take } from 'rxjs/operators'; +import { Subject } from 'rxjs'; +import { debounceTime, take, takeUntil, takeWhile } from 'rxjs/operators'; +import { BulkSelectionService } from '../cards/bulk-selection.service'; import { UpdateFilterEvent } from '../cards/card-detail-layout/card-detail-layout.component'; +import { KEY_CODES } from '../shared/_services/utility.service'; +import { SeriesAddedEvent } from '../_models/events/series-added-event'; import { Pagination } from '../_models/pagination'; import { Series } from '../_models/series'; import { FilterItem, mangaFormatFilters, SeriesFilter } from '../_models/series-filter'; +import { Action, ActionFactoryService } from '../_services/action-factory.service'; +import { ActionService } from '../_services/action.service'; +import { MessageHubService } from '../_services/message-hub.service'; import { SeriesService } from '../_services/series.service'; /** @@ -16,10 +23,10 @@ import { SeriesService } from '../_services/series.service'; templateUrl: './recently-added.component.html', styleUrls: ['./recently-added.component.scss'] }) -export class RecentlyAddedComponent implements OnInit { +export class RecentlyAddedComponent implements OnInit, OnDestroy { isLoading: boolean = true; - recentlyAdded: Series[] = []; + series: Series[] = []; pagination!: Pagination; libraryId!: number; @@ -28,7 +35,10 @@ export class RecentlyAddedComponent implements OnInit { mangaFormat: null }; - constructor(private router: Router, private route: ActivatedRoute, private seriesService: SeriesService, private titleService: Title) { + onDestroy: Subject = new Subject(); + + constructor(private router: Router, private route: ActivatedRoute, private seriesService: SeriesService, private titleService: Title, + private actionService: ActionService, public bulkSelectionService: BulkSelectionService, private hubService: MessageHubService) { this.router.routeReuseStrategy.shouldReuseRoute = () => false; this.titleService.setTitle('Kavita - Recently Added'); if (this.pagination === undefined || this.pagination === null) { @@ -37,7 +47,30 @@ export class RecentlyAddedComponent implements OnInit { this.loadPage(); } - ngOnInit() {} + @HostListener('document:keydown.shift', ['$event']) + handleKeypress(event: KeyboardEvent) { + if (event.key === KEY_CODES.SHIFT) { + this.bulkSelectionService.isShiftDown = true; + } + } + + @HostListener('document:keyup.shift', ['$event']) + handleKeyUp(event: KeyboardEvent) { + if (event.key === KEY_CODES.SHIFT) { + this.bulkSelectionService.isShiftDown = false; + } + } + + ngOnInit() { + this.hubService.seriesAdded.pipe(takeWhile(event => event.libraryId === this.libraryId), debounceTime(6000), takeUntil(this.onDestroy)).subscribe((event: SeriesAddedEvent) => { + this.loadPage(); + }); + } + + ngOnDestroy() { + this.onDestroy.next(); + this.onDestroy.complete(); + } seriesClicked(series: Series) { this.router.navigate(['library', this.libraryId, 'series', series.id]); @@ -65,7 +98,7 @@ export class RecentlyAddedComponent implements OnInit { } this.isLoading = true; this.seriesService.getRecentlyAdded(this.libraryId, this.pagination?.currentPage, this.pagination?.itemsPerPage, this.filter).pipe(take(1)).subscribe(series => { - this.recentlyAdded = series.result; + this.series = series.result; this.pagination = series.pagination; this.isLoading = false; window.scrollTo(0, 0); @@ -76,4 +109,41 @@ export class RecentlyAddedComponent implements OnInit { const urlParams = new URLSearchParams(window.location.search); return urlParams.get('page'); } + + bulkActionCallback = (action: Action, data: any) => { + const selectedSeriesIndexies = this.bulkSelectionService.getSelectedCardsForSource('series'); + const selectedSeries = this.series.filter((series, index: number) => selectedSeriesIndexies.includes(index + '')); + + switch (action) { + case Action.AddToReadingList: + this.actionService.addMultipleSeriesToReadingList(selectedSeries, () => { + this.bulkSelectionService.deselectAll(); + }); + break; + case Action.AddToCollection: + this.actionService.addMultipleSeriesToCollectionTag(selectedSeries, () => { + this.bulkSelectionService.deselectAll(); + }); + break; + case Action.MarkAsRead: + this.actionService.markMultipleSeriesAsRead(selectedSeries, () => { + this.loadPage(); + this.bulkSelectionService.deselectAll(); + }); + + break; + case Action.MarkAsUnread: + this.actionService.markMultipleSeriesAsUnread(selectedSeries, () => { + this.loadPage(); + this.bulkSelectionService.deselectAll(); + }); + break; + case Action.Delete: + this.actionService.deleteMultipleSeries(selectedSeries, () => { + this.loadPage(); + this.bulkSelectionService.deselectAll(); + }); + break; + } + } } diff --git a/UI/Web/src/app/typeahead/typeahead.component.scss b/UI/Web/src/app/typeahead/typeahead.component.scss index 2672736ad..d798e2c5b 100644 --- a/UI/Web/src/app/typeahead/typeahead.component.scss +++ b/UI/Web/src/app/typeahead/typeahead.component.scss @@ -10,7 +10,7 @@ input { .typeahead-input { border: 1px solid #ccc; - padding: 4px 6px; + padding: 0px 6px; display: inline-block; width: 100%; overflow: hidden; diff --git a/UI/Web/src/app/typeahead/typeahead.component.ts b/UI/Web/src/app/typeahead/typeahead.component.ts index 3ebf81280..99b721f18 100644 --- a/UI/Web/src/app/typeahead/typeahead.component.ts +++ b/UI/Web/src/app/typeahead/typeahead.component.ts @@ -1,7 +1,7 @@ import { Component, ContentChild, ElementRef, EventEmitter, HostListener, Input, OnDestroy, OnInit, Output, Renderer2, RendererStyleFlags2, TemplateRef, ViewChild } from '@angular/core'; import { FormControl, FormGroup } from '@angular/forms'; -import { Observable, Observer, of, Subject } from 'rxjs'; -import { debounceTime, distinctUntilChanged, filter, last, map, shareReplay, switchMap, take, takeLast, takeUntil, tap, withLatestFrom } from 'rxjs/operators'; +import { Observable, of, Subject } from 'rxjs'; +import { debounceTime, filter, map, shareReplay, switchMap, take, takeUntil, tap } from 'rxjs/operators'; import { KEY_CODES } from '../shared/_services/utility.service'; import { TypeaheadSettings } from './typeahead-settings'; diff --git a/UI/Web/src/app/user-login/user-login.component.html b/UI/Web/src/app/user-login/user-login.component.html index 9caa02e73..226b42057 100644 --- a/UI/Web/src/app/user-login/user-login.component.html +++ b/UI/Web/src/app/user-login/user-login.component.html @@ -1,6 +1,6 @@
    /// /// + [Authorize(Policy = "RequireAdminRole")] [HttpPost("register")] public async Task> Register(RegisterDto registerDto) { diff --git a/UI/Web/src/app/admin/admin-routing.module.ts b/UI/Web/src/app/admin/admin-routing.module.ts index a29927171..ad55b01d4 100644 --- a/UI/Web/src/app/admin/admin-routing.module.ts +++ b/UI/Web/src/app/admin/admin-routing.module.ts @@ -4,7 +4,7 @@ import { AdminGuard } from '../_guards/admin.guard'; import { DashboardComponent } from './dashboard/dashboard.component'; const routes: Routes = [ - {path: '**', component: DashboardComponent, pathMatch: 'full'}, + {path: '**', component: DashboardComponent, pathMatch: 'full', canActivate: [AdminGuard]}, { runGuardsAndResolvers: 'always', canActivate: [AdminGuard], From 7fb41f09456ddb544a045482f986e952777889ca Mon Sep 17 00:00:00 2001 From: Joseph Milazzo Date: Wed, 5 Jan 2022 14:59:29 -0800 Subject: [PATCH 06/11] Fixed a bug with previous hotfix which prevented registration for new users. (#899) --- API/Controllers/AccountController.cs | 14 ++++++++++++-- Kavita.Common/Kavita.Common.csproj | 4 ++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/API/Controllers/AccountController.cs b/API/Controllers/AccountController.cs index 1ae406b8a..415b51f59 100644 --- a/API/Controllers/AccountController.cs +++ b/API/Controllers/AccountController.cs @@ -13,7 +13,6 @@ using API.Interfaces.Services; using API.Services; using AutoMapper; using Kavita.Common; -using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; @@ -79,7 +78,6 @@ namespace API.Controllers ///
    /// /// - [Authorize(Policy = "RequireAdminRole")] [HttpPost("register")] public async Task> Register(RegisterDto registerDto) { @@ -90,6 +88,17 @@ namespace API.Controllers return BadRequest("Username is taken."); } + // If we are registering an admin account, ensure there are no existing admins or user registering is an admin + if (registerDto.IsAdmin) + { + var firstTimeFlow = !(await _userManager.GetUsersInRoleAsync("Admin")).Any(); + if (!firstTimeFlow && !await _unitOfWork.UserRepository.IsUserAdmin( + await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername()))) + { + return BadRequest("You are not permitted to create an admin account"); + } + } + var user = _mapper.Map(registerDto); user.UserPreferences ??= new AppUserPreferences(); user.ApiKey = HashUtil.ApiKey(); @@ -105,6 +114,7 @@ namespace API.Controllers if (!result.Succeeded) return BadRequest(result.Errors); + var role = registerDto.IsAdmin ? PolicyConstants.AdminRole : PolicyConstants.PlebRole; var roleResult = await _userManager.AddToRoleAsync(user, role); diff --git a/Kavita.Common/Kavita.Common.csproj b/Kavita.Common/Kavita.Common.csproj index 0c00c0d36..005b8a5b8 100644 --- a/Kavita.Common/Kavita.Common.csproj +++ b/Kavita.Common/Kavita.Common.csproj @@ -4,7 +4,7 @@ net5.0 kavitareader.com Kavita - 0.4.9.1 + 0.4.9.2 en @@ -18,4 +18,4 @@ - \ No newline at end of file + From 41096d6dc5a842383aa57cfb8e0ed219ecb86a25 Mon Sep 17 00:00:00 2001 From: Joseph Milazzo Date: Tue, 18 Jan 2022 15:31:34 -0800 Subject: [PATCH 07/11] v0.5.0 Release (#960) * Bump versions by dotnet-bump-version. * Color Theme applies to scrollbars (#793) * Moved more scss to use syntax to reduce css size * Hooked in color-scheme to help brower render scroll bars appropriately depending on color scheme user selects * Bump versions by dotnet-bump-version. * UI Updates + New Events (#806) * Implemented ability to see downloads users are performing on the events widget. * Fixed a bug where version update task was calling wrong code * Fixed a bug where when checking for updates, the event wouldn't be pushed to server with correct name. Added update check to the event widget rather than opening a modal on the user. * Relaxed password requirements to only be 6-32 characters and inform user on register form about the requirements * Removed a ton of duplicate logic for series cards where the logic was already defined in action service * Fixed OPDS total items giving a rounded number rather than total items. * Fixed off by one issue on OPDS pagination * Bump versions by dotnet-bump-version. * Update GA .net version (#818) * Local Metadata Integration Part 1 (#817) * Started with some basic plumbing with comic info parsing updating Series/Volume. * We can now get chapter title from comicInfo.xml * Hooked in the ability to store people into the chapter metadata. * Removed no longer used imports, fixed up some foreign key constraints on deleting series with person linked. * Refactored Summary out of the UI for Series into SeriesMetadata. Updated application to .net 6. There is a bug in metadata code for updating. * Removed the parallel.ForEach with a normal foreach which lets us use async. For I/O heavy code, shouldn't change much. * Refactored scan code to only check extensions with comic info, fixed a bug on scan events not using correct method name, removed summary field (still buggy) * Fixed a bug where on cancelling a metadata request in modal, underlying button would get stuck in a disabled state. * Changed how metadata selects the first volume to read summary info from. It will now select the first non-special volume rather than Volume 1. * More debugging and found more bugs to fix * Redid all the migrations as one single one. Fixed a bug with GetChapterInfo returning null when ChapterMetadata didn't exist for that Chapter. Fixed an issue with mapper failing on GetChapterMetadata. Started work on adding people and a design for people. * Fixed a bug where checking if file modified now takes into account if file has been processed at least once. Introduced a bug in saving people to series. * Just made code compilable again * Fixed up code. Now people for series and chapters add correctly without any db issues. * Things are working, but I'm not happy with how the management of Person is. I need to take into account that 1 person needs to map to an image and role is arbitrary. * Started adding UI code to showcase chapter metadata * Updated workflow to be .NET 6 * WIP of updating card detail to show the information more clearly and without so many if statements * Removed ChatperMetadata and store on the Chapter itself. Much easier to use and less joins. * Implemented Genre on SeriesMetadata level * Genres and People are now removed from Series level if they are no longer on comicInfo * PeopleHelper is done with unit tests. Everything is working. * Unit tests in place for Genre Helper * Starting on CacheHelper * Finished tests for ShouldUpdateCoverImage. Fixed and added tests in ArchiveService/ScannerService. * CacheHelper is fully tested * Some DI cleanup * Scanner Service now calls GetComicInfo for books. Added ability to update Series Sort name from metadata files (mainly epub as comicinfo doesn't have a field) * Forgot to move a line of code * SortName now populates from metadata (epub only, ComicInfo has no tags) * Cards now show the chapter title name if it's set on hover, else will default back to title. * Fixed a major issue with how MangaFiles were being updated with LastModified, which messed up our logic for avoiding refreshes. * Woohoo, more tests and some refactors to be able to test more services wtih mock filesystem. Fixed an issue where SortName was getting set as first chapter, but the Series was in a group. * Refactored the MangaFile creation code into the DbFactory where we also setup the first LastModified update. * Has file changed bug is now finally fixed * Remove dead genres, refactor genre to use title instead of name. * Refactored out a directory from ShouldUpdateCoverImage() to keep the code clean * Unit tests for ComicInfo on BookService. * Refactored series detail into it's own component * Series-detail now received refresh metadata events to refresh what's on screen * Removed references to Artist on PersonRole as it has no metadata mapping * Security audit * Fixed a benchmark * Updated JWT Token generator to use new methods in .NET 6 * Updated all the docker and build commands to use net6.0 * Commented out sonar scan since it's not setup for net6.0 yet. * Don't rely on test (#819) * Bump versions by dotnet-bump-version. * Update monorepo-build.sh Updated build to use .net6.0 * Bump versions by dotnet-bump-version. * Update sonar-scan.yml More updates to 6.0 * Update sonar-scan.yml Please work * Bump versions by dotnet-bump-version. * Please work * Bump versions by dotnet-bump-version. * Local Metadata Integration Part 1 (#820) * Started with some basic plumbing with comic info parsing updating Series/Volume. * We can now get chapter title from comicInfo.xml * Hooked in the ability to store people into the chapter metadata. * Removed no longer used imports, fixed up some foreign key constraints on deleting series with person linked. * Refactored Summary out of the UI for Series into SeriesMetadata. Updated application to .net 6. There is a bug in metadata code for updating. * Removed the parallel.ForEach with a normal foreach which lets us use async. For I/O heavy code, shouldn't change much. * Refactored scan code to only check extensions with comic info, fixed a bug on scan events not using correct method name, removed summary field (still buggy) * Fixed a bug where on cancelling a metadata request in modal, underlying button would get stuck in a disabled state. * Changed how metadata selects the first volume to read summary info from. It will now select the first non-special volume rather than Volume 1. * More debugging and found more bugs to fix * Redid all the migrations as one single one. Fixed a bug with GetChapterInfo returning null when ChapterMetadata didn't exist for that Chapter. Fixed an issue with mapper failing on GetChapterMetadata. Started work on adding people and a design for people. * Fixed a bug where checking if file modified now takes into account if file has been processed at least once. Introduced a bug in saving people to series. * Just made code compilable again * Fixed up code. Now people for series and chapters add correctly without any db issues. * Things are working, but I'm not happy with how the management of Person is. I need to take into account that 1 person needs to map to an image and role is arbitrary. * Started adding UI code to showcase chapter metadata * Updated workflow to be .NET 6 * WIP of updating card detail to show the information more clearly and without so many if statements * Removed ChatperMetadata and store on the Chapter itself. Much easier to use and less joins. * Implemented Genre on SeriesMetadata level * Genres and People are now removed from Series level if they are no longer on comicInfo * PeopleHelper is done with unit tests. Everything is working. * Unit tests in place for Genre Helper * Starting on CacheHelper * Finished tests for ShouldUpdateCoverImage. Fixed and added tests in ArchiveService/ScannerService. * CacheHelper is fully tested * Some DI cleanup * Scanner Service now calls GetComicInfo for books. Added ability to update Series Sort name from metadata files (mainly epub as comicinfo doesn't have a field) * Forgot to move a line of code * SortName now populates from metadata (epub only, ComicInfo has no tags) * Cards now show the chapter title name if it's set on hover, else will default back to title. * Fixed a major issue with how MangaFiles were being updated with LastModified, which messed up our logic for avoiding refreshes. * Woohoo, more tests and some refactors to be able to test more services wtih mock filesystem. Fixed an issue where SortName was getting set as first chapter, but the Series was in a group. * Refactored the MangaFile creation code into the DbFactory where we also setup the first LastModified update. * Has file changed bug is now finally fixed * Remove dead genres, refactor genre to use title instead of name. * Refactored out a directory from ShouldUpdateCoverImage() to keep the code clean * Unit tests for ComicInfo on BookService. * Refactored series detail into it's own component * Series-detail now received refresh metadata events to refresh what's on screen * Removed references to Artist on PersonRole as it has no metadata mapping * Security audit * Fixed a benchmark * Updated JWT Token generator to use new methods in .NET 6 * Updated all the docker and build commands to use net6.0 * Commented out sonar scan since it's not setup for net6.0 yet. * Removed some directives * Removed my test db * Bump versions by dotnet-bump-version. * .NET 6 Coding Patterns + Unit Tests (#823) * Refactored all files to have Interfaces within the same file. Started moving over to file-scoped namespaces. * Refactored common methods for getting underlying file's cover, pages, and extracting into 1 interface. * More refactoring around removing dependence on explicit filetype testing for getting information. * Code is buildable, tests are broken. Huge refactor (not completed) which makes most of DirectoryService testable with a mock filesystem (and thus the services that utilize it). * Finished porting DirectoryService to use mocked filesystem implementation. * Added a null check * Added a null check * Finished all unit tests for DirectoryService. * Some misc cleanup on the code * Fixed up some bugs from refactoring scan loop. * Implemented CleanupService testing and refactored more of DirectoryService to be non-static. Fixed a bug where cover file cleanup wasn't properly finding files due to a regex bug. * Fixed an issue in CleanupBackup() where we weren't properly selecting database files older than 30 days. Finished CleanupService Tests. * Refactored Flatten and RemoveNonImages to directory service to allow CacheService to be testable. * Finally have CacheService tested. Rewrote GetCachedPagePath() to be much more straightforward & performant. * Updated DefaultParserTests.cs to contain all existing tests and follow new test layout format. * All tests fixed up * Bump versions by dotnet-bump-version. * Bump docnet version to support x64 ARM pdfium binaries. (#826) * Bump versions by dotnet-bump-version. * Fixed bad build (#828) * Bump versions by dotnet-bump-version. * Bugfix/bad build (#829) * Fixed bad build * More directory service issues in Program * Bump versions by dotnet-bump-version. * Feature/local metadata more tags (#832) * Stashing code * removed some debug code on series detail page. Now detail is collapsed by default. * Added AgeRating * Fixed a crash when NetVips tries to write a cover file and cover directory is not existing. * When a card is selected for bulk actions, show an outline in addition to select box * Added AgeRating into the metadata parsing. Added a hack where ComicInfo uses Number in ComicInfo rather than Volume. This is to test out the effects on users libraries. * Added AgeRating and ReleaseDate to the metadata implelentation. * Bump versions by dotnet-bump-version. * Misc Fixes (#839) * Fixed a case where chapter was being parsed incorrectly when the series title ends in a number. * Updated Kavita to support Tome/T notation found in French comics * Added support for identifying European specials and expanded support for cleaning some tags used in European comics. During cleaning, if series starts with - or comma, remove it. * Fixed an issue where add to collection for a single series wasn't calling the bulk action handler * Fixed a NPE on AgeRating conversion. Fixed a bug where when looking for cover image, file extensions was throwing off sort code. * Refactored Natural Sort ordering to better follow how Windows behaves. This is a departure from how the original code executes. * GetCachedPagePath now uses natural sorting to pick the images for reading in a more correct order. * Updated parser to handle a case where there was more than one space as a separator * Bump versions by dotnet-bump-version. * Beefed up ToC generation to handle new ways of packing epub. (#840) * Bump versions by dotnet-bump-version. * Tachiyomi Enhancements (#845) * Added a new endpoint to get all Series with Progress info. * Fixed up some potential NPEs during scan * Commented out filter code, not ready for it. * Fixed up a parsing case for european comics * Refactored FilterDto to allow for specifying multiple formats to return. * Refactored FilterDto to allow for specifying multiple formats to return. * Refactored the UI to show OPDS as 3rd Party Clients since Tachiyomi now uses OPDS url scheme for authentication. * Bump versions by dotnet-bump-version. * In-Depth Filtering (#850) * Laying the foundation for the filter rework * Filtering by Genre is now possible. * Cleaned up code and preparing for People filtering * People filtering is hooked up for the frontend * Filtering now works. On Deck does not work with filtering currently due to a unique implementation. * More cleanup * Implemented the ability to reset the filters * Added a mobile drawer for filtering * Added some additional cases for NaturalSortComparer. Filter now uses a drawer on smaller screens. * Fixed a bug where backup service was not pointing to the correct directory. * Undid the fix, it's working as expected * Bump versions by dotnet-bump-version. * More Filtering and Support for ComicInfo v2.1 (draft) Tags (#851) * Added a reoccuring task to cleanup db entries that might be abandoned. On library page, the Library in question will be prepoulated. * Laid out the foundation for customized sorting. Added all series page to the UI when clicking on Libraries section header on home page so user can apply any filtering they like. * When filtering, the current library filter will now automatically filter out the options for people and genres. * Implemented Sorting controls * Clear now clears sorting and read progress. Sorting is disabled on deck and recently added. * Fixed an issue where all-series page couldn't click to open series * Don't let the user unselect the last read progress. Added new comicinfo v2.1 draft tags. * Hooked in Translator tag into backend and UI. * Fixed an issue where you could open multiple typeaheads at the same time * Integrated Translator and Tags ComicInfo extension fields. Started work on a badge expander. * Reworked a bit more on badge expander. Added the UI code for Age Rating and Tags * Integrated backend for Tags, Translator, and Age Rating * Metadata tags now collapse if more than 4 present * Some code cleanup * Made the not read badge slightly smaller * Bump versions by dotnet-bump-version. * More Filtering and Support for ComicInfo v2.1 (draft) Tags (#853) * Added a reoccuring task to cleanup db entries that might be abandoned. On library page, the Library in question will be prepoulated. * Laid out the foundation for customized sorting. Added all series page to the UI when clicking on Libraries section header on home page so user can apply any filtering they like. * When filtering, the current library filter will now automatically filter out the options for people and genres. * Implemented Sorting controls * Clear now clears sorting and read progress. Sorting is disabled on deck and recently added. * Fixed an issue where all-series page couldn't click to open series * Don't let the user unselect the last read progress. Added new comicinfo v2.1 draft tags. * Hooked in Translator tag into backend and UI. * Fixed an issue where you could open multiple typeaheads at the same time * Integrated Translator and Tags ComicInfo extension fields. Started work on a badge expander. * Reworked a bit more on badge expander. Added the UI code for Age Rating and Tags * Integrated backend for Tags, Translator, and Age Rating * Metadata tags now collapse if more than 4 present * Some code cleanup * Made the not read badge slightly smaller * Implemented Language filter. Fixed up some logic around Release Year not being set when month is missing. * Added a missing file and Updated Filter to use different design for layout * Fixed up some alignment issues * Refined the styles further * Bump versions by dotnet-bump-version. * Fixes v0.4.19! (#855) * Fixed OPDS urls to work with new Filtering schema * Fixed a rendering issue with Language tag when it's null * Fixed a bug where locked covers were resetting during refresh metadata. * Redid all the migrations and put some extra checks due to a bad migration from previous release (EF Core was producing an error). * Fixed a bug which didn't take sort direction when not changing sort field * Default installs now backup daily * Bump versions by dotnet-bump-version. * Fixed a bug in how to determine if the volume or series updates cover image. (#857) * Bump versions by dotnet-bump-version. * More fixes (again) (#858) * Send stack trace to the UI on prod mode * Pdfs will now generate cover images. I missed something a few releases ago. * Bump versions by dotnet-bump-version. * I can't believe it's more fixes! (#863) * Send stack trace to the UI on prod mode * Pdfs will now generate cover images. I missed something a few releases ago. * Ignore @Recently-Snapshot directories for QNAP. * Refactored Bitmap code to use ImageSharp so it's truly cross platform. * Updated pdf extraction to use a multi-threaded approach to greatly speed up pdf image extraction * Hooked in Characters tag from ComicInfo.xml * Bump versions by dotnet-bump-version. * Added check to see if mount folder is empty (#871) * Added check for if mount folder is empty * updating log message * Adding unit test * Bump versions by dotnet-bump-version. * Reader Fixes and Enhancements (#880) * Don't show an exception when bookmarking doesn't have anything to change. * Cleaned up the bookmark code a bit. * Implemented fullscreen mode in the web reader. Refactored User Settings to move Password and 3rd Party Clients to a tab rather than accordion. Removed color filters for web reader. * Implemented fullscreen mode into book reader * Added some code for toggling fullscreen which re-renders the screen to ensure the fitting works optimially * Fixed an issue where moving from FitToScreen -> Split (L/R) wouldn't render the screen correctly due to canvas not being reset. * Fixed bad optimization and scaling when drawing fit to screen * Removed left/right highlights on page direction change in favor for icons. Double arrow will dictate the page change. * Reduced overlay auto close time to 3 seconds * Updated the paginging direction overlay to use icons and colors. Added a blur effect on menus * Removed debug flags * Bump versions by dotnet-bump-version. * Fixed a bug with OPDS feeds not returning back results due to improperly setting up FilterDto. (#882) * Bump versions by dotnet-bump-version. * Bookmark Refactor (#893) * Fixed a bug which didn't take sort direction when not changing sort field * Added foundation for Bookmark refactor * Code broken, need to take a break. Issue is Getting bookmark image needs authentication but UI doesn't send. * Implemented the ability to send bookmarked files to the web. Implemented ability to clear bookmarks on disk on a re-occuring basis. * Updated the bookmark design to have it's own card that is self contained. View bookmarks modal has been updated to better lay out the cards. * Refactored download bookmark codes to select files from bookmark directory directly rather than open underlying files. * Wrote the basic logic to kick start the bookmark migration. Added Installed Version into the DB to allow us to know more accurately when to run migrations * Implemented the ability to change the bookmarks directory * Updated all references to BookmarkDirectory to use setting from the DB. Updated Server Settings page to use 2 col for some rows. * Refactored some code to DirectoryService (hasWriteAccess) and fixed up some unit tests from a previous PR. * Treat folders that start with ._ as blacklisted. * Implemented Reset User preferences. Some extra code to prep for the migration. * Implemented a migration for existing bookmarks to using new filesystem based bookmarks * Bump versions by dotnet-bump-version. * Only admins should be able to create new users (#896) * Bump versions by dotnet-bump-version. * Backup on Migrations (#898) * Refactored how the migrations are run. * A backup will be performed before any migrations. Added additional guards before a sub-module is loaded. * Bump versions by dotnet-bump-version. * Fixed a critical bug where registration was broken for first time flow. Refactored how backup before migrations occured such that it now puts the db in temp. The db will be deleted automatically that night. (#900) * Bump versions by dotnet-bump-version. * Fixed lack of ability to scroll with fullscreen mode (#903) * Bump versions by dotnet-bump-version. * Book Reader Issues (#906) * Refactored the Font Escaping Regex with new unit tests. * Fonts are now properly escaped, somehow a regression was introduced. * Refactored most of the book page loading for the reader into the service. * Fixed a bug where going into fullscreen in non dark mode will cause the background of the reader to go black. Fixed a rendering issue with margin left/right screwing html up. Fixed an issue where line-height: 100% would break book's css, now we remove the styles if they are non-valuable. * Changed how I fixed the black mode in fullscreen * Fixed an issue where anchors wouldn't be colored blue in white mode * Fixed a bug in the code that checks if a filename is a cover where it would choose "backcover" as a cover, despite it not being a valid case. * Validate if ReleaseYear is a valid year and if not, set it to 0 to disable it. * Fixed an issue where some large images could blow out the screen when reading on mobile. Now images will force to be max of width of browser * Put my hack back in for fullscreen putting background color to black * Change forwarded headers from All to explicit names * Fixed an issue where Scheme was not https when it should have been. Now the browser will handle which scheme to request. * Cleaned up the user preferences to stack multiple controls onto one row * Fixed fullscreen scroll issue with progress, but now sticky top is missing. * Corrected the element on which we fullscreen * Bump versions by dotnet-bump-version. * Fixed a bug where loading page on book reader wouldn't scroll to last position (#907) * Bump versions by dotnet-bump-version. * Metadata Optimizations (#910) * Added a tooltip to inform user that format and collection filter selections do not only show for the selected library. * Refactored a lot of code around when we update chapter cover images. Applied an optimization for when we re-calculate volume/series covers, such that it only occurs when the first chapter's image updates. * Updated code to ensure only lastmodified gets refreshed in metadata since it always follows a scan * Optimized how metadata is populated on the series. Instead of re-reading the comicInfos, instead I read the data from the underlying chapter entities. This reduces N additional reads AND enables the ability in the future to show/edit chapter level metadata. * Spelling mistake * Fixed a concurency issue by not selecting Genres from DB. Added a test for long paths. * Fixed a bug in filter where collection tag wasn't populating on load * Cleaned up the logic for changelog to better compare against the installed verison. For nightly users, show the last stable as installed. * Removed some demo code * SplitQuery to allow loading tags much faster for series metadata load. * Bump versions by dotnet-bump-version. * Fixed the book reader off by one issue with loading last page (#911) * Bump versions by dotnet-bump-version. * Misc Fixes (#914) * Fixed the book reader off by one issue with loading last page * Fixed a case where scanner would not delete a series if another series with same name but different format was added in that same scan. * Added some missing tag generation (chapter language and summary) * Bump versions by dotnet-bump-version. * Implemented Publication Status in SeriesMetadata and the ability to filter it. (#915) * Bump versions by dotnet-bump-version. * Book Reader Issue Take 2 (#916) * Implemented Publication Status in SeriesMetadata and the ability to filter it. * Updated the docs for Language on metadata to specify it's a BCP-47 code to match Anansi Project. Fixed a bug with reader from previous PR. * Bump versions by dotnet-bump-version. * Don't tag a series as completed if count is 0. (#917) * Bump versions by dotnet-bump-version. * Last Page Rendering Twice on Web Reader Fix (#920) * Don't tag a series as completed if count is 0. * Removed some dead code and added some spacers for when certain fields are disabled so filter section still looks good. * Fixed a bug where last page of a manga reader would be rendered twice when paging backwards. * Bump versions by dotnet-bump-version. * Metadata Performance Scan (#921) * Refactored updating chapter metadata from ComicInfo into the Scan loop. This let's us avoid an additional N file reads (expensive) in the metadata service, as we already have to read them in the scan loop. * Refactored Series level metadata aggregation into the scan loop. This allows for the batching of DB updates to be much smaller, thus faster without much overhead of GC. * Refactored some of the code for ProcessFile to remove a few redundant if statements * Fixed broken build (#922) * Bump versions by dotnet-bump-version. * Bump versions by dotnet-bump-version. * Misc Fixes and Changes (#927) * Cleaned up a ton of warnings/suggestions from the IDE. * Fixed a bug when clearing the filters some presets could be undone. * Renamed a class in the OPDS spec * Simplified logic for when Fit To Screen rendering logic occurs. It now works always rather than only on cover images. * Give some additional info to the user on what the differences between Library Types are * Don't scan .qpkg folders (QNAP devices) * Refactored some code to enable ability to test CoverImage Test. This is a broken test, test.zip is waiting on an issue in NetVips. * Fixed an issue where Extra might get flagged as special too early, if in a word like Extraordinary * Cleaned up the regex for the extra issue to be more flexible * Bump versions by dotnet-bump-version. * Bump follow-redirects from 1.13.0 to 1.14.7 in /UI/Web (#929) Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.13.0 to 1.14.7. - [Release notes](https://github.com/follow-redirects/follow-redirects/releases) - [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.13.0...v1.14.7) --- updated-dependencies: - dependency-name: follow-redirects dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Fixed a bug in CleanupBookmarks where the Except was deleting all files because the path separators didn't match. (#932) * Bump versions by dotnet-bump-version. * Bump versions by dotnet-bump-version. * Feature/parse scanned files tests (#934) * Fixed a bug in CleanupBookmarks where the Except was deleting all files because the path separators didn't match. * Added unit tests for ParseScannedFiles.cs. * Fixed some unit tests. Parser will now clear out multiple spaces in a row and replace with a single. * Bump versions by dotnet-bump-version. * Performance Enhancements (#937) * Bump versions by dotnet-bump-version. * Unit Tests & New Natural Sort (#941) * Added a lot of tests * More tests! Added a Parser.NormalizePath to normalize all paths within Kavita. * Fixed a bug where MarkChaptersAsUnread implementation wasn't consistent between different files and lead to extra row generation for no reason. * Added more unit tests * Found a better implementation for Natural Sorting. Added tests and validate it works. Next commit will swap out natural Sort for new Extension. * Replaced NaturalSortComparer with OrderByNatural. * Drastically simplified and sped up FindFirstEntry for finding cover images in archives * Initial fix for a epub bug where metadata defines key as absolute path but document uses a relative path. We now have a hack to correct for the epub. * Bump versions by dotnet-bump-version. * Fix image aspect ratio in rare case (#935) * Bump versions by dotnet-bump-version. * Fixed missing handlers for adding a chapter to a reading list from card details modal and adding series to collection from series detail. (#942) * Bump versions by dotnet-bump-version. * Bump versions by dotnet-bump-version. * Metadata Tags (#947) * Implemented the ability to click a metadata tag (in series detail) and load a pre-filtered view. Apply still needs to be implemented (preset load is out of sync with external filter) * Refactored people to properly use typeahead so duplicates don't happen and use an observable chain so we can update the screen correctly * Many refactoring to ensure that the timings for filtering always works * Bump versions by dotnet-bump-version. * Removed a hack that was put in when users complained about a tool improperly tagging. This is not the case for most tools. (#949) * Scanner not merging with series that has LocalizedName match (#950) * When performing a scan, series should group if they share the same localized name as a pre-existing series. * Fixed a bug where a series with a different name and localized name weren't merging with a different set of files with the same naming as localized name. * Bump versions by dotnet-bump-version. * Bump versions by dotnet-bump-version. * Bump versions by dotnet-bump-version. * Reader Fixes (#951) * Normalized paths on download controller and when scan is killed due to missing or empty folders, log a critical error. * Tweaked the query for OnDeck to better promote recently added chapters in a series with read progress, but it's still not perfect. * Fixed an issue where up/down key weren't working unless you clicked on the book explicitly * Fixed an issue where infinite scroller was broken in fullscreen mode * When toggling fullscreen mode on infinite scroller, the current page is retained as current position * Fixed an issue where a double render would occur when we didn't need to render as fit split * Stop showing loader when not using fit split * Bump versions by dotnet-bump-version. * Shakeout testing Fixes (#952) * Cleaned up some old code in download bookmark that could create pointless temp folders. * Fixed a bad http call on reading list remove read and cleaned up the messaging * Undid an optimization in finding cover image due to it perfoming depth first rather than breadth. * Updated CleanComicInfo to have Translators and CoverArtists, which were previously missing. * Renamed Refresh Metadata to Refresh Covers on the UI, given Metadata refresh is done in Scan. * Library detail will now retain the search query in the UI. Reduced the amount of api calls to the backend on load. * Reverted allowing the filter to reside in the UI (even though it does work). * Updated the Age Rating to match the v2.1 spec. * Fixed a bug where progress wasn't being saved * Fixed line height not having any effect due to not applying to children elements in the reader * Fixed some wording for Refresh Covers confirmation * Delete Series will now send an event to the UI informing that series was deleted. * Change Progress widget to show Refreshing Covers for * When we exit early due to potential missing folders/drives in a scan, tell the UI that scan is 100% done. * Fixed manage library not supressing scan loader when a complete came in * Fixed a spelling difference for Publication Status between filter and series detail * Fixed a bug where collection detail page would flash on first load due to duplicate load events * Added bookmarks to backups * Fixed issues where fullscreen mode would break infinite scroller contiunous reader * Bump versions by dotnet-bump-version. * Fixed GetTags having wrong return type defined (#954) * Bump versions by dotnet-bump-version. * Missing Age Ratings (#955) * Fixed GetTags having wrong return type defined * Added missing Age Rating tags * Bump versions by dotnet-bump-version. * Version bump for release (#953) Co-authored-by: Robbie Davis Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Andrew Mackrodt --- .github/ISSUE_TEMPLATE/bug_report.md | 2 +- .github/workflows/sonar-scan.yml | 133 +- .gitignore | 6 +- API.Benchmark/API.Benchmark.csproj | 2 +- API.Benchmark/ParseScannedFilesBenchmarks.cs | 10 +- API.Benchmark/TestBenchmark.cs | 8 +- API.Tests/API.Tests.csproj | 7 +- .../ChapterSortComparerZeroFirstTests.cs | 17 + API.Tests/Comparers/NumericComparerTests.cs | 26 + .../Comparers/StringLogicalComparerTest.cs | 19 +- API.Tests/Converters/CronConverterTests.cs | 4 +- API.Tests/Entities/ComicInfoTests.cs | 38 + .../Extensions/ChapterListExtensionsTests.cs | 49 +- .../EnumerableExtensionsTests.cs} | 72 +- .../Extensions/FilterDtoExtensionsTests.cs | 48 + .../ParserInfoListExtensionsTests.cs | 18 +- API.Tests/Extensions/PathExtensionsTests.cs | 20 + API.Tests/Extensions/SeriesExtensionsTests.cs | 39 +- .../Extensions/VolumeListExtensionsTests.cs | 177 ++ API.Tests/Helpers/CacheHelperTests.cs | 293 ++++ API.Tests/Helpers/EntityFactory.cs | 7 +- API.Tests/Helpers/GenreHelperTests.cs | 110 ++ API.Tests/Helpers/ParserInfoFactory.cs | 52 +- API.Tests/Helpers/ParserInfoHelperTests.cs | 75 + API.Tests/Helpers/PersonHelperTests.cs | 140 ++ API.Tests/Helpers/SeriesHelperTests.cs | 160 ++ API.Tests/Helpers/TagHelperTests.cs | 119 ++ API.Tests/Parser/ComicParserTests.cs | 104 +- API.Tests/Parser/DefaultParserTests.cs | 312 ++++ API.Tests/Parser/MangaParserTests.cs | 196 +-- API.Tests/Parser/ParserInfoTests.cs | 18 +- API.Tests/Parser/ParserTest.cs | 78 +- API.Tests/Services/ArchiveServiceTests.cs | 141 +- API.Tests/Services/BackupServiceTests.cs | 143 ++ API.Tests/Services/BookServiceTests.cs | 40 +- API.Tests/Services/CacheServiceTests.cs | 583 +++++-- API.Tests/Services/CleanupServiceTests.cs | 433 +++++ API.Tests/Services/DirectoryServiceTests.cs | 754 ++++++++- API.Tests/Services/FileSystemTests.cs | 44 + API.Tests/Services/MetadataServiceTests.cs | 119 +- API.Tests/Services/ParseScannedFilesTests.cs | 314 ++++ API.Tests/Services/ReaderServiceTests.cs | 814 +++++++++ API.Tests/Services/ScannerServiceTests.cs | 165 +- .../ComicInfos/ComicInfo_authors.zip | Bin 0 -> 913 bytes .../CoverImages/output/test2_output.png | Bin 0 -> 92095 bytes .../CoverImages/test.expected.jpg | Bin 0 -> 1125792 bytes .../ArchiveService/CoverImages/test.zip | Bin 0 -> 1055238 bytes ... Floes A Story of the Whaling Grounds.epub | Bin 258623 -> 258785 bytes .../Test Data/BookService/EPUB/content.opf | 81 + API.Tests/generate_test_data.py | 80 - API/API.csproj | 42 +- API/API.csproj.DotSettings | 3 +- API/Comparators/ChapterSortComparer.cs | 2 +- API/Comparators/NaturalSortComparer.cs | 106 -- API/Controllers/AccountController.cs | 7 +- API/Controllers/BookController.cs | 236 +-- API/Controllers/CollectionController.cs | 6 +- API/Controllers/DownloadController.cs | 112 +- API/Controllers/FallbackController.cs | 6 +- API/Controllers/ImageController.cs | 61 +- API/Controllers/LibraryController.cs | 4 +- API/Controllers/MetadataController.cs | 140 ++ API/Controllers/OPDSController.cs | 1457 +++++++++-------- API/Controllers/PluginController.cs | 4 +- API/Controllers/ReaderController.cs | 59 +- API/Controllers/ReadingListController.cs | 5 +- API/Controllers/SeriesController.cs | 39 +- API/Controllers/ServerController.cs | 10 +- API/Controllers/SettingsController.cs | 60 +- API/Controllers/UploadController.cs | 3 +- API/Controllers/UsersController.cs | 2 +- API/DTOs/ChapterDto.cs | 38 + API/DTOs/Filtering/FilterDto.cs | 91 +- API/DTOs/Filtering/LanguageDto.cs | 7 + API/DTOs/Filtering/ReadStatus.cs | 13 + API/DTOs/Filtering/SortField.cs | 8 + API/DTOs/Filtering/SortOptions.cs | 10 + API/DTOs/Metadata/AgeRatingDto.cs | 9 + API/DTOs/Metadata/ChapterMetadataDto.cs | 19 + API/DTOs/Metadata/GenreTagDto.cs | 8 + API/DTOs/Metadata/PublicationStatusDto.cs | 9 + API/DTOs/Metadata/TagDto.cs | 7 + API/DTOs/OPDS/Feed.cs | 2 +- API/DTOs/OPDS/{Author.cs => FeedAuthor.cs} | 2 +- API/DTOs/PersonDto.cs | 3 +- API/DTOs/Reader/BookInfoDto.cs | 1 + API/DTOs/Reader/ChapterInfoDto.cs | 5 +- API/DTOs/Reader/IChapterInfoDto.cs | 1 + API/DTOs/SeriesMetadataDto.cs | 57 +- API/DTOs/Settings/ServerSettingDTO.cs | 9 +- API/DTOs/Update/UpdateNotificationDto.cs | 4 +- API/DTOs/UserPreferencesDto.cs | 2 +- API/Data/DataContext.cs | 5 +- API/Data/DbFactory.cs | 55 +- API/Data/Metadata/ComicInfo.cs | 126 +- API/Data/MigrateBookmarks.cs | 102 ++ API/Data/MigrateConfigFiles.cs | 46 +- API/Data/MigrateCoverImages.cs | 28 +- ...11127200244_MetadataFoundation.Designer.cs | 1215 ++++++++++++++ .../20211127200244_MetadataFoundation.cs | 203 +++ ...29231007_RemoveChapterMetadata.Designer.cs | 1232 ++++++++++++++ .../20211129231007_RemoveChapterMetadata.cs | 138 ++ .../20211130134642_GenreProvider.Designer.cs | 1182 +++++++++++++ .../20211130134642_GenreProvider.cs | 86 + .../20211201230003_GenreTitle.Designer.cs | 1196 ++++++++++++++ .../Migrations/20211201230003_GenreTitle.cs | 85 + ...211205185207_MetadataAgeRating.Designer.cs | 1199 ++++++++++++++ .../20211205185207_MetadataAgeRating.cs | 26 + ...193225_AgeRatingAndReleaseDate.Designer.cs | 1208 ++++++++++++++ .../20211206193225_AgeRatingAndReleaseDate.cs | 49 + ...0211217013734_BookmarkRefactor.Designer.cs | 1317 +++++++++++++++ .../20211217013734_BookmarkRefactor.cs | 25 + ...0211217180457_filteringChanges.Designer.cs | 1314 +++++++++++++++ .../20211217180457_filteringChanges.cs | 155 ++ .../20211227180752_FullscreenPref.Designer.cs | 1317 +++++++++++++++ .../20211227180752_FullscreenPref.cs | 26 + ...22_ChapterMetadataOptimization.Designer.cs | 1339 +++++++++++++++ ...20107232822_ChapterMetadataOptimization.cs | 108 ++ .../20220108200822_CountMetadata.Designer.cs | 1345 +++++++++++++++ .../20220108200822_CountMetadata.cs | 37 + ...220108202027_PublicationStatus.Designer.cs | 1351 +++++++++++++++ .../20220108202027_PublicationStatus.cs | 37 + .../Migrations/DataContextModelSnapshot.cs | 402 ++++- .../Repositories/AppUserProgressRepository.cs | 124 +- API/Data/Repositories/ChapterRepository.cs | 341 ++-- .../Repositories/CollectionTagRepository.cs | 212 +-- API/Data/Repositories/FileRepository.cs | 35 - API/Data/Repositories/GenreRepository.cs | 86 + API/Data/Repositories/LibraryRepository.cs | 384 ++--- API/Data/Repositories/PersonRepository.cs | 79 + .../Repositories/ReadingListRepository.cs | 300 ++-- .../Repositories/SeriesMetadataRepository.cs | 31 +- API/Data/Repositories/SeriesRepository.cs | 1230 ++++++++------ API/Data/Repositories/SettingsRepository.cs | 67 +- API/Data/Repositories/TagRepository.cs | 86 + API/Data/Repositories/UserRepository.cs | 481 +++--- API/Data/Repositories/VolumeRepository.cs | 410 ++--- API/Data/Seed.cs | 20 +- API/Data/UnitOfWork.cs | 154 +- API/Dockerfile | 4 +- API/Entities/AppUserBookmark.cs | 5 + API/Entities/Chapter.cs | 44 + API/Entities/CollectionTag.cs | 1 + API/Entities/Enums/AgeRating.cs | 43 + API/Entities/Enums/LibraryType.cs | 9 + API/Entities/Enums/PersonRole.cs | 32 +- API/Entities/Enums/PublicationStatus.cs | 23 + API/Entities/Enums/ServerSettingKey.cs | 13 +- API/Entities/Genre.cs | 24 +- API/Entities/MangaFile.cs | 13 +- API/Entities/Metadata/ChapterMetadata.cs | 34 + API/Entities/Metadata/SeriesMetadata.cs | 58 + API/Entities/Person.cs | 25 +- API/Entities/Series.cs | 7 +- API/Entities/SeriesMetadata.cs | 29 - API/Entities/Tag.cs | 17 + .../ApplicationServiceExtensions.cs | 12 +- API/Extensions/DateTimeExtensions.cs | 18 + API/Extensions/DirectoryInfoExtensions.cs | 86 - API/Extensions/EnumerableExtensions.cs | 31 +- API/Extensions/FilterDtoExtensions.cs | 11 +- API/Extensions/HttpExtensions.cs | 7 +- API/Extensions/IdentityServiceExtensions.cs | 7 +- API/Extensions/ParserInfoListExtensions.cs | 20 +- API/Extensions/PathExtensions.cs | 14 + API/Extensions/SeriesExtensions.cs | 2 +- API/Extensions/StringExtensions.cs | 13 + API/Extensions/VolumeListExtensions.cs | 6 +- API/Helpers/AutoMapperProfiles.cs | 101 +- API/Helpers/CacheHelper.cs | 73 + API/Helpers/Converters/CronConverter.cs | 24 +- .../Converters/ServerSettingConverter.cs | 3 + API/Helpers/GenreHelper.cs | 64 + API/Helpers/ParserInfoHelpers.cs | 50 + API/Helpers/PersonHelper.cs | 96 ++ API/Helpers/SQLHelper.cs | 1 + API/Helpers/SeriesHelper.cs | 46 + API/Helpers/TagHelper.cs | 90 + API/Interfaces/ITaskScheduler.cs | 22 - API/Interfaces/IUnitOfWork.cs | 25 - .../IAppUserProgressRepository.cs | 14 - .../Repositories/IChapterRepository.cs | 24 - .../Repositories/ICollectionTagRepository.cs | 24 - .../Repositories/IFileRepository.cs | 10 - .../Repositories/ILibraryRepository.cs | 26 - .../Repositories/IReadingListRepository.cs | 22 - .../Repositories/ISeriesMetadataRepository.cs | 9 - .../Repositories/ISeriesRepository.cs | 62 - .../Repositories/ISettingsRepository.cs | 17 - .../Repositories/IUserRepository.cs | 33 - .../Repositories/IVolumeRepository.cs | 25 - API/Interfaces/Services/IAccountService.cs | 12 - API/Interfaces/Services/IArchiveService.cs | 21 - API/Interfaces/Services/IBackupService.cs | 20 - API/Interfaces/Services/IBookService.cs | 33 - API/Interfaces/Services/ICacheService.cs | 41 - API/Interfaces/Services/ICleanupService.cs | 10 - API/Interfaces/Services/IDirectoryService.cs | 20 - API/Interfaces/Services/IImageService.cs | 23 - API/Interfaces/Services/IMetadataService.cs | 25 - API/Interfaces/Services/IReaderService.cs | 17 - API/Interfaces/Services/IScannerService.cs | 18 - API/Interfaces/Services/IStartupTask.cs | 10 - API/Interfaces/Services/IStatsService.cs | 11 - API/Interfaces/Services/ITokenService.cs | 10 - .../Services/IVersionUpdaterService.cs | 13 - API/Interfaces/Services/ReaderService.cs | 310 ---- API/Middleware/ExceptionMiddleware.cs | 14 +- API/Parser/DefaultParser.cs | 160 ++ API/Parser/Parser.cs | 259 ++- API/Parser/ParserInfo.cs | 22 +- API/Program.cs | 54 +- API/Services/AccountService.cs | 6 +- API/Services/ArchiveService.cs | 135 +- API/Services/BookService.cs | 297 +++- API/Services/CacheService.cs | 156 +- API/Services/DirectoryService.cs | 402 +++-- API/Services/DownloadService.cs | 80 +- API/Services/FileService.cs | 46 + .../StartupTasksHostedService.cs | 3 +- API/Services/ImageService.cs | 101 +- API/Services/MetadataService.cs | 613 +++---- API/Services/ReaderService.cs | 326 ++++ API/Services/ReadingItemService.cs | 141 ++ API/Services/TaskScheduler.cs | 291 ++-- API/Services/Tasks/BackupService.cs | 355 ++-- API/Services/Tasks/CleanupService.cs | 171 +- .../Tasks/Scanner/ParseScannedFiles.cs | 84 +- API/Services/Tasks/ScannerService.cs | 1381 +++++++++------- API/Services/Tasks/StatsService.cs | 165 +- API/Services/Tasks/VersionUpdaterService.cs | 301 ++-- API/Services/TokenService.cs | 79 +- API/Services/WarmupServiceStartupTask.cs | 43 - API/SignalR/MessageFactory.cs | 20 +- API/SignalR/Presence/PresenceTracker.cs | 2 +- API/SignalR/SignalREvents.cs | 26 +- API/SignalR/SignalRMessage.cs | 3 + API/Startup.cs | 71 +- Kavita.Common/Configuration.cs | 8 +- Kavita.Common/Kavita.Common.csproj | 10 +- UI/Web/package-lock.json | 201 ++- UI/Web/src/app/_models/chapter-metadata.ts | 16 + UI/Web/src/app/_models/chapter.ts | 17 + UI/Web/src/app/_models/genre.ts | 4 + .../app/_models/metadata/age-rating-dto.ts | 6 + UI/Web/src/app/_models/metadata/age-rating.ts | 15 + UI/Web/src/app/_models/metadata/language.ts | 4 + .../metadata/publication-status-dto.ts | 6 + .../_models/metadata/publication-status.ts | 5 + UI/Web/src/app/_models/page-bookmark.ts | 1 + UI/Web/src/app/_models/person.ts | 16 +- .../app/_models/preferences/preferences.ts | 1 + UI/Web/src/app/_models/series-filter.ts | 56 +- UI/Web/src/app/_models/series-metadata.ts | 25 +- UI/Web/src/app/_models/series.ts | 1 - UI/Web/src/app/_models/tag.ts | 4 + .../app/_services/action-factory.service.ts | 4 +- UI/Web/src/app/_services/action.service.ts | 33 +- UI/Web/src/app/_services/image.service.ts | 25 +- .../src/app/_services/message-hub.service.ts | 23 +- UI/Web/src/app/_services/metadata.service.ts | 87 + UI/Web/src/app/_services/nav.service.ts | 17 +- UI/Web/src/app/_services/reader.service.ts | 30 + .../src/app/_services/reading-list.service.ts | 2 +- UI/Web/src/app/_services/series.service.ts | 48 +- .../directory-picker.component.html | 3 +- .../directory-picker.component.ts | 40 +- .../library-editor-modal.component.html | 6 +- .../src/app/admin/_models/server-settings.ts | 1 + .../admin/changelog/changelog.component.html | 6 +- .../admin/changelog/changelog.component.ts | 19 +- .../manage-library.component.ts | 6 +- .../manage-settings.component.html | 45 +- .../manage-settings.component.ts | 29 +- UI/Web/src/app/admin/settings.service.ts | 4 + .../app/all-series/all-series.component.html | 14 + .../app/all-series/all-series.component.scss | 0 .../app/all-series/all-series.component.ts | 145 ++ UI/Web/src/app/app-routing.module.ts | 8 + UI/Web/src/app/app.component.ts | 8 +- UI/Web/src/app/app.module.ts | 10 +- .../book-reader/book-reader.component.html | 28 +- .../book-reader/book-reader.component.scss | 24 +- .../book-reader/book-reader.component.ts | 98 +- .../bookmarks-modal.component.html | 19 +- .../bookmarks-modal.component.ts | 4 + .../card-details-modal.component.html | 7 +- .../card-details-modal.component.ts | 3 + .../edit-series-modal.component.ts | 7 +- .../cards/bookmark/bookmark.component.html | 28 + .../cards/bookmark/bookmark.component.scss | 25 + .../app/cards/bookmark/bookmark.component.ts | 43 + .../card-detail-layout.component.html | 350 +++- .../card-detail-layout.component.scss | 9 + .../card-detail-layout.component.ts | 555 ++++++- .../cards/card-item/card-item.component.html | 6 +- .../cards/card-item/card-item.component.scss | 13 +- .../cards/card-item/card-item.component.ts | 18 +- UI/Web/src/app/cards/cards.module.ts | 14 +- .../chapter-metadata-detail.component.html | 114 ++ .../chapter-metadata-detail.component.scss | 0 .../chapter-metadata-detail.component.ts | 53 + .../cards/file-info/file-info.component.html | 11 + .../cards/file-info/file-info.component.scss | 0 .../cards/file-info/file-info.component.ts | 25 + .../series-card/series-card.component.ts | 30 +- .../collection-detail.component.html | 2 +- .../collection-detail.component.scss | 2 +- .../collection-detail.component.ts | 25 +- .../library-detail.component.html | 4 +- .../library-detail.component.ts | 36 +- UI/Web/src/app/library/library.component.html | 2 +- UI/Web/src/app/library/library.component.ts | 2 + .../app/manga-reader/_models/reader-enums.ts | 5 - .../infinite-scroller.component.html | 5 +- .../infinite-scroller.component.scss | 4 + .../infinite-scroller.component.ts | 119 +- .../manga-reader/manga-reader.component.html | 27 +- .../manga-reader/manga-reader.component.scss | 46 +- .../manga-reader/manga-reader.component.ts | 263 +-- .../nav-events-toggle.component.html | 9 +- .../nav-events-toggle.component.scss | 13 +- .../nav-events-toggle.component.ts | 34 +- .../app/nav-header/nav-header.component.scss | 2 +- UI/Web/src/app/on-deck/on-deck.component.html | 3 +- UI/Web/src/app/on-deck/on-deck.component.ts | 16 +- .../person-badge/person-badge.component.html | 12 - UI/Web/src/app/person-role.pipe.ts | 26 + UI/Web/src/app/publication-status.pipe.ts | 19 + .../reading-list-detail.component.ts | 6 +- .../recently-added.component.html | 4 +- .../recently-added.component.ts | 16 +- .../register-member.component.html | 8 +- UI/Web/src/app/scroll.service.ts | 6 +- .../series-detail.component.html | 48 +- .../series-detail/series-detail.component.ts | 59 +- .../series-metadata-detail.component.html | 192 +++ .../series-metadata-detail.component.scss | 6 + .../series-metadata-detail.component.ts | 69 + .../app/shared/_services/utility.service.ts | 120 ++ .../badge-expander.component.html | 8 + .../badge-expander.component.scss | 12 + .../badge-expander.component.ts | 32 + .../person-badge/person-badge.component.html | 9 + .../person-badge/person-badge.component.scss | 10 +- .../person-badge/person-badge.component.ts | 6 +- UI/Web/src/app/shared/shared.module.ts | 9 +- .../app/typeahead/typeahead.component.html | 3 +- .../app/typeahead/typeahead.component.scss | 11 +- .../src/app/typeahead/typeahead.component.ts | 18 +- .../user-preferences.component.html | 312 ++-- .../user-preferences.component.ts | 2 + .../app/user-settings/user-settings.module.ts | 2 + UI/Web/src/assets/themes/dark.scss | 4 + UI/Web/src/styles.scss | 24 +- UI/Web/src/theme/_colors.scss | 14 + build.sh | 16 +- docker-build.sh | 20 +- global.json | 7 + monorepo-build.sh | 6 +- 360 files changed, 33758 insertions(+), 8073 deletions(-) create mode 100644 API.Tests/Comparers/ChapterSortComparerZeroFirstTests.cs create mode 100644 API.Tests/Comparers/NumericComparerTests.cs create mode 100644 API.Tests/Entities/ComicInfoTests.cs rename API.Tests/{Comparers/NaturalSortComparerTest.cs => Extensions/EnumerableExtensionsTests.cs} (64%) create mode 100644 API.Tests/Extensions/FilterDtoExtensionsTests.cs create mode 100644 API.Tests/Extensions/PathExtensionsTests.cs create mode 100644 API.Tests/Extensions/VolumeListExtensionsTests.cs create mode 100644 API.Tests/Helpers/CacheHelperTests.cs create mode 100644 API.Tests/Helpers/GenreHelperTests.cs create mode 100644 API.Tests/Helpers/ParserInfoHelperTests.cs create mode 100644 API.Tests/Helpers/PersonHelperTests.cs create mode 100644 API.Tests/Helpers/SeriesHelperTests.cs create mode 100644 API.Tests/Helpers/TagHelperTests.cs create mode 100644 API.Tests/Parser/DefaultParserTests.cs create mode 100644 API.Tests/Services/BackupServiceTests.cs create mode 100644 API.Tests/Services/CleanupServiceTests.cs create mode 100644 API.Tests/Services/FileSystemTests.cs create mode 100644 API.Tests/Services/ParseScannedFilesTests.cs create mode 100644 API.Tests/Services/ReaderServiceTests.cs create mode 100644 API.Tests/Services/Test Data/ArchiveService/ComicInfos/ComicInfo_authors.zip create mode 100644 API.Tests/Services/Test Data/ArchiveService/CoverImages/output/test2_output.png create mode 100644 API.Tests/Services/Test Data/ArchiveService/CoverImages/test.expected.jpg create mode 100644 API.Tests/Services/Test Data/ArchiveService/CoverImages/test.zip create mode 100644 API.Tests/Services/Test Data/BookService/EPUB/content.opf delete mode 100644 API.Tests/generate_test_data.py delete mode 100644 API/Comparators/NaturalSortComparer.cs create mode 100644 API/Controllers/MetadataController.cs create mode 100644 API/DTOs/Filtering/LanguageDto.cs create mode 100644 API/DTOs/Filtering/ReadStatus.cs create mode 100644 API/DTOs/Filtering/SortField.cs create mode 100644 API/DTOs/Filtering/SortOptions.cs create mode 100644 API/DTOs/Metadata/AgeRatingDto.cs create mode 100644 API/DTOs/Metadata/ChapterMetadataDto.cs create mode 100644 API/DTOs/Metadata/GenreTagDto.cs create mode 100644 API/DTOs/Metadata/PublicationStatusDto.cs create mode 100644 API/DTOs/Metadata/TagDto.cs rename API/DTOs/OPDS/{Author.cs => FeedAuthor.cs} (88%) create mode 100644 API/Data/MigrateBookmarks.cs create mode 100644 API/Data/Migrations/20211127200244_MetadataFoundation.Designer.cs create mode 100644 API/Data/Migrations/20211127200244_MetadataFoundation.cs create mode 100644 API/Data/Migrations/20211129231007_RemoveChapterMetadata.Designer.cs create mode 100644 API/Data/Migrations/20211129231007_RemoveChapterMetadata.cs create mode 100644 API/Data/Migrations/20211130134642_GenreProvider.Designer.cs create mode 100644 API/Data/Migrations/20211130134642_GenreProvider.cs create mode 100644 API/Data/Migrations/20211201230003_GenreTitle.Designer.cs create mode 100644 API/Data/Migrations/20211201230003_GenreTitle.cs create mode 100644 API/Data/Migrations/20211205185207_MetadataAgeRating.Designer.cs create mode 100644 API/Data/Migrations/20211205185207_MetadataAgeRating.cs create mode 100644 API/Data/Migrations/20211206193225_AgeRatingAndReleaseDate.Designer.cs create mode 100644 API/Data/Migrations/20211206193225_AgeRatingAndReleaseDate.cs create mode 100644 API/Data/Migrations/20211217013734_BookmarkRefactor.Designer.cs create mode 100644 API/Data/Migrations/20211217013734_BookmarkRefactor.cs create mode 100644 API/Data/Migrations/20211217180457_filteringChanges.Designer.cs create mode 100644 API/Data/Migrations/20211217180457_filteringChanges.cs create mode 100644 API/Data/Migrations/20211227180752_FullscreenPref.Designer.cs create mode 100644 API/Data/Migrations/20211227180752_FullscreenPref.cs create mode 100644 API/Data/Migrations/20220107232822_ChapterMetadataOptimization.Designer.cs create mode 100644 API/Data/Migrations/20220107232822_ChapterMetadataOptimization.cs create mode 100644 API/Data/Migrations/20220108200822_CountMetadata.Designer.cs create mode 100644 API/Data/Migrations/20220108200822_CountMetadata.cs create mode 100644 API/Data/Migrations/20220108202027_PublicationStatus.Designer.cs create mode 100644 API/Data/Migrations/20220108202027_PublicationStatus.cs delete mode 100644 API/Data/Repositories/FileRepository.cs create mode 100644 API/Data/Repositories/GenreRepository.cs create mode 100644 API/Data/Repositories/PersonRepository.cs create mode 100644 API/Data/Repositories/TagRepository.cs create mode 100644 API/Entities/Enums/AgeRating.cs create mode 100644 API/Entities/Enums/PublicationStatus.cs create mode 100644 API/Entities/Metadata/ChapterMetadata.cs create mode 100644 API/Entities/Metadata/SeriesMetadata.cs delete mode 100644 API/Entities/SeriesMetadata.cs create mode 100644 API/Entities/Tag.cs create mode 100644 API/Extensions/DateTimeExtensions.cs delete mode 100644 API/Extensions/DirectoryInfoExtensions.cs create mode 100644 API/Extensions/PathExtensions.cs create mode 100644 API/Extensions/StringExtensions.cs create mode 100644 API/Helpers/CacheHelper.cs create mode 100644 API/Helpers/GenreHelper.cs create mode 100644 API/Helpers/ParserInfoHelpers.cs create mode 100644 API/Helpers/PersonHelper.cs create mode 100644 API/Helpers/SeriesHelper.cs create mode 100644 API/Helpers/TagHelper.cs delete mode 100644 API/Interfaces/ITaskScheduler.cs delete mode 100644 API/Interfaces/IUnitOfWork.cs delete mode 100644 API/Interfaces/Repositories/IAppUserProgressRepository.cs delete mode 100644 API/Interfaces/Repositories/IChapterRepository.cs delete mode 100644 API/Interfaces/Repositories/ICollectionTagRepository.cs delete mode 100644 API/Interfaces/Repositories/IFileRepository.cs delete mode 100644 API/Interfaces/Repositories/ILibraryRepository.cs delete mode 100644 API/Interfaces/Repositories/IReadingListRepository.cs delete mode 100644 API/Interfaces/Repositories/ISeriesMetadataRepository.cs delete mode 100644 API/Interfaces/Repositories/ISeriesRepository.cs delete mode 100644 API/Interfaces/Repositories/ISettingsRepository.cs delete mode 100644 API/Interfaces/Repositories/IUserRepository.cs delete mode 100644 API/Interfaces/Repositories/IVolumeRepository.cs delete mode 100644 API/Interfaces/Services/IAccountService.cs delete mode 100644 API/Interfaces/Services/IArchiveService.cs delete mode 100644 API/Interfaces/Services/IBackupService.cs delete mode 100644 API/Interfaces/Services/IBookService.cs delete mode 100644 API/Interfaces/Services/ICacheService.cs delete mode 100644 API/Interfaces/Services/ICleanupService.cs delete mode 100644 API/Interfaces/Services/IDirectoryService.cs delete mode 100644 API/Interfaces/Services/IImageService.cs delete mode 100644 API/Interfaces/Services/IMetadataService.cs delete mode 100644 API/Interfaces/Services/IReaderService.cs delete mode 100644 API/Interfaces/Services/IScannerService.cs delete mode 100644 API/Interfaces/Services/IStartupTask.cs delete mode 100644 API/Interfaces/Services/IStatsService.cs delete mode 100644 API/Interfaces/Services/ITokenService.cs delete mode 100644 API/Interfaces/Services/IVersionUpdaterService.cs delete mode 100644 API/Interfaces/Services/ReaderService.cs create mode 100644 API/Parser/DefaultParser.cs create mode 100644 API/Services/FileService.cs create mode 100644 API/Services/ReaderService.cs create mode 100644 API/Services/ReadingItemService.cs delete mode 100644 API/Services/WarmupServiceStartupTask.cs create mode 100644 UI/Web/src/app/_models/chapter-metadata.ts create mode 100644 UI/Web/src/app/_models/genre.ts create mode 100644 UI/Web/src/app/_models/metadata/age-rating-dto.ts create mode 100644 UI/Web/src/app/_models/metadata/age-rating.ts create mode 100644 UI/Web/src/app/_models/metadata/language.ts create mode 100644 UI/Web/src/app/_models/metadata/publication-status-dto.ts create mode 100644 UI/Web/src/app/_models/metadata/publication-status.ts create mode 100644 UI/Web/src/app/_models/tag.ts create mode 100644 UI/Web/src/app/_services/metadata.service.ts create mode 100644 UI/Web/src/app/all-series/all-series.component.html create mode 100644 UI/Web/src/app/all-series/all-series.component.scss create mode 100644 UI/Web/src/app/all-series/all-series.component.ts create mode 100644 UI/Web/src/app/cards/bookmark/bookmark.component.html create mode 100644 UI/Web/src/app/cards/bookmark/bookmark.component.scss create mode 100644 UI/Web/src/app/cards/bookmark/bookmark.component.ts create mode 100644 UI/Web/src/app/cards/chapter-metadata-detail/chapter-metadata-detail.component.html create mode 100644 UI/Web/src/app/cards/chapter-metadata-detail/chapter-metadata-detail.component.scss create mode 100644 UI/Web/src/app/cards/chapter-metadata-detail/chapter-metadata-detail.component.ts create mode 100644 UI/Web/src/app/cards/file-info/file-info.component.html create mode 100644 UI/Web/src/app/cards/file-info/file-info.component.scss create mode 100644 UI/Web/src/app/cards/file-info/file-info.component.ts delete mode 100644 UI/Web/src/app/person-badge/person-badge.component.html create mode 100644 UI/Web/src/app/person-role.pipe.ts create mode 100644 UI/Web/src/app/publication-status.pipe.ts create mode 100644 UI/Web/src/app/series-metadata-detail/series-metadata-detail.component.html create mode 100644 UI/Web/src/app/series-metadata-detail/series-metadata-detail.component.scss create mode 100644 UI/Web/src/app/series-metadata-detail/series-metadata-detail.component.ts create mode 100644 UI/Web/src/app/shared/badge-expander/badge-expander.component.html create mode 100644 UI/Web/src/app/shared/badge-expander/badge-expander.component.scss create mode 100644 UI/Web/src/app/shared/badge-expander/badge-expander.component.ts create mode 100644 UI/Web/src/app/shared/person-badge/person-badge.component.html rename UI/Web/src/app/{ => shared}/person-badge/person-badge.component.scss (76%) rename UI/Web/src/app/{ => shared}/person-badge/person-badge.component.ts (64%) create mode 100644 global.json diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 1fe2d72e8..bfd2bab0a 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -9,7 +9,7 @@ assignees: '' **If this is a feature request, request [here](https://feats.kavitareader.com/) instead. Feature requests will be deleted from Github.** - +Please put as much information as possible to help me understand your issue. OS, browser, version are very important! **Describe the bug** A clear and concise description of what the bug is. diff --git a/.github/workflows/sonar-scan.yml b/.github/workflows/sonar-scan.yml index 48a93318a..6673f3f00 100644 --- a/.github/workflows/sonar-scan.yml +++ b/.github/workflows/sonar-scan.yml @@ -20,7 +20,8 @@ jobs: - name: Setup .NET Core uses: actions/setup-dotnet@v1 with: - dotnet-version: 5.0.100 + include-prerelease: True + dotnet-version: '6.0' - name: Install dependencies run: dotnet restore @@ -35,67 +36,68 @@ jobs: name: csproj path: Kavita.Common/Kavita.Common.csproj - test: - name: Install Sonar & Test - needs: build - runs-on: windows-latest - steps: - - name: Checkout Repo - uses: actions/checkout@v2 - with: - fetch-depth: 0 - - - name: Setup .NET Core - uses: actions/setup-dotnet@v1 - with: - dotnet-version: 5.0.100 - - - name: Install dependencies - run: dotnet restore - - - name: Set up JDK 11 - uses: actions/setup-java@v1 - with: - java-version: 1.11 - - - name: Cache SonarCloud packages - uses: actions/cache@v1 - with: - path: ~\sonar\cache - key: ${{ runner.os }}-sonar - restore-keys: ${{ runner.os }}-sonar - - - name: Cache SonarCloud scanner - id: cache-sonar-scanner - uses: actions/cache@v1 - with: - path: .\.sonar\scanner - key: ${{ runner.os }}-sonar-scanner - restore-keys: ${{ runner.os }}-sonar-scanner - - - name: Install SonarCloud scanner - if: steps.cache-sonar-scanner.outputs.cache-hit != 'true' - shell: powershell - run: | - New-Item -Path .\.sonar\scanner -ItemType Directory - dotnet tool update dotnet-sonarscanner --tool-path .\.sonar\scanner - - - name: Sonar Scan - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any - SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - shell: powershell - run: | - .\.sonar\scanner\dotnet-sonarscanner begin /k:"Kareadita_Kavita" /o:"kareadita" /d:sonar.login="${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="https://sonarcloud.io" - dotnet build --configuration Release - .\.sonar\scanner\dotnet-sonarscanner end /d:sonar.login="${{ secrets.SONAR_TOKEN }}" - - - name: Test - run: dotnet test --no-restore --verbosity normal +# test: +# name: Install Sonar & Test +# needs: build +# runs-on: windows-latest +# steps: +# - name: Checkout Repo +# uses: actions/checkout@v2 +# with: +# fetch-depth: 0 +# +# - name: Setup .NET Core +# uses: actions/setup-dotnet@v1 +# with: +# include-prerelease: True +# dotnet-version: '6.0' +# +# - name: Install dependencies +# run: dotnet restore +# +# - name: Set up JDK 11 +# uses: actions/setup-java@v1 +# with: +# java-version: 1.11 +# +# - name: Cache SonarCloud packages +# uses: actions/cache@v1 +# with: +# path: ~\sonar\cache +# key: ${{ runner.os }}-sonar +# restore-keys: ${{ runner.os }}-sonar +# +# - name: Cache SonarCloud scanner +# id: cache-sonar-scanner +# uses: actions/cache@v1 +# with: +# path: .\.sonar\scanner +# key: ${{ runner.os }}-sonar-scanner +# restore-keys: ${{ runner.os }}-sonar-scanner +# +# - name: Install SonarCloud scanner +# if: steps.cache-sonar-scanner.outputs.cache-hit != 'true' +# shell: powershell +# run: | +# New-Item -Path .\.sonar\scanner -ItemType Directory +# dotnet tool update dotnet-sonarscanner --tool-path .\.sonar\scanner +# +# - name: Sonar Scan +# env: +# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any +# SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} +# shell: powershell +# run: | +# .\.sonar\scanner\dotnet-sonarscanner begin /k:"Kareadita_Kavita" /o:"kareadita" /d:sonar.login="${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="https://sonarcloud.io" +# dotnet build --configuration Release +# .\.sonar\scanner\dotnet-sonarscanner end /d:sonar.login="${{ secrets.SONAR_TOKEN }}" +# +# - name: Test +# run: dotnet test --no-restore --verbosity normal version: name: Bump version on Develop push - needs: [ build, test ] + needs: [ build ] runs-on: ubuntu-latest if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/develop' }} steps: @@ -106,7 +108,8 @@ jobs: - name: Setup .NET Core uses: actions/setup-dotnet@v1 with: - dotnet-version: 5.0.100 + include-prerelease: True + dotnet-version: '6.0' - name: Install dependencies run: dotnet restore @@ -122,7 +125,7 @@ jobs: develop: name: Build Nightly Docker if Develop push - needs: [ build, test, version ] + needs: [ build, version ] runs-on: ubuntu-latest if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/develop' }} steps: @@ -186,7 +189,8 @@ jobs: - name: Compile dotnet app uses: actions/setup-dotnet@v1 with: - dotnet-version: '5.0.x' + include-prerelease: True + dotnet-version: '6.0' - run: ./monorepo-build.sh - name: Login to Docker Hub @@ -225,7 +229,7 @@ jobs: stable: name: Build Stable Docker if Main push - needs: [ build, test ] + needs: [ build ] runs-on: ubuntu-latest if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} steps: @@ -299,7 +303,8 @@ jobs: - name: Compile dotnet app uses: actions/setup-dotnet@v1 with: - dotnet-version: '5.0.x' + include-prerelease: True + dotnet-version: '6.0' - run: ./monorepo-build.sh - name: Login to Docker Hub diff --git a/.gitignore b/.gitignore index bc28fac8f..1ee566816 100644 --- a/.gitignore +++ b/.gitignore @@ -508,6 +508,7 @@ UI/Web/dist/ /API/config/cache/ /API/config/temp/ /API/config/stats/ +/API/config/bookmarks/ /API/config/kavita.db /API/config/kavita.db-shm /API/config/kavita.db-wal @@ -517,5 +518,8 @@ API/config/covers/ API/config/*.db API/config/stats/* API/config/stats/app_stats.json - +API/config/pre-metadata/ +API/config/post-metadata/ +API.Tests/TestResults/ UI/Web/.vscode/settings.json +/API.Tests/Services/Test Data/ArchiveService/CoverImages/output/* diff --git a/API.Benchmark/API.Benchmark.csproj b/API.Benchmark/API.Benchmark.csproj index d63d24ddc..cbf7d76f9 100644 --- a/API.Benchmark/API.Benchmark.csproj +++ b/API.Benchmark/API.Benchmark.csproj @@ -1,7 +1,7 @@ - net5.0 + net6.0 Exe diff --git a/API.Benchmark/ParseScannedFilesBenchmarks.cs b/API.Benchmark/ParseScannedFilesBenchmarks.cs index 8681c1261..a180d566f 100644 --- a/API.Benchmark/ParseScannedFilesBenchmarks.cs +++ b/API.Benchmark/ParseScannedFilesBenchmarks.cs @@ -1,6 +1,6 @@ using System.IO; +using System.IO.Abstractions; using API.Entities.Enums; -using API.Interfaces.Services; using API.Parser; using API.Services; using API.Services.Tasks.Scanner; @@ -20,11 +20,15 @@ namespace API.Benchmark private readonly ParseScannedFiles _parseScannedFiles; private readonly ILogger _logger = Substitute.For>(); private readonly ILogger _bookLogger = Substitute.For>(); + private readonly IArchiveService _archiveService = Substitute.For(); public ParseScannedFilesBenchmarks() { - IBookService bookService = new BookService(_bookLogger); - _parseScannedFiles = new ParseScannedFiles(bookService, _logger); + var directoryService = new DirectoryService(Substitute.For>(), new FileSystem()); + _parseScannedFiles = new ParseScannedFiles( + Substitute.For(), + directoryService, + new ReadingItemService(_archiveService, new BookService(_bookLogger, directoryService, new ImageService(Substitute.For>(), directoryService)), Substitute.For(), directoryService)); } // [Benchmark] diff --git a/API.Benchmark/TestBenchmark.cs b/API.Benchmark/TestBenchmark.cs index a2aabdd8a..618a8b93c 100644 --- a/API.Benchmark/TestBenchmark.cs +++ b/API.Benchmark/TestBenchmark.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using API.Comparators; using API.DTOs; +using API.Extensions; using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Order; @@ -16,9 +17,6 @@ namespace API.Benchmark [RankColumn] public class TestBenchmark { - private readonly NaturalSortComparer _naturalSortComparer = new (); - - private static IEnumerable GenerateVolumes(int max) { var random = new Random(); @@ -50,11 +48,11 @@ namespace API.Benchmark return list; } - private void SortSpecialChapters(IEnumerable volumes) + private static void SortSpecialChapters(IEnumerable volumes) { foreach (var v in volumes.Where(vDto => vDto.Number == 0)) { - v.Chapters = v.Chapters.OrderBy(x => x.Range, _naturalSortComparer).ToList(); + v.Chapters = v.Chapters.OrderByNatural(x => x.Range).ToList(); } } diff --git a/API.Tests/API.Tests.csproj b/API.Tests/API.Tests.csproj index 59ecff406..4f268a38a 100644 --- a/API.Tests/API.Tests.csproj +++ b/API.Tests/API.Tests.csproj @@ -1,15 +1,16 @@ - net5.0 + net6.0 false - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/API.Tests/Comparers/ChapterSortComparerZeroFirstTests.cs b/API.Tests/Comparers/ChapterSortComparerZeroFirstTests.cs new file mode 100644 index 000000000..72d6908c6 --- /dev/null +++ b/API.Tests/Comparers/ChapterSortComparerZeroFirstTests.cs @@ -0,0 +1,17 @@ +using System.Linq; +using API.Comparators; +using Xunit; + +namespace API.Tests.Comparers; + +public class ChapterSortComparerZeroFirstTests +{ + [Theory] + [InlineData(new[] {1, 2, 0}, new[] {0, 1, 2,})] + [InlineData(new[] {3, 1, 2}, new[] {1, 2, 3})] + [InlineData(new[] {1, 0, 0}, new[] {0, 0, 1})] + public void ChapterSortComparerZeroFirstTest(int[] input, int[] expected) + { + Assert.Equal(expected, input.OrderBy(f => f, new ChapterSortComparerZeroFirst()).ToArray()); + } +} diff --git a/API.Tests/Comparers/NumericComparerTests.cs b/API.Tests/Comparers/NumericComparerTests.cs new file mode 100644 index 000000000..9a66e7666 --- /dev/null +++ b/API.Tests/Comparers/NumericComparerTests.cs @@ -0,0 +1,26 @@ +using System; +using API.Comparators; +using Xunit; + +namespace API.Tests.Comparers; + +public class NumericComparerTests +{ + [Theory] + [InlineData( + new[] {"x1.jpg", "x10.jpg", "x3.jpg", "x4.jpg", "x11.jpg"}, + new[] {"x1.jpg", "x3.jpg", "x4.jpg", "x10.jpg", "x11.jpg"} + )] + public void NumericComparerTest(string[] input, string[] expected) + { + var nc = new NumericComparer(); + Array.Sort(input, nc); + + var i = 0; + foreach (var s in input) + { + Assert.Equal(s, expected[i]); + i++; + } + } +} diff --git a/API.Tests/Comparers/StringLogicalComparerTest.cs b/API.Tests/Comparers/StringLogicalComparerTest.cs index ae93b3b46..3d13e43ac 100644 --- a/API.Tests/Comparers/StringLogicalComparerTest.cs +++ b/API.Tests/Comparers/StringLogicalComparerTest.cs @@ -8,13 +8,20 @@ namespace API.Tests.Comparers { [Theory] [InlineData( - new[] {"x1.jpg", "x10.jpg", "x3.jpg", "x4.jpg", "x11.jpg"}, - new[] {"x1.jpg", "x3.jpg", "x4.jpg", "x10.jpg", "x11.jpg"} + new[] {"x1.jpg", "x10.jpg", "x3.jpg", "x4.jpg", "x11.jpg"}, + new[] {"x1.jpg", "x3.jpg", "x4.jpg", "x10.jpg", "x11.jpg"} )] - public void TestLogicalComparer(string[] input, string[] expected) + [InlineData( + new[] {"a.jpg", "aaa.jpg", "1.jpg", }, + new[] {"1.jpg", "a.jpg", "aaa.jpg"} + )] + [InlineData( + new[] {"a.jpg", "aaa.jpg", "1.jpg", "!cover.png"}, + new[] {"!cover.png", "1.jpg", "a.jpg", "aaa.jpg"} + )] + public void StringComparer(string[] input, string[] expected) { - NumericComparer nc = new NumericComparer(); - Array.Sort(input, nc); + Array.Sort(input, StringLogicalComparer.Compare); var i = 0; foreach (var s in input) @@ -24,4 +31,4 @@ namespace API.Tests.Comparers } } } -} \ No newline at end of file +} diff --git a/API.Tests/Converters/CronConverterTests.cs b/API.Tests/Converters/CronConverterTests.cs index 34efbd59e..813d82426 100644 --- a/API.Tests/Converters/CronConverterTests.cs +++ b/API.Tests/Converters/CronConverterTests.cs @@ -9,9 +9,11 @@ namespace API.Tests.Converters [InlineData("daily", "0 0 * * *")] [InlineData("disabled", "0 0 31 2 *")] [InlineData("weekly", "0 0 * * 1")] + [InlineData("", "0 0 31 2 *")] + [InlineData("sdfgdf", "")] public void ConvertTest(string input, string expected) { Assert.Equal(expected, CronConverter.ConvertToCronNotation(input)); } } -} \ No newline at end of file +} diff --git a/API.Tests/Entities/ComicInfoTests.cs b/API.Tests/Entities/ComicInfoTests.cs new file mode 100644 index 000000000..7b7106eb9 --- /dev/null +++ b/API.Tests/Entities/ComicInfoTests.cs @@ -0,0 +1,38 @@ +using API.Data.Metadata; +using API.Entities.Enums; +using Xunit; + +namespace API.Tests.Entities; + +public class ComicInfoTests +{ + #region ConvertAgeRatingToEnum + + [Theory] + [InlineData("G", AgeRating.G)] + [InlineData("Everyone", AgeRating.Everyone)] + [InlineData("Teen", AgeRating.Teen)] + [InlineData("Adults Only 18+", AgeRating.AdultsOnly)] + [InlineData("Early Childhood", AgeRating.EarlyChildhood)] + [InlineData("Everyone 10+", AgeRating.Everyone10Plus)] + [InlineData("M", AgeRating.Mature)] + [InlineData("MA 15+", AgeRating.Mature15Plus)] + [InlineData("Mature 17+", AgeRating.Mature17Plus)] + [InlineData("Rating Pending", AgeRating.RatingPending)] + [InlineData("X18+", AgeRating.X18Plus)] + [InlineData("Kids to Adults", AgeRating.KidsToAdults)] + [InlineData("NotValid", AgeRating.Unknown)] + [InlineData("PG", AgeRating.PG)] + [InlineData("R18+", AgeRating.R18Plus)] + public void ConvertAgeRatingToEnum_ShouldConvertCorrectly(string input, AgeRating expected) + { + Assert.Equal(expected, ComicInfo.ConvertAgeRatingToEnum(input)); + } + + [Fact] + public void ConvertAgeRatingToEnum_ShouldCompareCaseInsensitive() + { + Assert.Equal(AgeRating.RatingPending, ComicInfo.ConvertAgeRatingToEnum("rating pending")); + } + #endregion +} diff --git a/API.Tests/Extensions/ChapterListExtensionsTests.cs b/API.Tests/Extensions/ChapterListExtensionsTests.cs index 2251c660b..845b1387b 100644 --- a/API.Tests/Extensions/ChapterListExtensionsTests.cs +++ b/API.Tests/Extensions/ChapterListExtensionsTests.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Linq; using API.Entities; using API.Entities.Enums; using API.Extensions; @@ -9,7 +10,7 @@ namespace API.Tests.Extensions { public class ChapterListExtensionsTests { - private Chapter CreateChapter(string range, string number, MangaFile file, bool isSpecial) + private static Chapter CreateChapter(string range, string number, MangaFile file, bool isSpecial) { return new Chapter() { @@ -20,7 +21,7 @@ namespace API.Tests.Extensions }; } - private MangaFile CreateFile(string file, MangaFormat format) + private static MangaFile CreateFile(string file, MangaFormat format) { return new MangaFile() { @@ -28,7 +29,7 @@ namespace API.Tests.Extensions Format = format }; } - + [Fact] public void GetAnyChapterByRange_Test_ShouldBeNull() { @@ -51,11 +52,11 @@ namespace API.Tests.Extensions }; var actualChapter = chapterList.GetChapterByRange(info); - + Assert.NotEqual(chapterList[0], actualChapter); - + } - + [Fact] public void GetAnyChapterByRange_Test_ShouldBeNotNull() { @@ -78,9 +79,39 @@ namespace API.Tests.Extensions }; var actualChapter = chapterList.GetChapterByRange(info); - + Assert.Equal(chapterList[0], actualChapter); - } + + #region GetFirstChapterWithFiles + + [Fact] + public void GetFirstChapterWithFiles_ShouldReturnAllChapters() + { + var chapterList = new List() + { + CreateChapter("darker than black", "0", CreateFile("/manga/darker than black.cbz", MangaFormat.Archive), true), + CreateChapter("darker than black", "1", CreateFile("/manga/darker than black.cbz", MangaFormat.Archive), false), + }; + + Assert.Equal(chapterList.First(), chapterList.GetFirstChapterWithFiles()); + } + + [Fact] + public void GetFirstChapterWithFiles_ShouldReturnSecondChapter() + { + var chapterList = new List() + { + CreateChapter("darker than black", "0", CreateFile("/manga/darker than black.cbz", MangaFormat.Archive), true), + CreateChapter("darker than black", "1", CreateFile("/manga/darker than black.cbz", MangaFormat.Archive), false), + }; + + chapterList.First().Files = new List(); + + Assert.Equal(chapterList.Last(), chapterList.GetFirstChapterWithFiles()); + } + + + #endregion } -} \ No newline at end of file +} diff --git a/API.Tests/Comparers/NaturalSortComparerTest.cs b/API.Tests/Extensions/EnumerableExtensionsTests.cs similarity index 64% rename from API.Tests/Comparers/NaturalSortComparerTest.cs rename to API.Tests/Extensions/EnumerableExtensionsTests.cs index b624caac8..0f04ac9d7 100644 --- a/API.Tests/Comparers/NaturalSortComparerTest.cs +++ b/API.Tests/Extensions/EnumerableExtensionsTests.cs @@ -1,15 +1,12 @@ -using System; -using System.Linq; -using API.Comparators; +using System.Linq; +using API.Extensions; using Xunit; -namespace API.Tests.Comparers -{ - public class NaturalSortComparerTest - { - private readonly NaturalSortComparer _nc = new NaturalSortComparer(); +namespace API.Tests.Extensions; - [Theory] +public class EnumerableExtensionsTests +{ + [Theory] [InlineData( new[] {"x1.jpg", "x10.jpg", "x3.jpg", "x4.jpg", "x11.jpg"}, new[] {"x1.jpg", "x3.jpg", "x4.jpg", "x10.jpg", "x11.jpg"} @@ -46,19 +43,43 @@ namespace API.Tests.Comparers new[] {"Solo Leveling - c000 (v01) - p000 [Cover] [dig] [Yen Press] [LuCaZ].jpg", "Solo Leveling - c000 (v01) - p001 [dig] [Yen Press] [LuCaZ].jpg", "Solo Leveling - c000 (v01) - p002 [dig] [Yen Press] [LuCaZ].jpg", "Solo Leveling - c000 (v01) - p003 [dig] [Yen Press] [LuCaZ].jpg"}, new[] {"Solo Leveling - c000 (v01) - p000 [Cover] [dig] [Yen Press] [LuCaZ].jpg", "Solo Leveling - c000 (v01) - p001 [dig] [Yen Press] [LuCaZ].jpg", "Solo Leveling - c000 (v01) - p002 [dig] [Yen Press] [LuCaZ].jpg", "Solo Leveling - c000 (v01) - p003 [dig] [Yen Press] [LuCaZ].jpg"} )] - public void TestNaturalSortComparer(string[] input, string[] expected) + [InlineData( + new[] {"Marvel2In1-7", "Marvel2In1-7-01", "Marvel2In1-7-02"}, + new[] {"Marvel2In1-7", "Marvel2In1-7-01", "Marvel2In1-7-02"} + )] + [InlineData( + new[] {"001", "002", "!001"}, + new[] {"!001", "001", "002"} + )] + [InlineData( + new[] {"001.jpg", "002.jpg", "!001.jpg"}, + new[] {"!001.jpg", "001.jpg", "002.jpg"} + )] + [InlineData( + new[] {"001", "002", "!002"}, + new[] {"!002", "001", "002"} + )] + [InlineData( + new[] {"001", ""}, + new[] {"", "001"} + )] + [InlineData( + new[] {"Honzuki no Gekokujou_ Part 2/_Ch.019/002.jpg", "Honzuki no Gekokujou_ Part 2/_Ch.019/001.jpg", "Honzuki no Gekokujou_ Part 2/_Ch.020/001.jpg"}, + new[] {"Honzuki no Gekokujou_ Part 2/_Ch.019/001.jpg", "Honzuki no Gekokujou_ Part 2/_Ch.019/002.jpg", "Honzuki no Gekokujou_ Part 2/_Ch.020/001.jpg"} + )] + [InlineData( + new[] {@"F:\/Anime_Series_Pelis/MANGA/Mangahere (EN)\Kirara Fantasia\_Ch.001\001.jpg", @"F:\/Anime_Series_Pelis/MANGA/Mangahere (EN)\Kirara Fantasia\_Ch.001\002.jpg"}, + new[] {@"F:\/Anime_Series_Pelis/MANGA/Mangahere (EN)\Kirara Fantasia\_Ch.001\001.jpg", @"F:\/Anime_Series_Pelis/MANGA/Mangahere (EN)\Kirara Fantasia\_Ch.001\002.jpg"} + )] + [InlineData( + new[] {"01/001.jpg", "001.jpg"}, + new[] {"001.jpg", "01/001.jpg"} + )] + public void TestNaturalSort(string[] input, string[] expected) { - Array.Sort(input, _nc); - - var i = 0; - foreach (var s in input) - { - Assert.Equal(s, expected[i]); - i++; - } + Assert.Equal(expected, input.OrderByNatural(x => x).ToArray()); } - [Theory] [InlineData( new[] {"x1.jpg", "x10.jpg", "x3.jpg", "x4.jpg", "x11.jpg"}, @@ -84,6 +105,10 @@ namespace API.Tests.Comparers new[] {"001.jpg", "10.jpg",}, new[] {"001.jpg", "10.jpg",} )] + [InlineData( + new[] {"001", "002", "!001"}, + new[] {"!001", "001", "002"} + )] [InlineData( new[] {"10/001.jpg", "10.jpg",}, new[] {"10.jpg", "10/001.jpg",} @@ -92,9 +117,13 @@ namespace API.Tests.Comparers new[] {"Batman - Black white vol 1 #04.cbr", "Batman - Black white vol 1 #03.cbr", "Batman - Black white vol 1 #01.cbr", "Batman - Black white vol 1 #02.cbr"}, new[] {"Batman - Black white vol 1 #01.cbr", "Batman - Black white vol 1 #02.cbr", "Batman - Black white vol 1 #03.cbr", "Batman - Black white vol 1 #04.cbr"} )] - public void TestNaturalSortComparerLinq(string[] input, string[] expected) + [InlineData( + new[] {"Honzuki no Gekokujou_ Part 2/_Ch.019/002.jpg", "Honzuki no Gekokujou_ Part 2/_Ch.019/001.jpg"}, + new[] {"Honzuki no Gekokujou_ Part 2/_Ch.019/001.jpg", "Honzuki no Gekokujou_ Part 2/_Ch.019/002.jpg"} + )] + public void TestNaturalSortLinq(string[] input, string[] expected) { - var output = input.OrderBy(c => c, _nc); + var output = input.OrderByNatural(x => x); var i = 0; foreach (var s in output) @@ -103,5 +132,4 @@ namespace API.Tests.Comparers i++; } } - } } diff --git a/API.Tests/Extensions/FilterDtoExtensionsTests.cs b/API.Tests/Extensions/FilterDtoExtensionsTests.cs new file mode 100644 index 000000000..c9985f509 --- /dev/null +++ b/API.Tests/Extensions/FilterDtoExtensionsTests.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using API.DTOs.Filtering; +using API.Entities.Enums; +using API.Extensions; +using Xunit; + +namespace API.Tests.Extensions; + +public class FilterDtoExtensionsTests +{ + [Fact] + public void GetSqlFilter_ShouldReturnAllFormats() + { + var filter = new FilterDto() + { + Formats = null + }; + + Assert.Equal(Enum.GetValues(), filter.GetSqlFilter()); + } + + [Fact] + public void GetSqlFilter_ShouldReturnAllFormats2() + { + var filter = new FilterDto() + { + Formats = new List() + }; + + Assert.Equal(Enum.GetValues(), filter.GetSqlFilter()); + } + + [Fact] + public void GetSqlFilter_ShouldReturnJust2() + { + var formats = new List() + { + MangaFormat.Archive, MangaFormat.Epub + }; + var filter = new FilterDto() + { + Formats = formats + }; + + Assert.Equal(formats, filter.GetSqlFilter()); + } +} diff --git a/API.Tests/Extensions/ParserInfoListExtensionsTests.cs b/API.Tests/Extensions/ParserInfoListExtensionsTests.cs index f6119cc69..e7c8e9994 100644 --- a/API.Tests/Extensions/ParserInfoListExtensionsTests.cs +++ b/API.Tests/Extensions/ParserInfoListExtensionsTests.cs @@ -1,15 +1,27 @@ using System.Collections.Generic; +using System.IO.Abstractions.TestingHelpers; using System.Linq; using API.Entities.Enums; using API.Extensions; using API.Parser; +using API.Services; using API.Tests.Helpers; +using Microsoft.Extensions.Logging; +using NSubstitute; using Xunit; namespace API.Tests.Extensions { public class ParserInfoListExtensions { + private readonly DefaultParser _defaultParser; + public ParserInfoListExtensions() + { + _defaultParser = + new DefaultParser(new DirectoryService(Substitute.For>(), + new MockFileSystem())); + } + [Theory] [InlineData(new[] {"1", "1", "3-5", "5", "8", "0", "0"}, new[] {"1", "3-5", "5", "8", "0"})] public void DistinctVolumesTest(string[] volumeNumbers, string[] expectedNumbers) @@ -17,7 +29,7 @@ namespace API.Tests.Extensions var infos = volumeNumbers.Select(n => new ParserInfo() {Volumes = n}).ToList(); Assert.Equal(expectedNumbers, infos.DistinctVolumes()); } - + [Theory] [InlineData(new[] {@"Cynthia The Mission - c000-006 (v06) [Desudesu&Brolen].zip"}, new[] {@"E:\Manga\Cynthia the Mission\Cynthia The Mission - c000-006 (v06) [Desudesu&Brolen].zip"}, true)] [InlineData(new[] {@"Cynthia The Mission - c000-006 (v06-07) [Desudesu&Brolen].zip"}, new[] {@"E:\Manga\Cynthia the Mission\Cynthia The Mission - c000-006 (v06) [Desudesu&Brolen].zip"}, true)] @@ -27,7 +39,7 @@ namespace API.Tests.Extensions var infos = new List(); foreach (var filename in inputInfos) { - infos.Add(API.Parser.Parser.Parse( + infos.Add(_defaultParser.Parse( filename, string.Empty)); } @@ -38,4 +50,4 @@ namespace API.Tests.Extensions Assert.Equal(expectedHasInfo, infos.HasInfo(chapter)); } } -} \ No newline at end of file +} diff --git a/API.Tests/Extensions/PathExtensionsTests.cs b/API.Tests/Extensions/PathExtensionsTests.cs new file mode 100644 index 000000000..bdc752a92 --- /dev/null +++ b/API.Tests/Extensions/PathExtensionsTests.cs @@ -0,0 +1,20 @@ +using System.IO; +using Xunit; +using API.Extensions; + +namespace API.Tests.Extensions; + +public class PathExtensionsTests +{ + #region GetFullPathWithoutExtension + + [Theory] + [InlineData("joe.png", "joe")] + [InlineData("c:/directory/joe.png", "c:/directory/joe")] + public void GetFullPathWithoutExtension_Test(string input, string expected) + { + Assert.Equal(Path.GetFullPath(expected), input.GetFullPathWithoutExtension()); + } + + #endregion +} diff --git a/API.Tests/Extensions/SeriesExtensionsTests.cs b/API.Tests/Extensions/SeriesExtensionsTests.cs index 35054770b..fc5b5b8ca 100644 --- a/API.Tests/Extensions/SeriesExtensionsTests.cs +++ b/API.Tests/Extensions/SeriesExtensionsTests.cs @@ -1,6 +1,11 @@ -using API.Entities; +using System.Linq; +using API.Entities; +using API.Entities.Enums; +using API.Entities.Metadata; using API.Extensions; using API.Parser; +using API.Services.Tasks.Scanner; +using API.Tests.Helpers; using Xunit; namespace API.Tests.Extensions @@ -31,6 +36,38 @@ namespace API.Tests.Extensions Assert.Equal(expected, series.NameInList(list)); } + [Theory] + [InlineData(new [] {"Darker than Black", "Darker Than Black", "Darker than Black"}, new [] {"Darker than Black"}, MangaFormat.Archive, true)] + [InlineData(new [] {"Darker than Black", "Darker Than Black", "Darker than Black"}, new [] {"Darker_than_Black"}, MangaFormat.Archive, true)] + [InlineData(new [] {"Darker than Black", "Darker Than Black", "Darker than Black"}, new [] {"Darker then Black!"}, MangaFormat.Archive, false)] + [InlineData(new [] {"Salem's Lot", "Salem's Lot", "Salem's Lot"}, new [] {"Salem's Lot"}, MangaFormat.Archive, true)] + [InlineData(new [] {"Salem's Lot", "Salem's Lot", "Salem's Lot"}, new [] {"salems lot"}, MangaFormat.Archive, true)] + [InlineData(new [] {"Salem's Lot", "Salem's Lot", "Salem's Lot"}, new [] {"salem's lot"}, MangaFormat.Archive, true)] + // Different normalizations pass as we check normalization against an on-the-fly calculation so we don't delete series just because we change how normalization works + [InlineData(new [] {"Salem's Lot", "Salem's Lot", "Salem's Lot", "salems lot"}, new [] {"salem's lot"}, MangaFormat.Archive, true)] + [InlineData(new [] {"Rent-a-Girlfriend", "Rent-a-Girlfriend", "Kanojo, Okarishimasu", "rentagirlfriend"}, new [] {"Kanojo, Okarishimasu"}, MangaFormat.Archive, true)] + public void NameInListParserInfoTest(string[] seriesInput, string[] list, MangaFormat format, bool expected) + { + var series = new Series() + { + Name = seriesInput[0], + LocalizedName = seriesInput[1], + OriginalName = seriesInput[2], + NormalizedName = seriesInput.Length == 4 ? seriesInput[3] : API.Parser.Parser.Normalize(seriesInput[0]), + Metadata = new SeriesMetadata(), + }; + + var parserInfos = list.Select(s => new ParsedSeries() + { + Name = s, + NormalizedName = API.Parser.Parser.Normalize(s), + }).ToList(); + + // This doesn't do any checks against format + Assert.Equal(expected, series.NameInList(parserInfos)); + } + + [Theory] [InlineData(new [] {"Darker than Black", "Darker Than Black", "Darker than Black"}, "Darker than Black", true)] [InlineData(new [] {"Rent-a-Girlfriend", "Rent-a-Girlfriend", "Kanojo, Okarishimasu", "rentagirlfriend"}, "Kanojo, Okarishimasu", true)] diff --git a/API.Tests/Extensions/VolumeListExtensionsTests.cs b/API.Tests/Extensions/VolumeListExtensionsTests.cs new file mode 100644 index 000000000..48d39aa24 --- /dev/null +++ b/API.Tests/Extensions/VolumeListExtensionsTests.cs @@ -0,0 +1,177 @@ +using System.Collections.Generic; +using API.Entities; +using API.Entities.Enums; +using API.Extensions; +using API.Tests.Helpers; +using Xunit; + +namespace API.Tests.Extensions; + +public class VolumeListExtensionsTests +{ + #region FirstWithChapters + + [Fact] + public void FirstWithChapters_ReturnsVolumeWithChapters() + { + var volumes = new List() + { + EntityFactory.CreateVolume("0", new List()), + EntityFactory.CreateVolume("1", new List() + { + EntityFactory.CreateChapter("1", false), + EntityFactory.CreateChapter("2", false), + }), + }; + + Assert.Equal(volumes[1].Number, volumes.FirstWithChapters(false).Number); + Assert.Equal(volumes[1].Number, volumes.FirstWithChapters(true).Number); + } + + [Fact] + public void FirstWithChapters_Book() + { + var volumes = new List() + { + EntityFactory.CreateVolume("1", new List() + { + EntityFactory.CreateChapter("3", false), + EntityFactory.CreateChapter("4", false), + }), + EntityFactory.CreateVolume("0", new List() + { + EntityFactory.CreateChapter("1", false), + EntityFactory.CreateChapter("0", true), + }), + }; + + Assert.Equal(volumes[0].Number, volumes.FirstWithChapters(true).Number); + } + + [Fact] + public void FirstWithChapters_NonBook() + { + var volumes = new List() + { + EntityFactory.CreateVolume("1", new List() + { + EntityFactory.CreateChapter("3", false), + EntityFactory.CreateChapter("4", false), + }), + EntityFactory.CreateVolume("0", new List() + { + EntityFactory.CreateChapter("1", false), + EntityFactory.CreateChapter("0", true), + }), + }; + + Assert.Equal(volumes[0].Number, volumes.FirstWithChapters(false).Number); + } + + #endregion + + #region GetCoverImage + + [Fact] + public void GetCoverImage_ArchiveFormat() + { + var volumes = new List() + { + EntityFactory.CreateVolume("1", new List() + { + EntityFactory.CreateChapter("3", false), + EntityFactory.CreateChapter("4", false), + }), + EntityFactory.CreateVolume("0", new List() + { + EntityFactory.CreateChapter("1", false), + EntityFactory.CreateChapter("0", true), + }), + }; + + Assert.Equal(volumes[0].Number, volumes.GetCoverImage(MangaFormat.Archive).Number); + } + + [Fact] + public void GetCoverImage_EpubFormat() + { + var volumes = new List() + { + EntityFactory.CreateVolume("1", new List() + { + EntityFactory.CreateChapter("3", false), + EntityFactory.CreateChapter("4", false), + }), + EntityFactory.CreateVolume("0", new List() + { + EntityFactory.CreateChapter("1", false), + EntityFactory.CreateChapter("0", true), + }), + }; + + Assert.Equal(volumes[1].Name, volumes.GetCoverImage(MangaFormat.Epub).Name); + } + + [Fact] + public void GetCoverImage_PdfFormat() + { + var volumes = new List() + { + EntityFactory.CreateVolume("1", new List() + { + EntityFactory.CreateChapter("3", false), + EntityFactory.CreateChapter("4", false), + }), + EntityFactory.CreateVolume("0", new List() + { + EntityFactory.CreateChapter("1", false), + EntityFactory.CreateChapter("0", true), + }), + }; + + Assert.Equal(volumes[1].Name, volumes.GetCoverImage(MangaFormat.Pdf).Name); + } + + [Fact] + public void GetCoverImage_ImageFormat() + { + var volumes = new List() + { + EntityFactory.CreateVolume("1", new List() + { + EntityFactory.CreateChapter("3", false), + EntityFactory.CreateChapter("4", false), + }), + EntityFactory.CreateVolume("0", new List() + { + EntityFactory.CreateChapter("1", false), + EntityFactory.CreateChapter("0", true), + }), + }; + + Assert.Equal(volumes[0].Name, volumes.GetCoverImage(MangaFormat.Image).Name); + } + + [Fact] + public void GetCoverImage_ImageFormat_NoSpecials() + { + var volumes = new List() + { + EntityFactory.CreateVolume("2", new List() + { + EntityFactory.CreateChapter("3", false), + EntityFactory.CreateChapter("4", false), + }), + EntityFactory.CreateVolume("1", new List() + { + EntityFactory.CreateChapter("1", false), + EntityFactory.CreateChapter("0", true), + }), + }; + + Assert.Equal(volumes[1].Name, volumes.GetCoverImage(MangaFormat.Image).Name); + } + + + #endregion +} diff --git a/API.Tests/Helpers/CacheHelperTests.cs b/API.Tests/Helpers/CacheHelperTests.cs new file mode 100644 index 000000000..9d1024ff0 --- /dev/null +++ b/API.Tests/Helpers/CacheHelperTests.cs @@ -0,0 +1,293 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.IO.Abstractions.TestingHelpers; +using API.Entities; +using API.Helpers; +using API.Services; +using Microsoft.Extensions.Logging; +using NSubstitute; +using Xunit; + +namespace API.Tests.Helpers; + +public class CacheHelperTests +{ + private const string TestCoverImageDirectory = @"c:\"; + private const string TestCoverImageFile = "thumbnail.jpg"; + private readonly string _testCoverPath = Path.Join(TestCoverImageDirectory, TestCoverImageFile); + private const string TestCoverArchive = @"file in folder.zip"; + private readonly ICacheHelper _cacheHelper; + + public CacheHelperTests() + { + var file = new MockFileData("") + { + LastWriteTime = DateTimeOffset.Now.Subtract(TimeSpan.FromMinutes(1)) + }; + var fileSystem = new MockFileSystem(new Dictionary + { + { Path.Join(TestCoverImageDirectory, TestCoverArchive), file }, + { Path.Join(TestCoverImageDirectory, TestCoverImageFile), file } + }); + + var fileService = new FileService(fileSystem); + _cacheHelper = new CacheHelper(fileService); + } + + [Theory] + [InlineData("", false)] + [InlineData("C:/", false)] + [InlineData(null, false)] + public void CoverImageExists_DoesFileExist(string coverImage, bool exists) + { + Assert.Equal(exists, _cacheHelper.CoverImageExists(coverImage)); + } + + [Fact] + public void CoverImageExists_FileExists() + { + Assert.True(_cacheHelper.CoverImageExists(TestCoverArchive)); + } + + [Fact] + public void ShouldUpdateCoverImage_OnFirstRun() + { + var file = new MangaFile() + { + FilePath = TestCoverArchive, + LastModified = DateTime.Now + }; + Assert.True(_cacheHelper.ShouldUpdateCoverImage(null, file, DateTime.Now.Subtract(TimeSpan.FromMinutes(1)), + false, false)); + } + + [Fact] + public void ShouldUpdateCoverImage_ShouldNotUpdateOnSecondRunWithCoverImageSetNotLocked() + { + // Represents first run + var file = new MangaFile() + { + FilePath = TestCoverArchive, + LastModified = DateTime.Now + }; + Assert.False(_cacheHelper.ShouldUpdateCoverImage(_testCoverPath, file, DateTime.Now.Subtract(TimeSpan.FromMinutes(1)), + false, false)); + } + + [Fact] + public void ShouldUpdateCoverImage_ShouldNotUpdateOnSecondRunWithCoverImageSetNotLocked_2() + { + // Represents first run + var file = new MangaFile() + { + FilePath = TestCoverArchive, + LastModified = DateTime.Now + }; + Assert.False(_cacheHelper.ShouldUpdateCoverImage(_testCoverPath, file, DateTime.Now, + false, false)); + } + + [Fact] + public void ShouldUpdateCoverImage_ShouldNotUpdateOnSecondRunWithCoverImageSetLocked() + { + // Represents first run + var file = new MangaFile() + { + FilePath = TestCoverArchive, + LastModified = DateTime.Now + }; + Assert.False(_cacheHelper.ShouldUpdateCoverImage(_testCoverPath, file, DateTime.Now.Subtract(TimeSpan.FromMinutes(1)), + false, true)); + } + + [Fact] + public void ShouldUpdateCoverImage_ShouldNotUpdateOnSecondRunWithCoverImageSetLocked_Modified() + { + // Represents first run + var file = new MangaFile() + { + FilePath = TestCoverArchive, + LastModified = DateTime.Now + }; + Assert.False(_cacheHelper.ShouldUpdateCoverImage(_testCoverPath, file, DateTime.Now.Subtract(TimeSpan.FromMinutes(1)), + false, true)); + } + + [Fact] + public void ShouldUpdateCoverImage_CoverImageSetAndReplaced_Modified() + { + var filesystemFile = new MockFileData("") + { + LastWriteTime = DateTimeOffset.Now + }; + var fileSystem = new MockFileSystem(new Dictionary + { + { Path.Join(TestCoverImageDirectory, TestCoverArchive), filesystemFile }, + { Path.Join(TestCoverImageDirectory, TestCoverImageFile), filesystemFile } + }); + + var fileService = new FileService(fileSystem); + var cacheHelper = new CacheHelper(fileService); + + var created = DateTime.Now.Subtract(TimeSpan.FromHours(1)); + var file = new MangaFile() + { + FilePath = TestCoverArchive, + LastModified = DateTime.Now.Subtract(TimeSpan.FromMinutes(1)) + }; + Assert.True(cacheHelper.ShouldUpdateCoverImage(_testCoverPath, file, created, + false, false)); + } + + [Fact] + public void HasFileNotChangedSinceCreationOrLastScan_NotChangedSinceCreated() + { + var filesystemFile = new MockFileData("") + { + LastWriteTime = DateTimeOffset.Now + }; + var fileSystem = new MockFileSystem(new Dictionary + { + { Path.Join(TestCoverImageDirectory, TestCoverArchive), filesystemFile }, + { Path.Join(TestCoverImageDirectory, TestCoverImageFile), filesystemFile } + }); + + var fileService = new FileService(fileSystem); + var cacheHelper = new CacheHelper(fileService); + + var chapter = new Chapter() + { + Created = filesystemFile.LastWriteTime.DateTime, + LastModified = filesystemFile.LastWriteTime.DateTime + }; + + var file = new MangaFile() + { + FilePath = TestCoverArchive, + LastModified = filesystemFile.LastWriteTime.DateTime + }; + Assert.True(cacheHelper.HasFileNotChangedSinceCreationOrLastScan(chapter, false, file)); + } + + [Fact] + public void HasFileNotChangedSinceCreationOrLastScan_NotChangedSinceLastModified() + { + var filesystemFile = new MockFileData("") + { + LastWriteTime = DateTimeOffset.Now + }; + var fileSystem = new MockFileSystem(new Dictionary + { + { Path.Join(TestCoverImageDirectory, TestCoverArchive), filesystemFile }, + { Path.Join(TestCoverImageDirectory, TestCoverImageFile), filesystemFile } + }); + + var fileService = new FileService(fileSystem); + var cacheHelper = new CacheHelper(fileService); + + var chapter = new Chapter() + { + Created = filesystemFile.LastWriteTime.DateTime, + LastModified = filesystemFile.LastWriteTime.DateTime + }; + + var file = new MangaFile() + { + FilePath = TestCoverArchive, + LastModified = filesystemFile.LastWriteTime.DateTime + }; + Assert.True(cacheHelper.HasFileNotChangedSinceCreationOrLastScan(chapter, false, file)); + } + + [Fact] + public void HasFileNotChangedSinceCreationOrLastScan_NotChangedSinceLastModified_ForceUpdate() + { + var filesystemFile = new MockFileData("") + { + LastWriteTime = DateTimeOffset.Now + }; + var fileSystem = new MockFileSystem(new Dictionary + { + { Path.Join(TestCoverImageDirectory, TestCoverArchive), filesystemFile }, + { Path.Join(TestCoverImageDirectory, TestCoverImageFile), filesystemFile } + }); + + var fileService = new FileService(fileSystem); + var cacheHelper = new CacheHelper(fileService); + + var chapter = new Chapter() + { + Created = filesystemFile.LastWriteTime.DateTime, + LastModified = filesystemFile.LastWriteTime.DateTime + }; + + var file = new MangaFile() + { + FilePath = TestCoverArchive, + LastModified = filesystemFile.LastWriteTime.DateTime + }; + Assert.False(cacheHelper.HasFileNotChangedSinceCreationOrLastScan(chapter, true, file)); + } + + [Fact] + public void HasFileNotChangedSinceCreationOrLastScan_ModifiedSinceLastScan() + { + var filesystemFile = new MockFileData("") + { + LastWriteTime = DateTimeOffset.Now + }; + var fileSystem = new MockFileSystem(new Dictionary + { + { Path.Join(TestCoverImageDirectory, TestCoverArchive), filesystemFile }, + { Path.Join(TestCoverImageDirectory, TestCoverImageFile), filesystemFile } + }); + + var fileService = new FileService(fileSystem); + var cacheHelper = new CacheHelper(fileService); + + var chapter = new Chapter() + { + Created = filesystemFile.LastWriteTime.DateTime.Subtract(TimeSpan.FromMinutes(10)), + LastModified = filesystemFile.LastWriteTime.DateTime.Subtract(TimeSpan.FromMinutes(10)) + }; + + var file = new MangaFile() + { + FilePath = Path.Join(TestCoverImageDirectory, TestCoverArchive), + LastModified = filesystemFile.LastWriteTime.DateTime + }; + Assert.False(cacheHelper.HasFileNotChangedSinceCreationOrLastScan(chapter, false, file)); + } + + [Fact] + public void HasFileNotChangedSinceCreationOrLastScan_ModifiedSinceLastScan_ButLastModifiedSame() + { + var filesystemFile = new MockFileData("") + { + LastWriteTime = DateTimeOffset.Now + }; + var fileSystem = new MockFileSystem(new Dictionary + { + { Path.Join(TestCoverImageDirectory, TestCoverArchive), filesystemFile }, + { Path.Join(TestCoverImageDirectory, TestCoverImageFile), filesystemFile } + }); + + var fileService = new FileService(fileSystem); + var cacheHelper = new CacheHelper(fileService); + + var chapter = new Chapter() + { + Created = filesystemFile.LastWriteTime.DateTime.Subtract(TimeSpan.FromMinutes(10)), + LastModified = filesystemFile.LastWriteTime.DateTime + }; + + var file = new MangaFile() + { + FilePath = Path.Join(TestCoverImageDirectory, TestCoverArchive), + LastModified = filesystemFile.LastWriteTime.DateTime + }; + Assert.False(cacheHelper.HasFileNotChangedSinceCreationOrLastScan(chapter, false, file)); + } + +} diff --git a/API.Tests/Helpers/EntityFactory.cs b/API.Tests/Helpers/EntityFactory.cs index 456cd1b52..7b55df108 100644 --- a/API.Tests/Helpers/EntityFactory.cs +++ b/API.Tests/Helpers/EntityFactory.cs @@ -1,6 +1,8 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using API.Entities; using API.Entities.Enums; +using API.Entities.Metadata; namespace API.Tests.Helpers { @@ -27,6 +29,7 @@ namespace API.Tests.Helpers return new Volume() { Name = volumeNumber, + Number = int.Parse(volumeNumber), Pages = 0, Chapters = chapters ?? new List() }; @@ -75,4 +78,4 @@ namespace API.Tests.Helpers }; } } -} \ No newline at end of file +} diff --git a/API.Tests/Helpers/GenreHelperTests.cs b/API.Tests/Helpers/GenreHelperTests.cs new file mode 100644 index 000000000..0d0aebe0c --- /dev/null +++ b/API.Tests/Helpers/GenreHelperTests.cs @@ -0,0 +1,110 @@ +using System.Collections.Generic; +using API.Data; +using API.Entities; +using API.Helpers; +using Xunit; + +namespace API.Tests.Helpers; + +public class GenreHelperTests +{ + [Fact] + public void UpdateGenre_ShouldAddNewGenre() + { + var allGenres = new List + { + DbFactory.Genre("Action", false), + DbFactory.Genre("action", false), + DbFactory.Genre("Sci-fi", false), + }; + var genreAdded = new List(); + + GenreHelper.UpdateGenre(allGenres, new[] {"Action", "Adventure"}, false, genre => + { + genreAdded.Add(genre); + }); + + Assert.Equal(2, genreAdded.Count); + Assert.Equal(4, allGenres.Count); + } + + [Fact] + public void UpdateGenre_ShouldNotAddDuplicateGenre() + { + var allGenres = new List + { + DbFactory.Genre("Action", false), + DbFactory.Genre("action", false), + DbFactory.Genre("Sci-fi", false), + + }; + var genreAdded = new List(); + + GenreHelper.UpdateGenre(allGenres, new[] {"Action", "Scifi"}, false, genre => + { + genreAdded.Add(genre); + }); + + Assert.Equal(3, allGenres.Count); + } + + [Fact] + public void AddGenre_ShouldAddOnlyNonExistingGenre() + { + var existingGenres = new List + { + DbFactory.Genre("Action", false), + DbFactory.Genre("action", false), + DbFactory.Genre("Sci-fi", false), + }; + + + GenreHelper.AddGenreIfNotExists(existingGenres, DbFactory.Genre("Action", false)); + Assert.Equal(3, existingGenres.Count); + + GenreHelper.AddGenreIfNotExists(existingGenres, DbFactory.Genre("action", false)); + Assert.Equal(3, existingGenres.Count); + + GenreHelper.AddGenreIfNotExists(existingGenres, DbFactory.Genre("Shonen", false)); + Assert.Equal(4, existingGenres.Count); + } + + [Fact] + public void AddGenre_ShouldNotAddSameNameAndExternal() + { + var existingGenres = new List + { + DbFactory.Genre("Action", false), + DbFactory.Genre("action", false), + DbFactory.Genre("Sci-fi", false), + }; + + + GenreHelper.AddGenreIfNotExists(existingGenres, DbFactory.Genre("Action", true)); + Assert.Equal(3, existingGenres.Count); + } + + [Fact] + public void KeepOnlySamePeopleBetweenLists() + { + var existingGenres = new List + { + DbFactory.Genre("Action", false), + DbFactory.Genre("Sci-fi", false), + }; + + var peopleFromChapters = new List + { + DbFactory.Genre("Action", false), + }; + + var genreRemoved = new List(); + GenreHelper.KeepOnlySameGenreBetweenLists(existingGenres, + peopleFromChapters, genre => + { + genreRemoved.Add(genre); + }); + + Assert.Equal(1, genreRemoved.Count); + } +} diff --git a/API.Tests/Helpers/ParserInfoFactory.cs b/API.Tests/Helpers/ParserInfoFactory.cs index 7dcf564e1..2dc2f2869 100644 --- a/API.Tests/Helpers/ParserInfoFactory.cs +++ b/API.Tests/Helpers/ParserInfoFactory.cs @@ -1,6 +1,10 @@ -using System.IO; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.IO; +using System.Linq; using API.Entities.Enums; using API.Parser; +using API.Services.Tasks.Scanner; namespace API.Tests.Helpers { @@ -21,5 +25,49 @@ namespace API.Tests.Helpers Volumes = volumes }; } + + public static void AddToParsedInfo(IDictionary> collectedSeries, ParserInfo info) + { + var existingKey = collectedSeries.Keys.FirstOrDefault(ps => + ps.Format == info.Format && ps.NormalizedName == API.Parser.Parser.Normalize(info.Series)); + existingKey ??= new ParsedSeries() + { + Format = info.Format, + Name = info.Series, + NormalizedName = API.Parser.Parser.Normalize(info.Series) + }; + if (collectedSeries.GetType() == typeof(ConcurrentDictionary<,>)) + { + ((ConcurrentDictionary>) collectedSeries).AddOrUpdate(existingKey, new List() {info}, (_, oldValue) => + { + oldValue ??= new List(); + if (!oldValue.Contains(info)) + { + oldValue.Add(info); + } + + return oldValue; + }); + } + else + { + if (!collectedSeries.ContainsKey(existingKey)) + { + collectedSeries.Add(existingKey, new List() {info}); + } + else + { + var list = collectedSeries[existingKey]; + if (!list.Contains(info)) + { + list.Add(info); + } + + collectedSeries[existingKey] = list; + } + + } + + } } -} \ No newline at end of file +} diff --git a/API.Tests/Helpers/ParserInfoHelperTests.cs b/API.Tests/Helpers/ParserInfoHelperTests.cs new file mode 100644 index 000000000..d3b58d96b --- /dev/null +++ b/API.Tests/Helpers/ParserInfoHelperTests.cs @@ -0,0 +1,75 @@ +using System.Collections.Generic; +using API.Entities; +using API.Entities.Enums; +using API.Entities.Metadata; +using API.Helpers; +using API.Parser; +using API.Services.Tasks.Scanner; +using Xunit; + +namespace API.Tests.Helpers; + +public class ParserInfoHelperTests +{ + #region SeriesHasMatchingParserInfoFormat + + [Fact] + public void SeriesHasMatchingParserInfoFormat_ShouldBeFalse() + { + var infos = new Dictionary>(); + + ParserInfoFactory.AddToParsedInfo(infos, new ParserInfo() {Series = "Darker than Black", Volumes = "1", Format = MangaFormat.Archive}); + //AddToParsedInfo(infos, new ParserInfo() {Series = "Darker than Black", Volumes = "1", Format = MangaFormat.Epub}); + + var series = new Series() + { + Name = "Darker Than Black", + LocalizedName = "Darker Than Black", + OriginalName = "Darker Than Black", + Volumes = new List() + { + new Volume() + { + Number = 1, + Name = "1" + } + }, + NormalizedName = API.Parser.Parser.Normalize("Darker Than Black"), + Metadata = new SeriesMetadata(), + Format = MangaFormat.Epub + }; + + Assert.False(ParserInfoHelpers.SeriesHasMatchingParserInfoFormat(series, infos)); + } + + [Fact] + public void SeriesHasMatchingParserInfoFormat_ShouldBeTrue() + { + var infos = new Dictionary>(); + + ParserInfoFactory.AddToParsedInfo(infos, new ParserInfo() {Series = "Darker than Black", Volumes = "1", Format = MangaFormat.Archive}); + ParserInfoFactory.AddToParsedInfo(infos, new ParserInfo() {Series = "Darker than Black", Volumes = "1", Format = MangaFormat.Epub}); + + var series = new Series() + { + Name = "Darker Than Black", + LocalizedName = "Darker Than Black", + OriginalName = "Darker Than Black", + Volumes = new List() + { + new Volume() + { + Number = 1, + Name = "1" + } + }, + NormalizedName = API.Parser.Parser.Normalize("Darker Than Black"), + Metadata = new SeriesMetadata(), + Format = MangaFormat.Epub + }; + + Assert.True(ParserInfoHelpers.SeriesHasMatchingParserInfoFormat(series, infos)); + } + + #endregion +} diff --git a/API.Tests/Helpers/PersonHelperTests.cs b/API.Tests/Helpers/PersonHelperTests.cs new file mode 100644 index 000000000..f5b5551ae --- /dev/null +++ b/API.Tests/Helpers/PersonHelperTests.cs @@ -0,0 +1,140 @@ +using System.Collections.Generic; +using API.Data; +using API.Entities; +using API.Entities.Enums; +using API.Helpers; +using Xunit; + +namespace API.Tests.Helpers; + +public class PersonHelperTests +{ + [Fact] + public void UpdatePeople_ShouldAddNewPeople() + { + var allPeople = new List + { + DbFactory.Person("Joe Shmo", PersonRole.CoverArtist), + DbFactory.Person("Joe Shmo", PersonRole.Writer) + }; + var peopleAdded = new List(); + + PersonHelper.UpdatePeople(allPeople, new[] {"Joseph Shmo", "Sally Ann"}, PersonRole.Writer, person => + { + peopleAdded.Add(person); + }); + + Assert.Equal(2, peopleAdded.Count); + Assert.Equal(4, allPeople.Count); + } + + [Fact] + public void UpdatePeople_ShouldNotAddDuplicatePeople() + { + var allPeople = new List + { + DbFactory.Person("Joe Shmo", PersonRole.CoverArtist), + DbFactory.Person("Joe Shmo", PersonRole.Writer), + DbFactory.Person("Sally Ann", PersonRole.CoverArtist), + + }; + var peopleAdded = new List(); + + PersonHelper.UpdatePeople(allPeople, new[] {"Joe Shmo", "Sally Ann"}, PersonRole.CoverArtist, person => + { + peopleAdded.Add(person); + }); + + Assert.Equal(3, allPeople.Count); + } + + [Fact] + public void RemovePeople_ShouldRemovePeopleOfSameRole() + { + var existingPeople = new List + { + DbFactory.Person("Joe Shmo", PersonRole.CoverArtist), + DbFactory.Person("Joe Shmo", PersonRole.Writer) + }; + var peopleRemoved = new List(); + PersonHelper.RemovePeople(existingPeople, new[] {"Joe Shmo", "Sally Ann"}, PersonRole.Writer, person => + { + peopleRemoved.Add(person); + }); + + Assert.NotEqual(existingPeople, peopleRemoved); + Assert.Equal(1, peopleRemoved.Count); + } + + [Fact] + public void RemovePeople_ShouldRemovePeopleFromBothRoles() + { + var existingPeople = new List + { + DbFactory.Person("Joe Shmo", PersonRole.CoverArtist), + DbFactory.Person("Joe Shmo", PersonRole.Writer) + }; + var peopleRemoved = new List(); + PersonHelper.RemovePeople(existingPeople, new[] {"Joe Shmo", "Sally Ann"}, PersonRole.Writer, person => + { + peopleRemoved.Add(person); + }); + + Assert.NotEqual(existingPeople, peopleRemoved); + Assert.Equal(1, peopleRemoved.Count); + + PersonHelper.RemovePeople(existingPeople, new[] {"Joe Shmo"}, PersonRole.CoverArtist, person => + { + peopleRemoved.Add(person); + }); + + Assert.Equal(0, existingPeople.Count); + Assert.Equal(2, peopleRemoved.Count); + } + + [Fact] + public void KeepOnlySamePeopleBetweenLists() + { + var existingPeople = new List + { + DbFactory.Person("Joe Shmo", PersonRole.CoverArtist), + DbFactory.Person("Joe Shmo", PersonRole.Writer), + DbFactory.Person("Sally", PersonRole.Writer), + }; + + var peopleFromChapters = new List + { + DbFactory.Person("Joe Shmo", PersonRole.CoverArtist), + }; + + var peopleRemoved = new List(); + PersonHelper.KeepOnlySamePeopleBetweenLists(existingPeople, + peopleFromChapters, person => + { + peopleRemoved.Add(person); + }); + + Assert.Equal(2, peopleRemoved.Count); + } + + [Fact] + public void AddPeople_ShouldAddOnlyNonExistingPeople() + { + var existingPeople = new List + { + DbFactory.Person("Joe Shmo", PersonRole.CoverArtist), + DbFactory.Person("Joe Shmo", PersonRole.Writer), + DbFactory.Person("Sally", PersonRole.Writer), + }; + + + PersonHelper.AddPersonIfNotExists(existingPeople, DbFactory.Person("Joe Shmo", PersonRole.CoverArtist)); + Assert.Equal(3, existingPeople.Count); + + PersonHelper.AddPersonIfNotExists(existingPeople, DbFactory.Person("Joe Shmo", PersonRole.Writer)); + Assert.Equal(3, existingPeople.Count); + + PersonHelper.AddPersonIfNotExists(existingPeople, DbFactory.Person("Joe Shmo Two", PersonRole.CoverArtist)); + Assert.Equal(4, existingPeople.Count); + } +} diff --git a/API.Tests/Helpers/SeriesHelperTests.cs b/API.Tests/Helpers/SeriesHelperTests.cs new file mode 100644 index 000000000..8acd4bb85 --- /dev/null +++ b/API.Tests/Helpers/SeriesHelperTests.cs @@ -0,0 +1,160 @@ +using System.Collections.Generic; +using System.Linq; +using API.Data; +using API.Entities; +using API.Entities.Enums; +using API.Helpers; +using API.Services.Tasks.Scanner; +using Xunit; + +namespace API.Tests.Helpers; + +public class SeriesHelperTests +{ + #region FindSeries + [Fact] + public void FindSeries_ShouldFind_SameFormat() + { + var series = DbFactory.Series("Darker than Black"); + series.OriginalName = "Something Random"; + series.Format = MangaFormat.Archive; + Assert.True(SeriesHelper.FindSeries(series, new ParsedSeries() + { + Format = MangaFormat.Archive, + Name = "Darker than Black", + NormalizedName = API.Parser.Parser.Normalize("Darker than Black") + })); + + Assert.True(SeriesHelper.FindSeries(series, new ParsedSeries() + { + Format = MangaFormat.Archive, + Name = "Darker than Black".ToLower(), + NormalizedName = API.Parser.Parser.Normalize("Darker than Black") + })); + + Assert.True(SeriesHelper.FindSeries(series, new ParsedSeries() + { + Format = MangaFormat.Archive, + Name = "Darker than Black".ToUpper(), + NormalizedName = API.Parser.Parser.Normalize("Darker than Black") + })); + } + + [Fact] + public void FindSeries_ShouldNotFind_WrongFormat() + { + var series = DbFactory.Series("Darker than Black"); + series.OriginalName = "Something Random"; + series.Format = MangaFormat.Archive; + Assert.False(SeriesHelper.FindSeries(series, new ParsedSeries() + { + Format = MangaFormat.Image, + Name = "Darker than Black", + NormalizedName = API.Parser.Parser.Normalize("Darker than Black") + })); + + Assert.False(SeriesHelper.FindSeries(series, new ParsedSeries() + { + Format = MangaFormat.Image, + Name = "Darker than Black".ToLower(), + NormalizedName = API.Parser.Parser.Normalize("Darker than Black") + })); + + Assert.False(SeriesHelper.FindSeries(series, new ParsedSeries() + { + Format = MangaFormat.Image, + Name = "Darker than Black".ToUpper(), + NormalizedName = API.Parser.Parser.Normalize("Darker than Black") + })); + } + + [Fact] + public void FindSeries_ShouldFind_UsingOriginalName() + { + var series = DbFactory.Series("Darker than Black"); + series.OriginalName = "Something Random"; + series.Format = MangaFormat.Image; + Assert.True(SeriesHelper.FindSeries(series, new ParsedSeries() + { + Format = MangaFormat.Image, + Name = "Something Random", + NormalizedName = API.Parser.Parser.Normalize("Something Random") + })); + + Assert.True(SeriesHelper.FindSeries(series, new ParsedSeries() + { + Format = MangaFormat.Image, + Name = "Something Random".ToLower(), + NormalizedName = API.Parser.Parser.Normalize("Something Random") + })); + + Assert.True(SeriesHelper.FindSeries(series, new ParsedSeries() + { + Format = MangaFormat.Image, + Name = "Something Random".ToUpper(), + NormalizedName = API.Parser.Parser.Normalize("Something Random") + })); + + Assert.True(SeriesHelper.FindSeries(series, new ParsedSeries() + { + Format = MangaFormat.Image, + Name = "SomethingRandom".ToUpper(), + NormalizedName = API.Parser.Parser.Normalize("SomethingRandom") + })); + } + + [Fact] + public void FindSeries_ShouldFind_UsingLocalizedName() + { + var series = DbFactory.Series("Darker than Black"); + series.LocalizedName = "Something Random"; + series.Format = MangaFormat.Image; + Assert.True(SeriesHelper.FindSeries(series, new ParsedSeries() + { + Format = MangaFormat.Image, + Name = "Something Random", + NormalizedName = API.Parser.Parser.Normalize("Something Random") + })); + + Assert.True(SeriesHelper.FindSeries(series, new ParsedSeries() + { + Format = MangaFormat.Image, + Name = "Something Random".ToLower(), + NormalizedName = API.Parser.Parser.Normalize("Something Random") + })); + + Assert.True(SeriesHelper.FindSeries(series, new ParsedSeries() + { + Format = MangaFormat.Image, + Name = "Something Random".ToUpper(), + NormalizedName = API.Parser.Parser.Normalize("Something Random") + })); + + Assert.True(SeriesHelper.FindSeries(series, new ParsedSeries() + { + Format = MangaFormat.Image, + Name = "SomethingRandom".ToUpper(), + NormalizedName = API.Parser.Parser.Normalize("SomethingRandom") + })); + } + #endregion + + [Fact] + public void RemoveMissingSeries_Should_RemoveSeries() + { + var existingSeries = new List() + { + EntityFactory.CreateSeries("Darker than Black Vol 1"), + EntityFactory.CreateSeries("Darker than Black"), + EntityFactory.CreateSeries("Beastars"), + }; + var missingSeries = new List() + { + EntityFactory.CreateSeries("Darker than Black Vol 1"), + }; + existingSeries = SeriesHelper.RemoveMissingSeries(existingSeries, missingSeries, out var removeCount).ToList(); + + Assert.DoesNotContain(missingSeries[0].Name, existingSeries.Select(s => s.Name)); + Assert.Equal(missingSeries.Count, removeCount); + } +} diff --git a/API.Tests/Helpers/TagHelperTests.cs b/API.Tests/Helpers/TagHelperTests.cs new file mode 100644 index 000000000..5370d9971 --- /dev/null +++ b/API.Tests/Helpers/TagHelperTests.cs @@ -0,0 +1,119 @@ +using System.Collections.Generic; +using API.Data; +using API.Entities; +using API.Helpers; +using Xunit; + +namespace API.Tests.Helpers; + +public class TagHelperTests +{ + [Fact] + public void UpdateTag_ShouldAddNewTag() + { + var allTags = new List + { + DbFactory.Tag("Action", false), + DbFactory.Tag("action", false), + DbFactory.Tag("Sci-fi", false), + }; + var tagAdded = new List(); + + TagHelper.UpdateTag(allTags, new[] {"Action", "Adventure"}, false, (tag, added) => + { + if (added) + { + tagAdded.Add(tag); + } + + }); + + Assert.Equal(1, tagAdded.Count); + Assert.Equal(4, allTags.Count); + } + + [Fact] + public void UpdateTag_ShouldNotAddDuplicateTag() + { + var allTags = new List + { + DbFactory.Tag("Action", false), + DbFactory.Tag("action", false), + DbFactory.Tag("Sci-fi", false), + + }; + var tagAdded = new List(); + + TagHelper.UpdateTag(allTags, new[] {"Action", "Scifi"}, false, (tag, added) => + { + if (added) + { + tagAdded.Add(tag); + } + TagHelper.AddTagIfNotExists(allTags, tag); + }); + + Assert.Equal(3, allTags.Count); + Assert.Empty(tagAdded); + } + + [Fact] + public void AddTag_ShouldAddOnlyNonExistingTag() + { + var existingTags = new List + { + DbFactory.Tag("Action", false), + DbFactory.Tag("action", false), + DbFactory.Tag("Sci-fi", false), + }; + + + TagHelper.AddTagIfNotExists(existingTags, DbFactory.Tag("Action", false)); + Assert.Equal(3, existingTags.Count); + + TagHelper.AddTagIfNotExists(existingTags, DbFactory.Tag("action", false)); + Assert.Equal(3, existingTags.Count); + + TagHelper.AddTagIfNotExists(existingTags, DbFactory.Tag("Shonen", false)); + Assert.Equal(4, existingTags.Count); + } + + [Fact] + public void AddTag_ShouldNotAddSameNameAndExternal() + { + var existingTags = new List + { + DbFactory.Tag("Action", false), + DbFactory.Tag("action", false), + DbFactory.Tag("Sci-fi", false), + }; + + + TagHelper.AddTagIfNotExists(existingTags, DbFactory.Tag("Action", true)); + Assert.Equal(3, existingTags.Count); + } + + [Fact] + public void KeepOnlySamePeopleBetweenLists() + { + var existingTags = new List + { + DbFactory.Tag("Action", false), + DbFactory.Tag("Sci-fi", false), + }; + + var peopleFromChapters = new List + { + DbFactory.Tag("Action", false), + }; + + var tagRemoved = new List(); + TagHelper.KeepOnlySameTagBetweenLists(existingTags, + peopleFromChapters, tag => + { + tagRemoved.Add(tag); + }); + + Assert.Equal(1, tagRemoved.Count); + } +} diff --git a/API.Tests/Parser/ComicParserTests.cs b/API.Tests/Parser/ComicParserTests.cs index 043c0e027..fe0cd0961 100644 --- a/API.Tests/Parser/ComicParserTests.cs +++ b/API.Tests/Parser/ComicParserTests.cs @@ -1,7 +1,10 @@ -using System; using System.Collections.Generic; +using System.IO.Abstractions.TestingHelpers; using API.Entities.Enums; using API.Parser; +using API.Services; +using Microsoft.Extensions.Logging; +using NSubstitute; using Xunit; using Xunit.Abstractions; @@ -10,10 +13,14 @@ namespace API.Tests.Parser public class ComicParserTests { private readonly ITestOutputHelper _testOutputHelper; + private readonly DefaultParser _defaultParser; public ComicParserTests(ITestOutputHelper testOutputHelper) { _testOutputHelper = testOutputHelper; + _defaultParser = + new DefaultParser(new DirectoryService(Substitute.For>(), + new MockFileSystem())); } [Theory] @@ -61,8 +68,17 @@ namespace API.Tests.Parser [InlineData("Demon 012 (Sep 1973) c2c", "Demon")] [InlineData("Dragon Age - Until We Sleep 01 (of 03)", "Dragon Age - Until We Sleep")] [InlineData("Green Lantern v2 017 - The Spy-Eye that doomed Green Lantern v2", "Green Lantern")] - [InlineData("Green Lantern - Circle of Fire Special - Adam Strange (2000)", "Green Lantern - Circle of Fire - Adam Strange")] - [InlineData("Identity Crisis Extra - Rags Morales Sketches (2005)", "Identity Crisis - Rags Morales Sketches")] + [InlineData("Green Lantern - Circle of Fire Special - Adam Strange (2000)", "Green Lantern - Circle of Fire - Adam Strange")] + [InlineData("Identity Crisis Extra - Rags Morales Sketches (2005)", "Identity Crisis - Rags Morales Sketches")] + [InlineData("Daredevil - t6 - 10 - (2019)", "Daredevil")] + [InlineData("Batgirl T2000 #57", "Batgirl")] + [InlineData("Teen Titans t1 001 (1966-02) (digital) (OkC.O.M.P.U.T.O.-Novus)", "Teen Titans")] + [InlineData("Conquistador_-Tome_2", "Conquistador")] + [InlineData("Max_l_explorateur-_Tome_0", "Max l explorateur")] + [InlineData("Chevaliers d'Héliopolis T3 - Rubedo, l'oeuvre au rouge (Jodorowsky & Jérémy)", "Chevaliers d'Héliopolis")] + [InlineData("Bd Fr-Aldebaran-Antares-t6", "Aldebaran-Antares")] + [InlineData("Tintin - T22 Vol 714 pour Sydney", "Tintin")] + [InlineData("Fables 2010 Vol. 1 Legends in Exile", "Fables 2010")] public void ParseComicSeriesTest(string filename, string expected) { Assert.Equal(expected, API.Parser.Parser.ParseComicSeries(filename)); @@ -101,6 +117,15 @@ namespace API.Tests.Parser [InlineData("Cyberpunk 2077 - Trauma Team 04.cbz", "0")] [InlineData("2000 AD 0366 [1984-04-28] (flopbie)", "0")] [InlineData("Daredevil - v6 - 10 - (2019)", "6")] + // Tome Tests + [InlineData("Daredevil - t6 - 10 - (2019)", "6")] + [InlineData("Batgirl T2000 #57", "2000")] + [InlineData("Teen Titans t1 001 (1966-02) (digital) (OkC.O.M.P.U.T.O.-Novus)", "1")] + [InlineData("Conquistador_Tome_2", "2")] + [InlineData("Max_l_explorateur-_Tome_0", "0")] + [InlineData("Chevaliers d'Héliopolis T3 - Rubedo, l'oeuvre au rouge (Jodorowsky & Jérémy)", "3")] + [InlineData("Adventure Time (2012)/Adventure Time #1 (2012)", "0")] + [InlineData("Adventure Time TPB (2012)/Adventure Time v01 (2012).cbz", "1")] public void ParseComicVolumeTest(string filename, string expected) { Assert.Equal(expected, API.Parser.Parser.ParseComicVolume(filename)); @@ -144,6 +169,8 @@ namespace API.Tests.Parser [InlineData("2000 AD 0366 [1984-04-28] (flopbie)", "366")] [InlineData("Daredevil - v6 - 10 - (2019)", "10")] [InlineData("Batman Beyond 2016 - Chapter 001.cbz", "1")] + [InlineData("Adventure Time (2012)/Adventure Time #1 (2012)", "1")] + [InlineData("Adventure Time TPB (2012)/Adventure Time v01 (2012).cbz", "0")] public void ParseComicChapterTest(string filename, string expected) { Assert.Equal(expected, API.Parser.Parser.ParseComicChapter(filename)); @@ -155,76 +182,13 @@ namespace API.Tests.Parser [InlineData("Zombie Tramp vs. Vampblade TPB (2016) (Digital) (TheArchivist-Empire)", true)] [InlineData("Baldwin the Brave & Other Tales Special SP1.cbr", true)] [InlineData("Mouse Guard Specials - Spring 1153 - Fraggle Rock FCBD 2010", true)] + [InlineData("Boule et Bill - THS -Bill à disparu", true)] + [InlineData("Asterix - HS - Les 12 travaux d'Astérix", true)] + [InlineData("Sillage Hors Série - Le Collectionneur - Concordance-DKFR", true)] + [InlineData("laughs", false)] public void ParseComicSpecialTest(string input, bool expected) { Assert.Equal(expected, !string.IsNullOrEmpty(API.Parser.Parser.ParseComicSpecial(input))); } - - [Fact] - public void ParseInfoTest() - { - const string rootPath = @"E:/Comics/"; - var expected = new Dictionary(); - var filepath = @"E:/Comics/Teen Titans/Teen Titans v1 Annual 01 (1967) SP01.cbr"; - expected.Add(filepath, new ParserInfo - { - Series = "Teen Titans", Volumes = "0", - Chapters = "0", Filename = "Teen Titans v1 Annual 01 (1967) SP01.cbr", Format = MangaFormat.Archive, - FullFilePath = filepath - }); - - // Fallback test with bad naming - filepath = @"E:\Comics\Comics\Babe\Babe Vol.1 #1-4\Babe 01.cbr"; - expected.Add(filepath, new ParserInfo - { - Series = "Babe", Volumes = "0", Edition = "", - Chapters = "1", Filename = "Babe 01.cbr", Format = MangaFormat.Archive, - FullFilePath = filepath, IsSpecial = false - }); - - filepath = @"E:\Comics\Comics\Publisher\Batman the Detective (2021)\Batman the Detective - v6 - 11 - (2021).cbr"; - expected.Add(filepath, new ParserInfo - { - Series = "Batman the Detective", Volumes = "6", Edition = "", - Chapters = "11", Filename = "Batman the Detective - v6 - 11 - (2021).cbr", Format = MangaFormat.Archive, - FullFilePath = filepath, IsSpecial = false - }); - - filepath = @"E:\Comics\Comics\Batman - The Man Who Laughs #1 (2005)\Batman - The Man Who Laughs #1 (2005).cbr"; - expected.Add(filepath, new ParserInfo - { - Series = "Batman - The Man Who Laughs", Volumes = "0", Edition = "", - Chapters = "1", Filename = "Batman - The Man Who Laughs #1 (2005).cbr", Format = MangaFormat.Archive, - FullFilePath = filepath, IsSpecial = false - }); - - foreach (var file in expected.Keys) - { - var expectedInfo = expected[file]; - var actual = API.Parser.Parser.Parse(file, rootPath, LibraryType.Comic); - if (expectedInfo == null) - { - Assert.Null(actual); - return; - } - Assert.NotNull(actual); - _testOutputHelper.WriteLine($"Validating {file}"); - Assert.Equal(expectedInfo.Format, actual.Format); - _testOutputHelper.WriteLine("Format ✓"); - Assert.Equal(expectedInfo.Series, actual.Series); - _testOutputHelper.WriteLine("Series ✓"); - Assert.Equal(expectedInfo.Chapters, actual.Chapters); - _testOutputHelper.WriteLine("Chapters ✓"); - Assert.Equal(expectedInfo.Volumes, actual.Volumes); - _testOutputHelper.WriteLine("Volumes ✓"); - Assert.Equal(expectedInfo.Edition, actual.Edition); - _testOutputHelper.WriteLine("Edition ✓"); - Assert.Equal(expectedInfo.Filename, actual.Filename); - _testOutputHelper.WriteLine("Filename ✓"); - Assert.Equal(expectedInfo.FullFilePath, actual.FullFilePath); - _testOutputHelper.WriteLine("FullFilePath ✓"); - } - } - } } diff --git a/API.Tests/Parser/DefaultParserTests.cs b/API.Tests/Parser/DefaultParserTests.cs new file mode 100644 index 000000000..a9c593de9 --- /dev/null +++ b/API.Tests/Parser/DefaultParserTests.cs @@ -0,0 +1,312 @@ +using System.Collections.Generic; +using System.IO.Abstractions.TestingHelpers; +using API.Entities.Enums; +using API.Parser; +using API.Services; +using Microsoft.Extensions.Logging; +using NSubstitute; +using Xunit; +using Xunit.Abstractions; + +namespace API.Tests.Parser; + +public class DefaultParserTests +{ + private readonly ITestOutputHelper _testOutputHelper; + private readonly DefaultParser _defaultParser; + + public DefaultParserTests(ITestOutputHelper testOutputHelper) + { + _testOutputHelper = testOutputHelper; + var directoryService = new DirectoryService(Substitute.For>(), new MockFileSystem()); + _defaultParser = new DefaultParser(directoryService); + } + + + #region ParseFromFallbackFolders + [Theory] + [InlineData("C:/", "C:/Love Hina/Love Hina - Special.cbz", "Love Hina")] + [InlineData("C:/", "C:/Love Hina/Specials/Ani-Hina Art Collection.cbz", "Love Hina")] + [InlineData("C:/", "C:/Mujaki no Rakuen Something/Mujaki no Rakuen Vol12 ch76.cbz", "Mujaki no Rakuen")] + [InlineData("C:/", "C:/Something Random/Mujaki no Rakuen SP01.cbz", "Something Random")] + public void ParseFromFallbackFolders_FallbackShouldParseSeries(string rootDir, string inputPath, string expectedSeries) + { + var actual = _defaultParser.Parse(inputPath, rootDir); + if (actual == null) + { + Assert.NotNull(actual); + return; + } + + Assert.Equal(expectedSeries, actual.Series); + } + + [Theory] + [InlineData("/manga/Btooom!/Vol.1/Chapter 1/1.cbz", "Btooom!~1~1")] + [InlineData("/manga/Btooom!/Vol.1 Chapter 2/1.cbz", "Btooom!~1~2")] + [InlineData("/manga/Monster #8/Ch. 001-016 [MangaPlus] [Digital] [amit34521]/Monster #8 Ch. 001 [MangaPlus] [Digital] [amit34521]/13.jpg", "Monster #8~0~1")] + public void ParseFromFallbackFolders_ShouldParseSeriesVolumeAndChapter(string inputFile, string expectedParseInfo) + { + const string rootDirectory = "/manga/"; + var tokens = expectedParseInfo.Split("~"); + var actual = new ParserInfo {Chapters = "0", Volumes = "0"}; + _defaultParser.ParseFromFallbackFolders(inputFile, rootDirectory, LibraryType.Manga, ref actual); + Assert.Equal(tokens[0], actual.Series); + Assert.Equal(tokens[1], actual.Volumes); + Assert.Equal(tokens[2], actual.Chapters); + } + + #endregion + + + #region Parse + + [Fact] + public void Parse_ParseInfo_Manga() + { + const string rootPath = @"E:/Manga/"; + var expected = new Dictionary(); + var filepath = @"E:/Manga/Mujaki no Rakuen/Mujaki no Rakuen Vol12 ch76.cbz"; + expected.Add(filepath, new ParserInfo + { + Series = "Mujaki no Rakuen", Volumes = "12", + Chapters = "76", Filename = "Mujaki no Rakuen Vol12 ch76.cbz", Format = MangaFormat.Archive, + FullFilePath = filepath + }); + + filepath = @"E:/Manga/Shimoneta to Iu Gainen ga Sonzai Shinai Taikutsu na Sekai Man-hen/Vol 1.cbz"; + expected.Add(filepath, new ParserInfo + { + Series = "Shimoneta to Iu Gainen ga Sonzai Shinai Taikutsu na Sekai Man-hen", Volumes = "1", + Chapters = "0", Filename = "Vol 1.cbz", Format = MangaFormat.Archive, + FullFilePath = filepath + }); + + filepath = @"E:\Manga\Beelzebub\Beelzebub_01_[Noodles].zip"; + expected.Add(filepath, new ParserInfo + { + Series = "Beelzebub", Volumes = "0", + Chapters = "1", Filename = "Beelzebub_01_[Noodles].zip", Format = MangaFormat.Archive, + FullFilePath = filepath + }); + + filepath = @"E:\Manga\Ichinensei ni Nacchattara\Ichinensei_ni_Nacchattara_v01_ch01_[Taruby]_v1.1.zip"; + expected.Add(filepath, new ParserInfo + { + Series = "Ichinensei ni Nacchattara", Volumes = "1", + Chapters = "1", Filename = "Ichinensei_ni_Nacchattara_v01_ch01_[Taruby]_v1.1.zip", Format = MangaFormat.Archive, + FullFilePath = filepath + }); + + filepath = @"E:\Manga\Tenjo Tenge (Color)\Tenjo Tenge {Full Contact Edition} v01 (2011) (Digital) (ASTC).cbz"; + expected.Add(filepath, new ParserInfo + { + Series = "Tenjo Tenge", Volumes = "1", Edition = "Full Contact Edition", + Chapters = "0", Filename = "Tenjo Tenge {Full Contact Edition} v01 (2011) (Digital) (ASTC).cbz", Format = MangaFormat.Archive, + FullFilePath = filepath + }); + + filepath = @"E:\Manga\Akame ga KILL! ZERO (2016-2019) (Digital) (LuCaZ)\Akame ga KILL! ZERO v01 (2016) (Digital) (LuCaZ).cbz"; + expected.Add(filepath, new ParserInfo + { + Series = "Akame ga KILL! ZERO", Volumes = "1", Edition = "", + Chapters = "0", Filename = "Akame ga KILL! ZERO v01 (2016) (Digital) (LuCaZ).cbz", Format = MangaFormat.Archive, + FullFilePath = filepath + }); + + filepath = @"E:\Manga\Dorohedoro\Dorohedoro v01 (2010) (Digital) (LostNerevarine-Empire).cbz"; + expected.Add(filepath, new ParserInfo + { + Series = "Dorohedoro", Volumes = "1", Edition = "", + Chapters = "0", Filename = "Dorohedoro v01 (2010) (Digital) (LostNerevarine-Empire).cbz", Format = MangaFormat.Archive, + FullFilePath = filepath + }); + + filepath = @"E:\Manga\APOSIMZ\APOSIMZ 040 (2020) (Digital) (danke-Empire).cbz"; + expected.Add(filepath, new ParserInfo + { + Series = "APOSIMZ", Volumes = "0", Edition = "", + Chapters = "40", Filename = "APOSIMZ 040 (2020) (Digital) (danke-Empire).cbz", Format = MangaFormat.Archive, + FullFilePath = filepath + }); + + filepath = @"E:\Manga\Corpse Party Musume\Kedouin Makoto - Corpse Party Musume, Chapter 09.cbz"; + expected.Add(filepath, new ParserInfo + { + Series = "Kedouin Makoto - Corpse Party Musume", Volumes = "0", Edition = "", + Chapters = "9", Filename = "Kedouin Makoto - Corpse Party Musume, Chapter 09.cbz", Format = MangaFormat.Archive, + FullFilePath = filepath + }); + + filepath = @"E:\Manga\Goblin Slayer\Goblin Slayer - Brand New Day 006.5 (2019) (Digital) (danke-Empire).cbz"; + expected.Add(filepath, new ParserInfo + { + Series = "Goblin Slayer - Brand New Day", Volumes = "0", Edition = "", + Chapters = "6.5", Filename = "Goblin Slayer - Brand New Day 006.5 (2019) (Digital) (danke-Empire).cbz", Format = MangaFormat.Archive, + FullFilePath = filepath + }); + + filepath = @"E:\Manga\Summer Time Rendering\Specials\Record 014 (between chapter 083 and ch084) SP11.cbr"; + expected.Add(filepath, new ParserInfo + { + Series = "Summer Time Rendering", Volumes = "0", Edition = "", + Chapters = "0", Filename = "Record 014 (between chapter 083 and ch084) SP11.cbr", Format = MangaFormat.Archive, + FullFilePath = filepath, IsSpecial = true + }); + + filepath = @"E:\Manga\Seraph of the End\Seraph of the End - Vampire Reign 093 (2020) (Digital) (LuCaZ).cbz"; + expected.Add(filepath, new ParserInfo + { + Series = "Seraph of the End - Vampire Reign", Volumes = "0", Edition = "", + Chapters = "93", Filename = "Seraph of the End - Vampire Reign 093 (2020) (Digital) (LuCaZ).cbz", Format = MangaFormat.Archive, + FullFilePath = filepath, IsSpecial = false + }); + + filepath = @"E:\Manga\Kono Subarashii Sekai ni Bakuen wo!\Vol. 00 Ch. 000.cbz"; + expected.Add(filepath, new ParserInfo + { + Series = "Kono Subarashii Sekai ni Bakuen wo!", Volumes = "0", Edition = "", + Chapters = "0", Filename = "Vol. 00 Ch. 000.cbz", Format = MangaFormat.Archive, + FullFilePath = filepath, IsSpecial = false + }); + + filepath = @"E:\Manga\Toukyou Akazukin\Vol. 01 Ch. 001.cbz"; + expected.Add(filepath, new ParserInfo + { + Series = "Toukyou Akazukin", Volumes = "1", Edition = "", + Chapters = "1", Filename = "Vol. 01 Ch. 001.cbz", Format = MangaFormat.Archive, + FullFilePath = filepath, IsSpecial = false + }); + + filepath = @"E:\Manga\Harrison, Kim - The Good, The Bad, and the Undead - Hollows Vol 2.5.epub"; + expected.Add(filepath, new ParserInfo + { + Series = "Harrison, Kim - The Good, The Bad, and the Undead - Hollows", Volumes = "2.5", Edition = "", + Chapters = "0", Filename = "Harrison, Kim - The Good, The Bad, and the Undead - Hollows Vol 2.5.epub", Format = MangaFormat.Epub, + FullFilePath = filepath, IsSpecial = false + }); + + // If an image is cover exclusively, ignore it + filepath = @"E:\Manga\Seraph of the End\cover.png"; + expected.Add(filepath, null); + + filepath = @"E:\Manga\The Beginning After the End\Chapter 001.cbz"; + expected.Add(filepath, new ParserInfo + { + Series = "The Beginning After the End", Volumes = "0", Edition = "", + Chapters = "1", Filename = "Chapter 001.cbz", Format = MangaFormat.Archive, + FullFilePath = filepath, IsSpecial = false + }); + + filepath = @"E:\Manga\Monster #8\Ch. 001-016 [MangaPlus] [Digital] [amit34521]\Monster #8 Ch. 001 [MangaPlus] [Digital] [amit34521]\13.jpg"; + expected.Add(filepath, new ParserInfo + { + Series = "Monster #8", Volumes = "0", Edition = "", + Chapters = "1", Filename = "13.jpg", Format = MangaFormat.Archive, + FullFilePath = filepath, IsSpecial = false + }); + + filepath = @"E:\Manga\Air Gear\Air Gear Omnibus v01 (2016) (Digital) (Shadowcat-Empire).cbz"; + expected.Add(filepath, new ParserInfo + { + Series = "Air Gear", Volumes = "1", Edition = "Omnibus", + Chapters = "0", Filename = "Air Gear Omnibus v01 (2016) (Digital) (Shadowcat-Empire).cbz", Format = MangaFormat.Archive, + FullFilePath = filepath, IsSpecial = false + }); + + + foreach (var file in expected.Keys) + { + var expectedInfo = expected[file]; + var actual = _defaultParser.Parse(file, rootPath); + if (expectedInfo == null) + { + Assert.Null(actual); + return; + } + Assert.NotNull(actual); + _testOutputHelper.WriteLine($"Validating {file}"); + Assert.Equal(expectedInfo.Format, actual.Format); + _testOutputHelper.WriteLine("Format ✓"); + Assert.Equal(expectedInfo.Series, actual.Series); + _testOutputHelper.WriteLine("Series ✓"); + Assert.Equal(expectedInfo.Chapters, actual.Chapters); + _testOutputHelper.WriteLine("Chapters ✓"); + Assert.Equal(expectedInfo.Volumes, actual.Volumes); + _testOutputHelper.WriteLine("Volumes ✓"); + Assert.Equal(expectedInfo.Edition, actual.Edition); + _testOutputHelper.WriteLine("Edition ✓"); + Assert.Equal(expectedInfo.Filename, actual.Filename); + _testOutputHelper.WriteLine("Filename ✓"); + Assert.Equal(expectedInfo.FullFilePath, actual.FullFilePath); + _testOutputHelper.WriteLine("FullFilePath ✓"); + } + } + + [Fact] + public void Parse_ParseInfo_Comic() + { + const string rootPath = @"E:/Comics/"; + var expected = new Dictionary(); + var filepath = @"E:/Comics/Teen Titans/Teen Titans v1 Annual 01 (1967) SP01.cbr"; + expected.Add(filepath, new ParserInfo + { + Series = "Teen Titans", Volumes = "0", + Chapters = "0", Filename = "Teen Titans v1 Annual 01 (1967) SP01.cbr", Format = MangaFormat.Archive, + FullFilePath = filepath + }); + + // Fallback test with bad naming + filepath = @"E:\Comics\Comics\Babe\Babe Vol.1 #1-4\Babe 01.cbr"; + expected.Add(filepath, new ParserInfo + { + Series = "Babe", Volumes = "0", Edition = "", + Chapters = "1", Filename = "Babe 01.cbr", Format = MangaFormat.Archive, + FullFilePath = filepath, IsSpecial = false + }); + + filepath = @"E:\Comics\Comics\Publisher\Batman the Detective (2021)\Batman the Detective - v6 - 11 - (2021).cbr"; + expected.Add(filepath, new ParserInfo + { + Series = "Batman the Detective", Volumes = "6", Edition = "", + Chapters = "11", Filename = "Batman the Detective - v6 - 11 - (2021).cbr", Format = MangaFormat.Archive, + FullFilePath = filepath, IsSpecial = false + }); + + filepath = @"E:\Comics\Comics\Batman - The Man Who Laughs #1 (2005)\Batman - The Man Who Laughs #1 (2005).cbr"; + expected.Add(filepath, new ParserInfo + { + Series = "Batman - The Man Who Laughs", Volumes = "0", Edition = "", + Chapters = "1", Filename = "Batman - The Man Who Laughs #1 (2005).cbr", Format = MangaFormat.Archive, + FullFilePath = filepath, IsSpecial = false + }); + + foreach (var file in expected.Keys) + { + var expectedInfo = expected[file]; + var actual = _defaultParser.Parse(file, rootPath, LibraryType.Comic); + if (expectedInfo == null) + { + Assert.Null(actual); + return; + } + Assert.NotNull(actual); + _testOutputHelper.WriteLine($"Validating {file}"); + Assert.Equal(expectedInfo.Format, actual.Format); + _testOutputHelper.WriteLine("Format ✓"); + Assert.Equal(expectedInfo.Series, actual.Series); + _testOutputHelper.WriteLine("Series ✓"); + Assert.Equal(expectedInfo.Chapters, actual.Chapters); + _testOutputHelper.WriteLine("Chapters ✓"); + Assert.Equal(expectedInfo.Volumes, actual.Volumes); + _testOutputHelper.WriteLine("Volumes ✓"); + Assert.Equal(expectedInfo.Edition, actual.Edition); + _testOutputHelper.WriteLine("Edition ✓"); + Assert.Equal(expectedInfo.Filename, actual.Filename); + _testOutputHelper.WriteLine("Filename ✓"); + Assert.Equal(expectedInfo.FullFilePath, actual.FullFilePath); + _testOutputHelper.WriteLine("FullFilePath ✓"); + } + } + #endregion +} diff --git a/API.Tests/Parser/MangaParserTests.cs b/API.Tests/Parser/MangaParserTests.cs index 1576cbb07..fe4dd5e42 100644 --- a/API.Tests/Parser/MangaParserTests.cs +++ b/API.Tests/Parser/MangaParserTests.cs @@ -167,6 +167,9 @@ namespace API.Tests.Parser [InlineData("Great_Teacher_Onizuka_v16[TheSpectrum]", "Great Teacher Onizuka")] [InlineData("[Renzokusei]_Kimi_wa_Midara_na_Boku_no_Joou_Ch5_Final_Chapter", "Kimi wa Midara na Boku no Joou")] [InlineData("Battle Royale, v01 (2000) [TokyoPop] [Manga-Sketchbook]", "Battle Royale")] + [InlineData("Kaiju No. 8 036 (2021) (Digital)", "Kaiju No. 8")] + [InlineData("Seraph of the End - Vampire Reign 093 (2020) (Digital) (LuCaZ).cbz", "Seraph of the End - Vampire Reign")] + [InlineData("Love Hina - Volume 01 [Scans].pdf", "Love Hina")] public void ParseSeriesTest(string filename, string expected) { Assert.Equal(expected, API.Parser.Parser.ParseSeries(filename)); @@ -240,6 +243,8 @@ namespace API.Tests.Parser [InlineData("Deku_&_Bakugo_-_Rising_v1_c1.1.cbz", "1.1")] [InlineData("Chapter 63 - The Promise Made for 520 Cenz.cbr", "63")] [InlineData("Harrison, Kim - The Good, The Bad, and the Undead - Hollows Vol 2.5.epub", "0")] + [InlineData("Kaiju No. 8 036 (2021) (Digital)", "36")] + [InlineData("Samurai Jack Vol. 01 - The threads of Time", "0")] public void ParseChaptersTest(string filename, string expected) { Assert.Equal(expected, API.Parser.Parser.ParseChapter(filename)); @@ -255,6 +260,7 @@ namespace API.Tests.Parser [InlineData("Chobits Omnibus Edition v01 [Dark Horse]", "Omnibus Edition")] [InlineData("[dmntsf.net] One Piece - Digital Colored Comics Vol. 20 Ch. 177 - 30 Million vs 81 Million.cbz", "")] [InlineData("AKIRA - c003 (v01) [Full Color] [Darkhorse].cbz", "Full Color")] + [InlineData("Love Hina Omnibus v05 (2015) (Digital-HD) (Asgard-Empire).cbz", "Omnibus")] public void ParseEditionTest(string input, string expected) { Assert.Equal(expected, API.Parser.Parser.ParseEdition(input)); @@ -272,6 +278,8 @@ namespace API.Tests.Parser [InlineData("Yuki Merry - 4-Komga Anthology", false)] [InlineData("Beastars - SP01", false)] [InlineData("Beastars SP01", false)] + [InlineData("The League of Extraordinary Gentlemen", false)] + [InlineData("The League of Extra-ordinary Gentlemen", false)] public void ParseMangaSpecialTest(string input, bool expected) { Assert.Equal(expected, !string.IsNullOrEmpty(API.Parser.Parser.ParseMangaSpecial(input))); @@ -294,194 +302,6 @@ namespace API.Tests.Parser } - [Theory] - [InlineData("/manga/Btooom!/Vol.1/Chapter 1/1.cbz", "Btooom!~1~1")] - [InlineData("/manga/Btooom!/Vol.1 Chapter 2/1.cbz", "Btooom!~1~2")] - [InlineData("/manga/Monster #8/Ch. 001-016 [MangaPlus] [Digital] [amit34521]/Monster #8 Ch. 001 [MangaPlus] [Digital] [amit34521]/13.jpg", "Monster #8~0~1")] - public void ParseFromFallbackFoldersTest(string inputFile, string expectedParseInfo) - { - const string rootDirectory = "/manga/"; - var tokens = expectedParseInfo.Split("~"); - var actual = new ParserInfo {Chapters = "0", Volumes = "0"}; - API.Parser.Parser.ParseFromFallbackFolders(inputFile, rootDirectory, LibraryType.Manga, ref actual); - Assert.Equal(tokens[0], actual.Series); - Assert.Equal(tokens[1], actual.Volumes); - Assert.Equal(tokens[2], actual.Chapters); - } - - [Fact] - public void ParseInfoTest() - { - const string rootPath = @"E:/Manga/"; - var expected = new Dictionary(); - var filepath = @"E:/Manga/Mujaki no Rakuen/Mujaki no Rakuen Vol12 ch76.cbz"; - expected.Add(filepath, new ParserInfo - { - Series = "Mujaki no Rakuen", Volumes = "12", - Chapters = "76", Filename = "Mujaki no Rakuen Vol12 ch76.cbz", Format = MangaFormat.Archive, - FullFilePath = filepath - }); - - filepath = @"E:/Manga/Shimoneta to Iu Gainen ga Sonzai Shinai Taikutsu na Sekai Man-hen/Vol 1.cbz"; - expected.Add(filepath, new ParserInfo - { - Series = "Shimoneta to Iu Gainen ga Sonzai Shinai Taikutsu na Sekai Man-hen", Volumes = "1", - Chapters = "0", Filename = "Vol 1.cbz", Format = MangaFormat.Archive, - FullFilePath = filepath - }); - - filepath = @"E:\Manga\Beelzebub\Beelzebub_01_[Noodles].zip"; - expected.Add(filepath, new ParserInfo - { - Series = "Beelzebub", Volumes = "0", - Chapters = "1", Filename = "Beelzebub_01_[Noodles].zip", Format = MangaFormat.Archive, - FullFilePath = filepath - }); - - filepath = @"E:\Manga\Ichinensei ni Nacchattara\Ichinensei_ni_Nacchattara_v01_ch01_[Taruby]_v1.1.zip"; - expected.Add(filepath, new ParserInfo - { - Series = "Ichinensei ni Nacchattara", Volumes = "1", - Chapters = "1", Filename = "Ichinensei_ni_Nacchattara_v01_ch01_[Taruby]_v1.1.zip", Format = MangaFormat.Archive, - FullFilePath = filepath - }); - - filepath = @"E:\Manga\Tenjo Tenge (Color)\Tenjo Tenge {Full Contact Edition} v01 (2011) (Digital) (ASTC).cbz"; - expected.Add(filepath, new ParserInfo - { - Series = "Tenjo Tenge", Volumes = "1", Edition = "Full Contact Edition", - Chapters = "0", Filename = "Tenjo Tenge {Full Contact Edition} v01 (2011) (Digital) (ASTC).cbz", Format = MangaFormat.Archive, - FullFilePath = filepath - }); - - filepath = @"E:\Manga\Akame ga KILL! ZERO (2016-2019) (Digital) (LuCaZ)\Akame ga KILL! ZERO v01 (2016) (Digital) (LuCaZ).cbz"; - expected.Add(filepath, new ParserInfo - { - Series = "Akame ga KILL! ZERO", Volumes = "1", Edition = "", - Chapters = "0", Filename = "Akame ga KILL! ZERO v01 (2016) (Digital) (LuCaZ).cbz", Format = MangaFormat.Archive, - FullFilePath = filepath - }); - - filepath = @"E:\Manga\Dorohedoro\Dorohedoro v01 (2010) (Digital) (LostNerevarine-Empire).cbz"; - expected.Add(filepath, new ParserInfo - { - Series = "Dorohedoro", Volumes = "1", Edition = "", - Chapters = "0", Filename = "Dorohedoro v01 (2010) (Digital) (LostNerevarine-Empire).cbz", Format = MangaFormat.Archive, - FullFilePath = filepath - }); - - filepath = @"E:\Manga\APOSIMZ\APOSIMZ 040 (2020) (Digital) (danke-Empire).cbz"; - expected.Add(filepath, new ParserInfo - { - Series = "APOSIMZ", Volumes = "0", Edition = "", - Chapters = "40", Filename = "APOSIMZ 040 (2020) (Digital) (danke-Empire).cbz", Format = MangaFormat.Archive, - FullFilePath = filepath - }); - - filepath = @"E:\Manga\Corpse Party Musume\Kedouin Makoto - Corpse Party Musume, Chapter 09.cbz"; - expected.Add(filepath, new ParserInfo - { - Series = "Kedouin Makoto - Corpse Party Musume", Volumes = "0", Edition = "", - Chapters = "9", Filename = "Kedouin Makoto - Corpse Party Musume, Chapter 09.cbz", Format = MangaFormat.Archive, - FullFilePath = filepath - }); - - filepath = @"E:\Manga\Goblin Slayer\Goblin Slayer - Brand New Day 006.5 (2019) (Digital) (danke-Empire).cbz"; - expected.Add(filepath, new ParserInfo - { - Series = "Goblin Slayer - Brand New Day", Volumes = "0", Edition = "", - Chapters = "6.5", Filename = "Goblin Slayer - Brand New Day 006.5 (2019) (Digital) (danke-Empire).cbz", Format = MangaFormat.Archive, - FullFilePath = filepath - }); - - filepath = @"E:\Manga\Summer Time Rendering\Specials\Record 014 (between chapter 083 and ch084) SP11.cbr"; - expected.Add(filepath, new ParserInfo - { - Series = "Summer Time Rendering", Volumes = "0", Edition = "", - Chapters = "0", Filename = "Record 014 (between chapter 083 and ch084) SP11.cbr", Format = MangaFormat.Archive, - FullFilePath = filepath, IsSpecial = true - }); - - filepath = @"E:\Manga\Seraph of the End\Seraph of the End - Vampire Reign 093 (2020) (Digital) (LuCaZ).cbz"; - expected.Add(filepath, new ParserInfo - { - Series = "Seraph of the End - Vampire Reign", Volumes = "0", Edition = "", - Chapters = "93", Filename = "Seraph of the End - Vampire Reign 093 (2020) (Digital) (LuCaZ).cbz", Format = MangaFormat.Archive, - FullFilePath = filepath, IsSpecial = false - }); - - filepath = @"E:\Manga\Kono Subarashii Sekai ni Bakuen wo!\Vol. 00 Ch. 000.cbz"; - expected.Add(filepath, new ParserInfo - { - Series = "Kono Subarashii Sekai ni Bakuen wo!", Volumes = "0", Edition = "", - Chapters = "0", Filename = "Vol. 00 Ch. 000.cbz", Format = MangaFormat.Archive, - FullFilePath = filepath, IsSpecial = false - }); - - filepath = @"E:\Manga\Toukyou Akazukin\Vol. 01 Ch. 001.cbz"; - expected.Add(filepath, new ParserInfo - { - Series = "Toukyou Akazukin", Volumes = "1", Edition = "", - Chapters = "1", Filename = "Vol. 01 Ch. 001.cbz", Format = MangaFormat.Archive, - FullFilePath = filepath, IsSpecial = false - }); - - filepath = @"E:\Manga\Harrison, Kim - The Good, The Bad, and the Undead - Hollows Vol 2.5.epub"; - expected.Add(filepath, new ParserInfo - { - Series = "Harrison, Kim - The Good, The Bad, and the Undead - Hollows", Volumes = "2.5", Edition = "", - Chapters = "0", Filename = "Harrison, Kim - The Good, The Bad, and the Undead - Hollows Vol 2.5.epub", Format = MangaFormat.Epub, - FullFilePath = filepath, IsSpecial = false - }); - - // If an image is cover exclusively, ignore it - filepath = @"E:\Manga\Seraph of the End\cover.png"; - expected.Add(filepath, null); - - filepath = @"E:\Manga\The Beginning After the End\Chapter 001.cbz"; - expected.Add(filepath, new ParserInfo - { - Series = "The Beginning After the End", Volumes = "0", Edition = "", - Chapters = "1", Filename = "Chapter 001.cbz", Format = MangaFormat.Archive, - FullFilePath = filepath, IsSpecial = false - }); - - filepath = @"E:\Manga\Monster #8\Ch. 001-016 [MangaPlus] [Digital] [amit34521]\Monster #8 Ch. 001 [MangaPlus] [Digital] [amit34521]\13.jpg"; - expected.Add(filepath, new ParserInfo - { - Series = "Monster #8", Volumes = "0", Edition = "", - Chapters = "1", Filename = "13.jpg", Format = MangaFormat.Archive, - FullFilePath = filepath, IsSpecial = false - }); - - - foreach (var file in expected.Keys) - { - var expectedInfo = expected[file]; - var actual = API.Parser.Parser.Parse(file, rootPath); - if (expectedInfo == null) - { - Assert.Null(actual); - return; - } - Assert.NotNull(actual); - _testOutputHelper.WriteLine($"Validating {file}"); - Assert.Equal(expectedInfo.Format, actual.Format); - _testOutputHelper.WriteLine("Format ✓"); - Assert.Equal(expectedInfo.Series, actual.Series); - _testOutputHelper.WriteLine("Series ✓"); - Assert.Equal(expectedInfo.Chapters, actual.Chapters); - _testOutputHelper.WriteLine("Chapters ✓"); - Assert.Equal(expectedInfo.Volumes, actual.Volumes); - _testOutputHelper.WriteLine("Volumes ✓"); - Assert.Equal(expectedInfo.Edition, actual.Edition); - _testOutputHelper.WriteLine("Edition ✓"); - Assert.Equal(expectedInfo.Filename, actual.Filename); - _testOutputHelper.WriteLine("Filename ✓"); - Assert.Equal(expectedInfo.FullFilePath, actual.FullFilePath); - _testOutputHelper.WriteLine("FullFilePath ✓"); - } - } } } diff --git a/API.Tests/Parser/ParserInfoTests.cs b/API.Tests/Parser/ParserInfoTests.cs index 78b879de7..16906cf55 100644 --- a/API.Tests/Parser/ParserInfoTests.cs +++ b/API.Tests/Parser/ParserInfoTests.cs @@ -20,7 +20,7 @@ namespace API.Tests.Parser Title = "darker than black", Volumes = "0" }; - + var p2 = new ParserInfo() { Chapters = "1", @@ -32,7 +32,7 @@ namespace API.Tests.Parser Title = "Darker Than Black", Volumes = "0" }; - + var expected = new ParserInfo() { Chapters = "1", @@ -45,11 +45,11 @@ namespace API.Tests.Parser Volumes = "0" }; p1.Merge(p2); - + AssertSame(expected, p1); } - + [Fact] public void MergeFromTest2() { @@ -64,7 +64,7 @@ namespace API.Tests.Parser Title = "darker than black", Volumes = "0" }; - + var p2 = new ParserInfo() { Chapters = "0", @@ -76,7 +76,7 @@ namespace API.Tests.Parser Title = "Darker Than Black", Volumes = "1" }; - + var expected = new ParserInfo() { Chapters = "1", @@ -93,9 +93,9 @@ namespace API.Tests.Parser AssertSame(expected, p1); } - - private void AssertSame(ParserInfo expected, ParserInfo actual) + + private static void AssertSame(ParserInfo expected, ParserInfo actual) { Assert.Equal(expected.Chapters, actual.Chapters); Assert.Equal(expected.Volumes, actual.Volumes); @@ -107,4 +107,4 @@ namespace API.Tests.Parser Assert.Equal(expected.FullFilePath, actual.FullFilePath); } } -} \ No newline at end of file +} diff --git a/API.Tests/Parser/ParserTest.cs b/API.Tests/Parser/ParserTest.cs index 8fdf0509d..5068b39b3 100644 --- a/API.Tests/Parser/ParserTest.cs +++ b/API.Tests/Parser/ParserTest.cs @@ -1,3 +1,5 @@ +using System.Linq; +using API.Entities.Enums; using Xunit; using static API.Parser.Parser; @@ -5,6 +7,14 @@ namespace API.Tests.Parser { public class ParserTests { + [Theory] + [InlineData("Joe Shmo, Green Blue", "Joe Shmo, Green Blue")] + [InlineData("Shmo, Joe", "Shmo, Joe")] + [InlineData(" Joe Shmo ", "Joe Shmo")] + public void CleanAuthorTest(string input, string expected) + { + Assert.Equal(expected, CleanAuthor(input)); + } [Theory] [InlineData("Beastars - SP01", true)] @@ -40,6 +50,8 @@ namespace API.Tests.Parser [InlineData("Hello_I_am_here ", false, "Hello I am here")] [InlineData("[ReleaseGroup] The Title", false, "The Title")] [InlineData("[ReleaseGroup]_The_Title", false, "The Title")] + [InlineData("-The Title", false, "The Title")] + [InlineData("- The Title", false, "The Title")] [InlineData("[Suihei Kiki]_Kasumi_Otoko_no_Ko_[Taruby]_v1.1", false, "Kasumi Otoko no Ko v1.1")] [InlineData("Batman - Detective Comics - Rebirth Deluxe Edition Book 04 (2019) (digital) (Son of Ultron-Empire)", true, "Batman - Detective Comics - Rebirth Deluxe Edition")] public void CleanTitleTest(string input, bool isComic, string expected) @@ -47,20 +59,28 @@ namespace API.Tests.Parser Assert.Equal(expected, CleanTitle(input, isComic)); } + [Theory] + [InlineData("src: url(fonts/AvenirNext-UltraLight.ttf)", true)] + [InlineData("src: url(ideal-sans-serif.woff)", true)] + [InlineData("src: local(\"Helvetica Neue Bold\")", true)] + [InlineData("src: url(\"/fonts/OpenSans-Regular-webfont.woff2\")", true)] + [InlineData("src: local(\"/fonts/OpenSans-Regular-webfont.woff2\")", true)] + [InlineData("src: url(data:application/x-font-woff", false)] + public void FontCssRewriteMatches(string input, bool expectedMatch) + { + Assert.Equal(expectedMatch, FontSrcUrlRegex.Matches(input).Count > 0); + } - // [Theory] - // //[InlineData("@font-face{font-family:\"PaytoneOne\";src:url(\"..\\/Fonts\\/PaytoneOne.ttf\")}", "@font-face{font-family:\"PaytoneOne\";src:url(\"PaytoneOne.ttf\")}")] - // [InlineData("@font-face{font-family:\"PaytoneOne\";src:url(\"..\\/Fonts\\/PaytoneOne.ttf\")}", "..\\/Fonts\\/PaytoneOne.ttf")] - // //[InlineData("@font-face{font-family:'PaytoneOne';src:url('..\\/Fonts\\/PaytoneOne.ttf')}", "@font-face{font-family:'PaytoneOne';src:url('PaytoneOne.ttf')}")] - // //[InlineData("@font-face{\r\nfont-family:'PaytoneOne';\r\nsrc:url('..\\/Fonts\\/PaytoneOne.ttf')\r\n}", "@font-face{font-family:'PaytoneOne';src:url('PaytoneOne.ttf')}")] - // public void ReplaceStyleUrlTest(string input, string expected) - // { - // var replacementStr = "PaytoneOne.ttf"; - // // Use Match to validate since replace is weird - // //Assert.Equal(expected, FontSrcUrlRegex.Replace(input, "$1" + replacementStr + "$2" + "$3")); - // var match = FontSrcUrlRegex.Match(input); - // Assert.Equal(!string.IsNullOrEmpty(expected), FontSrcUrlRegex.Match(input).Success); - // } + [Theory] + [InlineData("src: url(fonts/AvenirNext-UltraLight.ttf)", new [] {"src: url(", "fonts/AvenirNext-UltraLight.ttf", ")"})] + [InlineData("src: url(ideal-sans-serif.woff)", new [] {"src: url(", "ideal-sans-serif.woff", ")"})] + [InlineData("src: local(\"Helvetica Neue Bold\")", new [] {"src: local(\"", "Helvetica Neue Bold", "\")"})] + [InlineData("src: url(\"/fonts/OpenSans-Regular-webfont.woff2\")", new [] {"src: url(\"", "/fonts/OpenSans-Regular-webfont.woff2", "\")"})] + [InlineData("src: local(\"/fonts/OpenSans-Regular-webfont.woff2\")", new [] {"src: local(\"", "/fonts/OpenSans-Regular-webfont.woff2", "\")"})] + public void FontCssCorrectlySeparates(string input, string[] expected) + { + Assert.Equal(expected, FontSrcUrlRegex.Match(input).Groups.Values.Select(g => g.Value).Where((_, i) => i > 0).ToArray()); + } [Theory] @@ -132,28 +152,14 @@ namespace API.Tests.Parser [InlineData("test.jpeg", true)] [InlineData("test.png", true)] [InlineData(".test.jpg", false)] - [InlineData("!test.jpg", false)] + [InlineData("!test.jpg", true)] [InlineData("test.webp", true)] public void IsImageTest(string filename, bool expected) { Assert.Equal(expected, IsImage(filename)); } - [Theory] - [InlineData("C:/", "C:/Love Hina/Love Hina - Special.cbz", "Love Hina")] - [InlineData("C:/", "C:/Love Hina/Specials/Ani-Hina Art Collection.cbz", "Love Hina")] - [InlineData("C:/", "C:/Mujaki no Rakuen Something/Mujaki no Rakuen Vol12 ch76.cbz", "Mujaki no Rakuen")] - public void FallbackTest(string rootDir, string inputPath, string expectedSeries) - { - var actual = Parse(inputPath, rootDir); - if (actual == null) - { - Assert.NotNull(actual); - return; - } - Assert.Equal(expectedSeries, actual.Series); - } [Theory] [InlineData("Love Hina - Special.jpg", false)] @@ -164,6 +170,8 @@ namespace API.Tests.Parser [InlineData("cover.jpg", true)] [InlineData("cover.png", true)] [InlineData("ch1/cover.png", true)] + [InlineData("ch1/backcover.png", false)] + [InlineData("backcover.png", false)] public void IsCoverImageTest(string inputPath, bool expected) { Assert.Equal(expected, IsCoverImage(inputPath)); @@ -174,9 +182,23 @@ namespace API.Tests.Parser [InlineData("TEST/Love Hina - Special.jpg", false)] [InlineData("__macosx/Love Hina/", false)] [InlineData("MACOSX/Love Hina/", false)] + [InlineData("._Love Hina/Love Hina/", true)] + [InlineData("@Recently-Snapshot/Love Hina/", true)] public void HasBlacklistedFolderInPathTest(string inputPath, bool expected) { Assert.Equal(expected, HasBlacklistedFolderInPath(inputPath)); } + + [Theory] + [InlineData("/manga/1/1/1", "/manga/1/1/1")] + [InlineData("/manga/1/1/1.jpg", "/manga/1/1/1.jpg")] + [InlineData(@"/manga/1/1\1.jpg", @"/manga/1/1/1.jpg")] + [InlineData("/manga/1/1//1", "/manga/1/1//1")] + [InlineData("/manga/1\\1\\1", "/manga/1/1/1")] + [InlineData("C:/manga/1\\1\\1.jpg", "C:/manga/1/1/1.jpg")] + public void NormalizePathTest(string inputPath, string expected) + { + Assert.Equal(expected, NormalizePath(inputPath)); + } } } diff --git a/API.Tests/Services/ArchiveServiceTests.cs b/API.Tests/Services/ArchiveServiceTests.cs index 7bdc18f1d..526abde3e 100644 --- a/API.Tests/Services/ArchiveServiceTests.cs +++ b/API.Tests/Services/ArchiveServiceTests.cs @@ -1,11 +1,14 @@ using System.Diagnostics; using System.IO; +using System.IO.Abstractions; +using System.IO.Abstractions.TestingHelpers; using System.IO.Compression; +using System.Linq; using API.Archive; using API.Data.Metadata; -using API.Interfaces.Services; using API.Services; using Microsoft.Extensions.Logging; +using NetVips; using NSubstitute; using NSubstitute.Extensions; using Xunit; @@ -19,12 +22,12 @@ namespace API.Tests.Services private readonly ArchiveService _archiveService; private readonly ILogger _logger = Substitute.For>(); private readonly ILogger _directoryServiceLogger = Substitute.For>(); - private readonly IDirectoryService _directoryService = new DirectoryService(Substitute.For>()); + private readonly IDirectoryService _directoryService = new DirectoryService(Substitute.For>(), new FileSystem()); public ArchiveServiceTests(ITestOutputHelper testOutputHelper) { _testOutputHelper = testOutputHelper; - _archiveService = new ArchiveService(_logger, _directoryService); + _archiveService = new ArchiveService(_logger, _directoryService, new ImageService(Substitute.For>(), _directoryService)); } [Theory] @@ -107,15 +110,15 @@ namespace API.Tests.Services var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ArchiveService/Archives"); var extractDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ArchiveService/Archives/Extraction"); - DirectoryService.ClearAndDeleteDirectory(extractDirectory); + _directoryService.ClearAndDeleteDirectory(extractDirectory); - Stopwatch sw = Stopwatch.StartNew(); + var sw = Stopwatch.StartNew(); _archiveService.ExtractArchive(Path.Join(testDirectory, archivePath), extractDirectory); var di1 = new DirectoryInfo(extractDirectory); - Assert.Equal(expectedFileCount, di1.Exists ? di1.GetFiles().Length : 0); + Assert.Equal(expectedFileCount, di1.Exists ? _directoryService.GetFiles(extractDirectory, searchOption:SearchOption.AllDirectories).Count() : 0); _testOutputHelper.WriteLine($"Processed in {sw.ElapsedMilliseconds} ms"); - DirectoryService.ClearAndDeleteDirectory(extractDirectory); + _directoryService.ClearAndDeleteDirectory(extractDirectory); } @@ -128,7 +131,7 @@ namespace API.Tests.Services [InlineData(new [] {"Akame ga KILL! ZERO - c055 (v10) - p000 [Digital] [LuCaZ].jpg", "Akame ga KILL! ZERO - c055 (v10) - p000 [Digital] [LuCaZ].jpg", "Akame ga KILL! ZERO - c060 (v10) - p200 [Digital] [LuCaZ].jpg", "folder.jpg"}, "folder.jpg")] public void FindFolderEntry(string[] files, string expected) { - var foundFile = _archiveService.FindFolderEntry(files); + var foundFile = ArchiveService.FindFolderEntry(files); Assert.Equal(expected, string.IsNullOrEmpty(foundFile) ? "" : foundFile); } @@ -141,6 +144,7 @@ namespace API.Tests.Services [InlineData(new [] {"__MACOSX/cover.jpg", "vol1/page 01.jpg"}, "vol1/page 01.jpg")] [InlineData(new [] {"Akame ga KILL! ZERO - c055 (v10) - p000 [Digital] [LuCaZ].jpg", "Akame ga KILL! ZERO - c055 (v10) - p000 [Digital] [LuCaZ].jpg", "Akame ga KILL! ZERO - c060 (v10) - p200 [Digital] [LuCaZ].jpg", "folder.jpg"}, "Akame ga KILL! ZERO - c055 (v10) - p000 [Digital] [LuCaZ].jpg")] [InlineData(new [] {"001.jpg", "001 - chapter 1/001.jpg"}, "001.jpg")] + [InlineData(new [] {"chapter 1/001.jpg", "chapter 2/002.jpg", "somefile.jpg"}, "somefile.jpg")] public void FindFirstEntry(string[] files, string expected) { var foundFile = ArchiveService.FirstFileEntry(files, string.Empty); @@ -157,27 +161,29 @@ namespace API.Tests.Services [InlineData("macos_native.zip", "macos_native.jpg")] [InlineData("v10 - duplicate covers.cbz", "v10 - duplicate covers.expected.jpg")] [InlineData("sorting.zip", "sorting.expected.jpg")] + [InlineData("test.zip", "test.expected.jpg")] // https://github.com/kleisauke/net-vips/issues/155 public void GetCoverImage_Default_Test(string inputFile, string expectedOutputFile) { - var archiveService = Substitute.For(_logger, new DirectoryService(_directoryServiceLogger)); - var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ArchiveService/CoverImages"); - var expectedBytes = File.ReadAllBytes(Path.Join(testDirectory, expectedOutputFile)); + var ds = Substitute.For(_directoryServiceLogger, new FileSystem()); + var imageService = new ImageService(Substitute.For>(), ds); + var archiveService = Substitute.For(_logger, ds, imageService); + + var testDirectory = Path.GetFullPath(Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ArchiveService/CoverImages")); + var expectedBytes = Image.Thumbnail(Path.Join(testDirectory, expectedOutputFile), 320).WriteToBuffer(".png"); + archiveService.Configure().CanOpen(Path.Join(testDirectory, inputFile)).Returns(ArchiveLibrary.Default); - var sw = Stopwatch.StartNew(); var outputDir = Path.Join(testDirectory, "output"); - DirectoryService.ClearAndDeleteDirectory(outputDir); - DirectoryService.ExistOrCreate(outputDir); - + _directoryService.ClearDirectory(outputDir); + _directoryService.ExistOrCreate(outputDir); var coverImagePath = archiveService.GetCoverImage(Path.Join(testDirectory, inputFile), - Path.GetFileNameWithoutExtension(inputFile) + "_output"); - var actual = File.ReadAllBytes(coverImagePath); + Path.GetFileNameWithoutExtension(inputFile) + "_output", outputDir); + var actual = File.ReadAllBytes(Path.Join(outputDir, coverImagePath)); Assert.Equal(expectedBytes, actual); - _testOutputHelper.WriteLine($"Processed in {sw.ElapsedMilliseconds} ms"); - DirectoryService.ClearAndDeleteDirectory(outputDir); + //_directoryService.ClearAndDeleteDirectory(outputDir); } @@ -191,35 +197,69 @@ namespace API.Tests.Services [InlineData("sorting.zip", "sorting.expected.jpg")] public void GetCoverImage_SharpCompress_Test(string inputFile, string expectedOutputFile) { - var archiveService = Substitute.For(_logger, new DirectoryService(_directoryServiceLogger)); + var imageService = new ImageService(Substitute.For>(), _directoryService); + var archiveService = Substitute.For(_logger, + new DirectoryService(_directoryServiceLogger, new FileSystem()), imageService); var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ArchiveService/CoverImages"); var expectedBytes = File.ReadAllBytes(Path.Join(testDirectory, expectedOutputFile)); + var outputDir = Path.Join(testDirectory, "output"); + _directoryService.ClearDirectory(outputDir); + _directoryService.ExistOrCreate(outputDir); + archiveService.Configure().CanOpen(Path.Join(testDirectory, inputFile)).Returns(ArchiveLibrary.SharpCompress); - Stopwatch sw = Stopwatch.StartNew(); - Assert.Equal(expectedBytes, File.ReadAllBytes(archiveService.GetCoverImage(Path.Join(testDirectory, inputFile), Path.GetFileNameWithoutExtension(inputFile) + "_output"))); - _testOutputHelper.WriteLine($"Processed in {sw.ElapsedMilliseconds} ms"); + var actualBytes = File.ReadAllBytes(archiveService.GetCoverImage(Path.Join(testDirectory, inputFile), + Path.GetFileNameWithoutExtension(inputFile) + "_output", outputDir)); + Assert.Equal(expectedBytes, actualBytes); + + _directoryService.ClearAndDeleteDirectory(outputDir); } - // TODO: This is broken on GA due to DirectoryService.CoverImageDirectory - //[Theory] + [Theory] [InlineData("Archives/macos_native.zip")] [InlineData("Formats/One File with DB_Supported.zip")] public void CanParseCoverImage(string inputFile) { + var imageService = Substitute.For(); + imageService.WriteCoverThumbnail(Arg.Any(), Arg.Any(), Arg.Any()).Returns(x => "cover.jpg"); + var archiveService = new ArchiveService(_logger, _directoryService, imageService); var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ArchiveService/"); - Assert.NotEmpty(File.ReadAllBytes(_archiveService.GetCoverImage(Path.Join(testDirectory, inputFile), Path.GetFileNameWithoutExtension(inputFile) + "_output"))); + var inputPath = Path.GetFullPath(Path.Join(testDirectory, inputFile)); + var outputPath = Path.Join(testDirectory, Path.GetFileNameWithoutExtension(inputFile) + "_output"); + new DirectoryInfo(outputPath).Create(); + var expectedImage = archiveService.GetCoverImage(inputPath, inputFile, outputPath); + Assert.Equal("cover.jpg", expectedImage); + new DirectoryInfo(outputPath).Delete(); } - [Fact] - public void ShouldHaveComicInfo() - { - var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ArchiveService/ComicInfos"); - var archive = Path.Join(testDirectory, "file in folder.zip"); - var summaryInfo = "By all counts, Ryouta Sakamoto is a loser when he's not holed up in his room, bombing things into oblivion in his favorite online action RPG. But his very own uneventful life is blown to pieces when he's abducted and taken to an uninhabited island, where he soon learns the hard way that he's being pitted against others just like him in a explosives-riddled death match! How could this be happening? Who's putting them up to this? And why!? The name, not to mention the objective, of this very real survival game is eerily familiar to Ryouta, who has mastered its virtual counterpart-BTOOOM! Can Ryouta still come out on top when he's playing for his life!?"; + #region ShouldHaveComicInfo - Assert.Equal(summaryInfo, _archiveService.GetComicInfo(archive).Summary); - } + [Fact] + public void ShouldHaveComicInfo() + { + var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ArchiveService/ComicInfos"); + var archive = Path.Join(testDirectory, "ComicInfo.zip"); + const string summaryInfo = "By all counts, Ryouta Sakamoto is a loser when he's not holed up in his room, bombing things into oblivion in his favorite online action RPG. But his very own uneventful life is blown to pieces when he's abducted and taken to an uninhabited island, where he soon learns the hard way that he's being pitted against others just like him in a explosives-riddled death match! How could this be happening? Who's putting them up to this? And why!? The name, not to mention the objective, of this very real survival game is eerily familiar to Ryouta, who has mastered its virtual counterpart-BTOOOM! Can Ryouta still come out on top when he's playing for his life!?"; + + var comicInfo = _archiveService.GetComicInfo(archive); + Assert.NotNull(comicInfo); + Assert.Equal(summaryInfo, comicInfo.Summary); + } + + [Fact] + public void ShouldHaveComicInfo_WithAuthors() + { + var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ArchiveService/ComicInfos"); + var archive = Path.Join(testDirectory, "ComicInfo_authors.zip"); + + var comicInfo = _archiveService.GetComicInfo(archive); + Assert.NotNull(comicInfo); + Assert.Equal("Junya Inoue", comicInfo.Writer); + } + + #endregion + + #region CanParseComicInfo [Fact] public void CanParseComicInfo() @@ -243,5 +283,38 @@ namespace API.Tests.Services Assert.NotStrictEqual(expected, actual); } + + #endregion + + #region FindCoverImageFilename + + [Theory] + [InlineData(new string[] {}, "", null)] + [InlineData(new [] {"001.jpg", "002.jpg"}, "Test.zip", "001.jpg")] + [InlineData(new [] {"001.jpg", "!002.jpg"}, "Test.zip", "!002.jpg")] + [InlineData(new [] {"001.jpg", "!001.jpg"}, "Test.zip", "!001.jpg")] + [InlineData(new [] {"001.jpg", "cover.jpg"}, "Test.zip", "cover.jpg")] + [InlineData(new [] {"001.jpg", "Chapter 20/cover.jpg", "Chapter 21/0001.jpg"}, "Test.zip", "Chapter 20/cover.jpg")] + [InlineData(new [] {"._/001.jpg", "._/cover.jpg", "010.jpg"}, "Test.zip", "010.jpg")] + [InlineData(new [] {"001.txt", "002.txt", "a.jpg"}, "Test.zip", "a.jpg")] + public void FindCoverImageFilename(string[] filenames, string archiveName, string expected) + { + Assert.Equal(expected, _archiveService.FindCoverImageFilename(archiveName, filenames)); + } + + + #endregion + + #region CreateZipForDownload + + //[Fact] + public void CreateZipForDownloadTest() + { + var fileSystem = new MockFileSystem(); + var ds = new DirectoryService(Substitute.For>(), fileSystem); + //_archiveService.CreateZipForDownload(new []{}, outputDirectory) + } + + #endregion } } diff --git a/API.Tests/Services/BackupServiceTests.cs b/API.Tests/Services/BackupServiceTests.cs new file mode 100644 index 000000000..1af01632c --- /dev/null +++ b/API.Tests/Services/BackupServiceTests.cs @@ -0,0 +1,143 @@ +using System.Collections.Generic; +using System.Data.Common; +using System.IO.Abstractions.TestingHelpers; +using System.Linq; +using System.Threading.Tasks; +using API.Data; +using API.Entities; +using API.Entities.Enums; +using API.Extensions; +using API.Services; +using API.Services.Tasks; +using API.SignalR; +using AutoMapper; +using Microsoft.AspNetCore.SignalR; +using Microsoft.Data.Sqlite; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; +using NSubstitute; +using Xunit; + +namespace API.Tests.Services; + +public class BackupServiceTests +{ + private readonly ILogger _logger = Substitute.For>(); + private readonly IUnitOfWork _unitOfWork; + private readonly IHubContext _messageHub = Substitute.For>(); + private readonly IConfiguration _config; + + private readonly DbConnection _connection; + private readonly DataContext _context; + + private const string CacheDirectory = "C:/kavita/config/cache/"; + private const string CoverImageDirectory = "C:/kavita/config/covers/"; + private const string BackupDirectory = "C:/kavita/config/backups/"; + private const string LogDirectory = "C:/kavita/config/logs/"; + + public BackupServiceTests() + { + var contextOptions = new DbContextOptionsBuilder() + .UseSqlite(CreateInMemoryDatabase()) + .Options; + _connection = RelationalOptionsExtension.Extract(contextOptions).Connection; + + _context = new DataContext(contextOptions); + Task.Run(SeedDb).GetAwaiter().GetResult(); + + _unitOfWork = new UnitOfWork(_context, Substitute.For(), null); + _config = Substitute.For(); + + } + + #region Setup + + private static DbConnection CreateInMemoryDatabase() + { + var connection = new SqliteConnection("Filename=:memory:"); + + connection.Open(); + + return connection; + } + + public void Dispose() => _connection.Dispose(); + + private async Task SeedDb() + { + await _context.Database.MigrateAsync(); + var filesystem = CreateFileSystem(); + + await Seed.SeedSettings(_context, new DirectoryService(Substitute.For>(), filesystem)); + + var setting = await _context.ServerSetting.Where(s => s.Key == ServerSettingKey.CacheDirectory).SingleAsync(); + setting.Value = CacheDirectory; + + setting = await _context.ServerSetting.Where(s => s.Key == ServerSettingKey.BackupDirectory).SingleAsync(); + setting.Value = BackupDirectory; + + _context.ServerSetting.Update(setting); + + _context.Library.Add(new Library() + { + Name = "Manga", + Folders = new List() + { + new FolderPath() + { + Path = "C:/data/" + } + } + }); + return await _context.SaveChangesAsync() > 0; + } + + private async Task ResetDB() + { + _context.Series.RemoveRange(_context.Series.ToList()); + + await _context.SaveChangesAsync(); + } + + private static MockFileSystem CreateFileSystem() + { + var fileSystem = new MockFileSystem(); + fileSystem.Directory.SetCurrentDirectory("C:/kavita/"); + fileSystem.AddDirectory("C:/kavita/config/"); + fileSystem.AddDirectory(CacheDirectory); + fileSystem.AddDirectory(CoverImageDirectory); + fileSystem.AddDirectory(BackupDirectory); + fileSystem.AddDirectory(LogDirectory); + fileSystem.AddDirectory("C:/data/"); + + return fileSystem; + } + + #endregion + + + + #region GetLogFiles + + public void GetLogFiles_ExpectAllFiles_NoRollingFiles() + { + var filesystem = CreateFileSystem(); + filesystem.AddFile($"{LogDirectory}kavita.log", new MockFileData("")); + filesystem.AddFile($"{LogDirectory}kavita1.log", new MockFileData("")); + + var ds = new DirectoryService(Substitute.For>(), filesystem); + // You can't mock _config extensions because they are static + _config.GetMaxRollingFiles().Returns(1); + _config.GetLoggingFileName().Returns(ds.FileSystem.Path.Join(LogDirectory, "kavita.log")); + + var backupService = new BackupService(_logger, _unitOfWork, ds, _config, _messageHub); + + Assert.Single(backupService.GetLogFiles(1, LogDirectory)); + } + + + #endregion + +} diff --git a/API.Tests/Services/BookServiceTests.cs b/API.Tests/Services/BookServiceTests.cs index d0cc29040..07fa2936d 100644 --- a/API.Tests/Services/BookServiceTests.cs +++ b/API.Tests/Services/BookServiceTests.cs @@ -1,5 +1,5 @@ using System.IO; -using API.Interfaces.Services; +using System.IO.Abstractions; using API.Services; using Microsoft.Extensions.Logging; using NSubstitute; @@ -14,7 +14,8 @@ namespace API.Tests.Services public BookServiceTests() { - _bookService = new BookService(_logger); + var directoryService = new DirectoryService(Substitute.For>(), new FileSystem()); + _bookService = new BookService(_logger, directoryService, new ImageService(Substitute.For>(), directoryService)); } [Theory] @@ -27,5 +28,40 @@ namespace API.Tests.Services Assert.Equal(expectedPages, _bookService.GetNumberOfPages(Path.Join(testDirectory, filePath))); } + [Fact] + public void ShouldHaveComicInfo() + { + var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/BookService/EPUB"); + var archive = Path.Join(testDirectory, "The Golden Harpoon; Or, Lost Among the Floes A Story of the Whaling Grounds.epub"); + const string summaryInfo = "Book Description"; + + var comicInfo = _bookService.GetComicInfo(archive); + Assert.NotNull(comicInfo); + Assert.Equal(summaryInfo, comicInfo.Summary); + Assert.Equal("genre1, genre2", comicInfo.Genre); + } + + [Fact] + public void ShouldHaveComicInfo_WithAuthors() + { + var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/BookService/EPUB"); + var archive = Path.Join(testDirectory, "The Golden Harpoon; Or, Lost Among the Floes A Story of the Whaling Grounds.epub"); + + var comicInfo = _bookService.GetComicInfo(archive); + Assert.NotNull(comicInfo); + Assert.Equal("Roger Starbuck,Junya Inoue", comicInfo.Writer); + } + + + #region BookEscaping + + [Fact] + public void EscapeCSSImportReferencesTest() + { + + } + + #endregion + } } diff --git a/API.Tests/Services/CacheServiceTests.cs b/API.Tests/Services/CacheServiceTests.cs index 410c43ade..7a2cbada8 100644 --- a/API.Tests/Services/CacheServiceTests.cs +++ b/API.Tests/Services/CacheServiceTests.cs @@ -1,115 +1,508 @@ -namespace API.Tests.Services +using System.Collections.Generic; +using System.Data.Common; +using System.IO; +using System.IO.Abstractions.TestingHelpers; +using System.Linq; +using System.Threading.Tasks; +using API.Data; +using API.Data.Metadata; +using API.Entities; +using API.Entities.Enums; +using API.Parser; +using API.Services; +using API.SignalR; +using AutoMapper; +using Microsoft.AspNetCore.SignalR; +using Microsoft.Data.Sqlite; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.Extensions.Logging; +using NSubstitute; +using Xunit; + +namespace API.Tests.Services { + internal class MockReadingItemServiceForCacheService : IReadingItemService + { + private readonly DirectoryService _directoryService; + + public MockReadingItemServiceForCacheService(DirectoryService directoryService) + { + _directoryService = directoryService; + } + + public ComicInfo GetComicInfo(string filePath) + { + return null; + } + + public int GetNumberOfPages(string filePath, MangaFormat format) + { + return 1; + } + + public string GetCoverImage(string fileFilePath, string fileName, MangaFormat format) + { + return string.Empty; + } + + public void Extract(string fileFilePath, string targetDirectory, MangaFormat format, int imageCount = 1) + { + throw new System.NotImplementedException(); + } + + public ParserInfo Parse(string path, string rootPath, LibraryType type) + { + throw new System.NotImplementedException(); + } + } public class CacheServiceTests { - // private readonly CacheService _cacheService; - // private readonly ILogger _logger = Substitute.For>(); - // private readonly IUnitOfWork _unitOfWork = Substitute.For(); - // private readonly IArchiveService _archiveService = Substitute.For(); - // private readonly IDirectoryService _directoryService = Substitute.For(); - // - // public CacheServiceTests() - // { - // _cacheService = new CacheService(_logger, _unitOfWork, _archiveService, _directoryService); - // } - + private readonly ILogger _logger = Substitute.For>(); + private readonly IUnitOfWork _unitOfWork; + private readonly IHubContext _messageHub = Substitute.For>(); + + private readonly DbConnection _connection; + private readonly DataContext _context; + + private const string CacheDirectory = "C:/kavita/config/cache/"; + private const string CoverImageDirectory = "C:/kavita/config/covers/"; + private const string BackupDirectory = "C:/kavita/config/backups/"; + private const string DataDirectory = "C:/data/"; + + public CacheServiceTests() + { + var contextOptions = new DbContextOptionsBuilder() + .UseSqlite(CreateInMemoryDatabase()) + .Options; + _connection = RelationalOptionsExtension.Extract(contextOptions).Connection; + + _context = new DataContext(contextOptions); + Task.Run(SeedDb).GetAwaiter().GetResult(); + + _unitOfWork = new UnitOfWork(_context, Substitute.For(), null); + } + + #region Setup + + private static DbConnection CreateInMemoryDatabase() + { + var connection = new SqliteConnection("Filename=:memory:"); + + connection.Open(); + + return connection; + } + + public void Dispose() => _connection.Dispose(); + + private async Task SeedDb() + { + await _context.Database.MigrateAsync(); + var filesystem = CreateFileSystem(); + + await Seed.SeedSettings(_context, new DirectoryService(Substitute.For>(), filesystem)); + + var setting = await _context.ServerSetting.Where(s => s.Key == ServerSettingKey.CacheDirectory).SingleAsync(); + setting.Value = CacheDirectory; + + setting = await _context.ServerSetting.Where(s => s.Key == ServerSettingKey.BackupDirectory).SingleAsync(); + setting.Value = BackupDirectory; + + _context.ServerSetting.Update(setting); + + _context.Library.Add(new Library() + { + Name = "Manga", + Folders = new List() + { + new FolderPath() + { + Path = "C:/data/" + } + } + }); + return await _context.SaveChangesAsync() > 0; + } + + private async Task ResetDB() + { + _context.Series.RemoveRange(_context.Series.ToList()); + + await _context.SaveChangesAsync(); + } + + private static MockFileSystem CreateFileSystem() + { + var fileSystem = new MockFileSystem(); + fileSystem.Directory.SetCurrentDirectory("C:/kavita/"); + fileSystem.AddDirectory("C:/kavita/config/"); + fileSystem.AddDirectory(CacheDirectory); + fileSystem.AddDirectory(CoverImageDirectory); + fileSystem.AddDirectory(BackupDirectory); + fileSystem.AddDirectory(DataDirectory); + + return fileSystem; + } + + #endregion + + #region Ensure + + [Fact] + public async Task Ensure_DirectoryAlreadyExists_DontExtractAnything() + { + var filesystem = CreateFileSystem(); + filesystem.AddFile($"{DataDirectory}Test v1.zip", new MockFileData("")); + filesystem.AddDirectory($"{CacheDirectory}1/"); + var ds = new DirectoryService(Substitute.For>(), filesystem); + var cleanupService = new CacheService(_logger, _unitOfWork, ds, + new ReadingItemService(Substitute.For(), Substitute.For(), Substitute.For(), ds)); + + await ResetDB(); + var s = DbFactory.Series("Test"); + var v = DbFactory.Volume("1"); + var c = new Chapter() + { + Number = "1", + Files = new List() + { + new MangaFile() + { + Format = MangaFormat.Archive, + FilePath = $"{DataDirectory}Test v1.zip", + } + } + }; + v.Chapters.Add(c); + s.Volumes.Add(v); + s.LibraryId = 1; + _context.Series.Add(s); + + await _context.SaveChangesAsync(); + + await cleanupService.Ensure(1); + Assert.Empty(ds.GetFiles(filesystem.Path.Join(CacheDirectory, "1"), searchOption:SearchOption.AllDirectories)); + } + // [Fact] - // public async void Ensure_ShouldExtractArchive(int chapterId) + // public async Task Ensure_DirectoryAlreadyExists_ExtractsImages() // { - // - // // CacheDirectory needs to be customized. - // _unitOfWork.VolumeRepository.GetChapterAsync(chapterId).Returns(new Chapter + // // TODO: Figure out a way to test this + // var filesystem = CreateFileSystem(); + // filesystem.AddFile($"{DataDirectory}Test v1.zip", new MockFileData("")); + // filesystem.AddDirectory($"{CacheDirectory}1/"); + // var ds = new DirectoryService(Substitute.For>(), filesystem); + // var archiveService = Substitute.For(); + // archiveService.ExtractArchive($"{DataDirectory}Test v1.zip", + // filesystem.Path.Join(CacheDirectory, "1")); + // var cleanupService = new CacheService(_logger, _unitOfWork, ds, + // new ReadingItemService(archiveService, Substitute.For(), Substitute.For(), ds)); + // + // await ResetDB(); + // var s = DbFactory.Series("Test"); + // var v = DbFactory.Volume("1"); + // var c = new Chapter() // { - // Id = 1, + // Number = "1", // Files = new List() // { // new MangaFile() // { - // FilePath = "" + // Format = MangaFormat.Archive, + // FilePath = $"{DataDirectory}Test v1.zip", // } // } - // }); - // - // await _cacheService.Ensure(1); - // - // var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/CacheService/Archives"); + // }; + // v.Chapters.Add(c); + // s.Volumes.Add(v); + // s.LibraryId = 1; + // _context.Series.Add(s); // + // await _context.SaveChangesAsync(); + // + // await cleanupService.Ensure(1); + // Assert.Empty(ds.GetFiles(filesystem.Path.Join(CacheDirectory, "1"), searchOption:SearchOption.AllDirectories)); // } - - //string GetCachedPagePath(Volume volume, int page) + + + #endregion + + #region CleanupChapters + + [Fact] + public void CleanupChapters_AllFilesShouldBeDeleted() + { + var filesystem = CreateFileSystem(); + filesystem.AddDirectory($"{CacheDirectory}1/"); + filesystem.AddFile($"{CacheDirectory}1/001.jpg", new MockFileData("")); + filesystem.AddFile($"{CacheDirectory}1/002.jpg", new MockFileData("")); + filesystem.AddFile($"{CacheDirectory}3/003.jpg", new MockFileData("")); + var ds = new DirectoryService(Substitute.For>(), filesystem); + var cleanupService = new CacheService(_logger, _unitOfWork, ds, + new ReadingItemService(Substitute.For(), Substitute.For(), Substitute.For(), ds)); + + cleanupService.CleanupChapters(new []{1, 3}); + Assert.Empty(ds.GetFiles(CacheDirectory, searchOption:SearchOption.AllDirectories)); + } + + + #endregion + + #region GetCachedEpubFile + + [Fact] + public void GetCachedEpubFile_ShouldReturnFirstEpub() + { + var filesystem = CreateFileSystem(); + filesystem.AddDirectory($"{CacheDirectory}1/"); + filesystem.AddFile($"{DataDirectory}1.epub", new MockFileData("")); + filesystem.AddFile($"{DataDirectory}2.epub", new MockFileData("")); + var ds = new DirectoryService(Substitute.For>(), filesystem); + var cs = new CacheService(_logger, _unitOfWork, ds, + new ReadingItemService(Substitute.For(), Substitute.For(), Substitute.For(), ds)); + + var c = new Chapter() + { + Files = new List() + { + new MangaFile() + { + FilePath = $"{DataDirectory}1.epub" + }, + new MangaFile() + { + FilePath = $"{DataDirectory}2.epub" + } + } + }; + cs.GetCachedEpubFile(1, c); + Assert.Same($"{DataDirectory}1.epub", cs.GetCachedEpubFile(1, c)); + } + + #endregion + + #region GetCachedPagePath + + [Fact] + public void GetCachedPagePath_ReturnNullIfNoFiles() + { + var filesystem = CreateFileSystem(); + filesystem.AddDirectory($"{CacheDirectory}1/"); + filesystem.AddFile($"{DataDirectory}1.zip", new MockFileData("")); + filesystem.AddFile($"{DataDirectory}2.zip", new MockFileData("")); + + var c = new Chapter() + { + Id = 1, + Files = new List() + }; + + var fileIndex = 0; + foreach (var file in c.Files) + { + for (var i = 0; i < file.Pages - 1; i++) + { + filesystem.AddFile($"{CacheDirectory}1/{fileIndex}/{i+1}.jpg", new MockFileData("")); + } + + fileIndex++; + } + + var ds = new DirectoryService(Substitute.For>(), filesystem); + var cs = new CacheService(_logger, _unitOfWork, ds, + new ReadingItemService(Substitute.For(), Substitute.For(), Substitute.For(), ds)); + + // Flatten to prepare for how GetFullPath expects + ds.Flatten($"{CacheDirectory}1/"); + + var path = cs.GetCachedPagePath(c, 11); + Assert.Equal(string.Empty, path); + } + + [Fact] + public void GetCachedPagePath_GetFileFromFirstFile() + { + var filesystem = CreateFileSystem(); + filesystem.AddDirectory($"{CacheDirectory}1/"); + filesystem.AddFile($"{DataDirectory}1.zip", new MockFileData("")); + filesystem.AddFile($"{DataDirectory}2.zip", new MockFileData("")); + + var c = new Chapter() + { + Id = 1, + Files = new List() + { + new MangaFile() + { + Id = 1, + FilePath = $"{DataDirectory}1.zip", + Pages = 10 + + }, + new MangaFile() + { + Id = 2, + FilePath = $"{DataDirectory}2.zip", + Pages = 5 + } + } + }; + + var fileIndex = 0; + foreach (var file in c.Files) + { + for (var i = 0; i < file.Pages; i++) + { + filesystem.AddFile($"{CacheDirectory}1/00{fileIndex}_00{i+1}.jpg", new MockFileData("")); + } + + fileIndex++; + } + + var ds = new DirectoryService(Substitute.For>(), filesystem); + var cs = new CacheService(_logger, _unitOfWork, ds, + new ReadingItemService(Substitute.For(), Substitute.For(), Substitute.For(), ds)); + + // Flatten to prepare for how GetFullPath expects + ds.Flatten($"{CacheDirectory}1/"); + + Assert.Equal(ds.FileSystem.Path.GetFullPath($"{CacheDirectory}/1/000_001.jpg"), ds.FileSystem.Path.GetFullPath(cs.GetCachedPagePath(c, 0))); + + } + + + [Fact] + public void GetCachedPagePath_GetLastPageFromSingleFile() + { + var filesystem = CreateFileSystem(); + filesystem.AddDirectory($"{CacheDirectory}1/"); + filesystem.AddFile($"{DataDirectory}1.zip", new MockFileData("")); + + var c = new Chapter() + { + Id = 1, + Files = new List() + { + new MangaFile() + { + Id = 1, + FilePath = $"{DataDirectory}1.zip", + Pages = 10 + + } + } + }; + c.Pages = c.Files.Sum(f => f.Pages); + + var fileIndex = 0; + foreach (var file in c.Files) + { + for (var i = 0; i < file.Pages; i++) + { + filesystem.AddFile($"{CacheDirectory}1/{fileIndex}/{i+1}.jpg", new MockFileData("")); + } + + fileIndex++; + } + + var ds = new DirectoryService(Substitute.For>(), filesystem); + var cs = new CacheService(_logger, _unitOfWork, ds, + new ReadingItemService(Substitute.For(), Substitute.For(), Substitute.For(), ds)); + + // Flatten to prepare for how GetFullPath expects + ds.Flatten($"{CacheDirectory}1/"); + + // Remember that we start at 0, so this is the 10th file + var path = cs.GetCachedPagePath(c, c.Pages); + Assert.Equal(ds.FileSystem.Path.GetFullPath($"{CacheDirectory}/1/000_0{c.Pages}.jpg"), ds.FileSystem.Path.GetFullPath(path)); + } + + [Fact] + public void GetCachedPagePath_GetFileFromSecondFile() + { + var filesystem = CreateFileSystem(); + filesystem.AddDirectory($"{CacheDirectory}1/"); + filesystem.AddFile($"{DataDirectory}1.zip", new MockFileData("")); + filesystem.AddFile($"{DataDirectory}2.zip", new MockFileData("")); + + var c = new Chapter() + { + Id = 1, + Files = new List() + { + new MangaFile() + { + Id = 1, + FilePath = $"{DataDirectory}1.zip", + Pages = 10 + + }, + new MangaFile() + { + Id = 2, + FilePath = $"{DataDirectory}2.zip", + Pages = 5 + } + } + }; + + var fileIndex = 0; + foreach (var file in c.Files) + { + for (var i = 0; i < file.Pages; i++) + { + filesystem.AddFile($"{CacheDirectory}1/{fileIndex}/{i+1}.jpg", new MockFileData("")); + } + + fileIndex++; + } + + var ds = new DirectoryService(Substitute.For>(), filesystem); + var cs = new CacheService(_logger, _unitOfWork, ds, + new ReadingItemService(Substitute.For(), Substitute.For(), Substitute.For(), ds)); + + // Flatten to prepare for how GetFullPath expects + ds.Flatten($"{CacheDirectory}1/"); + + // Remember that we start at 0, so this is the page + 1 file + var path = cs.GetCachedPagePath(c, 10); + Assert.Equal(ds.FileSystem.Path.GetFullPath($"{CacheDirectory}/1/001_001.jpg"), ds.FileSystem.Path.GetFullPath(path)); + } + + #endregion + + #region ExtractChapterFiles + // [Fact] - // //[InlineData("", 0, "")] - // public void GetCachedPagePathTest_Should() + // public void ExtractChapterFiles_ShouldExtractOnlyImages() // { - // - // // string archivePath = "flat file.zip"; - // // int pageNum = 0; - // // string expected = "cache/1/pexels-photo-6551949.jpg"; - // // - // // var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ArchiveService/Archives"); - // // var file = Path.Join(testDirectory, archivePath); - // // var volume = new Volume - // // { - // // Id = 1, - // // Files = new List() - // // { - // // new() - // // { - // // Id = 1, - // // Chapter = 0, - // // FilePath = archivePath, - // // Format = MangaFormat.Archive, - // // Pages = 1, - // // } - // // }, - // // Name = "1", - // // Number = 1 - // // }; - // // - // // var cacheService = Substitute.ForPartsOf(); - // // cacheService.Configure().CacheDirectoryIsAccessible().Returns(true); - // // cacheService.Configure().GetVolumeCachePath(1, volume.Files.ElementAt(0)).Returns("cache/1/"); - // // _directoryService.Configure().GetFilesWithExtension("cache/1/").Returns(new string[] {"pexels-photo-6551949.jpg"}); - // // Assert.Equal(expected, _cacheService.GetCachedPagePath(volume, pageNum)); - // //Assert.True(true); + // const string testDirectory = "/manga/"; + // var fileSystem = new MockFileSystem(); + // for (var i = 0; i < 10; i++) + // { + // fileSystem.AddFile($"{testDirectory}file_{i}.zip", new MockFileData("")); // } // - // [Fact] - // public void GetOrderedChaptersTest() - // { - // // var files = new List() - // // { - // // new() - // // { - // // Number = "1" - // // }, - // // new() - // // { - // // Chapter = 2 - // // }, - // // new() - // // { - // // Chapter = 0 - // // }, - // // }; - // // var expected = new List() - // // { - // // new() - // // { - // // Chapter = 1 - // // }, - // // new() - // // { - // // Chapter = 2 - // // }, - // // new() - // // { - // // Chapter = 0 - // // }, - // // }; - // // Assert.NotStrictEqual(expected, _cacheService.GetOrderedChapters(files)); - // } + // fileSystem.AddDirectory(CacheDirectory); // - + // var ds = new DirectoryService(Substitute.For>(), fileSystem); + // var cs = new CacheService(_logger, _unitOfWork, ds, + // new MockReadingItemServiceForCacheService(ds)); + // + // + // cs.ExtractChapterFiles(CacheDirectory, new List() + // { + // new MangaFile() + // { + // ChapterId = 1, + // Format = MangaFormat.Archive, + // Pages = 2, + // FilePath = + // } + // }) + // } + + #endregion } -} \ No newline at end of file +} diff --git a/API.Tests/Services/CleanupServiceTests.cs b/API.Tests/Services/CleanupServiceTests.cs new file mode 100644 index 000000000..419dd4126 --- /dev/null +++ b/API.Tests/Services/CleanupServiceTests.cs @@ -0,0 +1,433 @@ +using System; +using System.Collections.Generic; +using System.Data.Common; +using System.IO; +using System.IO.Abstractions.TestingHelpers; +using System.Linq; +using System.Threading.Tasks; +using API.Data; +using API.Entities; +using API.Entities.Enums; +using API.Services; +using API.Services.Tasks; +using API.SignalR; +using AutoMapper; +using Microsoft.AspNetCore.SignalR; +using Microsoft.Data.Sqlite; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.Extensions.Logging; +using NSubstitute; +using Xunit; + +namespace API.Tests.Services; + +public class CleanupServiceTests +{ + private readonly ILogger _logger = Substitute.For>(); + private readonly IUnitOfWork _unitOfWork; + private readonly IHubContext _messageHub = Substitute.For>(); + + private readonly DbConnection _connection; + private readonly DataContext _context; + + private const string CacheDirectory = "C:/kavita/config/cache/"; + private const string CoverImageDirectory = "C:/kavita/config/covers/"; + private const string BackupDirectory = "C:/kavita/config/backups/"; + private const string BookmarkDirectory = "C:/kavita/config/bookmarks/"; + + + public CleanupServiceTests() + { + var contextOptions = new DbContextOptionsBuilder() + .UseSqlite(CreateInMemoryDatabase()) + .Options; + _connection = RelationalOptionsExtension.Extract(contextOptions).Connection; + + _context = new DataContext(contextOptions); + Task.Run(SeedDb).GetAwaiter().GetResult(); + + _unitOfWork = new UnitOfWork(_context, Substitute.For(), null); + } + + #region Setup + + private static DbConnection CreateInMemoryDatabase() + { + var connection = new SqliteConnection("Filename=:memory:"); + + connection.Open(); + + return connection; + } + + public void Dispose() => _connection.Dispose(); + + private async Task SeedDb() + { + await _context.Database.MigrateAsync(); + var filesystem = CreateFileSystem(); + + await Seed.SeedSettings(_context, new DirectoryService(Substitute.For>(), filesystem)); + + var setting = await _context.ServerSetting.Where(s => s.Key == ServerSettingKey.CacheDirectory).SingleAsync(); + setting.Value = CacheDirectory; + + setting = await _context.ServerSetting.Where(s => s.Key == ServerSettingKey.BackupDirectory).SingleAsync(); + setting.Value = BackupDirectory; + + setting = await _context.ServerSetting.Where(s => s.Key == ServerSettingKey.BookmarkDirectory).SingleAsync(); + setting.Value = BookmarkDirectory; + + _context.ServerSetting.Update(setting); + + _context.Library.Add(new Library() + { + Name = "Manga", + Folders = new List() + { + new FolderPath() + { + Path = "C:/data/" + } + } + }); + return await _context.SaveChangesAsync() > 0; + } + + private async Task ResetDB() + { + _context.Series.RemoveRange(_context.Series.ToList()); + _context.Users.RemoveRange(_context.Users.ToList()); + _context.AppUserBookmark.RemoveRange(_context.AppUserBookmark.ToList()); + + await _context.SaveChangesAsync(); + } + + private static MockFileSystem CreateFileSystem() + { + var fileSystem = new MockFileSystem(); + fileSystem.Directory.SetCurrentDirectory("C:/kavita/"); + fileSystem.AddDirectory("C:/kavita/config/"); + fileSystem.AddDirectory(CacheDirectory); + fileSystem.AddDirectory(CoverImageDirectory); + fileSystem.AddDirectory(BackupDirectory); + fileSystem.AddDirectory(BookmarkDirectory); + fileSystem.AddDirectory("C:/data/"); + + return fileSystem; + } + + #endregion + + + #region DeleteSeriesCoverImages + + [Fact] + public async Task DeleteSeriesCoverImages_ShouldDeleteAll() + { + var filesystem = CreateFileSystem(); + filesystem.AddFile($"{CoverImageDirectory}series_01.jpg", new MockFileData("")); + filesystem.AddFile($"{CoverImageDirectory}series_03.jpg", new MockFileData("")); + filesystem.AddFile($"{CoverImageDirectory}series_1000.jpg", new MockFileData("")); + + // Delete all Series to reset state + await ResetDB(); + + var s = DbFactory.Series("Test 1"); + s.CoverImage = "series_01.jpg"; + s.LibraryId = 1; + _context.Series.Add(s); + s = DbFactory.Series("Test 2"); + s.CoverImage = "series_03.jpg"; + s.LibraryId = 1; + _context.Series.Add(s); + s = DbFactory.Series("Test 3"); + s.CoverImage = "series_1000.jpg"; + s.LibraryId = 1; + _context.Series.Add(s); + + var ds = new DirectoryService(Substitute.For>(), filesystem); + var cleanupService = new CleanupService(_logger, _unitOfWork, _messageHub, + ds); + + await cleanupService.DeleteSeriesCoverImages(); + + Assert.Empty(ds.GetFiles(CoverImageDirectory)); + } + + [Fact] + public async Task DeleteSeriesCoverImages_ShouldNotDeleteLinkedFiles() + { + var filesystem = CreateFileSystem(); + filesystem.AddFile($"{CoverImageDirectory}series_01.jpg", new MockFileData("")); + filesystem.AddFile($"{CoverImageDirectory}series_03.jpg", new MockFileData("")); + filesystem.AddFile($"{CoverImageDirectory}series_1000.jpg", new MockFileData("")); + + // Delete all Series to reset state + await ResetDB(); + + // Add 2 series with cover images + var s = DbFactory.Series("Test 1"); + s.CoverImage = "series_01.jpg"; + s.LibraryId = 1; + _context.Series.Add(s); + s = DbFactory.Series("Test 2"); + s.CoverImage = "series_03.jpg"; + s.LibraryId = 1; + _context.Series.Add(s); + + + await _context.SaveChangesAsync(); + var ds = new DirectoryService(Substitute.For>(), filesystem); + var cleanupService = new CleanupService(_logger, _unitOfWork, _messageHub, + ds); + + await cleanupService.DeleteSeriesCoverImages(); + + Assert.Equal(2, ds.GetFiles(CoverImageDirectory).Count()); + } + #endregion + + #region DeleteChapterCoverImages + [Fact] + public async Task DeleteChapterCoverImages_ShouldNotDeleteLinkedFiles() + { + var filesystem = CreateFileSystem(); + filesystem.AddFile($"{CoverImageDirectory}v01_c01.jpg", new MockFileData("")); + filesystem.AddFile($"{CoverImageDirectory}v01_c03.jpg", new MockFileData("")); + filesystem.AddFile($"{CoverImageDirectory}v01_c1000.jpg", new MockFileData("")); + + // Delete all Series to reset state + await ResetDB(); + + // Add 2 series with cover images + var s = DbFactory.Series("Test 1"); + var v = DbFactory.Volume("1"); + v.Chapters.Add(new Chapter() + { + CoverImage = "v01_c01.jpg" + }); + v.CoverImage = "v01_c01.jpg"; + s.Volumes.Add(v); + s.CoverImage = "series_01.jpg"; + s.LibraryId = 1; + _context.Series.Add(s); + + s = DbFactory.Series("Test 2"); + v = DbFactory.Volume("1"); + v.Chapters.Add(new Chapter() + { + CoverImage = "v01_c03.jpg" + }); + v.CoverImage = "v01_c03jpg"; + s.Volumes.Add(v); + s.CoverImage = "series_03.jpg"; + s.LibraryId = 1; + _context.Series.Add(s); + + + await _context.SaveChangesAsync(); + var ds = new DirectoryService(Substitute.For>(), filesystem); + var cleanupService = new CleanupService(_logger, _unitOfWork, _messageHub, + ds); + + await cleanupService.DeleteChapterCoverImages(); + + Assert.Equal(2, ds.GetFiles(CoverImageDirectory).Count()); + } + #endregion + + #region DeleteTagCoverImages + + [Fact] + public async Task DeleteTagCoverImages_ShouldNotDeleteLinkedFiles() + { + var filesystem = CreateFileSystem(); + filesystem.AddFile($"{CoverImageDirectory}tag_01.jpg", new MockFileData("")); + filesystem.AddFile($"{CoverImageDirectory}tag_02.jpg", new MockFileData("")); + filesystem.AddFile($"{CoverImageDirectory}tag_1000.jpg", new MockFileData("")); + + // Delete all Series to reset state + await ResetDB(); + + // Add 2 series with cover images + var s = DbFactory.Series("Test 1"); + s.Metadata.CollectionTags = new List(); + s.Metadata.CollectionTags.Add(new CollectionTag() + { + Title = "Something", + CoverImage ="tag_01.jpg" + }); + s.CoverImage = "series_01.jpg"; + s.LibraryId = 1; + _context.Series.Add(s); + + s = DbFactory.Series("Test 2"); + s.Metadata.CollectionTags = new List(); + s.Metadata.CollectionTags.Add(new CollectionTag() + { + Title = "Something 2", + CoverImage ="tag_02.jpg" + }); + s.CoverImage = "series_03.jpg"; + s.LibraryId = 1; + _context.Series.Add(s); + + + await _context.SaveChangesAsync(); + var ds = new DirectoryService(Substitute.For>(), filesystem); + var cleanupService = new CleanupService(_logger, _unitOfWork, _messageHub, + ds); + + await cleanupService.DeleteTagCoverImages(); + + Assert.Equal(2, ds.GetFiles(CoverImageDirectory).Count()); + } + + #endregion + + #region CleanupCacheDirectory + + [Fact] + public void CleanupCacheDirectory_ClearAllFiles() + { + var filesystem = CreateFileSystem(); + filesystem.AddFile($"{CacheDirectory}01.jpg", new MockFileData("")); + filesystem.AddFile($"{CacheDirectory}02.jpg", new MockFileData("")); + + var ds = new DirectoryService(Substitute.For>(), filesystem); + var cleanupService = new CleanupService(_logger, _unitOfWork, _messageHub, + ds); + cleanupService.CleanupCacheDirectory(); + Assert.Empty(ds.GetFiles(CacheDirectory, searchOption: SearchOption.AllDirectories)); + } + + [Fact] + public void CleanupCacheDirectory_ClearAllFilesInSubDirectory() + { + var filesystem = CreateFileSystem(); + filesystem.AddFile($"{CacheDirectory}01.jpg", new MockFileData("")); + filesystem.AddFile($"{CacheDirectory}subdir/02.jpg", new MockFileData("")); + + var ds = new DirectoryService(Substitute.For>(), filesystem); + var cleanupService = new CleanupService(_logger, _unitOfWork, _messageHub, + ds); + cleanupService.CleanupCacheDirectory(); + Assert.Empty(ds.GetFiles(CacheDirectory, searchOption: SearchOption.AllDirectories)); + } + + #endregion + + #region CleanupBackups + + [Fact] + public void CleanupBackups_LeaveOneFile_SinceAllAreExpired() + { + var filesystem = CreateFileSystem(); + var filesystemFile = new MockFileData("") + { + CreationTime = DateTimeOffset.Now.Subtract(TimeSpan.FromDays(31)) + }; + filesystem.AddFile($"{BackupDirectory}kavita_backup_11_29_2021_12_00_13 AM.zip", filesystemFile); + filesystem.AddFile($"{BackupDirectory}kavita_backup_12_3_2021_9_27_58 AM.zip", filesystemFile); + filesystem.AddFile($"{BackupDirectory}randomfile.zip", filesystemFile); + + var ds = new DirectoryService(Substitute.For>(), filesystem); + var cleanupService = new CleanupService(_logger, _unitOfWork, _messageHub, + ds); + cleanupService.CleanupBackups(); + Assert.Single(ds.GetFiles(BackupDirectory, searchOption: SearchOption.AllDirectories)); + } + + [Fact] + public void CleanupBackups_LeaveLestExpired() + { + var filesystem = CreateFileSystem(); + var filesystemFile = new MockFileData("") + { + CreationTime = DateTimeOffset.Now.Subtract(TimeSpan.FromDays(31)) + }; + filesystem.AddFile($"{BackupDirectory}kavita_backup_11_29_2021_12_00_13 AM.zip", filesystemFile); + filesystem.AddFile($"{BackupDirectory}kavita_backup_12_3_2021_9_27_58 AM.zip", filesystemFile); + filesystem.AddFile($"{BackupDirectory}randomfile.zip", new MockFileData("") + { + CreationTime = DateTimeOffset.Now.Subtract(TimeSpan.FromDays(14)) + }); + + var ds = new DirectoryService(Substitute.For>(), filesystem); + var cleanupService = new CleanupService(_logger, _unitOfWork, _messageHub, + ds); + cleanupService.CleanupBackups(); + Assert.True(filesystem.File.Exists($"{BackupDirectory}randomfile.zip")); + } + + #endregion + + #region CleanupBookmarks + + [Fact] + public async Task CleanupBookmarks_LeaveAllFiles() + { + var filesystem = CreateFileSystem(); + filesystem.AddFile($"{BookmarkDirectory}1/1/1/0001.jpg", new MockFileData("")); + filesystem.AddFile($"{BookmarkDirectory}1/1/1/0002.jpg", new MockFileData("")); + + // Delete all Series to reset state + await ResetDB(); + + _context.Series.Add(new Series() + { + Name = "Test", + Library = new Library() { + Name = "Test LIb", + Type = LibraryType.Manga, + }, + Volumes = new List() + { + new Volume() + { + Chapters = new List() + { + new Chapter() + { + + } + } + } + } + }); + + await _context.SaveChangesAsync(); + + _context.AppUser.Add(new AppUser() + { + Bookmarks = new List() + { + new AppUserBookmark() + { + AppUserId = 1, + ChapterId = 1, + Page = 1, + FileName = "1/1/1/0001.jpg", + SeriesId = 1, + VolumeId = 1 + } + } + }); + + await _context.SaveChangesAsync(); + + + var ds = new DirectoryService(Substitute.For>(), filesystem); + var cleanupService = new CleanupService(_logger, _unitOfWork, _messageHub, + ds); + + await cleanupService.CleanupBookmarks(); + + Assert.Equal(1, ds.GetFiles(BookmarkDirectory, searchOption:SearchOption.AllDirectories).Count()); + + } + + #endregion +} diff --git a/API.Tests/Services/DirectoryServiceTests.cs b/API.Tests/Services/DirectoryServiceTests.cs index d64df0d82..bdbb7a238 100644 --- a/API.Tests/Services/DirectoryServiceTests.cs +++ b/API.Tests/Services/DirectoryServiceTests.cs @@ -1,7 +1,11 @@ -using System; +using System; using System.Collections.Generic; using System.IO; +using System.IO.Abstractions; +using System.IO.Abstractions.TestingHelpers; using System.Linq; +using System.Text; +using System.Threading.Tasks; using API.Services; using Microsoft.Extensions.Logging; using NSubstitute; @@ -12,92 +16,658 @@ namespace API.Tests.Services public class DirectoryServiceTests { - private readonly DirectoryService _directoryService; private readonly ILogger _logger = Substitute.For>(); - public DirectoryServiceTests() - { - _directoryService = new DirectoryService(_logger); - } - + #region TraverseTreeParallelForEach [Fact] - public void GetFilesTest_Should_Be28() + public void TraverseTreeParallelForEach_JustArchives_ShouldBe28() { - var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ScannerService/Manga"); - // ReSharper disable once CollectionNeverQueried.Local + var testDirectory = "/manga/"; + var fileSystem = new MockFileSystem(); + for (var i = 0; i < 28; i++) + { + fileSystem.AddFile($"{testDirectory}file_{i}.zip", new MockFileData("")); + } + + fileSystem.AddFile($"{testDirectory}file_{29}.jpg", new MockFileData("")); + + var ds = new DirectoryService(Substitute.For>(), fileSystem); var files = new List(); - var fileCount = DirectoryService.TraverseTreeParallelForEach(testDirectory, s => files.Add(s), + var fileCount = ds.TraverseTreeParallelForEach(testDirectory, s => files.Add(s), API.Parser.Parser.ArchiveFileExtensions, _logger); Assert.Equal(28, fileCount); + Assert.Equal(28, files.Count); } [Fact] - public void GetFiles_WithCustomRegex_ShouldPass_Test() + public void TraverseTreeParallelForEach_LongDirectory_ShouldBe1() { - var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/DirectoryService/regex"); - var files = DirectoryService.GetFiles(testDirectory, @"file\d*.txt"); - Assert.Equal(2, files.Count()); + var fileSystem = new MockFileSystem(); + // Create a super long path + var testDirectory = "/manga/"; + for (var i = 0; i < 200; i++) + { + testDirectory = fileSystem.FileSystem.Path.Join(testDirectory, "supercalifragilisticexpialidocious"); + } + + + fileSystem.AddFile(fileSystem.FileSystem.Path.Join(testDirectory, "file_29.jpg"), new MockFileData("")); + + var ds = new DirectoryService(Substitute.For>(), fileSystem); + var files = new List(); + try + { + var fileCount = ds.TraverseTreeParallelForEach("/manga/", s => files.Add(s), + API.Parser.Parser.ImageFileExtensions, _logger); + Assert.Equal(1, fileCount); + } + catch (Exception ex) + { + Assert.False(true); + } + + + Assert.Equal(1, files.Count); + } + + + + [Fact] + public void TraverseTreeParallelForEach_DontCountExcludedDirectories_ShouldBe28() + { + var testDirectory = "/manga/"; + var fileSystem = new MockFileSystem(); + for (var i = 0; i < 28; i++) + { + fileSystem.AddFile($"{testDirectory}file_{i}.zip", new MockFileData("")); + } + + fileSystem.AddFile($"{Path.Join(testDirectory, "@eaDir")}file_{29}.jpg", new MockFileData("")); + fileSystem.AddFile($"{Path.Join(testDirectory, ".DS_Store")}file_{30}.jpg", new MockFileData("")); + fileSystem.AddFile($"{Path.Join(testDirectory, ".qpkg")}file_{30}.jpg", new MockFileData("")); + + var ds = new DirectoryService(Substitute.For>(), fileSystem); + var files = new List(); + var fileCount = ds.TraverseTreeParallelForEach(testDirectory, s => files.Add(s), + API.Parser.Parser.ArchiveFileExtensions, _logger); + + Assert.Equal(28, fileCount); + Assert.Equal(28, files.Count); + } + #endregion + + #region GetFilesWithCertainExtensions + [Fact] + public void GetFilesWithCertainExtensions_ShouldBe10() + { + const string testDirectory = "/manga/"; + var fileSystem = new MockFileSystem(); + for (var i = 0; i < 10; i++) + { + fileSystem.AddFile($"{testDirectory}file_{i}.zip", new MockFileData("")); + } + + fileSystem.AddFile($"{testDirectory}file_{29}.jpg", new MockFileData("")); + + var ds = new DirectoryService(Substitute.For>(), fileSystem); + var files = ds.GetFilesWithExtension(testDirectory, API.Parser.Parser.ArchiveFileExtensions); + + Assert.Equal(10, files.Length); + Assert.All(files, s => fileSystem.Path.GetExtension(s).Equals(".zip")); } [Fact] - public void GetFiles_TopLevel_ShouldBeEmpty_Test() + public void GetFilesWithCertainExtensions_OnlyArchives() { - var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/DirectoryService"); - var files = DirectoryService.GetFiles(testDirectory); - Assert.Empty(files); + const string testDirectory = "/manga/"; + var fileSystem = new MockFileSystem(); + for (var i = 0; i < 10; i++) + { + fileSystem.AddFile($"{testDirectory}file_{i}.zip", new MockFileData("")); + } + + fileSystem.AddFile($"{testDirectory}file_{29}.rar", new MockFileData("")); + + var ds = new DirectoryService(Substitute.For>(), fileSystem); + var files = ds.GetFilesWithExtension(testDirectory, ".zip|.rar"); + + Assert.Equal(11, files.Length); + } + #endregion + + #region GetFiles + [Fact] + public void GetFiles_ArchiveOnly_ShouldBe10() + { + const string testDirectory = "/manga/"; + var fileSystem = new MockFileSystem(); + for (var i = 0; i < 10; i++) + { + fileSystem.AddFile($"{testDirectory}file_{i}.zip", new MockFileData("")); + } + + fileSystem.AddFile($"{testDirectory}file_{29}.jpg", new MockFileData("")); + + var ds = new DirectoryService(Substitute.For>(), fileSystem); + var files = ds.GetFiles(testDirectory, API.Parser.Parser.ArchiveFileExtensions).ToList(); + + Assert.Equal(10, files.Count()); + Assert.All(files, s => fileSystem.Path.GetExtension(s).Equals(".zip")); } [Fact] - public void GetFilesWithExtensions_ShouldBeEmpty_Test() + public void GetFiles_All_ShouldBe11() { - var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/DirectoryService/extensions"); - var files = DirectoryService.GetFiles(testDirectory, "*.txt"); - Assert.Empty(files); + const string testDirectory = "/manga/"; + var fileSystem = new MockFileSystem(); + for (var i = 0; i < 10; i++) + { + fileSystem.AddFile($"{testDirectory}file_{i}.zip", new MockFileData("")); + } + + fileSystem.AddFile($"{testDirectory}file_{29}.jpg", new MockFileData("")); + + var ds = new DirectoryService(Substitute.For>(), fileSystem); + var files = ds.GetFiles(testDirectory).ToList(); + + Assert.Equal(11, files.Count()); } [Fact] - public void GetFilesWithExtensions_Test() + public void GetFiles_All_MixedPathSeparators() { - var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/DirectoryService/extension"); - var files = DirectoryService.GetFiles(testDirectory, ".cbz|.rar"); - Assert.Equal(3, files.Count()); + const string testDirectory = "/manga/"; + var fileSystem = new MockFileSystem(); + for (var i = 0; i < 10; i++) + { + fileSystem.AddFile($"{testDirectory}file_{i}.zip", new MockFileData("")); + } + + fileSystem.AddFile($"/manga\\file_{29}.jpg", new MockFileData("")); + + var ds = new DirectoryService(Substitute.For>(), fileSystem); + var files = ds.GetFiles(testDirectory).ToList(); + + Assert.Equal(11, files.Count()); } [Fact] - public void GetFilesWithExtensions_BadDirectory_ShouldBeEmpty_Test() + public void GetFiles_All_TopDirectoryOnly_ShouldBe10() { - var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/DirectoryService/doesntexist"); - var files = DirectoryService.GetFiles(testDirectory, ".cbz|.rar"); - Assert.Empty(files); + const string testDirectory = "/manga/"; + var fileSystem = new MockFileSystem(); + for (var i = 0; i < 10; i++) + { + fileSystem.AddFile($"{testDirectory}file_{i}.zip", new MockFileData("")); + } + + fileSystem.AddFile($"{testDirectory}/SubDir/file_{29}.jpg", new MockFileData("")); + + var ds = new DirectoryService(Substitute.For>(), fileSystem); + var files = ds.GetFiles(testDirectory).ToList(); + + Assert.Equal(10, files.Count()); } [Fact] - public void ListDirectory_SubDirectory_Test() + public void GetFiles_WithSubDirectories_ShouldCountOnlyTopLevel() { - var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/DirectoryService/"); - var dirs = _directoryService.ListDirectory(testDirectory); - Assert.Contains(dirs, s => s.Contains("regex")); + const string testDirectory = "/manga/"; + var fileSystem = new MockFileSystem(); + for (var i = 0; i < 10; i++) + { + fileSystem.AddFile($"{testDirectory}file_{i}.zip", new MockFileData("")); + } + fileSystem.AddFile($"{testDirectory}/SubDir/file_{29}.jpg", new MockFileData("")); + + var ds = new DirectoryService(Substitute.For>(), fileSystem); + var files = ds.GetFiles(testDirectory).ToList(); + + Assert.Equal(10, files.Count()); } [Fact] - public void ListDirectory_NoSubDirectory_Test() + public void GetFiles_ShouldNotReturnFilesThatAreExcluded() { - var dirs = _directoryService.ListDirectory(""); - Assert.DoesNotContain(dirs, s => s.Contains("regex")); + const string testDirectory = "/manga/"; + var fileSystem = new MockFileSystem(); + for (var i = 0; i < 10; i++) + { + fileSystem.AddFile($"{testDirectory}file_{i}.zip", new MockFileData("")); + } + fileSystem.AddFile($"{testDirectory}/._file_{29}.jpg", new MockFileData("")); + + var ds = new DirectoryService(Substitute.For>(), fileSystem); + var files = ds.GetFiles(testDirectory).ToList(); + + Assert.Equal(10, files.Count()); } + [Fact] + public void GetFiles_WithCustomRegex_ShouldBe10() + { + const string testDirectory = "/manga/"; + var fileSystem = new MockFileSystem(); + for (var i = 0; i < 10; i++) + { + fileSystem.AddFile($"{testDirectory}data-{i}.txt", new MockFileData("")); + } + fileSystem.AddFile($"{testDirectory}joe.txt", new MockFileData("")); + fileSystem.AddFile($"{testDirectory}0d.txt", new MockFileData("")); + + var ds = new DirectoryService(Substitute.For>(), fileSystem); + var files = ds.GetFiles(testDirectory, @".*d.*\.txt"); + Assert.Equal(11, files.Count()); + } + + [Fact] + public void GetFiles_WithCustomRegexThatContainsFolder_ShouldBe10() + { + const string testDirectory = "/manga/"; + var fileSystem = new MockFileSystem(); + for (var i = 0; i < 10; i++) + { + fileSystem.AddFile($"{testDirectory}file/data-{i}.txt", new MockFileData("")); + } + fileSystem.AddFile($"{testDirectory}joe.txt", new MockFileData("")); + fileSystem.AddFile($"{testDirectory}0d.txt", new MockFileData("")); + + var ds = new DirectoryService(Substitute.For>(), fileSystem); + var files = ds.GetFiles(testDirectory, @".*d.*\.txt", SearchOption.AllDirectories); + Assert.Equal(11, files.Count()); + } + #endregion + + #region GetTotalSize + [Fact] + public void GetTotalSize_ShouldBeGreaterThan0() + { + const string testDirectory = "/manga/"; + var fileSystem = new MockFileSystem(); + for (var i = 0; i < 10; i++) + { + fileSystem.AddFile($"{testDirectory}file/data-{i}.txt", new MockFileData("abc")); + } + fileSystem.AddFile($"{testDirectory}joe.txt", new MockFileData("")); + + + var ds = new DirectoryService(Substitute.For>(), fileSystem); + var fileSize = ds.GetTotalSize(fileSystem.AllFiles); + Assert.True(fileSize > 0); + } + #endregion + + #region CopyFileToDirectory + [Fact] + public void CopyFileToDirectory_ShouldCopyFileToNonExistentDirectory() + { + const string testDirectory = "/manga/"; + var fileSystem = new MockFileSystem(); + fileSystem.AddFile($"{testDirectory}file/data-0.txt", new MockFileData("abc")); + + var ds = new DirectoryService(Substitute.For>(), fileSystem); + ds.CopyFileToDirectory($"{testDirectory}file/data-0.txt", "/manga/output/"); + Assert.True(fileSystem.FileExists("manga/output/data-0.txt")); + Assert.True(fileSystem.FileExists("manga/file/data-0.txt")); + } + [Fact] + public void CopyFileToDirectory_ShouldCopyFileToExistingDirectoryAndOverwrite() + { + const string testDirectory = "/manga/"; + var fileSystem = new MockFileSystem(); + fileSystem.AddFile($"{testDirectory}file/data-0.txt", new MockFileData("abc")); + fileSystem.AddFile($"{testDirectory}output/data-0.txt", new MockFileData("")); + + var ds = new DirectoryService(Substitute.For>(), fileSystem); + ds.CopyFileToDirectory($"{testDirectory}file/data-0.txt", "/manga/output/"); + Assert.True(fileSystem.FileExists("/manga/output/data-0.txt")); + Assert.True(fileSystem.FileExists("/manga/file/data-0.txt")); + Assert.True(fileSystem.FileInfo.FromFileName("/manga/file/data-0.txt").Length == fileSystem.FileInfo.FromFileName("/manga/output/data-0.txt").Length); + } + #endregion + + #region CopyDirectoryToDirectory + [Fact] + public void CopyDirectoryToDirectory_ShouldThrowWhenSourceDestinationDoesntExist() + { + const string testDirectory = "/manga/"; + var fileSystem = new MockFileSystem(); + fileSystem.AddFile($"{testDirectory}file/data-0.txt", new MockFileData("abc")); + fileSystem.AddFile($"{testDirectory}output/data-0.txt", new MockFileData("")); + + var ds = new DirectoryService(Substitute.For>(), fileSystem); + var ex = Assert.Throws(() => ds.CopyDirectoryToDirectory("/comics/", "/manga/output/")); + Assert.Equal(ex.Message, "Source directory does not exist or could not be found: " + "/comics/"); + } + + [Fact] + public void CopyDirectoryToDirectory_ShouldCopyEmptyDirectory() + { + const string testDirectory = "/manga/"; + var fileSystem = new MockFileSystem(); + fileSystem.AddFile($"{testDirectory}file/data-0.txt", new MockFileData("abc")); + fileSystem.AddDirectory($"{testDirectory}empty/"); + + var ds = new DirectoryService(Substitute.For>(), fileSystem); + ds.CopyDirectoryToDirectory($"{testDirectory}empty/", "/manga/output/"); + Assert.Empty(fileSystem.DirectoryInfo.FromDirectoryName("/manga/output/").GetFiles()); + } + + [Fact] + public void CopyDirectoryToDirectory_ShouldCopyAllFileAndNestedDirectoriesOver() + { + const string testDirectory = "/manga/"; + var fileSystem = new MockFileSystem(); + fileSystem.AddFile($"{testDirectory}file/data-0.txt", new MockFileData("abc")); + fileSystem.AddFile($"{testDirectory}data-1.txt", new MockFileData("abc")); + fileSystem.AddDirectory($"{testDirectory}empty/"); + + var ds = new DirectoryService(Substitute.For>(), fileSystem); + ds.CopyDirectoryToDirectory($"{testDirectory}", "/manga/output/"); + Assert.Equal(2, ds.GetFiles("/manga/output/", searchOption: SearchOption.AllDirectories).Count()); + } + #endregion + + #region IsDriveMounted + [Fact] + public void IsDriveMounted_DriveIsNotMounted() + { + const string testDirectory = "c:/manga/"; + var fileSystem = new MockFileSystem(); + fileSystem.AddFile($"{testDirectory}data-0.txt", new MockFileData("abc")); + var ds = new DirectoryService(Substitute.For>(), fileSystem); + + Assert.False(ds.IsDriveMounted("d:/manga/")); + } + + [Fact] + public void IsDriveMounted_DriveIsMounted() + { + const string testDirectory = "c:/manga/"; + var fileSystem = new MockFileSystem(); + fileSystem.AddFile($"{testDirectory}data-0.txt", new MockFileData("abc")); + var ds = new DirectoryService(Substitute.For>(), fileSystem); + + Assert.True(ds.IsDriveMounted("c:/manga/file")); + } + #endregion + + #region IsDirectoryEmpty + [Fact] + public void IsDirectoryEmpty_DirectoryIsEmpty() + { + const string testDirectory = "c:/manga/"; + var fileSystem = new MockFileSystem(); + fileSystem.AddDirectory(testDirectory); + var ds = new DirectoryService(Substitute.For>(), fileSystem); + + Assert.True(ds.IsDirectoryEmpty("c:/manga/")); + } + + [Fact] + public void IsDirectoryEmpty_DirectoryIsNotEmpty() + { + const string testDirectory = "c:/manga/"; + var fileSystem = new MockFileSystem(); + fileSystem.AddFile($"{testDirectory}data-0.txt", new MockFileData("abc")); + var ds = new DirectoryService(Substitute.For>(), fileSystem); + + Assert.False(ds.IsDirectoryEmpty("c:/manga/")); + } + #endregion + + #region ExistOrCreate + [Fact] + public void ExistOrCreate_ShouldCreate() + { + var fileSystem = new MockFileSystem(); + var ds = new DirectoryService(Substitute.For>(), fileSystem); + ds.ExistOrCreate("c:/manga/output/"); + + Assert.True(ds.FileSystem.DirectoryInfo.FromDirectoryName("c:/manga/output/").Exists); + } + #endregion + + #region ClearAndDeleteDirectory + [Fact] + public void ClearAndDeleteDirectory_ShouldDeleteSelfAndAllFilesAndFolders() + { + const string testDirectory = "/manga/base/"; + var fileSystem = new MockFileSystem(); + for (var i = 0; i < 10; i++) + { + fileSystem.AddFile($"{testDirectory}file/data-{i}.txt", new MockFileData("abc")); + } + fileSystem.AddFile($"{testDirectory}data-a.txt", new MockFileData("abc")); + fileSystem.AddFile($"{testDirectory}data-b.txt", new MockFileData("abc")); + fileSystem.AddDirectory($"{testDirectory}empty/"); + + var ds = new DirectoryService(Substitute.For>(), fileSystem); + ds.ClearAndDeleteDirectory($"{testDirectory}"); + Assert.Empty(ds.GetFiles("/manga/", searchOption: SearchOption.AllDirectories)); + Assert.Empty(ds.FileSystem.DirectoryInfo.FromDirectoryName("/manga/").GetDirectories()); + Assert.True(ds.FileSystem.DirectoryInfo.FromDirectoryName("/manga/").Exists); + Assert.False(ds.FileSystem.DirectoryInfo.FromDirectoryName("/manga/base").Exists); + } + #endregion + + #region ClearDirectory + [Fact] + public void ClearDirectory_ShouldDeleteAllFilesAndFolders_LeaveSelf() + { + const string testDirectory = "/manga/base/"; + var fileSystem = new MockFileSystem(); + for (var i = 0; i < 10; i++) + { + fileSystem.AddFile($"{testDirectory}file/data-{i}.txt", new MockFileData("abc")); + } + fileSystem.AddFile($"{testDirectory}data-a.txt", new MockFileData("abc")); + fileSystem.AddFile($"{testDirectory}data-b.txt", new MockFileData("abc")); + fileSystem.AddDirectory($"{testDirectory}file/empty/"); + + var ds = new DirectoryService(Substitute.For>(), fileSystem); + ds.ClearDirectory($"{testDirectory}file/"); + Assert.Empty(ds.FileSystem.DirectoryInfo.FromDirectoryName($"{testDirectory}file/").GetDirectories()); + Assert.True(ds.FileSystem.DirectoryInfo.FromDirectoryName("/manga/").Exists); + Assert.True(ds.FileSystem.DirectoryInfo.FromDirectoryName($"{testDirectory}file/").Exists); + } + + [Fact] + public void ClearDirectory_ShouldDeleteFoldersWithOneFileInside() + { + const string testDirectory = "/manga/base/"; + var fileSystem = new MockFileSystem(); + for (var i = 0; i < 10; i++) + { + fileSystem.AddFile($"{testDirectory}file/data-{i}.txt", new MockFileData("abc")); + } + + var ds = new DirectoryService(Substitute.For>(), fileSystem); + ds.ClearDirectory($"{testDirectory}"); + Assert.Empty(ds.FileSystem.DirectoryInfo.FromDirectoryName($"{testDirectory}").GetDirectories()); + Assert.True(ds.FileSystem.DirectoryInfo.FromDirectoryName(testDirectory).Exists); + Assert.False(ds.FileSystem.DirectoryInfo.FromDirectoryName($"{testDirectory}file/").Exists); + } + #endregion + + #region CopyFilesToDirectory + [Fact] + public void CopyFilesToDirectory_ShouldMoveAllFiles() + { + const string testDirectory = "/manga/"; + var fileSystem = new MockFileSystem(); + for (var i = 0; i < 10; i++) + { + fileSystem.AddFile($"{testDirectory}file_{i}.zip", new MockFileData("")); + } + + var ds = new DirectoryService(Substitute.For>(), fileSystem); + ds.CopyFilesToDirectory(new []{$"{testDirectory}file_{0}.zip", $"{testDirectory}file_{1}.zip"}, "/manga/output/"); + Assert.Equal(2, ds.GetFiles("/manga/output/").Count()); + } + + [Fact] + public void CopyFilesToDirectory_ShouldMoveAllFiles_InclFilesInNestedFolders() + { + const string testDirectory = "/manga/"; + var fileSystem = new MockFileSystem(); + for (var i = 0; i < 10; i++) + { + fileSystem.AddFile($"{testDirectory}file_{i}.zip", new MockFileData("")); + } + fileSystem.AddFile($"{testDirectory}nested/file_11.zip", new MockFileData("")); + + var ds = new DirectoryService(Substitute.For>(), fileSystem); + ds.CopyFilesToDirectory(new []{$"{testDirectory}file_{0}.zip", $"{testDirectory}file_{1}.zip", $"{testDirectory}nested/file_11.zip"}, "/manga/output/"); + Assert.Equal(3, ds.GetFiles("/manga/output/").Count()); + } + + [Fact] + public void CopyFilesToDirectory_ShouldMoveAllFiles_WithPrepend() + { + const string testDirectory = "/manga/"; + var fileSystem = new MockFileSystem(); + for (var i = 0; i < 10; i++) + { + fileSystem.AddFile($"{testDirectory}file_{i}.zip", new MockFileData("")); + } + + var ds = new DirectoryService(Substitute.For>(), fileSystem); + ds.CopyFilesToDirectory(new []{$"{testDirectory}file_{0}.zip", $"{testDirectory}file_{1}.zip", $"{testDirectory}nested/file_11.zip"}, + "/manga/output/", "mangarocks_"); + Assert.Equal(2, ds.GetFiles("/manga/output/").Count()); + Assert.All(ds.GetFiles("/manga/output/"), filepath => ds.FileSystem.Path.GetFileName(filepath).StartsWith("mangarocks_")); + } + + [Fact] + public void CopyFilesToDirectory_ShouldMoveOnlyFilesThatExist() + { + const string testDirectory = "/manga/"; + var fileSystem = new MockFileSystem(); + for (var i = 0; i < 10; i++) + { + fileSystem.AddFile($"{testDirectory}file_{i}.zip", new MockFileData("")); + } + + var ds = new DirectoryService(Substitute.For>(), fileSystem); + ds.CopyFilesToDirectory(new []{$"{testDirectory}file_{0}.zip", $"{testDirectory}file_{1}.zip", $"{testDirectory}nested/file_11.zip"}, + "/manga/output/"); + Assert.Equal(2, ds.GetFiles("/manga/output/").Count()); + } + + #endregion + + #region ListDirectory + [Fact] + public void ListDirectory_EmptyForNonExistent() + { + const string testDirectory = "/manga/"; + var fileSystem = new MockFileSystem(); + fileSystem.AddFile($"{testDirectory}file_0.zip", new MockFileData("")); + + var ds = new DirectoryService(Substitute.For>(), fileSystem); + Assert.Empty(ds.ListDirectory("/comics/")); + } + + [Fact] + public void ListDirectory_ListsAllDirectories() + { + const string testDirectory = "/manga/"; + var fileSystem = new MockFileSystem(); + fileSystem.AddDirectory($"{testDirectory}dir1"); + fileSystem.AddDirectory($"{testDirectory}dir2"); + fileSystem.AddDirectory($"{testDirectory}dir3"); + fileSystem.AddFile($"{testDirectory}file_0.zip", new MockFileData("")); + + var ds = new DirectoryService(Substitute.For>(), fileSystem); + Assert.Equal(3, ds.ListDirectory(testDirectory).Count()); + } + + [Fact] + public void ListDirectory_ListsOnlyNonSystemAndHiddenOnly() + { + const string testDirectory = "/manga/"; + var fileSystem = new MockFileSystem(); + fileSystem.AddDirectory($"{testDirectory}dir1"); + var di = fileSystem.DirectoryInfo.FromDirectoryName($"{testDirectory}dir1"); + di.Attributes |= FileAttributes.System; + fileSystem.AddDirectory($"{testDirectory}dir2"); + di = fileSystem.DirectoryInfo.FromDirectoryName($"{testDirectory}dir2"); + di.Attributes |= FileAttributes.Hidden; + fileSystem.AddDirectory($"{testDirectory}dir3"); + fileSystem.AddFile($"{testDirectory}file_0.zip", new MockFileData("")); + + var ds = new DirectoryService(Substitute.For>(), fileSystem); + Assert.Equal(1, ds.ListDirectory(testDirectory).Count()); + } + + #endregion + + #region ReadFileAsync + + [Fact] + public async Task ReadFileAsync_ShouldGetBytes() + { + const string testDirectory = "/manga/"; + var fileSystem = new MockFileSystem(); + fileSystem.AddFile($"{testDirectory}file_1.zip", new MockFileData("Hello")); + + var ds = new DirectoryService(Substitute.For>(), fileSystem); + var bytes = await ds.ReadFileAsync($"{testDirectory}file_1.zip"); + Assert.Equal(Encoding.UTF8.GetBytes("Hello"), bytes); + } + + [Fact] + public async Task ReadFileAsync_ShouldReadNothingFromNonExistent() + { + const string testDirectory = "/manga/"; + var fileSystem = new MockFileSystem(); + fileSystem.AddFile($"{testDirectory}file_1.zip", new MockFileData("Hello")); + + var ds = new DirectoryService(Substitute.For>(), fileSystem); + var bytes = await ds.ReadFileAsync($"{testDirectory}file_32123.zip"); + Assert.Empty(bytes); + } + + + #endregion + + #region FindHighestDirectoriesFromFiles + [Theory] [InlineData(new [] {"C:/Manga/"}, new [] {"C:/Manga/Love Hina/Vol. 01.cbz"}, "C:/Manga/Love Hina")] - public void FindHighestDirectoriesFromFilesTest(string[] rootDirectories, string[] folders, string expectedDirectory) + [InlineData(new [] {"C:/Manga/Dir 1/", "c://Manga/Dir 2/"}, new [] {"C:/Manga/Dir 1/Love Hina/Vol. 01.cbz"}, "C:/Manga/Dir 1/Love Hina")] + [InlineData(new [] {"C:/Manga/Dir 1/", "c://Manga/"}, new [] {"D:/Manga/Love Hina/Vol. 01.cbz", "D:/Manga/Vol. 01.cbz"}, "")] + public void FindHighestDirectoriesFromFilesTest(string[] rootDirectories, string[] files, string expectedDirectory) { - var actual = DirectoryService.FindHighestDirectoriesFromFiles(rootDirectories, folders); - var expected = new Dictionary {{expectedDirectory, ""}}; + var fileSystem = new MockFileSystem(); + foreach (var directory in rootDirectories) + { + fileSystem.AddDirectory(directory); + } + foreach (var f in files) + { + fileSystem.AddFile(f, new MockFileData("")); + } + var ds = new DirectoryService(Substitute.For>(), fileSystem); + + var actual = ds.FindHighestDirectoriesFromFiles(rootDirectories, files); + var expected = new Dictionary(); + if (!string.IsNullOrEmpty(expectedDirectory)) + { + expected = new Dictionary {{expectedDirectory, ""}}; + } + Assert.Equal(expected, actual); } + #endregion + + #region GetFoldersTillRoot + [Theory] [InlineData("C:/Manga/", "C:/Manga/Love Hina/Specials/Omake/", "Omake,Specials,Love Hina")] [InlineData("C:/Manga/", "C:/Manga/Love Hina/Specials/Omake", "Omake,Specials,Love Hina")] @@ -114,12 +684,110 @@ namespace API.Tests.Services [InlineData(@"M:\", @"M:\Toukyou Akazukin\Vol. 01 Ch. 005.cbz", @"Toukyou Akazukin")] public void GetFoldersTillRoot_Test(string rootPath, string fullpath, string expectedArray) { + var fileSystem = new MockFileSystem(); + fileSystem.AddDirectory(rootPath); + fileSystem.AddFile(fullpath, new MockFileData("")); + + var ds = new DirectoryService(Substitute.For>(), fileSystem); + var expected = expectedArray.Split(","); if (expectedArray.Equals(string.Empty)) { - expected = Array.Empty(); + expected = Array.Empty(); } - Assert.Equal(expected, DirectoryService.GetFoldersTillRoot(rootPath, fullpath)); + Assert.Equal(expected, ds.GetFoldersTillRoot(rootPath, fullpath)); } + + #endregion + + #region RemoveNonImages + + [Fact] + public void RemoveNonImages() + { + const string testDirectory = "/manga/"; + var fileSystem = new MockFileSystem(); + fileSystem.AddDirectory(testDirectory); + fileSystem.AddFile($"{testDirectory}file/data-0.txt", new MockFileData("abc")); + fileSystem.AddFile($"{testDirectory}data-1.jpg", new MockFileData("abc")); + fileSystem.AddFile($"{testDirectory}data-2.png", new MockFileData("abc")); + fileSystem.AddFile($"{testDirectory}data-3.webp", new MockFileData("abc")); + + var ds = new DirectoryService(Substitute.For>(), fileSystem); + ds.RemoveNonImages($"{testDirectory}"); + Assert.False(fileSystem.FileExists($"{testDirectory}file/data-0.txt")); + Assert.Equal(3, ds.GetFiles($"{testDirectory}", searchOption:SearchOption.AllDirectories).Count()); + } + + #endregion + + #region Flatten + + [Fact] + public void Flatten_ShouldDoNothing() + { + const string testDirectory = "/manga/"; + var fileSystem = new MockFileSystem(); + fileSystem.AddDirectory(testDirectory); + fileSystem.AddFile($"{testDirectory}data-1.jpg", new MockFileData("abc")); + fileSystem.AddFile($"{testDirectory}data-2.png", new MockFileData("abc")); + fileSystem.AddFile($"{testDirectory}data-3.webp", new MockFileData("abc")); + + var ds = new DirectoryService(Substitute.For>(), fileSystem); + ds.Flatten($"{testDirectory}"); + Assert.True(fileSystem.FileExists($"{testDirectory}data-1.jpg")); + Assert.True(fileSystem.FileExists($"{testDirectory}data-2.png")); + Assert.True(fileSystem.FileExists($"{testDirectory}data-3.webp")); + } + + [Fact] + public void Flatten_ShouldFlatten() + { + const string testDirectory = "/manga/"; + var fileSystem = new MockFileSystem(); + fileSystem.AddDirectory(testDirectory); + fileSystem.AddFile($"{testDirectory}data-1.jpg", new MockFileData("abc")); + fileSystem.AddFile($"{testDirectory}subdir/data-3.webp", new MockFileData("abc")); + + var ds = new DirectoryService(Substitute.For>(), fileSystem); + ds.Flatten($"{testDirectory}"); + Assert.Equal(2, ds.GetFiles(testDirectory).Count()); + Assert.False(fileSystem.FileExists($"{testDirectory}subdir/data-3.webp")); + Assert.True(fileSystem.Directory.Exists($"{testDirectory}subdir/")); + } + + #endregion + + #region CheckWriteAccess + + [Fact] + public async Task CheckWriteAccess_ShouldHaveAccess() + { + const string testDirectory = "/manga/"; + var fileSystem = new MockFileSystem(); + + var ds = new DirectoryService(Substitute.For>(), fileSystem); + var hasAccess = await ds.CheckWriteAccess(ds.FileSystem.Path.Join(testDirectory, "bookmarks")); + Assert.True(hasAccess); + + Assert.False(ds.FileSystem.Directory.Exists(ds.FileSystem.Path.Join(testDirectory, "bookmarks"))); + Assert.False(ds.FileSystem.File.Exists(ds.FileSystem.Path.Join(testDirectory, "bookmarks", "test.txt"))); + } + + + #endregion + + #region GetHumanReadableBytes + + [Theory] + [InlineData(1200, "1.17 KB")] + [InlineData(1, "1 B")] + [InlineData(10000000, "9.54 MB")] + [InlineData(10000000000, "9.31 GB")] + public void GetHumanReadableBytesTest(long bytes, string expected) + { + Assert.Equal(expected, DirectoryService.GetHumanReadableBytes(bytes)); + } + #endregion } } diff --git a/API.Tests/Services/FileSystemTests.cs b/API.Tests/Services/FileSystemTests.cs new file mode 100644 index 000000000..97250ea45 --- /dev/null +++ b/API.Tests/Services/FileSystemTests.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.IO.Abstractions.TestingHelpers; +using API.Services; +using Xunit; + +namespace API.Tests.Services; + +public class FileSystemTests +{ + [Fact] + public void FileHasNotBeenModifiedSinceCreation() + { + var file = new MockFileData("Testing is meh.") + { + LastWriteTime = DateTimeOffset.Now.Subtract(TimeSpan.FromMinutes(1)) + }; + var fileSystem = new MockFileSystem(new Dictionary + { + { @"c:\myfile.txt", file } + }); + + var fileService = new FileService(fileSystem); + + Assert.False(fileService.HasFileBeenModifiedSince(@"c:\myfile.txt", DateTime.Now)); + } + + [Fact] + public void FileHasBeenModifiedSinceCreation() + { + var file = new MockFileData("Testing is meh.") + { + LastWriteTime = DateTimeOffset.Now + }; + var fileSystem = new MockFileSystem(new Dictionary + { + { @"c:\myfile.txt", file } + }); + + var fileService = new FileService(fileSystem); + + Assert.True(fileService.HasFileBeenModifiedSince(@"c:\myfile.txt", DateTime.Now.Subtract(TimeSpan.FromMinutes(1)))); + } +} diff --git a/API.Tests/Services/MetadataServiceTests.cs b/API.Tests/Services/MetadataServiceTests.cs index 5d61ee249..60a1bd0bd 100644 --- a/API.Tests/Services/MetadataServiceTests.cs +++ b/API.Tests/Services/MetadataServiceTests.cs @@ -1,8 +1,9 @@ using System; +using System.Collections.Generic; using System.IO; -using API.Entities; +using System.IO.Abstractions.TestingHelpers; +using API.Helpers; using API.Services; -using Xunit; namespace API.Tests.Services { @@ -10,6 +11,7 @@ namespace API.Tests.Services { private readonly string _testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ArchiveService/Archives"); private const string TestCoverImageFile = "thumbnail.jpg"; + private const string TestCoverArchive = @"c:\file in folder.zip"; private readonly string _testCoverImageDirectory = Path.Join(Directory.GetCurrentDirectory(), @"../../../Services/Test Data/ArchiveService/CoverImages"); //private readonly MetadataService _metadataService; // private readonly IUnitOfWork _unitOfWork = Substitute.For(); @@ -18,116 +20,23 @@ namespace API.Tests.Services // private readonly IArchiveService _archiveService = Substitute.For(); // private readonly ILogger _logger = Substitute.For>(); // private readonly IHubContext _messageHub = Substitute.For>(); + private readonly ICacheHelper _cacheHelper; + public MetadataServiceTests() { //_metadataService = new MetadataService(_unitOfWork, _logger, _archiveService, _bookService, _imageService, _messageHub); - } - - [Fact] - public void ShouldUpdateCoverImage_OnFirstRun() - { - // Represents first run - Assert.True(MetadataService.ShouldUpdateCoverImage(null, new MangaFile() + var file = new MockFileData("") { - FilePath = Path.Join(_testDirectory, "file in folder.zip"), - LastModified = DateTime.Now - }, false, false)); - } - - [Fact] - public void ShouldUpdateCoverImage_OnFirstRunSeries() - { - // Represents first run - Assert.True(MetadataService.ShouldUpdateCoverImage(null,null, false, false)); - } - - [Fact] - public void ShouldUpdateCoverImage_OnFirstRun_FileModified() - { - // Represents first run - Assert.True(MetadataService.ShouldUpdateCoverImage(null, new MangaFile() + LastWriteTime = DateTimeOffset.Now.Subtract(TimeSpan.FromMinutes(1)) + }; + var fileSystem = new MockFileSystem(new Dictionary { - FilePath = Path.Join(_testDirectory, "file in folder.zip"), - LastModified = new FileInfo(Path.Join(_testDirectory, "file in folder.zip")).LastWriteTime.Subtract(TimeSpan.FromDays(1)) - }, false, false)); - } + { TestCoverArchive, file } + }); - [Fact] - public void ShouldUpdateCoverImage_OnFirstRun_CoverImageLocked() - { - // Represents first run - Assert.True(MetadataService.ShouldUpdateCoverImage(null, new MangaFile() - { - FilePath = Path.Join(_testDirectory, "file in folder.zip"), - LastModified = new FileInfo(Path.Join(_testDirectory, "file in folder.zip")).LastWriteTime - }, false, true)); - } - - [Fact] - public void ShouldUpdateCoverImage_OnSecondRun_ForceUpdate() - { - // Represents first run - Assert.True(MetadataService.ShouldUpdateCoverImage(null, new MangaFile() - { - FilePath = Path.Join(_testDirectory, "file in folder.zip"), - LastModified = new FileInfo(Path.Join(_testDirectory, "file in folder.zip")).LastWriteTime - }, true, false)); - } - - [Fact] - public void ShouldUpdateCoverImage_OnSecondRun_NoFileChangeButNoCoverImage() - { - // Represents first run - Assert.True(MetadataService.ShouldUpdateCoverImage(null, new MangaFile() - { - FilePath = Path.Join(_testDirectory, "file in folder.zip"), - LastModified = new FileInfo(Path.Join(_testDirectory, "file in folder.zip")).LastWriteTime - }, false, false)); - } - - [Fact] - public void ShouldUpdateCoverImage_OnSecondRun_FileChangeButNoCoverImage() - { - // Represents first run - Assert.True(MetadataService.ShouldUpdateCoverImage(null, new MangaFile() - { - FilePath = Path.Join(_testDirectory, "file in folder.zip"), - LastModified = new FileInfo(Path.Join(_testDirectory, "file in folder.zip")).LastWriteTime + TimeSpan.FromDays(1) - }, false, false)); - } - - [Fact] - public void ShouldNotUpdateCoverImage_OnSecondRun_CoverImageSet() - { - // Represents first run - Assert.False(MetadataService.ShouldUpdateCoverImage(TestCoverImageFile, new MangaFile() - { - FilePath = Path.Join(_testDirectory, "file in folder.zip"), - LastModified = new FileInfo(Path.Join(_testDirectory, "file in folder.zip")).LastWriteTime - }, false, false, _testCoverImageDirectory)); - } - - [Fact] - public void ShouldNotUpdateCoverImage_OnSecondRun_HasCoverImage_NoForceUpdate_NoLock() - { - - Assert.False(MetadataService.ShouldUpdateCoverImage(TestCoverImageFile, new MangaFile() - { - FilePath = Path.Join(_testDirectory, "file in folder.zip"), - LastModified = DateTime.Now - }, false, false, _testCoverImageDirectory)); - } - - [Fact] - public void ShouldUpdateCoverImage_OnSecondRun_HasCoverImage_NoForceUpdate_HasLock_CoverImageDoesntExist() - { - - Assert.True(MetadataService.ShouldUpdateCoverImage(@"doesn't_exist.jpg", new MangaFile() - { - FilePath = Path.Join(_testDirectory, "file in folder.zip"), - LastModified = DateTime.Now - }, false, true, _testCoverImageDirectory)); + var fileService = new FileService(fileSystem); + _cacheHelper = new CacheHelper(fileService); } } } diff --git a/API.Tests/Services/ParseScannedFilesTests.cs b/API.Tests/Services/ParseScannedFilesTests.cs new file mode 100644 index 000000000..fd55143a1 --- /dev/null +++ b/API.Tests/Services/ParseScannedFilesTests.cs @@ -0,0 +1,314 @@ +using System.Collections.Generic; +using System.Data.Common; +using System.IO.Abstractions.TestingHelpers; +using System.Linq; +using System.Threading.Tasks; +using API.Data; +using API.Data.Metadata; +using API.Entities; +using API.Entities.Enums; +using API.Parser; +using API.Services; +using API.Services.Tasks.Scanner; +using API.SignalR; +using API.Tests.Helpers; +using AutoMapper; +using Microsoft.AspNetCore.SignalR; +using Microsoft.Data.Sqlite; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.Extensions.Logging; +using NSubstitute; +using Xunit; + +namespace API.Tests.Services; + +internal class MockReadingItemService : IReadingItemService +{ + private readonly DefaultParser _defaultParser; + + public MockReadingItemService(DefaultParser defaultParser) + { + _defaultParser = defaultParser; + } + + public ComicInfo GetComicInfo(string filePath) + { + return null; + } + + public int GetNumberOfPages(string filePath, MangaFormat format) + { + return 1; + } + + public string GetCoverImage(string fileFilePath, string fileName, MangaFormat format) + { + return string.Empty; + } + + public void Extract(string fileFilePath, string targetDirectory, MangaFormat format, int imageCount = 1) + { + throw new System.NotImplementedException(); + } + + public ParserInfo Parse(string path, string rootPath, LibraryType type) + { + return _defaultParser.Parse(path, rootPath, type); + } +} + +public class ParseScannedFilesTests +{ + private readonly ILogger _logger = Substitute.For>(); + private readonly IUnitOfWork _unitOfWork; + + private readonly DbConnection _connection; + private readonly DataContext _context; + + private const string CacheDirectory = "C:/kavita/config/cache/"; + private const string CoverImageDirectory = "C:/kavita/config/covers/"; + private const string BackupDirectory = "C:/kavita/config/backups/"; + private const string DataDirectory = "C:/data/"; + + public ParseScannedFilesTests() + { + var contextOptions = new DbContextOptionsBuilder() + .UseSqlite(CreateInMemoryDatabase()) + .Options; + _connection = RelationalOptionsExtension.Extract(contextOptions).Connection; + + _context = new DataContext(contextOptions); + Task.Run(SeedDb).GetAwaiter().GetResult(); + + _unitOfWork = new UnitOfWork(_context, Substitute.For(), null); + + // Since ProcessFile relies on _readingItemService, we can implement our own versions of _readingItemService so we have control over how the calls work + } + + #region Setup + + private static DbConnection CreateInMemoryDatabase() + { + var connection = new SqliteConnection("Filename=:memory:"); + + connection.Open(); + + return connection; + } + + public void Dispose() => _connection.Dispose(); + + private async Task SeedDb() + { + await _context.Database.MigrateAsync(); + var filesystem = CreateFileSystem(); + + await Seed.SeedSettings(_context, new DirectoryService(Substitute.For>(), filesystem)); + + var setting = await _context.ServerSetting.Where(s => s.Key == ServerSettingKey.CacheDirectory).SingleAsync(); + setting.Value = CacheDirectory; + + setting = await _context.ServerSetting.Where(s => s.Key == ServerSettingKey.BackupDirectory).SingleAsync(); + setting.Value = BackupDirectory; + + _context.ServerSetting.Update(setting); + + _context.Library.Add(new Library() + { + Name = "Manga", + Folders = new List() + { + new FolderPath() + { + Path = DataDirectory + } + } + }); + return await _context.SaveChangesAsync() > 0; + } + + private async Task ResetDB() + { + _context.Series.RemoveRange(_context.Series.ToList()); + + await _context.SaveChangesAsync(); + } + + private static MockFileSystem CreateFileSystem() + { + var fileSystem = new MockFileSystem(); + fileSystem.Directory.SetCurrentDirectory("C:/kavita/"); + fileSystem.AddDirectory("C:/kavita/config/"); + fileSystem.AddDirectory(CacheDirectory); + fileSystem.AddDirectory(CoverImageDirectory); + fileSystem.AddDirectory(BackupDirectory); + fileSystem.AddDirectory(DataDirectory); + + return fileSystem; + } + + #endregion + + #region GetInfosByName + + [Fact] + public void GetInfosByName_ShouldReturnGivenMatchingSeriesName() + { + var fileSystem = new MockFileSystem(); + var ds = new DirectoryService(Substitute.For>(), fileSystem); + var psf = new ParseScannedFiles(Substitute.For>(), ds, + new MockReadingItemService(new DefaultParser(ds))); + + var infos = new List() + { + ParserInfoFactory.CreateParsedInfo("Accel World", "1", "0", "Accel World v1.cbz", false), + ParserInfoFactory.CreateParsedInfo("Accel World", "2", "0", "Accel World v2.cbz", false) + }; + var parsedSeries = new Dictionary> + { + { + new ParsedSeries() + { + Format = MangaFormat.Archive, + Name = "Accel World", + NormalizedName = API.Parser.Parser.Normalize("Accel World") + }, + infos + }, + { + new ParsedSeries() + { + Format = MangaFormat.Pdf, + Name = "Accel World", + NormalizedName = API.Parser.Parser.Normalize("Accel World") + }, + new List() + } + }; + + var series = DbFactory.Series("Accel World"); + series.Format = MangaFormat.Pdf; + + Assert.Empty(ParseScannedFiles.GetInfosByName(parsedSeries, series)); + + series.Format = MangaFormat.Archive; + Assert.Equal(2, ParseScannedFiles.GetInfosByName(parsedSeries, series).Count()); + + } + + [Fact] + public void GetInfosByName_ShouldReturnGivenMatchingNormalizedSeriesName() + { + var fileSystem = new MockFileSystem(); + var ds = new DirectoryService(Substitute.For>(), fileSystem); + var psf = new ParseScannedFiles(Substitute.For>(), ds, + new MockReadingItemService(new DefaultParser(ds))); + + var infos = new List() + { + ParserInfoFactory.CreateParsedInfo("Accel World", "1", "0", "Accel World v1.cbz", false), + ParserInfoFactory.CreateParsedInfo("Accel World", "2", "0", "Accel World v2.cbz", false) + }; + var parsedSeries = new Dictionary> + { + { + new ParsedSeries() + { + Format = MangaFormat.Archive, + Name = "Accel World", + NormalizedName = API.Parser.Parser.Normalize("Accel World") + }, + infos + }, + { + new ParsedSeries() + { + Format = MangaFormat.Pdf, + Name = "Accel World", + NormalizedName = API.Parser.Parser.Normalize("Accel World") + }, + new List() + } + }; + + var series = DbFactory.Series("accel world"); + series.Format = MangaFormat.Archive; + Assert.Equal(2, ParseScannedFiles.GetInfosByName(parsedSeries, series).Count()); + + } + + #endregion + + #region MergeName + + [Fact] + public void MergeName_ShouldMergeMatchingFormatAndName() + { + var fileSystem = new MockFileSystem(); + fileSystem.AddDirectory("C:/Data/"); + fileSystem.AddFile("C:/Data/Accel World v1.cbz", new MockFileData(string.Empty)); + fileSystem.AddFile("C:/Data/Accel World v2.cbz", new MockFileData(string.Empty)); + fileSystem.AddFile("C:/Data/Accel World v2.pdf", new MockFileData(string.Empty)); + + var ds = new DirectoryService(Substitute.For>(), fileSystem); + var psf = new ParseScannedFiles(Substitute.For>(), ds, + new MockReadingItemService(new DefaultParser(ds))); + + + psf.ScanLibrariesForSeries(LibraryType.Manga, new List() {"C:/Data/"}, out _, out _); + + Assert.Equal("Accel World", psf.MergeName(ParserInfoFactory.CreateParsedInfo("Accel World", "1", "0", "Accel World v1.cbz", false))); + Assert.Equal("Accel World", psf.MergeName(ParserInfoFactory.CreateParsedInfo("accel_world", "1", "0", "Accel World v1.cbz", false))); + Assert.Equal("Accel World", psf.MergeName(ParserInfoFactory.CreateParsedInfo("accelworld", "1", "0", "Accel World v1.cbz", false))); + } + + [Fact] + public void MergeName_ShouldMerge_MismatchedFormatSameName() + { + var fileSystem = new MockFileSystem(); + fileSystem.AddDirectory("C:/Data/"); + fileSystem.AddFile("C:/Data/Accel World v1.cbz", new MockFileData(string.Empty)); + fileSystem.AddFile("C:/Data/Accel World v2.cbz", new MockFileData(string.Empty)); + fileSystem.AddFile("C:/Data/Accel World v2.pdf", new MockFileData(string.Empty)); + + var ds = new DirectoryService(Substitute.For>(), fileSystem); + var psf = new ParseScannedFiles(Substitute.For>(), ds, + new MockReadingItemService(new DefaultParser(ds))); + + + psf.ScanLibrariesForSeries(LibraryType.Manga, new List() {"C:/Data/"}, out _, out _); + + Assert.Equal("Accel World", psf.MergeName(ParserInfoFactory.CreateParsedInfo("Accel World", "1", "0", "Accel World v1.epub", false))); + Assert.Equal("Accel World", psf.MergeName(ParserInfoFactory.CreateParsedInfo("accel_world", "1", "0", "Accel World v1.epub", false))); + } + + #endregion + + #region ScanLibrariesForSeries + + [Fact] + public void ScanLibrariesForSeries_ShouldFindFiles() + { + var fileSystem = new MockFileSystem(); + fileSystem.AddDirectory("C:/Data/"); + fileSystem.AddFile("C:/Data/Accel World v1.cbz", new MockFileData(string.Empty)); + fileSystem.AddFile("C:/Data/Accel World v2.cbz", new MockFileData(string.Empty)); + fileSystem.AddFile("C:/Data/Accel World v2.pdf", new MockFileData(string.Empty)); + fileSystem.AddFile("C:/Data/Nothing.pdf", new MockFileData(string.Empty)); + + var ds = new DirectoryService(Substitute.For>(), fileSystem); + var psf = new ParseScannedFiles(Substitute.For>(), ds, + new MockReadingItemService(new DefaultParser(ds))); + + + var parsedSeries = psf.ScanLibrariesForSeries(LibraryType.Manga, new List() {"C:/Data/"}, out _, out _); + + Assert.Equal(3, parsedSeries.Values.Count); + Assert.NotEmpty(parsedSeries.Keys.Where(p => p.Format == MangaFormat.Archive && p.Name.Equals("Accel World"))); + + } + + + #endregion +} diff --git a/API.Tests/Services/ReaderServiceTests.cs b/API.Tests/Services/ReaderServiceTests.cs new file mode 100644 index 000000000..940bc2ebe --- /dev/null +++ b/API.Tests/Services/ReaderServiceTests.cs @@ -0,0 +1,814 @@ +using System.Collections.Generic; +using System.Data.Common; +using System.IO; +using System.IO.Abstractions.TestingHelpers; +using System.Linq; +using System.Threading.Tasks; +using API.Data; +using API.Data.Repositories; +using API.DTOs; +using API.Entities; +using API.Entities.Enums; +using API.Helpers; +using API.Services; +using API.SignalR; +using API.Tests.Helpers; +using AutoMapper; +using Microsoft.AspNetCore.SignalR; +using Microsoft.Data.Sqlite; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.Extensions.Logging; +using NSubstitute; +using Xunit; + +namespace API.Tests.Services; + +public class ReaderServiceTests +{ + private readonly ILogger _logger = Substitute.For>(); + private readonly IUnitOfWork _unitOfWork; + private readonly IHubContext _messageHub = Substitute.For>(); + + private readonly DbConnection _connection; + private readonly DataContext _context; + + private const string CacheDirectory = "C:/kavita/config/cache/"; + private const string CoverImageDirectory = "C:/kavita/config/covers/"; + private const string BackupDirectory = "C:/kavita/config/backups/"; + private const string DataDirectory = "C:/data/"; + + public ReaderServiceTests() + { + var contextOptions = new DbContextOptionsBuilder().UseSqlite(CreateInMemoryDatabase()).Options; + _connection = RelationalOptionsExtension.Extract(contextOptions).Connection; + + _context = new DataContext(contextOptions); + Task.Run(SeedDb).GetAwaiter().GetResult(); + + var config = new MapperConfiguration(cfg => cfg.AddProfile()); + var mapper = config.CreateMapper(); + _unitOfWork = new UnitOfWork(_context, mapper, null); + } + + #region Setup + + private static DbConnection CreateInMemoryDatabase() + { + var connection = new SqliteConnection("Filename=:memory:"); + + connection.Open(); + + return connection; + } + + public void Dispose() => _connection.Dispose(); + + private async Task SeedDb() + { + await _context.Database.MigrateAsync(); + var filesystem = CreateFileSystem(); + + await Seed.SeedSettings(_context, + new DirectoryService(Substitute.For>(), filesystem)); + + var setting = await _context.ServerSetting.Where(s => s.Key == ServerSettingKey.CacheDirectory).SingleAsync(); + setting.Value = CacheDirectory; + + setting = await _context.ServerSetting.Where(s => s.Key == ServerSettingKey.BackupDirectory).SingleAsync(); + setting.Value = BackupDirectory; + + _context.ServerSetting.Update(setting); + + _context.Library.Add(new Library() + { + Name = "Manga", Folders = new List() {new FolderPath() {Path = "C:/data/"}} + }); + return await _context.SaveChangesAsync() > 0; + } + + private async Task ResetDB() + { + _context.Series.RemoveRange(_context.Series.ToList()); + + await _context.SaveChangesAsync(); + } + + private static MockFileSystem CreateFileSystem() + { + var fileSystem = new MockFileSystem(); + fileSystem.Directory.SetCurrentDirectory("C:/kavita/"); + fileSystem.AddDirectory("C:/kavita/config/"); + fileSystem.AddDirectory(CacheDirectory); + fileSystem.AddDirectory(CoverImageDirectory); + fileSystem.AddDirectory(BackupDirectory); + fileSystem.AddDirectory(DataDirectory); + + return fileSystem; + } + + #endregion + + #region FormatBookmarkFolderPath + + [Theory] + [InlineData("/manga/", 1, 1, 1, "/manga/1/1/1")] + [InlineData("C:/manga/", 1, 1, 10001, "C:/manga/1/1/10001")] + public void FormatBookmarkFolderPathTest(string baseDir, int userId, int seriesId, int chapterId, string expected) + { + Assert.Equal(expected, ReaderService.FormatBookmarkFolderPath(baseDir, userId, seriesId, chapterId)); + } + + #endregion + + #region CapPageToChapter + + [Fact] + public async Task CapPageToChapterTest() + { + await ResetDB(); + + _context.Series.Add(new Series() + { + Name = "Test", + Library = new Library() { + Name = "Test LIb", + Type = LibraryType.Manga, + }, + Volumes = new List() + { + new Volume() + { + Chapters = new List() + { + new Chapter() + { + Pages = 1 + } + } + } + } + }); + + await _context.SaveChangesAsync(); + + var fileSystem = new MockFileSystem(); + var ds = new DirectoryService(Substitute.For>(), fileSystem); + var cs = new CacheService(_logger, _unitOfWork, ds, new MockReadingItemServiceForCacheService(ds)); + var readerService = new ReaderService(_unitOfWork, Substitute.For>(), ds, cs); + + Assert.Equal(0, await readerService.CapPageToChapter(1, -1)); + Assert.Equal(1, await readerService.CapPageToChapter(1, 10)); + } + + #endregion + + #region SaveReadingProgress + + [Fact] + public async Task SaveReadingProgress_ShouldCreateNewEntity() + { + await ResetDB(); + + _context.Series.Add(new Series() + { + Name = "Test", + Library = new Library() { + Name = "Test LIb", + Type = LibraryType.Manga, + }, + Volumes = new List() + { + new Volume() + { + Chapters = new List() + { + new Chapter() + { + Pages = 1 + } + } + } + } + }); + + _context.AppUser.Add(new AppUser() + { + UserName = "majora2007" + }); + + await _context.SaveChangesAsync(); + + var fileSystem = new MockFileSystem(); + var ds = new DirectoryService(Substitute.For>(), fileSystem); + var cs = new CacheService(_logger, _unitOfWork, ds, new MockReadingItemServiceForCacheService(ds)); + var readerService = new ReaderService(_unitOfWork, Substitute.For>(), ds, cs); + + var successful = await readerService.SaveReadingProgress(new ProgressDto() + { + ChapterId = 1, + PageNum = 1, + SeriesId = 1, + VolumeId = 1, + BookScrollId = null + }, 1); + + Assert.True(successful); + Assert.NotNull(await _unitOfWork.AppUserProgressRepository.GetUserProgressAsync(1, 1)); + } + + [Fact] + public async Task SaveReadingProgress_ShouldUpdateExisting() + { + await ResetDB(); + + _context.Series.Add(new Series() + { + Name = "Test", + Library = new Library() { + Name = "Test LIb", + Type = LibraryType.Manga, + }, + Volumes = new List() + { + new Volume() + { + Chapters = new List() + { + new Chapter() + { + Pages = 1 + } + } + } + } + }); + + _context.AppUser.Add(new AppUser() + { + UserName = "majora2007" + }); + + await _context.SaveChangesAsync(); + + var fileSystem = new MockFileSystem(); + var ds = new DirectoryService(Substitute.For>(), fileSystem); + var cs = new CacheService(_logger, _unitOfWork, ds, new MockReadingItemServiceForCacheService(ds)); + var readerService = new ReaderService(_unitOfWork, Substitute.For>(), ds, cs); + + var successful = await readerService.SaveReadingProgress(new ProgressDto() + { + ChapterId = 1, + PageNum = 1, + SeriesId = 1, + VolumeId = 1, + BookScrollId = null + }, 1); + + Assert.True(successful); + Assert.NotNull(await _unitOfWork.AppUserProgressRepository.GetUserProgressAsync(1, 1)); + + Assert.True(await readerService.SaveReadingProgress(new ProgressDto() + { + ChapterId = 1, + PageNum = 1, + SeriesId = 1, + VolumeId = 1, + BookScrollId = "/h1/" + }, 1)); + + Assert.Equal("/h1/", (await _unitOfWork.AppUserProgressRepository.GetUserProgressAsync(1, 1)).BookScrollId); + + } + + + #endregion + + #region MarkChaptersAsRead + + [Fact] + public async Task MarkChaptersAsReadTest() + { + await ResetDB(); + + _context.Series.Add(new Series() + { + Name = "Test", + Library = new Library() { + Name = "Test LIb", + Type = LibraryType.Manga, + }, + Volumes = new List() + { + new Volume() + { + Chapters = new List() + { + new Chapter() + { + Pages = 1 + }, + new Chapter() + { + Pages = 2 + } + } + } + } + }); + + _context.AppUser.Add(new AppUser() + { + UserName = "majora2007" + }); + + await _context.SaveChangesAsync(); + + var fileSystem = new MockFileSystem(); + var ds = new DirectoryService(Substitute.For>(), fileSystem); + var cs = new CacheService(_logger, _unitOfWork, ds, new MockReadingItemServiceForCacheService(ds)); + var readerService = new ReaderService(_unitOfWork, Substitute.For>(), ds, cs); + + var volumes = await _unitOfWork.VolumeRepository.GetVolumes(1); + readerService.MarkChaptersAsRead(await _unitOfWork.UserRepository.GetUserByIdAsync(1, AppUserIncludes.Progress), 1, volumes.First().Chapters); + await _context.SaveChangesAsync(); + + Assert.Equal(2, (await _unitOfWork.UserRepository.GetUserByIdAsync(1, AppUserIncludes.Progress)).Progresses.Count); + } + #endregion + + #region MarkChapterAsUnread + + [Fact] + public async Task MarkChapterAsUnreadTest() + { + await ResetDB(); + + _context.Series.Add(new Series() + { + Name = "Test", + Library = new Library() { + Name = "Test LIb", + Type = LibraryType.Manga, + }, + Volumes = new List() + { + new Volume() + { + Chapters = new List() + { + new Chapter() + { + Pages = 1 + }, + new Chapter() + { + Pages = 2 + } + } + } + } + }); + + _context.AppUser.Add(new AppUser() + { + UserName = "majora2007" + }); + + await _context.SaveChangesAsync(); + + var fileSystem = new MockFileSystem(); + var ds = new DirectoryService(Substitute.For>(), fileSystem); + var cs = new CacheService(_logger, _unitOfWork, ds, new MockReadingItemServiceForCacheService(ds)); + var readerService = new ReaderService(_unitOfWork, Substitute.For>(), ds, cs); + + var volumes = (await _unitOfWork.VolumeRepository.GetVolumes(1)).ToList(); + readerService.MarkChaptersAsRead(await _unitOfWork.UserRepository.GetUserByIdAsync(1, AppUserIncludes.Progress), 1, volumes.First().Chapters); + + await _context.SaveChangesAsync(); + Assert.Equal(2, (await _unitOfWork.UserRepository.GetUserByIdAsync(1, AppUserIncludes.Progress)).Progresses.Count); + + readerService.MarkChaptersAsUnread(await _unitOfWork.UserRepository.GetUserByIdAsync(1, AppUserIncludes.Progress), 1, volumes.First().Chapters); + await _context.SaveChangesAsync(); + + var progresses = (await _unitOfWork.UserRepository.GetUserByIdAsync(1, AppUserIncludes.Progress)).Progresses; + Assert.Equal(0, progresses.Max(p => p.PagesRead)); + Assert.Equal(2, progresses.Count); + } + + #endregion + + #region GetNextChapterIdAsync + + [Fact] + public async Task GetNextChapterIdAsync_ShouldGetNextVolume() + { + // V1 -> V2 + await ResetDB(); + + _context.Series.Add(new Series() + { + Name = "Test", + Library = new Library() { + Name = "Test LIb", + Type = LibraryType.Manga, + }, + Volumes = new List() + { + EntityFactory.CreateVolume("1", new List() + { + EntityFactory.CreateChapter("1", false, new List()), + EntityFactory.CreateChapter("2", false, new List()), + }), + EntityFactory.CreateVolume("2", new List() + { + EntityFactory.CreateChapter("21", false, new List()), + EntityFactory.CreateChapter("22", false, new List()), + }), + EntityFactory.CreateVolume("3", new List() + { + EntityFactory.CreateChapter("31", false, new List()), + EntityFactory.CreateChapter("32", false, new List()), + }), + } + }); + + _context.AppUser.Add(new AppUser() + { + UserName = "majora2007" + }); + + await _context.SaveChangesAsync(); + + var fileSystem = new MockFileSystem(); + var ds = new DirectoryService(Substitute.For>(), fileSystem); + var cs = new CacheService(_logger, _unitOfWork, ds, new MockReadingItemServiceForCacheService(ds)); + var readerService = new ReaderService(_unitOfWork, Substitute.For>(), ds, cs); + + var nextChapter = await readerService.GetNextChapterIdAsync(1, 1, 1, 1); + var actualChapter = await _unitOfWork.ChapterRepository.GetChapterAsync(nextChapter); + Assert.Equal("2", actualChapter.Range); + } + + [Fact] + public async Task GetNextChapterIdAsync_ShouldRollIntoNextVolume() + { + await ResetDB(); + + _context.Series.Add(new Series() + { + Name = "Test", + Library = new Library() { + Name = "Test LIb", + Type = LibraryType.Manga, + }, + Volumes = new List() + { + EntityFactory.CreateVolume("1", new List() + { + EntityFactory.CreateChapter("1", false, new List()), + EntityFactory.CreateChapter("2", false, new List()), + }), + EntityFactory.CreateVolume("2", new List() + { + EntityFactory.CreateChapter("21", false, new List()), + EntityFactory.CreateChapter("22", false, new List()), + }), + EntityFactory.CreateVolume("3", new List() + { + EntityFactory.CreateChapter("31", false, new List()), + EntityFactory.CreateChapter("32", false, new List()), + }), + } + }); + + _context.AppUser.Add(new AppUser() + { + UserName = "majora2007" + }); + + await _context.SaveChangesAsync(); + + var fileSystem = new MockFileSystem(); + var ds = new DirectoryService(Substitute.For>(), fileSystem); + var cs = new CacheService(_logger, _unitOfWork, ds, new MockReadingItemServiceForCacheService(ds)); + var readerService = new ReaderService(_unitOfWork, Substitute.For>(), ds, cs); + + + var nextChapter = await readerService.GetNextChapterIdAsync(1, 1, 2, 1); + var actualChapter = await _unitOfWork.ChapterRepository.GetChapterAsync(nextChapter); + Assert.Equal("21", actualChapter.Range); + } + + [Fact] + public async Task GetNextChapterIdAsync_ShouldNotMoveFromVolumeToSpecial() + { + await ResetDB(); + + _context.Series.Add(new Series() + { + Name = "Test", + Library = new Library() { + Name = "Test LIb", + Type = LibraryType.Manga, + }, + Volumes = new List() + { + EntityFactory.CreateVolume("1", new List() + { + EntityFactory.CreateChapter("1", false, new List()), + EntityFactory.CreateChapter("2", false, new List()), + }), + EntityFactory.CreateVolume("0", new List() + { + EntityFactory.CreateChapter("A.cbz", true, new List()), + EntityFactory.CreateChapter("B.cbz", true, new List()), + }), + } + }); + + _context.AppUser.Add(new AppUser() + { + UserName = "majora2007" + }); + + await _context.SaveChangesAsync(); + + var fileSystem = new MockFileSystem(); + var ds = new DirectoryService(Substitute.For>(), fileSystem); + var cs = new CacheService(_logger, _unitOfWork, ds, new MockReadingItemServiceForCacheService(ds)); + var readerService = new ReaderService(_unitOfWork, Substitute.For>(), ds, cs); + + + var nextChapter = await readerService.GetNextChapterIdAsync(1, 1, 2, 1); + Assert.Equal(-1, nextChapter); + } + + [Fact] + public async Task GetNextChapterIdAsync_ShouldMoveFromSpecialToSpecial() + { + await ResetDB(); + + _context.Series.Add(new Series() + { + Name = "Test", + Library = new Library() { + Name = "Test LIb", + Type = LibraryType.Manga, + }, + Volumes = new List() + { + EntityFactory.CreateVolume("1", new List() + { + EntityFactory.CreateChapter("1", false, new List()), + EntityFactory.CreateChapter("2", false, new List()), + }), + EntityFactory.CreateVolume("0", new List() + { + EntityFactory.CreateChapter("A.cbz", true, new List()), + EntityFactory.CreateChapter("B.cbz", true, new List()), + }), + } + }); + + _context.AppUser.Add(new AppUser() + { + UserName = "majora2007" + }); + + await _context.SaveChangesAsync(); + + var fileSystem = new MockFileSystem(); + var ds = new DirectoryService(Substitute.For>(), fileSystem); + var cs = new CacheService(_logger, _unitOfWork, ds, new MockReadingItemServiceForCacheService(ds)); + var readerService = new ReaderService(_unitOfWork, Substitute.For>(), ds, cs); + + + var nextChapter = await readerService.GetNextChapterIdAsync(1, 2, 3, 1); + Assert.NotEqual(-1, nextChapter); + var actualChapter = await _unitOfWork.ChapterRepository.GetChapterAsync(nextChapter); + Assert.Equal("B.cbz", actualChapter.Range); + } + + #endregion + + #region GetPrevChapterIdAsync + + [Fact] + public async Task GetPrevChapterIdAsync_ShouldGetPrevVolume() + { + // V1 -> V2 + await ResetDB(); + + _context.Series.Add(new Series() + { + Name = "Test", + Library = new Library() { + Name = "Test LIb", + Type = LibraryType.Manga, + }, + Volumes = new List() + { + EntityFactory.CreateVolume("1", new List() + { + EntityFactory.CreateChapter("1", false, new List()), + EntityFactory.CreateChapter("2", false, new List()), + }), + EntityFactory.CreateVolume("2", new List() + { + EntityFactory.CreateChapter("21", false, new List()), + EntityFactory.CreateChapter("22", false, new List()), + }), + EntityFactory.CreateVolume("3", new List() + { + EntityFactory.CreateChapter("31", false, new List()), + EntityFactory.CreateChapter("32", false, new List()), + }), + } + }); + + _context.AppUser.Add(new AppUser() + { + UserName = "majora2007" + }); + + await _context.SaveChangesAsync(); + + var fileSystem = new MockFileSystem(); + var ds = new DirectoryService(Substitute.For>(), fileSystem); + var cs = new CacheService(_logger, _unitOfWork, ds, new MockReadingItemServiceForCacheService(ds)); + var readerService = new ReaderService(_unitOfWork, Substitute.For>(), ds, cs); + + var prevChapter = await readerService.GetPrevChapterIdAsync(1, 1, 2, 1); + var actualChapter = await _unitOfWork.ChapterRepository.GetChapterAsync(prevChapter); + Assert.Equal("1", actualChapter.Range); + } + + [Fact] + public async Task GetPrevChapterIdAsync_ShouldRollIntoPrevVolume() + { + await ResetDB(); + + _context.Series.Add(new Series() + { + Name = "Test", + Library = new Library() { + Name = "Test LIb", + Type = LibraryType.Manga, + }, + Volumes = new List() + { + EntityFactory.CreateVolume("1", new List() + { + EntityFactory.CreateChapter("1", false, new List()), + EntityFactory.CreateChapter("2", false, new List()), + }), + EntityFactory.CreateVolume("2", new List() + { + EntityFactory.CreateChapter("21", false, new List()), + EntityFactory.CreateChapter("22", false, new List()), + }), + EntityFactory.CreateVolume("3", new List() + { + EntityFactory.CreateChapter("31", false, new List()), + EntityFactory.CreateChapter("32", false, new List()), + }), + } + }); + + _context.AppUser.Add(new AppUser() + { + UserName = "majora2007" + }); + + await _context.SaveChangesAsync(); + + var fileSystem = new MockFileSystem(); + var ds = new DirectoryService(Substitute.For>(), fileSystem); + var cs = new CacheService(_logger, _unitOfWork, ds, new MockReadingItemServiceForCacheService(ds)); + var readerService = new ReaderService(_unitOfWork, Substitute.For>(), ds, cs); + + + var prevChapter = await readerService.GetPrevChapterIdAsync(1, 2, 3, 1); + var actualChapter = await _unitOfWork.ChapterRepository.GetChapterAsync(prevChapter); + Assert.Equal("2", actualChapter.Range); + } + + [Fact] + public async Task GetPrevChapterIdAsync_ShouldMoveFromVolumeToSpecial() + { + await ResetDB(); + + _context.Series.Add(new Series() + { + Name = "Test", + Library = new Library() { + Name = "Test LIb", + Type = LibraryType.Manga, + }, + Volumes = new List() + { + EntityFactory.CreateVolume("1", new List() + { + EntityFactory.CreateChapter("1", false, new List()), + EntityFactory.CreateChapter("2", false, new List()), + }), + EntityFactory.CreateVolume("0", new List() + { + EntityFactory.CreateChapter("A.cbz", true, new List()), + EntityFactory.CreateChapter("B.cbz", true, new List()), + }), + } + }); + + _context.AppUser.Add(new AppUser() + { + UserName = "majora2007" + }); + + await _context.SaveChangesAsync(); + + var fileSystem = new MockFileSystem(); + var ds = new DirectoryService(Substitute.For>(), fileSystem); + var cs = new CacheService(_logger, _unitOfWork, ds, new MockReadingItemServiceForCacheService(ds)); + var readerService = new ReaderService(_unitOfWork, Substitute.For>(), ds, cs); + + + var prevChapter = await readerService.GetPrevChapterIdAsync(1, 1, 1, 1); + Assert.NotEqual(-1, prevChapter); + var actualChapter = await _unitOfWork.ChapterRepository.GetChapterAsync(prevChapter); + Assert.Equal("B.cbz", actualChapter.Range); + } + + [Fact] + public async Task GetPrevChapterIdAsync_ShouldMoveFromSpecialToSpecial() + { + await ResetDB(); + + _context.Series.Add(new Series() + { + Name = "Test", + Library = new Library() { + Name = "Test LIb", + Type = LibraryType.Manga, + }, + Volumes = new List() + { + EntityFactory.CreateVolume("1", new List() + { + EntityFactory.CreateChapter("1", false, new List()), + EntityFactory.CreateChapter("2", false, new List()), + }), + EntityFactory.CreateVolume("0", new List() + { + EntityFactory.CreateChapter("A.cbz", true, new List()), + EntityFactory.CreateChapter("B.cbz", true, new List()), + }), + } + }); + + _context.AppUser.Add(new AppUser() + { + UserName = "majora2007" + }); + + await _context.SaveChangesAsync(); + + var fileSystem = new MockFileSystem(); + var ds = new DirectoryService(Substitute.For>(), fileSystem); + var cs = new CacheService(_logger, _unitOfWork, ds, new MockReadingItemServiceForCacheService(ds)); + var readerService = new ReaderService(_unitOfWork, Substitute.For>(), ds, cs); + + + var prevChapter = await readerService.GetPrevChapterIdAsync(1, 2, 4, 1); + Assert.NotEqual(-1, prevChapter); + var actualChapter = await _unitOfWork.ChapterRepository.GetChapterAsync(prevChapter); + Assert.Equal("A.cbz", actualChapter.Range); + } + + #endregion + + // #region GetNumberOfPages + // + // [Fact] + // public void GetNumberOfPages_EPUB() + // { + // const string testDirectory = "/manga/"; + // var fileSystem = new MockFileSystem(); + // + // var actualFile = Path.Join(Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/BookService/EPUB"), "The Golden Harpoon; Or, Lost Among the Floes A Story of the Whaling Grounds.epub") + // fileSystem.File.WriteAllBytes("${testDirectory}test.epub", File.ReadAllBytes(actualFile)); + // + // fileSystem.AddDirectory(CacheDirectory); + // + // var ds = new DirectoryService(Substitute.For>(), fileSystem); + // var cs = new CacheService(_logger, _unitOfWork, ds, new MockReadingItemServiceForCacheService(ds)); + // var readerService = new ReaderService(_unitOfWork, Substitute.For>(), ds, cs); + // + // + // } + // + // + // #endregion + +} diff --git a/API.Tests/Services/ScannerServiceTests.cs b/API.Tests/Services/ScannerServiceTests.cs index 0253ccef6..b78c6be35 100644 --- a/API.Tests/Services/ScannerServiceTests.cs +++ b/API.Tests/Services/ScannerServiceTests.cs @@ -3,13 +3,14 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Data.Common; using System.IO; +using System.IO.Abstractions.TestingHelpers; using System.Linq; using System.Threading.Tasks; using API.Data; using API.Entities; using API.Entities.Enums; -using API.Interfaces; -using API.Interfaces.Services; +using API.Entities.Metadata; +using API.Helpers; using API.Parser; using API.Services; using API.Services.Tasks; @@ -27,55 +28,38 @@ using Xunit; namespace API.Tests.Services { - public class ScannerServiceTests : IDisposable + public class ScannerServiceTests { - private readonly ScannerService _scannerService; - private readonly ILogger _logger = Substitute.For>(); - private readonly IArchiveService _archiveService = Substitute.For(); - private readonly IBookService _bookService = Substitute.For(); - private readonly IImageService _imageService = Substitute.For(); - private readonly ILogger _metadataLogger = Substitute.For>(); - private readonly ICacheService _cacheService = Substitute.For(); - private readonly IHubContext _messageHub = Substitute.For>(); - - private readonly DbConnection _connection; - private readonly DataContext _context; - - - public ScannerServiceTests() + [Fact] + public void FindSeriesNotOnDisk_Should_Remove1() { - var contextOptions = new DbContextOptionsBuilder() - .UseSqlite(CreateInMemoryDatabase()) - .Options; - _connection = RelationalOptionsExtension.Extract(contextOptions).Connection; + var infos = new Dictionary>(); - _context = new DataContext(contextOptions); - Task.Run(SeedDb).GetAwaiter().GetResult(); + ParserInfoFactory.AddToParsedInfo(infos, new ParserInfo() {Series = "Darker than Black", Volumes = "1", Format = MangaFormat.Archive}); + //AddToParsedInfo(infos, new ParserInfo() {Series = "Darker than Black", Volumes = "1", Format = MangaFormat.Epub}); - IUnitOfWork unitOfWork = new UnitOfWork(_context, Substitute.For(), null); - - - IMetadataService metadataService = Substitute.For(unitOfWork, _metadataLogger, _archiveService, _bookService, _imageService, _messageHub); - _scannerService = new ScannerService(unitOfWork, _logger, _archiveService, metadataService, _bookService, _cacheService, _messageHub); - } - - private async Task SeedDb() - { - await _context.Database.MigrateAsync(); - await Seed.SeedSettings(_context); - - _context.Library.Add(new Library() + var existingSeries = new List { - Name = "Manga", - Folders = new List() + new Series() { - new FolderPath() + Name = "Darker Than Black", + LocalizedName = "Darker Than Black", + OriginalName = "Darker Than Black", + Volumes = new List() { - Path = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ScannerService/Manga") - } + new Volume() + { + Number = 1, + Name = "1" + } + }, + NormalizedName = API.Parser.Parser.Normalize("Darker Than Black"), + Metadata = new SeriesMetadata(), + Format = MangaFormat.Epub } - }); - return await _context.SaveChangesAsync() > 0; + }; + + Assert.Equal(1, ScannerService.FindSeriesNotOnDisk(existingSeries, infos).Count()); } [Fact] @@ -83,9 +67,9 @@ namespace API.Tests.Services { var infos = new Dictionary>(); - AddToParsedInfo(infos, new ParserInfo() {Series = "Darker than Black", Format = MangaFormat.Archive}); - AddToParsedInfo(infos, new ParserInfo() {Series = "Cage of Eden", Volumes = "1", Format = MangaFormat.Archive}); - AddToParsedInfo(infos, new ParserInfo() {Series = "Cage of Eden", Volumes = "10", Format = MangaFormat.Archive}); + ParserInfoFactory.AddToParsedInfo(infos, new ParserInfo() {Series = "Darker than Black", Format = MangaFormat.Archive}); + ParserInfoFactory.AddToParsedInfo(infos, new ParserInfo() {Series = "Cage of Eden", Volumes = "1", Format = MangaFormat.Archive}); + ParserInfoFactory.AddToParsedInfo(infos, new ParserInfo() {Series = "Cage of Eden", Volumes = "10", Format = MangaFormat.Archive}); var existingSeries = new List { @@ -138,78 +122,25 @@ namespace API.Tests.Services // Assert.Equal(expected, actualName); // } - [Fact] - public void RemoveMissingSeries_Should_RemoveSeries() - { - var existingSeries = new List() - { - EntityFactory.CreateSeries("Darker than Black Vol 1"), - EntityFactory.CreateSeries("Darker than Black"), - EntityFactory.CreateSeries("Beastars"), - }; - var missingSeries = new List() - { - EntityFactory.CreateSeries("Darker than Black Vol 1"), - }; - existingSeries = ScannerService.RemoveMissingSeries(existingSeries, missingSeries, out var removeCount).ToList(); + // [Fact] + // public void RemoveMissingSeries_Should_RemoveSeries() + // { + // var existingSeries = new List() + // { + // EntityFactory.CreateSeries("Darker than Black Vol 1"), + // EntityFactory.CreateSeries("Darker than Black"), + // EntityFactory.CreateSeries("Beastars"), + // }; + // var missingSeries = new List() + // { + // EntityFactory.CreateSeries("Darker than Black Vol 1"), + // }; + // existingSeries = ScannerService.RemoveMissingSeries(existingSeries, missingSeries, out var removeCount).ToList(); + // + // Assert.DoesNotContain(missingSeries[0].Name, existingSeries.Select(s => s.Name)); + // Assert.Equal(missingSeries.Count, removeCount); + // } - Assert.DoesNotContain(missingSeries[0].Name, existingSeries.Select(s => s.Name)); - Assert.Equal(missingSeries.Count, removeCount); - } - private void AddToParsedInfo(IDictionary> collectedSeries, ParserInfo info) - { - var existingKey = collectedSeries.Keys.FirstOrDefault(ps => - ps.Format == info.Format && ps.NormalizedName == API.Parser.Parser.Normalize(info.Series)); - existingKey ??= new ParsedSeries() - { - Format = info.Format, - Name = info.Series, - NormalizedName = API.Parser.Parser.Normalize(info.Series) - }; - if (collectedSeries.GetType() == typeof(ConcurrentDictionary<,>)) - { - ((ConcurrentDictionary>) collectedSeries).AddOrUpdate(existingKey, new List() {info}, (_, oldValue) => - { - oldValue ??= new List(); - if (!oldValue.Contains(info)) - { - oldValue.Add(info); - } - - return oldValue; - }); - } - else - { - if (!collectedSeries.ContainsKey(existingKey)) - { - collectedSeries.Add(existingKey, new List() {info}); - } - else - { - var list = collectedSeries[existingKey]; - if (!list.Contains(info)) - { - list.Add(info); - } - - collectedSeries[existingKey] = list; - } - - } - - } - - private static DbConnection CreateInMemoryDatabase() - { - var connection = new SqliteConnection("Filename=:memory:"); - - connection.Open(); - - return connection; - } - - public void Dispose() => _connection.Dispose(); } } diff --git a/API.Tests/Services/Test Data/ArchiveService/ComicInfos/ComicInfo_authors.zip b/API.Tests/Services/Test Data/ArchiveService/ComicInfos/ComicInfo_authors.zip new file mode 100644 index 0000000000000000000000000000000000000000..e44b8aa5a2fc09d038a310376be57810102dd50c GIT binary patch literal 913 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

    8y7RH(DkfyBfGO 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�eJS}F+jGyCS%2Wl3TF2BsW5_* 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 `cn{=}L?4_x5F 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

    M9Pn=DiYKQR zIi?eLfF}!zD{Za4IU?BmyT%UnBh#2r z5#<<1I26sSuz7#mLiASnpA!)2A zkA)gbr~hr090?&V6c)G6u~w2^4=;=+M6zw$IP4I*XE%1>=2wBplc_nZKY7gK3&F^vrTa z%MKnc<%}QBf|UjmEa90Sxd`+S3qo8_Fzywdw!^ibAVCs-M2!C^{B;ws z;ZijNUW~>9A5BHrVf?KF~fwaDcN?W8SUrq-q1Rg{`_p(@JIre zTht{rwP`7J$no=N(Nhbj-SboYb10TO?a-1k&STi19QqJ;=xNrzHeeDpw(2T>A5!(C zCIzqX4e<{L1FcN@emD2qX>SFShGrn>WdlgNi~wTS%RlYrcA*Q@rS)6o8;-L%;8Y^mLOYp}X~hMHyl z{#h+M@4H5yOB9zc>}tN3FR>xl6WT!T!2G4y(dfw+rn4=Wwzv;pdvm6Y%CtbG;4G!s zaS8FC|Lp|1cEx@@RLx2$+6&mq1m~@aSl1obx)HG6KnJBIE>2_7vvUFxAO-^ zfFx-z-UwUxkn5&e_hkSQV9cO_lwQcvsRVCHk!0#lVF8qi<>3JRWPV-ubC_&i)+AL; z;!8mYSj33cq3;G=?g1@@QaZHGMPix|fLjXL}p|5FWWL-C|g0Vj@YYuE(W4A}MLLI4uQimK<4 z=)PE@gdtrHx|F_VBLXG3NFx@Ff1r3`?GVgBl@gb4wRr%?n65Z^oXaxO6x)E|{7=s; zK&oNIv>FP?%6Se`UbEOR%%TN5e|E6ij=b+Mh*gJRyPQ_VRU5!eg;7fSoCotqI9vc% zm9FQos8j_rR%0b$(@`Q(KEg^Nrz_n7&9I=IvPWHoY3?NfVBK2wCK3C^vu8msMr=eZ zT%-K6PayV4@15AQorxpw#OBN4L9Ry?f}7w63fLS0H&X!4N*yKb9d23wuDyieWy@?1 z)yWCl!0~(tp-3?YrRLgh97(cm_{>jN9B0~5Fx~v>zws=cGj85);}7*3^SPagKKQxl zOnF&JEw(oR`<0!?m6qE?jEIulKQ2kFc8JFT?R>-p?k(Xi(QKe})bM7tHV-fh2r|e~3bB3`^;=;$i_Qcq^hHHK{6l`A5XgPeLFo_7i#Nv@zyKBV zd03kAL%hI4&zN=yo<7ApU+MsK_7x(*D1Q85&^QcMdZn4*+qyjl33Yb$a_qW~5$q^vHrO0C3r-s)68KzY!XGofOe!N} zK>W7CS^H^Gu^wqZAQh#$>r{eMdIwB4&K_EGoKC|NfVjLz-h9B%uXXv-6afYYmKWF{ zFbfn0e=L2V(o=)T%%KUeSk~8ZcQu}MpNH}U&G!21Fa`zY%krjVaEyOaTyCA?pvy6b zu^CF%m*;6%!WA9UoF*oSr&W3p2O-hniBdSYTebYnlLmdXmNm5fj3n z$^VFQ<1vH!dUdn!x7ysPUG$!mp@{&2=w|5LC=g)_0asy^%w{X1z+HrMbqQ(UGzWcJ zbVD75(g!xhTqB@_^Ib!IZmaA;r77lZi4mA+=7W9y`L+T#i*pSMU@M^eZyHv;V42{f z8dCeODREux&eX^8fOO#UVuf&W{4r)jenHSOqM?2SB)XP=5U5Tcb;79^ix$EHRYQC%Oge-0 z_Xdp>wnT%JEYT$sTM2kv*3q@5v#~Wxj|tF8ODRLVFXG%-`A6%s z(Szf8Dfpw|e6ehTc9&+~apLKGWA8QPah?JW(}5NN7PT98-R8Kux-W8>amjU{LfMz} zX)xIP8GyRZ_+1b9qQJb>dqZRR|o|v&Rm$|J_ajYZ%^oQII0@+!I+krkrXF z+k^{-NW-|Fe9?6W4=G@CE8*1s6R3Ag7IqpG*FiLP#{x>1CYiw{D*181$$6j<>TKXICM7Y!6ze`nPFZWU0b%?GHE6$!dh@EL~)qK^uDagv_0am6ZMe8nfq{ zjxem6fBEY}w!)m&k+GPrk29$afo)^f(N1Z_tB zzy~TG7jU@0Jl?qOF$H2NPx6!!;ePNGm}?|TF!=;7QNzu{fH+kGH~=lHWV=&cRp8VH zp7TuPXHAF`#)(KGKrO_Kvu!_{MrJ>ST-NQr8w}#depoiLe~4{`s|Z#Jpdn}fqm0`%zh*50OIQ_#J`z+(EN^o{-kzXN(S6P&y)(LE zg%S8;LiynuR|n^8I2E*S3ynyFAU!gY8rYRHNMC!$L>RoF+jhu`5%WZe0iWEi*@(UcDrkn>?W@wm zA@F8XG5(n$S0acKjR@p|6~x~{6Tm>)h=}kx7}XmS2dW@25wgh6Qp1!d z0Jgw_-X8m}iZn}>(g6^Xw9I^(VZ9}(FF8GXsM%l}kkS>odMjGHtoe7Pb<9E{F zS1yk^Z#F~yguW)~PIt*fYMw{{xY919u3 z_i^OlZd`g6e+I}6e^U8It4B)XM{uBpf->*z`>{ObDsgQXS9{&5it~cLX#Y)j0@kEwlpm@jF1mb5UnWsm?J^0nRp2=+3|#}X+R5Di6t&=VotkiUJDa3JnBy-edwG(t z&r^<>1_k9jftY=m)3Ts4zK{&^JP}u0Q4(d6eOnux1Ozr&qZjBQKi-ij(kDW90ZHq} zIQWI6^}f!WHU!Uvn5cR~fOZi|DTQ`ou=V2_&JuVrM?*+#gjTXLt*Hgx{G~TCUvavO z2xNi1@%^^zCsRkf!N4^ZHbks1H<)?iuV88wmfe=_sRI(;B`gxPk44^~bf^wf$Dq)> z2-*E#HcYQq*FD7&hIL4R;OW`MOoH~_@Pm7w5GA;-91q7dJ9QaD@UF!6=X^VV7MBbw z)k#I4nUZhKcU*!1e3rq>%-j=?NKj-6xbA|})3DGu%=MIRY6fK| zmSC$?8lngOwfrv3b*csm$q?T#o$><_UG`Q*W1!dXjtW@-!K`!A4`7Y+tz;9HAS!Lh z|JT_7-)#a4mUR5T@aCmcDLQAdoP_65GJ~S#+SARTm8E#8llin>Bmrhh_N2WXS0W`` zP^-zRil#V^_u2{yX+kCTybHSkh-F-pd3BQ`dShmSeM6C#Q=!o{I zkqhv`4lKVuasIxHxjPAmE2QcD2w|9^STCh~fXi(N%w=i~#>S>QouPi^JqVGU8RPvh zv-#35J6wvG{NDdMApAd`qW(WY8UEjR&5Rj`o>aCyriH5te5>fym3Q>+`hC@X;AgYt z-3$%Y4EY>v5z<=#JxgbPYf$Z#r*7lu{w_}#TQJOfQ@@~U(TN@~3Y+7#b9fKNtQ(qb z<0HoZg4BxdDh?>68va!%iBBLS;)8Gp;-G$t%@7io(J##nzUHHMH6iXrEPd`a&o?Dy zPgtG<=^X!pf~BDv_t6);f>Qkkt&zg#|73=`)zwOaxOqxwwSO@brnHscM@@P0Hf3{0 zZFc0CeEaal_CcIYnb|Yp9VdF+4!fYo@U)DBXz5TEmn0dABgRV~e@+H@?#qu3YFNwO z=W@SjcJ$>J#MNV(muo$!_(y@5e%t7_gcGkup*4Z~RQo7TyKgznG_*2+_1T)$eOz!z zGDgdUY*Y=c5U+2er_)%6mHEgNR6r0%->}SHvuxQFwr29@?L`SCh*LOg+_*L_PO7UU zv3hbPmLN0_3s}Mwj4U(WubP?*l1WAwJXi17R5=M$Jv z8;8HWO;pHGtzqI_o%~KBClm$6F9Am~tXsDo!=1b>iM5y%sgE#j68k{o1@uH zV@*MDa@Z77<6L*z!yxwymqhp|8xb)DbG=Z606H#5Fnjj!&yM&{{_L`)fdR|>5yI=Z zFlEFu?Ra=r`cmF6am$Y(zT!{l8-ohCd~K?0(d+Tg^>;)tbYOO11St z?f?K*ny7?E@+Tfu^Wzi_rH+_)`&W<;l97v(kDClxUiOpRF-9L2a>MBP_4qkI7=7!b9wRg@Ll*^4 z?1n)uR1Tq=@Jj;fqb}MlT$B(vakuQ3JRab78s4FlM+uwFjAU@<3p{JuUA;*2V|T#*IX2lw));z zWWwwYxwOf>mFe?F7Q{X1TqHa39N&NIzlpFj`n5RRiHj`AANQrK-~DyqJ>Pw*O$+)N z_7^}=f_siVwrhCg$(!j%D|I*85OUi}A3Rb(z$3_SdbZox7d5YL$tyjRd9@G@Syd0` z6!>^2JQJb(i=t+DH!LO)It_VlV^Nog8UYq$?>iX)KMKB9lAAHzD`lhfV#I|lW)o#3 z>POgoa>>JD8Kefeu`-OHoAf%tcgb~c9rpVsr-;g%UO>kGlf^~K{OAOA#Z9-ykX>c& zbo9pOJ08I~J?eV^LF}1F!3rex`Z`f8V2OazMCUoVb#OF;3CvW5MDBXGb5<|~m4TpWSGRuh;H%=g zEpg-o_)aXJ+gff)7P4f1Rz^yF61Y+txGi6cAIEv|1tUxz7N!7}K}(N8i=+ktt@fyI z5@jbN7^4S282GqTKXg^o02t{HlL58ygMZcNs%?psKK%H^J3dGvk7Bl3G&WTqID9rC z90+?V;{gQ1Tf=?hGJ~)Y=YX^Tp@^Yi3ikVTr-ackjT71yZyqz^!wMga>9jC-|8sgY^9U6@VGoNF#`mwrOsXQHaS<=wBYT ztuj!0jC;5P2T@QgmL|8*Wj;>&S?0lb=bUJakXYgObNHxKSaEIYeaN8R+oQcM zzxjL;H;f8{Q$V2(m1RYmMkY9bH?dLwR2B`_n*ZDeL^kN%WPxv5@VhCkH;7Nyt{k`i za7}HkB@vO1%iTUVX3g88rosv}5W01+{st;fiD|L>mkACCh}x1#$V7ly7LS!$eY3=Y z>X6@4uxqLVBxOpaQlY&6d5NZDmgnbfC5B%tnhOY=&cA#aXuY?72#W#>z51TRgby+D z8v{C&H8tij6Xw%d22bA* z+irzYSyt$-_&(J-bVr5URRsZcT-$QU-&^ZtybcjY}I#A;Rd{O+Ekrg;QqPf?@ZhqIO|5}|^pA{BRno;Af zYW+0#5OqoxA^CC}2G&J^-Io7pWU%(I%&eqoL9b^T&`*Z$k4MomS6_toQ9M~r>rsjohqHwOUHLnYyv7qw&*EXBSI{3x7@ zYh6J;{GzDBG2TRki2woiyGA_b^O?^o3^w*@;Sd3`QA!y~wkESC zYmB8T1ga6QZ&Hg&VHbuF?^W{d$t18dMys*I6QnV~PXVl(qUHr$3h={Y`oxkBdge^q zM&S#%Vgsn;&;Qs_6h0!MlbTgVB#H9PpbDdaeoX{JWnd`KL? z!ju5R_hp{A?*p`eLEnAKP)=ipr4K>^U&*pU0SGixi$$dc6DwRZA{-aE3)|FTnC35} zpNQME+ofNnGW6>DA+9-dKc6GOLUwa|VuEG1!%KrV2ajsGP$U!r-2NXaTU!r3$Z~mM z)(#@R0mrwEouu|S93QuRnx=L?>#sN_o5=TiHz%KAm=h+#!lcay=Ka9iG7CRYqu!xq zEQt)=+D>`;IY9-uJ4E!rPnnHb_v~C%JRC^u2vVrTE$!q@6zpsnA5D-K#J^(rE0_jW zLV0BV?v`gW`7DS6Qw1Y0=g&H7~a&;3IM9~sZw71(T!<%E>8%(bD ztdUcBqSkEUEHp_`BYWL`x}=1 zs$H+y`tUNRkdkT=|mUm-$>I5MdnonFCi8DQXFxx?d_FO?(WML+jShLmsbSV+`OD5zO1{}F8}$x ztP?v(`;(MO^DwI9E3yRXeTG!T$QP+>eB@?-AxnF#e^vxj<)<}xcjX0i=ewu#+s zj+}e4YLUbzrE2>dQlr{4r+uQEyKh~2I#OFAsqdtCzpz_eH zCyM~{idJLyfs*>fajGgLJ_LYj3e|q}fIKm9TiR)suuKp;kF?n=cWBDnC?i^99-mA` zZ^*~{ZsR9;Ml$u8K~_wX`Z-v%z*{r|=+%q@oKc>Dr?;J`ch;803fa%3o-l!=N=WmI zK1wle3O%~!?*66j>WrZ9XY{_j+RBaZeqRZWX9|(4j(4?M)%{L@o!0=CqM2!l2A~q6 z5IlF0Y-8*$Q~98HEKU3LqfN8RFQ|D?f{-tdPf*Q*3hqT#g183OIDg;xRaRFZ+ zmvY*4P1TpdcrvAr&CLgw=j1UVCW0KIPeB@c@>7KKd=-ex2BFTcnqei~&>WU zjZJ`<2YWKh;*s+>2?v!mFM3yVnGLq>t!RPk&*t(EHz2LUUjW<$JgsG?tRUuz9SdW? zTRhVF;Q-Dibb6L$f5o=bns zkyBk>6HZ?cC?Vyk&CD6ln4n7wAUL0qp5rRQ za8L=vGTEGXK4NaGR|@>`+VWvrn`f8OcXK`&(`nA!9YAtqOtiwXOubLczivi(jFf!W z0Q7dh!K{FLUo#0brU)vyskgd}eyQ7TAmrCXMAH_W!UFfEX_SK;kp0{1FQ}c!kAJY! zXcfPjpE*$xTmvQCb*5BpVlTfm>kXhWqBDYL)!j+&FRV-pi_5G3wXFTF@wCA4 z#&5qK(3?wmCrYx>>W4MtK;a}KxqQA$gW;-AqsgU(xx%ISjY>Vz6wJgVi+mMY}Kk8gXRpZ?nAG zf16wE^R48P#W7xzB09VDAD|rTxUIXqwf)O>|4L!8+vhSR?B^mL0&K7x^;7ttO+9tPd|nA&cp@CjD!#j+CAYw<<{?zTF;pV9%%Ei!;yfd26&* zN1Svke`Jcyx<7_$3;K61a(3FcVV3%{A6-x;P~;!n`@gf9{K?(-g`iFiRfmdMc46^fVQ*_BsgvRsAk=O8gR^cL0EaiA12<7vUrHjUcX@q99Z(A!NU(1AEh<}u@Iu=ZM}O%c~Xmke!WsdPaAc7iMuB1fJuXglF8lRUd!an*5?|f zMfM5MQE(l09fj!=u@N!`AYVXH%_-dwXfOy}eo`6lCvS+VQ%9j90HQJPKz9)~h#?+F zqBf)9fUH5|k8rbmeEQF8)o)dwc^$$Z;F05`%kR5d$A8!ObGa`EG>)*fwpL14nNI`g zX2vqcQ$hq>$=gHq3Ibyr3pdr3T+N|+#z>eUEF>NWmVEFqz$w7mpBY;z4^^5l zpw2+2^0s)Nnm4z8E-})Hh?MSg56lJSbnibn@xJwaRiBX4 z%ud|Sg^b_{fQ^EIFj?GDQI)029C_?H-F%h{vhNwR!Q?~OEj=ZCN<~d$_qCw0$)s(BnbE#S$1JWz=q0S({c&59ns6AY`RCxA^D)zwueiuN3SJMZ^p5|eH#o8)X@~pz3ST_{B#q0uF4&OOU>5y>3{V&G2bM(Wf?t=EhTrg>Tzcrx!80*s&&t}ZJcG9JS3O9jTd=@0PUK}?iFCxE z0X1y+d0QgA-w}nCiXuaoY*52O0GT?9{Y0E$KdsZ=@Mi=s=5tz$W0<-`z}*Muw(Zux zlDCDNDJh7@l+@9g+@SU zT_)3^{S^7JYPwiCFd@QXC-coG&LMc9ia9xfm2XuLYqc1lx;Ze)X$j%vgLJO!rxW7F zBL2k}IM5G(-gYS$sdoywzu%=B9=!(E{3b{%wgUfi5o_T$1Pi#grURYmyoMbRjP^zp|Dsl@%H}T}H>i!2AH~OO$W+iGPdM zZL@;D@Rk?&gA4RD@-AV6^koJ4@neqHqYLzMu-_ke-vg_P29o6eJwW$yrpXWfgM)-# zhy%UHd2MY^ip~k;;G>Brnc5oi5mgnsRm!6YN#X}Q4wf*MxhhSUPZ|6MLQMwS@g!cH5qCW0B!x%`9-9(L-{ zt%syEz~-1##)dv=ys5y9xDw1;ymfIna6;ekI*=Sk)?@+w@I2Icgg%hN?xV{>7f@bd zxY{v?>)UYi0uHG z<58#WYx{S#W50x*)@X5LfrJx4|EDYHDV^(%U5wm0k9ahoam)RrFy^_cMn_uUZ2Xtw zUiDRVK1CB{Y;UR8q!eli&R=#-yKFyyQ*ZoIqkAVOK9qqB(8cOBt4CE+@=erHvrF5J zKlaCeFRY=h@&Du3O#2Xhv%y;HX8FzLxvw)fQ)s8@;;gvt9f#@k=jBxwWbP>kLbcY~ zEOc1jOw=N>abkP?6~bb_HXASToIyK-=o`Jv2$RGEzJHJ-H7*C9cAWEiK*w>T29Iy` z0=uA{)RF(vx0#2Vsd}{juN~UvZt; zn{vKdnQw~tyF4y<=}1CFyW4XoV+ub;Wlwwsl{3G6iHnR+5DSk`8Y;&X1o55IZp%DN zZwCRd-fsiLOOL`Ich{Q-h6ho&`mw~S0YKFz2)>lc{dbP-O6rWdRvtM2#QVN^hdQ}0 zXT4e&3SB$qU#c-YO{SyRs@e%w+A`#%DA|3*o$3by>%<1UcF$whe1})h5^i^w>QOt- zwq>o+zlc5dzhr9aKyfj7UbhLR2?xsCFs@i7$h$HTeOB|D2jBv2e@_cGk?#wL7^3-| z>ZS$vb&pJ1%zfeuB9sYyU+9|24Ybp`Cy+~d9JC*aw6g(kJqKW-v_w)woS1gtQ~kQ3 zPZZO2HllAiQExRLFwuQ4aa7`b;=%ac>Kx1}er0VYv)|zrvLf2e3+~<*0^je(`=;9!qSqi2a=YNU%IB&RRC4dUq5BXK6{6S!in>Io@w_ruoQ zFqEW#E*7&SXbaUJqel z&N6g`Ets8 z_b1$FyfLmap4=U)BI4LK{@eYI>r2K%fSi#n?D;tnpP6v&7D#(#Eh|A=h&4tlz$1JtyuM{6S@*^yzNLI ztNf;M+>tHXm;8;ic7ziBBW-S33OM+g-*UX-OX31bJLA~{U(mq*#8%as7cQ>{eGL1^ z5jUOQe64;Ioc;#X$Yr_FweR4K)TY^MGSfaGOt>Qpn|)K9IN`+FrY0OJdpef*dZ)H& zw=kpfRrG^;jdQnOca{G=?c+IDEB$#9>RoPn7dS~N_gc(e0xYRSntMm_qMLI;YY3)E z@|;SzLtA3h*6#if>F)L1hhUA$aZvw8{tYvrN=f-@%J2<|t!}!b>}-EFd1(0dzJ%^C z+qDnw8K3^&k>g3_$Fq-VJr9i&N8|Q~5mG7Q!w5%YufA=!tVizOV4Yn1U1J&Q>$g4e ziuCQHH3`;wkG@3Ey6<>bwp)iTelxjM>*dQ|>a*2V&{?Ji#=y;~z%7^G`8pR_IJ{KC ziMD7s_;xAie-WB&bXa_w?U#OS9MEtat%<+EliP3=tzi7a7lVb!u zIzb#$O3lq{fJhBxSoYUiMkt6><@IlM^;ft$( zrNP1D*0Df80Z>A+>{Webr67AzqI}w3ME^VkckZros>FI=6CP-gOSNK1O4iH3jK6`Hc--C*He!?06or#)BY}0rgXjIx$y`iU}=qo-_&nP{;m-=J`}@L=zmrt zo8!V6bUaqM;qO++xd%C@oSfigw-bNn$fxGjgtUa=T^VbCj^40;dbVoE{m?`Kg~zVF zaa^T@z>b^PHiaXmZK$3!M6o&qdX-#SB8i2`JBWmq2VLKgHSlH!FolyR$=}@&DZuQq zWBtc}^52~_4N@nRaH@P_yGK@}W#a}9y_TUwh!1EpD@va}r&AT84kEEzX#X=)-t75o zE!PU?%p=9aGWEKuFOwg62H=MDLWWfnMQ5vf#SRLzpqF&uwAK%g@y+%tV9E!WoG3id z?Wbj+jEf~+mQi1EVkWUm*Fo%Szr0oW`$k)YIY>suRyLp3tl+lbL3jeQa9o*A<^v2= zeh?cC zkv-f!{^M!wr4H7ZV?d3|unxwzR{Y2+Pp$|tA5;Sg z_btipM|!|5m>omd&)l9c!m5e&z&-u0@nrH_-F@smZd$yNc=%OkmvBvE4=7~WPw#t} zY|pwGZgKX=l3V&CGcK9y^M4~fd!cbz-8E`6*&BlCEZyzMY-)rGWW8g}E029U5D_sm zVdp#B=e#!GirBKceRW7?_tKj|>1ph9^r+7O-tnjmN@1GqXKepqTA51BP`A7m8-+#6Ff^Ax7}S=?}^rZgF0pFv7(6OExR2) zM)K<{{OMh^D7v?M)Zka*#kA;({$MSKFMdaZUw3ST{4$;2p@VB`N0dVJZZsX6KMX|c zSHrVWFY(troZX=_o+m%z6~*+*Ekr775YmNTE`ZLGwBD_2-8M4!_4VcIw#y7Qj^1=Sl!h6I>NyJ`d;{XMfy0`CppBa!{@ z?Do!Zb_yD(p}cSgXFhOAs*pl*g?wdyw|%?Q=I-F<5u#zM(z%Dg=Z_(FWCk!$GwPdn zad58OGZ*eo}KGep2gLkJar`c@C}$hY7e z+2D8IbV&6<%i|8EVQm9V4n*Te(s_@rdfUHRTCa5juL$V(dO8!p4;;!` z%6(>$E=;>8jK{KiXSMnbb3a`aJ+O_nT z%DCvV$0apyI~>hq9|dzfN&vCh3Nan^+|q`}-n439IJDV@PT2od95pcQ7SeyRBp}ip zxWQ?s{eSgY|MRh6Eqy{ze(j$-54<{*@+BzhfSn*&L6VheiV6CJ4$LxZG-$-FkRE)n zqHTNJ+G_@%dep8Zi}lMS{Pi|93jLdoe&>YgRXNdu{VFfDrRHxJgGtUxmrbEIvOB(e zy$*GIAGP*~I2<;7Aoq#inoL3V%qsn$vGO<_=mv&uC2N!4RsE^<>S>4=GwTrSHj6Dc zZ$OQlm_8OlFzUXvuvBN|G5DMT+{!tkrL$9O{et)JDp4hrGw%LgeU=}|qUnt3#;8Uq zR%!JLqa{X6&hCy#5xdW8KCumvmE{HJzTM_$)@dw^JWH#xS~GaAnYY<&bEe7<0l|3% za7Q90`_fyn29rDbUbu&cjc|17TQ^{mu4G0cw-;6yEt>e#<|`lGl6x$qeY?p%pw{iVVTLeR>Jz<$_pKuEk&$^p8#Wg$+&iBb4!zo|uerxj%W^ z>r$Pi3%;i!?_)J?VTDzgi1v^}fjUQNVBL za*(NS{QgeCO;CULjYj_qsOEPDW2ZHEpl}3Qx?_F6rNb>K%|&Ng_L>8g7bR*-B3Cd4 zWx90kvP!%E-Mf;1nkypzqb7Sdc?Gzbx$xsgi@=soypZsB$Ik$Jfq^H)ANgC(l%o`Q zop1&C#**QDPbzqI6HP29i1ZJR{4u>LprDpP14|%FJoL>N3MmSMG+7<)SpJqeO@Ohp zLLT7nLv4hd2s)QV`z}#yH2PP}a&G^!H}^e({9|^~;aE3emaUXZczMh%)k&AGsC5B^ zgt}6nHp04qz63A*9|IHGr55$zN|`X#z-Ze-pkM}N8hz^0ae#r>Xa9^Xryq#`a8?=g zDaHHhJ}*;&GAB_F9tYnVQwFEW`CbPp;MiSa=LGHNw9ft}Gs+8ALps%G*B?F5i5Pu9 ziXWsi|C7> zM?s0Z?>U{1hq@e(fA@BNv-HsEc9`2-j+4Zm&%366Y6%3u7E)73d@H!AVgBhcXoOur^8J`J zp)`Q~K`X+`n_~|Kua>BYG6T(RT!iWm+{tdW;lq=|elh2}rib}$!#~X=rISOrw;yI+ z%kb2)>)13mKu;3lwdEa*pGaha!5zu=55et z(tuEa7Q4_#Q7KpAZxVE3EWB#6LT|sJeN-O@R%w#v!hzG*VuQ%1;m|KcZ`4g0+E)?kpp)_CT4`In8KwlO?o#`?3hbfS0cf|9gpv?FQwU1ozt zjrn?>1p@)mAw|^zSv1F?CvZApm%NfF_DMFI(ECLcdqBri-_yTTQ-FEwgD%0xZJy`^ z@pRM7PydDV_`hQS8Yl<%rPG zC;iuMn;AM)7^kfAbd$_f+`par>{Mi2|CQvrN_SvWLOC9!q`X2ujyg5E(BF1#c-WGA zI~M=-c=J_{7VFWowZ5r~zw*YhBPBVzbA1y17$)2HeSpq$1~{YH0<3ucY&&U%wc7wo z;DZvS$uHW^=lL4mQuX!qC2MV`XFmOWI!AFJ#HNNZmWiCaGE1|V&53^x0JDUVz*m9= zQPz9MCISFq0io)ZqzfRHw&aKmHb!5rCtyTq>4I% zhAMon^i$cTKy(lSqkEzxE9eupU?85M2v&@e>d%8fLWh{pJCIa>N$HV)H8Uo~`*(vO z4|b8GK>~A)nNtDaWC|`>$>Wc@CBBih6OwlKZUmiOAQ%z2{v(~cT7CSn8ajf&U8eu{ ztvrV3=C|l@C_vaF>2iq6umS`Jh_ML@(xJcqBiq&6sIOi|?_rXizs?hP5Gjf;!D`7w zsitI{@!iLMHmB%cVbaroyl$AFoTCP=CLaL#E8(a8f3&`_Ay84uwGSoh1eKS8Z}M14aG6MO)Z4ovo&Xurpc z`NsyJd$Y<&B|cut?RyY&dT0ik6)+4n;mLP#@6?~b_#y`QE`2v9Td>1*hyZfm@T6_gVI= zY~8H3*S77{P9Stc$8;0ZjXGI$EB(o>(%JSY6zFGs)f^_SIcZs?ndx!u05 zh9frqQ2HbAhJIOB?;N=xWk-Hbfn`o#J{UoWKZg^p5brqty5HN(p{v4uLBcD3l*ETg z;m>mXgaUf|k~T`s-F=cxf5U5oNr-gd9v z!_nWgUXZ3pBAU!q9#n*Ll1CIi%&_}2GeB%07WCp=pZFWZAYOvN(j;^i~t?3+4Jy6&_>JskM}3dvfokv=ch3 zUUigG%^M3&Gr@FF*4ev?VmD{KDXP3`JE;DHM^1r|Jnw(_?*hy}8z+L?=tB&?@~Bqn z;*0sTqi_dhk-S&sre3Kb?I!oRn5z$nSPAA0kGI}F)+2b(bZ;f2zjO{?drSICW?z1J z#3(q76Uy!rGBH*|y`-pUHHjpbC}Dpaw^KKk+Aq0jZ~QqtO&2)0s-e5^00+^Dm0OAG zPtZi!Q+!eP*k~5{qRC%!a%;|mZk*$q&j$VjJeyz7uWQISU~R3>!(1f+8@bO|He>8e zL17UacaZpM1Ad&9yEYr(#{*T*XUu2YC9+Q}64b{k-cJb|gK z)bOc=8O#~Q`KD;7+pRj^*#~Bq$%3C|s-;Roq;pMS5H7c@{Eq@lb@=aF7~^ar{D+yk z1m~v0g4U5cvi$_;9{H;SG!J%MIXFtc|G1M9;td4@gm1Ro7W(3|`ZG=|WV8hc!kaSr-$%%_I4`u-229m&YLlL-Ms3+0Q4eYzPItnu1%AqY7pC?p zV(ZFPbyW=p!;y9lw|W-~-oqi#3ll-EXsL`X4=7Z7%XP>6bXR?4-6@SLN;kf(eY3&# zDOa=Uka$t%OXs_i)AJ7uJ+aj;PCIn(d{vo1kHQY@L+Z_BKesTzxlI7fT)MPv&5;u; z{u6%w|MjcS;ivcQFNSkKj$`f~Uw&iIinU-9pFOMDs`Ul`BkD*V;ZXy3)TEWN7-uFD zeA7zCg_egXjqaWbGw+%6P3`fncya{SM!nOVu#>(Zp?!I9V58}p#xkGN1-FFj>U*p1 zQk#UK0qYW9kA}a@S?^?IbfUrA)c@I@Lq{{iHtVe+S%vXFD$U9#L$58n?Ece_8!Ya1 z+q?K5vb#_~uGKo7vbwpAun=zE56G_ym-X`Pb=23y{+1(5r{m%+E1lD-MXjQzdU^#^Z*K{5e z|F+$Qx_Ntx%k_@`I`5d4mR3|- zI3f5RrIPE}bn1HshFXd&4=d8%ttPYp9SUerfP8u!o9+`k&Lml=iQO+BQmoZ9FBN}z z;^V|ePd~c-(S69$%{T-6@pdx<|4>gM5rVmPJQz(Q(M3<6{K0`i_Tgao{3CdokoW~6 z%L}Ay?)!{U!D>Hf#CN0a5H)X%`a39f?k=^N3QzIs|Ia-+rdpjwkxeCB$n(NOLzlu zXG^xT(_n_;{m#_Rf^`l5S*3wDV9J*VdXTV~HMw9byQZ#Q*Y*U5lq zAo@40Qd8^iVwWH4Y_)uH0J9r&$vkI-lUe^XP|nRN63w3V>}4DM5o_IV4W8iJR@3TvwNbD&bQLo zqR?+ze^xaG?Cz2K$+Q7v2~qoKDxA>5tj}aRh9{(4 zML&))dqr3!j~?OcE|WX{R`KCVn9cCUct6Lje}xzvQ9oE=Z>*V$GR_OOn_6l!me?`y za=l^rtWgYbRPuT8%!`cfKkA)Yb&*Y8hqpKr%zT7r%uw4n8|;$We(ycj#?ij>2S&Yl z+->Lp(B+#OIZx*HUNHwk8{(V2|3$y|zoWykXs6@L$#t7%>2TSB>52n0hrZsVIi;u< z8a=u0@Hu*{NGJ4~JYDSA3@vdoFOF%UH~rkLwjCKV>Y4z=-mxB`dFdb3)anJ{@B6jp z1kD`=D~Y3zktHB|FPxI+s(zK<4%Fnqr_h4MI47VW?v|2_LQc1Y$A@JGM_<7@^naR7 z$++@;$I0rz36!qSN}v9t9PaQCM0r{0!7g~q9#TfB9q~#e8I%JU+UKSw9ZgnHqug9& z&i6&7x>%aOQ${B{d10+<9zKdO4r{KeI%^(;FUvdqg*5fT)*uJ5Qsc#Dvgew*hS<^= zfX`e^SQf*h7#n`8(RNzzPamd0O5(EIs(`R;82V~hKszL%CBl`9l13amNgHuTdT1l3 z)%$zSsBqK`Pnrlxj|X)~r>h#l^hEER<~Qpdy~0)ReAgu5y!*n5L$0XlpZG$6nF{b` zk}2Xf9^7~~>myHbMeP`CVE2yMkMNgLawS7NGTPaRcu%dT+AP;~YqBM+Xz(kKc@LDw z?}N#p$ClO(=q%}~9>`x4I*m@0L5pzO8~kFR5loUK78);qHjb}9o{NmKXyTo8L!#ac z?Pf#BV>!V!`*`2f)T%v5xf={ixIloHR{{;#Hao;AcD{ca*aY?Y4a_M49T|a%NO*SV z%QvmpEoWjjgL+3iiPrO)Ya&p2{JAU8(Q;|3fge3~`MYx&a4|J=PCHFop{}L;BEKaf zkI-8As|rj-<=M|Xj4`#nE}dU6`@U&~hg!(*U3P$_?{R1ofyann;z8_`l%W(FcsG&z z05?0X0CU;)a^47W&4H{q=w_G@^f&I{xziR8UHY;cBh)2dq3T@?Et)LKIMXMdR{wr7 zBHjU9n0O#X6sqeGa`QK>^|aIQYB}a;ZJit&5l#sq&(TDwldHfvo7o5}{~AgMchW`s*T71scPMniTFI~CPv!{T^tj7lv+o<-DafQaWt^~U_BpfF13kOzT zefNPSaqlh4{VqGBtY0$A?t+#~I)*=9k55y(gnN@zEUX71Se6YMP5^#f@50T~G)l~L zmj_I4h`!on>-Wj;n^qVO>JbXcxQ!&NGJuh^oV~5L^u?aRh7_YG37D!MclrO~v?GnI zPoL4IGKpnyDka4UCAN^^#ceOndz~-X*n6d(Rvi=3UVy5rtGGTp1#CKtLpD@rt79>Q zI0_%rfO%o7Hpo?-K^TFCOx$L%i!(}gL)4zVX6^IIrtR5p#P8P15`GvuFEh4zu^22x zOnXTDJ%K51p#Rc3!uKJcE{nfVhTrX5R$Vh3?OYtWt*4*=*arjWD*VVEK1%Bqdz#k_ zbzi%-{uJ*+9M?oWi|L@hM#&vGvQY8zcWdFbO*%2$SHq{0HWVdU*VG1ebb!qT3^r&D z6yobYGvsz$FeEc(=xzR!+EcvcdUxlzzLc>jv}Wi2Nso`~ohwuRY^eQQaf~)$Sc71) z_dWZNmD7ggMhDWO^NGX4ytEEFQ(H}X_|VV5hy+?+Wr3?jj-2Ab;&hg~#@xn4@XjOGKM;<;By*7rFQ(B)W$|x{$q79tPJ(}io zx8=9-qhzxq-GV)~wqd^vb4s8ZZGlSUE`vl3ESDX90;%r$0KfN|Tc1;Hyz5xi`V}op zPpxjlhNfpVG@iNTW*TD$wKD{_LE@MvA5mfCMKjpdp%L=;Hs!?<*VT+u2L>x`TxjvKUw)!@{scr13HcQ|ARvXy9>;3w9 z-iJS~v^!0^apWl09L#m%k|^UCt6ODW`aT1H>Sd_dDk;nFLe($}>d{^7v~a{?$@7=~ z{`L{&+ue~hG1->hH@5Po$Cu(L*tnzL2{Fg2$7>&zA7WP^adDc6V^8p9oJ~a##6O~7 z2ozrWRBsdE?r&PrTxA$1{zQb^j8F~gFT(blut(#3kWPC5noDtKNvawdV_f43IvpkWhk`FFXiW0&QXvaM zV?&<2L>I+6T>)DKqz@Kcwg4ZiKHxB3D`fbV$^K%X0kJ97I2U&b2D#34L27ByE;2!T zR&8JMuX5!-_8UR=5ceKH38^T)vqQXuF+1@nb5(`}IOwS2dPdmUwFAeNZSjL{20>{kfc0YSDmd;eb(h^IaSEGBMhc~Zlw%fi#1X)J?piV&#V)OrOT~6PYuR=6r6aqLS`O(_k?? zPPOB|g4i-LFFL2N)us>B^6!m{wmwd?aET>0TB8T>LRS5Z>YaFf@`<>>J_>($Xvs=C z3CCUF3}*u=mk_l84yGlOsw`5fI16wVqAc>LN6_Kyx4TXbC}grI`NZ_}6imM}hwMw% zcxn>i&ncX>&^i4pqz&poP|GKhmIu1WSJk|vV&rbt?1)z?>-(FgY)mSQb?^?bA6&_u zqKh!HQ=%J`zX+>hY&}KN;(Z3u1I4e;vaIj35+X{@Q*t}$gZ9Ip{EZyOnB;7gqiMaY zrmnxtd?r8{5=BdIIH^2x+F-LZFE?RB*URgI2>4xzX~+|12q=5%$w>WxEdxDEjhRD|0dT)q*Ie*S8 z=hNxJM|lO%O#mVe+#F>Xn~qRa;43dCTCC z;jt~u15EZr`pg1cal^$;YJfUJhyx|Ezd(`n1m{)T*AP33-`g_MlnqY+L2|Q2dLhg# zqA>n4&a2}$tf3r@D=p#Zq`Eyo_|5$lGXS0UFNVDV+E? zNne=%3PiV(dYS^?gkU_)z-B~w?opNnnbs%#Qd^thWsz-6BL#wuEbj^TvpC;^KuCYB!a<}BpeMBT3iYR`X>r9ELmzI)oB zNNAF@qSqr_7XR$-1ZNq{70=1k=eYx0Zh%yJDCf5rP~fX-akrE~YK=qAXQ$RQ_rLFh z5?V?$P!dpAi+tr7hBlneXwC_kv>)y6(dT)?Tt0s7>g?j zz(TYn)a+c(Fw%5aY5qW-!#GiyaFl6bE|jouHhd~KA6Nah8hAVzX=oPQmczZ~Iinj@ zrxnIP=uc_Qi{i0Ulo~>ve6_fEc0|o_>c+(Q0LcWgY=>J+5;P+XVX8G|(=k|Ju%_DK z48OpC(}Jbk{(>kgZGpv9oq#MQ4-%fnJVuKsw;2b>r8a0QxNb=w!{&F7E5MH9$)s)lHUZ9`D^|<#w ztTZHge%}ayYNXCUT_BB6`b-q$jxG-xnWjC1&p?^Gqit7W`a4?JVCmjQ)0su0BXfw~De2ntofCjhdCfpu<(DJ5PO9o~^Qwzm%KMpASQc)7rV_4H*j2 zUR`zD?gGvzzGRH&^?C#dnu#s&3kyXKj)Rr!dgvY?S3gs|^<`fiu#iKWdsy!}FWUW9Suapz?hYtTq6S zM{@q>VWO?z7i)`oxGT?Zl|>4)TaP98s?8jAEe3^9oqQ&scJy_Jx!0P#VQ3GP z>rI?~xWzPO6POVL_#yyP!O;BRj4x^KvO9m*rnno(m#FG>G}kluNKU20^B6|R`AB%A zCaNyZyk0GVK8AwdO2~pf=f@?M8Qp(6iP(Jj9Gh|g@vv~CU3bZ=sO;-d@4-Bz3|L%) zs<6$N0iWh57f6m0F9rPW3Mb3>4VLvEg==G{y0la-&(5}CFYJ(sjwCdZV$opal zj?k(=zmPiXcOk`tgvq|H8O$a@wl?&&CL4Ze7%riFu=qqlmT0TcaI-^`*+~GOvTsJF znsyCO4_mBN+lsXZ=t)j) z7uhl?7W;mhA#EN4Kz`bePVwA!yV38@d6jwp$b=;7l9^28#|lvShiD2w@+kPR0$vij z)@YTyJ~#+#dz-NCeBF(z4Q2VSv<1<=t|qELy0O7i<0u2MvL>kWXAZN#IeZXSHYMnd zdFm9Ty=AdO&7d8^qOTdCfpYYJy0Q2Fcs&pAp#sa~f6U|_KA4{tJ9drZ40k-dtmkPX zeKl6&?2L!nUt$c^`$X85)L*z5aZzK@xeaHkF1v5;D~!}DUbeh-e&_Xr)3(7)p63f) zJhObFSl)LtIcR5s%D;HG<@(~zFI>n4EP#98KQo)@C(TA+%deTGbl6V zlIue|71@ZEinCRnBn;E$f73cmTJByPBW%r@s~f!Y_6linh}FJ`@=#mTjVn&PT8p-T zW>wMSyy9OuHl71&tfmhBOzrD1st}FIFg5Az7q?p=n=m)F*&Aq!G)1rW7wpn`NYIP5 z!(b*7K${2B2MB&M_cksZl!L9x>4!gMdF(q@S66WAt2xB&d`=%3Xoyo(`koS)nK>3- zq_WWJyCvtwwlJoIi;-LQ2S>q*QIScBdslOL6UqjMp3VralBr+Dy4^YISJ4Zo-bpSf02jYskNH zt+^t(`%#4luxJ5e8w)(@vpb6%B@7TrNwaNdGcQjKN6FShOg2Bz&_@s&Fv;fh2|YVF zVd=mz5_y$NU%%G;ll7-WeGFzWch-cAo^*Rf5ZPj8r=yCo~aWU9B~aAk9MepPC)| zZb_({s&2Y31E?~BS?Kw`-XKWN`#()UxyDyG2+VMmiuNLl8Wh9OPGz1HfTc!EMyqWvia| zS!Kil8#zj2rNY!>quK;l1Ryp{+-?U;7)En=sb{#xTG$f|uIBkl!=?$vYVO<=tV4z;>O^DL53b)-(H7a=qVmX8V=pSU9wYZ2Fx4KT{Eetvq*cGnlyCIvHOFbz9jtBEe_ma`{o*02 z_uXILigq>=Cn-17<|CAa=VSyUQNfKudG!8@+ntr&l6bTDjaz?pTA19gr`LGmI{GMj zJ?G?#(zMkfZxa=_PaBLq9ZUb@Lq3%KoL0da32=~AWeP4TLCxvZ;HlgnPP<7u(aB@^ zTeZBPs*T4l&ym*!1E^u2;m^d6mX|UOzAdR4D>tFO&i86<+TOd}nsifnBlUHR$%wS^ z1JcuLy~y9se^{p`YhLa4SF7Sq`#dHL!8Mc?)F=LDN*WFxWvrKD-NZV?5%%rI1$&!l z)ehx_&xRIxn9eH<7K{f@rM^78n45P8dS^A}(0T)?`yZc&aN)j3@5XP8J$!xYj6q-AAi79 znW)#~j?r!seg>ds^H~4z`S~XaAFWw3RH6i{xKdU1y*FYp#ZhWYN}9HdgOi%p$qz6_ zSXV7TwT4}Hw|MeY&qZQSUT zrE$o=A$xge$PmQ5d+>M>WbuH0k?S1c?^$+f&I{}2f}Ukbt#k3anfseg&5B^7JWweU zq|N-{-HGj-4#swC@U*! z=Okv}g-fhvB0i2wqNl6ro3VxGeR3=^WGy)SH?46R`V^BI7`n1rt43HDXq+yxV_X;m zLh#?wK}=luaz)J97?2BFm?9U2+HC(x{RUxE23U^8g2-jKi4TJVRTncsI|^LEk+cM| zb68sAGle5+Iub-o6dZSmT%{tBgSm6pCZ__=O}K{xLss;=Yi*H%hCOF1@Be(CAsu6j zDV9|656jB4I0SShII9@Cp(eJxYc2lSZW0dc%`un->vA4KXV_T&7j0hl6id9<(B(G~ zp)#Tp-S9VjX3)(-9Xkj!C==Qcvru;+s2Td?(BopxgvS`i7z2M{W?qkhS<2~nR=d&4 zzM`7bSN;Ko4BCt^?GbIS+OgQA9h~X9>?DeT3za;8Ou9j=&TtSSjIv{eNH``qp&dT| zhs#4BjX+5Wkg=!jE!SxBF`;3=CzjYHh&U>S5+`cJ*n}wynk-us(+HSO zDx%v1*Yx7-9YXs!wdiVs%$>mbvcgL4Lm#!&1N72T3|~2`_8j=W0B|2qcfQ(7%zfn? zKNVeYw(zrNFJ_qDDsy3ZlV-;SpK??|Ei`>6XYs1(jn1U6tSFjT82)ZGoOgx7KqVnI zO!dh^TB6!B{r$vmeYpl%`SCx0xBi3`2W&~>%QHK(a@=(BMo3KffE zd7|`vblvAL(^Q(2g0(!>Qk+Zh=!Y@PI0_lDBrqI~_07hVj7&lOzISQLfWEuI$fFAp zvXb9X64PdRsF>4?m{uo^kOg`VT%Vm}Pqes;$#=iR5CK(60nEnYz)u=&7TG!JD&lY= z)E7@>qu|_icX!{SXEOBZ3gr^E*cL#|dAI{Ngv0AcdUik)Ka-JB7{(%v(VD=lO`4K< zOvFeQ4J2u*2(J?FOxX#F`LN1@kNo&{G6&sC>_@i;Zj{%Hf=3TL3qFN~vBfdAquPH- zNfqa7qER#4&}i9qn5>Fdu_R?G5NVqGFl*GCKob-#YY|zKTk#HEj`1N)KgIa6R2FSs zelyFvNkYVj0alJ^4}z}l*}bNI8@VM6iSCqkGfyZZU;V zyVzJg4VUUp6#_hysJQ`#XX=+?OYyEY~`TGaoy-t|h0`R$rgmCO&4te|yy` z?UF7}P$(!@uzkI0iH8weB^T|``p7!2HkEP}7xc)SzhnV(Vl2cz-`tpa3da*x2 z{IJMWoyo}`0cNJw?|>OkDNKw0AY^HnDi-Nb-pzB+ZEf^w8#b&`IblSp^7hF|q&*a# zfiaBclDoZ0qMBJC4DX`vf95HR63Ff%ahxV4ioa<6>Z|a+BhijmP15YOMRZg?ybe`~ z0rLza%P-0pZkmTp+LHwaY3Rzf$kG^J_4yjnXH>QS7y`Y~@6x&7%zIDxrbS?IL?^y! zecC9yRb7ewQH>Q%-+mSVbO5L2k0#k}b!njwqKYP>j=CAIb&Q+6mg%o|Ng5)-u*R_@ zZm6>GxM+Vz02J-REvmCH55rnXU6S8)OYvsDRe;TK1-UiU{bp-LAa5>;RWtMYQuOAw zhuhNj{9vTJ{*4{0)boE~+hyX(phTOTvj;~~Vl$kQZfe||wF8^TP3Pv@1iaf-e`0lY zMBbNWDQS!F=tG@NJr}N&oTOMg-V6&1N@=L{_&IIsYw4HMDF#Nhc4K7(e*y~q>Kls2Q{t$UtN&-FaY1w)z0&TMnj!euH2Bf;HsO!=~Zsf zTML0ZFqDYUJagI;iywpaIL(jTt(z-E!}&i^yGuWhY1R*D?LzB2C+W>ZN*G%dMLBLo znTW3&gAB21oJ+D^2CMREjD1WZmdCi|wc2Nuz`HN(YvbBRY<#E^_0=NL<%dg9;_fDD z)~P01-T=e){n3*}eQ>{<*%^0?ciFq4yANO1D`<2O#enVG`@^9rAWZ{(`tJ-9b~b@G z31ye<%bruyls%}*Og9t7H2N|c;!4WuvG(+f0LnOTqx|Dsv~Lei_(Bc8tJuGn6hnaC zF#Bu3EL1#P5bBWc0zcRXrjH&H|LN4&WOxq@H_`62?E{-5V9f7VG|saHTmSLu+znvN z5!0>herl;xgxBs4B8FlB-c9(?P18t_-opnO-;u+TmtUk)&JYl7bn-t^{&~t1XV^v% zWAE1aCSP4>ADDX4$5xqDMx(N+Qo&&S65P4TS_rtc0h}p)z%@TsvQ}7|DF=n>Vdy(7 zTT@Y40vEtLXcWm$YrWSE0o0ZW%*da85*XTdLHS2RlTPX?)WD;emDkg41Bl5@O0oLu zd_#_n5N49O#J)!BVk#C$kP< ze}@aK+MO#W(Ys~U_~WXG+KHu-0cD8@Mqb{8Of&4u7JW{ zqjduj1Jw4=MWlw)pFLX(PW-%m;}^cps?x69T$RCoP3{6 zNzv$6a}tT2y0)wl^;*ffY4MPG#l!4y4`l}wsn?iaHaLsGNV!Arj0;~34lH}+&DSHm z`13DGeo<63Uua)V6lu`lgxHmB-9B+geT#$zAF55jv5R&BJ`2f>*9pwTqoK=P{krKb zjHUkgoRe7TZHx;NN~o=>;)A(FOwhtp*gdl{+<_1Fs3-Be%9hy6! z`uvNd^+w+u{-wrdZm0a>uqAe+-aRikGjDhyYWS5Py^Wxh2Q?%5qO-YS zkL5vopMQ|>&$S)_4IWYR5Bn}1*nR>ZQnH6qC~>*=9bPTfG4 zteb@nt6|ECt-4QyM&jhwKQ5OZ8o@mq{@7_)c_72r-KsluJeV1jEb?igEmS*nKm6FR zZX_Sol5?hkaLlI8LzYT^p!B{OTIrFcGaytL=~${<#EXHwKo=R%=2o zFS%B47||a8#aqKNAFB6dpX}d3N@YwarNur^Cwt1j3^h(Do(P6G>h7<%&OJ)b_+J2r z|A$@BVmvoQ7rFy$Toms>n?!?_v$l=W*2lojIsOB*o7HAvHgAV^1&$t1S)sj$L_TU) zwy2RG!hF;S20H3$x@|8~%q6PWa*NGr>&?ezjkETR@7r)K15GA8DH!ybMS;-k2`J(O z#1QGoK?+3?pHplCo#px1HDdni0e9{v`MEUG`8tE8;(=GohhF?jxkLM0NfTj)tX|i7 z(^O7`4qqvFsTAqr=_`zt@|o91tg~-~eae7el#3S1>I-&76ove8=C(nm`p_p{lY_i$ zw1i=z+84;GzFl%#6MUj)b6pNx6&L^)PUch(eKkxfH=}81H|&*F!$S@O>^Yh{h52rn z(5X`@kd}2*U)RU-zckd-N}6m4A4ydx0Z$C7a-UYrTKd5ro#4Ct3i$;xKV;t_2}X*ToS~fx}o6VuQZQMefaQ30z-I zY(?xc%wR$OpZ4fa7p5UFB8!7tX|zUMHGT}eLjL%0?$JJOMto<&M5i%n@@D`fF)+FJ z6tBCvyU_$;X<~6yv{zywI>d+NSr>`1;CrOHmG8K?C1+y7W7ZwOSkNTO;xIWW6O~VV zP8xB$zG>B54JzPdd&#|zH$CG95J2eoAW#C414R1$%A{$ipM5o-%M2r(X`~6yWU`e? z@xjbn;;6FGjU~kAF$9#|LAcKqiHDUXi47t+WjjldExYXh{^wb^4?Govv%tQ|Aihot4pN*$DdY~o25###}XaKDo z6!IB{b-EYxX38dr;hPi4nG>ktdthW050J{o0vl04QgZ2Vm~CgZczHu$7)AYjHZ7cG zJSWh2;MlgZ_9UDvF5_Ufcyt@#V-KMb%0ARZo>l`YOoa`d*BC##v@=$s`a8!xgx34x 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�vOTQi+<{D6n02snKesSmWg8z+w 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

    i5jt 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ﰆJvYL)$!L>eQoJpbtfbN z*AuU9WXw5KD}NaWm@&xCeq-hBgT)-WVN}4+1dOZ|3Ou@e?FceCqjb~8D!CcR+5Ux_ z)Nd?ugPVOVa)7AqISu{gzq1|%C#A@-Ab_V<(f)XyENWHncQJ15hd=TR_43masFAbo4KJ9Y6wZ?K9IiO~M0Su566lRYta>{Ugb5wCB7Lr>|6_U;C5cZ?}9L8ebg zgm0hRaI6V!ux|W!)~8KFVd}>t49ld9H+5;%H6yangP%0^&`?Wq;b5>oxhWQG@r2`` z71KidhxP$dguwm9+SEMH&NA8$xNF3vHO+^0u+VnrF?H!A=;!tDe8DX}Eyp9h2$iO` zkY^Lk(A8|9i~WNs&;5|lsud@X_jU_DY?R#tOX*#KQSC=z8(K563}`nz_X!=wO&Ueq zdAjvNKCnA%S(0q-8pXj!)>qcE0gDsgWR0#@ilz5DUm;g!downs2BL+P5fmn zn)Co-59o%lAJFqfS4)jF|+BTNTN4bTp^Yrg=_lSF{ zcYT`^A9o_&7MzQ=mi&!Vb)x=!j~23m+03#^T2GRZ7bJ0;ZLGROjqaTTXLAd?Z(y%L zAu9UXWXv10!4GdXH>CgcTfJNtI8DsJHR~SIkTieLFL%!!b7-=X9dSn8_~C=RR@vIm(fd`n-;s5NqYa z+pcMMwJC9?yAzJ&CcDWa00S8_y#PhG+m(x~6-m!YbelPF#co0x_I+?L>3P#vL8@OE z=J2~;+b|*2mw&k$F6Dmq!{+IYPS~J%?6`sW9Gqrs!+#NBxB_|W;`@T^bDo5@)m86d zl=?Hs`gzz2o!#p5C!*KoV!=P zO4`FOMh$zJ zTfd6chqp}3+eQ+i22-_YlY0IC?R8|(|wa>1E(Mp4Qx zQ!WZ#%WS3cX|afV$$S;(8gd%HG=kBW@2>M38;r;i%$p)?)*{Q3NZ3jIXL#D2YkKPn zN8pwbgbN6ZPrmrf(l1q>nG3(;ontxa1=v!xw*x#L5f^sfBd9Uku9s}}S2%*c*9HJu zGmGg>(O^e0BE?qeIeB0C_^{4VxyFjVzC&sZ8=1LEd8}O+>dCGHf;x4T9cHGTnoxiS zl6eMDQ(am~>)}Hya)ivu+ahC|n`tXFHz<<0w4!SY5ve^J08L-HC?`A|B#}+fiF)j# zToPO(Yc<+YJWLJ5*^)%es;hEFnQ%W6sEz*FxD8Y{IUc{Nc-W3aK>vQB!M}vVCi-CX z4YCT`Q;Azm`OTDz*##zLcp`kF4GMG}h4jgWuu0XR|3qDMK^SljBTx5RdkV010cCe5 z>MqC@*<=$(s+0%umSp3HE}Pcm-th6AtsRurch-0Ir#N1=uEJ; z*27dvbf7F_S7#aRN>r`Rs_LyT9xxO2RiYl-m@VZYBz{=--22Pa7wy1JWq=MP6}> za;LJAf7Ul1EBl~V$ICfECYY%KSJUr)=0zdHkMY2F=rUB3Pak>36Efep1wOPAI;Bv^ zNL~{Ve!)1(MJeFFl=O*v-FG|zD3tv^HX`TgcZ5I5-G-+%;SEDzJLyIE07D7OQgeeK zk8c@9MhH%T@IOO)h;y;bFf@<{X~DDr5D-fPDo*lj&t{oglYmwOb2VVJXh_<%x=)Kr z9|_QPJ!61R(w_l5xn4rHVtzjrSt%u|Sk@W{;*MBbxFMjh}0sU5)Srman!)$vmD zel%3MFK|9&b9P(aYk1j42MuWxq>t-@MyL3IU5pe`n9Bbw?}|FnRr2qw#IXR=^PasN z!;~4qsyQ$nYEjwZS`UZR$qahyF2KfXBpYML8aGyCkY15+zusB*{yfFS5J0<;JOVAs>VSt>Z7o&Cyq z>S>iZL;#X!5JD1+jj}a4(eqhddSNToSdJwLD6)(o-AW4OaDP%*~Asjo<6`ZC__o^Y*)xpR7)nYYa51Sy}Rvp~kNYuk*yN=0!x&^U7<- zucEk*7mFy|7_c8o4_2&6#T{_O@EHN)|9c1Y`Jw*%|E2|V+P{Yy=pVIH+fe&=*cJ+2 zLEsQFXtugorA1Q;tzm?`JUnq#NJZh$Zt=gf9uL87-AogdVzTcEIZXLbZgWBof^sn$ zd(3>773M<+x7kxOU)S44a5LeAaz%Kzwz9zuv&a7Pv3A5%ia+fa)m_PBzBg!~b{saZ z76kEfC0KE>@Nh)k;Ru_bb>E8SoA!{u(RI3!^|J=xk1QcquL2mu*s^C~*m^d zc3L@KOVEvg<42pLCODLiZnfE@7`UT1CvH$wiP5ymdSn!Yi7vk$q^m~6{|8A2L_51C zWC_IyK*3RjmXM{&-Dxf9#f1}F8!6UFb(K=Bo6OA&TaV8GQM)4#n+I-dvrBc?jdOG= zb#uN=b(cHI=$@2y6jTd;dbi~JF`)D*XxvX3hU&@jSZfz<73&;-8aG!-v$*;*^7%MG zxdm9M8+8Hz01D1n?HI|=zF32o4 zuX8V(wt(YY2)>znSNre=XlvuR;Avd|qO%Unxs0-C&5-p)ebsei8|xChgfMNg5@w{K za^inuv5Y6WHZPEpa~$HD8jx}OLMpO%1$G@k80_#zNySaB>l+?LRHta^CH~=tr#F+C z@53&Coo}J_hR25|>P)x*RD5*{#c%FdAQ0vGkR0@nl3edPuA5mg(nMUQF0*HRWr(jek6jT+*VI`MriT z-zevzu<*#USX8QMoF@u6Ubu1VxA?1|4>&GB+ubBUT#sS-;8gqtLt{^l5zNIs)<~Z+ zhpkKNJkQJRLc~P92*vI{i>dmy{#}L~kcW*%ao^KAbq=k$7qpQ~#J}3jyuD3(pKyD? z&;tu_evku1N^L=SUH1n;OlQHXbQO1|+=Cqg^!v%b^iB8*R=5-5Mr3|%)yinPMPFs{ zRcN&8EiB^mpp1~XYs1d0Y_f}67<7u z98`<_J)@mzpLOJpUbed<4_C`zqT!O=(N`8fe`y z8=!L&VSr!LoGO*#^k}xF(DSCeh1Gj98z_gH;ZN0l705gI{|Y4$7Y-xKLz2!Itc)?6 zzhff}Yq7vMxuA$Ul4}g}QEsIRrEVU+y=!yB!Ef7_3F%MAa>XXMP-g{v&E2si$@6F) ziEX^yX3U3UosrQg`zN|EQ5*L^(!EnyLQe9J=@Z+b(M;gX0J+x1JB&v5_5)>D4R7tF zbFiN*Kkn(fBpWi5k4~c#)^Q}N*O_}v^d*XX%lEL4j^xVrMzI_iGh1jgZ8wam)NKZu z^TOIY&Yx8=UVv$rujw;;eZ4p$WUlhzdw=MTDmW-PB+PIH7EkdF7bhJ18gD6>R~@Q~ zJymB&Zdd?E2bPIu&!s_09+UDClyqWFTVyK*bY8%+xIk)+jE`toYd)g8;|d0MCZ9Q_ z0?9WJFEzwXIR;r=oOn)#1*Sl>@`Q}Bywa_$*dAIed2E83R9DyaV#p-+Fv-y4LU;GV z(cSUDvFwqj)(BOGr!dJn-AbSjmdY;*PpQhd?&Mcn4P@71BS*n#My!O-V{K#Q_EjWsh=zMI@xg&L;_f|4Fb{wg%#}cytcGKmS#+z01Sst5}?r zZ=G!Vkxf7E2~IT+Z#vf<82IPu PHs>27-D!+*^&pn-Iye-;>XGk$pGR%>X=#EPk`~tvXw#0_g1CO0Cq|8o zEAIS#O|DZ`Sno^87*IwThq44Wxb0e8YdXGt&G5KE=elACfk1)Y--7(}h3F{oiMVYI{{D*cwZjmuwN-cr8 zDq+-M>t(T`)*;#FD9UHu|#LE05FGh8%QjBUxCj<;)0Ux zo2r3!IsNNk99X#XuE$FGw_9Bvs%X-Wsm5CyE}8P$93J};C zVX@^hpWyt9psEb^cnJuY5!C$hg=#N#E7(+!SZRBdbXscodH(gpJIv>4b?6i-s$vuHI2bHV9po3t)iTt-V5=vyHCh56k3bf>7%IS!{!Vg4B&lv|m zkrpV$JX8^x%Oo+zXFDc;ssMyG=p8Kn8))j$9=hohuV;4*xfq@LdD4OWhLjY)f_2TV zosY=1JMq;X+ra}pO!mB4GWmVZWJ0G`BN1ayi_mS_amojhf>8oHKKe>HXX3+Rf6ndb z#rLBsI49%{TgnL#?%`|W+&!1TZ3jH+jbc{Hbl}B`@<6v7st(N{lbZOQY`oC%_@Ebj zfv&nJ)p!8@bk0q{$OYFa4?i#kxP*6rDTi70WyVdd&|Qxsvg^Yfqa){wzFNE*Gb&_2 zj4auHg^AlcDKM?y4%$*pU=Ts?w?jDpOO>MiQXph-g2U9Xq#81Gze`G(Xph;r)Z*3v zC*CL+{FV=L3R?U??qM$V^=>QmgR`^dM<$hHvAhQ<{Dse{FQufkO*CvHV`fk$&t2yN#W8CGN(J~0wqmn-;4aZ{Uyt`TI z6Sv0GmUa+iBiU!oj6@QIsMH4RpvR^awT<-2t>JcAt9M%0(X5Srq#`G6qqX;0xX06i zkI=v!Kc=I6GP;bSfBGVG3y@_&v6XVo*!|}r`|AQlaxI5f(4hjGbge$xL-NCWW-Y=IHkv;@h|HSd=_~s;Zop3{7Nr_Y<9O4hU%c4NZCg+DA#?Muuu{Nqm;P@jOG_#^(u8t;`7M zOy7aQ-n4v{0&WJ*N^F;$+q%o%b?nTwvw4Ai)J#<;zi1+wd*D9EQcKKz5NKdOek&;i z!2kvld_j@87%pYIWQTDVydYRTu4t%=OpGe6${7lA!~r|f=FR{OLVgd@?L>-a6Jo8) z7^%6AZWlod23tc*$8!rCx+}FRJ){D4hE0aY1&>$Kw~@w8rhKCPYvtn+&ouNx-ct1; z-mvQpuTCq?%G!gji%6^EZD&NfyP3OAe}3q?+m7ajr)*&hfLI&pa0-xco5H^lZHrE)-2wbw$CuFp)y5BlLe}FN=Z7rhA-7T7m3@vJBTdGwhd1w0&FN{yaQ4GGN@iBZ)yq93r2T;SLh4aUNX>LgZ%5 z@}!DpFqk^0SO_l@3`Eoo)xxnwf}sI#G1s|ew8soD&h(&9TYz_+r#xn&H<2^)m!=QD zJ|SF~GJ$>hX)I>)`pNU~d^XkWzhAi(8`R>H9;*@aK z#pLZYo2MtP8JKNP1v%rGNMQ`9>|#UDL(Upn(%$Ahm#Ds~TLVA#cllN~5-UL(lN!4J zI~E`2NwEVr2@tOt9}Rv(u;M6w;pe0{?F;3?j=NzoCv%4`kC@H`COIyc1HUw7PDwr9 z8SRR=cC*#we5u_)?~Lsf70jH{dm2Kl+ig;Bov!WnuyNUdbwx;ewRMwnR$xr*$)DIB z=MI>cGP>&HHFb?r7V6Riy%cZ+=I9(<(FomqJmAKyUJe`+S`x1EHs199ADr8}s&2*_ z!Ii?Hm=zzO2FrD+yOir6U}qkdNvd-TpX9#?=`VesI=yY?ACJxC*8>*+v0Qq}sKjRQ z+(yVCxCx)ezhGSXz>3%9RmFSfC*s&Ql4f+`j;=hEYi?P_RZk=uI*6 zCVu5KBTH9}^jsDsgsk_f3O%}t_c)o zfRUIlK5lv@`oxxLX{!|3bY}BI_pC%LCy9ngJe3-`-p}R3yF*(&dycyq>0-U#1aXl9 zvsgQP?oQQeXsf+jW7Pe6+Y$_4w{@R3C9;f}lYeH#W>B%5sx)L)Yxq>nkk(Inx?n*j zH1IYK&j(*l=T{}rEOe2eVqY0vS5`BE%#-Gp(F>YScRPE#%`Ykec!_jM{`tlizd8Ng zY`Oj~hy*kGzCbGyg7UFXD&TlAw@?oNQR~Tf8(g zHFUKfQ%G1%ob&$0XT$ajZ>fn+#{F!=qSV z;2)vJbgvWlw*q(V!yIY;XK>Y8l8) z&ct%oDx6Vg%Cep^3PE|~pA=c%WNjyU=<(og+Y4Yo`4gDR)N^*28vP^6hsMoa3ye9r z!KLpE!F}SI5HAUrxdM$7%`6&uvD!0RyzOW%ckPc}#M;c@_fN`7BMTEyHuvMpjbSx! zjIP-vvr~eLRVw7Yu`xsGVI(<0ijUArtb<|8SWG!&Y-FgHv*i+jn)P2?ItLcZ^l>4d zjGjR|T{!X^F}MLB7jRSf2O!Ek(~P;s|HGYTE%zKm-`X1lgb?mG*%N@c<9C1&`KV z2lqDCzKR8mI5C>Ug*m929DevAyEL*`rk}y;cDpk8d+MBkHz}?k*4fU;RyIXjhCwe{Y{=eZgz( z`FKxLA#ueAy2?xFmU=uT4t>=@t1=}~e!I;dmN!ctLEC{l`rI{kSWB_0G@qK1$P&>l zRjY}9Z}riR3+`Z_vz}{v4t=QI1Ypyys_x_KUV8S89>XdwHE$>_<&Rbu2bwTXMFW^j z(E^y*L>+)7e)u48Wyy?4t6ytJ7R$0YdQDNhc|v2ofG6`?4HAA#OfxU)*ou^t)rkfi zPqB?P*`zjrsm^CI?%H!C=GTebwbF#h)Vw4{NBZ7WOhwQPJ(&@AC9n?YmOTX%k&j1$ zUtHT>z!2ingxPL?h<7+6+Cqk&s{$I5TFjJS&sx+}*nkK82eP~!fa4lPN}^++qd z!sf(Gug#}5)DHW-i6z+lwk`6CE@n;33FHePcsY8{^z}tlbx(q}`KQ;TI`$chW!D}9 zN(MO_=?3jweZlc`F>sTm((biKjn}o0(Tf1Cq*~kJ%x*jtHlUU91)1ILkD+$}@ub9p zo<~m_b0`YQ&_g|q>Lmy6?hAQeCRJ85KnvweQgU~pv5%aiL89nDNolTLDJ0!QzHyp= zbKkI+kT8FbJ5*wM>VrBjXujL!{9m@7j=S7n6LSe9^kj23qRALG9{MRmOOhd@8Kn7|Jn)Oz9~zD_j_Lh7J3@O=(DefDDy%Y`gw7W&tg&{2~(++0`ma-aV`sMv3$hXAQ z3$TInnn{QoU1bDKi`jqZe6jC!6=mqJb=3k~x>Nm?QrkOA08nP}dmoeQ z*6jk9Zh%XJ2_rDlTnvIekav&y7VGe(t!H14E)bRe8ma5$nHh zqe!tDCWTP#H6(2AsL=xTFckwwkfkJ>iTv+Bty2tQbo2XhBl?nN9lN^TA_z2hFR7wD zz%}`H_ah;8ku9_*+L1d0!D+U|0t2-hdx@WnLYnI}a@jURQ%I z5o^P0Di`CHp!;9dLMol1`pPUrzxDiZuKOu`iZN6hZOUV>Fm6fOc}PLN2JH zqU!qfn+btlWxHFeuJPzEdi{S43Z(o~v@!OQ*${S8>DiKRA#5~n{-O`~Ai9Bdwmq#? zjqh=P5zDT9G$y=rCvh~&p>x2%W~}23ZyxF?_Spyg3j&TyU;5Q2)+A1sE454`}7?zT~4&**XSW<&D?tw;NRxMvJehV?kUxHgQCq{urK2KLg zlD4na0|d~HRRmC%;@>}Me)J=Ka>%kmS@wLjfe!DJmH0b1<>&=cj-^&2=`TEcah31Z zu*0WnyJOHCI=!6J4^S5dd6ctrbjbgoEdQo2*v!n!z3v#eId<0i%SNi|Qu*pLRj;^m zTL9*}17!ns|DEBO)Moab$oW^wSFjl>jy?>87U?Qp5$rb9(T@cqWesM`(9gY4YA_#>VnWGp9f5)pS?%DLGztk!&>bZwjg%Ep}Me;i2mlinjz+S7!p|f z9+JZQBPAxdX(f!S9!e#vKTg`#b+OiX{Xo5?1<%d^Z6AioPpMs7q@jd#cWPfwrg=-lXR+on;$`4&-NovSwq0 z(FUk|U{%x((oO9>@@ZeNZ14G#Gm_db!k<*(Y7>N)mbdjz>I_s0LUphUm9J%msDb?6%hz9>QH;K``=r)`VYw)KX;@Jj&H;sm6+N z#0?cpPc8@R+6ItomIz4StbWUg7<0Nbx}E+N3g3tFz{K%SIUPPX-rOZp^I9=RD>GvFhm`EtBYlUP zk|i)iQXxhCI3Ys%WJz9CHumb%^vWm(+($r%AV?|F^Y4bM#C zy=9?iYY*GwX_FCDqkI1f%O8OA;eBJW(Tb|v@G62nyl*oWhwVxJY9xIO%!K7%G2SFv z$wI;zQ=Ti3b1ASvJ^j3TOJGn)@UM)xb}i~AQkf!TWd#d)KII9?3?81oO`?lm;q8-d z<(%tjRC&KO(_4OR3LTAmxO8A`1o?Z@0Nlp>A4!6qn$oeP7#F1x0hT%!Xb)yllk1Of z>}EH*wBFWzmE!5%xylFk;NdB7l8}Qy+NbN7^w4xwLn11lp|Qo&0J@vgEWIT`YW%LB zn<_h%X&v`Z3Z=SS|7d7#**T3HM1w?f;$19*_!E^UKlR3)YWj9*N+uv13P7~A(HRdb zT+ro?!?s%!iTjDRbv=~ruu0hwu#NtaC}oh&3orDHXtY6K3hdwlaqJrn#@W>?kf3($ zXzsjp`?S`T1vbcP!=iyW20)Js>ZeVI43NeIlNGa&O&q#|5h6b!k$Yo^ z%dl=n#SACd&1Bwmup1f)(bZr{K96;D%vQ^Y{C8H3{ADQpeIql?bay|TBk7OPZGGwf zf!D`-gC+F!Qve@C;0>T1zJ2+=$_CdDJkWn#pVz^Q*#z(cb6woQCCT`6pHQzz z?FU?xt5KE$$LQ44tRa?e-R!tX!ArZ#8<&3Z*_sny63}7;cLkb?QPXA(>oz?6g|*B- z0$=U&duc)E>GZSM;&3cVeD@0+4mb1s*_C1p9HSg(4H;d`KZp&O?#qA3waz*_O}o zH0czWUG)m(kX4ZB814$204I+abx{saJTp7R?@j#MTmb(Q8F%3wh#6`J*t-AFtZMUi zb&lowY!J-c3Fs5?)u1==NhtrL@tdB1p*EfLX^_+-8tKMTG3rD)Vhm{3I;* z5AqEx)RH>-kYI-f{?5xrsL&w?Y&x?*%>;Z4;m{Wj1)%42JlxgECohm1rTB__KM}Ml z-W^u!@f<-Z?U|R6fS%FaRS;eq{NB(%Kktw>btaKL>#jGi`ZFLnvz8S^{R?i^g@g#g z>(b;}y7iA>OOH`-FLZ!Y@!f3Y*!`zXro6{Go;QHQt~tQ*S0EnriQp*5u9EAZ+3;z` zO~z{IH1tQKBk6jGd#wV0g}7QrBZF8mzs+>llou0L2+%10RnU z8E|l>0YkdM2QXbcpJJ)-KQ$jPFZK!Ja+Icv+A^f8A29$2#lQ5`Dd`o3!f06X-iWGj z&clZE0wF7%xXF0n>hr;I?1xXIHFZ_pPM|hklM3qEi*=RtFAeG`k4WPWO0!8Tqbusb zn{t+~OiJZ2ELc4k#~uPw@xQb5-$hiRRYJ2%)8%(#w=))r?Pu@)juF#?F*Q@hPF~)dfEuiWGd~e4QmDT@lO& zt2}*O{>=c8vJqT!Uvd^2ZNe_~(c=1t5IX?U3CdZQiQ7?oxZiJhbx&gcRt1s~r6HMn zKE@F_!o;RjNN2382XUgH_;og<-&cWjLSt5i{ON}ZhRE-Yyf1Eql#V%|KZ1D#uVIF{ ze{xR^xNop3UV)R}ZsrRw$t-yoMhQ@qXS+?!2g8upYm?DO7<>J@Cm6JW$IdtsUOHGNtP0 zSGi=h#idk3zo80DcEJl>Z!&IQeGC$chzr0jYGkO_{Z;%>&^(u$pm&C`vS3f~@w$si zpwJrvRp&l&$*I0qlF@tyiLV#mCZ9<*>!g_}MH52{**fpi;lSjYRm`+0P!i{O>?|E* znVLx;*lK)n89is8vK4O&$C7(GG3ke|CG+`MP%b@Vt-B*_Gujk_-;USna%R9cJo0G}G=>%M@Ob!FgBADqT<$-} zG6%V{{n@FDF;&R{g%57SWjy(2ZKGgXOWi-{k?@vig#==^T-g8cnIjA9HRHG_LNJ@^^dIa!Us4jT$fkr#lXw^9euXi$z!|&cg@5=79)Y$)S zw80Iv*iw_MaZi&$8O+bf{cU_~Wf15EU`02{id0(IfklP;J%XGA$RH2oumt5;VM<8V zLe0(e@~|zz{t@QYGfFQ!T3rJ+%Kpl_4v)y`j1l^kWq}G)+I!+mCSe2lYhKOKLqH#N zX^!?*hBn=liCIVZxj^Ac==Vtn)JzC%Aq(1LANQFuJEeTgJ%#3MOav1mFM20jLTu{t zfZBFL<#jB7BbZD3vYGFUdfa&34Muzp_+9&V*1e6L;10qJ>EFbMlAacY{=D+sF$Vz( z#kBd2Q@iRv#~3kzSjuD87Th;p0J*}D4zVP=i=*ih%x9VFE<_e91@tq?HWLFi>S@8I zm;~QDyFwD>=Sg{Xe3o7;xb}1=d|o~KQ&SWkt;|Bzz)4cfks;vBtvBUCC-HLx6UY*F z6m!DH@l_QATf)sqS$+AK(zpCPBRsumZs#N$A!e?P&-BpvWfj%tF?S5zMS(Th`30AeS!1b?nUj{Nm~9R7;_H z!JOl}sWD5UwrT>2{k<`z7%Z@8X7t&Qn7s*hrFsi-&Ghe*w!G|Ot?itCVHN~G z9V&89^w>OMuSykpq85BDPUn|mi2g&=9xALZwlItnt;hWWN^k6n?O>&v@|X|A*a^M3 z6rStamG7v_y(%PK#V=zAvZyb~Ro-E-@y{a@d2tvOzI*yC=7fBT|7L`hMw?v$JfW)i z?mKXOb^uxqj>Xd2Y4vw?oA2^WQ{nf|+#Aehd|}J`j8l}igqx<^qc1F@21^r*sm}0d zRLVu@|P?>6qatL2KWn~eY5)rgfcfl`X~VXI|M*OkW9zsVP)@G4M1{oM)zE?nz{Sou6{8HoOAhuI%F{Vjlw?vp;`L zB65?@Zp6B^J3zB(@B$Q~(f!uA>Ep#-=u^pBi#s-_u=jElX)Qh7#oozEqN(?NWV@{E zD1H{tHhx!v7t^B~?@Ep+1eecC`%K3h1^Ea+B=-R%T_1O)e;G1}Mey|$paUV?$|ww{ z+4aC9Ho0TsH!lSPK7Y3+FTP~3c9W6Efg-@4@CMU8P~*h`2=p}OKx-ZP1~enK3wPBj z8JEw2-!k0aMxU0-<_NHm=>;LGjo=@C&*1fo7;~|=$SRuc-t0cV%g(_kBN5HZz`jA! z?6q`#s@b%>G!iQR5cZ`_HhTsi1WSU6!p?<5eK z9=xF;(cq1@Zl!=4#B2p+v94&Cn);7mStHQSaQH+48p$W%$E|<&UAJmWeGQ^xPK|&* z@_L2t4}eXMe1gv~Zs1oe8{x~W{?@xbEwZ>fl6p1f?cKtNfb`^Q5WARDxafvRLy-c9 zE@Nm9DvZa6!l8NYb{8j+KS zK982dmeOu^N=VM^Wr0I*!C;>$XA)3qwa_%{8l7 zH`q9)={cC+P|#qJ{HQ`x0EQvbrZT`6$n|M3ft-dOe6PL%cWw5MDT4HOF>)FGy@{0D zz71M&xlr@mpHT*Kz+f>s)yN&)YB?49%CUV$gd*JO;;bNjXY$uQKt{#NvUGJ*j5fp5 z3XdA&QTR>yROS83s}u>A1YA)~ab(tpe4h9s5|T>+Hx?cDatD|fXvD^BUDL+s&)1DI z?lbf$S>V~+0W7V#Y5(k;bLrlQfJhFmZ;g7>V=l_Zbvz3RTG!nAwAZfH4z1$yQLSNy z5NYx0ix>DPoE(DnhELSP`fTqAZz5sZvFV zD=1s4CpMNi9NDgs5z?jv6o`Vw3<80t5&ULkQXTnen}Se&2uI z&&RD5;w<;su5+F1l$RMef1?*I_!0)&x1L@Vx|y?~;5AUoJd%uaMCMezu59Ji$?^!b z*;b3w#z#kfesprH((%ilPEOU7%vY?G5;RIx`pM`{Nf;KTHQc}V7eO3;$O?!w{xzfI zHT~e2)a2zK7+L3+4D(nfxqO#Yp8pUNFc7>BvEtDj*+VUtiZfG?tw?@1C9-Rm$SzdHC$S7 zh`{Y_k%A=5jpH0N8|?lBUBseZVDBKF|Gq`660`)h?iB=OioTF@i=W(ckr zIAnU*10|;ygmKmYrg>r^L>>*<%bIND@CBt>@Xuzw-VC2>T3!7iWygdP5Zn2?`2{!$ z_yBRf0(UW`EUyS82L`HI@f-2W>1US%ya-4lYz(dL8bFNN5}PC*SU|S5snT?;{E(@Q zYe%&0Y@+Ra=fZf}>I_bcvmig493!>-p)Jc{8|0}M5|1)KJ|rBG_|U5^cC2_LppSt% zNh%ZFw@mL)FDL{f6mudE)kPVb?trtFMPJ?C@F0DebFQP=iwV8{XLe%XPIc30WntRa z0F{LK>aqyJyK51n_FgApjE;1aS0C zv%ncO=u59Y@cHZCU1t^7@NxHk8lcy&p27swNY8;nnWzn1+(<@e=!w?l)}bA9@eDIK zHoi1|xFo-ExiI9K@;p#smpYFs1cdX4F8p%v`}A)Je*n1zmTEZrG&nY3=YZ~iI|oAH z8GN-KJp($HdVyhm-LG&=rU_>3HeG!bC}?Efh%v*AA=bT-`ph$#tU(45xro}B=Z}yp zz_}Y!K@*rtKS{@H$p@?4GMnSx|b?_?1Qp8Eq%7dWgF zrkT}w*iIwf@JPXl@J`c1=?6q*oKfuf;`3w0wB;0|lOE{RtQA!y<>%d=^~Q%^e_sMg z-%Ij8c8qkDuZfJ&Lfu+tA*z<|?vFh+;NL`PS^-H|TvqZg&WcPWMg{uO5YUfy2l~;n zZe!$`%Z3f4>zfpxr=*)093O3O#o}R&J-K2l@~QvpLIk`eX;tWj@r9?8f4gK=0*r^n zGFh#IUEemOgYT(;N09=&0>vTn%f`9C*Css*bA8l3oz-;R4U{p!MBOqh-Mn*?D+~N< zD@e%l#>`|Lpzm@wNvK=?6Z*pAjkB`oBCr>B@oD

    lD-WvD?HQ$ZXaK@I9e)fw4vl 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 c7 zlQP=5p|oYGniTlu0I9)Xun`gmRbx=I>^kNv(iz%!u_^8*GcVvg6DDy5hRcg=#=0nOr~7aXY;cZ>u&EA}8TkIm|1*9pJ|&+Df;g3($x?TrjAG6o(`4=K-^*l~2H&|6pA(#wYh!&$ihXJ#@ZNSpb-T zzqpvno7i~qapZK8OIb-s(Bli0l^G)~KDC`5c{r}goaaGKiFY=rKiNv_LvP;QGetCt z2O;qKiCUpbvm```S*)|hENMY+mFZI7fMq4U%mk1Z$NPVnAVPo;wbD_n{Ey|fy4B8k zxQ!ULs6-QX2n-yO_Dms)ab6#8;Fx0kvVo0I!38B&1e!UMY z5xcR*sK_G+7*onvUu$gbOhUf@k3$1OL_3?_Lj0&BBnEh zJ;I`+A5H-#89aLal$`y_^t<3hI?zC_yB&&={r*7;9`h+JU@n5T?i=lilaA%fmwyxJ zjTY|*0)Espt~$jvO*G3ocmS>0&jx2qiDR+U(??nk zgE+j{P&*2G-i{(^L^8re6Tq)sI*wQ!=6zC<02{Cd3uTItleFXa-%^v4>Np}j*u0&3 z`tjDrAso1zutbd>zYcG7skt}@e#^cXO>OCWUc?g_);w@)tB9hH*mAK7u@0t*f(Bbm z^+icT8oT?Hr||$65FDHgGoC0QXMysaElQn(v**i#4-|eV^_V`_51_q9$}VA7GR4C` z?+CqW9&JitF=D#5=rZ)u3n85t8hVN%lWRRCZE^P3qNGSwns<_!UdrF45#P=(uaO+t zKXjq<9EHt&OIX#1m&qwr9my0 znPFIi{~8th+f;5h6F#P}>a2JMw!?+HZXg<-J;rd26E+GVVm$XD85 zdwes#*5oDvJ$#TReI4gX!35PP{W1CoQlS5e<>yMa(2G0)uwdIP9cLW`(vnH8=rV=AF zRXaA0Y)EM(nP^%@WH?E09iyjSRQCstoD#dlTkiB?>b=<%sGOWsP7I#}&B@EpJ1dF_GfO+d zEDURtLJlicW``vR+n{bqyx2FjF6E8Yw_GsAEERKgiaTh`Q)h2xWG=0xy)9aYLht*s zu1=(oF-O?-c)R!Gpd*LmT49sFVry*eG~1ox@tOB*PE+p5rBw3EssEymS?bap=DVhjm?FIWyBwu`1c@Qy$sC1RR61 z`F#yVYdiTT(x#gEiFYw0`e>MTn)YU@NbD14eJ_gs{?5~pW6M!yC?-l>t``tA#GyJ;%@uid26n$2;bPpM4k z-B4Gha)e;R705(+>VG`>xmX%gK-_G2UG8pz-avjaL0@Ol3wVbzeJh-h-@y2V5EMOB zaLz1j6s|n^kzBx=yzK}%CV^0(P9-O*BD9&`>peb#0ltPy=wl2Ak*Ry@bJo+57X}dR zaO|s>1EP3A`((&(a1bR`r7chO*ozkBf+IQPbkiy6}9c$RT{ZrNE6dl$f2+`pp0hU1>6C&_P} z7aLOu(=n!GV?0A+1G@Zp5|+m@N88wy^cE>@WbfwJC2?M|%dd`U^prce37`cs)tPxy(H2amS0HD*2V{6GHshX^THu$HwIWWGm&)-N7{%5Q}a zw`*RMZ&3h;nU+IW+t7M{H1|EX9RYbDJ3;+X;Y!T@Z^7+DWMEOJQa^T%I|Boi+$5>= zVeeZT;~SbgSQxf8xr=ggIDYj#*s`i2i;?&)=g*Ls-L)=BxF*;f#YSCB(Gd~x)Wo@*+w;S{o2&KJ1sQQPJo;A0 z7JGybk~C!|LI5qXW5C_6toMj*z%z&Jod=!4%D^Mu2+X_wWXLZ>#DA*W;*s2^aMg%~ zPuSmJ=fM_BR`^1r^ALf6?lod%jS|X|G2ySL3Y;&j9U`i(jG6x+s&z>l<|+(d{3by- zR66J>B&heL5cErp9Ji+tmcZTBs!@hrm=(Rr4XqoBytF0gQfOeK*Sw}1 zS-Ee5zB|tByIJNBpYojQ4-4-ZJ$0}$#65{BB@7$unV;P}aYO!zo$mzYD{xx+2mGtV z)h(07rQwmp)5tSM1w0~0;j52I$j*_Ze){My5)^kke(!41DiUxUQo2A`eDEe&sx_yj z16i>)4gL=Dfr^#J{}9d{sqMr)j2uA+rp(gLbHrzbr)$|wB$4CG$VM?Ih}ZDta+B-y zBI*xQ_dv0b-o8(-5i{B0`Pe$}?ht&5g*d^JV3bM!iVVMJ{BR#$aWA-*HOPyjh!ymy zbYRJI6{6@?PxhtkS^Xd-S9~~oYfm&a!mkoUV4<)a-lFnJ)$tv?_P*5NZEwJ=)Y;-J zz%S&4b3>TaqTev)7r*C&1iBILl6Q(n>zGArGT(03;aO@KZ-o4etlEkYq4V%*D^(r$ zRmPFQbw___m|TnVlKCbjFC6}sU?Im_38Ac5?rq!+$bv0!Zl!;67BN1pFGG%Vq&e{8 z5uuZkFQVz%#?$UfbKi;&95GoZpE$r*?Z}Fkh%Uk>cfk(aep%&NdgE)X4|< ztULHQ+#`Qj<(Pey04O)39j0s7dX(oaNBKVPrR2-x`2(o}Vhv5zgeIy%CGOrQn6O8>) zU=UUw6m+_C5)U~|FILYqq};B-zZUB#>MqSfveP7W0M*dL5xS{;&Xbzg*Rr0W)F%M- zOZa%J0b!M-(YU>Qw+|Ux-pADYt7kUi4v1;3jz4eA98P7ge>8zvXc5J5$p6cmNlS>s zk8Z$F31ECe=#&60h;dW?2<`(*Z!-gVAj#%no8ZQu!Tq>~d_nsTf18Zha=-O2{SZAs zcwc3~k~(&IDV)Lubd>rL`|EbE_@5cYS6e-Zr|@Hv-Wm`L!}PFj-)|V8JW->qw7|?~ z!c~&nrK8U`M9;y>FvbbaWZk$Sq~Wygee#JdNls2JYuB$XXOKxoifp598$Mf84mbJ$ zMA%wYKT|>a#Q%2NP>SvrJVE(3{8SNqcJvtt!z4w_axoj-6K@_x>d2pcH13nXq&eJr zab`^UN!mF<$RcIoZ(Q%(!x)>G#}nzB&OGSnPmhN3Nk+f2^KX<7>rCq{c;P_S zN1`f-Zy%DfO~1}~YYuYFT*92iuwghyx7`8AMk}E#8=rCPuh+}LQ(nJjNhb)+LOqC> zRx?tbYw5idU%_5I{Bo;gozJ@yu>|wFQ9zH9wiI_3J*2`9*c`L_adDu^A`cSU7o140 z9lsVVdLPX$r(5N&@wmwcD}n%g81NLx|*TyxLcw>-Z<8%k;onRMsmbP@&t2})E?2Nq+ z{lSoh+xsv)7^M2_ZDM3kpn2zs#HaYoHt+{ALzl~S2-?2U4-U)xLxl@Gnh$_-D?AEe zh-(-oW;1lfHTfNo)hoA}gpV76C^5KQK54}xMeu8_uHrNXQf83He;+Ql_@6{nbo`xo zNfrB3rSXd7tGjXm*cV^|VYsF56`H&%CRxZLGIwK^xqObQ37U_#r5k*rgs z*amkBONvKoyTQO#ma+Yp`am^(5T$EgThkxyAmY0)4=T0H`~y}~0Z9m8N&UZDnZ_!v z3&4pil#bAaGV&|X(ysx&2IzUOc1@=KWo&vGe4dTf9|miL;3um(?I=<~7ah4q>Luv2 z;6V`f{Uk)}#{mauZIFtT(@W{{ihCI(mfvK2GfFnvmDW(uFEgqDIONqhH6n8@u**N| z+vVMIies6eJt@+J^t->sOG5DsIQZ{6+rKfA5zk-Or${z1bgw|xy8q-YstdhhBkm8= zh*{Hs!MkoB29Ev*)82e-FjGAf(1(d8?$GG~kYU4b?ZP)Z25|m*uZTR4gO@601z_s-nbRen^~t2N2_^p>PL?jj5MVQ3 z;7(CoSM1s&uN8SaYuRUkjQyHP5gnRn#-0k^*%97Gs__3v@=o2cNRiVplN^jGLGJJ+ zngGwhJAJ-4?uFwkcN#CF_;Z z5zE>=DEAb7eIG0iR?SrM7X1Nu)V;c)r@?z3_KaDJsGOzbH$kXf?nTlI9!d8{^h~wc z0-MXs?DLX>&HcpTJVW7@nRMw{@*BV|b1~UpwP|}s+@ltw8jHv6qm7!esq&%fUpSpx zO2)++r>pvpC(Ex5F^(?;d$t=*2d8JMt6v*@C20HVu#d?KJT0lrrAel>gTbkSOCe-y z|BL?qeI)&a_KJWh6S2s^8y+SPtbNZ$tI*BBX8;t8eYCbsKMNc~Of<1(9sLr=mS86` zZXnL-$F3ckTu1AdMnc#b7&~CzE>^|XG`AEGpP-Q{>@6_CHoroL(b*<6MT!m~KKzWm zpL`tJ4iZ>E2l(+G{U2Xk*#71n9JFFTNKOID|cuD6xfo~+k{21xWf>?HV5#}$$K z*(%#+(f1zwi_5YhOZKSpjsl11LojN$KQ>UGZFJ2Ay$a)zxbH6)Ny6$TJR|9CVAB9T zO6a|azb04KocH;*9&$-4*R4;y~lE&k0}H1!=%ZSlL|0JE7V0 z#I`;Qr9RToZk}ek_*#fI3_2V+*O8IY5&sRhrbl%{rVfZ;Jl{F_>wf7Eu9kS$g0#}` zbtn0?L)izSRM#D@1Z4yt4rlZZw5OF*hU@9lP5u)f=|V&T4qK<(x4mvZb1V2)Fap{8 z<{8iQY71yiO7|S(S+SZK<$XQ^ZJ6++XZ>hM)vUM`#R9|ZT4AZBDtWU{`#H?Bun zOzmT;Vx8#+PaY#*9$0Xtd}RJ`)5CyNiQR|H$rN)oDtA>gn(XL5HV;4NEm-T|Znb{T zdtaw^+xRN-%IgQk8~itwC&Gckrs3Y6Wem>C5#|J)oR{PuWk`N*=?Ct$4SfH>Y}%~< z`sX;FFMkV?+qQ6;0dOY$BqOK3`7km|kAF74`3udMcYJ{g?k)SIKqfGi`yji~63wom z&orKC+gV^ru^fN<8+KP}+DSlHgHvzz#ai5e<&XkyTME#*9}m1X)6O9&AdUF+x`-rlYO<%JYswwggF&+3 z5F|h(x^3@(Q}SJtLHrDsu&l) ztVkqV8SlR7y5bbxnK}UvulE?Q{S~pg%9lO5YRY+xeT>%)r-P2bm0xS0Sbj!9(CfIW zmx+iMAYxi=qBrv{AeA4jTmLtlYo$1AS&0T?f6+Fi=(f}tIS5ActwiYNMgJBopv+gKU{>g$68G68!%v&v>d zswRV_`0gQgCS;T09sjqn=B2?fFSRHL-OW)D!JzbC*vIKaTLOgN zy=Du4C8yvxKpiS|djZdxH8=kW#cmzgGuNS6Q^bqt>c31u^TZ|mBB_B}NQD>RDG%GZ z-QQC|qvVOsJ6(E*{mWMw{`X(o*H1FHpb!*W2tbI8cLzRoIj^E|4}ksi~#gB1=rb#vg#pF-uyYy;Sm19C34#|Dp^5k;q!k z@}iz}^&nc06OVMwm*S~r8X}!CnBBK`L!8SS{c)C;1{4U8)SJ6MGvb%ON?aUGKocCJ zl&7=LPp-=IpNe4urE75jld(h*b|V%*j+b=FG#DYJmUCge<75*2D90RWHd}iLUpp+T z^h?jNSdrFA7-K-ye4!S*(*4HwGzhOTzT3oT5r#Rv;;uePv6t%mpAuF{u#+o59U~QX z*2aB@6|WRit|1`v-?kCd$piNO(EhA_SD^S*yaqA*3Yer}z*Dzs`^WXk=ru4cl_<4C z+y-?L!}`hHfx`%4*z^RX4J3yKk3^lcX1CF73vnLxr0c!w5sY?YGwP|WSpKhUI_uQq z{-0#-uSemm>5^q6(5N-DH~%6Nexy?M^_hAos)*sOaM6j4Fd;3ho(6*K^4O)W%ITZmH| zTg=EiEN2Z!PXFjTQ!$~r9C+$L7}Az2mS&qM$47{D_-A9!S3YYEdnVmd(#1EB2GN!S z(`kg$^c zzv&MRyjD^s#ZRmp&6+Eq#M-Kfe4WlNJ^S|*N?Qan8F3p9h)2uVSGLB0Q3d$ggf^Az z;9trW){al+fOYv==HLza_z$fG`aWm9TKtKs+U{oz&Ct>rr~M2Wkuib7vc^Bu+X%&_gSnr zf6C4JpBZ{Yt;8F4ImJdO@R^{&zW?z!1`~!|aQirZacbn5_s-ixH9n`4cmYNopAFn$ z1+#$)Z^IYPU6`SKio$P?XGdcKBkU4Tg7iaKnuQM*)?BAVn53vWJAGSC1x!+vUUv9RL#Eq1>nRlZZJEcRy3)*P%a*OAodeG8)(tPGcQUGkuFsCt7Az5DyrYeWTn6xoA}1`1_MemmP2zbO_Ux36&E^>Hle;Ndd%6

    Ir9&HM_w_*3e#XH)1)Urg8qZx9Q$T!uf&CwbNvT@_8+IrW=@g zc53VDz^C){g(fvw;A5j^=}T-ZRzEgRQ%fVm2SyA@HJ~Avyy#fK`5p9^|IDc6um{sq z(}>w+OMTr93)Cne>&&ODn_AC@WBVb7cHDmhbzPSdg*srqS8~TU*Pt7(P-_oh=bA2| zoYxvCpTbBiutfyr7Vst{mY*`bjpDysR<;?T<|IS#1?G3i)cp5K!UuF)u@t|%$vrtk zhd#%^CxfSX>*09CYdIi;_o8W?h1|s9neN6hxMIWN}`l!kQePQ%d2;vw-1p2ID+{c19&pB7R42KU6!o# z?dqdvPO&k=o+ogZfE7@H$jNUuF18x$O zs6J7tCo8@ht;OF6xkTeN`9xA}2`se)fbUjAG8Xh|*-Fa`+7FM_lnYhP^H0|3%@ui% zWNEb0;_*eDCe=Wcu=?&~r}SMU$jHd;x8tr3p2-l%O(2=*o{-}UH`E0iL{i~Yg9zI5 z+C>*13UHsDsoXCg)oj#-gc$_XgN(5>ZOn5TQ;Ndh?9V?qKw=cZ{6S%!F`GmFUXdX& zfP&GjV3)W740THjlfMB#T5QL*fCK$SaoHb6N=Y$Pq7I`yI!XJ~Yq`-1li6K*JipzT z^U_SX}fBEs=yeV!)j2Y5CK^k98HD%EbDqohuS`a&L=94b_lWg!h_w99>D^5jELQNAWI7` zW17ECWREgiiL-H6be_<8GC{mvv-@$~vux-2DWv@zH8IQ0i3W9+ub;?5LEfHK5si8J zKzJh)(7`XER1Ps;I?s_CvgnGObn=Av89v}nEIWzx)}B=`%V}vDAQGROi8tdbRM<$? zxdib=;#}R$<=|ZlGayMj&72Yo$&|Z#kg6(+n8ki3(bltD_OP*Aef5Gbg=GR(5ffTR zy3zVOkT?j-Kt7q3qx4UjCYTeMlhAsB-|VxfvS$D?r3faGr@&#nAQ^8aNFkuuNBU4bW74@qg<^h0hE17$=2^dXK#Yypz zZW;qVir-^~M_+pf>J-q(q{D>DRQD$KXJ`PZzj~;ZEj9-?s`+Rd2&|w0DWb-ilgN@; z%s)por`2^U;UV&I+&35#8P9_p z{XJI7bug|(w+$j-$p*gU43MM1i7RHiG3SgUz18}p2Gmn!8>tbrT%*B?Ltx~Syp~>@?pHM1t-!Or~|L_IO?8V zYGIdAcO0gS7-)rhsE`a)?I(CcVv%hlka2cV-4%s`7g;;tmp(UL|5wjxAW^2KUv{$w z14idTW%a+d)2!Jm`L&y4?->YYEx`CgUo>+9se;Gt^W@|wMGK6?LFIWOLCelU=6ZRv#(WmOQ_$M(rKJ0D zI8V+IO&NfFM9C9X#N9KJheW2#*CjW?w^>AOmon%p5_t%%XcTc6vi9nT&%RNx{|U73 z4LlZPpn0Zg$Eo(;(C1tzzL1EBTxhUV#DA-jLj=*!_d0%g2lF@oGXoZCeO}Of^2fMy zjM4B=nbLEjbK8-=sb3lzFvL2AeMZG@^qXV*XT7ijt}5C%+QI^c;sAvpCJYKT;>^v`ms&oElP7HPTSV{0F*o2OsFY+#5?mLX&_90TNpU51M- zek8&AbqThsR}N_oO=ATv`Lj(*d3(xD2g1V3yurtdL#PznY3ZS08EcFm^keDnA{#jX zhIxBLmvjBms$?jiZ(N_HSnZy}bvcYKdKVjUYq!eoa5q?7io>3yK%EK_*<_U_DVhs= z8|Lp34U(=xBkWSN4kVnl>hMOjXKR|Fg=C+S*E-->e@zpjURCowI0j!jMWQt%kw6RIcecdGtAO8Rj=lBC zeocg1HN)oCqt`Ylmu!%LLecznrz-Ybk?s4~jF1QS;l7}&rf|E;yawLZWIQhPMCSd0 zlqQhZ%E&8kU&E07^#Xf**<-t0nik%wvvC%@~;fJ)gJWgf;~_t;GV7Ns@V8%CFCWn0+bVTDCmx|P}Hwy z0xewAA%COdGFLca8)(QWK5CS8kBH~cYzEM9bvN^ZqG-QLp9P+j@Le=fs}xRfi@-eb z1QMi3sGIB1)3m$uPVUPlQudsXIUqhu#X>JUQF+Xi-h9B^O*Z&>8|1Rs!us5Ac90@1 zY#AJ0$F2RZjy@MGq3$i==E|OSNPtT{MPf^|czt}>f!wSkgZ=C0uHm=+@@QzPJR*C2 zJf5n2ZK%lGRehnS!|!H2;;{{f0iv@(enSIQajZ1Vqj1{~7zTe1zvME5DaGZ}HD;Z5 zbOR^dCS?Cr7YhOlG!iswc@NRzG|{dx!5V>CuLPk~Tlpw#1vJ(lC}x?Y6dD z*v7l5E2uI@2~J~f3rP-NrKuB)?r*`|}k0e!gXim_j{pvScv0r!?N~Qpw9HFZk5dGlK%0 zlcKXBa9`IQ4h7Nh7J@N1AL$Za;w^veuFr2n&-vx9lyr2&n{*N_;H?818ikLiIm_Tn zoVk>@{-#pBk4&kH#BHn*dFTN17@pKdxpoq;PD*(JTnrn3Z3!rU=o=sJnp;FM zgQ5(^8ecO)MEpT4F*)Ot2%5!b>l>|IRO=4B)>4d<(>+lqW1X<0DrC z6yA-_eKGO0nsj>QE@vECgaZ^SdhnRso6U{CGtZI+sPx?$%pYT-w-15*y!LupDo-G|@T|BhZCpxjDy)C|V~Bx{AHd1*yK&*QPQ(~viUQbTt_ zadMfgh%h1#7(9)--vM53O!JF5znRR1x8lCEey3Ud;Ob2O=auPS4U9^$nBjVwo$euv z)N5uN9sHh-o%rogdpyPcwY64*U@)Bp4JGS5UzaOro#1UKp>6=Y@EOn@<`7o#kNwz+ zM><5t{xhS4-PecRZ5bGm(2%-3G!v(`hdEbju%9m2mU1q|CT9J@pJ||h1(3FZ8jch7 z$Rn-)Ugf3`Z(;sODnb@$KIQ7p31>%9(&s(}S%a4E?ZZ5u7W()>}UwFRmREv)N z?Y0y2$G&(K;Mf9QhVLdY=KY%G`);6*KVtFiRUD;PdoY`(%nO3kA*czT%~(E(5T}03 z*!s}BwZeQYL*Fxn%UOeFjj+akO?#PRU&-^zyy0ukn||Pvf#CE3Z)@AA6&Lz2L!XJ< zfWnL?di2zY?%dChOMs(Y$utjuLBIFr;hsMU_3AIr$ux(>=p~Svc;_?$Egpej3~wSmHcX_$CZN4mFL%vVjYBAt(z6*u5FQW z^Z)vxpl4a>{09Z4sGA0p|9rIkdQ|;Z34hMmdtaj21ZL-l`)JTRp=D!+>$^df@NCBF zJ1>0voqv8mvD~rdL;1RO-WzjW29P!;{uO8w4P=0qcJ4xkQ*{B+bGI>4PrvAK|I7}& zc1VB`c5(PXVgz)0tg|q}G*`v`LLcEoQc_RTu*JK)-Yfoj#9vBWIjYKG)3;88S2@@M2>ovxJq3 z1B%-|^7iwmLgS=sLDzD`>lMmwj(LixK)-blVP(v?=ClI$H3Dp;Zj3y;ce#u?swMdpbN-~5BJaV{X^9M6v+x3_G^}EghbS8{hi7Zs1jQDE{xDbgI&!|#}G(wh?r_uYW#eGRh z)z`^Ff6+VqMl-z7?EI>&(0#UzaIuc(Wj2F(w8|5=o~34^fasWc!Rtr1<)0agQU(T` zo$dpZ>?MbYr%bV z$go7PDW|aX7oqcc#^RS(A5?)cL)0k0;(2Vy7IzLOja4g4%3vwC=Rn4iIF=#*(XwiX%XGO{ZgYa9e2xo_ssq9G0!D~;{KMy&5QpuQ7Tk0>vOzDC8@;1bF5Y~m) zIS+a7$}&tb?md;Rq$8nF=N=!&z4zqaNWeFA_{5(%YW(Vxc8M*Cx8P1v}=*( zL|%B|7FpjTAn-{2x#Q%q59|P&}RiK zfR?13b4DMATP$GoIhWSquolos@eo4&&yiy6j*1;H|MjSr_~CQDSuYbT{|n;ZlUTK> zlZVbYegyCkakCZJvSu7p<7sNX8~R*(su3eC9GW!?l#OTF&s6F9Sq1A7dP6iPEzED% zc;uhys}@v?`e`-VlbZW;tnEkg0|vtT>K$k<9`TdM!wY^8YAlC?-Fr z{4--_$@MY*jYQ+@C_d<-%Y#gYA4CE++r&SGCz##f*XzKk_wM~?Mt%KbORN`bLT#jY zJr(DQndsb{uf_G2KYSfen`tx_NdMbmU#5!UaAyM=ZWRBbq^xbjy1K+2I8KHlONF7CS- zrVY090>G)|XblRDrX{0x5dg7=e1b1it^4Nmp8*#HXevGXuee&NuGRSdl3F4efYtr{vHps->_B7g;;H4x#5#zzIPXojs zA*Z6iw$IUN-Nad5b0SrS7w~*%SN1niake30&J)!&-)@T$Ph_z}9R|8puBoDiNdVLm zt&cOto0C}&YoD&-Gx6Y$pU-l6je>c}Zp(yV)f-J8`9R0hk7c%h9)wlEX@7kkTg3EC z^m^;FabYGlxnP0LDMnU-DMV;TO>5Dn9{fKkmEmf}rS(4jL!|FcF_xB;LL`qNCGG=Y zIdw;$pTD_;u1bx-$RoHnZ?U;+!_FLQz7cSON6T)*%-t)<8$eqz9vZ(7@*iMv4xnAqQdJh2*$7H7ug``OsLT(v zb?@9rKN>6!rIAK8`rJO+qQO|4;U46O`0~{4GWxdr-4txsFPXz;esi3&|b88i6Zo1w+y$F>YC1ci3E{*4)K3IRiAFTW9=cuU(= zoOa>P2QCvF>(c9#f=GqsBU1{ppxsen^+^D0WMIoHr!ISwm^#^rF_n1)e-S*lCL4~X z|H-vQ{PpG*{N54woBz!Ct&aZ+rql9=kt*LmMvX_*WkcjYMsr>Rvx8e|TONf$60zb? z6^NOC8)Py8{SNf0K+Qro319SsV0)F$!fFTXbkjv!BO9Fir%L8mgT{2r0r({;l8|>q z(r!iS0$WMA#PV|+W<8OtljMTD=><%|$SnljnTlt7D4ziCs z3gpq2!bOF+?uqG(^1`gP4*>m#bh-D(Eo0 z^_h}SBu66A9oTDSwka>##PkGFZ+d5BKzF9cw zyY%89JaI#8^bFvk2XFH$Sig^~%4d-8?K&xJZ#By;>^Yz0fv?Vpk5wtT?I&wu#*w#L*>|4D zRtf255FNc>k|YqfUiT;5EEP*U@ca~ZQX$tQ&q$Z ziQ24Vi}BAgzIo6}n(1vtdSw?Wd(DsR#iyT87qVTn9R#sJXo;ql6ZLWB4 zm*P<@*woCt7qO`3^rJ2ImE^js8L38pkE~2y(V~J`JQw-FKY!nB7vDGmZEc6I53K*S zciMvp@1}&YugqVy{ygq`cm@L`r!Nh*K-ZQ(1i|c z?}Y2E&%WYoJ`-s8S~UHWaP=U?HYK9<*Vl1_?diLP%Pvk_3j>V1+U;At+SaPeg{cyRbXBsVl$MOhdxd)V7aV^m8N;GNFdFU?C^mw`5 zQBgR!0x+u_0I9Z2aG0lYM6*#lc0X*~ywhJ?O+Wt`aUB0{?0qCYRKNqtD99bpFT_iY zzJR$4IR{M~iSP_ZOex zqK!Rq;=<}e?^>#p@hCLTRO9(r7u+~|$x-ZL)o8K_8r;ycfN9oM@}$ND`!Wsxz7)OX zC~a91TNth+L4p0iz;NHi^tI)*Bq*9V$pr7&XUZIjMt88eYce)tcgYKliv zdG(auFCLBsL@8630YHRzI<6->(YuIFD+>q8ouA+<(q_WvDWXqEv-84?^~S4z52Qr! zd}j5;y2hk$>t6mNDKb71eUwNvf3=|RaqPXMsT0*EKy@<0MAdw-=lA;#IF+d)vyCe} z@vfpT0bb>*(e`fGv$>uwY_n%F&oNm=2lF_k$yttYN`#9fkPTh3MD462G2=2EbUs6(r7qv_QL~jbu8*1+}^h^G>70yV%+2lU@!&TFm<; zmVY}4HL;bc@hiNkumh7JL=UfG=wD6l6-Q1!;gWdTa%JT`N`Xka%OjNrC~OEO*{`pQ z+g+2L=Kz4+`l62!=w)e7-J1P1`Q^zm2*^)_dpi7@YW^~YTlRH5OD$Jq+-UH5UnB)C z$W9aK*H!e(WNg?9-)9VvfI}qK-a~)M3@%kd#w9M%-EdWn@ALo;q0B}|w~Km8Tt#HF z0$`G?{a-bXihR!jybe#cD2?Xhm!n47H&E3!Q)aCakOi?+6%Ft=@xh{qw|S^U>;<1s zEzZ5;)}8I;Xn?1L&$fW1{%CFasx6NuucZWgU!xgrrt)<-4RcCMTsIQkE28ibT_?XJ zW8(w=2O*%{r@W`tqg(j0_5}BXr4K{;qk>igzdA3nR3QN5O&%)b;@U~)Rn_MuyY4TU zZWi9r%IN#g)<3@%3GiFQQX-qp4mXW9gnE;r{Msn|wqo(X5!6SNs(|_1B;s#nl#+3q z;L|b<&p8(4AZ!LGJP_j!4y$KkkiY`n6k%x7?+`?K!_^qy-+x?R*|T=ASAVg-w7yb? zQ=z3M;UU3jeN92%)Z&4@p=A*HG+Y#&IgixaZ4#?>{rEYbBV0{I&A>J=LW0syMF1up z6Ra~nVTD6C{_0@rx-@d&Wg`gIF>WMk(T=6(Wy*pkm+!bKHZBLh zLvI6H09aThE3glQmhc8)(DRmk%%^3-0MLIo0v0!m_pDzInu%4a+cZZOF~FDREyor? zpL+T?iT$ul&VEh3j6=Fab3we(J6OqSx;%;rn2ET(10L;_3}~vAgmX9Y1bs+7+30GK z-1iVRQL>RQlA6>* zDCwi{E9?{zQP6qp5gBRunz)b0V2>SPoHrZp|5fK?k)pUmFSh1}|CLE^7@}wj-bL9{ zT|^-NW@_5EkC5%bJ+_CIzDZ}3x^HzRRi;PRbQrYg#f#Rr)VZ6Xn>>?j&%dycf-QIE zpq6AbUM733Bz=9^)BNcZzC8PE?vB2{VUWP`;nreOJwzOi;;dOE9(D<<;=YG~5Dio{UV-B$8Q>mlo=KFTWz|JQ+!m~nDz)!M3lA)$VsIIF*PfT=rN%A0 zlR!HItsfBQ#_>)Ga_y1-keGBSC#G694If ze*G@PDwRc_pFuMAgI@ovP!W)pCAnuQXV-T>_9^OjlArOaC^?edbYwN$sKjXLML_>} zLV>|A!pg-vC#dCfZ&ecoV?KqXQXNl{E#-WbQ3?sHlUF}aICF+<$xHl3N%;;{Ng(Z zfTOf~x`!gGQVe=oMgBLYvHuM@Zl+6GEr7x9n@6-jp`eG+C9)CdAW1;U(@EaumRXq( zN?83wy2f=}xSOhk{Shas0iE$+SOG%s?rYim!TmK#ke&uzv8t*W|_5fpk^# z!OY}q+{Q+XZx52Qn~pw4lqu`EwW;38Tb_I;JGwf3O?60lf?TGt@x`tu0Mw$S1A~G{??-M?{#}|6T4X78KsHq3(c7uzMIbcqZ z3Li^lLXmPEA%e5S z-W4!t#riPkr37e5U2gX72LQvIhE)5UQ(K*9SkU|NuvC#$#FCSR^~9DN;Va(Y9F`Co zjiTZpgb>6LQ)|VJWqCvSE8$X3ardnTY^fiOuG&1;=Q|B?+AyC0J8b}Sf#^y2gN^?0 zF8CO^FM1GZ5m}#h1?rMAJ$HGH##dPnr6%gVgN5p+b#-V12_pEPs*d}J6h4&_1yirI zz&VDWFV|jKh8PW^yus z2SM{9ERc}+TenF@c7_|jgk!uZp(@@*nF~m)TFLVYRJ(L7wFc78p zt?7H%_N;Pdw_8DlDe#~WD31)74M|W*+ZIFXot3=^cG~#bC-W~WR=kiCdtoa=d7bO^ zHVp^Mv&9({%lEjzXBJlGGbhDKLOd7B$-0=p_mKNtBa6q(Ell&O^1negB+wVaACpn} zgeUcyV^}}mksbE|OjwfGf0PDPI8-d31L~8s#^__pic5y-+BB;4-lhFjWqw$9xgs)# z8D5l@81$ir6u^>UJ2pHzuuq1sG&@iOfTa2lrT6HRnQYT*$0@~x(@x%=>k4k*p9ZhA ztH9{lx6_3OiB>`L0(q&=L*wo_Q%ZG!o**Ob*Y{G^ z@^?BEgp~vRtPAUZmc02rEuPN)j}A3o?vAQ=$*}pMKD`J57MxX_4v*te0Srr}g5s0i zZ#GYGd>492zS5fCh-;I=4{FAKr&IDYY9=t!?v|h5Ez@ z=bR`C=Sj_k@>5lwL7q4$R>}q57S)?*+ZvJmW_f76yb^`p%8Lc4lXl~=nt-@( zVsGyN3$?Z4A)_y(>XDxjr>HmsQTuR-bhYQU~7VmXDh-}M9l@_OS;4N)3M0?U5S3>KM#?8 z;HvO2YUL6KmN|jlg%SqS4!xy0UR0AOZ#bJ4!XKuoLxYpOpl>&l$_9V$4RaFP0!qRf zKWFEgui%p*P~lB3$!Y9+zQioO9U*6w$daN5y@SH*QynIi`)eM*FSqy$6v<)m>xb3B z`}NAq-_j1B#zR{X;vB>rD`%(Id{79V12J}QTam{al( z1{ohgGC#<#4=kv;CfW){Dm~82K&bDY&C8SN$y4#VQ4Wh_9v5%FjtB=6*Q7)JWPw?z zoRXJ*NXd?d=Ezom^8P%=JW#4n%?NquONXDH+yt}qHC~!fJ#&y6(JU+o0+blvFbXQ} zIOnfx&Y)hVo6_nW(aR?)GoZiawC{V$6a43{=+4+yv6~9N0~45$$?-|0h{clfWV}Y^ zd9&l$!9_ih3XiMVVuiW+D$!?3f&&Mw;Q3%K0}b_v^Px92qS-Qv5dW+_aNcVKRM=Lq z{OyF#JapxIpLxc0u0T68=HQSsC)&(IYZ{)}Md0-*71stjqGdGF^A!k*uf`KUgzcPK z4-8-hb4p6IPor)z<2N6k*;8=5>^{8WDO@hW0z6@IXZ{?CjbFCi@^%uq9w z$`$m<#D3;z&ed)EdhOs7XYl}LMI4WK6>KWDHxb*HfwnduTv_6vslpTqxJybvcf~m#x zquF^lV6@SpXR$M!EBi!#7PmiP6QRZ=AE&04*Og_}2m(8%Kt$^SX$%JOk%rV_J?BVV z>B_2C_MJ}jfrNi%Y~h(kpSN2R!n^NXi*EbxKQj)$-MbUUws9e*o$$s-Us|ocK zm3&`jaJC<@yqzEAgRt0I?dZ)1QOSDsq0o=_)4^@Ko~o6g8o50CX>H7Knm_(na~dSM z2fm9Gh)d78c3=W>Lk3h4@3m9D_Md~Q)y@nshSTb#kN^IBT)kXut;Vn3s0F_j zf4G)f@3G!+(;d5KXo%;-8ilNY*VDU-)5)Hv_X2IwA|^@pF8<^AJCW0v3Ii+_Jp+3& z4?3S1%rh2NYx=-%{2d`PR7MB?R{*dTt~4+t5Q??RU&W^g9v^$#?@}u1hVWxlb41Y% zoO~tW40+k3o<0i08azHE;RkRS5gR$T-?h8*{~xm6JgSNN{Q|btigkgyASz4RqEbbn ziU_hzU6CS0MM2q8MMXeJDWI&Gx*#e@R4OP-QbmY}5RoOaPFbTOL=6xYA&>wugphlLer4Py!!)abN>)%lHjacQ6+ZI9y^)b#{L9x)Y5YHIsN6QmxVybutrd-6ns+{YWMU_NuELnC1(%R?y%J!QD z$?l4{vmy~~bq_cRv(W#(IU-&$Y}h`TCy3`+P{B@BbZ%b`UP^!eUO?eZ@jZK^(uu#=-=mbKTQ?EZH;+3=?y1*u~cMf_%)=w zr5|^27!J?)7Ear*)`ox@ zQY|~7Qo-l%IuwJ|d6Yaz${ROvyMdZWW_ptuQF`K48*mn}J5qh2;z=7aAAtF_sV z$>~Y;zbzBfug2yfTEqCXEWi^l`-w26EOI`Iilc7LT^tCPkU$*S7ve`(!|$+%0E{8_ zJNQWrT7k?aso%|^^3}^ex1aW-)G=%4^dkmYV@uq&%+&Fn?t{6_7eB^dkZGwMVPJ`k zDGVA}P(k)J=*BL!(wFErN};rd`J*Tf|6zx%Vc5lW=kjP_9};%{Jal5PsNng|e^j2H zXOB8%(yl~&a7#gJLWXuRXXzOor`;+}_9og;vH=0$<7`dZ@h^>V+^QqN(U02HGmt|w zX$wAR$q`VU0+A2;)!L*~Z4X2H55a{PrbTRI+t5-a5Xu1^yPKseDCzv*l zfn2}R8r*?|obiN}He+Nt79D(F8keTuYWvko`2B}MDpTy6AQE?5U%qEvRw*+mPSM7+ zC)zf@Vq>dAFEc<7|X&{Bire+UdlU6u@1WOkNzQhFX%+tXdOoVCl&SGAmcK@;^Jxf9IKs zf{ukrCgf0YG1a-gHz-j|A1ldQpY*{5+CIYy)HC(b5(S+{#+E2~;~Xdq0Kf?w!TQD` zZYr<{GttXlHHerrjXhcx{A)!(;OqGQ0w?}_N2cp9B1&5vT@DiO6-In6aW!d(yNVJz zk{eieF=sU_>}CrI9|`-PFK&;&dW%^^EIFG%ebWVp#--58a*9~j`BRyho*?PI4?b)B zcotueL{3kW2+)7qf_bqn)t5klby*?QH;SST!Yn-Nm3B@azMxuOGz(LKacLuJBdZ@)>y)?3^a$*Xc;3$guULDYplVngmy=h1z z?1M<%ktLnQq!#YCh4-LMMb$kvk8e;lx?WqOsCY{%sVQxCK4$onlsnK6BlS5Ucf(Sj z55mvJSN>tdZ#F33Wj2Xqs*T8MvYl+m<#o(b$&QW*qwT!2W)D z3N%(lC#@No!w4%_;q+)uoC#~WeaH)=F4zBSYOrx=G^c4t8dz(=BLO1P^1L_Ld59}EaV6q6NOdsV#z;%P#>!AM*>Bx$JUNYJdgTSt)p;l~b zk4rh`Ra5ad6+>o4giiPN*JGd#tCl&x(X0gG!K)IY1%E;e`Zfs#(sm%N8y+4@;zh~+Eb_~6to@zH1hHQ^AZHKhR;MqG4b5atc5@rU>ek6ipA=g}V74>2U zPl*}GGDt|xXmBMHG>cDCklP8jS}wsh)N$;AB)Cy(;|PykNOpRNjgz*6xf7yq-=fP< zbfhH4b&>cFps+vNN&~PJk~!*HZ@T37!I9x4(mIVw{2mj4AbHDA^_99m#m)FkBHT#@ zvjDyR6!9TT159R3z;klz0ElPJu9%${`<>d4*zE)}sU>u|XkYAI`JAhaLzU-ZQQB=i zs{9RY1xVk02E`9V!Df&zCHh|gs8L{~Ge%JV)qaW35FUgE>yyqQj}f&4a}HkZwkuFT zR`1ynUkCU2$mbONBG_qa2%(yT5N3?7058)thc{@WXZGu;(rf2I+8wnh5sx5yWsj-) z2=5I-FwzBkc`e1hRhlqS3f|%B6gUkhW=FVW{VmlL=8r4DNqueCz%6HWammD5cdiBb zxezns1w%Z1(ZESET_BPW@+f{fhz4F+4(sEe}%6*o#;% zqyJF~*+54$M1OE5(XbIg-+vwH}H zF5kcYUWQNDE_;(&$oAZ_+Av7XRdKO6;r%atCr{gd=9nh%GQ&Gb%c zV&v1kV?mG(U`bwk2yTDaMv?{+B6_|chw=2(BX=7lTX$NSp$RP7EV_*VWY~gOOPca@ zXQuoPw~iM-0w$Z>b{$>WI*o+XYhg;S`Z6QNY9FXNGTj41z=2}K!w-DB9WAd_sGs9G z(eWcDZ*>gfbZIizQ$LdSc5(+s&pmexnF_-Q(vkh>PNEGDNBx<(wW<+-4Aj|WaBL~> zjEtdQktq+nPTVyE&^>g|rZb?hQ;}9TRALvY!2WsFYKP+^4+n7C5%4=Tuo0d(ZJ_dy zvDKy6qF%m(JcAt%kI~wV3_U?O%w|w%$e?Hzeq!k7vpjV)KgE?))V?d&kAt0y0!P20 z4j0fIf9u$kAhwLI3LYY&0iM$^F6TRO0f1rL9`I#zPXi_nU6g2ZKQ<6Xpf{jM!h`RK zFjvuz4h^)?t>6pW>b?6vJ|&=ifdP(1cb-lGKem7i68f?Vsrhm@SnU}p2klJ<+zlIz z5Y@JG&HYhL%k(yCdSql1af$jde>W1(1MBuQ(P~7W7bfB~l0d3ywhP&hzJfwu>Rko5 z6*>Y(GiS-IhR;%^KJ=>|vOJZYx_#^#Lr$*(yo^urWY3MZ+}5Y@zoX@>eC;5~;1+gR z=5XWL?{j1~96!(VTl9YR*}7@|!*jKiV?(onoi%dIN^IGLdR%1CF8On?fW;yL{GYXixt@l(g8TWwJ|Y0G|BJ5=$EzLd_~PaI#rslZ z8p`+DSSAUwRMKCQ)f>1SAyNm`d-ZO5a3HXgP-h);ThtfhFyqGJ;T6uisUXwpa3Vq( z(4k?sTIn|#TqAnEuFm`fEI<hPd!&W!}4K~Sr#L>2q& z_`mZm0+5{}{SYXoWt8HR@j{rYq?JNNT(v`K`??WCCg-)+FiL{Cpq4$`-g9ImD6kux zMCo5)YrEt1CFRRAfQnm7?evtQWyV#bFykFg_-N-ZbF7!0Yh%Hj;fDaRedpVM`I*< z+uRKhw8@R+7xawM8>4By<&qsQ*&i@}=h#qryT?BkfBLl4$5fi%z=5{9Ov_$ND1P?^ zTjgjt%H5jYFO~2RTklmS+&0aQyM45kp*8RAv7pK)P}0@hUIH#&z7}2+e;4F2SNj4V zAxAt8LoKhA+S$A36Fag5AgKA-8CW z$0|TmL*e!!mfH8=ua2#Tmy4W2JLY<;Jv)bXqj!9r>q~F;2cmypIflG7{P-#V_k$8b z&+>`N%r^Afe}D(Yga}*KlDVb|mq~ym4PujR+Ia{53juyg!_lvQc82Z1(Kg1;qCepD zkxf>!nSOxp@|>=11gTWjWY*T(ai%uKzh<&pS7xK&()kl1>MP)b{D~y!Lc><#UQvyz zl7hhyOPQdr#b83qb# zoL6kr;QxbgT0^YBdX$v41E3~>p4i)DI_WkXE*6%O2;}-PB|elIkaYIqz*G~6l<%<9 z;8p$}*(r;xf&F#wcIw}%f?T#3MM<2~5aBC3prtMa5tl9z1Cbytp4;|s&(!k9s+o$R*_ZQV( z@?e7S!#-Fn5^)u(c2ZHR;~~4TEmw!e*hH(hHacYbFG<84hY`}*c6u}W-L~WBd9he8 zx27&Zuhg-jkJc(*3J)Hjj~-(jePiE-EKdIJTz0}Cw#U!!FECbL;8#fQ&EwZ<7r_SL zS=uZk56C^U_Nq;#*l{7(`NF<0>XzA!2@0i%B_#CF^d^5G106C3nq+Np3q#EAWQ{&;Ixd*YXr&d`BL|tvjUuc2?qo&y_ z91|%Y0@xFmP`H)x+w|lI!K>TYJKb1@1_{(Dad6?LB0xc%5Ea*o(ZrP52 zB>Ri29bwJ+Y3*P2!33p zGgjsFlX_|f%hEe;T1k=-IrYe!a#Nm3DycU_rT#&qrz_~}A%q|Za=eu+Vd3ks`B*)O zJ#4Os(XOUGpc?O3Tg<58JZGbjC+`SOU&D}S_#9=qYuuT-5A35gcq*uE{g@D#T{-#n z1h4<7N`G)B1H8Zq6k!25wybLFozm`F`|B)qPB^u(dV4fcMb;>o8kbnQwVLFshr7Yd z?|IO{q+lJGR&4LSAHRM?GRH@qzo;+Xhdrp$3!DxIHBdCSy1udYyFv9_>zM=+(Jt`( z9N~1mYLe+!uVD3S=CBJtRv(;MaYpk)7UQXQPNV>oVWgkPHwHp;5}jZ2GIe$6jytVm zi0NnU;61pdXB~b5J~Mr#3kQ{f^`;R^a1^*D(MehM7N(FCP78S%+fm&t5f2?m&% zn!zKa+cYsBsqqJ1^${mPDvC68VbvN{#T7c5RT4R?5;c+y=lFM2o7xD@SixW2M_WG!0Y#1_|~U5^1}nntG#Q zTO^E(xi@e6tuHwt8mDJbS3#3LQVS3!AY_2Son0+POPKoB2obFQ@zQiEUvioIO&oHY zYASwGsqWGp6hYGJzsTYpNwv?5 za_kQ4U4rt}@DKi9*&CaI>fT6n^w|GLUF^@z<&zc&+Y)$@Q$#)FHc*+&ggaIEo^{0t zlgEd2??S1w2%2bqNgD@w!z^RV|6a_i>{O)^UH-V&YS{8e?FU=S+_hPW9wzs+}aB~Brm2lH!ZZ)#Js?m*u8Z={$V4&dTgXLF2%TwTS zfM}lDjLFxzc2>go?tPs^618r4?yPl8+cnKgF1eJMlF6Gzm0vk z&uw}9+_(L%vs5F8g}{96ix+bOv17!U1P|NkrkJ@(}~=) z29Lrs9#~Vy9KLTW?A&R-=dGM7>w@o;=fzCCX=Eoc!GY!DUV#%ariT9}>rLl$zgvly z>vqzbS;hpE#xwcH@wv;cEjcSRoI2)Z$u247Y2s)Y_e?#=r7tR9DEKlXQ%8bm)r(I@ zzM!?ua7%C)xNK+9At8fc%Wi)G-SnsRw=t@1suPIb?aF zH-QdPS0c!e|6o5+0tz4LH>zLQosB38id|=u_B5}87XFE^v(?S_v%)si6~XR1|FAyr zVEN3QudViC^-4<)2XQ&wbOJ3w&LL?)+Kk)`8S5=&69o-@{$hIG-y(~Hl)2X6pQ;4E za>|SX`z>m_V=I#l64g5F+e)xb3u>)0y+5Fk1-HCu%j>X@z?4&di3FGD+T@nmBp>_ZP*Mb1K;K!fZ%}ER z&EMTUa6ou1z9Z&J^kppuACd)j7sV8}A~8(Pr%>)1rj?LVxTgF^d7Iy*%@@!95%W42 z#>a3(;=soC-go4O)LNxm)3B3L=~gY%2u#PqkE%{Abr5~f!1$&#M$YfUL|$K8(HZe7 zw)k_-+rjgJJvR67oj8GBAsBga@(9YLuLV(yS$6VNJ)J<1XZBQUf)4E|@f%dKJ>4ib zbcx>;rP0oai?{-zyw>1e9=ueS2)Zs2$-LxNo@-)a2w6T-=JS7y$^RkJLXWaxjKERK z>ko9hf|y7r%0)+y`v&z3);#(zf2c)ske>*HTcuqd$Io2Q zg=&muA^*&{0Sq_!QxpmvJ5ra`Nlt2VK``V3X4TgeBa53Q1b-R+e`4zLPN=b9q^~ig zV;!Skd@hxMhAxktF^mBR$6x;zWk6w(4yq8f3E$`@M}kw`Z>0C{u)dUog_uxfLNZ;g zEXRf3dbjPw1)J3(5i&7>cn%Jy82#N@^4!g2`K@O)Y<*4&WMruUD8bb#~b@Ugvn&)GUvngoGz%U>mnr&vA>@Hmo*3?$9L%igz9j zQxUY0T2c^L6S}G<*sgP>(eRMx=cDYPW_^fqOH0wJ>M;g8HLFR;>P z)e_@nH{GY-Z8GyjG(IFpzqycX^s-WlQW|9uZ9hwDr21gLw5{Xm*q-1oet=~BOCS&z zb4(d=NnOalCY{OE?I?wZgFd-qk6HLiOTA9;^+Vq6aN>&iba$!2)gR<8u4AIo6q}Zj zPyfz)?Rgly1XO(ybI1LyeH)7!=L`dG31&#Usdp37#)r9M3}wtsPW3Xswz@8iQ8waH z5?(i0^!NnlTUggtA;nPwcqM1pO)>X4S;Fhx8+9g1nLMbCeN>R z*blS;=~*q6fy}Zg|0n)%za^W;EQn5s0DV;hz(a5YEN>^jLD+!w-DiL@UU<|ScZ_^o zMtNk6=qp$LJ1>MnJqsEr+LY?&c&F-c9nRH{4zQgH=233DL?el63a0K1P`gVhxa%Zb zP40x{D;ewNk3hC4m8q990NXK$hB^XgW8tDP{4!zDa*PeHCp2YY6bLV8SG%$BUR!}( z5Se=Xp6$j#76$G#RiLB|cH9fJoPuTY|9XfHs5_A_`dxw1f5k3}&{zgN!Yt0U4F3_d z0#rbp>Poj;mPu_21(zmh{XC!qlRIg@q%Cj8C6xMUjwwJRJWpl>2TbGd+OY%}w3oB6 zL3Fs`#fOmCT#xlENI;fT5|3nbBsm4uH?e3+T5;|F5c73!ZiI83dlJQxRj@u^ zE6CywR@gRp6u&9teiG76yKplN4J19#vH$T^cCNh5BrEXU$AGY!6wr%_E`iC!i*rpi z_d<1M+ggnTg83-KVhbwP7Wq?K#F74NEd!o)HTpkw*SCaVnC9e^TtF7GMj_UPq%xaH z&(}ool-vc#s1g;OGrd79cesp|2V^>Dj$i^1Eshr=3FRA8e|Bkz#e!0xvIOJJNqD@7 z18gyN?h2sH`$SaW{f;p~0E(zYXv0^bwYjbe1((dyGoDnM9wUQ}pKXvpm@G2K+MKO5rzy`M3 zmkKIBoU7qlx{5itCNbtV47s`BkM*w4I-C??06uzeB4~vbyXxUku^ER!{Lm(nj9n^5xv2V7d_n@lM;be>|FT{R|oJroVRnYJzGMwl$T|_SD;@?GIplj*Qt$^q8-6O zm0vhkWEu9Cy!@o_XU!&~Atf-S#R}(BJM}tW1>5avxauO@)buKS4pA@}8a-NS;BmdX zTf@pyKY^A4XpCtLVL)t7i7kvIg1TG~v|*#<84{Y1glR#Z0RMm&&g ztVB7$l^aV+>Zyw=GkjED=QYu)azx@LGWnWJJv0ro*Uc3}>y7S+=#e ze(F7W!`o1R57`o#jq^OC-i!RNIS~uYtE)oM-ylH-{3~NUofxz3a z6S*ZR8}E;~+E0S()cFRQpjm;s56ba5p{kpFloEAkXs>xb2RF+`%;bH4I<1`^Q5Wl| ziU^p-(en|+IBLoi5-%}zHD8}Qg|BS4Ndk-;uE@V63A z)Yg7%dNa8mK94(}Y1>L^Ou?&tBbCZ`l<#u~xL+W&kB0FU0=CB2m6N{lW3m|Xx(+!v zG9hwf*nh+Og$IT+ON!Mb=ZDqnxe3v_r!uA-g)Q#i+@S0lr-YyI7=MG6zQbP4Vadm8 z`0hPrR9%SJ2)5X8gGsdnYG}EUWgX8r2X7j7I)Y=i6j(V_?dmi+Qv3+K_aiiS7E-?4 zk3F_XniDC@3f#IU%)bjr*t7lfVlwUSq$uOLmF_DT2XOO zovla!6dsc*q5m`KbL6V6kZGLks%lm}HYT|WaLXM@IoCbwljx@EmVm&pU?Xr_fnc!G zv%yG>f^6YUB}~D(C8T!TV&oLzvYWBmPRjO9{o#Z7T3t6|{Yk)SD1GNv`fOx4BfY+H z&z#_No7r#kw%fJC%`VVr0d+nAh$+y*Sk`qQ>A#~ig8tobJMj`9He+3&1iIvxV_Go286v+I+CgKBkkg| z9xi666~?I(SAN)U%sU3;)D7>}b2tiU?0+)PtES#9T}JS(>Wl5#>)x|`kaetz(lW8U z`;bF;-}F~&ng^Mb=-0d67^|b7gXU@hPmc@vcbX!k3M%<34UF)+( z{k!F6d7@Gj$@V>(5$93rFFGCif6KG z4(XStVawF${eUicvWM)e_h8-tQg;!J^zS^`q!VcuU;0@Oihu=X=>3KbyxR_KFV$C> zb0O|c)jeBdHF3^9L>E;K9I^285}VzSn3NJR=OWo8H-Db^wIg3Rm^nYXduHCa+1-qk zUo7}CdT|Ngz9LK>zJSsNlwbvi@%4=P8)`J_VcBpwNbYtg`vHX z#Rbk#voENQlY!G*5iu)BeM1OXP4?*o4!RVkTrV?HJIGZB_BJg`V!j@3=sG$WqnKoI z0fmzQicY&E{%0pF_^;IMG|2W)C`X7Tq3#?|8=seLv;TMA+DsztxHC7B?VA)A6hyW$ zvub_ImFD4t=MeAQt$jHhzsUrsnSRY;h1x_q)Cw(0UTNM&vXB;Cb4p1Y4D5>j>9E0| z%}vKGC(iKa&y$TboklC6Q7UyIa09p|73jCBD5n`)ecP`YJB;$J&%>p_u@M^9)zy3x{L#ZRkD-R}5 zY#G?)aW48|&W`fQPxOXzNo*D|z+X^#qf^?SVcpXEH)Z*N<6!5$st?@aTyE2CJLyqK z?a-G=W`W>+XCq+gB4-I| zD`E>YVA4w3Bt=>qJ%bxw$jW+565r*vx2A3jyKh0M2vvhZkjoQ`p zHM2S?l;H}@%Om6a&WS&qFG2M6vF6Uah6d4QDAEtMA8 z`F~YMX=B1RM9|`rN?H@P2v0rj=`2)USeKmRJ){gk-!w`(Q=mn7y{Sxx+uHih-WG?+ zvBK3?r94&!=8|Yp0Hs2sSGg6E>-L??E^-db6m#oHk0MhR{2^N1>^bnsB#>Hh?<;+Z zt4KBWq%+hENa$;HK9>*wLm{&nyFqQ2?-z$(o$T?nF^{Jo>4I4UWy(aFd3~wF8TR_a&F%ou%cYh>rHB=1UyF5a;uX(8p}pIbc^ z7;b&>mHA62Gm^*d|KyZN%$n7uk&!SzX%y=7cp9EfJ)hUJQuQNrDCrhDy!n~o?q8s< zA!;C2^=9WcU%m2H3)tqnBw*6IM_54j7FGu5(YbzF40yF;d;qHrq5gb^Iq_T3*}Ro8X9``mG#Ou#+a zQt_r!|2aRif!Zk@PfW@^y5P);i=1dGmRktinH5f&SblM8_W3*WHw>9TSAUb zW)yX;W_uBG0TaVx_+-s}#W_ck*_#)~Q_4+jJdMkSK5}Zr!BcOB;>w4(GSdL?%q_*3 zb$zs?XTwv3<*9v-;#_;*tm}B#)jnyLKVT%9^4@$4ZvF}iS%8zFvUw_v((7kX`F;l# zkOUGUps%Mote-E;j3~u^)=Or7>nORW3;r5Srz+;HiDNa*GZ(2Mevx7i$8HBEcf?xy^L7C3*U?6wkB0*7Q^Sp4Rplbyjn3 zK~3djk7wb1v(1K&A_^Gm{RcY!fa?t1=evp&B0uRc`9{@kpFO>gGN)RPRlTaHW85)} zq;K6{@Lu#eCSNtT_H#4Trhg=$DO8d!$Db{uQ~p$aPu<&}0%`S}&Plyjo6Fu?t$cX~ z#}2?-$2%84ynXW6z4Xt;pK>cX2b601qv`jZ(i59)uA44>5g#<@(Y{kljQfy4d#?`y z-Q5*qQai&0zw1N8!KFEVCP$6L(f6VRTLAg-!1r@zcdv4ZU3iecudF1so4o%k%TpF; zg(U_6xtKe4;_ztfdq1(wq&aBm<%LO!7+7kWf_T>PnPSqm?&H<}&WkUn*QgTdq6iB} zOS=oduYojHV4aAxGd>AhbW^uRO$d|=K@=-s5q1@bEiy5nyumnJFZ#c0s+ zzpnwRkHYbdfQ=wf+N$vd<(_Bw^X|B&AoS?qIQ)0725TI?eb~dhFc?4mbylaHfqzsv z;c@VE(T+Yz#QK_vfQv_8Zx4^HSabgD`xAj@^FQKqro~9Nwy2EUPFF`8Oz$aq>FUtl zFOW?22|!LN+5?SVgDUo96hGwsJwo$)4T$V}68*$EGhh{Y3c7?{@&hf$@_@Gc$eK_b zuyDo>b)x>S`!pAl%kKf{6S$Om>kg=`7egT%bXqurS=>e9;s|OvaIGlEyY=c^CzD7B8t%d(f=a6FWRJ|R&7W#wA|R-J2#Q=RZ^Q2$`#CmG zup<)Ga+ExP$G+{=Ig^;AjWUA_x8*|ru9{k&m!)pu4F6=$zw@dVIE4Rbkmb3Z2*)KHB_D02rSX9W+# zlFiayMbZ}kdjIW;Z;4Ib<6BmmK3Kl|wKzlB?JRKod*{rWL`@pk^>@h7)%qV$w5Xr0 zWobKJk#}O;=o2P+x+BgQS)X_t znTGkj5>RsRmyG$9|Jn%VpByge5x!9Ke!wof0Ohb_9KGdk2+zgI?G z17ys^v|td=Lq_MTeKvr%F(CB&cK^=vb&SETJtTgy=NZ(HQU+$-r)za4$;;5Yv0ZpCwd$$Vjk3N07UVh~(@f9OuW$wLozql70x;whWs#p_}Lkn!?X`G}ct}Ix_ z+(mP`o{`*d7Q@&z-%bFL%uxucrqz8qa?HAbc!%U{%zg8tmK->KN_CYt)G5g zS86e0YUH`h>quc*rio$A%dnX`t3r0rbd}pz=o4r(52_3m`|&@!S?c{i+INaC4tZYv zb>E9#H|Dvm;%^7;Y(05%+MA!1Eu1BP1xfee`cK(d*5Q}LKX8gA>!Rix@sJR`ft$dQ z&T0SZ+tYd8PFa-QW|tJqqJ4{hHM8xG{_IB|PXVX-6X)Y^$@}@w=}WG6N?ig9MqkAL zG&?bnvSp;&>GuiG(X^_+LWYJX!?p&v3~CJVH_F7%CTh=AIE);=I>LJFSFNSDyw+25 zutjCMrQUh)m_gs4;0CWumML}?B5Dp7o=^HJc?Vk1U=$(MjYXwfTpcU*2yI+_dhe!t zm%h)-%C^imbjRm3CY=l%eMy{OXlN%SABvlEO$!%O>lU`TdhZr9gA?9pITpl@e809e zXRmatvmCmmB_%(ddsyxNp>FE0BCEKIydEF?v8n^FT&P=`y^gg^3`80Fj%-VF2#EDa z>7ur=^sBGq2B>?~1MnC*)om>WpOKh$Lus^J?=N##74-D|92guO_BWcf-jok4UJd67 zZ)up=w@JE<>QYr6TBP3)xjJi?)ZvOm+_0Z-{>OQ+fN^0ua#39XzWU5L;Nf_B-n{X9 z^TuzX>41c=+>&S8!5ysR<+MpGlJ~H8K-aOK)t5`vnLF635p|{nUtg;W9VokeN@a2F zRLqq{%(e6p@&H?PL5c|(0>E7|iM zl~_@iKH|+Q&(;Qd>Z<_9(gNAa&L7sEyX{RFFf3v`mBg7M)6+FJzZMisKmH(fbX&y? zk>~r`;;v_|T!I#l-wU7pb!bDQ%DXSJ^0TM&Pg}N#pO@X)&{)*iSan2|X?l2h!W*m0 z+T+8>&i}Mn$$i&!g);11o(_@MA-4kr1tTT4OJeh0FPd`W78XBMt+peWbwRgkAA35UlQr*)e{-Dl{hW=QMV7gS18SGxQHi8rNm;mXWox zE8#<1Y)5wv-hVY)#K>Z^Y0yo5hxO;*`>A2iFr*v6ak)L#gp}Na!yCQGxaR~KK~Cvy z9-O*~KC-`zS0>CNLWW2o*4|RN`rxle_@z*r7QlxT0N^Z32rhbD-O<^(2xPxl4V-8P zAi0>4x?d{oysAD8;V6(MRISS}TnKktS4!zOziDs#*=yDd=Mo1ZD`3{pU9#`T=H!jt zna-o-0BPhVJA5u@+QDOUGRS(a+W=af0XvQ4s#2OTD&+c$Zhp&P>$^S`E=Xfi2bOWpS0uo9d4K(dB;t#jm?F}oiXTFZMIi#YQ9t1WvQ3(B)0aHi?y=oU%aXIne?zIs1$@@Rri##*GY>uUAVuj( z2#+xoYwWe|ysh8Zd%0cOrx{Nlk_owpdQJ@-nbz5NHR)da%=P{8puAAQ(1WGf#5wu4 zH7Q&nAX9^>ebr}!j>Hrd%nKk5^7gWT1} z;hQ6-`>WI1ouZCLB*1JwnIr#l#UZb{nkM!I$>DZgKjP*Jbw{xN;~QlSBw~P9b_h{_ z4~Y>l8at~q`;0A>ZP3Hg3eqx^+M?~E=IL}@xbm!L@TieocnhsiY*BBdhF;`~%UN9Bc=NKRia3>XkPo82N^g1tYXr9d z8gwpm=vYNf?-mQ^JkOzkq^D2t%9R1bWQ;*zeMA<@?9!%mgtDWpVf0S#bj)-XIxv>p zIv4!5tS%s^MpP^oHjZF{l{@3jA@D%>KlJfhQW^(FR1CA8|GEAl1yeq%CLNZwZ@ZJNl7LZz zzlNl{Kz4ntXTe-ER{J^0gybr;>n`Pyg&8XozdWW?VFJ|9&7&f9kD>?*VI4=>jA z=P_#~)9&!ZEh(K0Rx__+i%tmpoJz8e$}H-Q+iKRC=V$?aPDZVsV!-l=5Spqx;)VK= z%;z8K0+N}!p2uiIz8g>z{uwd&5EaK=E;0d?UkRg%rQJZ^n~?H!gpdCiEBnOnL#_ik zU+H1nK|Hqjh|W6#w-|^#*e(kWV^G)Hi->6!^J^Gw+Va~{JILQDoekuE5{GBB zI()v~T1hli2h+bh-B@-OD6yQ_z)+%*bwh&6jF#-L?_DCCtVu6ZjIfI9{5h3?a#l@(f`UoIs!@4U#@t@OMS1RtMm zVx<5H+#sNiu1;@XSF@`D>7n2F9^|sE7Z%23ph3^40v`T&z#t>Uwbt_KxLhqKl*%?n zr#6qlahUKj+nNJzdTGDAB1m3dx+Zgy+my z@@H>o@n>RrLyLw~=q7lfP2#;cW19Cp2Bpyigsz8^cDlV5A~*;h`=GTro~Er{PxW%W zP?r#)QGNeE_d|yqi56CVo<)HG1lAZ&EB$Zw@r~;UVU`(8B@;z>4~L6W(F%xO?X}*y z4yN{y5?GGAfE^`qOabMnd9*=IC#XiQocAuRyZcCiI-*9nx72l!V5FvO_W)TWhYRrO zx0mX~Y-!_LFH<^E1m;!R#V2$auCM$UiGTorl~eftz6!mM`=iqzHG{XmkkZck4pX+> zdQ_dV#x9b%w(F#&h4x> zv$>~bJjC0&a?LPDt)q%Okhh5%^{FPOYBkB46}m9u)qrv&J; z(|shs%f~~2xy0GFX`>0E*RtzJW~aN8ximJopJX`%YHk43Tse)1mr2Dy8Hsomvj7`x z$<8lc)%V3FIi^whMoR|3`cshqU?Mk+JNsRSwaRFzx>aXwjNT@$_Rf2OYhN6c}<(01^sh!t3hhl_6G0y z#+dMS4H-m=%eB%3(vRg|l)6f6RSm1bolYWf-htf(qXp_54;e8n7Qf=Wg9>;QmWL&h zN>4ov=zL&ry<~_`<3H@b0w1W0bCD6Ykb1b4PD3naG6T-{+?qInQVrv;E)@1O+J0#E8-P`Iu_6w zAoa0GEDu-B+k6ywJ@r2e2w9z{3MQgQ3b29fo*{AO+LoRb_K_vqYp)GwM85u*vf3?p4`+w2E*(hf|0}{x) z_6N;#pZGE+PILiYKcMb7dSo}PYE}=AE;~NtU2@!qVW}aR`4GOm^zMfX8uIzyeol!2 zgKvJLZ|=TKlS>oZw4kCP0QH5_zkEFnY8x%)g5iGUB?moAx&FE(zu^I{2ZPCpf;Q5O zYF1BV5ZM8-PA__}iX%sht3Mz)L4XR-OWq)hQ`gnLdd1ba&HY6579|IYK|AR?x>?rgCKXobrrQsMl}THbBXHp-ShC9;zH zDI&3>Bn~j72Fu2qlEDdX0JsvFPMZZfwlCssL5K-tHf>^#(XTZJ=xjik33tY}P66uZ z-cG(=c6NYd`h82-tq$vR6i>#R3k-ec#*uEmf8WQhUAlb@De*Y6_a~D5=cb>C>V0|# zl{1kt$)7tCz{D&tOdzZnB^b39+fP=+yvf2`liy*JTx#%SrNZ1*AID!(aQe($h369b zW}El$BdT1~;mlD6TTr251lE6pUeX`^BEXnGL3#K*9vIyauQmLfW8&r_Yio+sXGbT@ zy$=I|KvOAp`F?E7SPefWvD|PqvW<+$)ePB^2QlW76lNck)OL4KRYcg2D3(VXVxkcpNNM$YM>=JVrG)G>#sHE`ry{?_>lW|fJ z6XFvbZnPyODe;%kINhA{4@PIXuxK(;wC>|xB6|PSY=FDTeWnHs$~bG+)$e?rkVF<~ z6B9G3nc+cEM6TPH#$ni5uAQv&3nftMh?VSGKt;t0 zQnN0rsE8=2C@rg~2oWOEA<1V)M9nG-C?!!5B2uDKA}x^`5Ftt+ks1gkh7gjFLdutK z@9X~l_s*TUGuIiMaUA{H`=0ll=RD_mj`JyshwouANuFN`p5)b8$ZnE*RZDmM9*ofs zE{6K1wgYy?#lFael!>=}pvWP|JBv;JM?jdJDz{3eG?`;UGCq}d7XLdd8boz6lo#QU z)}1p}@A}tckNloS{3DeJJc+8X^2=1wWKdl6s*SWQ= zrZ2GoM)9Ww`EMU8PGI*E1uS(kWP;E={b!0dmFb`Eu6D%Yb}kRn{|SuVg$2dGCmpMq zzPv@*rJn{wEk08#)&(!+d+INAr)QO(gI>maok#TG*iUleHYVVCv)#H%z^OvoTe3EF z#+Aa-s-%B>nm&~KkLQNTm+#ZPL3rgM&}svPG7K`Mg@k<;qd)Nph5Tpn<8; zr%+$t(2Ql=z>8k!!8RnGjhUE>3-v9t%glpYKScmmKnIxHSAFs=>$8!rLE^M2Vm6Oi zd}-c4>C!#-9WLW)M>0Sv%_gQTdcFtw=Z&cJkOfFcSbL8UNm6YMRu!v>}hK= z049$fJ<@ms!JQq2mU;2xga_Jt_GmVhra5M0htFiCs`cmfM{K7BVlCIDpzusTAz2xB z{?7Qp`#yoek*Xn-XMJ^;d!WZw?}lE71(Y&(y>yr8KG?s`&a*S>)x_vB&iZ4BxIF_5 zlCY**i~i4JFY;?hFz({`_k*pwV(s`yg)_RPs2%Hjdxf%Z4uAJmZD4R3Ij3?(t6}rj zAQl@NZJYc8VwFKv=?4YPkb%I+DcB+@e$0~mZ9J3leIun#gG*M8XBfbGzRsXHgED9P z)IwF@0aTP29#IE(Osv@}XMza!ipzF_g zGF~ZOwW|H9h<~!CCyb=U+VJEovsppymW3k=M%~Z%EJCkEx3nj0NjORwGB|I;St@8~ zA!WH##Tq*?++CzhOAK4Oe5O@T+x1bc`zu2?e@HbHiAuy;uI{0vF_U9J2`p1pwMbTiG0iXD+y_&lIO3!Z+1Pn)D2f~ z*jGb8GcVKv^Q#8^@zdWh<}P-DZdd{~ufLB#uVb3H@2y&v=}|ldRj7VEy2k@LKEdDi z=>B*`bue8Phkf%}rA%@9+p30vFP! z6k=Z$Pwi%EUf1|g)n#R+wXLP^oN21nsm(^Az+S|p2U4HVSn1c|cYH=n;YG5e8AI%a zm$((OCzD$hi3I^yx0QSNDjyLD1iY(xE#utKb@zLwJV7ad0M4Q0^} zNKWg@V&q`wft_|2YmX$Y|FjFPyP(Cd&ZZ}BWO+cR@=16?eAE99Znmh zi}TYZ#A@qWhfB=gU2Kpp^c;rK@7@B`!>GbFN6xzqw=E0v4oCw-A~A>CL)fmb!saZT z$2OB41s`W_yk>vMtJ?gOA^tCcXFv#W)F+4iYJ?2fl#(*A$|f1v4DmDmPAAU6LM05$#l?4Fi#C!VzDa!Bo(lzW+H`gG)N zIPcUMuX3FgzcifdHt?6m&$^-0-3;kVnas&}akw|6RM{(3VqZXY0SxoNiTT)9prEk5 zatNu4di?1wBX_yM4V6Qg!CXQVeD-dqW4+JdY|hGVxpGjj3PK2T!E0*sJLs0Ukh@=j?!dkr_I;A>xCuRp6LeL>#fPc18!v;42_ zkYa8`;C>pfu}XQkY7HW~KOP?*^h+k0j5|=2Ssjp-NK5`ST~!%y;x$ZpT%oQl=XFZm zPj}j1-K(`{q1oBwNVf9TR7p_TjYCu0*3pyaUC2DQY@@vYt#$L!c}Ia_(}K~*8*}4x z>YJ~%ObuQ8@xCHko*j9!WrVNo1P^ips@oSWU93qxt#Os5c-guv`%)6Vo3=!g-s#_u zU3mvs=7uf$!PXb@@(heuvTw)vpqloou6l_*;_-YwrqcI!H}CxP zt|G+m>lYR7WN8mL9RgAfmo#{jRGkm)2DLy@HV)yH`vmmc#PF37@K4Y}>r}2xxas_%=%g5cx2; z;hJB?KPC)-(}wL2f||j(wzg2Wz($sGM;7JP1geCf2xvXSorim`FG3q%h)dLC)FA2` z5eFRNOLc$9q_Ek@aQgFzQZHF}^@YnYxZlt+g#hS79zlg0S)|R_)sy;G4Y@Uq-9Z`0 z^&L$*o(;92PW;`2NoHN}d!G7X=m$y=Uo-R|-w}Z*NCK3MWDgOn!&#@9oT;;wZz|tc zRMIor_4{jH%x__hh)<8ZEV(jnnToKHt`F*}Dvyb>s!sjOZhdh*72IAD;mT2iQuIZH z%V;|VMgRRNb#A)N)ALfGuTRd^cHJu3RZpQA=@$A7F=10Z^79X|v4lMQubS%DDak<8 z+uN5OZCQG6~Y)wx=6ye~{Tz znAnzA?MDk+*~zLOe;RO^_KWD0Ue`x|t@t9%U7Uvd=PLh^2%KsldE^!qW6yjkGjGY@IKQ6J*HGbh`NUY}N8^`*ekS`t-R@p1ZI zWuBiU*Zj|c8tJ7ORnM95DdJby53F+v!bThSNTRZ8U0FT{k0h3D|MeZ4+Gk_7&qYso zfTx1pJvUv(@z9g*WPUmojKuSMJ<)64&q_d^?9muUM+gtXQU!YKC1tqT8ESdG>IOY_ z9R>7qoD2yo4eYtYRzIH&fyx?oHakz1uFq01D0cMc>aUkmtQ$BU!(_X06*DoUxSGIH zJ{mUBSTpOxe9wC%9^yvLRYYuwjd>Aa0%>$W?#NkA9xT_H%Tm>u8asJ@kCn{r{_gfa zB+XE1AZFdM*)-d@IZ8=tS9T<(DWP>|1z7iYfe{FYeicnK>jSz{K*j9ntIUj~a=-S? z)AnIw_kcM1v{e#nggy2Uo8ll#+)%u~sC3EGvpZrE4sW8JVh(-X;pCh)vgdT{wUA3Q zhw_WEeM@=KdHQ1Zl>f&YyU!DHh&cvm8?%$Tfb#eCvFne~Y>@tm@4;Zm=0+mY>jg)C zVPC^1LbEitpZgV*S6=-=ew32a{OvqS*|+w`_sc&j>cqN-3NxSZD{&9emk9~TN%-Gc zS)*SkNvOMR^46jgYaWZm=W=-do&J%j{{Giy{-zI^-tAZCgKxRm@Xu(@XZ&$a zYMXRx`B%d{^3kgYhjb&ENDLF_$jeZ_)qGw;?0BTf-e1aFmhP|ob$Tyyk>LQ0AX|u0 zEGckV20>*T{{c~)7U%jXXlD`K+|MkN`mpVn-ZJ0nLyj(far*Biu z_A5l^06YN`%lfiFp954Z-QupUtxhR3mXFZv3aE7t0C^V&{|1=t>7Yt~!tR)XkFr&X zmQou4VXTs&%hp({+YQ-!p3bp_%$&9|HFGiqv)qp6d5&=Sd5K9$jNdf7nyzdiua?`A z3Y*~rmvNFQ6N~HfJOiH~u;w&W)&`e<}9C_V%i`7uNS& z0D>~!p6ym8S$P+EkFf-{q%nj$w>L{(hZ~qUfx>oq% zUY6DUi%gUDotI-yk{U0>ja~K%*_LdT-9b#?_GApRlFOl=;!>I;w^io`cm@^p^@i{wn~a-iTSLQd%w4$aYxd~0b#^&; z;g5-JSNpVWBRdAZ~B%K{(W}$lPJ(y)a&CZm{Y2;VUi%oxxP&Ao=(YkB| zorWK!FKTpSp0@|u7g90e7KC{{hAbXEojuR|7x|goxHjk9^UCg!(pVr>J>@lAWAtu- z=@Vu;{VqTf=Afjj(`2sdJPlf|KgKO%Cz02AxS#kexFOIrU;1ReAe^<}>f(~0N3RjX zK}O#v;+wjx)nJD0Zj@6{aSUY$g8KZMo$u|s6@SmO#{RTo;&fVvTVTSECJKP1%pv^K z2VayIwZuBJZv9pMco#`GzejPyWOgdQmPm%`yv!)-{qonjd(pTrbu4OcRVrUWYcK6E z{xAlIrOU>gKoQmK^mdbTXKG4XPI~fW)rLH}6TZQ^epqqec4;cZbVXP%Qy81*$h75F zEd#C98&8q8$9;qXC%@QIBtFYj7(^a$c8o5dAU}KScPxmwLf*)Dgnplym`V!tk%QgJ zMciWFjcPj$ambUx2>y}6QCup0>fc!`PKEQXdj>D+&1}bLgqP(=be2@)Om@O1FQ^Tb zJGpuDZ4T|JWww=6!5L~dS&F(-Vd?{7? zAr=Jvwn-36=P%18dA_v+d^%1=XdzU09IWiLFpBK&P+apYgpChIw6m1Xx1o)kemqT~ zi|jC2vkS3E+rPe_4+V!q4Nd@WqME5G^11J^$PERi7Q)D+9|xeX@kWN(|IQi*_)a;x z$On9_XUM0+{hFITsYs>hCiVH+Z$PHZn~(eqZX`bz+xtb;lP3gcsXMBTVXd{>xfdY5 zWJ>2#b@Ee2>=uL3dIgmzd@2fV!qy1GE-G0GM?*WM{LD=$kz ziOj1oUv=_tZp7?!H8sNe)i-TEDz-##Idw@Mx0+6FKfpVMoup%5_W6o>tgm*pyemJ- ztliW0&NFsE8hf73iPY`VNc0zAQv*4g;Mf38w>{#%tv)A8^@QSDaz;eL`3m%O|K;Vq zdr{Yfd2z1+dTc`$en@4G!1P2Z|A)tuwsU_O8i1tEf zYl+D%XqnRrd0|~lpuKF*r~JnV<9<)Z^0-Jc+o1{(%^|q_Uh`sEZxZWokSZ#~E!H#wQt* zKGb{>ir$$a{&?T6DY_E!vB*AN8>j>b*Q(awH z?QWxu0Kg>Hu-q>`&{POgW3|ZNsu4Zw5^AZ_*1|Zy#>}wvg8a~Qb6fKmpTD)AJ#dlX zu70a7E1UQ3-8*M`KI_1$C6liwr1?xV+J@Km`@gd+D2p_i4UM)N^|`Tywaj0egU` zK!^Zx1o-OXbq_C8x!qnrjpwTwK% z`r97OU`Se2%mjB+(5@GjdMs(M7sQZtePqf5{Fr=py@K%0<8bd9b?lPmv=IYj(q-5c z*gk|>?kWgF=`D~;phpt*jTt>2A@m!e6SXR;_|&J}3t<5C+$;XJje8>3^|`fhc^ef`K+qD9)YPDDpmFtXe#cM@(0aLNS_`5a0f@vf%2 z{zVTC>7@M1(y}l}EuJs%T+|nu9_i;#(;b2265w=>Slp>O{Exa+%8>yb;)VYSK#?`E z$0|9vt@($}-@(S?zXId$)8PGALl2;QCcHRUt*kJVpf8||HSSFgMc()$nt%}8@Ya|? zcbbbDOR(rNJQjC7IKZ0BOj?8Ro1iDg*{Oc*dv1S(^3Sx6xl@j2CqPHBYCsll(??+t zfLW9$-Gp5WFfEit_>gGocM?G$Zt6FBO_hE_e!;)9u1L#O=+2rWip>B*NVKsLfj;nc zewx6A<}(G|t|dT2lnL{~)7nI}l@x6vo1=J0xno~)G6Rd2GlhM;Y29k#n(ur7mz^>O zNkCW{M^hGGt?xy+fukwRv>XrOI@U% z4RkHL82_7e;mHAV#Jz+P{um3VXxib2`^>5NAN&0GW!}$0t8w3{HFnUt%npS!6N8ld zdRNBlPzq(q6_eUVh=`tcKmrtiV{#l|^D`ujh}9MR<1K-Q^Z_8NCHx=-1V5JiPu?R9 z&Tpj`L~YHRKwpp|kJNz&oj{L5#S6E{a0W5E5c2sto^8k=B)W*w!2@hk9P}4Y z<00ezJ4;=s$<3u`JY6=QhAzPNovH<{bG{d7y~)+xMtwVp0|IL~%kT&2Lr$!p3vDBt z2N;23;YR*9vX$Yr(+11ZVLu#+zEnf1N7k25Z^60r&;rl&2841m2DU^=l^(80KVTLp z8L~e!aqzkXrvxY4n1qwHw`+U@DR~WHbMHK*8nO&axt-jWpvi!UY=c84k}6oprOX|* zw{%Sd9WXvLeo4}+hV{gx#=m4xucqjzwP{7N-&8_=c{NT>P~ z;9rfqiUdWf*g`(wW~nm6Q`?3{WHW4tEjp%c;oFPF*R{|iu@plZe>!fx-O!B*Kn!|2 zkQ&dt=^?B}%et!q%B1v@i6W-wd(?MA!?AZu2L}vq5yC|457z)pMVa12K7(lCB#qC< zu0Rf*&lwXIOdRlM#14dE!wP;bv3G_tfH?INFbaa8T26HPVs^#0-j{><&j=C}I`$tc zcWLeaWX^pz=}lf4pn5VTiirNi4H5=WhLQ8Ty`RR6WRGW^(f`k{)NzuDQh-ybuqWOf zq{7!$OW(oJr^2;s`hlN1*iW6$LCa*!Q`0?N{a)G!D<#L?jofSj%#GKpEyT4@|cT#VHpsm~2VXb{q(_VxeZ3nsG zRw85YtAtJ5fe~lvkKpIYAjujTjzyX86c&t&AC@k^1kC!jJa!ebgCk`XPzq&n>quqAk=-o_MM{`O^a8hj5C?*XO>#NfuKL3Q1_Zkw4SIM1WHfT);>1RiXP zR=<~{CnNPqW>4P(#v}k}F&UWPwudZV+xZAdQ_hYPn z=Ri<5fjd2&;HNwBf?V5AMw1~!)JOP7>eLKOB)DL>tj@>rzVtC zVy@qZRLqV|%Z@}3=^j$RvM;$4z;7c1yOm5&8~%4@5%>Re2`?WyRvOM)-n6jqZSxL~ z+}?O1TJ~M`^b<(I{u72N;8E?qjdEpWK}2LRlr{wdP)Z@I_&Z$R(2G;4s;*gmoHMs@Gn(m?*HbF@nFEXnQ56bj(wdBirRRTx@zD}O73 z^VjJTbg>p`d`)nJ^x36X$tF3GR&d!gljl!lV%o}~E2G*#bE^+$-_^bEKne-ZF z3*ms$^@;6Xn9Y87K~Q;6DUgc41{D+B z0do97y{w{Q$NtXbTt))AiP-TWGdM}@r-1z?&XS;-M~LS(YkVr;pn!ivW1v?T{xpt#aA(Z*bc8WOgVvTC5l{Cb{!U!y?4YJ)ggYIwOWD(xb8c*XlE+QN zX-WXrY&1l4}wyd4c`77SkgZ@waThJc2p<5(zoU3)JlAWw$Z))g?j_4h~ z0q{xR!e9#_oA6zj4Nt~Vr(cV_Cip`j_CGjNjpLxD{~+@pUU2 zC4))arvhW|Np(RO!+9Di21&XB5{kLaWp8>!WREP6THGZv8tBLUJHDH&U-o6>MLLnd zTMGtIj83lA^Hx0H^MIbs<#I!irxD0I!4W_=Q^Dx8$idyb5?pxdpPl(24->p}?)WN4j7I&?X0R0$ zKqU?_;P)$pxbHdaHE+gyg=F;hVya>H2w)RAP`v%mKlX2?8OaXuKzfGSm)ZNid#P<4 z22cX_HbX5%8@h_8wpsiz^ZnVV8fDQ3LeciVV!C`pg38cJJUf9}O8(b)ic-#2jPx-Q zIO|i}vAD;c+PE2X8+8O0pZmx|Ht0gF;Az+y&33w&;{fqa>DGffVb*SUpVImFiBg%4 zh&JFtzm4N|Ts39(t3?Rpq}!TP-BSBq^B>&>IWP@bkrY)>@Gz%@utSrm_wjHb{@*+@ zBk$}XoAN$`?FveZn*~_QeM;Jn)W(&?+?OQVr7IvIWf-pA#qRP6D?BY;sp9mVh6)sa z1_lc`>#V-Uj#mIFm)URLa-L@*~0=M+__Z2C#igWgdF|W z-0!M6l%o!ijem6G=jYQN(F+GXb<87+DEa7mO5`iog;%5=WDLjyoFcU+bG%O+oN35^ z8AqB4NK7Qw1j$NPo#2w~t=wBiHWJwgO)Po@Gt*{W>gmm^6{?GcEfg`Hkpp7tQAX}p zpV@%Cj~(2|-4<0ifBl_4ixcnM^dx13M1x?`{JU++xBBWQKf~#K;VbF)m3V?{t6oV^ zvd8fP8x;lM@d{D?(qE>@MU&F+dpMy-&v@Bdph>tHIlI zK`IgG&>r`c_QU7z^o`z%m4Y4E&0)SO+)?y*gZjLd4=YC$s0V8av}^#&Xe>|MpD}Nt z)QQ-jE=70hx9~4bdy^EJ`-r_D$C%l}OEdt<74ZMojF`o61#>fmLNUq-a#gm6OoDfB z0%W9l9cTzPwOAFOK6B1W3oF1wn00P;JP3lSw`xYL1(MXB<<%9B<*3#X8padwG~Rlg-E?rAR{-Bx0mTX0fc`mN#}J%C2@{+#FD1L7S|T)Fj^ zR0WxgZ|XXJrVEG?%~GIJ0L6C>Y$s=?nB^vynHW#>W_wt9mihXY`bAHkIS~2HTEmp5 zm&Xc>BTsUrgNLMh+zo#qm@;>Da(mMl7xH{2!EjL$ae;pb<{i7qUb5)vxz;gFUn%&6U~0ajvYD7I56qDT4F}TYxdO}NArljPhOVi* z%&Y$pumuTY!GwWm;WR2~-xzPHRqCh#0(Nnf1j8awH2&3_$CB9RGTKGK!|cUv;}D0{ z12yEM4N#Hr$;V2f$I~Dg%|M%*M)RzG=gGl5Rqp+mc17dw;TwQPYZ8Hv@e=)6Vl%SI z@C4`N99NacyocW)I9O8{;I;RbY0rc@hAK(8Fpz(+PQo5C#{WrQ_0m%tw3~vNjz=FS z`69{CPzm=B-1WiPmq0-D8TkYJ43eZ)oypM>8HZ5-M_E=yn4}xHI?fM#FWe zh?IbJxej&LFaTcFUhKwIg7lkA;r(wj2=Js3A(6ZvYba*#ba5q18@aDbWIG>*(Bszw zW=M?cGwbel;Gy*4940uL+a4k=uYw-w-1JfS)3q8$y?xxjvzjtbJm2$lH|RwZw&(Ap zuWa7J=zc_wl3%syaJ2Ex=E?hZvv;R@*gf4*lhvO3X*@!L5G!dS9P+cg&?8ue`s2-Q z#Qon{%lg1zs4iB&bsTL&b7mh#F7^c4Mw;lD+6z2bE+!$&oFO&F-K62keINhukc*x4 z{%Xs?EY*bDf==j|n$E}MJeD%jnWFP&&X~6Sd3&Y?)Hq0v11a3mKzs!(kuC-VssE8@ zY0j~|ke1G}Y7AZMa4m(M-6uyt*^y7bgkv8T(FGh&WpZ|RPv3wXQ#v$A-vnXozkBP%ca+~(mo%kPyjF)S7H z8!?jDh58YkGQp&~opCFtr>*talm&@mKay4w?g*vw$@Pplza#|x$Wh6*7;y9fJbu{h z-KxDrn>fo~ZW?xa&X0fB`p|`KD2P{qVJs0Qb^q1A8R_?C7M$2EW1RKb-Ey^`xXCW1 z8DEQ`rBzP`r3y9+wl5DYe~eU%442z$txjeg>fSwYs(tiOnO>jxss@}wK~-xM2(%Ju zhc2@3K7x;Eb_|)A?=s3d@p;SK77>z$4X>b|*G=z?uXDE6yi@$#Jl4S?p$s^dOsAqv z0Of;tnr9KQt#?JN!h(IGD{S40iLDTuzQ&%$t~uBCirad1G7@y>k9<6=?%re_5^i7^ zVj7Y+dNuyFy}Nd6NqZkHjTWxf#tC6FK9CHukh$GN%+7eMh3Z41BZ?;OY?@`|**V{~ zqCcWtyMwM-z7$LHV`yrKA9tyVVf@ zQ4)V>BDx-AE69)CK%7vtsB{=(u))4ST>_ zxd#%(=<^T8w@_TP=&=Gdl5J7r^UZ29M?YJWq|TN-q>r4JpJd*SDt5s>usN{QZ-HpM z%cTt{t-5H%y-ep7^j*~rq@5s%pzTEodH0YP;8e>{UvbsjXcESI&;-kZBBB&%pxP~`}=&sRQ%#?C9#p`<$pZl z6kGHI3ZqTt|x44!cYGI6~aHJ`XO&aNpl`qRBFss~OUD^TL%2Rz+htZxa#lLqpo z-fW=xT_!ozJ!4rwts^YF`KG#J4$-9?-YvSi786n`JkQ6{JDiE#FqoK8x5;iEBOTKO z$fkkoQ8(*W+5Bsu6b{HhWoRPr!H&&NX3IU-H*$dKJZ^^v-+faticj~bqBu9E%$yDd zo%MIq0~5?*(kM?o!MBol$Vre5IAokzf&6bZi^wYZWXjVW0O!!P7_bslU;A+gi@JZo zG*z&z#zY%!adUPpK4k5b&$J=oA$br)N7K4-=EWAkNcT(wA{10>&S>IS^o;+WlOhiB z-&q7^%jLt0L!}P@Vo#+q59{uXsP}6IOzQhg?k^iOdtW098>d7->NbeaHe|<{A7HOH z++l=p*wWv?Jur8IR9PkF%SRrT8)EUZJBI<$?*f!`D)td8GAu&I@hnfbUu$6LE@o(A zr8jxb9(dkr`2m~Tq6<%oELQ{(D>Jc#@T$HOoZ6fLy)kFt_!HhHl zQvXv~33$2wA%&#X#a?X@fvegmSozk$ja+mO!%}X1!#Ej73tbWkuAE1#b>5+zmH80_ z@x_i0b3qBN;tgPrE6ZzRVd)H!k!?q$ymo0Z+(9;C;Jq5dkYfrq!#%+D1if>N)Q)1% z!AkpsrFFIjM$#ADbLNFGhTgw%IZx(aoDqNhfhDlkJk_A14HUWKhgb>=l~M+61R-Ic zyUX|Ytn*P9Txqwu6+5ZzNcR+CwIsGeqA|I@+~I`6Kh+#tgA34ot3}TxETg+%?xJIT z7Wm=B7)>};zDNEXPf5WniGePTV)d(^r{!(t-Kn2p<* z)3)L@(B!6g4qwDCj_)QaZvQ(gssT>|*-8dlEuDxVnsG~_oD+e!0tI*rt7ncweL1|K zZw@~rU>OAS@1A0sx|qPu^4n!!4ra2Fwm$fxfV%oY{`EY7LhHNZCrW_xgOzqlzt8SDp58aU#6TCLAiH2AbC+LviaYc|GL zTYm(}Ku;dL1+D5g+yxndJr3ZL)g#VYw%VAn3#4&tna9CxzX&Wb%yr3E0rNO>h?+QRc#KbYL{UYCm_nmHsFoPf zAajubC_*_rMU|Y?=8l&705P*3@MtFE6pZ27KbsIje@5qKOjF9aO zI|AsinQ5JaiYGA*D>^Om$w=o}Ed4T)F6iY>j2PA#c4;9r&4~mr{UB6RWnK^cATR{pQ1ZuPi0!_hq@Pj(pjlI=NWWIa%fA8eAnz{QG}?d@JUF*8SNzCOkO;=|F!6Q% zk;wZZ&_N5{Vp_M}&=a|VK*>y`h8rFhk#-k8Aq4dfm%+3_{yk;^t28`91HPgN)}L&V z3?BGOacqfX(SS;Q=d1Nu)zN!(C|++BZ2?P7TXM;kJ+lqyGi-un;2U^8SMQktQqyQ) zA5l6{;oNZ6$!O%KkvqXM^{aI?Ded>rZw81uzD_|w7!eq-`RkmBYcv%$y-9VMx4Fr$ z&YTY6u59Y!nJ=Rs`yDOt;b|ja4Na6$hgwu)Y<0Z`wT5-e3B8TKCuz$g7j~K)*WX-EgxR}xLD1DrCJ!cLS3LtEysX?X4EQ2 zyY#306^5>)zP|S*g}_5QIeH@`IFmcE5-gIYyyEUUu!8}LWm);&-L7?p4;BbbND41E zY=r7I;x`S0nUYh5@dcMM0}B&_1u0K%j~Q+kaYiO92(pNWj)^9R`6=%+45wPtv8oFX z!kR)Q!J9S~W3m(rIV)67n+vFZ1ZfAKNWKKmN*abpzfFfcuaTp`qbB3FlFG0>F8G^1S8r#R^_a zM6uT&GCaky;02SF;;$pURU6OV8{B=Pclpqr9d`u}cdS0RmohpNps^18V+MtN}MFeY&{We2#gIMNQs!9N`xY@mc<&^?Hv{ZS z)q6As{g3cDuFFb%kSzUquBa2!57pZUQsQa==TuYZrpEv+f|nC~J!v+8-i76H4#k3= ztgJb!){9WEwx3`>n>rRa;P4NV#;fS7W^!4Y7hHC|gG+Lr^QYL%;!$R36@Y-pNC3oh zNz1xYjoTt!V!JOVPa-r!W7P ztWXbwq%)Dml4E#bMj|TAAZ3IQKUc$?RDHbUxLlCH}R-ZbX69401Xb(bxae` zhSVltnVDZxd-2i3e8~fgkYZ?LdeBBi(B4Va& zr)$K@BNT^2`hr9u5X7k!3)#tJlT5Bix;53XNHH@g1D#Wlgr~*bgQjP6pkVo+f`5l$ zdGll0pyk`kIq2wU4waYh0442lb!TJ_JkRVIJ%r{qZ3%+W?9b!1ZH<`@Hk7cPP!W)L z_m@+SCK8vkF+aR7Pd(IS`6kP7gjrjj3KNnv!rFLd!!&&aiA9S4LNfujXcvt9{MM+6 zWF%s~r8GO^pa)Ji)PB@$-{$90PKF@2Qb5*YE*Ovlpi~!wF56Axmi@Fn*zT6a_kc!EGIuvy%k$FN|L`5NI15{Zg|}?GG51&qmLLx-d!pKBIw_S8}#A zfT^u|i2xilip`ZDH?OdFH(TNUWYu9a`Z7$>*f5! zk!SGcswgz(o3++)$sR7!FX=1+xo=ZD{(BP7$nr$`V+}BNh9!sBd^a8-Z;z%sy0Rgb2Q`cnjgp+XsDJV zJK~HJ@RFe6Vwc(9vXBj$oek|^7~q>6qQ+%3sPVm6Zu(Oo?!((HrNTGfgEBb`+(6xO zkaHFEW;D@m+wzTwR_&|cKQt%LQon%!G|D(oTo9MQF)ZQ)l-czUDiL-!3$DMrhK1sk z4^o05?4I&ZJKBvK1A%k~g?UqSQ$j9>L6TJmZs;lI7xYEX6k9&sZE|1U#4=lM?2H4u z5j9^E$YWCuysu%a83ovvXNCsjd_dm!q=Iq{t18OcT`#xvKnlm7P+kdSm}%?wFz|QP zT5)*A5t(-L1?>%%7c@yi4&)3JzxFFDO9+ep2AvKx)8q}4mbsaz35M#yAj9T*!SOjm zG0u*`a@ye=!Xul>M?Tb0raKOK4tGROCMsCW>2m!-ggQG{Cx?n8O;8E-$`!26U7{=b^M0P`$Na_$}WVtLSeq zx%W{HsL*Hc=+bSbIJ$x8Zv?Yff=!A3wj2B^s`3&8!Z=46SXUKCV*7=ak-7CHQA+*^ z;9#WVM;^*8FL~o}EczOVjS*oUUB#c%Bn=a`Avlx3z);_U^7s0A84)(Uzh;hHi-#jf z<9lgOl^D%Nx@6bT$)_&XuqpSqH|9R53*EaN7Zi%2QoSKXX2DOlF}evX6W%Tp^I)DT zXzn3vy@#FBhr{#4m2ip1*{dqK)dM;5s!e) zy7@US-dKPL+kTBy!pv7H0qunZtWM|e9J%(L|8Y!~C_h=zK~cb?e%be|*?-yr1Ye|f zzc<}giT?Pk=)YDQIFA3{ZK`8Gr?vraKb>mL(ORR=(B_Hn+FIATk~mbAE?YRQ%x&wd zgR3Bt$XokAE&!Q&Mbr@i7rLS^=|c>lh`DyMK9L9+61J21pphMzf1wYqlpyi>$1YxM z4S!IJzKQs<;M(^}odQrlK+1FjNLe|CgVITQjfY-^m|waBjBu!R`uWnSvT8?+i@uR; z0s>;YFPBrRQs*E~Uxm0(KtZ$5V0nAs?NYQpL?nTeoZHWZCg2@F7IypN`U>8XpFk@! z--(>?oq!+@{9edB0XcO;kc_FA!@zK+xd_!|mx<^0hI3cS!)8=|+tkwUIy7qnT)5+0 z_b1_JwWApy(+BM~~E zl_&i)WF>n_U!H)~rcm#F+@S|VydiaM6%3vt5hYHQS&f+7VmRT~%TP_U*%%fWi(!#h zb5w?vYI`?nF>P!78juHVBPq5!eXliC{@@kBmP=irVqXcui~S7ZEXP~9ekZ2CT()ue(An{ zJZ_?Ep(BalgyA2@wE3TDP{l#J8;3*r6X}4~&8+%&7Nlf%zKQ#2f7_<0lWTB{qPr8= z6|KIZ8>z2_sT`1_s0sxg^+q0yN;Yo=aOlYf$N+-+bTa8bIh?|X8G8|rPa8uB;?4g^ z#;^ex956fj!YN>o3&AA(=~plA-MsSRUQDyn;HKe{|L5#F`_hY?x3%cw$ew4$FYa9} znN-|AHXFNBH{{zqC4K9loFry1$^mdx_sc%JMd)rh0$54>!wS?&Y(!t*rvTYoeQ>2% zlX_pSDp`H;x3eNVBUW4MDE$^Qrh$qDx%(4zYEJEpgh8!?=u(MiKCulAj`T*Gd%T%t zlH&bX!-L^94(`v5)EW2oM5>)FzecxkfPA3J*bk*x@J{#{%A~Mx_bh(Xe34r>F-`Ho zuLrRS>2F{A2LyzgXAmK{HW>C4_Xnxj$O3~NYsIp8m=65_8wpSqal3|C>f0p+mO0VL z_4ttoL1@|EVE;?i(GPO+!FIfk2$*C)=VjnTf6Q)>^(T|3kLycWsQ_HC@$mt2L&eb1 zIJfby0_Z~n8TZtp?q#ulo#HP!|~%t)6uZP)f5iyJIj1k+Wq zLW`ORO@hx0joa@?SJj_6PNgW_3uk5v60L7GF_vrw>^CtpXJ&ee7#;=oFl?KCrFM+1 z6FHLr0J2&*P1~P3L-|!t9)wjwt;(>axX1y&>E{ce^b%^3a(Yni6s~L#DgdhpqIj~* zblXf!R0)A?7|qI(!Qh*B3nZah3~r)V3Te(|C*UdTUaX;zj5s6^jVR^ScfAIVuLHYE zINiLr{j$Gp&`-&w9GIfu)t>cV(_WK^YJjhw^rDukkXlEV!l0D|BIZ>qu;;uOD_-U_ zi1yb}_G-NASYGHTJz{o`#`!w*4| zUyRu@5a4$xI#MyI*p`%qBt*i6!pMcea8({h&QnSG?H1`46u1^ig=7S1iM)UP;VCIn z>f%EeaaIUnYbwU7LFdTtZ(txJh7%BQ*cIzeE%56pdA_hiQ%cu6y@j#~5!zG5>LT4( z*QSMzo&OhOZvxcR{l1IaYNd6#PNG`?>k{grBV7E@R!ZR03FB%N&P;AF< zZbtE9vAW!Jt}a6Ddu;l^Xc|WwD4YUx%y6D6%F3aJdU^U7ym1M7{Q?Fb?W4(Z0RkRr z|F0m`%<;JuzbwxW_*l6FU%TH_MPiJ2Kwov7i#O+o=Jg5p=WX>~qlif1fcwW+ym(03 zzB1QIndlusFqC6(C$#ALctd++Q}igUI5fyxrdcP|X`ZZU3d$g`qGmA3SGpbHMwe76c*4~Ob@r(H;5C-~`h zU6;$-9(rlqZeJkm(+R{JvDEK>n$~UP$fE8Czow5G2slzCnj(i+cb!dn-qj0eGBr-y zHu$u`W0)D?Jwp!(bH!4fF^&<&P4WEe^GeX~*rA%`sIxn*8JLMA9@Y5wE2UVh;L-kE z)I+P3z@pO!YPb>QJT2hxDhOhj5Q!8VKf~EtrU{4CT`_igjSCk3@$6aBZ~0R_ZAO}2 z^eLwBZt^Jbb#-nJ8@MsX{%z7+=Z52~QFz&J^xg zIGSsvtYssL`&7nr%>K8gw&*oa10VweY#$40!-r-MG#?JL)r3d!y~oHdKo;U7B{sKz z8jd$5)U%Z$6}CA*yTbh%5>^e;jff7EA~^1TZa(qh2tP$iB^_OGzGKu7(eUQ42UiK; z70{m1_=>}QO^W$fh6(*5HczjaUVo>$_ILM*og9)7rmNztHLL4P{;NQ;z z3Om0b)>1rC1uB;wG_1_n2;e5bP&6yqI=|bI*Vt7!%q0+Ex^VE${Q3@?J6bTxM1H|$ z0PVnU+LImkjXtoTeCQ%7^|5NT@Nt*QgX;+fB~QTONMIbz;hMp|+;`WmOhgn@v4eNO zB-jMV5Im_lSnt5Ut(HsiIp36jN@(`0ZU8jS;F!R0T`e{6$ls zFuO*3_I=J1uq~7OTdi?t`f$KKmuIq)k|Aen9DdX3wf!ckgjVH0^_|fjZ?^iH_-)EE z8M(CJQSc6st-d2%s~oO0zEKf`ykXIj1= z;5+i8c#JV>Ps4#O%l{Lq`Z9C};HTaHj!m0@8!p?|&aTF?Qz)Vy;#2~#p!VH>XQOvX zw$m_?s6>^h3@(RtKh@L);_cAFAHitdQko4VIz9~ZW{mb2e7mk|MQYR;fcTY2Y08gG z1M?~~kPEJmwQ9j)ut4$pj<1ylW}~Kh&K@n}14Fmw9VJxaR$?QAn_Naru{DOI5T)cj z9vk(qJqYC{=qWc$FTqzN@21kx1BE{j3K$H=urB7J=I#+A%e<3^?N<6!O2Ap1J>co} z{!|YAkJp%(NP2^TAav=mE;(3k(`5He*wF>q@FQRIjJ3!MDzUbX)^>@rClY>N50~7H z6X{{M#R-I#igU78!$Ic(S~14xRn;?;+|wz8bad6zFQx3g8fBMl?6B~|wD_(sc!k)13LJf# zX3upWaGR7vw*I4j5aAkBm9%Y48M<)KAR*OfSAr6L%4$!|dXHThN{Yp^KfE6N=@4g2Alnvy zZOG*vWuoh9nZy$n7oIhC*PM}9I=>q!mp#w(JI7B~Glb!XQBbv9YHQmHeT$mRA-8ju zYQ*^E5*je}^H&x)4UlQc{VEN6Z{dKP^nr>l4GV?7rC7Y9xq1nbshGnc8Rne9&yVI} zp*p;bBfw)wr3nXL=)C6C*-3t_JIzPG5yijPItSo8Xb|>nqo2lrRKlF)64G;$%*$;n z-lKblMj1C{!fs_8E=1pNEC0G1Nk~O>aN0MNVfd8=Z-usnj+;IS!)8NcV&*VNJM!5D z&+Xm7tQ9}7r$?+%DS7lO@Tkvi6xse38e-hMLUGZ}-~7*vt;UWiXxyVblwJ!k^=iyZ z>0khr<2Qfa;0fq|tOat6{ylosLGnA5g5Y)Nb&gzl7beN2hW$g3e)W0CXa-gxmz$v1 zWP`WRb_=F$@pWVjx6(-rJQawPvvQy35$C-^F<4L@+-RpnW>(w9?8tU;HLq7OU=RfhE zvC}UQ^mNyhK#;cnDy>p;mJ9Wx{$t5!NjH^u)hdztC3tvClJ718z8^VWK;N{DQk3-( zEVeiMNkmwbLbXH99I&YSJro5w8*hX`AtUp79t59+=EGc%1BX58gU%C0Ivi==*uY`_ z4v;`#qhK%5`K$MVt5NHpr3v_O5uYD&B!f|huQa7|OH$YwW&}fJVGiDHe0GL!w>|et z(33eebq^ThQwIIS9aK%}n{SVENy`Lz+l`2Y*aR>Y2tz-@^6#(pqPS5SA zDyo+>4Ek6T)V2U(V!wd-Nj+w(Q!+`aEAStQh_H}P{Ab2KycukL=Iq3>@D-kLH@X$H zbwL~ObH+>le^iFehFz;da1|_Ngn|yNd zt6e$(062l!1gk<|A5#M_hUZ(f>#hzt!7sokio5}y6KWYG6pLsT@Y$ZHbo2+&k7WK7 zfoO=+fO_XB>eWgdk#VqYNSl+w`Tn07@9f%D&{f*Ce$di{CMW^2QdEDKgU^q$r}3-? zY*TT-qN^(b&?9V@+p}%xsNafKGCaDDBMOciKP!;8LcxQDHO7;6!^c2U6msEqnlWCz zX;Z7UZm~N#X+c4mG)iYf1jaOnz_U@lH9x-~FN(Ug{>E(5;JB&8REJh`JYv|a@S$(A z&hb%8Lv%lbr;r9v%(^RMp(UqXTmBsM9nXDynAFz>4tV6*Y1SvQ94DR`>DXd8QtE&8 zr60H=0|b%+Z`}2W*mtaID>AeRm>e`xqp*jSi=(J~Gaq`c6T0>&J70olx59KQH7E-b zgMhHD4S}bs55TNT6dwbjwEIS8p&ZO4G~9|q*+X{2^}S-S`$eU(-c zNt3zblDTvVIai&m@8<}a0fZ-r%HRF?=ucGX z>L)J_m_siw6eY+AqQKB*zJ5^y z_`Bn+7eN$kcb(!-)0*|y@WmCloP@&TlmiEJ3?Z16roDsFrH!>Pfx+9p< zuwjS^+{`4cm~?AHr`JjYcm(J1#B_A&@<22}<{e4l4AJbU#yNvlkSU;YLe?E1eR2ok zesv~@xyKPDw6h)h{4=7_POjeaW384vnFM;2IskLgxM1L7XEKPPp^afB&;JN)A8Ah= z+i=JBYfUr$I=1hmZi`=lD-1$v zA(-g-A6oo}6dU7lN((X@K1;n^r){EU;AUKP_{RM`LZijOTRlDGfNdXlJTh*2^kC5H zETeujju1#w{({v)CumpsGLU=vEM9}kz;o5%Kvt@zEQ2vC;nuF|kP*gQtPEQ)*(s&> zBS(Qj*wyk|aaQL;-DloSw5D=;5SuSEM4M#GFMk@{0aSC?mwlM3z~DStmJ#sXzyBhdfSFX^zIpyUK`9?lFQ)qZHAS3W$E8S{M{qsYRX9j{fF1 zMrKANZY|t%Uf);+7!qNgro(Y0RR00rWyr!Il2FaC%lFL;vpNk6#(`h82%K~J-uz}m zb(uw2R!9p+YOjMcV>&lWgZ`dOa$_L4DQY>lP|Q__cJt?@9IKnOT(8ExfBa|0j$3;S zcp)vfr;+q}DcrXd>8*EXKhNMI0EJ4TcxEd|>5;XQhvI)Sy1#%w#Bi#_RGv)5U^LiQ z1f0o{^+UND-3Z7;pbkuT5FMLL_UUi$GQ!R16@Ue%r%SCH^7>9+aED1sUM;1#B4unu zIp)ERfY?@GwU;K_4X82RRcMF?KTFFN zIOa`*d`-H(hN~i6r4X)>bm)f;o@)sZ@ecchzjx3R1$J{gifUL@rkupph-e>89}y+x zeG<5oe~R3{YdAK#nl`8fuGA&x4$=Y5``Ay)lXjaC7pap5dve;`qz0`@sepQ|hpDfr zGgHp$;)h9B`KIc6XmNslYo0@Gb#eHL6c)LmN1O8;JR$OCwtsvpnJ&iKLMyM`~SGrsA;codEaDZ^8M@rtBdT z{?)}dD@u>z(h2EIz3|qV?(cs)wY$KSXPA?OK4+g*Yr(Whd`hzG&CRq~M6xzJM9cYJRdBv|S1b%c6Q)<8NY z8?P!$)wBncHLiUF$ca3ogs)u4z1W)A6=&a)5Z{zc?F)Fx+MExH8j1ZdNtf5#2VRyx zaw->G$i>j&fL^e{I5v=r`rrc(Y5FVhkieTU@$lG(zf+#J=;|8wkxg6c54c<7EWNtpY>FjDOR<&hHVE;BKGcPW!Q3|`&-PF|m4skvaC|nLYLNXb4ol?OwAFQWtiK5X4?_Ln9R47(U zza8p)jpSEywZjTDh_8@4W}Zdqn1r+`U)^6RCjBBzUEPp%B5O5GSPOePi`YliaS_P& zBRMNl9HY*FG@lO$W--ON@hv9aLBsrk5&izx}()tg&Lv#2|C3&OxYE zuk5H_8S=et1ZR1N#g0hs6_4G%QNg_U)_!8r%iR z-XgpJSnL$m;KxWc=~H|Gr`Josd2M%zun_3c%nxZw>Ue#Kw|Ix~Mu=Af(9GzHldP4N zNHU8-s;LU34&(6l(p>5(fK-C=DPP$Bz9i{2k7G5=;NHM34*rjewK232> zS>L6$kS;j0R8tHTB{CuICe$uIGb(v@M_c=ua z=aA#)N>10P8y45qN=|DA`8^uw58|KD7w;FZk@!D6*C%)?dBv&^P z_b3-H4SFtgDgDT(jusmX@lq9A;8(eNm%j=EwU0kjeB>ZD2%1z5quubin<5V{LrNdT z>X#*HN-VQW{e_91AFd~#0Fx}h)QDmSp1A`^gs-i}3(I#85}4NREVSosjEs$%Euw@e z$9wEHQrO|(Hk_NH@yrZ9@(^~Pe|l^|NN|r-qLL82o;*j8#utBYo8?L_VDxXAh8M6A zj}EvX3NOPiTRBcFm*k zK33U?@1gJviT^?5Ia2pLhxCk?_%JvKdny%)^fAF)nYPJpxIeMxhPNQO;FpiPA<+$% z8-)aRVqIij>ELj0s=K9twpcFl$?XtAEKm=GPt*rN_~JE4t&-JI5*8gmt{fpAK$ZNv zxEaPwr+*=5Jozw#)PT-r)F3rwT!T_11})F*iHZ?&w4;q->-qn>RTyGLDzRG9Sa@~V z7@OALo;U7XjXxxB<_OTn@S8GX+F2FZrt{a{@g4ZnUDpW{fSs00s1=bB8SytwJ2CfW z9oXjOBpKh)>@?puR*=MWJ^aeO{FHUy+4?9l%xG=Rp@jlf<(2)=7-P&3YMG#_Y|`KA zF8USv!vId<2FmSdid@FYxCPmReXe%{~`hq94BKoElG$6u+`a*4Q(}& z7;F>ny%~^<${LMY(8H>d^<+g1(-!D?>j;`b5U)KT-m557`BHG#e}}uL`iueh?U(IQ zo;eN?bXGL_yAv6uIxnwy&UC~G{yXjwqrbq&Y6u#+;olmc1@-Ny&4~I506H^ODC>Ts z*GT%cjf`UaP3?#&d zbYt;&6nz>17FbF=V;A+6)RIASQ=v*xknm#4s#ASu&RAIY5=eW=9bw^FYeug==q=?8 z;wm-()M&Di`bS)hCxsd9vha#t_I~=avZ=-t>7W!h)l+2^WrJa&c|T79(0PnL=>ao> zeUpNz#r%P&TB1G-Pa4&5oJBW(n^?+RTJ_7-1)OIv*G?(o1bdb?rtV0yT-xfpTQ0zQ zg-l_;T1Yr5rSI+GlG;1;cyKM#l2oI>7Wf~msg)hNW$Y)9-poXZ2k@1YY-Q*bhjo=s z4V(sV{-h@&tlW`gcfDbU;|ucESN{MbX;UTcpd?;v*p{Ep-AFYMxe!oJa~MCqnZQ#= z4hE1h=OkDLP}`t}p4J65f`qd@;i37-V3G(@sx<25BMnC?rsHmGo8G&h;DjFq!94oC zGKi*`|16i92s^5%_z?jgy(kJKTygh3#hibvWNn)@#+&A-LE>mkq=V*U(V1Mw+J9#B z9^w+#ZX1gS#fc&M6TZCiYcWv~T78+H+-Bs15dP6EPTcb>ay;!M(G}+JVCyl{@B1fC z1mwF7fKJhlM?DW4MpEx~WePYo}Ly>0dRJ^2gIDxSK6yGTij`HxwJx<9)*fkbGKUJr$Y5MD`IE3KBQ zrFWCTS0^PM@73R(Y6Ep~(uqR@m2K7u7ecfou1YQDkdh``nxG$j9hSfx{2YZwqn}A@ z+m?0e=eyDPHnh>i>}ad`E#ex&%H(7iBLofdc35hX1#qGy`n!3d64) zyP?IvXa?m_Od)=I)WEAqfL^*XuGWy9nyoC}$C(0E{NL)BHBY)!$pK|ziO+AKWTN^6 z`1sff#cDXor1=wjj;{|x=CZ#1B25@y$He*a9j{5DGGUqobOY3iqf>=^p&6b@ zlKBvIKia*F`ZTvG$^S~qHhLIoiKlyD%lytp0T%r7^ZYHNp^k;$*VfNEeAsaPlIh+Z zJ8hPDne6V4h_9`CRwwHBg>7wPxb#D%VEA`TtUXKF46^TPc<6J175K=6l}H51)H??L zf!Py_q-sYd=PpY$o}{Czw=+`U(7!fINFa)*Hkb`FzDj`i$T)vKi-3Opur=8t0`lPk z|BPgdxo$q&GJL|_0vy(bopN#Wnn`df5+A?3ih9BsI6Hw-18WR>_xu>fRde)Wsd}6h zV3ApNJ?c(xta5rF8}mGBmAyWgQ_JUxKi>3@OzaH%xG!+$tN)Yr{j#udD9$wnxXgJj z14P~x6nV;jZP}2LmjFU~?iWR|Hoy1n&T0ZL53farimqoEH=^740A7|Lsv?*(VypkD z{zRgyK`qe3NAWwdc-*_eAG-k`rrnd}8q;h(P)L>I?jNQBKtWO@jPfSD&?PGYFLLh# z0WaZvzcVSMz>cnG3onwshTDlstnZ6->!nZzdZP4-^d;UZpA}RGpTyu?F)6NVol{IzejAV#|5*bb3<8mObmGn9G2Pw#O$lDv?mxC~n36tz z8rFZRFlWGH#fyZbzpIu7+C3#s(r7v2+IqFyDcueE9Qg%b0b{AV2b9Q|yc-IzQo9!- z(o+Ce?IJBnNcEFDy-uDV5ZtZ)HiWy?SY$bdb*pA#t5wD@@pbBJWe+m{7%6);`21f) z?>(MEc73qUy583&({s)Jg)&wuofh?MZY7dynZPI%ygm3xmJ>hqWB}m=-0fwe*W@JY zL3rq?uYC$Z2cGhfMmC-&byeZp2_>-0{`q<|$v~jjz&jz?k=b!TKtqeOlc{WcO?<&- zkkaW#@mP|S(5#=sX=3QD&mo$v9gh8x>G{nh#X2Lhe-}loS2-ASL6aT@I7ChhY>)xE zNcGTv`2K%Iut)#`k?jQKG^d$^usk;P;T_4~Ojj7bTl(3IJ@{TqT;?uBYq)00$d<&1?*yhOfYTMn9_? zLBOTpvgxt6TOJk5x(0WQD6!GQnHKtkxeBHIZk zV{Q}&Lj`y#9N-L}j+&!i2hIb&(8Jxwh9H+>V?&17f^dWnFuP|K*D4e{+*wvw3oEo1yF^SCtwjltX7RGFQQM_ zRw7R#T|Wb)A$Oh{q@7t$Zj4|#&+d7V7KvxdAi!q;qhwA7r10V3t#_h0J40UE_5E)C zm^oOXs7sd64}iJE>gD6uBTuK#h#UTcc!+xJadHTkke$L^?%S{mogK{qm9syWR-0lU zK;e=s7S$21xS|cl$=t#Lpgs1Mb?P$nECqAXvY~X~#0Hr63M@OjKWeJHw5N|Z5f8wz z%U|d|pC^xPVVVdhJT$`|;GKuT|DG?akHWsi3E&z2y&e*A)lyPRmUlJ~YoYH+!Y$#_ zWS%D5xW$(Fl9&dL_{5&~kct4cVG^C3^eTksT?s&EhYhoH43KqlAXb zDVwL+==BuLvzr6+(m~@SnW%)riPulc0sT#gGJwFShOoAi}ljPQk^_Sz5d58h2Mjx}yZ@$UtXh9^`Q zqvr+4SNxhkVsiZwnWNjK1|-{{!ZcX@hS7$S_VP!gxg`{akIr^XU;HUe%2j)X$tIos z*@N>yyx(p`1vUO5n8x6yN-@UK9Y8rl$x)FodiR`yDO*>wwb z7qsG@=ckYB&x5j!$|*GgqNNlbQTz9kK22>qi*`qS(10TQt`viM`1sx*!FC!k$vSJ! z)Ya;Do_rzSd7O1k2g?fkTlq6tTXemPiIS+Vf)Xf`&Fvrv06vS%u!IbHMgc`^4Vg5M zol&?mQSgGeXm?4V?|QIBt=30Ske(h(*Fvrs>gf|RRYubrozpNDgn*zy7!4+SPbwV)Ej!jk_L#BAIP7I`pm>Mwb`wGh}{*_UKGk0can+U;Os zaJbqIpL3c4Sh0LT2MzAv>a|AySq1}d%nNKqC!vw@ALEF+U!~x_U(6v5i-0JEA2dXt z>x6EJ%1pTnS8(-Gkg`Zb9=DP5T??d$Q4sf(DLtLGf>_mUD%Mj+FZRdMG#_#IBr z$)1F={1pHjnpGBr)Z|`9roIBhTn;O6Mm^yn?n`QCZHC(dz?ZDrL;?p&z_~g?)xL$m z59z-W2@3|J44ORTGADz;(v`?p@$q!Kg%r3imsV&33;>Zji=N(4aECwF6d>|0xCEXD znPm%f#d7PUP}~+;7}E;)_GA$cM8E(`&*E1bpJ(ABl40+O3$mO~0D^iy;*Ru(7+{yfku_-DpC$G8C|h!iiwujtOtkeOV%Ac*?1kjlpA zoPCM!tiJ%J1m?rv9Rf0{3>;EIHWhGK0C}K3f~$t^@O2x0xq`dtY~SmwspyK}FCRjk zW=|P{Ci}hZR&O}9C1(Nc*+Xp-m@P;Lau8@xwX#7RA^p*7B_eibD8*bl!q5l21&^z?aw$85$iN||g+y#2^>qzLW zj%nBaMQqp~J}a!I{@^a7HK_jCRs-K*E7yX#wMc>*=H$THOfJNoNzjOMzvK5%cSw-=+k8 z*yO%hZa1uX6kU8KFSv-xCsT22oy`vZ20R1NeE^uZjh3#jb71HT!g-9b8td~y;f zKcK)7R$77YG(u>BgKF&mUGQ4+M21e(I+|}1y!$JLtKtxqqG0xyAmbalvEZ})Ny(TH z#XY-~8rqKmy${@6s62Einqw)h=u%fy%v-bN7EI%!+6tgs1~w^?;IvTwp{GZ58D8Eu zol0Jl(%?>_iMWe(T+X{V-W65);_{5zEG;W^j158t$eBUHX8v+_N7*OWlsg9XMAGkZ zjH7ag#>z(}Q?WPj59VX+y~zfkMC8+#ygN9TJ1RAh=)Xf7!TNclL|lw%;+-|Z3hH^5t1KV@><1JTdfpw6 zT*kz^FH3Bf2_^{{`+@jQNqCaqSWCe;?O_1_Q(!>*C=uY~Xd{`yrxh_&fGfPT5`IOD z<@W~+8B$j2G9JIASx}ar?veYfR)9m+Y6X51)y?++jywZ%78xNgR3iKgCwg?sn>JPL z1p>rsa383mE>;zG6Aq_cB~(dUfqL6nUDzX^2u1?&AhWKX`wp2{(MkoqN>UIXbDngx z0k<-EX<}Aa=g-UTZnBf(wG!Q#{AEphW1Z^zBnY^BVW}GPa2+&v!)EWJT z6Q~i~qt7c0wQzK!4NwZA!Q8myn!Z@G7Gto?@d17{KNWXOaj(lf*s~#GL{3QW;Gw=L zgc0~D$Q7dagjR?XY%6-SDzA57ZFD`Jcs@C+u+fbt=PW(f7))S~gdP1v6f=WVRfby9 z^^)r);Q`;@;t`t$02pxc@lW?zTc=l6Fx^8P9Q^6F5r!4dBQfaUzXp?=)_>VEgoNMQ zua6Ua0w<^f>f8||{gXpdqLW#ivuMo4 z0tZt$GL&FIV`?H95sE9ln3c5IbIfCgd+0?oEG zY~0Q2skHEk4*&;k;!O2CKZhySlj(Y#l@w1Brdr*Mm=i1DWfuG)?Rv1VJY2CL={(Fy zIrQM+BFDnJF>UIZ9&RHK+g^OTG8UpL1?uuM#~vM+1eMkf9KN%!Z2$d%dRA@!NrghH z<9-^XJ^W|JiipDxk1)yKoGbYLOBMAD>{o80jgX2Ow86A8Fd*{q5BmCP!<>l2_hujS zKp?zvjw3RBQ_452AUma78bGH;I{NR$j>)`#ZJm*5$Hu?tEX0DiI!H=^Gj zPY*(zS-?!Irh7i0K6&NeJrlhOenp0k9mMkCurk_pe5OqM$#XG!E=Lfon3BNnV+mIX z%AZAv>W}c~@6+~)6tb>l4SePcBjGAoUh{yCK6#NDnWKp(i7vc= z6at{qT}JF~jLq-N#&f}NN>r~&GodzjsvndNsd=v*FZ8t*l?IY@POr@u0>VjlL)XN? zx4F_`)eS|)onWN0@-`3XlG*suE_bi6v9~q~&;B!|3LZYpYwndYPj~~<<`pr(@(;dq|emyFvX;myN+a41nT*p!BcM?c`*#MZ(ytF z;kRIMsU7uKkKa~kW>$@2Q|FU0avIDop%7XUA&qCu)g~}{X~V%603=uK)i)$31U3y< z`Bc_QOOQ?VhEM;qZNF=V<+||E^&oPlKgdg-M@bc9^LOk=wyE*7`{f<$z%%<`BS8Q> z4De{8AKQijN-HsUqTHeXarak7Z>o(vZi{aamqU-68l?5{X|YPdHRNJxcfEV1hmb?8v?VHn5>`q0#;i9dT|`qN9av z39e^oO2O?vKvclp)Hk|R=d!{Ox%1H&*U%qAr}|dQ1}_;R^1Q-B=|}bZ0zn7X zKF|YmD$b^uy^kYZ>HE8{Wzy%EOuM~Kd6J4;b;y8psv2Q_|4RH+13$2#o3c6~-&eO| zC|Ai)&t*8ZtoRe2+)B3M;GWZ!(-^cN$$w%~{xIg$>`C~5Zoa>LRJ6jfqOqK$(u4RA z?@z}2AF6RbLn$#AJI|;AW3zkA0J1b6{8L*;SabcgyN3b(6W#fVg9Jy9$YWIxY?>sd_(=h|AmI)KCB(?PtWb){*G)h2MGZW*%M*%~zQP*n_#!v(*Pouor|5W|dp^#Idi zKy}9APbEfXQh*B2*5J=p$^EZxKrJ799(*Tfl|`FpherTO3Jfx3n2iu-p|(y`Gz=aA zii>NTo6qMPi*3+Gu{ljH3I{ckI9YJDyJ1^Q`9N^^it?_{r8M*W4X{GG02XxdF7~Sl zf&TsQ49}I5!4|TDn%W1nQ;2*GPoqXt5@lF5?y-?f{Y2c}Rn-jien%Jzo`Gv1zdyb{ z*_C8VvC4H zZp(^ip36V%?;`+7=tvA>(Rx@`I_ik<`H>1H2y37z+#u*Q1&}6RG13@#%DPvKQOM>e zlRpnNb2Yil+%K<6*IOkEs7u`^bC$+izj+SkfULnO5w!Xy?kKF7eT%bYRi3b%D57%u zQCZ}!h)Sn5Z8w+TN4yDYoa}pm8=DYWYCOUDF$}OvjXB;fghDX+cT``O4JBh?;c?su zPpv|wC&cMMo8MR}a!qU8629Uy|5P<`u#auS)JqIPFgul*1p||JZtV6og{hGyn#)2` z?IIe^)bVZs4Fi%+d!Y7x?CPv3N>sL8E?zt(1oM1*)QsmTro*}v`;z|C8b17183|l@ z0s=$0$eDfGSnp zL^^pO13i(ieO4QK0)ldBO1&wsB1JsnyKTDCaTTUTYqG!$md2$#21tF~((DCqfI9_g z9G=R{X=G!#(X)FxUYh9fg+HY-x*C>XTks={O{67(i^gEC1^A7h<0~ZLzag0;YDsbi&M#G*w z-`71CLXz5zcTzeB073@8sWhExnhvWZN!!qRY?}rP-}+8sSBQfkONx03j!Z!W`{6HD zI6>L2MD=L(f7*(wpQMNO9Y_S|RRZp}pdv29J#7B7EjtsxsJvrjvCnzC92vdf{Y>66 zoFps^Q$F3*#_HS33C55Gg@bqBhyH6U@J+#K|a5WJ3^ z2~QX|#`l8Y*0~EI8yV`Cah&aZaFqiV_Om|5x^eL%u>u;;ghqUs8bnK1S>%h$+~zyJ z75H_>%`Ho~&t%ppg@q$Z@H|Is0M8lt#k~J4Gk9LR-YM%(96W(c+!SC$5?#RAn z5*ZqR7wOvf%e0d3j1jsdVe{Z(CJ<3fagincGehgjyy{|}LvP8UDZhCVc>UAL$wp{& z=`J&@LwBI5&`K7ZUYZcqyuvfT=yaaPjoN~e(}tiD7L6{db0$rwf}iSJxPK0TIwSGGzN0=TpCCB}N0-C6rbd+Dy9? zJddmL3HLetBhoW^?Yo+RQ(`s@b9@G(p4+$8BpZc|g z6r~pyLWV(Bff0o13?n$e@O#)!q>Nkt@!`PkN(mBhwn87q9Ek;h3;Q>O^L5$O!WKXPQb=)#N<|S3f$X8MdyH(8-DI?+`Hr~jVApIfNcg4y=vfNVD?{= zjg=Yg(7@EwaCJf~X$CnWvLZka+f~3;@o(iI9F_s#dw~vY$T2T<`|U~JQe1lHKCyAC zg4dBk+diGJmp)y!wO*r?YWap8P7|KUd)@>UUGn`M=uFf+>sunt{7@|!5%3t1CS%vo ziNsm7DY$UJqfBLoe@A_M^f3N$aG5e6JDFA;X3p%7fH?dhCBr&cJZdsgiOUG_*+9tto!`23W1^8dTSOHAxX4Yy+5An`4n-yKo$=3r6x*gWY<;GPQ*I772xiGIQ++nfThH ze-BO6r4*1O5gNp!6I%%yh{U6ddXQ7#B@fd_h_72k!1S9{pgTTg#ovQDi#w9<#)mc~ zzD*8-MP4Ph`9{c0;ua?6Mk0(ih6DIq%f-+uJf>g9KBD`1}hyiN=Q6 z=J?zX8(HI$(Nk|Li&@P$?D?<$8l9wDedCgsadXG{tJNLy$f}>z?nh{Fk%aWF-3!1R zdX%V_pik^c-6mj@-8;fb6U@~D2BiFq{Y;z4KZYoN!@BANy|N5{us>ROh&lKcZ`4fW zi$Zd*o`IVv1IJlfI!Zv^px~rlYHl9GKUmGn!jn>5m~4_^PPi2!__B_F?_&H}zPO*t zm~;cA83lasS0~(|E$Cs{?8fTRtR~V)F;$<`!13^8)#xTNs#m z0O$xA>**`rlSxO{4A-+7LCEI_Cw#1&VBTgvpn+JxnG6H;>8p+W_^FzE?{vaoxyj0q zj3TzpN3AH+Rv)5FVY)!#%^2Agq;Thdl^jFL0-&kh(y+l3l#{iO%6)Jqvkzfg8YpX7 z@hv{!@t?z2Ilysz6dKx@XngneV}Mz$|GuB^91GVnLIq0b*Izg zMMnxF%E*GO5V{(*1&6+Wy~1+4ra;#Vn{!N2o4nVX6Up%VX%?{BO&VGxkt$b4OF-yT zaJh0&P#VbLs(JbNjw4Y--R`%bE~qv^H`u8)-o^ffBg+m7z!;tdc)BGyahwGhtxFeo-JaJk{tH6V>=>W(c*UJ|in7xj(uLFkLe8usJ==z1*c6Q-xejQu-P>b&+s1o^1|ukrQr1-T_hCVKieBACWJ{y}#8>1NlU;SVHZrGNVKkq<|LP6cY9!{&e`Hk>8`mYeg|!Hz-Zs zKwId(n5MR$z!9Z76xFLxvGFwbhXnMyP*YSXlQaYxuq*<0o@}ct)&2Z&?$2G(wXjxP6|z=b5n=&R+Fjcs zBE*i;vWkj;m_?)nNbV{Eib_^lKtYI#5Rnp*rj%T%5fLH;h=33}gaGLw<=(r`*L`N5 zXWp52{`0;w;((ZPbI=xCq-dVOpO2;GBH}G7t}-26kiMws3eGmgXYMDqs%Uo#2!n9=f z2z^jbzZ?~G$s|iIdSH=yqLn+~vE`d8qWVHn^xm%ZU1PhS5Ye3ql>|igsJXA^)2L9K zw%+rYydQv__}N!I56VIDT6Zd4Xc4LWMs?4k-O z3y-^D4($+cK-^5v1J1`elL}oxZdX8K$sjw*@`63-oFuIm=s!knrdw)q{ggNpAe0zFu3YX&l@QBxN7QaW-&AJ~XVT{6!n3--4i^LqK{i*{V?EBIhyrXZa z(uR0@4-k|;i)X6T?1>S&1pOYiVvnrG=Uu6Q{Q(Uh$h;fX*@0f>W`OfVtn{+;z5 zp*cVs)JBHgNZ4f8$>Rc4keT5I>1PAM#?0WX?s_o#lDYxz6@n5Ne z3}mc?M!dn4>=`QnpIO$Hlk%nU$fk*%7Luf^K2p^BO z2?xWjnE(t|70~FQviu7iTQBQdYT}(@0%i24M~hs^M=D2;^Ulw2iS%ri_W9@v@$4*3AlOW-Cf0hTpex!@J6 z`2D#QX9|m@>fv3xXH9|GmpNkipO>2C29neU4(S+WLivB_%*!!jFmw+fdE2p5Zn z=}_F&612%lp3AAVUeA_uL50Fj#a>`H!J2BuEu;w8tw3sh&%$cH{gr_3*c=?l?^dfL zYkd=hc)?eNr^BWZ4O$yhxckVQ)#69U)RBBMG7=*Ae70a!!TKL_j)?=V3t%Al6$U*| z7jE-Hwyjy921Z1K-F==cAsO3a_GXGh;6+YCmsTFznWIVe{TpstxG(`;6b^P*(VV1a z>NJg?e*YJ*zVJoU>b)0!OEuF|)?HaLC+PE#)LyK;`*ZEPY4X8AS=S|>=-RBSetYvH zr(V$#BdGzhNB7u-*cTI>wYKIK-SVrAyE+ml@~e0+z!;9a<^Shq>9>aJE9=tj-UmL2 z6MIS{$AtW{h^m9X|LxVI4b*z*jEPFs$r}RUy>ZpU#s+TE)1#y|( z@P~l`J)~u=1`1~wzkmF>Alfg2NQ z|An6iVW!{h9&wt8QU@@Lc9KDD?|He{DC~4{DR9{FZpV07O^G+ntfO|wJ|mqzMT1OA zXKR(IzD4C<#xE!gr{h3&)59R;2kd|4;WyLC3+4l4xy+MLyZq|qz>?-oV7&sJE{tOh z;k3bE*=?MBX+qW_ z#JHpg5eRyEptzE#{m;K{%pa|D$#~)`#;JJ7w8=cdrb13k6PiH*wkYRjg$+zZA#4)F z{qQl8P3p)H4Y7ah>hRp(U^J6S;VTyKlfvIDAW@QY4KXaVRZ+ts7l>qz?ZEfCVNx=GQ>km}SkZ=Q#6WHld z2SN0jKjCIG@`lo?ng@s&Yob=$CJ4MZ$bh%+f32bK^g?jIY=N<)^wDdX#h303kXMrX zplUeYNUbxxdu0RIV;Wd5)EQ@2`T7B{8(xwprJ`=w03 zz*l}V$#SjK`;51HT9ZefYS_nk+a9(oq^Nz#!I*(}U({{dLT^W+WZ zBt7-W!CJGVR=pbxZW3$<88;@sCmV(=+(#B_a%)$dez$@%(;dRNiehGpY1@JFJq-p+ z<6j`%eW}w(zY+|Z z>&>UFSzlEkK@js`Qs*r=k}7GiHz0|~AKrd4_B1hD8v9BTNU16oYcKO!a|VAs`QlaX zRJSBsXr{Yj?}I`oaJXd)>1|aJ`fU-MIFz-eRH(r1hI&LU5ALkA8@q?iMa3;v<*DMC z38pIs6$nl7_GFNvOHZ|=XNw~mqMrw>NLgX68;hOh)E0zaMF~om<1G@VXAnOgT>^q_ zf4*=z$TkTHtvC-Zi;WJ-iL&Y3sCTPncCW7u^5V@Y901Cm@N@sv(nN+*I4RNIUAP+r zFp(pEGu=_C&l^vU=uD?(`EQ>$MO-J(avUo7lcWIwo;)yvE^|~HNd;Wttv*u?g?+hG zmsJ16Z56M!_u8STyOM>P=t*Rpd7(n2Hg?AM>Pj1EtpnsUcd zABh>&tun^)@uVD&45-zDYnpA(6;F1~EIv~0C7*U(%H%zT7*8eS(P#Rd_!lP7omoN} znp4*QI8Sxo`TeTXMI+&5U_RKP1B%;J2E=1#;)+On;JPm$ z7ll3UH9fz#qQ`vu$#;VeK*jjang*TVKaMuAr zaY-dItMocQ{S*Tr@jKuJbcag)>E5czYZfR5o8VtT`KFR}0GgVZRw;y=t**T~H*o?d zx~365L?J!+nvP4qlRb56U`)_JLm;I_E?{m05_WA9ZGK9>Kt82)DK!DT-)zR(=S_;Q0mc?5_{b=NFU`pLu}2! zv-L05(*HvVy&uW&U&4$Xf$fQN#xoy;!ExGou3jNqUQOvzL#)!S?r!nxuoMYfX5Mf> zy+#oiWS$LM0A&5*WAl!AT`!04&~K40igi0)d7p~bOd&nc*ota66(5Al4754wmDnf<{x&8#D_K!aUbR$0c zxbDCPU1@Ugb%*(6aExZ|C+B zry^GI@!bmFSZ*62n1JLZUo%Pl^2vDXrPW=h0NT{umu{4=TaUhiLDtf3=8gUHO_4Z8 zxEi&2=#mo!$*wZtS7*7z2WlQjmAK5?*V&XQ<3-aF(sVF+f+~$0G>YSFMfXVE>d5oR zJrkVOV4~lW2LIk}KBDMPtvypxTv-hLRc@l45#a%d^c3Zbn>Q8%`}I<4JLgfYYvGm7 zLF{nDlMjhsT{8PT0qxoX2z$cC)3)#y{BNYco7ZE*Yk(KnozrjD6p`Om$Q)~_$iQX| zjq=iqAPgs*EpN!r>ITyQ>&wS-xa!mFCyVRpIfI*K&(FB9`|A4l@TcX7R4|J4NAc~B z+|0V-V7BzHoDpqE$JLB-5htI}k;_amNr&v(Eywg+DZVd_%=>TJVZV575%>t#?Xjgp zZJD{t2`LgCtP=0|Fy2#k53ss{!T+P(Su`xdY2m7t$f2tJE3{B8Lo~%xD!WriGUDfX zWijL+tq&@Te`c4n=Bk9LK=q3riQG15Z6bXDB=?MMEo-Q>)c?8&ySrxH*~l?=c91~I z+rv8koaM}y3S65MQ$A4}t#7j@kDunSX&I?hq0TWi%2igHG!Qu7L$;|Z=j^zRVO(+5 z{*xV6_xFug`(%GP>p^=nJuxkT6vH+;Mibfr_vaI&M_t_1o!C<=k7g6O0$=X<*K~=o z!TSg}4UgW%^bPrU)>_gVK$2Bwg6|Bu56Fd(lx(QkvY~JD+cdSg#&9sQuC%Nifc7zx z0#O+GZF>Rq8E@=|O2C5>(!V`u1tFH2-F1j?&-=+h(&xTryY0!+j*ONjzE*~Pul+XvvtetL-I>K|tMZV|sk|hCz%kl4F zo(UrI)MEiJWR745d7O^WeF>Cj6r-*yTS56lrha>~@9gbi!ys=Tslfp6Hr+Pr=sV4W z!2?|bjQPTzuf5z2@c2&8v!Dv`vsuW(M>y$X9l;jb%&VIF)5j@HH}jXB-1`I zcIg?u1KKcfGXH8m+hOJ0m`yD>r-~<@A!P>v6vKVj>&I6H9t(#PF((XWYTQIC?d-Rj z7LerYUVO=lXFYiWTI#)q$GAhD>YN;^^$9z2u=ZX; zUnMZu68=~JqXkbG)*u%uAcO64^pbvubu!1t_RS?_Le-c;jXx5JR(|pYETmACST`ja zyRa-L7|`Be^2jrfI&X`jw&90?PBj~t69`W`87@&=efNr!pX=>k_V{5BNaGGDzC&pU zZ;Wue@}Tc4e+Kr<3N)$YT2JMa5Mk$EnlM@sxJHl&XP)V*y`7mT6rfC>RPEN^Eeh7L zd1WL%ix=FH6?gp`l?z*M<}Jvx{5H+t(avlvNgygceCiazJtFe*fbJ2Hp|MTykqup2 z%Lo@4_?i6_-0=^yVj1@~(e7eoh>gqexJ?x2RNgg1Ak&LS8yoRB z8-@ZGbYmvNT$aiG-2FJi+ComBu5m!d%GNMjID2B9^>-}TDq@D5)Te#utbx6sbnsS$ zSF0pH*^lVpOh?dWDFkG94&aV~f!J)hWUrEhq=Ye-3T`G0P)V91w;= z1*tOwB0Xqx<0ci*=c{?bi3^U5sE3cTLCD5n*(>i~D&NW07J+={S>j|XJ~1)48xg>s zFvI)1JePo@&L1YH@@%y4Qlzs{z)$HJ7k)Qxb2Ww~dfhxv?=qmcTHsI_$`!D|-Hh&{ zoiE6RnX2q2^g;eNO8X?f1hp%bW~4GV>6>mNkwMt@8_l#+1GJ5sjwW|jk8-D9e0#g_ zmZ2!?Z0wb#-dbW_0ChOwFgKsJXCTe8Rrwa@1#-k6KfR$tO(N}e_Nyi-oy-tsVszj1 z<5{RApn{?e#ml9gHU{0RiH2xo)95fk)@ZyaA~gSgq__Nf@jH1aErYn3+2k;0+E%)% zzq{zGM7seKq~PH*$|-N_A;wQ0hlF25o46@6RkW&dwJudscQR{Vii;ZIeg2iN&S2mM ziPPn4u09)_tD2W?yekxZbQy5U8i7IH4~)oKQ@&7pDNnfJLxKo%h=az~xY>tn51?8j z=o^VxGpro4Qdn)VVd!wAAlU}{PX@r?Zg`PrQEOdF3K38I#?%Ir2p|t+k5$~gQxd>! zXFE71;`T>CE&^H@`A<4$ZWl1?+(#z)PWTOqdEK$l87`X;N9HYUqGrc%8%JaWJ74Wk zKDDSff}Zyrwdu@SL;T}-pY0h$)F}Y>O;`1{$hh`Xw(URn_P1;|67?|2R}^Q=#`cF4 zQF|CtpcG4PD{%Q!JynPgvpCQqTD9H3vux=6CK-TZY?#W484)a&$Q4^lW>Q|#C7>}+ zPykUvmyK;!T;4bK3vcC214MA$?B%D}=JdDj9(M}!GoS1&_^EJAM}umL_uOwfgY%Yh zWII7Kp&hh>j`j3B&?($?UU&PP*6lZZl760nM_!;oq}uG@qU>=Bm7-4T;_%K<@LWi) z)jarSVeEKpHx>i+{{xpurkaN+^8jo!kFzGgWR)f|ANamH{@_^rR*SqSv+Qx~s>&4+ zAv25C;B!g?kAp=O={=!*m%fjky z{NhC>y97}a#@b;3L+lf3)?1@L8PyRrFp78S@g$?jB$`pVn27cA# z9J4Kes?df7wS2pGQ0#Kg?=~m{D@evcki^cC=%?D<1YD4|{ao zSZMdMCGH|ExUE^DoP|}DyB=)V)%s!^7ueBf5SqkL>>kwo*uikt(PIaf&H6um9se`4 zM`a3t*Te3cXUA%y2Oil4^drkPzYnb6rb+y*qxd}Gss3WFJ3edL;n5&+mw4A?eh1wc z{Y~a}qvYj$QW!aFal1DqsPSTokf(rP5y8zreSYT2DWT3x%)kAi~JE|9Nwp0_mUggZRobaPsBx+cHdj%2j}>7 zvR_=vOO!Ni%#7I3hWmUSm~6eMVfIxF6h`F~=*&U|Zzd|+phuxzpN6sOPLhCmMOjex zzHgU+V-n7Glrdu{eYGB~7WtA%;(D&Nu>j?)t4m$OZwpxS$Z}% zQ^bFcVx(8lWlFbrkTPXqXK$Eri9eNxS_hU@ zDyh`qm)-$=YyYVqygP3lVLZ$zIabb}e3G%Z<=PH=ahkq5>!%=SET8R}1vA?Q}&oz*8m zi|Lk+E0iPz?Jox1OxAn7LKVpTqq2*kRRO@>6#9r8E@{8}sX8H}O?2CXrzE|pUs z9=yG$W2??&kIwDJpjp{}E!iw~TA7$luB+YiGH2vW5}=?JmuJ)8;R3S3>LK_&bB$(8 z_g9DK*DLN$t=jq5ruHj}Fh6DE`-YtvRpI!akozD@*xzntPB<0oY>Qb;jMhx-StmD* z9c&RZ0E>Q)E)|#VDz*0gWzo?;_e}LDtu!)yIH;lR%{d!ga-+^_99fPA_lEC%4ZmAk zD*MjxHi+6OX~#eyTX55L*2*yxL=D#}L(QvwC zI?a0uH`~;_;(x57S73;r$POq86LS5k z5ym_9KZVN>Yi&NwD$G61-f<|bfw?LQ(28alsD~QZFgXCN{TKEtBT354ALr^gCj#S-hwz9178GHF}vmi{imq4(zqMy-&52!o=YZP z{M6N6kRR9mq1rV1LCc=+LG?$&tC>=grN#;ll=%+Utq}CtY|qOu{(Pan&Sces-}I+= z3l?R4_;PD;_JbQ4hpnLz*swoyGVI{*gk%gbEdyHq4Ua= zL`n1hILJL-RKaMuIngP#4ExDu_`(jgUBoQ6_1X_uF4X@Rx6#0ZUZgtayy6O;QPhsA z)Il|$^cqvY8wj1fscrO=BJ!eeO0xjEJv&uL{81wyKKmp3=5vYDnQu$VZw~PV z(96NX;gZKbhenT7!h##1vjiQ+Di%lATw2D-jjyGJ&7*hfB^~t3dZM56VrK=MD&V_? zu!2&PS#U1d+rK>KQ)+VVD=$y7u+P(3eP{G-CGaxNNlM?Q7mDOsT&5{L1T4WK_F zKH_RR?`GyyVL0<;f5&uRe5cUu;>8Mq;QYk-Urzw7GDuv67la^%+-lm1A*g{dPjjuW zjNw+Tdt`SxHR`i_b53kg*QNKlX7pw04&CC#GtNEv9om)z{!&KxNHYqLG+ z;<&xp5aWwLz3(%8i8ya5)TJV>7H{7d68QUWX=&@`!IsbW9zIo#U)wg1T{^S&=V?|( z}S)LrT2*PjPzQ6^x&lFTHICpbRxxV2Yq7q(ChM{Coq%OR#ov{_{M-s zFrN5R)J>{I7Jo4DY`%8oYW`IJj5T$L?WvyF=}ouZ-X#6Cvwkr72Xl|Wvm1q8MogC# z&+CS^AA=kVx{ zfH||*xy8muIt8>v6D)fXoT|bdQASPG%#hIy)YZW(YF|t-ZSN>Z3(D#Um3ngl_5;!0 z{_Tw9f%kRJeA%Y4>#bG>+jZSuku*n$Meo2!aXC>It1*@i`Jnd?kN0kjssv4og=IVm zmI`_`+kYdtX-d9x@TaByp5pM>`bn^a0gJ|g^aON^4fiu=M;&`z)Q7J^-nFTm*4?Iy zT{~^ZaOCzcL7l*Q`tNsd#A5Sh^vEW&rUN+d^Saxf-CAP{$|3{u2vC$}cS{DMqdYX< z$qcI-=e{kk{7e}sF>zyBcbgk@=kLRQ-ZKrY5hzAOp1?lgrG;+J3$Nsh%Qjt1uGv8g zY-(YSWwRQGWE8^;{nhvxc}X#P!aGHUTb#Qp2DT4*#c*qp z`GUgqs&^R7+shZk@0uD~DG@+p zSz!;rCX48LJ=4&i0nY1FFFL{d31)aA{tr#$&@Mf0((zL;7zWZ8L;wwhR;w+?1z2`3 z*@H?|Vk@|v!Td=?PF6SoYrE;WOVZ7*-OP}~7sU>4#@qdHszgNY=>Fp&>+=PACNm2* zhoncKAH_%U4*JR^B3(>nMCgsd`T891&e6G1vBfoa)3W;u&;KuHP2sFDE9~%%8OG}| z`D|q~yj4?AQL*PwvMG~S5JWK)dA+K9N`q3C!c_p(G~m%3+{o$i?oTPNd;cLbC(Bk2 zapqO)7BJyXB#wN)c`V9D!_-&hfC9AawrvJzO@_l5AmzB@!xYEqO+QxLDSPsL%g!Xb z$O{jlBzT4JXQ1v{i?493o6poZs%R-D=CbcO7m}^LN<4(zdpHzBv%XQ{w|{9JhfmQs zca-%xSG1m`+gt7$K(u#Me2HUoJO_cq+%mEPsK^ox9}k)@ww?rNS#|~_4`9M$9`mI$ z4O{=6^-kJQXo>~D1|ihsYXXdUbQ{$IiT0j=Ri{4ntrUPwRmouHeLna#GjpmFdAj9f z7F+L9&MB2EL^^Xuu9_3{4KHJM$JHKO|K4Q2T8e=FwbvFNVaRLbPk7<^w|C#0EQ}R- zUAkMN`+moI?r_smi#rhwBA%azu z*o^`G3ypQG1X24)guMKGB%N3OapE}ZuiCI)j)Xm=a1L%sI)R@};0VWbp*cyr3i`e( zXW0A5u?}`!l^P#UNIh^pLKle>82)dN`BC9M0B4xn0KCv&)?|SFk`pQo$**#bCo=`; z4s?+uz_|=ROy!%Ep`{N9FF07FNr@g5=HFjAn+?aacWN^ZxLY1`60mz9o<_xPcuQZ7 z?t2i%x>eFuaoDG=pbBOWFtX?X*Qj0}HE+;xfgiM7WgdK}-LkH-T#8jattzc3`{3bG zx`{uP{@W1bxn|5jAzT`?3~B%LF{RUDD%lS}_X8&i(rK_+MyTI0+Ww`Paur@G8K$?j z9$b#TjN0~p0tEiQ{O-G@1(--2t@{pxNfC174tb&7dKpwx&b}4p`&5Llm8##JdwIrx zm3K}+0PP%=LJd&c=6d8hPp=FS3G*Wm8K{}z{Qbk3zQbKOOsa)q{u{fUjn)Ax1Def8 zswnt8u700OzJ};h`3`%8Tadq!HS3Qqrb@%1GhouAi8rSg^dnN#VT3L__=6cixsd(Q zFMr_JD7e!gaY(nX`WEnERS5PLzCZw|L@DJxWD>PZ!^raJ^W$u2n?C=#-Hz>`-`i1N zYMBlnl3a{r2^TQV&$Sn$?;LERzLW7L*)qi-d9q&Si2qKBi}<82_kOm)`@pK1ILUVE z3$dE1{5HXvcyz+?>R0{Btp^2fatk_Xp$d^eHfhkD8dKNF->BOJkFoe5%gRs*HRQSm z=i6Rd5=Fr~rtNf5{#k3;*|VMw`UX$HAKIRU7X9u*mn)#0mcZBH45$U(?p^Ny#FGun zitW$Z{qvXr>zPfcK4hg8aH5xigfi}&-B?+`>8-$EGPfFE+2>*2wl`evWXLuJBsU&? z5AU$LIe-+~dmMlbQ+lC5H6!vaf%=XMbgHSy9@k+%Qk6sm)_4P0F|H9_YzL`nhvoBr zGJUN7Qm$8vRNOXBNM|6ul@fC9I&)*)?^~U48loHJjB9eTF=Rg|W3Hs3NUs+aCV$4v zM$!XZVnt!k7s|nM&2O7U=BziwU^lR4sA$AP@*@&E)i&y=T|(xv2SmCbXNZ8-wWjiv z-X8Uk5*ira2|dA`kX+#oeQ`8_Udj0SY(vs2kMtwCgB&DAkMyfM=%)*HiyTvF=TqL~&RAznRtibU*x5EmKK2BT zW0&Pa=XG=z>X*iQiop$8>{|bGAU(z)uyn)rD(x7VA`}(v;R46IzPqvqs0N>tnIwx| zYd;@|$}zm65SU8)=_R5kQx7_J-{WvZu z&N^dltMbq^eQmgd*`4!m%U&11<#gIXOikM5-NQn-eFH|aLQ~4B2{CYyge!?7FGkM= z76A9J4yhDys$~Yhe+HX#p_SthI4b)q^c%ZC%)6ibZlFh^#7vpmVEhAHnenzQu%N`? z@e*rihN@H^G#13;YX!rOQ@|L$57z9_pSX;#6;v(^Hm&Bxr{=jCk)?lM4&}gcc1|x% z0KsDhjg~~hb+xYFx=#)&Jt;2gTzsPlzBrn!%gV>7ftV+Cl844y?l3f3 z6$l;UTUNOpRt;8>oxrnXMEPOKmB*e(Z392t#d+OGjR&@m{6++?b|BP;46<)!fD)GV zEWihQaV1>B@{f3?YzvSYs6(VF=yD-GS13DC2TAXvmNJ6|=!ScYpu6(ofc+xDDS@3~ zo`*v166vHjLXX&OF9^dw^Eu^Ue>1KDF5`z}EEWoo#6_@cN!|RK@~|4>Pha7u0YXEE z9pl1o&hpOfAo)CNvG`E(W=M+A(c3c=&W~+(#LrvIM2zupb6#OnjU9 z^+Qr-c^;ClQ{lxT{cI_72&pCA%UI1vPf5iMs|fL^?aPDs-IwDton@uRrH);1prH?d zGYlQ8{+Zye>eMF9*#)5rl^BhKgnWx4n~7riGS1k+6!m;*WbTGZY) z)Un@i$%Sv!0{&E)F8SF-479m_1B#n|sRhuud6vLYx)h&Jru9Rs3BdVCk3w;)7}bWi z%P%DBqBxd%t5#`2)}Qdm#N@TDc_E9ozZ7*R=VsB@xQ(pYJ5UN4>c6Hf#Y%1|07aFR z+p6w4(ONsY($kTYQ&CW%d;?o&_hxXFhe=Jyt#kNm*dbUO(jWie|5c0@-Nj(`>~k}P+jW)R;oD&NPS@Wr@G`HyAH_p-IH(*{CeV*) zz+%?|6ZV^2EfAfIlmvGk&h6bOPdPYV+F|D9!9HlVki}lfQ@nWP9HI!pJ!wJs?5~4) zd9S`jN(Hvv^Ws}4s%{C0=S%Eum@L(D^X)d@G=t9l_jlH}IP>4Wzk?^X00s=b7pZ}W z6AL$9KOvT5NBEq&#u>*Uw0W1)_de*iT3Tq?vRAo|Y1%8qX;kzOD$eYt0s{4-pz)8r zE%qFQK{)LA-wNaB_Y?o*sZ64K%9d#f1w1e^Pp|rS*2_#BoB;BtAE@707f=3giJgrT z%oFH+r&>cwI{};~d$XNS-A{Q+ch5%g>sMVkIEYd_DObZ^I?do}Q^)r-{v6tNsDeJa zy$7_!m}EF2Djgw+Trc)|z3$TCxBt5wx(!@?5&5Hn(&MZ?-#PF(5LiUa-Tp|g{oc|l zZjxSGuyu;0BX;Wz+59YcHVl?vF9cErY@q2*ksYH8&cV`uXVoKr$dXeC(@?1$ff|A_ z2Ak(7@UL`157b>6N&r~PY1@i31<&7>KDOq9A!bXOtx2XFEf;8kYpRZb&Q&?91F=^n zj63utZ81!ceBZtHHN5P1y)pZNPqro+ztl{O2I=jWb{n{9gkB4VKmjVYwDxhFKHIvC zB1hd$)HH9yTM7sSC%7cnqoqkAbSd}Ge}>Ant0U4hu(rccz2Du)*;5S|qvbDcAdx8IQ!sdu#ECgN3f zDI8OPrUvz=JqrpM<6%HT-p=*`7&*1}A@#3;eVDbnpBNFZY*B!;*+UM(0dmsVV=qs( zRbBrUk%}O?Dr};7vnpIGa-2Hc$*yJOWM+!97ekH#y)C@Tgp7dVRglBa(ZR>|s|cit zfQFM8s}GArh?PhHr5FcMY@1%aVFo*nS4;tYqrqab^KjEaV!_i(0H953=u=n73z^w%YxgHDM(G>gha8do$P~ z!0jXG87zb%mt*Bn0DA@AK_JjKqLH$6?31u(RaQevf3wLE?J6i{62!xSDT_8fUI`DL z1CZq3`5-S?uBIDH5nay{EMOT(#Z7+z7wHJPh^6>p-PcNqC1_i`DVcObw+w}zjxe{B zlzW9mUWwx7SlrOtXAEp%@1Bp)4GZm^q1BM7+X8ON6Ed2}*TnGs5soX#4Og7t_ zFoe+`4*&43h18Ci_7sJgkPEAh}WAOXJ zi&r1Kh-`Km0-QdgW#d}HJ7}zrL)XN~*4ba%Q=D)1$$2iYy7xS=`}d^7I`ns%zh9nG z@X**AbDIWokY!qBzdqCEbLvmzLbbCk788LF@p6Tom93JY$*e{)_7a5PENgJ_8D!jH0|ntxk25egJKA>?A9CdDyAz_PYK3i;yM~UY+Ipn< zaU3gCnv-|_ip?0qFAF|CxKkI%wR*^%NL9uVD@%y_Eumq0Wyyj zo7fcjA^+ZKAcgO>KLJS~shT4gHJHgr;N%qB0Ye^aedCKJM5+l%5i4zAxi}J4p}MI1 z{$x!RVm`%h5)AV)>4b3qNZZ}#(j?sFl}B+7bIkZ%eWc0LBEM2PNorb#aA*H`&c*Og5f18Kvw9XoRRC8xT2{FP@;mKLUOkG$u&% zLuxwl@=(j4GjGM(^2(?;%m=Y{_^;h))gF=LM#=YyzFmo9ToE2|L&9B|^TOm08c;N1 zT7!SU{IRw#UXH%lBc^?&PqShk0cU?2iyva0$j8B?6>vdeUlyz=kGUW$dd3CEO(a|+ zQ{_%srMI!t7cj^8EIJ1Lcz)kq^am`6TVNImc8mE?9URAS8qCVc#Z5zdq4))`y1IKwG-?nPV2a75$xId@2@Zgy2M~?*#mc?deZ4Eam$T%d@$N>J7&4^) zI1yE>SvM^>C41d3J-h$1{j$YxZ#0KSx}S;g?#wN1@}Lr3V55MQ@DlbkXGYL8rVx5C zO+fOr1nIx&ZG{z5iV58T>gR1L(i}Q(McA$x@43>X5!ROw${m7_sS(+y(!gOk53Sn{ zh?w4H*pIkT6krZZgKJhnHyl=Le4V9bv6jvrk*gP4JD0AIK6hWR;Kt0IE!+)58>U2F zbVjC#PT+5~bXn?J)ONjUQ(Ir{5umso5NSK#cJ-Mbs!B@IOP)`a6y4h_Z@2K##`V5m zRey$PcrP+iA57kP|C5=|mOj_UfQwlbWH0aDhaB!HAh{0cU0#h~5^B)u|Dc@k|G84{ z*H=A74clFx8X9Smq)P|f>MPvhxb*q0sypQT$mG-%8C{Lse0oBG(X$?Ic4S*_q2arIvi3D&We{^bLXe*lw27MB zrry1Vx3lJ`Q{>;dyUn5UEaItbc0qX{X=!|I?y-W7@-8b1mt0%sfi_Ab)lQnVQb%it zh0^p_eaU@9)m*$QGLgIJeL@@*Z0FO-`Ac92J<~k=a7L_iNXhRuQaEs5ed!kVj4>Yd z^yaeJSB8g`|1144f9BBwaIPs4UYVDV$f?E=KE^>J9;v1hb%l(9j*=_UXsh?eiQ!Sc zdp>1TH%iP&Kb*9s{gi)cx8QNNgwuK2RWj|?o8b(-hoi%mSn^Rb4Q%-^BzPcjJ#_qs z6yx9j!s~J0$t}yfxW&@OgA}0_;8!|NO6tuzrx9h<%r# z)(2~D@a?`8G@Z}G^9~4#a_%ISceMm=r`MOUm8@e&okkpN zffjnt;Hlzde3vvdjy-SP_O!cA^F!ZOi|+nq9dvV>Ep3j&u@0m^4SF-36}0h#G`}w$ z$%~+gJ!r*SI1UXd4~_~=B35SuS7Q3attju@_TmML z-hU?%h?{pOeAmOvj-Y#i#>=lmyBQAL)-zW^LsEzSL`z4~{XXsjTMxo|oRyNuocQ{a zcin?M8ZLi0Vn+;GOfPi2cEBNXq#E*$P;d|H`!5FFV|yFIW4~>sUZuqm z2B9r8f7&@QFSb`D8`*r4202+Ay0p{XJm1eMfO27Kq_e~QGxCN_F((I1q$4IA-@0;N zbg5n)$hUY_3Fh;z$&~TKKR>g7*JzSaqGHBW8V#_25PcSTuWHRxrtS7w%w3*GKlFYq zJK_m|Lic-}YiSGqJ1Aj$-?MW!c%R_^Q5|YtH;hpmE>vZldwl5(7&RYpI&7b;?ouHE zVHV*}PMz`x)S!|Qw^nkXq(>0ibt(Q=KqgRvnbb|DgqIqF>WE5q&?^n8HZ`4(JT~vZ z?`HGtSSx=haBqEK7c!hEG!FQg{u8>*b5aBMD~Y0k=FPzgLzCggw)jf+@821mV7`y{ zTs*VLaezyzDL(V$02JeWOnxGXGqQpG+#@i%`zKLNw!r_YTqq4tg@q2AxA6L-!1}gFJRu0PR;^pRk2Xfxp1}1*|?F5(}v_> zvo|;UR)?4FUvSiP=9fF?W*bZ2{tOm`9DZs=wV*A1nmL+ z^60>>pqn>a?XAe6rPIQZbIM}}e|U0`2XvIlt~1v7B574e-9zddPtVKcR}_ubxjWsL za0@q#eNnxPtA*m?D~#TAe)>Y?qU%%Lz;FU{%&W6riIFsXItk&CfoO`b07@cvn!!A6 zm zmz@V%npD1WPNKn|} zMz*g5P@Atpme~KwkPf{k$&s7r=3eRbg+vzqKUgO&`NCo504dFLS~yyi$iz$GRcwj} z4g=Q1>=dAKF~{Wo0Mk%I^SW+s=+xRqQe__DPi_6a60jN$9M}-jKO@R0$+s`Ie(e-U zrTkELeBr}-J7>!s_rgy1GmblcA8Pf-;-U@HAaf84m6`r8MSO-F(sle8oH&+~+1gv$ zm+mD*4U_JD)0T}}C0tZFw{~H_aQ;xwUj95FH~@4ap?~B~jhCE?4p?7e`%Bl# zYWRQZBDQ#1u~7tgk+`-&hye23x$4FAT%FH|qf!!R4N?(1yk zwBaW>COCo-jS_QrVWiq_a|L6llD~D#zC2|gX)qvrz_DzC1W@6Oe@gs=S^2y8{F9R% zl}eb=XRwiQBg%NmBx#=J;)&0fBYfq0Qx>9WZw=pH)7f0!Q|nE*QPH^KKI^wyne)*A zRZ^Qnxs<%vIjkTj}EG7h55U`@q`%J(JqtJ&vUmeHx6T9<2 zjE8ewBYY<|vrcr4&rFm^=qb|%no+;-%>M3h-MlQRfYinnIVtc*f)=K zURADkW#JozpuJE{&Z5)&|Mzn~E}VP6Z#NRMA)rRA@pns(IPbL8fubW~kqWK=bx2YR<1O+FGGj-b z&wOeHIH_Ex_^N06YxNE8S9aOlvPrt-aNT+_!Dc64q=hrG%Y&BbVQ=pYdcdC!hd2+% zoGN2w20Y4U{YhVfOfn@9XBd>ZE8x3*i{o4#_B2Eou2}WgO=o>Lkf+FHX-BIB4X2^Y z&X4mGhfyq8goms0awAX53~u1n*J4JK+Xgphq6#$5`-$L(!}J8P1Ox!!@{T%OYm+Qq zuXsi^M@I5?{BDBxn~m83mwevyY;Vl_tFd8?msC+ zyS@FSk__UNV0G1gC*`_-XB|@VWX1u;Es2)hCmT2Esc^`ebb1S%^120Hr9xt%#g!x} zi|f5w6VsnhIr=%uX@KTS5)=pekWxNy_#yLcGpT+dems%4Lr_v{Gmx}4_fCbxI{oDJ zkuN3Dxl@qgdh8*KaZPeS3%W2LzF>>sEqTaJieAb(1DajIjd&*89sL6Q=5e@spB<=3 zewc$jRuW9McAiF-qUHgV0bYE$aV2O#T+%#m5g42-DIQy40^a%GvHwIahF`#+b{Z(l z7QKOkz{zKpL2)dBARB%Vp13|YWk|N${jIMG;f|GiXt7Snwf6k-!`^MldL2tkzxyZo zaVf3N*d8Xb$)p+tbWr=B+i)4U3GkDLWnLpw^|8?}X+X(GaPNAsdbPwrbMvDBBOWQQ z7@Gwyjd_1**&w~J+PsIcmC=g=uBroS>gW|Wp5tTL>9ga>o_Ch8dp#eGAha_ z0;8xPLV8?L5g0d+HKU9oAY>5Ple9YmN=6w#LC7dVM1+Veku@SqRD>u2B18xfAcTM< zgoIAg-E)ugtNQBJ_s6Y!tE9>z3F$t4&bvMD`#d}z_Zq$e=~3_-{AMfNGbztxmAOx` z!Mg+ppWm^2qXOoX#kk#+o#f#(kC7_b_=h&Wv*0wh3u8g+@VrX8H996GBDLZe;VkX z5m}bYqu5-?u&YpQ(P!6$3m(#6u?Ny6QJ|onOn$*_%%m7chl1`*nnk^im6?m&BmE_s z(pwdZ@JB#K^cMFtECO{gahXwl)jZI9;%n`s#2H4P9gc$P;`lr_lF6@OngUnuh&@9H zS}w9M#^r|7bS`*KA@9SufLZN9$9GB{Ek-`l0z_$=CW5@gF2y-ZL? zBmMMk@>#AABb%Y;u_X8$Kl$SrQl)Tujc>|0Sj`@vcW3h{`E~fS_kR3C`xYU7CI$^2 zt0I^j_&Ao?%mjj7*t24yI_IuSrJ!jK(Rt7nVggaI8}7R16VP6}I9fHpea&9fs245RTd$ke4BfURYUTjw zCE@0ll&oFH0ZTTDAWC4gcVQKz4S}-01^$}iZ(s*`M&L!T5i%q^!%84j=1%>0#$)1? zc-(Ri5AW~Y07 zM)!cYbMBpCCWBtCa`d7?mm6TC1(d30-B&CWHX#$hE8mMM2E*Zl+Pb5}zcA_i*|6kaet zXJv4o^&4x(D*N-y<+w3IZt5h;Oi#AvpAOpYYbwF%rCHwVj=lsOK9RXog(VArd5=6! ze>vcgg0bQ8BW!$$3IN5^C&Z88KVkn(#ILWiNRcWOShw$Wn+%iBw+$O5^ru;gxd1h> zSJ)NYoj5ru7=*QFhxL&}mUg*z9Yv9&X~t5vJ1!x1F-}6n+S#DPgO(=kBR4Jx>J&F* z6F$APQ#dtPh>`o)HMgHkEL_{8+v@7r9TS96qwex+x#ZEx3mH2e#rTIrz`1~r*^T9s z>C@xY^Dta9>+*pZ_3T=L-Fw;ZX@*6{Ti+{R9SH>&^9`yU_K>sO(iVu~ygS5SIczm& zPhn-&Zv`Rw1x;(2!jI$na_@nUfMvEYBC-$);q9CdZ8hKPgb z;cA#LXz@6`ON+B?6=G*^0luoCdMoBM2L~q0UDA~)P{*5>LdDFduTjF{|i!IPs#NbBb+xHj_J<|=7U8xEl)i`Sv8FHbU2Y@(KD@ zBuB1|doUFV7#nADIV52pm=7vG{aQ{Q+5cF);Za_<@4l!!G=2=Hk0C9n}Ge^N~h>LDDF9m8I!RM^4=x<};^T16wIsD%1Ay(#@ zrUhSqBmGQfI%(;5M8nCOfADaj9e7sd=9*olnH-}t3;suyI~Wrn@D_5qX-leTg8TN7 z86O9#=IIJun0BeWF$TWva3n44!(ZCqp(#^}j#1CyAnrUM(7E7F(dXRBVTbqleRGqV zN(n1}JK6!)g+hIKhHwc`f979<=0}V(SJ!R`j51tBYs?br;Hy;Y7(BipI&b1Ot?Fn? zFY^g_%KvbQU7w%U^(oQa8T~JPN^pPJO+GpHX>?Qcg_4=KTEc`!>k7u%Y*uJZ6a=t~ zzG|`JxCQeLd6_kE(v%yq8o-n=?<=cRSzgTQp-Y;2?WE(8T+J-S2(b%=-+G+X!-r8K zvQm*pF(#WgaF=$CDVox)(PKJVgWa`L?VG_l+sM=^1>F4Y34P4?D5hcc*^tMME%mZ3 z%~*+qcJUBZi}L|!!8~h3C31qugJEQ6>M5iw4|PbDXZNwD7IIzpLQ-{ogK69nLw>a2j-y#Zy2X|~W$A8Za+W_Nhs1E&=XVtok0&yNQRbB_bHFX@WY=+Gr_c^ro0>kg3AA@!vB0@ z3;^9?;+NbxxZ!!`T&mIO{uQ_09q*+pv19T=elcka;j#fA3?u& z*|QFCC;ES9w8%;vj+}LJb1jf!!INmKvcs~!{O0!nFEv6-z`!V|g>%z(j`KRpr@W1r z{*`}VH1N$3KbO?hbSNE0^gx=6yW2aqtRwyg3WY!QY0=j$0x|b!81^f>1~;*)in+i& zA#UvRbQi%e$IE;OoI1kRIwi5e$?ji(!%R~Y!59Rij<#ng!L<$Xj~>+rm}9}6XC!ky3o`i(J8VVgt1DlYG2WGfMNTkb43n~w9fP+QMWTN>TrorA z@RP7}NqJzktd`D|s!XcX>Y`sY*<=R#9ah*fT)66#L))pqV{r2xhXl37Z8~{Sl{jVT z+-Tzy9p$Px#~^%0ZF8K%A~bej*ROvLH}~cj!2I!Pa_g&|4?g)(v>~PrPca>k^6TZl zqvY1ZKZ=20^w$jH7303kM(J{0n^2zDjmd|Av<=R^|A4Z@87^5jRyuZOOvMhh5U@QNZ*@2n@&lLzC zPO(=j{FpoPW79rfp1{jTkHF2`(=r4o4~>~R2m$qMX2{aRFp@FK94Rkua>`o3MX`Wv zh%96LM@eO35R%hENOU*^htHc3Y>T1Sot8QB&{|&_{r>b6yPULoB(jAz*N6LVH907q zt!;uIu1!4{TaH|MQOD{HVh&3o^78_4L5{LVrH?uNtf;fKM!tYLTK#g7$!r)KRUtWWwviG zV2)vjaiwN&fYDdoG^*ms6KjPZMM#7tU7D(i{`Z?Iq$Sr{^;Va>ZlJR;fRZN)bbq^a z+I_Nz2JwmSYsU8b9rlJj@WP5Z*X(IHzK>hfO@w&VJNZGCg%Xf$>Ych`Z^Q9iVRl)) zpU?WjtZ{6xaSf-jqx~MyO~B+;6pBukWQ3$!n|}q+H1nty>_`#{Q1c6&Yp%8eMKuyH zWtua202%^)MliqJVkpRVtmc`3iyHTK2Y#L+EK+h3il}Fw9s*apK8yMFxj#|LP+)eA z0q0yM@H<45=2XXH169n>)|R1?&rG^QjNe1hB9<*-HkIxm`8&4K4?z(TD{%O&Qs#Ho zk2?V8lZ35g7+t*P-jBFetmftInl30WesU3dSMmYBFJ=2>m(A}!(pj~^Nd*xVGCZa! z_>kw|fagppzH8RZ0xjDsS}1Pq_64LN@-%L z*Z?8a$Hw2Hx)p&L=~%z?+(w|H5f&W_TiF8?>8Fjsao-ct6k(YRH zlh92t4z~lghmIa8`s%ZU$=|>Qc>IrG>Atr_PU`1IyVb)>a0{6iIT=1*)qEU=i+uJ7 z4N1#iRjtFElExOE{#<_+i;mum9ux`v2Ch zK66;S)FC85A?)WR)7SWk4#frZP0W+y=Gmc%B^a#JhB!BOMLVC<#wBPvqn7QvJZc&Jfc zEC?ijV#O1uELtFi^nn(>M|z*_eDB{GA32+Abno5cLfOD7DxuPe&&~L}1^vYC=7F#A zibTTA?&%v5z85VI40L`S_}V(zYqzewL8eHG;=Zu zZe{wlZH#Nvl{XmIQK#q8mqu0cy9uG9gH^#EmEONzdEwQS@XlPElDz{)?BePzmTe$j z)m`InfTO~mIW2^MM*|~9oAFJZc}jys2RF8h{++r8KGip*GYxk?$n6=+j4ZDVe#~v9?&>tuJ+B4QnyDWR-F%~ZZ6-jpBHiOU>J7N_8nPAZ%tF5K*NEt`1k%|P(xyT03lhhuWas{(t4pSlV;6+$<& zx0aMKp9;WJ>y<7OX2^;XJPX$8%|ZSEiX?Rhi5k=N*YCm<-4jiJB9q+%!IsAyT`oKi z@#3Gav*zK z9q8AyWU3v1D#RBWe|mc(q}E`xL3{mhD0TnYyV=!u9Efi9JBPXdOk5TlhR}CX*D8z} zlja!-Hd90TMIm$(lIQm&bwBjI{r=hIgEM1hD4a|RP@#MOJc3O+W2zNIq&v|9eG*tC zYZNd~CFmDNTQz>6mDH`OE$&}ub`JzAuU=N^eIKctthZeIC`q<>r@U65ysE#*r2bsj zY%j$z&&=e2mW|ub>3X`#+d5b@_S09Hn_eG(eV}~lJhg+z_Ka?2p!iu=S8l-LKr_A{ z_@--kZ>7_iW51ihXi4;Wq{Kr>FK{d@OYd&{E4k_IfzYpS*X?vGeU|)ZjJf#=G&cob zXe3y_+2A$J>32}C_E(0mRzm9jD}0t?u}l?@8mR`Z+fVbz-%)K#GQhLDZu2H`I`+vP zpBST6jU7WnELVb#pfXKGfyCh3XL{1$HLZVM>_rHRP@5V@?||=j1gFuWRwnxr{Rxr=LmiiTcy&-+&6Y+R*b=IlE{9yAX{osLc)f+M7PayKg~KAwSd-29n%4P8wj zAZxR%&pO|ntfBz+z8a=P<;8xj_w!oDjc}fmN;?i~ms?hzpLg~pVjAo(s4w^588iN!5$x^lLOjy>kAlhQ z{pp+{v?@Hr@R38`F3#qQmkSU|qu2B`boc22 zc)=(qZB==C1O+}F6Yw)9+c*hwb5nKJu1j=S+J9TH;8u*gv3}`_GB@`!Uw3}T!&A3e zW-aIStKFB_ZT90TSZVw191EjIGTh}g8E)Q8ncy$~h4FuiCYeW@V!@obntdJa137kC zi+C(daZE69F6$p}`E(^C@e<%x-+MOl;5FMwPP(Vr@7bGqc?RJ=LUbuvlU0p@+dDTg zJ38IFeKu<#gwzn2f$>ld{_*98kJwW?*n6THUQQ+IKSb`RtV4IA zx?%49=(wBOXw~NaYW@6lbQAb%=fY~TQk-j_>DW8cTGpu!$B;X0o|DK)&iH{t+XDg$ z#{+UkG~Qk3sU~0)V|H}4|2Q;z$~=?XrItVa9c@W4XQ)Q(6Z7_3 zz0cN$da#~}g1bhidI8m-J{%lq@KfhjCKh=N*d|g93ea6I6dz)VHv^Q*%kxje;TxfV znwKwka3X~VS9;r4{1B${ceK!)UwqGA!XB_=OX~3j)0Gdn=fw$c$!FjPVsAPgg%(BF_=IHP-MF%5LtcJaxKtf07Nk zGJEBPw->GkYr`9om%llS#^8mD-laZ&T;vC&@3dX-(Aw#zqKQgEw#R9ywoA{pyNB;d zCg0RO47;23TiMt|a8K{MuJvuouU}&rI9umM@4HwkRX3AS$_twT~{7N^zM#qLYm zjumouM?I5d{;V$=TPmF45An?#nTVBieB%J6+!L8~P%&}EvgpUe&Z#%sdpzFidKqJS zs~S8NVN2Mi(X0Wt+YY-WOcVJkke-|zaB-CY-pM%qBL`u+QPinfGSMtqqGT{-I&<;l zy$Ar%$a!*xKxcm4VR`@Nbc5@jt*dsnQgZHn$T{Cr7~|eK!j4QE)2}XB+pJhtR!@st z8Sp8P*5)n{luvMFf5QrQhUkztP1sntCt!@!97HR|*P+b4ig?tJqN!ALw7Jj*s(k57 zt+$MNUHmIX7e3WO-)|A>qv-9~g#&ko#oj2lplR3WVkHoEA&eY$96YdmXIJC*o!lvl zxI)ULTJY#AM*qdHvHxP;y|^JyZ{Ka5a#sHc?8z+gK#fxBN$WeNxCCmLA{_DS);P!Q z9iW*GQJ$}Rm>f#koLGka<=C`yP~8MQf@ekR-;kG7+vY{H>MDn`*dtywrM4N7tlTe2 zNpZJ~v+6DbFEoD57`NwLEp?CTmASd5M?)LS1fa$88Ao;M)ubu~7 zsDF>+j`6&-DGsw)IeTxq*<*Yp9VURd-dURxY*z_)n*`M z-kZqUwbe?i>Pz>zrRIyh@}0vk9W*nImS@{9jEC;z;0q0v$`uvJ{{HFTW1VPWKT1al zGV~Rj1xlj*a~@}E;t;!u6{(Mr)UX6lD*P~eO8R+lis*$qnQ5aY{*-O7k3gZq2*jg* zdQO2f|{hkm65|h6LkjfGTbK-t?~6XSY@fFa}%cChsn@ilm_>bQ@ z-qWB>_&cbtp!XLy0JvC*=!Fn>uVZMbdK2ll$|)0nhQ>AU39l%d23%(}Z@o~~ z_oAXR5KGSp5@YisCp!wfI%7vtt5*wuxLlCb9C);O5;V}i$#gmJeyh9Jp_nMIf*QA$ z0+1#JNOmvefcdngIA_|;NW&npHcU9uUgz1Ot4)+ybQn2VJAc+A?CX(hOX3_;-t>doDCHDfY(cj^~2nRYR9+mVKiogr6|D9pHp<*9=qxQ#x)Xxs}!$F>g zgOgxF;i=RiYH$@E+W*(AX`Bk&q@xn3BeewO)=y>vD-r{qXmib`?B#zNVM}8I(kco# zOnO!!(wqPL%V!zzxgi>N@Kk4afkp1LH;8oG+%&OBiNBKHC%s(zv*&?w*+9!&@oyPD zThCmLw5#A4%*y$027ksi9vl*RZiR))Kl?uT)KT@@X*2`4q+gIv)nxrL z#{bl(IiM^>w(q?n?;Oj{!YtJB5O)@FBftL&lYJOpJFvQP=MFe)=1&_ue4X23&eSTxY)-3gvetHMp-@aH9%6qDU>|->P05GX%O9E_iwqr;bOu5xe&q zu5bi}WwZl@{EMQUe1x?|(cMj|eM-tTwaeb!9ouS-S+CW#0%63lsK{Do_5%1N&N`Ek z`n>ZvT<|LCeY)T-lXA?l00p&{K8ZE5!L&xf8|dJVKTxE*B#Y{Me+JFSrk*kl_f>oY zG__2MU)^CRmnDwXwbO+)rDGt3wQlGCha3`yGaFZ(9JGNSy)l6n<1{@eqaH?f6|K*z zmvO9zxZ!*mw(Hz03IQorhmf2yR-k-~_kV*L8*d$om$i=Q9(Iy`ifi?Ev&G0-DT_VD zep1hmtz{}K0X4{b%r%ilC+F*q`}?1MHZr}7JS|)t-U{(unf-pon z`FwzBU!~s7_kNOAdGGrsV2#XKT6K~6AwVYH7P%IfqM%oHX#5d+%@1+53EMav#!0Zd zk2i1`S~&x+iAHzio5AM9DZY*l<)dN$4bFT}5)v~kv}v*Gt6{@h5Be$G_um=1-i~35 zZG7vu+55PY?O`~?;+j~<k;`5YKJw7A4doi|Yleh9z z2CQKclbsvhE>mIiS(Q_mr>+pxfSBOQZ$wM+Idc8s^VtsN71iyyQS@VPn!!N)bx9@G zRNSv`PQglE3%` z>T1{`OILap{b9Bm-!|`01v+vcV3Qq(T2GJT^i=E)TnCUS#R)lP-e3s5h-%uUwYpSz zMt-ysv1Ir9!f%Pc0o(@gNcc*Lpx?v(Ca^U}$!_DTP*H=c5&q>p&b?6&m-W^97Gji7 z8WJO3;HusfRf9#LK($bb7;By)7X8c>o;`WRPrQRF-SdOP zgWGU;S0hz=V^HVz`Lw+%Ce(UB(UYAYkxK@_tyQIq z7)-2h0n^Ty6JS3Pv6Hs#qAUuu-Ldd4_kj_Mqm?+ULUqWMzOK@$gy(q6%au_3JAncc zWJ8Nj4WgbIf2KiL`cnMeohiIbII%t7wPp6yI-QV>zQGvmaef`>?qH1_QU?BBQmt%} zUMZVH;wM3?0;9Y2UylYmB z#$4y|uA4KqQg0U2=Iau!aC#Fd@FVWr({_0*DViszwtTb+%0+e zMeswC2wx&rv(yzugkM^Ifz`&>{eqP$K_1o(g;Lk)4^ZbSTb|fvFGrYtHL=|)%tI4( zYpSBj;Ajg%s=!l6A;rD(3(PiR1*{gpgPoH+Dq#F4-_y-~;LSib5MLiEx<{Ei%3b8J ze%nQDv9}E0SULIAw-zJhe(b+99tt^#k;X(JzM&qs^{ha0l;I5ttY%7tVZzhs<`dTr z>-RHJ3`-&w{XlK9G5AY>eKpz&smWm261P>@F(7>1AqSJ$b(T#{_1n13V=V zvWU`Gyd%Q5CmK%Xm8nE5H9O>i*ln@%VqnFH9_;LHOe#nVnHQj(;A_=T8>e3{mVWFs zO?~1_5CaRN1E{4c`SqnOJWk3t0^z@Q%AJ4=#U^bm&~bHmHg10}Ft567eZjIupNp{? zQzixvsYi4l8t#EQXuP^$gj))59iN`eBD(sa&TXv}vPf)NkK!H~){Se}tUA>lNP> zBRx>FZuX>zxmsEG<&{HvoQcKWOSJgsyVRQk;q3rz8>^SdnB2y0r$PDuX}#zD$N#@) zfxcEM5uib5yQ-v95|cO_5)|%8xk%s&zL9c+fA+F(dcS)HX+qF@QU@u1;{zUI0Hm8o zcN#8kkw7z>!v+|0d|-YY<7JWyd3O~cXCN*<4+jghQ!jKv)eT?=cPR&<62f=~7_~mp z5#dp$;59VQ1C1IBTP4#(<(5x8(d;x!NII=w_;o^ro8i?$&Bnq}T|`Y`y9a}!@wnBf ze+LT#@}hUjL{lbEBFK|13|{w8G$*mAwJUHC5Y0aK>cv6yCKyPTFb zfj^|~_m7GKF;qKHORE*%EIDFjGcTc^>TZrropPYXc_v{iwnvhM7oTBdgp;I%2!Uq3w6LkVo;kxND$xDdMC*C1Vmv z^HF;wr(a&TkRfrKC)53tyfZ9p;Xm+4HO)%JKyU%O&BqzyGg~*{oqG3dtVlIol>KpmXoE{%Bq3s zMz(0FWI6#ii!L9Q_$ZkT3j)U7%K;JP!n-WMi(w@oDu=+#DsL>Csg%me7vMTqE``4o z?-H*pBhMWv@d@P4rW571hNgxJthzQvST@gkYFAC{#28trr#%I&ivP|4=%TLRH2{*` z3GpPOYGK)RXGi}Nw|dC$%+U&vEKkb7o1l6HdlZmL5-{>>8vKo-=*ER$P}W}ioQ>b0 z(Z90yPSWiL+{SN{JO1QOZmf&cqTmF2WheQEJf<#I%<8J&Ue)Vll=%!uhXA^INGMdJ zoyd)W0{+Tip{>fH)-4lHGGK*^7(kd!I>2cx08w$!($C&5YtN@$1Q9lmfne%NbSF>N z`wE=U+BxmDYojac>kYr#moZ7UJy|_+sRzRSzLxNb!dKh%CN(U*rNzXg(2b`aqeB1T z+Qg%D9{giy==MXkn}QdOl?d=pr~9J^lkh!WH>5g~-h3hMaA`toFooWsCwF((yqVai zQIT@;>@O9O-^4D+zLqn1T+qR(Esy%Ztoiv|QYmBICatKHuXX+L2(Ey)mh zG7bp9=^wHU)DG4!$#C4grXJ9l&+iCBTw7D5Q#X4 zD`KAQsifT~}l(#SmH$aWam6u+w7z+kzC7#~4i66E&c9bWKZJk*WMlZj-faDaC$p%6E4U{yV9 zV3cUXC5~icpiJYV^z~q*kJ*zLeR|t2Jc(i{1jT1kwUW0qn&{G2c=~}QJ%-!ivVovQ zp}a7`;q;Pmj#{U--$-LJN8`RSOf#SQt=ZQL0&(}-!Fj*#VEV@`S1e@mzq_mC9>^!|47O$Mkcvf86IzH z&Q_zW6W!Du8g|^^ShP~B!p%`TwgFNc5wgDV+BMa?MOZJ)o-!?)x|tuby@4=yZ?PG} zRNTy%jA7r#H~RRr3^>o*2H&%*E~?=T;j{ua@pxAoSB=4b!K)#%BBy0T`#*yI>JE?u zbkv7glf+WgLJ|_!uoPjO;BsMYpfy+sM^y`Lxw7C`{N57UCgR<%Yc(=4sOe$>T(`eZ zCk&QURK&B_akXI5Oitc@oW-BA5BmQet+?z}Mk9TniZj@(#+>>^MM0?OYsy*X+sOb_ z!cwUnH#u63n%H;r{*ipzj12q%i|bW(hP`9@QrGa(p}2riIGtD+ev$NT`g+}W!N%Tc z=TARy7+l>bCxCRM_h#(}>@Kjq>0RbRiyxt6KXXN5`4n zo`vNPjRjnUZ4Xf_ANUB8Vg7TuD13^(UvJ}@%%22DLFP13wQZ1pfd|;0l@*(j||^0 zEQ@DPy#+m@>=D7&o#L~=LOtk09feO6j0WqO$TPzB4Zt`hQK9FJ3~$F{ttv-dluqX{ zeMRp_-Fs7{nS-=Q%wB!Yh=1L3#@q8uD>M-Hh;~oFHVFlL^&~p?ji_i1td-hkE;5Y= z)B#W-><*P1G;zz|I%9O@v)p&K*$#^IdU%erzBe3?*Ko0IIFYX;8(yT0&zIH*b&3+9 zlI1%1E!##^^dLaWamyN*4|PH%AnAUPTc+w1LMfqQ4G2&I^4f#21RW9VSyFX-s{W`v z`M+-I;BT)PMt+0fFYv$On-Ehn%J!5bD(zZ(K&udO6kg*e*4w;v0!hl^C@soOG+mS~ z#Qi&AKd|(R@57Y?G>^fSjqP%nI|&Q3G|)#630%L6kOa-Dh86OYw+;miFbslLod^Sq z%4o4Me4U_DJ{SY(*lm@S4!{lKi9qH z%gFC~D$g=MhE1q(G9XR>-+z^eo{I11111~$lY{z@>O%_YZ`{P4>xoKbe-*dfUs0?l z`>DZACasLpFlS1my?{L^vxarchm%^OY60h<#@!WWzl1sYRUZDAm0~U;d`kmcX}=0Rj3cpnd;Gl z?)|OG+4;k9enIK!57nT8y|$Va@b$}5Kw!QGEf|04V5D*1o7M-7%(Hkur9urwk*Mp# z)yo~MRxz3#gd8+=}pO$pq`K@u;@mi1R zJ$J9~-#>Hi<#i^v*4>qj8fbZ{VvretRwY9GKEzQ%xnrNo(NXSfpBSszbZ8yu2GiN< zh(rx)rBfmvQ^%@{XU3@e)I2|Nwv&Y1NZKZ4idKg`IQnGj9VK;~a)VVQ>bdkOr|(sc zk@{g&vFw^px$Ki1yHKhsIl8mEF#8ixksnmnG_gq%YBQviKMdDhnr6RSQ#FMhRher$ z=;G{6)ynws1pS`isFZ_Zi*VMd%VBS^qNk zs9ut@F>$SC()bmK3VtSl-4sBh~VOQ0+`vJHL`UEl_G-JT9^ z{~9P>6CWC^9meiaBl1v7>Azq1m+6zMj3lJzmDv2xhi0JG%^-PVj6B zPgP29w!f%IZ-4nPG`LXY>DwC!&Mn-X6hM9XUg+j)72`R)Zn>LLntrpJ-u!)UCc8Pu zNx@njclnam9_-S_Q>W-hafm6O(s@+M;1XNj_;EM9;{^gKzY7lSQq<;aiBm+?mBtVe z{tk53<~DM>Pa|uTYx)6O&>OGmQBpld@WS}|y)yv`<9s%NoSBM+)Ax_DxZd#VG57$8 zz$j6-HdG?P%H#FNcC>#)53zcj#I5?X`A|A>Q23FnAkRB$KDPJ!Tlxi@MzX>C-{9s8 zqTtm5Ana?aw#9#3uSgj%zkG>%r#t;NYCPaJ_mrP+G`;(Ebi8xNwh~9|LABA%kABRl z*K>}2u)k!!p@xgk`+5%=vz;9aaEfk4jN`8E=<5st@Lhh~w>wi0Z+C#-R9jwBh~+y@ zRTMr;YR=EM(3ORD#xjYw8jdw6T}=yZaSu**C7ILr2|aOaGt<_!wgvz=@(lRiC|4*T z^>9u9osnu)KMEoy_SmK@68va-YBYi?)M zk|}WA8^5g?{65Yb%4|v)mOmf@T0qn6&*OHwKEiAIawP#ZRu#j6goHV*T9Od}uUO-& zl^}{|_;pM%(AB&BFLvA3&1;Bp$c!sIvl-5Y340L_m0#e^+*`WcXG@=n&xU|!u$J?< zwgrCuQG5GMj?dAwws93+N{hV!TMka}*X7wgwGDBfCQ7v*8LE(Raq>1~Qbpulbbf zsjEWooTKw%!UK6m;?TEzgB3c4v>9;c`GZC*>`|>1YWvBd;ZwD_guf^-*5_itv^_05 zKThN96V?V;V9D)9=pyETFurV}>z)MADmPa5Zc>nMsgoY%ytCF_vL_Ye4>UzIN)>F6 zI)l@Aiw^n#N?mJ!qrWID6<_VO>$sE^&da#@C?}|rbmtlQ)TkFtipKUBS6P_W;LJNP z=}+RKb4iVUP_xZg3+BQ`j=WcSw${TRMmS-I|-&z|Bx;&zA}D zIa=TOnVy2LVNC0X+01mVmo8qjrSmJ*QGXJh*=d=*FAh#LB_uTiz(yP*d_Go;a^F4| zBmUykjPK{w*k0V>sHp?RR-H^SFzE!%4sP=76N8>?Lx zO&S>`Dw0MYT=oj?jJhlt1NtP_$i>4Cl20DD_z-yV!(=X%y^T{aQfZs_zK7Zc60Y;7 zgO2?>Bc@HPaC9$>xunJ)0;l}%jF-YDMt4r1xSqR^YN~i8jIbm$=J>Ubw>}D_42rTW zLC!QZZ2-wEdBaqGnZo%Z?DO4m`&_m{>)*=Urr^` zga2r^+O0Fe4z= z=`~gX6C20a=ex}AmFI7x2VUccA@+W)DZbl9Wz}p|Cjj=)cHDvb19C-gkGyxAi8_~X z1l0W+a#>8|B=(q4at$;UjEkADA>0S6`Q}=l-*}KeS8n#WYjv z%`m{T@oY6B;sjUw4`$-A5#xYYiQI*nXPo5Qg`2f(Ax}hqDeA!|$byg9JnM#&4X6L? z2+BPx=M-{VaI>w4?&FAS?SF%8z&x*8rWFzjw8LZ~lOIUQ$8yS8&A5qA72tnZdJg_#g;%NZd~qn{OO-dLK*l ztB_}-_*L%TY{V|5@x_+}}n+e_TS9Og10{+#X08LBSk_ z3-YON84{qhY4n?KZH^wC7$0|g0B+-ns$Ca8KJMpF+Bdd(# zK&^Xt*=U?w?{S=K)y(eW%Q^UhG3AF?b{!+h@5h+%h(}0{Q^)r-K!<#j4{0|Fb;7A5 z&vJ_3RvLF<7FM9056Y6UXgHRttRLWA8NTmibPHY23R=XwqL<$>9UGK<_Ra3?1p|?k z?q8b@%*1BHTZ0jgrp+~d=$_Vq!r~;$4^iYvmDS@iap=h*`AbxqwDF?U?pZoK9%|!T zH02zbRYoI5f^kWYAw`dl{#5%K@bCQgf6X)ndPdP%yOl1v4~0Q@qGP` zXo`k~F>y00Q90L1LoqyWYqj$iHzS8{8nhc@y!P71iVW1A_2)O|ma*EANbIvmV z?S^&#-6ayH4Tl{XPXsvn7-d;BeOOihR`ZVAj7>aXsKkO%8?r5OC9hrM?YDc?k6`uy z5Udk$E{vLr9Vwm!!2Y%%x3%DtPUSAy4UOAHrcHR=VfuVC8N;oJ z%o2+%cSY&fU##6)9DhK0v*f}@EO%YHe$N{REpcSJw#?hD!*q0K)_Bg%E!Mituu_Qw znH9`pQ-p0L3NObZ+a=#7kBRcd09R?k*rj4ol4cv?p?t7`lhU+A1_S2n-GZDHsH^rD z1?U!MBSAY$+qW@;#f3D@7n?Qk6Dr8TNNPL^25Ba`%w7sWlpLu45F$F2f-eJ|C`pCT z;qv5xiMPccso=So#=3}Mpv(@67?7$3e(YFx$e&YjJ>gOI8q2ZrSrYDjA*XUK(sB7^-i zz-2E9|5>uYTa5fq3)DDL7Vy69vO`kIx9?cdj?hXlYDV zP7(>&+^49cMK{%05#OMDa%q zHCq>fbJJk^mxakr0P|(GR&7*k=`2S#T@)9E;Jd%908)PDS^@bV@Tt8AKg`A8BOvP| zX>%r=hXzy54iT&HnXOw~d$Sy&);K}dG;EV`_CN9Ypc*CIM2!7WWUiQek)%vrbGmWE#U*lC@res5LaTIw7 zm;H(PYmlEsNeM&x?~G3@A|Djx{W=CKryDJ++PZk0bSpPx`Zce!HddK7UdtU~smnD`5cezr`8oY6 zd|EsY{T7y6~anHXTbF#C09=>m_v(7r}{5a?Qa4lU6 zL$dQc_i)|UeO;$*Y2;MbrkyStp=L#c1aSAIy7P=yG^O|);LL!P4;H!+h>pr8hV+ZV zmW8=0a0Br4abF^{^O*rYAbbJO9nkxGa&Lrq{5mzX2Wa#*cybM)+P7z<7=pMcR0ths z3yrNa5mMA&-WB+%;GRdI?P@iIFgn5dNL#1P9G7NVD2}-!LfSsIBaE<4PDQhs%;o{9~!Y_X}C;1 ze==YyM^TP$9j#X4i_RYjQXYsx60GE7Jdm<^3a)Amiw=b`uEUDzB&wxg^bYDirXs_j zz2YvhFgj$zQ|mwhpbz{Ue|jz9@>sa*V5y#L1HW|qr%Ov_9P67?^OQ}uOVHsy z>Q;`B?A9F*HTh!GgCkDKF6T9~bO*ya>5;s)+#2yMw*bHeVrP##&l@2aBDpBl5|kFi zKuyek;Q3D32+Jd|CbHSy)($rao&jG>r3lcvpsom2tMNQPH=B5@e}n3G6*Q4*_RwiH z*s)Q(eP2ybd8l7cb+522;_fGxt+%LEnD;#BKq5sIY}w|r@^9gj26^rdIF?Lrg9}m% zNE3d(?RJj6HFEv0r|UEK*Rk`k4HtttKN7H1^tFhkVx_blm6;Qa2?@^h_$kaG-n|1q zU%B#AvZ!-m7p@J2oUrU5$}0r^7(8fx#xttquhps#)3_?=V9}P@wWa zB`d<+gPT?p)D>`iwmfa<+9~BS(A+nsohO~UKK@X-1&AxG5wjkuy|gn`sJkKsAQZ7kB?{1VpwHa8N0?j4((% zS<$%>)8TAT(=f6=8DIvXB8H1Q`CDAUQdPBZA@Hq5jJ9`&_N;)_3PPP2#osTJz-y9_ z^%hR!&Vk~S{F)&1%<9mbHvo08)578hm#`4ln76lm&v^%I$A;ywrh(S18I{J?c8NIL z1Q#QhgJL+=`w*KevP=0+FgnAQpn!>(VU7;IFx#c{%u32o4=Fm7(=|6vUjjEEau$Wk z7={Q3X!TVj%gvGI1g&w2C1^FJtjy*G26yZBx82F+gIW#u>1tp{W2`G5JB|^C4R@6p z&yB#gAtXzk08dNc97YLucILRv%dZ5VSA^WngJS6_dKAKV$VzdOmUj7uIx5Gz zNdX{2`~&kt<>5&Z)g|$}f%X1iDu^15{MG;~g0}R&1FT_mO3)^XD&QWFN-<*BPU{R< zC7!JBD_tAVwtN?oaMi_WjWh!UMlgHH*=5Rihy-)F~eoe=%6tv(d#=`rRgmsyah(unNl9^5JQzY93Qv0u8&nV z^L+1?0r|G_H}Ca~y}*$g|$7y;oM%^tAP#8(SveH;K};S~jwH}>B& zgKpX%ddStgbFr@l#k4ML?mIBYre}oM(J?E>jB22<9kZ`5@*01{QepnIxMYp}Q~+Ok z_d?7c)a!77)O!6H*Mn)vUsze#DlrIqQWP3SVxDLX3te=fg=~AU-TLyCUsu~EMtzKx za#kkb;)=JZyP?;t?2a=LXExSFv)2c$NLDxd;I5J*|Xx{7ylps zSac&bxpH$3fCt>b$z4Dmx5DY1CWT@NQM@$T#*hi~L%i#B0P;-Ku+$WDX$pLnIJjWz zE64)>9hk&BKUr!t=~$}2>gnhCKNQ>*L*lhkBkQw#+q35NAb}Ty)3Ug)L12_>ht_V( zK27nq$|3N0pU!xl+3$D?G9O3jMDhOP(~sB*cf0@FO#Um%(wHpKfFr%6Y2(C;VVfxf z)RxINzy;o*9ADYk3nCqKW8^#EC@*&a*8Dr?Q37!?QtliDwkmV6Yb7^~O}GdI7Yyy1 znmn`88`)NYuq56%?uE(>zt18#OIW;BpFt}GTv%hBvU9x6gM}`mYsrc=xjqP6Upl^U zFHGSKRKv3L?q=a&KXBjUf8;CvIgdh2gKgM$c}RL$(trEiSShrXdh$g?xlz&FR7QGF z(-n18lEOG_G?5nj>C=6pw%BQXDVTPgZ9LA%ZP8mXwBAMv7sW#O(7Ls&Lh?PIUQyE(id$1WjdwhPfJHf z3$M|of*o#Vmvj4}r|N?q`5Rv`^oyT>F~`qPPE(Q_SmN5K|1ZM^`VE)fY@PPuqtsGTqR{V+9H3>zoq~4%Ow?J3hHMzs)L-KYQTEEHv}3 z?3w=%dNzyjapcTY-o#K7dxw{;jcw!o;Z3tYEMt&65a>(XtS}!eYFg+X7;` z-?(7MdLIB(6Wgubrza%l%D+cWsQ;bAt};^_{c@%zfHAaf^HGE;GKhPv)7*x*^gHW0 zwqmIUr8bqC#7k3)ZWX1y97l$?AUTHEfeJJI!wlJCHo)^2e8lI5EX~!hy_#b_bI^Zhv-X|1Da7Ry!@W znETj%?n;f`^Dju(kO)7Z)dco`?d)7GD}T4%U%6{Vv~lnOM)%ql z3uBIHR$`>Ht0kX~Plb4tk2u*tviae~wLHSniec>_N2HN@Xf_6v6#_LPqB_~&=)GOj#1({MSD7ZW&F9t9X`qb4QeO5&L=is{$aGN~vk6mIyR)G3coMfa`A7CzJC}~VpELMOFfxY z2e?OdLF(F^&)kRFOO>uo*-ncm`dql3A9c|COl^$05WkStQ(&3ejx0oXJ=D|vo~H?A zfl2W1Sl|2U9skbR(@@P>n`rj_FRS3|CC6rGfRqO_kGyN;0F3>tl1L00NB6^@Aen>@^GqDAwqb`FT zgPbuTeXtXZeAbl9`VM48d$bqDKPp+%ppd=BZT)ez$>LC7!kmB^+ztFPvDaqhnv4L) z2NSsP2$fgGwg9X*y~lZTX)Hy~dL{O9@z39M0Qv$GB=^Yud!}=O0=qnEVN=x`?{qxA zaYw1M@34rGfJ#qOsFqf08{PYjkU708c>L@U2M079L$CHC~btZxR(D z_x1}bS8M{F72|Q&AED)-Op*}SjB(MNMsRmS6N$zn_@GTdFEPaiy$BYaHt>w>x7ZKs z&zr&wmNQV`b=t|$+C&p?pmXy`f)vb5j9}8Xpzfm@gUt~ju5tSwR%y&jO#oY&XC6dQ zS1}zD)6tFQ|3=GM=R_9DS^o?k0j#6GT!`3UUDk28FPXwOhbdM)bEyzz*yCMI@3p=N z=gZ~13eU61R%le1USb7SB{D6K&Z?V5Pf!^8eO}w5xKVm7$m#uI?J%Hk=^I9IOZ5xe zw3R~=yY;-y)uzY4?KhBOzBuf&f9V6pD{&e|P+H-W+(h%NcD&!T;LXHlb{cPYmOSp# zT}l%D%J{84`|;G2_QS%jbaJGiAP2QnZ8}EC(k5_0JEsILN!{l#s}JDsjLF8gm>4fY zB)KNBR&Gv3sitp}4)wd1`}j3B>ftisP;k6&+nquBQ@`_3Rpy+ycuN!xZ?(uMTw6NY zarU&T7!Ym3)Eo(Fkf&j+PL-`g%pWgBGw43fDdjMY+*yHSPEl(ue=NH3(i9j>!I0!B z%B;DsQZ()}r4yN*#;scE-;A6K9Jv!q{$wsV^f4qzlo!;n6?8d;0)>Rgcbozp;8)@L zt)`#-nDM*D)gEE3^qYy-{I$;rao>Z8AJFcRGRNeXKVtELbyIBezWK4>LOkYl|4`2K zdHG_F!Mv3(4cb$AX#8#wy*2Vlms^j37Shyz1JH>~&d~1WG|zkI)uzX5-36Vt{xj{H9Ota; z_~MA+Qj1!U(%&<@pq2FHf-PAY8$z0q&G3?ZsUF<3t1#ShnzkOD(|d`K%CIKaSl)mZ zEUMMcGh#nOH3Ty=BgYtwyZNhcJ51UN4|1aN%E7ej4!w*Ahh z>T7#lC2gN~;WW!nUtGPaaNZ9?u}Pve^|4!!Z1(5!ktk@Q~2 zs;`Q~pa)`Gr}S5{8^z6aS#@rU`ZpeMAvsJL)@J2W)Nv=7WdNa5`fx#~j#`Bbd~2>M z`d)wv=bhuld>B_~L3>a{`{5b-EE)*H9pRzI02zc@9eRKba1k+1kphNPqhaTlv?|O# zo%Nu2lD-yY-;;^RL4|iPM*htpLU95qDFefv*Gg#+Q4+G-8Fq(tItJW!|{b zAf_{B_KYD@z<5Z0aC{swtYj%U%4q21z6alX{a&S>fL|gvLBe%$Ny|KLt~~wzbY5aS z++zLJwL0;u=S?7Q#>wJ6uq^Y_H-e+=e}GW&EYpIk!WMAG5xp-I#mG34AjtILm#bI* zJ123w$u27_4DiwA+zF!3)G}6kpV9*q)4w0Hk(3n|uxfI|9}L*?N8$|DA@JC)Nd6(z z8Qu!kc$ye0v{H!7Ya(f>?}TkQ8`_Fl4z}A-VDgFCCy`+FKieQu8KQS2 zq#S8y)H0{cMIK~=-cKf0Q<5CM`V=+ zpRATgVfoPFrJ#Xs+281ZEi^xEgu^DL{0{Sd`qtqzh9Yck(cjv+8JW?ivKejERtb9zsomj$y6P<-M7@;#^?0ivsNB9fmBP;L!q*Y3B((GR_V&n&NEI9P8@fEoFv_Sy4p2IF^Xpop@j-M-=(Cy?)d=diZ%cD? zLo6jBiEVw@tPKumwC)-1V+4H`sDrHkN53TL;QvKv>;J7F*Z=+JzEA<#<@t)7m&h8L zwZ3&scgyv0O|V5fwzl7O?b+^Mbv8{NTK*K<_un~R9Bvj|@cGgjfY4k)-YA}J+JN;k zmf;skzZu#UIR-Bs0(mR=wbdPMm)(q1mg~o78?8WF39_a#16%eT-G#{>e$cMtfIFc96xE$Dk1pN<6E zr;Q&6H&{yZVeaUnUM3zg1c97+1wOz$YsZA8Tz=>4sjWvbK@cU+GjyW$)6kwNYNdhS zHK=*8EnxZ2pKyRo=OWJVOfy~;`Pb#zzTnZhG5N;+C1ESYRO6D zFR$l7jp{t8w>3q~Poe{LwE&epJ1T~9o*Q8={@Me;obB_hXdA;Dz4)FtWem8r34e*c zYMFsH6gz6P#qP7_ygOZYxBKf*m6!Bp)CThs3KeQ?qWX}k+K5YN_VI~gmxPBx^ONtm z49gGG^>JL0w8Kg4>=DMB&J>sf4CXCdHx5BpKm>($Q}?D{gf2ZkK80MkSa_l1+@^F%Td-VhYDP3RcoP0^6H}?YI;meQ3|I z{B)DWMBdA2oJW&6*-W5-y=@);;0}=~z_g1_Pf0>-j-{Y% zK!Dap*A?HeV(-b$k)R0w3qq#x_0~@uoFnu%2rz2S%3zyM1Cj?OD%9&gc_JI`*a}QrxPhZ3sWU26Tcv&v-RV2P)b!zRdqb>_rj?spCSii2_$Qgsx`n5O z6E)L~&7$8A9Yy;Y{BfTqD!dC@=}{Z+4KqMKda{WEe?TcJIVZ8ndOGAeN1xl1?@^0_ zW!zYQlyzhxeX0y85-ROV3kU=;sAWsSpES^l^MiXOPe?`#sbFsxKhv03ABjssE*RrL z<;pQ_m;HKj-9&fG5b*b)sCZ4Mgz7j6aI2PE~c4De%4-Z{m2?b;kY0>~1qwfQX^%37cz_ z`_6?X6!#WZrPDQc4R&B2Z%!0p?;gpgkW$3SMJ0PEOznKqhcz_B`K#FF>PpSY!J_Ku zSMq*5Oax%R`qOi7BInPS-G4Sl@^lF}mI2C+G5oG9#1^bId7zFdVr)70Hh%fj-f|$+ zYGqeN@>UN3h|$;ONIPvO3f9j!a|XDD%9Q{)G5wthx<=>#Qzjn3A!0#BVy=?0 zGU;qpPhmohvoE3NF8<8j8LZ#(v>c;4=_~orXgPx|mK`tHm^x;4)fJf&Z{wTZRnOn- zHn%9;V=+Q04{Fb04~FSuMw-tma;^hT6mjsP>Ucl)BaP?5Oh%WJU9w0|d^VR*=QWYR z-Uh=k&s@vFslMr@T%?jFFVI$gTKNOzB=4s;3jAI&lWBMmyZvfTjrO=LTUsAvlne(B z)1@4+QMDpYdsa^fgA+v1Et(ZCs``1w2CS2fV10e$?c%BI>|knrz<3Uatl#eY(x3Kw z>I-;Id~!$3Ugx(&fkzwi;j-7L<+DJzt@B_L;7%yT<32Bl*8;D1XDOsFa#?MJTQrY8 z7uh(%ck?@9eRP`{koYd;fw|rgOf08WByD&PfI;~H>t~Q8T~Zhe8{I@eDr26=H`#O; zZ2qg80*<8~2V=bk);IbToypgK19E448?0djoA-56fG_TB7+M=p-)2^e+vn8>y6~qXCpoQ%)t;05G{kMZx z$tW}iOonwZmL@srEz5u`_FzyDeO%6QKI4=CI0R7ZMT5~l58V3fVjgy~tQyR_w=CW* zW}*8??bX87NulP)H2}P^JEtpfdfy0PS!3J*`HN7K(+g_|H3lc`R075eU9i>@nz01G zjul0cJ&jL0?&V^dXXDgzdK-vEQsu9sCCNpHStfr+>2m~f(UT<%N4Rx8x?GvX&m8r( zz`o&LE3mHrcTO5z#A&;Icrr4ejiCbA@Ye;I;HV4c@)`PUc%RAAPid7hrVpcxLIdO7 z!ZE8C^u-@e!Y_lARYy`yPRID=Ac22$jvbSOMA+7fIe7craKo9BbG=R|I@VNVwiBzx zbT0^qe>YpD%MO2z9;T-5%bS9glD`4o4+sQymS{3vTT$BW!Eb@Anq5e^T4qM(D7R(U z{h-2qiZ_Z>b&h+V`Sq79>bM`Ci-lBxn!wKA8-A7qaLZ_FXb~lWSi{{oR&qMp$)=PK zs;evI+U;8x{bJ?#ay+6>#)3Dn3x=ughPYo8#MI_ZN&ZTo8|ap>CnqrO$lSiopkeO1 zNUSD|d!|E%#D<2Z*@r9p<=;7&!&>B7b?F-s9!g3=8da$K-$R`9=-`JFAY8oNCS+k2 z6zrIQ*7NTiTQBc1>N3HY%gY;)YSv;s&E;uAB5b@_0g0uuPz)j?ukDch{&LrggoKz+ z-XHH8kaK?~U<7Y!d>5_g07FaNaJ@)c@$a0=7;tO8cWckd-;V|G_!F=X$@=MFJ!YKv zSeH9a+;(Dpj!u_j!B>Nf$KMqi8j}zmdHVd_lfn@{GKoYcV~EU(p_GuYXjJOH|N3;r zUB9vAZ@4)lI1KbTTEY}l!8qLOM%SN6RO3VPin^k$u8ZnsH&;{91Tgi0`5E~FUS@Ct zSoU2>%>=`hg>mST1vLo}h?Oi=uPJnt(V7RP&=x;^cly_leNpR7@C~^=5PBL+wFUZ^ zo^}TD8dh*`af*%meT=Yqxg4Yx$t{hf=jo~YeBBm=UTI80IBnh=TvfkS5+Kpd#JWJtyM5 zxOF8jL$_g+V=RY*`emnUn2Zz7v&h<(*)`qFdT9naQD%M zsg2-ER&jXznv>7Td0~o0Fj!l(t2x`>w=&M`UCA@{pE^7EN*hN2*b|Ga_*7kZG{Zfv z`!)0mC%)D1&5_s4uf2!`;5ym*jHa)`f9W1fdc}ad&?>=h*|xvX{ISgBnrOqA=AzZogzspMN1%=}=^I(?&CpD3?-* zMzq#&-}FDW6_w8U)tgw6`T1B=)rU)(vV_gICq%6}uVzF%_X>Zo7lb2PJfQ%6QqT~)`{SM zUGsnkSm$N3I}p!4hb6`m)jHPSmndyPl!fyf+v=*)hF}-gc`E5;^{~S^|1}TuthRKT zMq2sMA)#G2}zF$oxrr!M4D$qYGMzyH+{y*kBzj7=$eDIc{ z7&Lknl!;c5ZLqAq^P?vg}x(`sFIN&$D2b84h-Szh~vg zRiLk*^Z(;d*p3;D#nzY;W@oN^G?yy_1JvK#$JyB5gI(~0rVjrA?rAQs94;iw&NP6X z3;Ey{D$N4*$K_n9d1!V*KamRs4wStdB9B2(J+Q_~jGnX0qG?v<{WA#1g@ySHUVvNf z!NE&!ZjGF^RUE_Ch(Z36?|_#C+Cy&`L1ojbG@bumlV)qJ_VC1oHoW z+C8o`%?w(gt0(ks*mtx}xE8+Fm=CHbJKNrMXmpK~=7cKJXox!od zX;~GX1@3?B{&Im>B`dEso)_ujEhE6#Rmdh2ULGT7c_SgPvG4bs_u%m0??aCtpV+@i zQJsBI`#0iF&!Ca~FDLTLm0@Yn6)+nzGBe3_9t9u8UKK45QlLna* zxgmvoIxUg^nUAiJz62`{H}nE+EH8=Sh;3+z#Y?3x&I}$}#0hg1i)Rmw5la9bb$f%Wkj}8!wCtywVG19gnsmTz9$60} zsTdIxx7-W$W~{l8Jr^rVI>eVtC-eyn@7$vRT%Wp|L(m^JA(qmQG?$$fZ}YstPAe#+ z7)=zy3x9#Kb<8SHXAc(jVY9~xEPggJhxo3boPd%u3!cw*N0N{h1x^RsG%tGqa$frX z{vczvA3^3d=luwrJ=%ad-46`kWU#^lK5Q^Sou&{a46e#BFAT3;%qV{pW;k_de6ck@ z_xvoIUcBcI_1WWW}uiAP}>4zK}bZ}CU1;WW2} z<&e%NA3rlWGXqQs>}MpzA0zh!j_J9&(cf2jlD{jo` z=H}XH>`q}YZ8f-sjqrcJ=8RVK-l6T5JV?~6VW|VIRpk^YYWLnqAPJi6PY z4KF2;PUxV6uatH|r`BVF;)Y@w%YZ#DE1Li z=TIUR=cHV6qR!p_{O;y?tn#_qstAhZ)4@{(i9ll}1}Im}78!JdxB$-49RqN0r2cfM zLZ$sdv90vW@7yfyPEO(-5e81m9=5UB+MD6*yyB9`n>3nqp?l=S3;nGPR$=+iCnDw3 zs?Fq}ax2pGz36!xPR}Imqz0yi91x}jM3@A1#`j=)sTea{0Qlb*%l}jI`i1(1w~DV| zbqEDKY`zb$vC6~vO5s)Kay$<8Z%m`yCzm@n=3BPqn0_8E6$IkcK_U*iKh-Par}=gW z&}CnMm~crB%8@38w0-2q{?kh6x?HaAI_B)UH9B;$Ig2|GReqg6_{XLtmK*VZq^Vvb zqgBvTS$nC0=H1Urp0L-4NHa49b|Xj@?Mmwo@{Kj~oE8`Swj*r$so#2uUO&C9={bNAfY3a{02~r7&feX*UhTiPg|q#+nE_OMTXu z^Ddu)ks$ihh=PFpBGM`_KG!@N2C)gRQ%+M$#m>**|0F5R2~u7Gl|sEpGC_K}DH?9^ zhDpwN?wC(HYrXOq`Z?ks&4 z3F6gdKy+*YDfdCH1a%*Gro1%v=dFEX_tVV-cOC#9=75BU6wzM5E%EDzO-oj@=cJD3Bv1T_BaxSd88Ws@?~EXSMmKt1 z8)Mo0v}xPY4cFQ~)%pLvqWaJ+=DhLj!Ro=!`L#9l}-j; z<+R-pnlB+=*2K}@r4!b~15x>qVUw0Mb!q9{`7NA>-YqN}ez`_lb}CIR*4v?WqlR=pQi}DsC4IfBLG7 zefitlwb!Ejz49N$vBp_zp580twk4cWY)=qH$2YP!P24(sG4JR)Oz8IWS7=EBBr&N_`vdIxrz?aCWjUXDw|tB35X5>C!E zcD)RY%2sAo2L1COhEoc43%qcAY#6QZ)9&3^MiAUD!|}f6Ab&+N}>BFF%~n zye4T^ud_Pbc{o|KKYe#Y?57@3L%7ZQa>)zGmI~_~? zSjUsAP5MW-Zdq0ihw_A=WDI_As8xU9hgUJ1N^vO&KN6N|47k07fioBGJ#cU`^VU8A z{#Fdh)ZIsS_NuTc zEG(ye-^|tH$V_%K#N9V5gML+FLD#;CO9DfTYoP=#S)sK9QNwx4jtO9e1)v|D1y=5E zO+luP{e_)3JEkHZfxj;Hn7Iy=a!~|6U@%YTVPF4YFsFEZf3JhPTz?IgSTXfl*4WL= zi%73X1@=#lnYnPw(scu-CGkhF4)Rji(-l4mqKKmh@paq176e-UnNew43k6{XX1oi4u%D?n|_ho0Z)$pQGtCP;|eGy}dIs z^klz=!c-OayXBw3PORt3D_l0STr41Sw2}XcYJ1@(H%+y&@Arf-=1*Pg`67ufeBwgB zC-p2V68cgtFC50Me+A&({S+(=Sp5R(ArI6X0g79A2Xmd*hR4BF?tHy(haJE~*z_r+ za*#$G`~Vh)??%p4fJP`g)L{0pHIvkIY<{ZgV3MmjleU8dY>ONn>b7Mij0)&W0y$%* zxm2n)y|dJlt5=&Y=kcc=+_EF-GF)3lO4|+jV;5GFE5?-rA>q16DT%~a;yG&$l<(i{ z$n1pun&FQ$&^v*}`xO~rEbxM0vy(Ant6-xPcippHsqW6S9nmfy85~BoeeT1Wt+fqRqYflh?Me>+zdH7Mc$5{Qy^jbg3s? z7wFnAcrZY-tH3QxDGFkWXTXs)92Y1?Dz_z%TP~6IbJyYNKy>xdVV?rO{JtVF3|7yI zm@o4aya)>UOY13@=EX-^>%FH4oGxwNQOANIk?IrjcF;TR`GF%dUjiX+rkMB{q|-0o z>HnmCPwQZOm9%G5LF@!_P2FWTNidTC3A+6)NYjfSS`^WCsc*KhrZC&LxcxlWP71p1 zuAG`P8IPV=lC)%1)#ttfMh5$R!#M#W(haXTMC?ozKm7m5$^C!g@P6r;ytR1C(=a;I z?t?MlBLQ7S(Z)VAKZMR$-mQ3KM0!_$hqBT?+u10rk zF)o2URE(P=tDh<1D@g%k4WC2nl8?TNU5h`Oi3R-}cmC(qT6;z@$vSIgHK5o3&w}UN z|3dAV{_MJUv66>*Z+*)*W8*)B+G8P`rkgkh39%TdI+tPy`JJ9fP41Fo(FR(U3YKXU zwc=5^EL@rQ;$o}z9Kej$kd_T{CKABDVh*tr)rtZ38A^?N8|>fmX+$|FFoYmsKrf4+ zZef+bo}~CD(1@v>tP4e28eAez?A_L-?Ib@}`bJxcrF>K;Bd(7xKWvj)+ZWew{a;Ir;YCtj0=5 zg#W7ksxw_5XMRh+3E^U99qPjNrkoo9_QV3VK_WX=v+(mJ)8o@7$pj6;Sj5D-u=vkx zcTk?j*aj@S1%GGA{pb-syT{fY@>TEVistq4y4^lDn%A-EM1mo)17fldXhg>9nDE4o zqM{H-d9}%uegceySco^WK%l^v#FCVr2l^rzI)1KFMa2ZMnZWm4BtMGTZ|YRqw>QVx zoh^ypbOMF#p5r0y0rW+L2)hqyQvkAC3ph(uJMa*klEOA-#7 zC;%Wjd8Y36_a|x}ItuIv>UgA2?Pd1RNHDK1^P`&=6opg2B3u#gsm42@tPt}-CFOv>dsR$q7Fi>1%eIh3k z-vN9efONZ@KI35uV~YhV`??#zcHQekq)}s`0=JzcDG4qJyY0!?S^@9klz=q*hBauQUFR|V2U(zLol8InFY2uSokP`$ zrRomwtrL3+It5{H1;}l!5e4{n)qOxI-RwXpPJCe5GchxgI=md1;Iem`#37FtXz)8i*V5%HA3+wP@i zty5ZXs7?pix#yxHWy`iVo8Kl23-V!(a3%U3dI5}UZ$jsUw$x{WF=Db8PEp@Ys7?sT zO&x4J_N0|8#q#njTTMS98?f(b0!9sAw&5{8Pei^Y{KktA8SR2zb=KsSJMFrbxYltG z*2Pl^Y^{wb?pjjNJrccbBEexfZP0L8C5w4e(r&vW8CzRfYjEU6A)bb<=C3g~xCP7& z&&pGl3YoX??s|Ox47VaDj1|aDf+fA?R2FSy*l8wjoCU1wOzxlG37LPm3RlH{ItMT| zmz+p2ZJVGEej&mf2Kkt%8W6#kaQQ=q}@J-^+}_ zKx#DvtToBWhIxEA&Sa-|Y|CY%hp>&xd2EGgS32h8l5Y3yQ@pKWVxpaaQU~?+t-_ga znksq7=kFe?)T}41dY_jDSRQT2;a5_;o2mXnMaS0hx3P)PR2{iD3GsI28&%M;<_#cd zv=hInxvdp0MlFgYN5Hgh)5mP-$y^*kp9i;9gLLqic!ZdbTZN4N4Y4`0Em0xT_K*z< z*7c|j&(q(&$9SP%3VjrqfJEx}fxuD3&QU!vRZihr)EpFzgFl)snv>IU06=AD-q zG{cl-6V))rn5W;`Vx$(7Dw!d*@6{%_s&kBcEzp)2r3|>a8JghA68Gew@c@l_3n66q zOaY;F4P;8$o7EUxGdPIh?7K>Cb!}m^zXfK@M82ASrFjncAUm*)N#qlaF(R%V{1P{I z1L0{1tAHMRiP!|8O~ZgZLy7IBI(`0Cj)0!xdUV$)d7!E#hhdepmkCs3^@XD1y23yy z160_I2I7||q(miQ;5Ybf%VU6yIAN!RgIQ{Z?2E@ICPTicRa(lv6XgM$W(!d|eifLN zSj>vhENxy-rDH#Pgp_MHQPZ&&^CgzyR@h_og1$+a9;9^bA6cEcJ9Cur(kbDThviG? zt4^`Lv@Ls9I5&2j`wjR#J7-LXz%##LCiS=UVDHS+PO#pNp(s%Sx0}-dZoh^#Uq<2S zZ0hZ?JZk8;&&~2ATvZe()00VOA4JC{@r@r)WOv zR1)91+ZVbHFW$V4-RG8no&l_jHfAeW90>Mr zTG&psy@VT3wZaNI?d_odL(7{e8M^|eoA&LsNR&QLX?eU+0%q8j@T;9~I5HvNOn?^n z)SaGs;Wd!g2+E6-f|tav%BE0~MaqQ985q7g<>gnPLEldNU>e z-#On_AcHmI=8M_uSXCesU_h0?Oe*hYg!|{afMRIwM3$6SlOsf4>Tv% zPbP_0=iP!BHxrBc87AbLlK>E(tc|ngpiL1%)db8u4!?yQO&bwE+B#Yv<16HMoTUVr zeS4Nc=vh7IF->|@fnC2eFEwo3hHIcGksId`kyeKlnLVXoMhGO<RKT-K(6Cawy6&s^Zt`+~06lQXkSO*MVvbhA5 zx;F(=b6T2h?oRTLDRC)kQ+KYmY!fn09Lr#+mUfhCSVtDO#>Tw$x2_GxB#4$6B2*Y{ zJ6(&Ci*9QD5}l^qeoPygl=|`j0FyR% z)bjcZV6d|1PmGHVnZB51V?c`Nl7PRGqV!kBkO9`%8z7Myo}lF}3u*tPSG6w%MO<&q zA{g|=MM}^c0|}h&rsQ$Q+l}5PThzUO(|7&Q*halhX)klfoR!zxnyEVN^-p-d7Puj2 zO*0;y)ToInaXOYiPba;FWVUd%$E zDjTrBoO#AF)0=BRVUN0~?$Sy;4I?teLiD5E_n0F%LY6aZ4dp>~J$#dv`WSUq08okE zc;fWf?Je3(3`u})jmVET1%&>lrKqNZq_t@^dKaV@emG~0NZ6K0EpNJB2CLhodKkzMMM(D=|M2&?=e7tO$@B)Iw+5zvZp4c9bjHeetC1uNS5fNK*{3-c<5LSJLpl0$#I@5Bka!k94QSZ%ScstD%rBeNF@b@kUCg2VIR&R`pT7<8SB7$-k2LtY&w{tlcHW$U z@)%@t)D~16K#tvYmj)KW($MW@o&J)W zd8IxSo4;#}bp?8cYm?s+Rv(4J^(@CLZVSyetax5nOlOyW1vc;*V8WvmM#Ho6_8z?{x%c&el14Rqm_D) z9Hqy+@$3B!o|mViff|6ZBr2<)zyP#PyvE@#z!*5xA7{0V)U*V=CYPYPGtwm51s4BV zW3FCPya}yXVAoVCMz&ryKloN`3+5ECvALj2al3hd^hCm9jD!jds@yV&sI>oQcAuO= zNadTo-EJJgyvNzuE^Q(qA~N!aFbm}}Qtof=-{WBeNrQ3>S{4^xB3&-Icv5l%tb0S% zdsNCwAIll@XeqA*|XSzdq-3T8Zj=oJCO=pgp>{pjCJ;B3AjQx@S3Kx zuRld&kcgk5>5_orDdG~$`wRoe5B{-G>%H#8S71#`BN}Orn0*j&+*t;Ri3(bQ-Cj1Q zW6IDZC24@8EhU-lI(}GxWBwS}!AJlfJqnaS@MR4e4!8W%jC;xk%AVYyy@eDL-Nvxf z3)mi&7k~vwC2=4!{si6Bss?q(rwG6fxbT1H@c+O3_sYL?A&k@GEXR)efs-VsF+2oF@~kD#Is%`41@e|xFNyu{shbzrEUYg>biPB&)N;|z^!du zfz8#wR}xVRU7qLYAG!$UbUS^1EffKVHy(Q#vNVXT$?M$j&?+DEsUSMj) z7QP6v9Hfi|=gr=St3cJua49|$L=J~WA@+66XpRz+-Tx=#uaN>9MKGx zc(WDv6Et&pteFU1L)}vR1l`+hF`^i(Dur+qR+w+b95HM)vpI0A#GTX{8l0?TCPoRuqH?5dp&xQrajeDEX8|lqs!<$QYGL z1QMAI?)w}OFi&}He)~uYOwP~{ePE&|@fVz<1mkIt2+S_1R zdpFt-&C#9(yC6vgHxZ<`k#-Q1+YT?r>2C>YAmM7{<4#JwS_CdWfkmS`L2A`J2B;eu zlz9;!aA20vE=;X@015w5Ge#p=G;9uG09yvXZx~|Bj)MoTgZ2*rBH|E>@p9inoTD6r z->DgjMc^wVcnPV^xC)N^?qF)nzq2ISbU{@ijCp%MR zjOKATjgJ4$`j9IbXHQtkSx-EWbS)0O1F0XR470T>8Txh9Z@8?(Y#eLH!Y^P1G*MbEIBOu|JaNIMp4Zk;Ng9Eg~L*(0cxf`b7pWRORnPyGhS z`z~YOf8$1bCIoGDDb@DqTFWv<3c-5>l4-?i?e)$S!(ecOt}%^mU|I?5^T6_!qi-*j z?@QrhD=wF~4)8<`3ZU)(=ZA@ezy(Pq@`{s)6RCzBIfm;^5|G5prCz50&bka_o}mul zs$j7Qc%5807OLbYD%iJh6^vH=VghepWN>zyz^dwxfExJemMDoT!2=p>;Yl85w~$fa`7=Duc1O^JJ}7 z94@@o^7lkn$^GsEky@)Iide@G#O9}%aE3LVZsT|Jm4b~29Q0Oiy-2ba*@3x${d=SR zectf&sPLbA6R|K`z+R^wEwMr5z<5YFxH1?|-@Am)7^87mnoSmEkp&o!zvw#tc|iNK zKDwS_A`@$ZSdYOBcoT5p#a3Gm!^0CAb9JmB)&KO$G*r(WG(?u?H-Y2MOB|9#=*t#z zjsW*V&I3B(5nWW4piQv=w1y5`@6a#(U5~{ux5YTC6I>(;|KRF*JFZfb$7!Q^j^Ba% z>26#T&X+z+P-8tGuOOt6V4y5KOwHNd#2h8_ky-qdZz1a#;DDP)&##c z%Ds}8>X#Yv`#!5lbi8vor8?xM%H%*&!W9YMgF}`>DQoWXSRjm1ChT)_r0WstX^_OU z(R+#{B*G{7#;+A&;e0NS4)}Ho#>BDl4Kw}DGkPP9KXS33SuK+9$TTHThDWPGN^6+J z>Wq`~O)zKh|7aJ(GlMMNoP*sLt<9_PCKR{NN>RQEK~#Qmim`oas@CoPL%03}B2Z(T zZ!9x!wp7J{Z0zb(bc37WN$or-!nFco7 zQ&YYYTfI^N_tJzf3HIzY_syzY^s7&(MT~uq>y$iyTn4~A94K`lwm8hn3q3#3j=?(q z={afW#A^Ru;o34QKXS-QL?~iwlxsU+&;KFAD))rbxpLeXFl=+1x@?rTU(*Mz!O7l5 zpL^;}Jx;kMv?qVM52l|X{9_z@k{v9b^zhaAVGCY7_K%5IZPCmw9EiL`S$-zUJ?}S% zz)Qlsf5>fnT&Fd9nBcFzD5i~a4^*vy0)b1_Q5ti30wfiB_gj@-w#fS(g*3&Nz=`nY32C)c2 zHC;;hF$NAx{n55|vnFy##3&nr>#~po=e6m4;A0EmSPfaRAFpmfb|^Z<~U zFT~c@H@r}Ry#}WP#_>GXE52sK^fkRB7M z>HtZRjTuX{!WRCtRSTSg(_Oag#z~LRje(=8M{m2i#attt6A!uuz1`@{PPo{UXc9P; zKAwiJf^(I1zn3hf{tG<$={VF7^4dUC*@ z3jJC68j(g4no})$m+z9xMy`P5vlP;O^EUddUog4Hb7!mQ;*|?kOqTRPx`>I{QbhQ!@LP)bxlIw^xbSC1sG}SLjk?r1;x8=mAyELgYJX239zX=I6e6%`+D^} zITkPEj}zRnPI`r9E1@s@?MsTA#siE;#5Sii2~Iq;3CGx^9~&OMwY6P3OL%Q6fv7?b zJ1odNv*T2Kz~(u(b-Jt$Tft=|08x(e*g7n;F4hfUSMYjjz>}OwmQZs zm`!>b(P2Pc8Ar)IFUBG;S4YMtTptNrK-V9lzK0AI{F{J@ppYzWd>k5Az`VWxM)95F zy{8BIKru9dF?o_OMv#rajbX$1tAXBHh~@~sDpz*b?Woe1^@44kKeGrQDj>$0)m&ur z?n#b5gXKEEd3ek41--8?Ba;X$4D{|HP*cnalwz!zp>Mh1r2Hg1OXR;azpz=2AA(nf z+LtF+I@BzQGW?zp&y|sk!|$%-fC*8C@=hz=9T1?z*N4lRW#l)Py`~pLp(oc$_v|q@ z=Nl-^3#caqX^TYlKc*A`#jw~spNFUp(wwj6NrbW`w#1C#uzt#y5LG;#gM#Rw<-Z(! z_h~865&q@>s}20W`}_L#IupU_>{zowV7ZmG_0PVK!EDw)V#4v5yNvCm@bIIfzX1m}LPwsD^QBmWNJv`_ zhs4~?lMR8XXOQxxOfQKTzb)4)8O1G8Kyi1@?QZjXqJ0U#D~;p;4}p>xtQRV~#8Tpd z#~OS9i~fCj(#8p_n^34k9p9A~d*0~_uX)PKd^z9`f%S9&In!zHRLUi$r|mrSnj2oc z2zA>|omY|_II zt*K0+(y7*q`4o;X-j?Hn)`|D|aSdH0bch*N0 z5Ga*C9=|s+Zt)i`okMGOQK=B3xAz3_QMQ}JIkYLMQ{jgux zTdPrE$-l2208;oJpC9qf+8yEea97v(v^EHPUAKhOQk#x$-o(zpU4U^Up@h@Yv9sRh zjOWDHQU~rOTDwfI^OfM;dp^h)zH(yrWUz+n=_jTUL*;e!HV9Rov0gI7xr4^gDvGOY zl>Sr{(Mm!ahM*Pxz99kTpX`=GpQHUP#m%pTe{dSVypDQnH5Di`YBKYCXNPWgw?%67 zr7pK#69P0iY@wz8 zPm1e{iZAt>WvsVXF7^I9t2j-5{B`%A$vCCXm1PDb@OwfA!F+_`;*r?QfCm0ykdN>! z)iH-{0nhs5$#uOG{rpUiLa*K0Q~%C7*-N#I@!j1tp^6No_0L2y5Y4x-%Wa2-jHh*G zVFPRNNad^7Rf$N9Wg=lj4Nfe07pdcN>m-QDFTiUy9o;tqx0G939i+?ZUcNw_P$%xk zfsJS}1pevoD!k?PGv&ALaIjbXHVadu$Juy%jYAe zbRW3FpFE}a3(w2T;-g0?c>Nj5N@=NKr3?6T%RO)%=^nHtxRX!kTK=*Kk&Ofz14ETqRv*C$o3~vk_*fQKWt; z6|lG#m4qJicaS`FBZ#ns*NQe@#n0HHFDjPUCsR>|2K30gghg#@eWO^tm)X|!DDafy z(3At{2sM#QNe8l~+K0%^AU-zRl?HuleHM!ArJB5G1hrs>_EsqFKcXI%J<}R){6Md? zy!FDc8Mgq)W=JCFiaUW~U*PLb2k_xw%s1FHmN9DKbuiu!`bM2z3+xhTCzc^th97nY zCXpTPo%Yn1#Ebx1;@tseg)Kl6rEqI=0@yKJMp^e%m5XmqY|e22paKelRyBr3BZl4V zRKC=k!6OY1I}ve4(Ra+&L1TU(2K@t=y~Bi?B2gc6t;|EbT$cFum@`m@Bd6Jc;evlL z&ATm?0t|{Xir3!n>B58@P~+l& zbPy>ikb*`VTSL)FvhIX1efMRazOf59;(k3$kCVsve1B*btOX^-2PXRO@mXI^WbG&a zPK`lbftGn0p+b&8gEwr4S^604uid0OW~Q=a@My^u1P$qUkFCoAB8galSW0sXx}*W2 zIGGU33~9vmIq>lxnD1mB*O8S{?wi*Rw?GXG%pLwMzTGdLu?XwLKtIGXKsg2zMKZ4d z?5Bq@6PZ~Z6kxw*(10luaDsrVITvOyOt@ZeH&_R)4T&JGU)msGuks`Y&Pyca_Xmr; z$?!C|2o0wN!l9T2v#H*1IH_(hHd^f6a=-6>k&Mu04^OYsyck|&SQFw)LY)v-DIH0i zWKFDm7V5g+O7@Xz*?0EE9$$j|M`2+*UIT&1;E!ewd|bs+7?U(mvR4y+9mQYME3k4k z7$RRQb6L0e3QK13>YkOKsnr`Q4uC}k1rNYISV?p@LoM~*)pw4aru?e$)Vs#~gxD#zcaK6#gESqo^n*RS--U;}&8M>a z_PkV43fe6 z*<$vgSp+1&_O=mDz6Kz=8$SvE0Q;DRll|P)P&|HyHPVe|3qkZum%<&(#n$@114OXL zAF#mqk1zW1X{<^L4STe(Q@2JAmt+HskYAZs`|zThp~j3*a{)F4epnmzTGnEaHnyqf zrbGJ>LS5nEz%=Olk|*PTa&N*-<_ya0FV@tbD1XWpo6VD1-rk6HVP9n=#yW@g|4R+kmH@0ANW2Zn6A`lO`=^h@EUspcZBs&0f|jzfd^lIRwQ_< za=4`cUABTN`eO`L9vZyul!a*+G-TgBS)t-hf>`3`21|K4y9r*3xXYY}#L1vZJMt(v zY(e;5;=z=GnRcWf5m4V*0WH@wgL*@zr@t=;`_+im=L&saM_4zm=ERr{vxoCF#`^eS zLW)h;h!lrx|D82t&YhVPk?C~|TmB6W283Do+b+G;L53H>B*ycNuAAP9>kDql5{fPL zzXpJua8+ibtJ}Y`^xp1ZUwzB=BrNj>;1m<6Pae}nUmE`T-&wC!Q4A7igoh>Nz7D-| z2F;X(mRC<>tcg>scc2SBeOMyiEY;!XA~qEjC^&n8hK65beG60U=Ag;tF(u7t_*D56 zP+9TA5}$!R2CBnX!gY&>C?@W}vFqJi-zqiu{1D zedmWQqk&+pJrhmTr=i5INjvr}*x2Y`J^D2I6yhF<>zzVY>TMAybrN(0Ca{p#{xSSX z!t{D3X#1lff3Y$*$eaZ|w~B}-sq-{9Vk3%?*&2^CXoJih)WsKo`#Le?Z;Y=1N6>4Y zq{W`l`&OkFvoaz^V&DP&HiBDSEb!u--QIHY@0@idv<-XQhDIcwQV$+1Xm{tZzHcZYj1REnt6Zs0 zQY5Rb37SjfSHoiK;%|K9u;wl?(x@3fpSS{)i`@$c;EzWoVwP+K%~!Bh-pnUfRbMb` zkfFbnl^1}KNEbgV0NzJ`kvz#={q~NOG(^uN&P$Gs2#LmS6=Xx&JA~lLtfVp!wflQd zuJ_a>^lD(2L>z_@nnm<$t_> z_4j*Au$9Xc^Asc}sHZ_@J2-RY+%GEd5)(AF8A zM?a1cKva<$b%$w#g!yCG;xCWV`ghk6w)MElVRnD_R{ zj}}%Gj2C*vG3d(jw+iCo&@_S>L6gX39251_TMaW>7L>KAEdKs?7V}jLRM$q3>bPeF z3?m;6>;+f2sb5Kypd=3D76ZRqiD!UaGuZ&%xkIOPROw_WvHN30US~>yXBbjnX9eQI z9nBn7W=&>U4RDrPBlGDfkxzLLtc=Mb0BBl5Frn<1#cT49)_&D1c#f130;!FQT>Bcw zZrlG52WB#RNXXzVG5V;X+8Z{|ESiDV*$K{uuXu-HS5nK*FdRRQM{zi`d74k~22vg9UC0W%Fir z0*EKu#5MzJ0k!Ciim@Q(uwd6IWHU!%4GSjZ*cmQ!PuImg*eAd?^~UzD_dpI?0fY6| zAy9VQd`7eR(HOmwBsLs+Hmd0;_2uz3=8bU$4CG#enH-2oh(W^H6!Gk<>VMvCBEt1$ z=&PPxc=q1D(TOI@X<=GBoQSBL~H9MiQ;rplPSqh3<*Da)U=KX^Af%pM1KO5aNmN{T(Jb)&1` zZ@l)1RqnW9a3^`)SQ^M=NH;dfj2dx(;oaZ`#8m%s*?Y#QhPS(p{gJC}o#^xHomihy z*{1FxtJeVFmfMlb<;q(VNY^y9kPKlIYa)0AgU#CnDX`cljF7I3gZ)gXj{A_&w*#{TxP8uHo#GUs_p$KW%(LLtWrdnFH zq$8)-jl_EDYM?0hewQ>>*WsXJ$u;!mtmH{q+eR1LG$cOWtWb{ph?`dHu)u>eCr6P~ z%8tI2RrX?Z*w#S}qu~+Q>M{P(=%T2GqkVE}vq=Nk{i_8723=5PslP?Scp)|s;HpLH zW+NTsyZye+JAHT%+YE|-k2s=xzvgTn7!ui>xJ z4Zq@QEwd5UFOW`I6VCLNfUN>b(odb`Vy(BI%pC;uU#U*UZljNgD%L~<=M|RmahoN|{Dotg4sKpGEnWtHd^$uW-4&kp z>Gv5RgM^M|T=x=)C~}5fc884L7L4B|xMp#xt>oG$Z5Wk*X$5G!fAjy>7xBOFH}5@W z#`=RBS(7qZH*QBMeLmCNqtkFenpExzy5{V#$hcBSwv*L69ZU9Jp5W-FL7Y|VL|7Wj zw9*qqbCfljiXpK@-?02RmuaeL^W;p58}?d=sU1*M z#EI{JVwd_-+4SYXoYC5x{3T1jfBUdtunMFMx2_r(tedk5Ebatu)-FoEb^EJ(>(YpS z51Jlo+j7LGG^6m{)9*uM@)L%Y_4d45bqVmIvs=#yZmO!Z;i@V|Ou54{kCx7T(YZ`Y?`F8v=q}xg}ez! z`VZ9{znZUm^;p_jC~Q<#=ndD3^OzZ^0o-T=2Qlu@f7ne*$;xb%%nhX)tk-_FjdxYSXKig0__jL+;_Yvb_I2#+ zJiqqox16Ko6z>CWAC>ak>?Pi_Z{>R~lSGg7N*L)#JnnCnG{A6P^AH_iJUv6nVB=kH z9s-_Ic_><5zI_JcX~PaKO_sM(&10#72_I!*c1>j49$^*iLzkY$_j(M|-`d#<)@YQQS{vHxNkE~)TZ^R`!a!h3RiusZrvNJ>gh6f-buN{B41 z#gG2GH0W-D?*U0{FFGN>DU+Njy(nVMI>W?AYJ)lkW9~B7Q3M<4d2Q+>{C>jWy zkq!0%w~7@^ONN%!d&tO5-g%3;F2Tj)pD*;CEL*X+1P<)&3z~>;-w*hQFKrXl-hVj1 zo69)FZKF$lCB4VM-e}|Z84d|=x~)d+WDd70%gl#5l2S;!U5$@-m9?@}su!_WY^E-j z^5$BPJoUC*t7fn-fBbjW7KWf2T8)R?Q z1BA(h6A>WQe}h(C>@k9`4nVaBcEX<#*CO_J;7;i_(0T<4jEgyp;}IKiD}mVMU+~pD zN1`#wSaWu2IwUGP=M=A(SWT|UBwx=t_4V4l*zqiszr6LE_2i3%nXA5cCJzG-&Tg5%im zY^@>o0*l@Z=N#*X?&(WuAJ`+A*iw_bhBw_7?nNTTbhjJgX6W>P>d(R30T;$`gvqCG zMWF!agjj}%fGrBv??gg0+F{$odz4L@uwjzv?)3qMh5ZMHM2-?_>&Aep4^=}ZK3k0( zm%RN&m?MzB)?*72^rUgQpGU0Jur0`8BCL{^I_UQFogfPvmX_RlMgDO}y<})dEq3hc z+uoXWqo1#T!Meg~_m98*FirOKtm)xL+zX1i=w@Jeu-tOOx3bUIU#;!a`@Mvq4ZxNs z&y;!o&ViMB%>1gAUOYpb*l9WGAvGJ=ayy9EWVN_JJHoKF(V9ByPZ_v^nNF+089Ynv zdrt6aqR+06wyU3(TdLL+=xOn61#a3(Z;mFqnP}8Q-jfZ|=0?JbsMaqOzenTyd(?;C z?ecx|@_MDw`2!sjeK&jz{h7r@e5S}fLlHUH{MuvV8n>03h1%B z;Ict~P!sHRZ?yBn2i)SADbM&L5h}Z?AScjOmBYwjWOP*rQWx9r@E4x12#Ud<=A=IU>jVkMjF0|&qaqncy}f-M_@TC z5oyA{vZTNEU;dy!DodX1jz)_L4p_JHkqzpX*WwH3by`o>g4n#%khg@S38K>-gfuHXAU}ifZo2V~n18cXayK9ju@xJc@z0MJm`s zUcG=I?F`~OMiCQ-y=7I_w1|K0Y;MBMuRl}V@SS=5vd80ozc&zsZ^z{VeftlPbT55< z==v$zFrzQ=Sj8vAIoPg2!8G_R5!+Uk{dN`pOk!-0Jag`!Yp=Fd$eY${2Q~`wjE0JB zszY+m-)k)Z0O+&Uc02x)qhY$f_LKehbH3h|%mz?UJ)&%=W)=D|+{xJdb^2W~k2x&? zJJBb~vW=e5QvVBFx8>5Rk?&sf>s}eHVZ@RPGUobQtQz4h$gv^+Y#?E4Y@!?LsLh!x zA*2pDC{5f)*J_9fL7yVI$lXcEuYS=Wyby7aKD{wW|M5a~oI#R{;~CP^@%8(z|7t~a z_B-)4<)4U7hn2VQpEa2Kqs9SS_(-~_jb2HfOdp13BX*o@ADKTZ#l?Bp*xz)ijh%D6 zRcf7QwqGFUlF?%%*kDbdX$0ZjgK&G=ikPCiGK=$j27e|xv^)GAcK`f;a`Q{7CevTz zJ*c$>zS~0oYDM*N_-gaL%5I(8E|4^rIMaLw?lcN*~9Bjbyh{*L0OCnlDGpb$VW9 zU9j?9Q|jQ-!@%(c2*wOc)=^Gq$i*6uX1cUgd1szA{>T{AR&*)9ld8oU=H&;?l&SNBzg?f$aA;OxA8hxhd-;g?-(S&Iyl|vd=5G#OeFdN>PExsQ*;&F?8qH9~@hS{$2g8p}fwqKZWC+M7FPMiy@2m5vdiJ!iTHS zF^tcW9wOY}SKoh-XIXX6@JA%@OWBg@>|qg+vbWSP5KP$o>COR%keuRy+%HS#8K)E4 z4d3!Ln+?SY(#x32nUyS$N&dY$b4?%f`aU$HpVjcm#f<-eF@D%U=9lz}G5bdT?bfzA z*|nEPWBooKP<^l?Gsi9ZYYu)?O*4OL>dK##**6YXlD(=vOU@VM_46NTc|-JdG3>^g zm0m-(D@A$6S$Jj5db6VF0({;M5I3H}YD;+{vFFM9+OB9neTV0f`pk~kU3QCDPC8dVz$r&^uHZUTp{tNlI3pe8&Nt$R zlk4vhwt$@&=nqP8ToGNy_&jm^%`wofQ99yJVU2k$p_j8IhI{L2##b;(m1T0yWoR(1?t!jX8FxuFICPul%du!0zRZB)xi7pQ0P4oOCTM{S#XbsY(E9j_x+CSlNtL|CoLhjs!uisY*}S8p5;W>C^(H1wQ~o5utz2D zVVd}F+ACatJ={j)u0yQ! z70sB<&>?7!w8z-ErT2tOkfGHF$@+(-fqTZXZ>Liy1<}#ua8>ZP^Rdi1hDpsw%5HU& zp4Rk9rfVjs$BOewT2;h&n^u9mAbfK`md|gro!m84v|(+(z;;#6x!Z}6A$c)6G7z1Q z{s-K=6Seo=@1NgGMMuxMzZF@fQe-?!DANx84Q{kz&ZT&uxvcZnmP6cD({*2-5>YUH`D4U-;etz}whk_d|#2A)GbP1yKi&whM1-aEt%Asl)jC0f+ z*xWMklZN&z^fC{W2Z#x{Ux`OuXW{xZfL^0D%rY%&zy;$8g^U1}uu$ayK!KZR3KU}4 z$8Di6W?(BWtnn2lA%_2i{z{BhdJ=sAt)psD6Za=yro+^W>dJ+0&ZHf`{4->@TcR=N ziysv=x^}cR*P(mb*uBE)+Fdz17_7}k*bJ+=p5xy1&|~)bQ>O#sGydH1(kJ`l(6L>| zCu}ZqvX=jC>~+Ay)2`!b4f#y^=!3=f28R2qEs1>3DM>+P4{B3Z{1V#Q<6`foZv*3$ zp?3l)Xz<`h#tZc;%GO20$+?hwXfn<#o(f` zrb`QIYFj`_i_b}!DSQ28M}3Q13!UE}gO6$IhJ;d-o%&dcCf!*zP0I5N+bHDUsxkl`m83E=Q27vTN$o%_4Hn zyjZ(<-?mek(tem=NR~a_$ww^ z*y=Svy-pc*0;_B2yoWb=1`%tFV`wX;vOdP&D6G`dd7A6 zA(ma|bPmf1EzW_fwlj?8JGX{@I~GRC;&~?`g&I+5IoWn6lmYzRV+^3hUF>A_s>2_nVVGbwmIt2xwU=l(Gx(;B7*6*vH5P z^(HDdPFFjZyh}TfE7x+rLDItvjfJ<^Tk4>?qluT{-+6-KSe+WLG{KhF$+(7{VjNLuibi8#W`O5tFi=Pc(%%Qdr-)= zmZ6B__czF4^sv%dD2$W-x=Mh_z1H$w{U$TR)OTjrAXnm1F=rFy`{)I>gO$~AK$RG z*eN?v-p_Ko5dPV4P=-65$3ibA#E7zFB|NdG{-9^r*=B6Bhx$lD-gdnTYe0$PFI-{9 z$ei0LtCG0y<+ZO+iPj85X+s1@N@z{ignDm!r?WNod3&vhvuQ@bbDPfnWKy5&kch>4eaLO#_;0PC-poD#S1a9ydik5v9ehIyB}_GJo;}tM(wFtQBd9 zz>p z@_1ntok~x{>c&FwjCQ3HeSQdOn6&&t-g=Mepl&-ax2El&2urH&j|U_}u4{skpsgvD zok(@6{RBk*?EL3V_wa#MO6pC@tGM}X?e$Ux&$|RW&kP&sxHaMvh821*!QFzYE+B780YfGJ5FCuN`GG)>%ydqV74Z~IjAkd zLC4h%f&&WE51!-B+b6F9>&}vcqVl7{O2FwHG!i`AKr*Ld^)Ow;Q#{)FB#b3R4Ya_U z`Th9i$&rE&kdA#cM(D<5)(d4%Z6($F^MF1#0~p=mcyGr?d&@0Sys}-uv)(@%TQ3mt z5TLNsu3D|xF(g?R!u(k#yi@sA>FjDlm<(Ivoc0s;slH0@FT@s=Qr|`LzOd}W#Ad|n zH#XcmP;RlT)r9&$N5%E9^6}RIKrO+RB1@$XH=>Q#T~yw2_cSx_c6mpmqmN2wdWO|3 z?3*ax5Z`w~&X>!_$?B|QqG|LH{;O>Zf5~nyPXXKrW(`>P?8e`qu9RgWo7WSP6?*-% zKV=q=Vxv{iB<`gT+|r~*=Y8Q|n|0CDzcuO2(9$P*{4H#=<|G>|+M8#?HQAn;Gli`x zc&(;yfSnC#ey6qqLZzYR0bQG^0OWz&-h$*w16crW3HFt56!k;{1&nowJG7+wz4;TFnS}xWBXMqpdybaq{b~xRa@(tz@fep2tz?DSrsOT^LC$O<$SkC0 z^x{}E6KNR>{Xvmy(T;6f5~`;GhznsKMBG!hCJ-Efy-DxE5@2imm&X+C5 zn!XY_ruj^iT@G{h>T%gosM$40PaLU99a1;C+D<+{6_7x~TFH2;L+@;;4w9v4#vY>oW1z!a%)2EEMsyndfgaZIne&f?9A1{paJl=C?aizwkRf#y zVStD;z}EF?U#n9#JqPLo5wB(l2z3k{MTq?c$#!?gC`%f<3MT2GQXGg?iN?R(4lEHT zF!T~-_e2BL4|f1DBqYlxYA|CojcOD?xvc3mVabkAyKw8Rsm+6i$u)BT?L}OWz<_ay)$e=7J4FC_@2S~82Awy~F zj4Z&FdFKmRDq#35vEUARH)hk9fyEuA0Z*`*-W+c@$ygE7_YHpM zD>~T?6x~lvK#FBu(Yt76r=(Dep;@dwyvWV0IUfV%`B@i7mdDUq%#2x8-BfGj_g5g@ zuk*J$$yOy*CCu2Nh5;1HM?$;$(|ly9iI176$ToeN;27 zJqvzAHw4J25G|sFJpz*=Kxy`Kv{ABRPgykI#D_N!jBSM%gxLFVCK<1T|KKDQ6)QT+ zdKxzBPgkSaR5O(IhHCbO6~s2sq@&(9DMyGzP@cjIY#ssIe=^H!DtgJ9Htrv?wb+L* zB_9x@1p7y_Ilsv+x~=AdAf86ul8RZYlMwe}|4^ohCYD6g8pb3^pk7^1ZDAbT!f1N! z9pHQ^;cU5i!lhie9lH@raKE_E#RjKgNfOXCe8uh#r~V5GF9x9`sfO1y9r{{X)iznD zcL~_1DtRWc1v#%C@vQ-K>ss74Gypo^+4dtMlwJt8aL4vhFJfJ|)l5T-)5k@2dQ4V5 zzQCW)I?uSSCP*JrKhxK3x(T=F^*G$QDm?+YZpTnav~vLk6>xIAPXHMZx9k9s{ydSs zKB~dMLu0rEWwqjXhJt-nErebjh3Rn(n}yf|2lt=q1{Gdw(92Iq7Q?bXLM@$6W`M4l zW$2Uo1Hil_zILL1%;E2G z3O%8sSZ3()s$zy8pY2gd#p3v%Dfi>E;++CMWD3Sf8aT5EuVSK4D)}jwW8%SQH0l@8 zmH^rh-bm%}mkUHU*Mo^J0m%7b6S!TKuZ@=yhenbvc%OCOjC={6WO^gjLajdHuA+pt z(FW8jAl!sb%O3_sh>efZee0`&^T2R5C>D+7$bxNY$96`a0iR4tbZt7z3oJi zHwZlw`=gLUB|KV1h2($(t=}^U85XcO&)R&Mk4M6W2Iy{3G)D~yb=07)SG|$(SRH!t zsG(9Gp)_@)54v&(@y(9RtuYhL2cz!pHib~A#hb2N3amsXL4Ol`2av+$1gB8E4I2md z72x?4O>s*{?_%o%F1!vZklCI}o&>mILSplM^>Qj^>H@b76#Y9ZVx@-6D3*W<{f63F z^4E>2a_|V<-Jzo3Kw?;dPqS%NM*T_IKGIsV-|SUjMg~y}cJ+RlrOKD*(_5=QbQdm2 zh>MHHJp@tZ*7)saM!lgJ9$Q$W{0GQvev#TcFA9G5x8MTA@~#% z?{xy(Wj-2@z3~qYg+xc(EOlXPHEafp^G*Med%w@mtLQWn)QEgx!$R#a^LNc7fhS`f zh-St>klXtjo_f3v@L@4{wvvHcep5xw4ng5JFS_698Er_)`Wr&tIWWvd*jWqA$nh9O z8!l5TxpirI*|#PjlYp`Chhcinvc5)DN$>$C7@_;xuq!@+xV4gdhxNJqoW)_6TFAx; z#&hTnn%rtRFn@W48-hBAFT4fn!;J`@iv3kB9@W+q^2La(O^em{({gcBK@c0n5vSs= zxQfnlKBfT+OMvA(7IRw>P;z?;aC0Dn@jKVHMh(N`7&VvKAX+he$l){d+Iwi7zxO(gIgyqJb;I-8RGic)@>VwDoe_Y0E}i^X@6NyNkaa(`hGHI zk+-1|cygKE4KS7(irKxaIUZ|lDvs(K}*cuP<2H6i=r|SI#i{6J<9m_{6hb5k0qKSaz z8UTzmP}mGLfkUw>xCAH zz^EC1`mH^X^G9tPj`pdi{E_*4djL*x?37fveHG~^ zurDBa6z#eV(#;uGjA_Gb_eJ@FkBB4oP{1FkE(_nj>EUt=wxti~f@yNvJ5KqUzTuGT z&@_9U7(j0dSMBIkM;|vIw_MmnsO`RbIp6iI;q)_$z)d+Y(8tzYDGJ#8!;~q@1pwEj zTWpM3_-<40WJ!5cY~D2QZ-Wn+I3Pd5@Kq-4?6+BGx8+=VXMHLfd<3I5B*byAk5|Or zXL@RHZGuHHSc6-}n3(}LuV-ArLjWrUghvlt7YK1e-N_k6jbq2gp&$Bzpvt0_5a{zr z%~~WDt5UT#@nR~Pir~fBQ-L?Nbft`4I1cWc!A^C4FaG}UC(^eztVWI_$orVp8mr;o zgOh{@AF8#vlukNbs~c^&=!(}y&nVFk#$lHB=A_JV^AVV~e(@LI!dv1zA6pk_GbRQq1Y6bS|ZL^i}SGwvSkiUlBuh|g`Gqh@xvn+@0 z3bZHuKW!uY-u~13Y|&ca0GQu`UhViB&GklM!rho?@zxOecwY}{D~I-hJIG_LWDVi5 zK3oN^#S*q)yK8EOH04jy2M}=sJmLO1)iCW9eAj{u0ubEK_$+4rBQ4 zjwGWiAKvI9?zz=6WQJ11n>Y{dZm*NUcUO9LDbQcHnuAkuGkp70sRUw=6GR~6nwyJ0 zRq*>NR9iLsWEPG6PiT8uy)~vtdoV}XJ7pYR6@ud zQAYZZN7MKwy*tH4>O-gJXaWyfx6LVd*fzrURh$945|<3@Y5rLqwGat;TNVQ%+4@Y6 zkONml>uh+g^S@VjFxqPHnf$TadQ*qPoDDyZ_a)q?FEyB&EGsL0^`Z;R3jmw+570+gISVux=KSzrqO{J3 zY->Wz`v*I&vznofmec)P$aAT}6y8>c#bzL$3%p zsjFvf|RFE85i z_(c&%sGCtMiHD$OZ2pg{j`)J#R(Arb)d@MXT?YITxVPLHIa08mWiv%Uwwlh}0$%9x z-_DV%;MMmC}%in3d;8W zquH;*MyfXk?m_U=SWs;!a11NaU;dqCC(-Poy=BXeVGH*~4x-ygm8@h1Zjt6P!3sCM zto}7n=FkbAIz=6nbWAX6hU%e;CVhZJ>BnSd zDn4yP8JS}-Rl}26=lJqgZ3GH$r^ijZ9-JmAX#b&31<-}lD)t_RXPBJ05)@1(pl&%` zhS7WK`7PX&J@SvYlnTWhZInP1FtD+(q6$H60mC~lq>9Z8ad0OGX_3t4Xu{n|0!aOMI5?=*`+TD!uGjZPvgR zF%tya)*F!qs1O8#PwVe>damMJoaxqVU^0byuC;AdL4Detr`^LM)xd7J9(L4`?dF+r zX138)w{FU~TW>T6iR3HTBVS&x%deRJGP;Tn>RpIyLuhi}_U|>*>1lK!=q%lOjXsGT z49ug`YyQ#w5#+Y#*dNXRv>`9k+?ZEfo$23am$RFh%enP?i$bWT(ka?A;`+9mwhGjC zA4j2K_9qk(jWP*=m0!xNodWow4g(F$2c=%?aXXzaz&&ugm0!#-8_;$Oxu3k%o?sX| zFvg8I_{G`J|IP{{^x>LuvOm6^N?;5!ZYWa&C=P`K!Dc(_DnWksVDvE_IS7xfE{K%u zJD3OfpCw9tl@ zYai>@%NQqNOaDSs#Pw&SP$M8c--uevIiVrIk^gAYJom6h2|bQq!dX&hY%}U;lv|?x z5ly1(bxRj`1vh5>eb3!6WxHE9(S$zT_Q&V9&T9R9;M?(}8}fw&!tr8;n#;gvja33S zxb$*Yz?aMc5IbMv_$h-w8Vwj^0pd-EMfE+?z&AQ2t1n*!sa!|8M{@aVK}ARMf}1hr zN8_7Jg16iU#u6Iha%kPq9kbchpRnzI+Ma>Kw`9lmceywg!|Vm+w!6R-dt|BJ;t}D# z?`V4LP+0tlPox$2>JY$JUeRV55gd&r)WsdiIS(=mB|(Wg6Qnhf>!V$t(!xs)bH~G5 zonKvC2bgfSfQSmA;c-h@Hv-#DU!sjXkk^agygbDLhn(L3hr2ibYU=L7N9}7ZwGOFT zMMX%hTC5bKl|dPD+EPmuF?B?lQbk3Gm?9tnlAP8F5g}DyKtU5HL_~)M^idi>91*?FeKAhCN&pAv^@7+kwS1jv;_H8nZiJBuzYcH zya&`q;B)YZ_lf$SA`JIf1LwM^LmXJ5QEW0R?}>Kj9z8H9vyNHf+UM=v+q-u8Z=q~p z4^p`%Xh62p{S`@ojdDn|g8RB@+m^TKhbr;jS6gg`AAUnrQp7^sywH+qS$-(*$fSD7 zhq(xzJp9ndQ%PPJ-M#nkf%I7|5#hDjeVq+7nf|z;i!K+P{er!?qB zz<}8+$qqU7WkJ+NO*&B}?1j4%8`PUk9r)v<6gLjFZ}lA>zWD~y1=A$L3XU`QTm!o4 z9<~96Rit_QKu$EjIBvJdh@81|nKD5o8Oc5IDFH${dQ~welI|ZR z);vKgOm@Wlj9mdW)urOvw-datqOH^`3FaCKI!d(KoXtrpg6?828W8HnjKT)6=|wil z2jtIgL`c94=8l^vy#MVT)30R-O5eRPe)}rQ$kDd&3Jxwf9PtvABB|UDll@dXY)KWG z0j^MBL{1&4w7GRlKxp}j(K&w$@RUHMQywzAter61i0&_t9`vDpU)jt{r2lST;6X_lD z!JQ-1v@1(p+0gCbrGdHJx8W;g*eCg0J_Ot(UW4g%-P|H&aS8-L1*JovJ@GAhk_6uT zsDfjm=mtzHRND&y+MW8Gxv1Hwc;<29J^dYv++Z!Z^Z>sOH_Okn!Gm2(Hb8eK7`t1MU(h{%-PCi#AHiqL`GI^v@Co%R?OvD!9~A!OmHJ$IVe%h5n|{H`{lYNE zB@i6-oB4|K2|`P(N}x07>Rdo~A|}X8H&&)bdNv8WCzTlp{^{ECnwCiEDJLM(W}^r6 z7_6yi+%{}I-I@Ipev`VKz3mXnw5?=+(dlDntlq?JCS|TL4z@2$k8wkT!dS|VRL!!%Gg)z=PaajDCKeTBQZ|;iVZKG2RKhvf30TweIU&S61)3G* ze~)nsg@8rN+iFSuH-gNdgLUc@`e3MM!0^|24eu*|qgb^cWK?N_cVH%6M$B&()39yK zQjikVLj{06ST8Vb>^RGfAUf#fgRO$Q3ea+xPc+>E^Nr@Esi&X=w7*SFjEK9KCkjU< zfN7`;kde2aq{D$qZ>bubo14N5h%&ZKELibM6M0qGr{vb0dBy~b#K5$_5mf-0`CEfW zmZX}eDAD#>vt2`ImRv5`=zWxZ$F`H(wp8(y`~^DpG?Bjn;09829coEnJ|xFF0lJAHCUadGQTKEWpq&|rlm0`%8ZDIp#1 z6hN3LJfBcwYYE!dx%N0^L`YdVrmlSg(9@iv8sq~gDfLL1R3|t2n{T6k-^0Anuz{M4 zgJZwvyhPeTndlFQx|x=g4)>T4=;L0mMC^>+R{S(66%g3kz!@M__s})Tf~yDDFO1Cs z;D}J0uVa5``&qG(?E{a>2o|4@6LsROJWs>jcTSKM7z`w!9W$#GZ8iT+%izxfz8?F{ z#60ceqD-MIjtaN$JnqIs1Kd!tG#_Ae5nyVgrn)T#QUmVd(V1pdXKnR!|0GWk7x({9 z2i2;OX9ga9kV31np5($wg2$u0UeE&2=pK$ROCIX<#r%M4t8Cwg)2XqwJ~&)Zkc|I@ zZZHx(1NMInJnBLky@XwciEG|d3<%N^XxOnG_6cf29@{tc2o|ER)Xx*mJ>%pVO=|8a z<$a)XRz37M1|D$)b~nve5{=upJG}181QGp3EY2zI6sNls=ro+@-U*Rq(x8s`PFDy2 z8cSU%=RfacycFPc1H11UBv&Zv*fkHd_JA&S72cdN8v7-ARDywK3^H%x@MX70XD9Do z`$67JpXc)%e~D51z5%pFbLQjO^^k=Lu)rTrPUtnk5o@>txl}m8(Ew1eV7>Bp{oD)Pts#;q_PF8;wm*HRrhCTJNuUIID!CMTPK4pEZF zA;lN|fFuoRwF|FJ4ocfGbt)6-IoapVe(r9cL}h`c(co{zvwoQ==x!_N9+v?3M{(h*#yZOtF+m2FEcZOBCV7hGwjA!TR89~ zy>%Bj+`Vt$!-0P0Q${!)KE_-$%%6|081OFQfOR@)y;TStx2I{wjb1^Qn`4O0p71HB z!sYHUe&kU#e&xFS1yY7IgxM)Yjndgi2@mlTAyd^+y}j%vsFRxL8NMY5?L@9ZVq~uz`Ek{ zx|H5c-}$URCnwMgV9HV#HzjETCSN`fJy>?dp`2jWAg3#dPOM4r8J#vD*c4_hV?x5dB%OgakMmOjSAp9;wT|6(k zDHgIL9+{k?|L$SU0#eQ#$}_4%W=IlK^;Wmucd+RiSrc4Y436!r9s{T!{zxHi9))Jnsk`R&#@x8J5}#Ms3tW(*0hu(oaqO5Ny9Azlx> zu2?Bd@{ZC7n?sU9u}L?gUAmqg+_D~WMFOc~gLBCJ?>&-zq(!*Jb*<09ixJZH)7a=n z;n?rsSxmC*hARH9SW?VdYC|P`gX=e@u8?PPFNpgJ2bwq!0j6&bz1x?rg{ z74(B4d1fl~#xpCmtPbf}@L~+26NtQLTv@s|a*S+^?E#1)q_m%-C>YL2 zVeG$EarP~h4HroVLE$r5v|)p=>!O0Yeuyv#3S?jbKG&-Le4fWj@MG#rlK6+^hSEo5 z+BPSJx-L@hgOJhB3d%ncD=RKHzD^T=*gP2E#OP*EFA2V z!_dQBd!hh1-zm6J6H?de1C0z9z^g#o9YA)C>I;0@g{c2Yi&^L%gBU#*f;?8C9jz%{M=H$Z0p^Dh_=XR9FQG#k#qM&d&Zy@vRAZ=0t`&Buk9 zO>Tg(FBg~})4B@GHsfb^l#UTLmuG|zShDmC&kVRV47jd7iC#`)MIUYilmdc2|_Gg*zpRWpg=T zVKsw^f|>2VYMnkqy>07Q$)j5;co&>ji{ur7Yy0SmmOCgDEU6#2fLuJgDlrOxUI||~ zbqdSIwK5JK_-GtZ3lP+>>LkHyijJ8-XDgkIZSPdDyPucE*#BgY^eV#_bbf(t&dBLhfV0*f?Od|q8*QeK5cSi$J*ul zVlIExH~LF*@))lm7^hGge5m$w0<67sP`3YF)SQ36SVG{7$Mq5eG`@TsHJgbx8@u{ySao;+vl5#O9$Lhp8VQiUC1F{h7 zL3IML$f@Iwn@;yOtU&kS@{SH^3uG$%TYqd)D^W(ZlChi3XbGFj$2SPY%kP8sXbGHNtp$ z{M~EVM-gXRaDr6?_xj|dA$Z60OD`Yy7zjra zSxv^1-@KNH%2@leWQTr$n`ss%?hECp+WZ)Uy3C^|eXfpyaKVSJY2@-wz%t>ZzC;D^ zZ%iY=$>dsvTvW#erTH^QsQ7r}JoCRhUQ1)U{GNz==W1$NrBx@wL zygIOpJT^~lqk|xIb$iy2WZ+Sr{Ri}EGJ#HQjH+dUIU8-cx#fTjV!7udw@ zrvoeMj_?jqzgj8KMm)oT&!vsEu+Z23WH9hO053Iu8R%UdQbu|A*~j z`;qN{rWce*+5T)zl6O~W?K-*%JT5L{EW})np3EIeAE0OCI*Kk6Uss6U)+Q~ZkE)gF8_bY?`%_Ts z;8$#bEhkAS7U1c`clRo8hhlCWOh`5km(xEwF|kTnD_0&(!~LqHC5#?o^?qzg8{19^ z%F~|kwt+I!?CP^%452%Q+cT$W2vT*vfd%2`kRy$pAfH!61^Cf;;T;X(pJjXR8(w2| z;bvnrwK5>&YEVSMh`+T9Qj3H_Hok%1apLnMmv;1eB*DXXR90|9wVD^gTW-+bVhH_P z`H{WeSW_=vY3hGcJz5^+R=0LI>7Gc6)d7$&N2DHsX<`R((M!0i6j2_1%h4_qeE|G@ z6EPVKmpDh;G*}WJyr>^ZQ8L1tYjoX%&=;U+Q+|(2iXixYTQ&Vzmm+6 z@bDN(5@H35A8T5Kso|Qeeq4IZR$;ofbTl(_3wK`VH8ENR`u-d=1_B7Z(^XiI^MWzdDClKs%p% zFUw@FWWwV`eklN0#O;ZJ?#Q^NWOCPpH?e-r4eyXZnBu9nBzG&M!oT2yinQ+MIR})2 zWj*_`qzIJj1u3Au2>lw4C$qC8vqMIUDr!Hd+HFj zH=)rPr3Reu`&5`Jq^^9A?E`-6JSyF}{ykkopE+LV*DtF7T>tMh__I7!#=&8!zv;6= zDTZ*W4It_~^(N(W?-6eV_T|DZHJHuj)IJ$1W`Y3?5*Dj$iAo5cci3h(_-00$;g$2C~d00nhsX1F7>2$`ZHQ8(B>E5=oS z+{ZuGWVM&2yp*73qg*yMz2}L5O&E0)j4w^@7suAgm zw?OUii?y%uBAs9q$BO!yJq`hI7ulSJUq_-5yB`00A4eIGv6#AIOQiiJJ8Xp&;2m&J zMqlwo6OnqLh3)BdI3f1BXIg%MX)ib18)YsDAn_Vf!uygf6s;&g5Q8=kWRy>(CUZz8 z@89&70+Y47;~P&b}wy0 z^f#a<6Bg72M@lhHFpCCIn;fEwc-syt1Y`%cVQ!xAsMqlar}_rhy2cFJ4#h^=wkmYU z$DFV_i$N29_BI;a8E_`?H>DIS<6-a%&AT8Ibw%3xaCsLeWPDsfLlf1^zDE}7LO?vZ zAJCWyQSx#f63XnCo+&^4s4CB2_SS7n0$7e~ zT;pD6L70nTm+7 zRQI@wA~1cs7P$iVIH)S5`h_NWBeAK%_6ya42c&9^PUqm*hyi3edR(Rh)318KnbeGb z3LiZQtoqf20Ss>B$R_kIfjFNawS1drgr828UA+>DHL;Ph7-+pUc~vMd@jJYR_z7x# z0=+YsH=!-INcP^hfLwxX?0sHW7(L%oeec${f3%fzApQQDDO}S|chV~nY+NEmkJ-Xm zm->A(TsXTv1$ieWhf72bRNecb2b|0^V3K`| zr6q+4%(Z3r{l6q$8T)u<;douj-Wru|uUD*-pcN^AdYbD&s{-o32tDHD=x`%o5qWSb`#Hy{^zi_K28osE{{kZ(65z&WAWM#c-8yG zpuq0D%|C#bUNG-2um7XY6Wn%}u$UU>VW8hpPnfj;*%}-a^@?s;44hRhy<>IFhAOb8 znpt0Zo3S{ibMX$(_b+WdLdw6>R;@Q!ugAXYEFQ{n&%E`R$@jUo?FNt?+Ua zN0PFV!KD%fAML^OumdN$0`(i9e^E=_o}UCL`GkplM?Vluw%JxGU^E+0j7H%=adG9) z6X`N-P&MP&xv|KvxdQqaDvwi2?N`-oGprxGYy0K#7*E=x<*Dhetn^0O{XqBE3UJX@ z&{pMo6N`m~g*&sIa>@$8cvI?)i4O&|?hYVP%Qpa5ewq=XU8?gqIY#e;vM&*4<`49V z-i_E3Ogmth&q(x=pBGNJ2-o*trlVPsAwuZ@t0i0Y;^nNj6Gal)vA$o*L^-c;1y<=? zDuHQ!f`-4ITyFJ_ucRqLU-CS86DuyJEC7lILP6thb2cI`M6p zi{wKRq~^mU+6S+WD7Ts{UUF#a*blKI8-e+3(uXYQs?9ERTSpj{sI@2|Xe&GRA$QXi zEEB>x*4#mJ_)Z(r|5f0K;VxD${1F(?)@;fp&jvE_s{vL0EnlcbW>CLUV0%sH z1UK(0j(}v5SA4|mXUp*XA5~(l8I1f_#ClZkX&L)A?_SsYu<%gwn$B0<6lxOBGO2&5 zL;~R>(7OVauqo!Vv4*8Ftr^B)_3v#Hb9TC#E}3eDFKyNL#J0VezAJ zq%T2(XyAr%=oh2mlnL8$BZaBkCi8lAf{yNLfy$tXAiVJ3X+P9}13mmZ;ALe_XU$bS z?VE*q$B@$|40D=e(_vDR+2E3ylL%;GZJhfG^7FdW158~H=$*94CTgVT!(A(lC8GYi zrK;U;Ye~#MzTOZ5@U31&C23sv2k@JbEa!%$sZSAfHT@LZZ@>jYL&ImGz_rfYoSH^) z1;5>2WbEzeuW1|46K6vvpK@T+BDF>kjHhFvS{1|fxO50?HhgaSG$?2>@ZmgNS(1fQ zEt8K4+gK#${EH2oy(P|W&xwFBgr?oq@3YS|-K}NA;NI+zto}z=f$yHlspA^_Y-hl) z`H}5|Za!@L3Uh!zK`9M{lLvQMrEDV2t&ZBcWFq5d89^;68IfRIMWSx~^-J^;Af#6z zd^vl4!}Aq9!TXDmy*5%)6c2POmp*N3&U6p34eLTh1Tu4zKHo+ zQz7-Vus>-Cx%2a%KTXl~H&azS8E-7J!cv*Evv_vHg0rlQMR_01iHS1*e11{L(eCKE z*~=dW*7U@bk0EHUr?hx(mcRVWRfp0v2oTYmC&V|hYsf3O9g2lcHekDFX#RO@FL)$B(}%FC-r3@bgei@!da+&V??&fm z(q%nK%)+C|1?Sy>;aCi~Aj$0A><5IMQUOgR{f$6Ex|r=Wy^V?ODQ-v-vaWwb z?ghlZ)AqL%ZoOn<IXuf47 z4#jl~Tju17x@z?!$%&wc;T3CDo+~TMwL2paV1lt8YF6vfKi-E@$A9Av!B>e0{u!NR_fmqXOnT_)eMakU9w{h#s> z@)0S5!UFhd#NWFDH(&yY4T@+{aPi>#hp_X+goI8T>@KJ%OG%@0!D@=uYL#!a&*2PK z$AIRH^T-paih#3SI%^jceS0es&pQD~!9C#W^w(4bKe0)JvvVT4%XBsztOSO_*5Qg` z{b0r@y?)dgo4{eGSYC3UV8o0;KvLPe^gQ-8_O14Yp}bR=LEBbpBR*IU25R_Q&jw_w`ycH-roO;jgHt6Wl8r3~dR& ziJKGbA#@>;Bym@yHlBd#DRh~_AolO&LLXS9i*EKt#YM`xzukHx@im>>A93yw;U;3E zWO_jg;n-f`O5XjbeZ1)9_XamxQA$nF1^PE|`F;>NM`v(mnjGrQeXET42ahO+;k~dX z_z(~}l=B)Bg<0e2U0HmGs~({}uK>K|lRRcHv{gL_z5!I0%;RIY{}ikRbwm)KJK9bL z+71$u;JIg&Et{Ftm6%h7tkzkWB%*RAM*gX+DUaE%Q=c{mRsvg<{xh_b^t>V7xoB0N#JxC{=gBLON*bF7_2l_Y9=RNG@@V0iW#o@9F z>Emb!bs`0W-a z5eO$d1O&x`t^ZE*pmdL!&*Ygwo_p#ldox<(COBp!J$o|ZL+O9_0ml}Ee4Gr*P7ah8 zfEfv~{C*t0GZI_&iH*@>b0J=Njie1|rKM<%vcQ~rro3v!l}Td{{@;J6F~Z;xh)}qo zH}QY41wasa;0EaP*KQet>-|&#MHxr-Qy_T@6ZqjXpp~`pX=|+F$^mgH&n(`mkcWT? z79480gGUhzS{1)Wb;MJ27CN;S!r8E(m_=0faN&NQ)9C_`t=D~_{XL}c+iQ{*=K;y! zgq2jxg24C8DVDr@OC+UmoyV*fIk7F=%dzc+Oqbx19xjNpCHx@e;5ns#l3;2(-}(+` zS>XIxuPeec`%931at!Gv5(#ttdmOlMflNp$Tbl*>4>VvC4=n= zP3-y2Zi=Y(d${T)#o8(cB^}VBoW2;pEqYG`!UAlQz-Wt6gVe^?&OiV5KJWtZ0Sw@C zz#7}CVmv%W*V>Nn64JFix)zPs|2Z1UHrV)ZB9UyJ+n$qgOt#WP;UiF6t1NRZ zu^qoI7_&xT(S3OlZZ2x-0-`zsN`>0)w-os>mU%>t#`Scf3%ABoZzUFMwX zBzdV6yfH&ha}&;3fPL>?JrT?vKS@;IcmmeGDFQ&Oe6$>TP?WCqrP`+m);f5zY85~1 zhuc+hBphH;t%~j*;)@KMGgo5u0sFz?RUZNGY2fQhvHjaY;=Rdn02@7l4Q=qDBNt(E!A9!tvi}g~CR`r`QVo z0T`T;E)0wtKuGK#(F&#G&)OEGV@3Mzjz7*RrzmN4n9@WVa}mvw+7&K< z_1l8R3RfW#LwB=sMsov5_6nL{hv@lf34uS4h7|8bosj5`3V>kcbnP?Sff-^w1YU%G zP1ny99wi()ec~RVbpNW34QtEpyk`(>D+%}N1zk!|lHP;gd+!|f4$_nUSAE_wde#f( zG~8zNeb-LW-?jNvxAOXNs{E`wqc;#-n&xn6yz zQn2=mtEsz~E#8pU%Giv(W`l!qDn{E!u1IZ!=2JI>pd0pNlKW8FKt-|qJQe|#5D~^= z83BIE>Fs@8crtzwG$pPepCxFDYhlxh0p~RLFpoZZMbrswzr3WPH>goCK9P903qGRh z+zU;R^iq{g0oHbr0sn?~2U4GfPcst#H4$3KevBqf7c_vGU8tHw9O?DuMa2HxdY9JaFcMDtn zb_L#EO+STE^4}$Og7Y|OC37eGSV88aXu_?RF`NgQ9q5()Jp6cR3EbFeg|RsXD|e5T zF#x883mS9BR!U=5m9HRzLuYf6aoKoD``>;b)NNIN%)5O<7gR%lDrRjlSw@1rPWiL=Y!P9^X%OK+idD zns5!+c4h0MDMEp8uBz4d2Nr=`64p+fMI($4^e|K%D`J8AM=kIv|^4bRia zAYZqW_h6fZ=eW+%3mDz<%RKeU6Ymqq(g~GZOW(=fYudRV08SB=mXYJ@2RF+FPvI+8 zVml$HFLp=Hif5!Ykmty35$03qTi_Eu_pc9hf)vuZWdOxm&Rh~U`S=aCBqHO-Ve-U) ztTtjziZ4vwjR=R;VO}RkD|AAUT4B|gpeCk0D@7^NlT@T7TF-x{MWNGeGc<6I+`OZi zIBi;CzB&a8JNNf&mm@|Vn0U2?2+cw747Q+QsV>5ZH1a<|y$?J<30gU}15JMrO`a!S zH9Q{{)|&h;t|hw6bX(4`?NGP5`AYjm)yqTcG24=YQFKG3&P`9qe%P>FU|&(%h@Dc zV5g5=Si12+u7wU1;!5S<|0BXdDi^=&en^HbiM(g%`nE6ub-NGsk_@IW|7v?Lz;Ic=Z=>Cm#E6>vFdS7vtJI0kY1=G zV8J+M-M;{S=1w@n^{?^EfNCxI#$?Y#x^!lgHLM*TRoMI*V3YGQD}37t#`jnY2EyhZ z*^_%{#s^&2>kaS1*LNZ$xIfJ^Pdtq!9ms#Z9@rJ=Gs;XWo{5MfY!uWO6;P$CFL=HN z%ZH#5`UT=^mNTeM!HJy50<5=QO@ebiE&~~BIJS#TsjCbJ4zjSQ(Nkes*J0DF&@KIyWRBs|!A)5O&R8Z|JV2X*>rDGZD~R*dF1=}UMRn>uqX^5 z09lzg1ZZCLvUq(im{=zP3T$kFe8663Z}i`4B>!C=u&FlWVX$VB{v|tUmGDvtt6?8d z|KRkR(p^d0r&{6yg}`!gHV}7t1`?b89AY~D7kAFPeWCXRN?LljbGZmXGgQ1sNelX- z$)lQ^8fPN3+}Be^97IO#$AxVWPhs!lX@kIskF<%lh~9MIHVbOVJy(_x>x^&e2CC@E z^1Q}nJ0@NSb^M8p+^9<-sulE0nIvax9VI5npc%3uZGEYu%>dwB3nl@J0Rw0X<(>5D z(&u141|4;Ug3*lFND6kEO#$P{&4Hf+@M+`@XG+`t&!XkI#9~!@NkmObQB-Z7pp7ga z8<%bci0gCwX6+u^@7y=YLaG~DKQuZ7FJj#$M(VxOV3pJ#Ff?q9;lQfK?l`(@NYQJV zw~CF7%I@c3K=&#|{;|r5KH>A(QqY_S_k=Mv9{KvnV%|d~&@qy2M}(Y-%Aw0$3T^P& z8#f+riG!08n2fJLhS1DNZ@p$sj+6aOe@LB$rW`PO4(O=%r-ncS?jZ-9`=;u<5qRKJ zkV5|xR)C+b0^w9Crs0>^vto)^d3(^b2Y!gZ@hkerc`u3EV~zF#lSWc<1B8X?Rug>( zOV*gSk{5TvHuO&t5~-S0e3%ecJ^OcBS({lz)EHz|vEgNrt$F8IWo|rCLFDk!qTk1| znSE@*@a;)ZmP{Dvz&V-bM|n_=Ts}ysC#m#2Ir*UdS~59BL)G->v*pvZV4{3;^q; zeqc2X%G%3Fy7l`ti-{n-6;b)CG1BUZl3ftcZ zH_)c<+fvB7@_eZo3}keU!p%dsQsR@ri?cEzQgXj89`K+kySwS{@7)428IcBpW--uf zpiha`?v;G^-z(zwOhL$>C)M z%?VCPc{C6wy%FpZ27iIi03Qv82)J%Ia1KWV8H5vD>3j}LDrm-UEu)Xwna-UyOYyaB zF}~VSUc(QZs`4&&ixEiMG=B+Za0p}|Q+z#WAaqBnRU9RnVBo+t^2Q537F^%iicwof zDVFqS;25R`at&3McUJ9FX!baK7BcRVcFP6~XOFE&t*0-A4hxsDZr3X=ecI5NyO3YP zg2u7q+OZn5t7*EXT77z4p%S%Yeg|AdxVNAZzCO316WLem!m`Tsy|!iOxk#R#?}PJw z4j65Fo`3{z436m5l1&yqqSDi|ky&gPFzz5VpEs%h8rg+I;5>XOUU~Gr=>yK&T_+I% zx)BlTdzBNh@LauE;R?|%5%H|ISsky&wi$%j8tzg!oLPnMg`ZVYzbR{9ju(ILDu~3w zrYC%LXjufl!55KebBPBYBeQgNgFJw5!Yc*FW4(3%P0rCr)S1KK`ojk(IWpV{bkR~j z!VT6w;aTOo5bA4YM~{I9W>g0wLQ4{#9^i{aY6jFmZ&z0|OLbb8=9l+=J8*%r;Wgl% z-gZSxBqw6K@DlOHu7=n`mS~Udm(G(g;B?C7IXUx3xq^?`;9v%d+hY}-$Zv2o2{3xh zGA6wKA@oejdC&}am^7pijK}f}+(>tHjwwR9iZ5{G*FD^~MaTl{I5x^(nDcQTOH)%9 z2u*$<&k7@%D{qAh=lo&$juT^Uv)$DrE#W;qDaUGchiOq4z`%nV)g#gtvX{2cxzlIe z8!W&?gh63c>3|o~1Ye-or%_#5 zrznqD^ahg&=P?DAX(;!NO6LKMFKUOLSNb>@8}^wz3gS!@WxS$0+_@6~dOw!^1J+bf zhQBr{U*jPd9i)e)Hgpsg?^|HI02f&5o#>4^~vs# zro+$%@Bzi(5S!%LOlc+JFO7p(1@oV1w)J>P)XWjE9e%h=V|ri=>+G>PTk6~ zT%`*`(D%zmTckCTMpXQnxHBeI*J_h#FP_9~krV2#KELIb8Sx6_JZc^&89was2)X2d z7&fl3#u6MnO24A#p}<*{xk28e#Zz|R`L>+E8@Lq+qDX{M|EG8NiD;3n*b~OaB=l_& zLe*|v*UDpFvCcc>K(=-K`5HzF&zZ*B1>~~mHzm~D_xCq|(CqdPn@>m02DIZ7(Hvc; z4ZDUU+8JUvr36dJG>XoawJx(P-yo5ANBD3scn4QhM!EHSKnwv6q~_iawi-PB+X?A58G?3 z?OvM?fbDmQn&5L>#WHyGl?ot#$$Rn~e{R?(3JeIm>YUA1Y#38v{OdtQN4?JGTmZ^J zB*wbunppd+?@uI}0W%F$5D4{gwXI-A=!F!8>-6|k1pK>H$)96dIG8nYwtd5vL#Ae? zYjIO8f}B$kTx5X(XW-#be;QmFN4%py0y+8(W@E0Efh-U^bZ<6JD(59_xc?Hq`(1fk zLcpzm_C+VJ>7sKU9jb9?-6$LlYIo}qe2QLH|5Tea|6Kr)zViAKUI>jTMCAqr2EqgJ zMa%;Nc-!*IQ^cC8Csin9TA(B5qo?zmR)6WoOo|V@hX7QzJ7E&rw*G~Zcw)K=M+LOv z(5gfb>-48;gF(w|1->mr7n2rG>?WI#Mb*r6dpG*b7Kv>Rv>KYEUoqyfj(hVIIIqDRL>~op z@gIiA!K@Uy$B`2DkDUXTO+&y$f^7G1Tl?cc-wZ3#KlUMa7=g0fZG)(D(4#dw%EE38F)_x1*-6~s+icJ3;X!s%0mIU%twxfowS>8Kz%+yJcqfVmc85x~fkwxHaki@$cLI!>5h> z0izTDz!Yg`Vc8b9KkL&ZdA5fqpjH@Ce-tk?^3r@bN-$AOs^5DeTI_84wXoo$mxq99 zFWA&hSu2)A$>lx?n9IInIQ&aoJ4hP$ia_y9hXt2jMp*;OFEcBzyd14d8M|nN$joG& zj!jm1r+YJQ*#9J_=nSjC4q{|}FKvbzuftO@A^~sWK820Hff}?7YKU(aul|@zZuRhdiaEZnIF!cF%VkyZ)$mzvs-?xxh$zGJ?miPT z`lg$<=jA6=ngZ@eFAZy71O%0U=6MdFP;$z$=Gg#F@oYH^HtrpMdczLR1>}mfPZ`;j zlh*K36|LeYP9YeKsc>}@T0ZBb67@dAb(|vW6A&E_hLCz1_O^+Au^^*6at1ykojIIn zPcM_yduLE|knt*6 zhexRrfR9isuVHwstgWh0xvpkUqh1t*hsY*8335!W8ByQDTDUEc@s}yw*7ZhZzG-Kt zN(H3>Dx@6SiGU*VTt5(&xAUDILmIxow7$LdGisKN+z(Gf1D<)sh|bkI4rGuUa##J= z!xXHsI%P5P_cbuVJF>Isyhqlco=)VkUd6O=>yD>=%f7Eyf>|cRgj1bmT)4wX(~SYV z=TKG0@w=UCBS3;Lcyjs@_`!U|jhJ2Q>ScsIO-sKamzKJJx99#OPQL-bC7orL9||iS zcYc~O$75i?U=yk()GA@v8}2l%yodbz7S~%>h~&*5sn;f;R`Gx=K5y3Ioetg%)=tQx zwwHq>LNl(c#I#3YdFT{&I{x9q1PEYj`V0AcKn55^)dC`-ppWETTzU#%UQ_dC5z^{~ z5AG-|S2n3%jUvKIUudbhWyMpm!B}0ogyfIJ z+enecwUfvMvo6#o3N?vRYrSV#cdZmYes+mz6H|BIxyW8-Q}U7!xug@?UY6p|i(q1`>K)OMKg1z#KQsV+a`SzR(+VT=?Y3 zp^U^QU9;(RQuGj)o~92KHXxsV1T6z>;Q;uT^}05;XMTw0q&U)Q$q)c^4Ipze0$k5> z;4Z?~q&CIGfpz{*(91YELX!X9p8@RCQ}7YyIb(4>eGP59H7RQW*T4uENmTsFdkv@c zt$-J^dK$fY!~ndWWjkMt=*W>oD!A&)i>@b1?zxQSn4ez$ciM9RQT;{C|HvB(R7o8) z*4d??xkKN361IjVfzrosQrNb|VKPr4=SiMC1u^cV@EkD{-K$km0Qfo3`CozfEoS#{ z*l9HajnPo%LRov`nV6Ntdi+U#o=g2t%~Juc=Hqr^%(=VNcOduF}6 zH&&IN-twQ(RxJqOUjrkBf~hN5PU_7aB|90LzQ3#jK=w*0$oBazqj|*VlO=&<>??^` zT_zhz{3tm7R#`3L;lFgJb_>Cju!VBzVjP&)7wSLhXC(+{->Zuu8Oq@aF˚w*O% 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

    t`#I;_zt-p9sJ`6Kar(rZC)NVBxI@K*yh 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Π+Bho8G1Ncy$$2 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 vR+^b{E$%gYq+?Z(?(~^Xxv2Wet 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 o%zJ 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 N(fwx(xcFn={{SfAfvErh literal 0 HcmV?d00001 diff --git a/API.Tests/Services/Test Data/ArchiveService/CoverImages/test.zip b/API.Tests/Services/Test Data/ArchiveService/CoverImages/test.zip new file mode 100644 index 0000000000000000000000000000000000000000..3d318ac6c3aeb3b4bcbab33507d705871db508b0 GIT binary patch literal 1055238 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 z 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�xzT6)N#nq9Ix@vHIM%DlV+0_uirH};La}&p}@ky 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�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

    >1k^krdoLpw?AKf6Xx&W#c5uBbQN%SZRj+f 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 >7k_d7~coK42=sflB( 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

    R&)zLk^g<U0L*;>58Iwyv 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%0AoO$zq%}F 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

    6B&H* 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%0DmUM{ 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Ƚ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

    uJw_$npJny0l)&6%%yQ|oy2BZUY9@~r~Tk37) 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 FYV2Fq(#cbNTB6_(6S#25>q$7I(Yb$ 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 <+oj-A?X|6~32m009JuxgGfT%mb>I`M>{l4YbaR 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

    >LHG^e1g(Rj3 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%0DKPU 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

    l+Qer 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

    - /// Normal sort for 2 doubles. 0 always comes before anything else + /// Normal sort for 2 doubles. 0 always comes last /// /// /// diff --git a/API/Comparators/NaturalSortComparer.cs b/API/Comparators/NaturalSortComparer.cs deleted file mode 100644 index 8fb0a74a5..000000000 --- a/API/Comparators/NaturalSortComparer.cs +++ /dev/null @@ -1,106 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text.RegularExpressions; -using static System.GC; -using static System.String; - -namespace API.Comparators -{ - /// - /// Attempts to emulate Windows explorer sorting - /// - /// This is not thread-safe - public sealed class NaturalSortComparer : IComparer, IDisposable - { - private readonly bool _isAscending; - private Dictionary _table = new(); - - private bool _disposed; - - - public NaturalSortComparer(bool inAscendingOrder = true) - { - _isAscending = inAscendingOrder; - } - - int IComparer.Compare(string x, string y) - { - if (x == y) return 0; - - if (!_table.TryGetValue(x ?? Empty, out var x1)) - { - x1 = Regex.Split(x ?? Empty, "([0-9]+)"); - _table.Add(x ?? Empty, x1); - } - - if (!_table.TryGetValue(y ?? Empty, out var y1)) - { - y1 = Regex.Split(y ?? Empty, "([0-9]+)"); - _table.Add(y ?? Empty, y1); - } - - int returnVal; - - for (var i = 0; i < x1.Length && i < y1.Length; i++) - { - if (x1[i] == y1[i]) continue; - returnVal = PartCompare(x1[i], y1[i]); - return _isAscending ? returnVal : -returnVal; - } - - if (y1.Length > x1.Length) - { - returnVal = 1; - } - else if (x1.Length > y1.Length) - { - returnVal = -1; - } - else - { - returnVal = 0; - } - - - return _isAscending ? returnVal : -returnVal; - } - - private static int PartCompare(string left, string right) - { - if (!int.TryParse(left, out var x)) - return Compare(left, right, StringComparison.Ordinal); - - if (!int.TryParse(right, out var y)) - return Compare(left, right, StringComparison.Ordinal); - - return x.CompareTo(y); - } - - private void Dispose(bool disposing) - { - if (!_disposed) - { - if (disposing) - { - // called via myClass.Dispose(). - _table.Clear(); - _table = null; - } - // Release unmanaged resources. - // Set large fields to null. - _disposed = true; - } - } - - public void Dispose() - { - Dispose(true); - SuppressFinalize(this); - } - - ~NaturalSortComparer() // the finalizer - { - Dispose(false); - } - } -} diff --git a/API/Controllers/AccountController.cs b/API/Controllers/AccountController.cs index 415b51f59..3d3a93f85 100644 --- a/API/Controllers/AccountController.cs +++ b/API/Controllers/AccountController.cs @@ -4,12 +4,11 @@ using System.Linq; using System.Reflection; using System.Threading.Tasks; using API.Constants; +using API.Data; using API.DTOs; using API.DTOs.Account; using API.Entities; using API.Extensions; -using API.Interfaces; -using API.Interfaces.Services; using API.Services; using AutoMapper; using Kavita.Common; @@ -92,7 +91,7 @@ namespace API.Controllers if (registerDto.IsAdmin) { var firstTimeFlow = !(await _userManager.GetUsersInRoleAsync("Admin")).Any(); - if (!firstTimeFlow && !await _unitOfWork.UserRepository.IsUserAdmin( + if (!firstTimeFlow && !await _unitOfWork.UserRepository.IsUserAdminAsync( await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername()))) { return BadRequest("You are not permitted to create an admin account"); @@ -167,7 +166,7 @@ namespace API.Controllers if (user == null) return Unauthorized("Invalid username"); - var isAdmin = await _unitOfWork.UserRepository.IsUserAdmin(user); + var isAdmin = await _unitOfWork.UserRepository.IsUserAdminAsync(user); var settings = await _unitOfWork.SettingsRepository.GetSettingsDtoAsync(); if (!settings.EnableAuthentication && !isAdmin) { diff --git a/API/Controllers/BookController.cs b/API/Controllers/BookController.cs index cf5e66e22..473640df7 100644 --- a/API/Controllers/BookController.cs +++ b/API/Controllers/BookController.cs @@ -1,15 +1,16 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using API.Data; using API.DTOs; using API.DTOs.Reader; using API.Entities.Enums; using API.Extensions; -using API.Interfaces; -using API.Interfaces.Services; using API.Services; using HtmlAgilityPack; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using VersOne.Epub; @@ -21,10 +22,11 @@ namespace API.Controllers private readonly IBookService _bookService; private readonly IUnitOfWork _unitOfWork; private readonly ICacheService _cacheService; - private static readonly string BookApiUrl = "book-resources?file="; + private const string BookApiUrl = "book-resources?file="; - public BookController(ILogger logger, IBookService bookService, IUnitOfWork unitOfWork, ICacheService cacheService) + public BookController(ILogger logger, IBookService bookService, + IUnitOfWork unitOfWork, ICacheService cacheService) { _logger = logger; _bookService = bookService; @@ -110,32 +112,12 @@ namespace API.Controllers } } - if (navigationItem.Link == null) - { - var item = new BookChapterItem() - { - Title = navigationItem.Title, - Children = nestedChapters - }; - if (nestedChapters.Count > 0) - { - item.Page = nestedChapters[0].Page; - } - chaptersList.Add(item); - } - else - { - var groupKey = BookService.CleanContentKeys(navigationItem.Link.ContentFileName); - if (mappings.ContainsKey(groupKey)) - { - chaptersList.Add(new BookChapterItem() - { - Title = navigationItem.Title, - Page = mappings[groupKey], - Children = nestedChapters - }); - } - } + CreateToCChapter(navigationItem, nestedChapters, chaptersList, mappings); + } + + if (navigationItem.NestedItems.Count == 0) + { + CreateToCChapter(navigationItem, Array.Empty(), chaptersList, mappings); } } @@ -188,6 +170,38 @@ namespace API.Controllers return Ok(chaptersList); } + private static void CreateToCChapter(EpubNavigationItemRef navigationItem, IList nestedChapters, IList chaptersList, + IReadOnlyDictionary mappings) + { + if (navigationItem.Link == null) + { + var item = new BookChapterItem() + { + Title = navigationItem.Title, + Children = nestedChapters + }; + if (nestedChapters.Count > 0) + { + item.Page = nestedChapters[0].Page; + } + + chaptersList.Add(item); + } + else + { + var groupKey = BookService.CleanContentKeys(navigationItem.Link.ContentFileName); + if (mappings.ContainsKey(groupKey)) + { + chaptersList.Add(new BookChapterItem() + { + Title = navigationItem.Title, + Page = mappings[groupKey], + Children = nestedChapters + }); + } + } + } + [HttpGet("{chapterId}/book-page")] public async Task> GetBookPage(int chapterId, [FromQuery] int page) { @@ -200,146 +214,40 @@ namespace API.Controllers var counter = 0; var doc = new HtmlDocument {OptionFixNestedTags = true}; - var baseUrl = Request.Scheme + "://" + Request.Host + Request.PathBase + "/api/"; + + var baseUrl = "//" + Request.Host + Request.PathBase + "/api/"; var apiBase = baseUrl + "book/" + chapterId + "/" + BookApiUrl; var bookPages = await book.GetReadingOrderAsync(); foreach (var contentFileRef in bookPages) { - if (page == counter) + if (page != counter) { - var content = await contentFileRef.ReadContentAsync(); - if (contentFileRef.ContentType != EpubContentType.XHTML_1_1) return Ok(content); - - // In more cases than not, due to this being XML not HTML, we need to escape the script tags. - content = BookService.EscapeTags(content); - - doc.LoadHtml(content); - var body = doc.DocumentNode.SelectSingleNode("//body"); - - if (body == null) - { - if (doc.ParseErrors.Any()) - { - LogBookErrors(book, contentFileRef, doc); - return BadRequest("The file is malformed! Cannot read."); - } - _logger.LogError("{FilePath} has no body tag! Generating one for support. Book may be skewed", book.FilePath); - doc.DocumentNode.SelectSingleNode("/html").AppendChild(HtmlNode.CreateNode("")); - body = doc.DocumentNode.SelectSingleNode("/html/body"); - } - - var inlineStyles = doc.DocumentNode.SelectNodes("//style"); - if (inlineStyles != null) - { - foreach (var inlineStyle in inlineStyles) - { - var styleContent = await _bookService.ScopeStyles(inlineStyle.InnerHtml, apiBase, "", book); - body.PrependChild(HtmlNode.CreateNode($"")); - } - } - - var styleNodes = doc.DocumentNode.SelectNodes("/html/head/link"); - if (styleNodes != null) - { - foreach (var styleLinks in styleNodes) - { - var key = BookService.CleanContentKeys(styleLinks.Attributes["href"].Value); - // Some epubs are malformed the key in content.opf might be: content/resources/filelist_0_0.xml but the actual html links to resources/filelist_0_0.xml - // In this case, we will do a search for the key that ends with - if (!book.Content.Css.ContainsKey(key)) - { - var correctedKey = book.Content.Css.Keys.SingleOrDefault(s => s.EndsWith(key)); - if (correctedKey == null) - { - _logger.LogError("Epub is Malformed, key: {Key} is not matching OPF file", key); - continue; - } - - key = correctedKey; - } - - var styleContent = await _bookService.ScopeStyles(await book.Content.Css[key].ReadContentAsync(), apiBase, book.Content.Css[key].FileName, book); - if (styleContent != null) - { - body.PrependChild(HtmlNode.CreateNode($"")); - } - } - } - - var anchors = doc.DocumentNode.SelectNodes("//a"); - if (anchors != null) - { - foreach (var anchor in anchors) - { - BookService.UpdateLinks(anchor, mappings, page); - } - } - - var images = doc.DocumentNode.SelectNodes("//img"); - if (images != null) - { - foreach (var image in images) - { - if (image.Name != "img") continue; - - // Need to do for xlink:href - if (image.Attributes["src"] != null) - { - var imageFile = image.Attributes["src"].Value; - if (!book.Content.Images.ContainsKey(imageFile)) - { - var correctedKey = book.Content.Images.Keys.SingleOrDefault(s => s.EndsWith(imageFile)); - if (correctedKey != null) - { - imageFile = correctedKey; - } - } - image.Attributes.Remove("src"); - image.Attributes.Add("src", $"{apiBase}" + imageFile); - } - } - } - - images = doc.DocumentNode.SelectNodes("//image"); - if (images != null) - { - foreach (var image in images) - { - if (image.Name != "image") continue; - - if (image.Attributes["xlink:href"] != null) - { - var imageFile = image.Attributes["xlink:href"].Value; - if (!book.Content.Images.ContainsKey(imageFile)) - { - var correctedKey = book.Content.Images.Keys.SingleOrDefault(s => s.EndsWith(imageFile)); - if (correctedKey != null) - { - imageFile = correctedKey; - } - } - image.Attributes.Remove("xlink:href"); - image.Attributes.Add("xlink:href", $"{apiBase}" + imageFile); - } - } - } - - // Check if any classes on the html node (some r2l books do this) and move them to body tag for scoping - var htmlNode = doc.DocumentNode.SelectSingleNode("//html"); - if (htmlNode != null && htmlNode.Attributes.Contains("class")) - { - var bodyClasses = body.Attributes.Contains("class") ? body.Attributes["class"].Value : string.Empty; - var classes = htmlNode.Attributes["class"].Value + " " + bodyClasses; - body.Attributes.Add("class", $"{classes}"); - // I actually need the body tag itself for the classes, so i will create a div and put the body stuff there. - return Ok($"
    {body.InnerHtml}
    "); - } - - - return Ok(body.InnerHtml); + counter++; + continue; } - counter++; + var content = await contentFileRef.ReadContentAsync(); + if (contentFileRef.ContentType != EpubContentType.XHTML_1_1) return Ok(content); + + // In more cases than not, due to this being XML not HTML, we need to escape the script tags. + content = BookService.EscapeTags(content); + + doc.LoadHtml(content); + var body = doc.DocumentNode.SelectSingleNode("//body"); + + if (body == null) + { + if (doc.ParseErrors.Any()) + { + LogBookErrors(book, contentFileRef, doc); + return BadRequest("The file is malformed! Cannot read."); + } + _logger.LogError("{FilePath} has no body tag! Generating one for support. Book may be skewed", book.FilePath); + doc.DocumentNode.SelectSingleNode("/html").AppendChild(HtmlNode.CreateNode("")); + body = doc.DocumentNode.SelectSingleNode("/html/body"); + } + + return Ok(await _bookService.ScopePage(doc, book, apiBase, body, mappings, page)); } return BadRequest("Could not find the appropriate html for that page"); diff --git a/API/Controllers/CollectionController.cs b/API/Controllers/CollectionController.cs index 681a962d0..9f297273f 100644 --- a/API/Controllers/CollectionController.cs +++ b/API/Controllers/CollectionController.cs @@ -3,11 +3,9 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using API.Data; -using API.DTOs; using API.DTOs.CollectionTags; -using API.Entities; +using API.Entities.Metadata; using API.Extensions; -using API.Interfaces; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -34,7 +32,7 @@ namespace API.Controllers public async Task> GetAllTags() { var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername()); - var isAdmin = await _unitOfWork.UserRepository.IsUserAdmin(user); + var isAdmin = await _unitOfWork.UserRepository.IsUserAdminAsync(user); if (isAdmin) { return await _unitOfWork.CollectionTagRepository.GetAllTagDtosAsync(); diff --git a/API/Controllers/DownloadController.cs b/API/Controllers/DownloadController.cs index d1ea4e8fb..c253fb9ee 100644 --- a/API/Controllers/DownloadController.cs +++ b/API/Controllers/DownloadController.cs @@ -4,16 +4,17 @@ using System.IO; using System.Linq; using System.Threading.Tasks; using API.Comparators; +using API.Data; using API.DTOs.Downloads; using API.Entities; using API.Entities.Enums; using API.Extensions; -using API.Interfaces; -using API.Interfaces.Services; using API.Services; +using API.SignalR; using Kavita.Common; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.SignalR; namespace API.Controllers { @@ -25,16 +26,19 @@ namespace API.Controllers private readonly IDirectoryService _directoryService; private readonly ICacheService _cacheService; private readonly IDownloadService _downloadService; + private readonly IHubContext _messageHub; private readonly NumericComparer _numericComparer; private const string DefaultContentType = "application/octet-stream"; - public DownloadController(IUnitOfWork unitOfWork, IArchiveService archiveService, IDirectoryService directoryService, ICacheService cacheService, IDownloadService downloadService) + public DownloadController(IUnitOfWork unitOfWork, IArchiveService archiveService, IDirectoryService directoryService, + ICacheService cacheService, IDownloadService downloadService, IHubContext messageHub) { _unitOfWork = unitOfWork; _archiveService = archiveService; _directoryService = directoryService; _cacheService = cacheService; _downloadService = downloadService; + _messageHub = messageHub; _numericComparer = new NumericComparer(); } @@ -42,21 +46,21 @@ namespace API.Controllers public async Task> GetVolumeSize(int volumeId) { var files = await _unitOfWork.VolumeRepository.GetFilesForVolume(volumeId); - return Ok(DirectoryService.GetTotalSize(files.Select(c => c.FilePath))); + return Ok(_directoryService.GetTotalSize(files.Select(c => c.FilePath))); } [HttpGet("chapter-size")] public async Task> GetChapterSize(int chapterId) { var files = await _unitOfWork.ChapterRepository.GetFilesForChapterAsync(chapterId); - return Ok(DirectoryService.GetTotalSize(files.Select(c => c.FilePath))); + return Ok(_directoryService.GetTotalSize(files.Select(c => c.FilePath))); } [HttpGet("series-size")] public async Task> GetSeriesSize(int seriesId) { var files = await _unitOfWork.SeriesRepository.GetFilesForSeries(seriesId); - return Ok(DirectoryService.GetTotalSize(files.Select(c => c.FilePath))); + return Ok(_directoryService.GetTotalSize(files.Select(c => c.FilePath))); } [HttpGet("volume")] @@ -67,13 +71,7 @@ namespace API.Controllers var series = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(volume.SeriesId); try { - if (files.Count == 1) - { - return await GetFirstFileDownload(files); - } - var (fileBytes, _) = await _archiveService.CreateZipForDownload(files.Select(c => c.FilePath), - $"download_{User.GetUsername()}_v{volumeId}"); - return File(fileBytes, DefaultContentType, $"{series.Name} - Volume {volume.Number}.zip"); + return await DownloadFiles(files, $"download_{User.GetUsername()}_v{volumeId}", $"{series.Name} - Volume {volume.Number}.zip"); } catch (KavitaException ex) { @@ -96,13 +94,7 @@ namespace API.Controllers var series = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(volume.SeriesId); try { - if (files.Count == 1) - { - return await GetFirstFileDownload(files); - } - var (fileBytes, _) = await _archiveService.CreateZipForDownload(files.Select(c => c.FilePath), - $"download_{User.GetUsername()}_c{chapterId}"); - return File(fileBytes, DefaultContentType, $"{series.Name} - Chapter {chapter.Number}.zip"); + return await DownloadFiles(files, $"download_{User.GetUsername()}_c{chapterId}", $"{series.Name} - Chapter {chapter.Number}.zip"); } catch (KavitaException ex) { @@ -110,6 +102,21 @@ namespace API.Controllers } } + private async Task DownloadFiles(ICollection files, string tempFolder, string downloadName) + { + await _messageHub.Clients.All.SendAsync(SignalREvents.DownloadProgress, + MessageFactory.DownloadProgressEvent(User.GetUsername(), Path.GetFileNameWithoutExtension(downloadName), 0F)); + if (files.Count == 1) + { + return await GetFirstFileDownload(files); + } + var (fileBytes, _) = await _archiveService.CreateZipForDownload(files.Select(c => c.FilePath), + tempFolder); + await _messageHub.Clients.All.SendAsync(SignalREvents.DownloadProgress, + MessageFactory.DownloadProgressEvent(User.GetUsername(), Path.GetFileNameWithoutExtension(downloadName), 1F)); + return File(fileBytes, DefaultContentType, downloadName); + } + [HttpGet("series")] public async Task DownloadSeries(int seriesId) { @@ -117,13 +124,7 @@ namespace API.Controllers var series = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(seriesId); try { - if (files.Count == 1) - { - return await GetFirstFileDownload(files); - } - var (fileBytes, _) = await _archiveService.CreateZipForDownload(files.Select(c => c.FilePath), - $"download_{User.GetUsername()}_s{seriesId}"); - return File(fileBytes, DefaultContentType, $"{series.Name}.zip"); + return await DownloadFiles(files, $"download_{User.GetUsername()}_s{seriesId}", $"{series.Name}.zip"); } catch (KavitaException ex) { @@ -135,57 +136,20 @@ namespace API.Controllers public async Task DownloadBookmarkPages(DownloadBookmarkDto downloadBookmarkDto) { // We know that all bookmarks will be for one single seriesId + var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername()); var series = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(downloadBookmarkDto.Bookmarks.First().SeriesId); - var totalFilePaths = new List(); - var tempFolder = $"download_{series.Id}_bookmarks"; - var fullExtractPath = Path.Join(DirectoryService.TempDirectory, tempFolder); - if (new DirectoryInfo(fullExtractPath).Exists) - { - return BadRequest( - "Server is currently processing this exact download. Please try again in a few minutes."); - } - DirectoryService.ExistOrCreate(fullExtractPath); + var bookmarkDirectory = + (await _unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.BookmarkDirectory)).Value; + var files = (await _unitOfWork.UserRepository.GetAllBookmarksByIds(downloadBookmarkDto.Bookmarks + .Select(b => b.Id) + .ToList())) + .Select(b => Parser.Parser.NormalizePath(_directoryService.FileSystem.Path.Join(bookmarkDirectory, b.FileName))); - var uniqueChapterIds = downloadBookmarkDto.Bookmarks.Select(b => b.ChapterId).Distinct().ToList(); - - foreach (var chapterId in uniqueChapterIds) - { - var chapterExtractPath = Path.Join(fullExtractPath, $"{series.Id}_bookmark_{chapterId}"); - var chapterPages = downloadBookmarkDto.Bookmarks.Where(b => b.ChapterId == chapterId) - .Select(b => b.Page).ToList(); - var mangaFiles = await _unitOfWork.ChapterRepository.GetFilesForChapterAsync(chapterId); - switch (series.Format) - { - case MangaFormat.Image: - DirectoryService.ExistOrCreate(chapterExtractPath); - _directoryService.CopyFilesToDirectory(mangaFiles.Select(f => f.FilePath), chapterExtractPath, $"{chapterId}_"); - break; - case MangaFormat.Archive: - case MangaFormat.Pdf: - _cacheService.ExtractChapterFiles(chapterExtractPath, mangaFiles.ToList()); - var originalFiles = DirectoryService.GetFilesWithExtension(chapterExtractPath, - Parser.Parser.ImageFileExtensions); - _directoryService.CopyFilesToDirectory(originalFiles, chapterExtractPath, $"{chapterId}_"); - DirectoryService.DeleteFiles(originalFiles); - break; - case MangaFormat.Epub: - return BadRequest("Series is not in a valid format."); - default: - return BadRequest("Series is not in a valid format. Please rescan series and try again."); - } - - var files = DirectoryService.GetFilesWithExtension(chapterExtractPath, Parser.Parser.ImageFileExtensions); - // Filter out images that aren't in bookmarks - Array.Sort(files, _numericComparer); - totalFilePaths.AddRange(files.Where((_, i) => chapterPages.Contains(i))); - } - - - var (fileBytes, _) = await _archiveService.CreateZipForDownload(totalFilePaths, - tempFolder); - DirectoryService.ClearAndDeleteDirectory(fullExtractPath); + var (fileBytes, _) = await _archiveService.CreateZipForDownload(files, + $"download_{user.Id}_{series.Id}_bookmarks"); return File(fileBytes, DefaultContentType, $"{series.Name} - Bookmarks.zip"); } + } } diff --git a/API/Controllers/FallbackController.cs b/API/Controllers/FallbackController.cs index ecd0315e2..ae8bad21f 100644 --- a/API/Controllers/FallbackController.cs +++ b/API/Controllers/FallbackController.cs @@ -1,5 +1,5 @@ using System.IO; -using API.Interfaces; +using API.Services; using Microsoft.AspNetCore.Mvc; namespace API.Controllers @@ -12,7 +12,7 @@ namespace API.Controllers public FallbackController(ITaskScheduler taskScheduler) { - // This is used to load TaskScheduler on startup without having to navigate to a Controller that uses. + // This is used to load TaskScheduler on startup without having to navigate to a Controller that uses. _taskScheduler = taskScheduler; } @@ -21,4 +21,4 @@ namespace API.Controllers return PhysicalFile(Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "index.html"), "text/HTML"); } } -} \ No newline at end of file +} diff --git a/API/Controllers/ImageController.cs b/API/Controllers/ImageController.cs index 88bafcff7..a875be14e 100644 --- a/API/Controllers/ImageController.cs +++ b/API/Controllers/ImageController.cs @@ -1,7 +1,8 @@ using System.IO; using System.Threading.Tasks; +using API.Data; +using API.Entities.Enums; using API.Extensions; -using API.Interfaces; using API.Services; using Microsoft.AspNetCore.Mvc; @@ -13,11 +14,13 @@ namespace API.Controllers public class ImageController : BaseApiController { private readonly IUnitOfWork _unitOfWork; + private readonly IDirectoryService _directoryService; /// - public ImageController(IUnitOfWork unitOfWork) + public ImageController(IUnitOfWork unitOfWork, IDirectoryService directoryService) { _unitOfWork = unitOfWork; + _directoryService = directoryService; } ///
    @@ -28,12 +31,12 @@ namespace API.Controllers [HttpGet("chapter-cover")] public async Task GetChapterCoverImage(int chapterId) { - var path = Path.Join(DirectoryService.CoverImageDirectory, await _unitOfWork.ChapterRepository.GetChapterCoverImageAsync(chapterId)); - if (string.IsNullOrEmpty(path) || !System.IO.File.Exists(path)) return BadRequest($"No cover image"); - var format = Path.GetExtension(path).Replace(".", ""); + var path = Path.Join(_directoryService.CoverImageDirectory, await _unitOfWork.ChapterRepository.GetChapterCoverImageAsync(chapterId)); + if (string.IsNullOrEmpty(path) || !_directoryService.FileSystem.File.Exists(path)) return BadRequest($"No cover image"); + var format = _directoryService.FileSystem.Path.GetExtension(path).Replace(".", ""); Response.AddCacheHeader(path); - return PhysicalFile(path, "image/" + format, Path.GetFileName(path)); + return PhysicalFile(path, "image/" + format, _directoryService.FileSystem.Path.GetFileName(path)); } /// @@ -44,12 +47,12 @@ namespace API.Controllers [HttpGet("volume-cover")] public async Task GetVolumeCoverImage(int volumeId) { - var path = Path.Join(DirectoryService.CoverImageDirectory, await _unitOfWork.VolumeRepository.GetVolumeCoverImageAsync(volumeId)); - if (string.IsNullOrEmpty(path) || !System.IO.File.Exists(path)) return BadRequest($"No cover image"); - var format = Path.GetExtension(path).Replace(".", ""); + var path = Path.Join(_directoryService.CoverImageDirectory, await _unitOfWork.VolumeRepository.GetVolumeCoverImageAsync(volumeId)); + if (string.IsNullOrEmpty(path) || !_directoryService.FileSystem.File.Exists(path)) return BadRequest($"No cover image"); + var format = _directoryService.FileSystem.Path.GetExtension(path).Replace(".", ""); Response.AddCacheHeader(path); - return PhysicalFile(path, "image/" + format, Path.GetFileName(path)); + return PhysicalFile(path, "image/" + format, _directoryService.FileSystem.Path.GetFileName(path)); } /// @@ -60,12 +63,12 @@ namespace API.Controllers [HttpGet("series-cover")] public async Task GetSeriesCoverImage(int seriesId) { - var path = Path.Join(DirectoryService.CoverImageDirectory, await _unitOfWork.SeriesRepository.GetSeriesCoverImageAsync(seriesId)); - if (string.IsNullOrEmpty(path) || !System.IO.File.Exists(path)) return BadRequest($"No cover image"); - var format = Path.GetExtension(path).Replace(".", ""); + var path = Path.Join(_directoryService.CoverImageDirectory, await _unitOfWork.SeriesRepository.GetSeriesCoverImageAsync(seriesId)); + if (string.IsNullOrEmpty(path) || !_directoryService.FileSystem.File.Exists(path)) return BadRequest($"No cover image"); + var format = _directoryService.FileSystem.Path.GetExtension(path).Replace(".", ""); Response.AddCacheHeader(path); - return PhysicalFile(path, "image/" + format, Path.GetFileName(path)); + return PhysicalFile(path, "image/" + format, _directoryService.FileSystem.Path.GetFileName(path)); } /// @@ -76,12 +79,34 @@ namespace API.Controllers [HttpGet("collection-cover")] public async Task GetCollectionCoverImage(int collectionTagId) { - var path = Path.Join(DirectoryService.CoverImageDirectory, await _unitOfWork.CollectionTagRepository.GetCoverImageAsync(collectionTagId)); - if (string.IsNullOrEmpty(path) || !System.IO.File.Exists(path)) return BadRequest($"No cover image"); - var format = Path.GetExtension(path).Replace(".", ""); + var path = Path.Join(_directoryService.CoverImageDirectory, await _unitOfWork.CollectionTagRepository.GetCoverImageAsync(collectionTagId)); + if (string.IsNullOrEmpty(path) || !_directoryService.FileSystem.File.Exists(path)) return BadRequest($"No cover image"); + var format = _directoryService.FileSystem.Path.GetExtension(path).Replace(".", ""); Response.AddCacheHeader(path); - return PhysicalFile(path, "image/" + format, Path.GetFileName(path)); + return PhysicalFile(path, "image/" + format, _directoryService.FileSystem.Path.GetFileName(path)); + } + + /// + /// Returns image for a given bookmark page + /// + /// This request is served unauthenticated, but user must be passed via api key to validate + /// + /// Starts at 0 + /// API Key for user. Needed to authenticate request + /// + [HttpGet("bookmark")] + public async Task GetBookmarkImage(int chapterId, int pageNum, string apiKey) + { + var userId = await _unitOfWork.UserRepository.GetUserIdByApiKeyAsync(apiKey); + var bookmark = await _unitOfWork.UserRepository.GetBookmarkForPage(pageNum, chapterId, userId); + if (bookmark == null) return BadRequest("Bookmark does not exist"); + + var bookmarkDirectory = + (await _unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.BookmarkDirectory)).Value; + var file = new FileInfo(Path.Join(bookmarkDirectory, bookmark.FileName)); + var format = Path.GetExtension(file.FullName).Replace(".", ""); + return PhysicalFile(file.FullName, "image/" + format, Path.GetFileName(file.FullName)); } } } diff --git a/API/Controllers/LibraryController.cs b/API/Controllers/LibraryController.cs index 15a8d1166..9cdd06158 100644 --- a/API/Controllers/LibraryController.cs +++ b/API/Controllers/LibraryController.cs @@ -3,13 +3,13 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; +using API.Data; using API.Data.Repositories; using API.DTOs; using API.Entities; using API.Entities.Enums; using API.Extensions; -using API.Interfaces; -using API.Interfaces.Services; +using API.Services; using AutoMapper; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; diff --git a/API/Controllers/MetadataController.cs b/API/Controllers/MetadataController.cs new file mode 100644 index 000000000..4aa13691f --- /dev/null +++ b/API/Controllers/MetadataController.cs @@ -0,0 +1,140 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Threading.Tasks; +using API.Data; +using API.DTOs; +using API.DTOs.Filtering; +using API.DTOs.Metadata; +using API.Entities.Enums; +using Kavita.Common.Extensions; +using Microsoft.AspNetCore.Mvc; + +namespace API.Controllers; + + +public class MetadataController : BaseApiController +{ + private readonly IUnitOfWork _unitOfWork; + + public MetadataController(IUnitOfWork unitOfWork) + { + _unitOfWork = unitOfWork; + } + + /// + /// Fetches genres from the instance + /// + /// String separated libraryIds or null for all genres + /// + [HttpGet("genres")] + public async Task>> GetAllGenres(string? libraryIds) + { + var ids = libraryIds?.Split(",").Select(int.Parse).ToList(); + if (ids != null && ids.Count > 0) + { + return Ok(await _unitOfWork.GenreRepository.GetAllGenreDtosForLibrariesAsync(ids)); + } + + return Ok(await _unitOfWork.GenreRepository.GetAllGenreDtosAsync()); + } + + /// + /// Fetches people from the instance + /// + /// String separated libraryIds or null for all people + /// + [HttpGet("people")] + public async Task>> GetAllPeople(string? libraryIds) + { + var ids = libraryIds?.Split(",").Select(int.Parse).ToList(); + if (ids != null && ids.Count > 0) + { + return Ok(await _unitOfWork.PersonRepository.GetAllPeopleDtosForLibrariesAsync(ids)); + } + return Ok(await _unitOfWork.PersonRepository.GetAllPeople()); + } + + /// + /// Fetches all tags from the instance + /// + /// String separated libraryIds or null for all tags + /// + [HttpGet("tags")] + public async Task>> GetAllTags(string? libraryIds) + { + var ids = libraryIds?.Split(",").Select(int.Parse).ToList(); + if (ids != null && ids.Count > 0) + { + return Ok(await _unitOfWork.TagRepository.GetAllTagDtosForLibrariesAsync(ids)); + } + return Ok(await _unitOfWork.TagRepository.GetAllTagDtosAsync()); + } + + /// + /// Fetches all age ratings from the instance + /// + /// String separated libraryIds or null for all ratings + /// + [HttpGet("age-ratings")] + public async Task>> GetAllAgeRatings(string? libraryIds) + { + var ids = libraryIds?.Split(",").Select(int.Parse).ToList(); + if (ids != null && ids.Count > 0) + { + return Ok(await _unitOfWork.SeriesRepository.GetAllAgeRatingsDtosForLibrariesAsync(ids)); + } + + return Ok(Enum.GetValues().Select(t => new AgeRatingDto() + { + Title = t.ToDescription(), + Value = t + })); + } + + /// + /// Fetches all publication status' from the instance + /// + /// String separated libraryIds or null for all publication status + /// + [HttpGet("publication-status")] + public async Task>> GetAllPublicationStatus(string? libraryIds) + { + var ids = libraryIds?.Split(",").Select(int.Parse).ToList(); + if (ids != null && ids.Count > 0) + { + return Ok(await _unitOfWork.SeriesRepository.GetAllPublicationStatusesDtosForLibrariesAsync(ids)); + } + + return Ok(Enum.GetValues().Select(t => new PublicationStatusDto() + { + Title = t.ToDescription(), + Value = t + })); + } + + /// + /// Fetches all age ratings from the instance + /// + /// String separated libraryIds or null for all ratings + /// + [HttpGet("languages")] + public async Task>> GetAllLanguages(string? libraryIds) + { + var ids = libraryIds?.Split(",").Select(int.Parse).ToList(); + if (ids != null && ids.Count > 0) + { + return Ok(await _unitOfWork.SeriesRepository.GetAllLanguagesForLibrariesAsync(ids)); + } + + return Ok(new List() + { + new () + { + Title = CultureInfo.GetCultureInfo("en").DisplayName, + IsoCode = "en" + } + }); + } +} diff --git a/API/Controllers/OPDSController.cs b/API/Controllers/OPDSController.cs index 49a70d90d..9b7e87d62 100644 --- a/API/Controllers/OPDSController.cs +++ b/API/Controllers/OPDSController.cs @@ -5,789 +5,800 @@ using System.Linq; using System.Threading.Tasks; using System.Xml.Serialization; using API.Comparators; +using API.Data; using API.DTOs; using API.DTOs.CollectionTags; using API.DTOs.Filtering; using API.DTOs.OPDS; using API.Entities; +using API.Entities.Enums; using API.Extensions; using API.Helpers; -using API.Interfaces; -using API.Interfaces.Services; using API.Services; using Kavita.Common; using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Logging; -namespace API.Controllers +namespace API.Controllers; + +public class OpdsController : BaseApiController { - public class OpdsController : BaseApiController + private readonly IUnitOfWork _unitOfWork; + private readonly IDownloadService _downloadService; + private readonly IDirectoryService _directoryService; + private readonly ICacheService _cacheService; + private readonly IReaderService _readerService; + + + private readonly XmlSerializer _xmlSerializer; + private readonly XmlSerializer _xmlOpenSearchSerializer; + private const string Prefix = "/api/opds/"; + private readonly FilterDto _filterDto = new FilterDto() { - private readonly IUnitOfWork _unitOfWork; - private readonly IDownloadService _downloadService; - private readonly IDirectoryService _directoryService; - private readonly ICacheService _cacheService; - private readonly IReaderService _readerService; + Formats = new List(), + Character = new List(), + Colorist = new List(), + Editor = new List(), + Genres = new List(), + Inker = new List(), + Languages = new List(), + Letterer = new List(), + Penciller = new List(), + Libraries = new List(), + Publisher = new List(), + Rating = 0, + Tags = new List(), + Translators = new List(), + Writers = new List(), + AgeRating = new List(), + CollectionTags = new List(), + CoverArtist = new List(), + ReadStatus = new ReadStatus(), + SortOptions = null, + PublicationStatus = new List() + }; + private readonly ChapterSortComparer _chapterSortComparer = new ChapterSortComparer(); + public OpdsController(IUnitOfWork unitOfWork, IDownloadService downloadService, + IDirectoryService directoryService, ICacheService cacheService, + IReaderService readerService) + { + _unitOfWork = unitOfWork; + _downloadService = downloadService; + _directoryService = directoryService; + _cacheService = cacheService; + _readerService = readerService; - private readonly XmlSerializer _xmlSerializer; - private readonly XmlSerializer _xmlOpenSearchSerializer; - private const string Prefix = "/api/opds/"; - private readonly FilterDto _filterDto = new FilterDto() + _xmlSerializer = new XmlSerializer(typeof(Feed)); + _xmlOpenSearchSerializer = new XmlSerializer(typeof(OpenSearchDescription)); + + } + + [HttpPost("{apiKey}")] + [HttpGet("{apiKey}")] + [Produces("application/xml")] + public async Task Get(string apiKey) + { + if (!(await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).EnableOpds) + return BadRequest("OPDS is not enabled on this server"); + var feed = CreateFeed("Kavita", string.Empty, apiKey); + SetFeedId(feed, "root"); + feed.Entries.Add(new FeedEntry() { - MangaFormat = null + Id = "onDeck", + Title = "On Deck", + Content = new FeedEntryContent() + { + Text = "Browse by On Deck" + }, + Links = new List() + { + CreateLink(FeedLinkRelation.SubSection, FeedLinkType.AtomNavigation, Prefix + $"{apiKey}/on-deck"), + } + }); + feed.Entries.Add(new FeedEntry() + { + Id = "recentlyAdded", + Title = "Recently Added", + Content = new FeedEntryContent() + { + Text = "Browse by Recently Added" + }, + Links = new List() + { + CreateLink(FeedLinkRelation.SubSection, FeedLinkType.AtomNavigation, Prefix + $"{apiKey}/recently-added"), + } + }); + feed.Entries.Add(new FeedEntry() + { + Id = "readingList", + Title = "Reading Lists", + Content = new FeedEntryContent() + { + Text = "Browse by Reading Lists" + }, + Links = new List() + { + CreateLink(FeedLinkRelation.SubSection, FeedLinkType.AtomNavigation, Prefix + $"{apiKey}/reading-list"), + } + }); + feed.Entries.Add(new FeedEntry() + { + Id = "allLibraries", + Title = "All Libraries", + Content = new FeedEntryContent() + { + Text = "Browse by Libraries" + }, + Links = new List() + { + CreateLink(FeedLinkRelation.SubSection, FeedLinkType.AtomNavigation, Prefix + $"{apiKey}/libraries"), + } + }); + feed.Entries.Add(new FeedEntry() + { + Id = "allCollections", + Title = "All Collections", + Content = new FeedEntryContent() + { + Text = "Browse by Collections" + }, + Links = new List() + { + CreateLink(FeedLinkRelation.SubSection, FeedLinkType.AtomNavigation, Prefix + $"{apiKey}/collections"), + } + }); + return CreateXmlResult(SerializeXml(feed)); + } + + + [HttpGet("{apiKey}/libraries")] + [Produces("application/xml")] + public async Task GetLibraries(string apiKey) + { + if (!(await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).EnableOpds) + return BadRequest("OPDS is not enabled on this server"); + var userId = await GetUser(apiKey); + var libraries = await _unitOfWork.LibraryRepository.GetLibrariesForUserIdAsync(userId); + var feed = CreateFeed("All Libraries", $"{apiKey}/libraries", apiKey); + SetFeedId(feed, "libraries"); + foreach (var library in libraries) + { + feed.Entries.Add(new FeedEntry() + { + Id = library.Id.ToString(), + Title = library.Name, + Links = new List() + { + CreateLink(FeedLinkRelation.SubSection, FeedLinkType.AtomNavigation, Prefix + $"{apiKey}/libraries/{library.Id}"), + } + }); + } + + return CreateXmlResult(SerializeXml(feed)); + } + + [HttpGet("{apiKey}/collections")] + [Produces("application/xml")] + public async Task GetCollections(string apiKey) + { + if (!(await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).EnableOpds) + return BadRequest("OPDS is not enabled on this server"); + var userId = await GetUser(apiKey); + var user = await _unitOfWork.UserRepository.GetUserByIdAsync(userId); + var isAdmin = await _unitOfWork.UserRepository.IsUserAdminAsync(user); + + IList tags = isAdmin ? (await _unitOfWork.CollectionTagRepository.GetAllTagDtosAsync()).ToList() + : (await _unitOfWork.CollectionTagRepository.GetAllPromotedTagDtosAsync()).ToList(); + + + var feed = CreateFeed("All Collections", $"{apiKey}/collections", apiKey); + SetFeedId(feed, "collections"); + foreach (var tag in tags) + { + feed.Entries.Add(new FeedEntry() + { + Id = tag.Id.ToString(), + Title = tag.Title, + Summary = tag.Summary, + Links = new List() + { + CreateLink(FeedLinkRelation.SubSection, FeedLinkType.AtomNavigation, Prefix + $"{apiKey}/collections/{tag.Id}"), + CreateLink(FeedLinkRelation.Image, FeedLinkType.Image, $"/api/image/collection-cover?collectionId={tag.Id}"), + CreateLink(FeedLinkRelation.Thumbnail, FeedLinkType.Image, $"/api/image/collection-cover?collectionId={tag.Id}") + } + }); + } + + return CreateXmlResult(SerializeXml(feed)); + } + + + [HttpGet("{apiKey}/collections/{collectionId}")] + [Produces("application/xml")] + public async Task GetCollection(int collectionId, string apiKey, [FromQuery] int pageNumber = 0) + { + if (!(await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).EnableOpds) + return BadRequest("OPDS is not enabled on this server"); + var userId = await GetUser(apiKey); + var user = await _unitOfWork.UserRepository.GetUserByIdAsync(userId); + var isAdmin = await _unitOfWork.UserRepository.IsUserAdminAsync(user); + + IEnumerable tags; + if (isAdmin) + { + tags = await _unitOfWork.CollectionTagRepository.GetAllTagDtosAsync(); + } + else + { + tags = await _unitOfWork.CollectionTagRepository.GetAllPromotedTagDtosAsync(); + } + + var tag = tags.SingleOrDefault(t => t.Id == collectionId); + if (tag == null) + { + return BadRequest("Collection does not exist or you don't have access"); + } + + var series = await _unitOfWork.SeriesRepository.GetSeriesDtoForCollectionAsync(collectionId, userId, new UserParams() + { + PageNumber = pageNumber, + PageSize = 20 + }); + + var feed = CreateFeed(tag.Title + " Collection", $"{apiKey}/collections/{collectionId}", apiKey); + SetFeedId(feed, $"collections-{collectionId}"); + AddPagination(feed, series, $"{Prefix}{apiKey}/collections/{collectionId}"); + + foreach (var seriesDto in series) + { + feed.Entries.Add(CreateSeries(seriesDto, apiKey)); + } + + + return CreateXmlResult(SerializeXml(feed)); + } + + [HttpGet("{apiKey}/reading-list")] + [Produces("application/xml")] + public async Task GetReadingLists(string apiKey, [FromQuery] int pageNumber = 0) + { + if (!(await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).EnableOpds) + return BadRequest("OPDS is not enabled on this server"); + var userId = await GetUser(apiKey); + + var readingLists = await _unitOfWork.ReadingListRepository.GetReadingListDtosForUserAsync(userId, true, new UserParams() + { + PageNumber = pageNumber + }); + + + var feed = CreateFeed("All Reading Lists", $"{apiKey}/reading-list", apiKey); + SetFeedId(feed, "reading-list"); + foreach (var readingListDto in readingLists) + { + feed.Entries.Add(new FeedEntry() + { + Id = readingListDto.Id.ToString(), + Title = readingListDto.Title, + Summary = readingListDto.Summary, + Links = new List() + { + CreateLink(FeedLinkRelation.SubSection, FeedLinkType.AtomNavigation, Prefix + $"{apiKey}/reading-list/{readingListDto.Id}"), + } + }); + } + + return CreateXmlResult(SerializeXml(feed)); + } + + [HttpGet("{apiKey}/reading-list/{readingListId}")] + [Produces("application/xml")] + public async Task GetReadingListItems(int readingListId, string apiKey) + { + if (!(await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).EnableOpds) + return BadRequest("OPDS is not enabled on this server"); + var userId = await GetUser(apiKey); + var user = await _unitOfWork.UserRepository.GetUserByIdAsync(userId); + + var userWithLists = await _unitOfWork.UserRepository.GetUserWithReadingListsByUsernameAsync(user.UserName); + var readingList = userWithLists.ReadingLists.SingleOrDefault(t => t.Id == readingListId); + if (readingList == null) + { + return BadRequest("Reading list does not exist or you don't have access"); + } + + var feed = CreateFeed(readingList.Title + " Reading List", $"{apiKey}/reading-list/{readingListId}", apiKey); + SetFeedId(feed, $"reading-list-{readingListId}"); + + var items = (await _unitOfWork.ReadingListRepository.GetReadingListItemDtosByIdAsync(readingListId, userId)).ToList(); + foreach (var item in items) + { + feed.Entries.Add(new FeedEntry() + { + Id = item.ChapterId.ToString(), + Title = $"{item.SeriesName} Chapter {item.ChapterNumber}", + Links = new List() + { + CreateLink(FeedLinkRelation.SubSection, FeedLinkType.AtomNavigation, Prefix + $"{apiKey}/series/{item.SeriesId}/volume/{item.VolumeId}/chapter/{item.ChapterId}"), + CreateLink(FeedLinkRelation.Image, FeedLinkType.Image, $"/api/image/chapter-cover?chapterId={item.ChapterId}") + } + }); + } + + return CreateXmlResult(SerializeXml(feed)); + } + + [HttpGet("{apiKey}/libraries/{libraryId}")] + [Produces("application/xml")] + public async Task GetSeriesForLibrary(int libraryId, string apiKey, [FromQuery] int pageNumber = 0) + { + if (!(await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).EnableOpds) + return BadRequest("OPDS is not enabled on this server"); + var userId = await GetUser(apiKey); + var library = + (await _unitOfWork.LibraryRepository.GetLibrariesForUserIdAsync(userId)).SingleOrDefault(l => + l.Id == libraryId); + if (library == null) + { + return BadRequest("User does not have access to this library"); + } + + var series = await _unitOfWork.SeriesRepository.GetSeriesDtoForLibraryIdAsync(libraryId, userId, new UserParams() + { + PageNumber = pageNumber, + PageSize = 20 + }, _filterDto); + + var feed = CreateFeed(library.Name, $"{apiKey}/libraries/{libraryId}", apiKey); + SetFeedId(feed, $"library-{library.Name}"); + AddPagination(feed, series, $"{Prefix}{apiKey}/libraries/{libraryId}"); + + foreach (var seriesDto in series) + { + feed.Entries.Add(CreateSeries(seriesDto, apiKey)); + } + + return CreateXmlResult(SerializeXml(feed)); + } + + [HttpGet("{apiKey}/recently-added")] + [Produces("application/xml")] + public async Task GetRecentlyAdded(string apiKey, [FromQuery] int pageNumber = 1) + { + if (!(await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).EnableOpds) + return BadRequest("OPDS is not enabled on this server"); + var userId = await GetUser(apiKey); + var recentlyAdded = await _unitOfWork.SeriesRepository.GetRecentlyAdded(0, userId, new UserParams() + { + PageNumber = pageNumber, + PageSize = 20 + }, _filterDto); + + var feed = CreateFeed("Recently Added", $"{apiKey}/recently-added", apiKey); + SetFeedId(feed, "recently-added"); + AddPagination(feed, recentlyAdded, $"{Prefix}{apiKey}/recently-added"); + + foreach (var seriesDto in recentlyAdded) + { + feed.Entries.Add(CreateSeries(seriesDto, apiKey)); + } + + return CreateXmlResult(SerializeXml(feed)); + } + + [HttpGet("{apiKey}/on-deck")] + [Produces("application/xml")] + public async Task GetOnDeck(string apiKey, [FromQuery] int pageNumber = 1) + { + if (!(await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).EnableOpds) + return BadRequest("OPDS is not enabled on this server"); + var userId = await GetUser(apiKey); + var userParams = new UserParams() + { + PageNumber = pageNumber, + PageSize = 20 }; - private readonly ChapterSortComparer _chapterSortComparer = new ChapterSortComparer(); + var results = await _unitOfWork.SeriesRepository.GetOnDeck(userId, 0, userParams, _filterDto); + var listResults = results.DistinctBy(s => s.Name).Skip((userParams.PageNumber - 1) * userParams.PageSize) + .Take(userParams.PageSize).ToList(); + var pagedList = new PagedList(listResults, listResults.Count, userParams.PageNumber, userParams.PageSize); - public OpdsController(IUnitOfWork unitOfWork, IDownloadService downloadService, - IDirectoryService directoryService, ICacheService cacheService, - IReaderService readerService) + Response.AddPaginationHeader(pagedList.CurrentPage, pagedList.PageSize, pagedList.TotalCount, pagedList.TotalPages); + + var feed = CreateFeed("On Deck", $"{apiKey}/on-deck", apiKey); + SetFeedId(feed, "on-deck"); + AddPagination(feed, pagedList, $"{Prefix}{apiKey}/on-deck"); + + foreach (var seriesDto in pagedList) { - _unitOfWork = unitOfWork; - _downloadService = downloadService; - _directoryService = directoryService; - _cacheService = cacheService; - _readerService = readerService; - - _xmlSerializer = new XmlSerializer(typeof(Feed)); - _xmlOpenSearchSerializer = new XmlSerializer(typeof(OpenSearchDescription)); - + feed.Entries.Add(CreateSeries(seriesDto, apiKey)); } - [HttpPost("{apiKey}")] - [HttpGet("{apiKey}")] - [Produces("application/xml")] - public async Task Get(string apiKey) + return CreateXmlResult(SerializeXml(feed)); + } + + [HttpGet("{apiKey}/series")] + [Produces("application/xml")] + public async Task SearchSeries(string apiKey, [FromQuery] string query) + { + if (!(await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).EnableOpds) + return BadRequest("OPDS is not enabled on this server"); + var userId = await GetUser(apiKey); + if (string.IsNullOrEmpty(query)) + { + return BadRequest("You must pass a query parameter"); + } + query = query.Replace(@"%", ""); + // Get libraries user has access to + var libraries = (await _unitOfWork.LibraryRepository.GetLibrariesForUserIdAsync(userId)).ToList(); + + if (!libraries.Any()) return BadRequest("User does not have access to any libraries"); + + var series = await _unitOfWork.SeriesRepository.SearchSeries(libraries.Select(l => l.Id).ToArray(), query); + + var feed = CreateFeed(query, $"{apiKey}/series?query=" + query, apiKey); + SetFeedId(feed, "search-series"); + foreach (var seriesDto in series) + { + feed.Entries.Add(CreateSeries(seriesDto, apiKey)); + } + + return CreateXmlResult(SerializeXml(feed)); + } + + private static void SetFeedId(Feed feed, string id) + { + feed.Id = id; + } + + [HttpGet("{apiKey}/search")] + [Produces("application/xml")] + public async Task GetSearchDescriptor(string apiKey) + { + if (!(await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).EnableOpds) + return BadRequest("OPDS is not enabled on this server"); + var feed = new OpenSearchDescription() + { + ShortName = "Search", + Description = "Search for Series", + Url = new SearchLink() + { + Type = FeedLinkType.AtomAcquisition, + Template = $"{Prefix}{apiKey}/series?query=" + "{searchTerms}" + } + }; + + await using var sm = new StringWriter(); + _xmlOpenSearchSerializer.Serialize(sm, feed); + + return CreateXmlResult(sm.ToString().Replace("utf-16", "utf-8")); + } + + [HttpGet("{apiKey}/series/{seriesId}")] + [Produces("application/xml")] + public async Task GetSeries(string apiKey, int seriesId) + { + if (!(await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).EnableOpds) + return BadRequest("OPDS is not enabled on this server"); + var userId = await GetUser(apiKey); + var series = await _unitOfWork.SeriesRepository.GetSeriesDtoByIdAsync(seriesId, userId); + var volumes = await _unitOfWork.VolumeRepository.GetVolumesDtoAsync(seriesId, userId); + var feed = CreateFeed(series.Name + " - Volumes", $"{apiKey}/series/{series.Id}", apiKey); + SetFeedId(feed, $"series-{series.Id}"); + feed.Links.Add(CreateLink(FeedLinkRelation.Image, FeedLinkType.Image, $"/api/image/series-cover?seriesId={seriesId}")); + foreach (var volumeDto in volumes) + { + feed.Entries.Add(CreateVolume(volumeDto, seriesId, apiKey)); + } + + return CreateXmlResult(SerializeXml(feed)); + } + + [HttpGet("{apiKey}/series/{seriesId}/volume/{volumeId}")] + [Produces("application/xml")] + public async Task GetVolume(string apiKey, int seriesId, int volumeId) + { + if (!(await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).EnableOpds) + return BadRequest("OPDS is not enabled on this server"); + var userId = await GetUser(apiKey); + var series = await _unitOfWork.SeriesRepository.GetSeriesDtoByIdAsync(seriesId, userId); + var volume = await _unitOfWork.VolumeRepository.GetVolumeAsync(volumeId); + var chapters = + (await _unitOfWork.ChapterRepository.GetChaptersAsync(volumeId)).OrderBy(x => double.Parse(x.Number), + _chapterSortComparer); + + var feed = CreateFeed(series.Name + " - Volume " + volume.Name + " - Chapters ", $"{apiKey}/series/{seriesId}/volume/{volumeId}", apiKey); + SetFeedId(feed, $"series-{series.Id}-volume-{volume.Id}-chapters"); + foreach (var chapter in chapters) { - if (!(await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).EnableOpds) - return BadRequest("OPDS is not enabled on this server"); - var feed = CreateFeed("Kavita", string.Empty, apiKey); - SetFeedId(feed, "root"); feed.Entries.Add(new FeedEntry() { - Id = "onDeck", - Title = "On Deck", - Content = new FeedEntryContent() - { - Text = "Browse by On Deck" - }, + Id = chapter.Id.ToString(), + Title = "Chapter " + chapter.Number, Links = new List() { - CreateLink(FeedLinkRelation.SubSection, FeedLinkType.AtomNavigation, Prefix + $"{apiKey}/on-deck"), + CreateLink(FeedLinkRelation.SubSection, FeedLinkType.AtomNavigation, Prefix + $"{apiKey}/series/{seriesId}/volume/{volumeId}/chapter/{chapter.Id}"), + CreateLink(FeedLinkRelation.Image, FeedLinkType.Image, $"/api/image/chapter-cover?chapterId={chapter.Id}") } }); - feed.Entries.Add(new FeedEntry() - { - Id = "recentlyAdded", - Title = "Recently Added", - Content = new FeedEntryContent() - { - Text = "Browse by Recently Added" - }, - Links = new List() - { - CreateLink(FeedLinkRelation.SubSection, FeedLinkType.AtomNavigation, Prefix + $"{apiKey}/recently-added"), - } - }); - feed.Entries.Add(new FeedEntry() - { - Id = "readingList", - Title = "Reading Lists", - Content = new FeedEntryContent() - { - Text = "Browse by Reading Lists" - }, - Links = new List() - { - CreateLink(FeedLinkRelation.SubSection, FeedLinkType.AtomNavigation, Prefix + $"{apiKey}/reading-list"), - } - }); - feed.Entries.Add(new FeedEntry() - { - Id = "allLibraries", - Title = "All Libraries", - Content = new FeedEntryContent() - { - Text = "Browse by Libraries" - }, - Links = new List() - { - CreateLink(FeedLinkRelation.SubSection, FeedLinkType.AtomNavigation, Prefix + $"{apiKey}/libraries"), - } - }); - feed.Entries.Add(new FeedEntry() - { - Id = "allCollections", - Title = "All Collections", - Content = new FeedEntryContent() - { - Text = "Browse by Collections" - }, - Links = new List() - { - CreateLink(FeedLinkRelation.SubSection, FeedLinkType.AtomNavigation, Prefix + $"{apiKey}/collections"), - } - }); - return CreateXmlResult(SerializeXml(feed)); + } + + return CreateXmlResult(SerializeXml(feed)); + } + + [HttpGet("{apiKey}/series/{seriesId}/volume/{volumeId}/chapter/{chapterId}")] + [Produces("application/xml")] + public async Task GetChapter(string apiKey, int seriesId, int volumeId, int chapterId) + { + if (!(await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).EnableOpds) + return BadRequest("OPDS is not enabled on this server"); + var userId = await GetUser(apiKey); + var series = await _unitOfWork.SeriesRepository.GetSeriesDtoByIdAsync(seriesId, userId); + var volume = await _unitOfWork.VolumeRepository.GetVolumeAsync(volumeId); + var chapter = await _unitOfWork.ChapterRepository.GetChapterDtoAsync(chapterId); + var files = await _unitOfWork.ChapterRepository.GetFilesForChapterAsync(chapterId); + + var feed = CreateFeed(series.Name + " - Volume " + volume.Name + " - Chapters ", $"{apiKey}/series/{seriesId}/volume/{volumeId}/chapter/{chapterId}", apiKey); + SetFeedId(feed, $"series-{series.Id}-volume-{volume.Id}-chapter-{chapter.Id}-files"); + foreach (var mangaFile in files) + { + feed.Entries.Add(CreateChapter(seriesId, volumeId, chapterId, mangaFile, series, volume, chapter, apiKey)); + } + + return CreateXmlResult(SerializeXml(feed)); + } + + /// + /// Downloads a file + /// + /// + /// + /// + /// Not used. Only for Chunky to allow download links + /// + [HttpGet("{apiKey}/series/{seriesId}/volume/{volumeId}/chapter/{chapterId}/download/{filename}")] + public async Task DownloadFile(string apiKey, int seriesId, int volumeId, int chapterId, string filename) + { + if (!(await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).EnableOpds) + return BadRequest("OPDS is not enabled on this server"); + var files = await _unitOfWork.ChapterRepository.GetFilesForChapterAsync(chapterId); + var (bytes, contentType, fileDownloadName) = await _downloadService.GetFirstFileDownload(files); + return File(bytes, contentType, fileDownloadName); + } + + private static ContentResult CreateXmlResult(string xml) + { + return new ContentResult + { + ContentType = "application/xml", + Content = xml, + StatusCode = 200 + }; + } + + private static void AddPagination(Feed feed, PagedList list, string href) + { + var url = href; + if (href.Contains("?")) + { + url += "&"; + } + else + { + url += "?"; + } + + var pageNumber = Math.Max(list.CurrentPage, 1); + + if (pageNumber > 1) + { + feed.Links.Add(CreateLink(FeedLinkRelation.Prev, FeedLinkType.AtomNavigation, url + "pageNumber=" + (pageNumber - 1))); + } + + if (pageNumber + 1 <= list.TotalPages) + { + feed.Links.Add(CreateLink(FeedLinkRelation.Next, FeedLinkType.AtomNavigation, url + "pageNumber=" + (pageNumber + 1))); + } + + // Update self to point to current page + var selfLink = feed.Links.SingleOrDefault(l => l.Rel == FeedLinkRelation.Self); + if (selfLink != null) + { + selfLink.Href = url + "pageNumber=" + pageNumber; } - [HttpGet("{apiKey}/libraries")] - [Produces("application/xml")] - public async Task GetLibraries(string apiKey) + feed.Total = list.TotalCount; + feed.ItemsPerPage = list.PageSize; + feed.StartIndex = (Math.Max(list.CurrentPage - 1, 0) * list.PageSize) + 1; + } + + private static FeedEntry CreateSeries(SeriesDto seriesDto, string apiKey) + { + return new FeedEntry() { - if (!(await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).EnableOpds) - return BadRequest("OPDS is not enabled on this server"); - var userId = await GetUser(apiKey); - var libraries = await _unitOfWork.LibraryRepository.GetLibrariesForUserIdAsync(userId); - var feed = CreateFeed("All Libraries", $"{apiKey}/libraries", apiKey); - SetFeedId(feed, "libraries"); - foreach (var library in libraries) + Id = seriesDto.Id.ToString(), + Title = $"{seriesDto.Name} ({seriesDto.Format})", + Summary = seriesDto.Summary, + Links = new List() { - feed.Entries.Add(new FeedEntry() - { - Id = library.Id.ToString(), - Title = library.Name, - Links = new List() - { - CreateLink(FeedLinkRelation.SubSection, FeedLinkType.AtomNavigation, Prefix + $"{apiKey}/libraries/{library.Id}"), - } - }); + CreateLink(FeedLinkRelation.SubSection, FeedLinkType.AtomNavigation, Prefix + $"{apiKey}/series/{seriesDto.Id}"), + CreateLink(FeedLinkRelation.Image, FeedLinkType.Image, $"/api/image/series-cover?seriesId={seriesDto.Id}"), + CreateLink(FeedLinkRelation.Thumbnail, FeedLinkType.Image, $"/api/image/series-cover?seriesId={seriesDto.Id}") } + }; + } - return CreateXmlResult(SerializeXml(feed)); - } - - [HttpGet("{apiKey}/collections")] - [Produces("application/xml")] - public async Task GetCollections(string apiKey) + private static FeedEntry CreateSeries(SearchResultDto searchResultDto, string apiKey) + { + return new FeedEntry() { - if (!(await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).EnableOpds) - return BadRequest("OPDS is not enabled on this server"); - var userId = await GetUser(apiKey); - var user = await _unitOfWork.UserRepository.GetUserByIdAsync(userId); - var isAdmin = await _unitOfWork.UserRepository.IsUserAdmin(user); - - IList tags; - if (isAdmin) + Id = searchResultDto.SeriesId.ToString(), + Title = $"{searchResultDto.Name} ({searchResultDto.Format})", + Links = new List() { - tags = (await _unitOfWork.CollectionTagRepository.GetAllTagDtosAsync()).ToList(); - } - else - { - tags = (await _unitOfWork.CollectionTagRepository.GetAllPromotedTagDtosAsync()).ToList(); + CreateLink(FeedLinkRelation.SubSection, FeedLinkType.AtomNavigation, Prefix + $"{apiKey}/series/{searchResultDto.SeriesId}"), + CreateLink(FeedLinkRelation.Image, FeedLinkType.Image, $"/api/image/series-cover?seriesId={searchResultDto.SeriesId}"), + CreateLink(FeedLinkRelation.Thumbnail, FeedLinkType.Image, $"/api/image/series-cover?seriesId={searchResultDto.SeriesId}") } + }; + } - - var feed = CreateFeed("All Collections", $"{apiKey}/collections", apiKey); - SetFeedId(feed, "collections"); - foreach (var tag in tags) - { - feed.Entries.Add(new FeedEntry() - { - Id = tag.Id.ToString(), - Title = tag.Title, - Summary = tag.Summary, - Links = new List() - { - CreateLink(FeedLinkRelation.SubSection, FeedLinkType.AtomNavigation, Prefix + $"{apiKey}/collections/{tag.Id}"), - CreateLink(FeedLinkRelation.Image, FeedLinkType.Image, $"/api/image/collection-cover?collectionId={tag.Id}"), - CreateLink(FeedLinkRelation.Thumbnail, FeedLinkType.Image, $"/api/image/collection-cover?collectionId={tag.Id}") - } - }); - } - - return CreateXmlResult(SerializeXml(feed)); - } - - - [HttpGet("{apiKey}/collections/{collectionId}")] - [Produces("application/xml")] - public async Task GetCollection(int collectionId, string apiKey, [FromQuery] int pageNumber = 0) + private static FeedEntry CreateVolume(VolumeDto volumeDto, int seriesId, string apiKey) + { + return new FeedEntry() { - if (!(await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).EnableOpds) - return BadRequest("OPDS is not enabled on this server"); - var userId = await GetUser(apiKey); - var user = await _unitOfWork.UserRepository.GetUserByIdAsync(userId); - var isAdmin = await _unitOfWork.UserRepository.IsUserAdmin(user); - - IEnumerable tags; - if (isAdmin) + Id = volumeDto.Id.ToString(), + Title = "Volume " + volumeDto.Name, + Links = new List() { - tags = await _unitOfWork.CollectionTagRepository.GetAllTagDtosAsync(); - } - else - { - tags = await _unitOfWork.CollectionTagRepository.GetAllPromotedTagDtosAsync(); + CreateLink(FeedLinkRelation.SubSection, FeedLinkType.AtomNavigation, Prefix + $"{apiKey}/series/{seriesId}/volume/{volumeDto.Id}"), + CreateLink(FeedLinkRelation.Image, FeedLinkType.Image, $"/api/image/volume-cover?volumeId={volumeDto.Id}"), + CreateLink(FeedLinkRelation.Thumbnail, FeedLinkType.Image, $"/api/image/volume-cover?volumeId={volumeDto.Id}") } + }; + } - var tag = tags.SingleOrDefault(t => t.Id == collectionId); - if (tag == null) - { - return BadRequest("Collection does not exist or you don't have access"); - } - - var series = await _unitOfWork.SeriesRepository.GetSeriesDtoForCollectionAsync(collectionId, userId, new UserParams() - { - PageNumber = pageNumber, - PageSize = 20 - }); - - var feed = CreateFeed(tag.Title + " Collection", $"{apiKey}/collections/{collectionId}", apiKey); - SetFeedId(feed, $"collections-{collectionId}"); - AddPagination(feed, series, $"{Prefix}{apiKey}/collections/{collectionId}"); - - foreach (var seriesDto in series) - { - feed.Entries.Add(CreateSeries(seriesDto, apiKey)); - } - - - return CreateXmlResult(SerializeXml(feed)); - } - - [HttpGet("{apiKey}/reading-list")] - [Produces("application/xml")] - public async Task GetReadingLists(string apiKey, [FromQuery] int pageNumber = 0) + private FeedEntry CreateChapter(int seriesId, int volumeId, int chapterId, MangaFile mangaFile, SeriesDto series, Volume volume, ChapterDto chapter, string apiKey) + { + var fileSize = + DirectoryService.GetHumanReadableBytes(_directoryService.GetTotalSize(new List() + {mangaFile.FilePath})); + var fileType = _downloadService.GetContentTypeFromFile(mangaFile.FilePath); + var filename = Uri.EscapeDataString(Path.GetFileName(mangaFile.FilePath) ?? string.Empty); + return new FeedEntry() { - if (!(await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).EnableOpds) - return BadRequest("OPDS is not enabled on this server"); - var userId = await GetUser(apiKey); - - var readingLists = await _unitOfWork.ReadingListRepository.GetReadingListDtosForUserAsync(userId, true, new UserParams() + Id = mangaFile.Id.ToString(), + Title = $"{series.Name} - Volume {volume.Name} - Chapter {chapter.Number}", + Extent = fileSize, + Summary = $"{fileType.Split("/")[1]} - {fileSize}", + Format = mangaFile.Format.ToString(), + Links = new List() { - PageNumber = pageNumber - }); - - - var feed = CreateFeed("All Reading Lists", $"{apiKey}/reading-list", apiKey); - SetFeedId(feed, "reading-list"); - foreach (var readingListDto in readingLists) + CreateLink(FeedLinkRelation.Image, FeedLinkType.Image, $"/api/image/chapter-cover?chapterId={chapterId}"), + CreateLink(FeedLinkRelation.Thumbnail, FeedLinkType.Image, $"/api/image/chapter-cover?chapterId={chapterId}"), + // Chunky requires a file at the end. Our API ignores this + CreateLink(FeedLinkRelation.Acquisition, fileType, $"{Prefix}{apiKey}/series/{seriesId}/volume/{volumeId}/chapter/{chapterId}/download/{filename}"), + CreatePageStreamLink(seriesId, volumeId, chapterId, mangaFile, apiKey) + }, + Content = new FeedEntryContent() { - feed.Entries.Add(new FeedEntry() - { - Id = readingListDto.Id.ToString(), - Title = readingListDto.Title, - Summary = readingListDto.Summary, - Links = new List() - { - CreateLink(FeedLinkRelation.SubSection, FeedLinkType.AtomNavigation, Prefix + $"{apiKey}/reading-list/{readingListDto.Id}"), - } - }); + Text = fileType, + Type = "text" } + }; + } - return CreateXmlResult(SerializeXml(feed)); - } + [HttpGet("{apiKey}/image")] + public async Task GetPageStreamedImage(string apiKey, [FromQuery] int seriesId, [FromQuery] int volumeId,[FromQuery] int chapterId, [FromQuery] int pageNumber) + { + if (pageNumber < 0) return BadRequest("Page cannot be less than 0"); + var chapter = await _cacheService.Ensure(chapterId); + if (chapter == null) return BadRequest("There was an issue finding image file for reading"); - [HttpGet("{apiKey}/reading-list/{readingListId}")] - [Produces("application/xml")] - public async Task GetReadingListItems(int readingListId, string apiKey) + try { - if (!(await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).EnableOpds) - return BadRequest("OPDS is not enabled on this server"); - var userId = await GetUser(apiKey); - var user = await _unitOfWork.UserRepository.GetUserByIdAsync(userId); + var path = _cacheService.GetCachedPagePath(chapter, pageNumber); + if (string.IsNullOrEmpty(path) || !System.IO.File.Exists(path)) return BadRequest($"No such image for page {pageNumber}"); - var userWithLists = await _unitOfWork.UserRepository.GetUserWithReadingListsByUsernameAsync(user.UserName); - var readingList = userWithLists.ReadingLists.SingleOrDefault(t => t.Id == readingListId); - if (readingList == null) - { - return BadRequest("Reading list does not exist or you don't have access"); - } - - var feed = CreateFeed(readingList.Title + " Reading List", $"{apiKey}/reading-list/{readingListId}", apiKey); - SetFeedId(feed, $"reading-list-{readingListId}"); - - var items = (await _unitOfWork.ReadingListRepository.GetReadingListItemDtosByIdAsync(readingListId, userId)).ToList(); - foreach (var item in items) - { - feed.Entries.Add(new FeedEntry() - { - Id = item.ChapterId.ToString(), - Title = $"{item.SeriesName} Chapter {item.ChapterNumber}", - Links = new List() - { - CreateLink(FeedLinkRelation.SubSection, FeedLinkType.AtomNavigation, Prefix + $"{apiKey}/series/{item.SeriesId}/volume/{item.VolumeId}/chapter/{item.ChapterId}"), - CreateLink(FeedLinkRelation.Image, FeedLinkType.Image, $"/api/image/chapter-cover?chapterId={item.ChapterId}") - } - }); - } - - return CreateXmlResult(SerializeXml(feed)); - } - - [HttpGet("{apiKey}/libraries/{libraryId}")] - [Produces("application/xml")] - public async Task GetSeriesForLibrary(int libraryId, string apiKey, [FromQuery] int pageNumber = 0) - { - if (!(await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).EnableOpds) - return BadRequest("OPDS is not enabled on this server"); - var userId = await GetUser(apiKey); - var library = - (await _unitOfWork.LibraryRepository.GetLibrariesForUserIdAsync(userId)).SingleOrDefault(l => - l.Id == libraryId); - if (library == null) - { - return BadRequest("User does not have access to this library"); - } - - var series = await _unitOfWork.SeriesRepository.GetSeriesDtoForLibraryIdAsync(libraryId, userId, new UserParams() - { - PageNumber = pageNumber, - PageSize = 20 - }, _filterDto); - - var feed = CreateFeed(library.Name, $"{apiKey}/libraries/{libraryId}", apiKey); - SetFeedId(feed, $"library-{library.Name}"); - AddPagination(feed, series, $"{Prefix}{apiKey}/libraries/{libraryId}"); - - foreach (var seriesDto in series) - { - feed.Entries.Add(CreateSeries(seriesDto, apiKey)); - } - - return CreateXmlResult(SerializeXml(feed)); - } - - [HttpGet("{apiKey}/recently-added")] - [Produces("application/xml")] - public async Task GetRecentlyAdded(string apiKey, [FromQuery] int pageNumber = 1) - { - if (!(await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).EnableOpds) - return BadRequest("OPDS is not enabled on this server"); - var userId = await GetUser(apiKey); - var recentlyAdded = await _unitOfWork.SeriesRepository.GetRecentlyAdded(0, userId, new UserParams() - { - PageNumber = pageNumber, - PageSize = 20 - }, _filterDto); - - var feed = CreateFeed("Recently Added", $"{apiKey}/recently-added", apiKey); - SetFeedId(feed, "recently-added"); - AddPagination(feed, recentlyAdded, $"{Prefix}{apiKey}/recently-added"); - - foreach (var seriesDto in recentlyAdded) - { - feed.Entries.Add(CreateSeries(seriesDto, apiKey)); - } - - return CreateXmlResult(SerializeXml(feed)); - } - - [HttpGet("{apiKey}/on-deck")] - [Produces("application/xml")] - public async Task GetOnDeck(string apiKey, [FromQuery] int pageNumber = 1) - { - if (!(await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).EnableOpds) - return BadRequest("OPDS is not enabled on this server"); - var userId = await GetUser(apiKey); - var userParams = new UserParams() - { - PageNumber = pageNumber, - PageSize = 20 - }; - var results = await _unitOfWork.SeriesRepository.GetOnDeck(userId, 0, userParams, _filterDto); - var listResults = results.DistinctBy(s => s.Name).Skip((userParams.PageNumber - 1) * userParams.PageSize) - .Take(userParams.PageSize).ToList(); - var pagedList = new PagedList(listResults, listResults.Count, userParams.PageNumber, userParams.PageSize); - - Response.AddPaginationHeader(pagedList.CurrentPage, pagedList.PageSize, pagedList.TotalCount, pagedList.TotalPages); - - var feed = CreateFeed("On Deck", $"{apiKey}/on-deck", apiKey); - SetFeedId(feed, "on-deck"); - AddPagination(feed, pagedList, $"{Prefix}{apiKey}/on-deck"); - - foreach (var seriesDto in pagedList) - { - feed.Entries.Add(CreateSeries(seriesDto, apiKey)); - } - - return CreateXmlResult(SerializeXml(feed)); - } - - [HttpGet("{apiKey}/series")] - [Produces("application/xml")] - public async Task SearchSeries(string apiKey, [FromQuery] string query) - { - if (!(await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).EnableOpds) - return BadRequest("OPDS is not enabled on this server"); - var userId = await GetUser(apiKey); - if (string.IsNullOrEmpty(query)) - { - return BadRequest("You must pass a query parameter"); - } - query = query.Replace(@"%", ""); - // Get libraries user has access to - var libraries = (await _unitOfWork.LibraryRepository.GetLibrariesForUserIdAsync(userId)).ToList(); - - if (!libraries.Any()) return BadRequest("User does not have access to any libraries"); - - var series = await _unitOfWork.SeriesRepository.SearchSeries(libraries.Select(l => l.Id).ToArray(), query); - - var feed = CreateFeed(query, $"{apiKey}/series?query=" + query, apiKey); - SetFeedId(feed, "search-series"); - foreach (var seriesDto in series) - { - feed.Entries.Add(CreateSeries(seriesDto, apiKey)); - } - - return CreateXmlResult(SerializeXml(feed)); - } - - private static void SetFeedId(Feed feed, string id) - { - feed.Id = id; - } - - [HttpGet("{apiKey}/search")] - [Produces("application/xml")] - public async Task GetSearchDescriptor(string apiKey) - { - if (!(await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).EnableOpds) - return BadRequest("OPDS is not enabled on this server"); - var feed = new OpenSearchDescription() - { - ShortName = "Search", - Description = "Search for Series", - Url = new SearchLink() - { - Type = FeedLinkType.AtomAcquisition, - Template = $"{Prefix}{apiKey}/series?query=" + "{searchTerms}" - } - }; - - await using var sm = new StringWriter(); - _xmlOpenSearchSerializer.Serialize(sm, feed); - - return CreateXmlResult(sm.ToString().Replace("utf-16", "utf-8")); - } - - [HttpGet("{apiKey}/series/{seriesId}")] - [Produces("application/xml")] - public async Task GetSeries(string apiKey, int seriesId) - { - if (!(await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).EnableOpds) - return BadRequest("OPDS is not enabled on this server"); - var userId = await GetUser(apiKey); - var series = await _unitOfWork.SeriesRepository.GetSeriesDtoByIdAsync(seriesId, userId); - var volumes = await _unitOfWork.VolumeRepository.GetVolumesDtoAsync(seriesId, userId); - var feed = CreateFeed(series.Name + " - Volumes", $"{apiKey}/series/{series.Id}", apiKey); - SetFeedId(feed, $"series-{series.Id}"); - feed.Links.Add(CreateLink(FeedLinkRelation.Image, FeedLinkType.Image, $"/api/image/series-cover?seriesId={seriesId}")); - foreach (var volumeDto in volumes) - { - feed.Entries.Add(CreateVolume(volumeDto, seriesId, apiKey)); - } - - return CreateXmlResult(SerializeXml(feed)); - } - - [HttpGet("{apiKey}/series/{seriesId}/volume/{volumeId}")] - [Produces("application/xml")] - public async Task GetVolume(string apiKey, int seriesId, int volumeId) - { - if (!(await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).EnableOpds) - return BadRequest("OPDS is not enabled on this server"); - var userId = await GetUser(apiKey); - var series = await _unitOfWork.SeriesRepository.GetSeriesDtoByIdAsync(seriesId, userId); - var volume = await _unitOfWork.VolumeRepository.GetVolumeAsync(volumeId); - var chapters = - (await _unitOfWork.ChapterRepository.GetChaptersAsync(volumeId)).OrderBy(x => double.Parse(x.Number), - _chapterSortComparer); - - var feed = CreateFeed(series.Name + " - Volume " + volume.Name + " - Chapters ", $"{apiKey}/series/{seriesId}/volume/{volumeId}", apiKey); - SetFeedId(feed, $"series-{series.Id}-volume-{volume.Id}-chapters"); - foreach (var chapter in chapters) - { - feed.Entries.Add(new FeedEntry() - { - Id = chapter.Id.ToString(), - Title = "Chapter " + chapter.Number, - Links = new List() - { - CreateLink(FeedLinkRelation.SubSection, FeedLinkType.AtomNavigation, Prefix + $"{apiKey}/series/{seriesId}/volume/{volumeId}/chapter/{chapter.Id}"), - CreateLink(FeedLinkRelation.Image, FeedLinkType.Image, $"/api/image/chapter-cover?chapterId={chapter.Id}") - } - }); - } - - return CreateXmlResult(SerializeXml(feed)); - } - - [HttpGet("{apiKey}/series/{seriesId}/volume/{volumeId}/chapter/{chapterId}")] - [Produces("application/xml")] - public async Task GetChapter(string apiKey, int seriesId, int volumeId, int chapterId) - { - if (!(await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).EnableOpds) - return BadRequest("OPDS is not enabled on this server"); - var userId = await GetUser(apiKey); - var series = await _unitOfWork.SeriesRepository.GetSeriesDtoByIdAsync(seriesId, userId); - var volume = await _unitOfWork.VolumeRepository.GetVolumeAsync(volumeId); - var chapter = await _unitOfWork.ChapterRepository.GetChapterDtoAsync(chapterId); - var files = await _unitOfWork.ChapterRepository.GetFilesForChapterAsync(chapterId); - - var feed = CreateFeed(series.Name + " - Volume " + volume.Name + " - Chapters ", $"{apiKey}/series/{seriesId}/volume/{volumeId}/chapter/{chapterId}", apiKey); - SetFeedId(feed, $"series-{series.Id}-volume-{volume.Id}-chapter-{chapter.Id}-files"); - foreach (var mangaFile in files) - { - feed.Entries.Add(CreateChapter(seriesId, volumeId, chapterId, mangaFile, series, volume, chapter, apiKey)); - } - - return CreateXmlResult(SerializeXml(feed)); - } - - /// - /// Downloads a file - /// - /// - /// - /// - /// Not used. Only for Chunky to allow download links - /// - [HttpGet("{apiKey}/series/{seriesId}/volume/{volumeId}/chapter/{chapterId}/download/{filename}")] - public async Task DownloadFile(string apiKey, int seriesId, int volumeId, int chapterId, string filename) - { - if (!(await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).EnableOpds) - return BadRequest("OPDS is not enabled on this server"); - var files = await _unitOfWork.ChapterRepository.GetFilesForChapterAsync(chapterId); - var (bytes, contentType, fileDownloadName) = await _downloadService.GetFirstFileDownload(files); - return File(bytes, contentType, fileDownloadName); - } - - private static ContentResult CreateXmlResult(string xml) - { - return new ContentResult - { - ContentType = "application/xml", - Content = xml, - StatusCode = 200 - }; - } - - private static void AddPagination(Feed feed, PagedList list, string href) - { - var url = href; - if (href.Contains("?")) - { - url += "&"; - } - else - { - url += "?"; - } - - var pageNumber = Math.Max(list.CurrentPage, 1); - - if (pageNumber > 1) - { - feed.Links.Add(CreateLink(FeedLinkRelation.Prev, FeedLinkType.AtomNavigation, url + "pageNumber=" + (pageNumber - 1))); - } - - if (pageNumber + 1 < list.TotalPages) - { - feed.Links.Add(CreateLink(FeedLinkRelation.Next, FeedLinkType.AtomNavigation, url + "pageNumber=" + (pageNumber + 1))); - } - - // Update self to point to current page - var selfLink = feed.Links.SingleOrDefault(l => l.Rel == FeedLinkRelation.Self); - if (selfLink != null) - { - selfLink.Href = url + "pageNumber=" + pageNumber; - } - - - feed.Total = list.TotalPages * list.PageSize; - feed.ItemsPerPage = list.PageSize; - feed.StartIndex = (Math.Max(list.CurrentPage - 1, 0) * list.PageSize) + 1; - } - - private static FeedEntry CreateSeries(SeriesDto seriesDto, string apiKey) - { - return new FeedEntry() - { - Id = seriesDto.Id.ToString(), - Title = $"{seriesDto.Name} ({seriesDto.Format})", - Summary = seriesDto.Summary, - Links = new List() - { - CreateLink(FeedLinkRelation.SubSection, FeedLinkType.AtomNavigation, Prefix + $"{apiKey}/series/{seriesDto.Id}"), - CreateLink(FeedLinkRelation.Image, FeedLinkType.Image, $"/api/image/series-cover?seriesId={seriesDto.Id}"), - CreateLink(FeedLinkRelation.Thumbnail, FeedLinkType.Image, $"/api/image/series-cover?seriesId={seriesDto.Id}") - } - }; - } - - private static FeedEntry CreateSeries(SearchResultDto searchResultDto, string apiKey) - { - return new FeedEntry() - { - Id = searchResultDto.SeriesId.ToString(), - Title = $"{searchResultDto.Name} ({searchResultDto.Format})", - Links = new List() - { - CreateLink(FeedLinkRelation.SubSection, FeedLinkType.AtomNavigation, Prefix + $"{apiKey}/series/{searchResultDto.SeriesId}"), - CreateLink(FeedLinkRelation.Image, FeedLinkType.Image, $"/api/image/series-cover?seriesId={searchResultDto.SeriesId}"), - CreateLink(FeedLinkRelation.Thumbnail, FeedLinkType.Image, $"/api/image/series-cover?seriesId={searchResultDto.SeriesId}") - } - }; - } - - private static FeedEntry CreateVolume(VolumeDto volumeDto, int seriesId, string apiKey) - { - return new FeedEntry() - { - Id = volumeDto.Id.ToString(), - Title = "Volume " + volumeDto.Name, - Links = new List() - { - CreateLink(FeedLinkRelation.SubSection, FeedLinkType.AtomNavigation, Prefix + $"{apiKey}/series/{seriesId}/volume/{volumeDto.Id}"), - CreateLink(FeedLinkRelation.Image, FeedLinkType.Image, $"/api/image/volume-cover?volumeId={volumeDto.Id}"), - CreateLink(FeedLinkRelation.Thumbnail, FeedLinkType.Image, $"/api/image/volume-cover?volumeId={volumeDto.Id}") - } - }; - } - - private FeedEntry CreateChapter(int seriesId, int volumeId, int chapterId, MangaFile mangaFile, SeriesDto series, Volume volume, ChapterDto chapter, string apiKey) - { - var fileSize = - DirectoryService.GetHumanReadableBytes(DirectoryService.GetTotalSize(new List() - {mangaFile.FilePath})); - var fileType = _downloadService.GetContentTypeFromFile(mangaFile.FilePath); - var filename = Uri.EscapeUriString(Path.GetFileName(mangaFile.FilePath) ?? string.Empty); - return new FeedEntry() - { - Id = mangaFile.Id.ToString(), - Title = $"{series.Name} - Volume {volume.Name} - Chapter {chapter.Number}", - Extent = fileSize, - Summary = $"{fileType.Split("/")[1]} - {fileSize}", - Format = mangaFile.Format.ToString(), - Links = new List() - { - CreateLink(FeedLinkRelation.Image, FeedLinkType.Image, $"/api/image/chapter-cover?chapterId={chapterId}"), - CreateLink(FeedLinkRelation.Thumbnail, FeedLinkType.Image, $"/api/image/chapter-cover?chapterId={chapterId}"), - // Chunky requires a file at the end. Our API ignores this - CreateLink(FeedLinkRelation.Acquisition, fileType, $"{Prefix}{apiKey}/series/{seriesId}/volume/{volumeId}/chapter/{chapterId}/download/{filename}"), - CreatePageStreamLink(seriesId, volumeId, chapterId, mangaFile, apiKey) - }, - Content = new FeedEntryContent() - { - Text = fileType, - Type = "text" - } - }; - } - - [HttpGet("{apiKey}/image")] - public async Task GetPageStreamedImage(string apiKey, [FromQuery] int seriesId, [FromQuery] int volumeId,[FromQuery] int chapterId, [FromQuery] int pageNumber) - { - if (pageNumber < 0) return BadRequest("Page cannot be less than 0"); - var chapter = await _cacheService.Ensure(chapterId); - if (chapter == null) return BadRequest("There was an issue finding image file for reading"); - - try - { - var (path, _) = await _cacheService.GetCachedPagePath(chapter, pageNumber); - if (string.IsNullOrEmpty(path) || !System.IO.File.Exists(path)) return BadRequest($"No such image for page {pageNumber}"); - - var content = await _directoryService.ReadFileAsync(path); - var format = Path.GetExtension(path).Replace(".", ""); - - // Calculates SHA1 Hash for byte[] - Response.AddCacheHeader(content); - - // Save progress for the user - await _readerService.SaveReadingProgress(new ProgressDto() - { - ChapterId = chapterId, - PageNum = pageNumber, - SeriesId = seriesId, - VolumeId = volumeId - }, await GetUser(apiKey)); - - return File(content, "image/" + format); - } - catch (Exception) - { - _cacheService.CleanupChapters(new []{ chapterId }); - throw; - } - } - - [HttpGet("{apiKey}/favicon")] - public async Task GetFavicon(string apiKey) - { - var files = DirectoryService.GetFilesWithExtension(Path.Join(Directory.GetCurrentDirectory(), ".."), @"\.ico"); - if (files.Length == 0) return BadRequest("Cannot find icon"); - var path = files[0]; var content = await _directoryService.ReadFileAsync(path); var format = Path.GetExtension(path).Replace(".", ""); // Calculates SHA1 Hash for byte[] Response.AddCacheHeader(content); + // Save progress for the user + await _readerService.SaveReadingProgress(new ProgressDto() + { + ChapterId = chapterId, + PageNum = pageNumber, + SeriesId = seriesId, + VolumeId = volumeId + }, await GetUser(apiKey)); + return File(content, "image/" + format); } - - /// - /// Gets the user from the API key - /// - /// - private async Task GetUser(string apiKey) + catch (Exception) { - try - { - var user = await _unitOfWork.UserRepository.GetUserIdByApiKeyAsync(apiKey); - return user; - } - catch - { - /* Do nothing */ - } - throw new KavitaException("User does not exist"); - } - - private static FeedLink CreatePageStreamLink(int seriesId, int volumeId, int chapterId, MangaFile mangaFile, string apiKey) - { - var link = CreateLink(FeedLinkRelation.Stream, "image/jpeg", $"{Prefix}{apiKey}/image?seriesId={seriesId}&volumeId={volumeId}&chapterId={chapterId}&pageNumber=" + "{pageNumber}"); - link.TotalPages = mangaFile.Pages; - return link; - } - - private static FeedLink CreateLink(string rel, string type, string href) - { - return new FeedLink() - { - Rel = rel, - Href = href, - Type = type - }; - } - - private static Feed CreateFeed(string title, string href, string apiKey) - { - var link = CreateLink(FeedLinkRelation.Self, string.IsNullOrEmpty(href) ? - FeedLinkType.AtomNavigation : - FeedLinkType.AtomAcquisition, Prefix + href); - - return new Feed() - { - Title = title, - Icon = Prefix + $"{apiKey}/favicon", - Links = new List() - { - link, - CreateLink(FeedLinkRelation.Start, FeedLinkType.AtomNavigation, Prefix + apiKey), - CreateLink(FeedLinkRelation.Search, FeedLinkType.AtomSearch, Prefix + $"{apiKey}/search") - }, - }; - } - - private string SerializeXml(Feed feed) - { - if (feed == null) return string.Empty; - using var sm = new StringWriter(); - _xmlSerializer.Serialize(sm, feed); - return sm.ToString().Replace("utf-16", "utf-8"); // Chunky cannot accept UTF-16 feeds + _cacheService.CleanupChapters(new []{ chapterId }); + throw; } } + + [HttpGet("{apiKey}/favicon")] + public async Task GetFavicon(string apiKey) + { + var files = _directoryService.GetFilesWithExtension(Path.Join(Directory.GetCurrentDirectory(), ".."), @"\.ico"); + if (files.Length == 0) return BadRequest("Cannot find icon"); + var path = files[0]; + var content = await _directoryService.ReadFileAsync(path); + var format = Path.GetExtension(path).Replace(".", ""); + + // Calculates SHA1 Hash for byte[] + Response.AddCacheHeader(content); + + return File(content, "image/" + format); + } + + /// + /// Gets the user from the API key + /// + /// + private async Task GetUser(string apiKey) + { + try + { + var user = await _unitOfWork.UserRepository.GetUserIdByApiKeyAsync(apiKey); + return user; + } + catch + { + /* Do nothing */ + } + throw new KavitaException("User does not exist"); + } + + private static FeedLink CreatePageStreamLink(int seriesId, int volumeId, int chapterId, MangaFile mangaFile, string apiKey) + { + var link = CreateLink(FeedLinkRelation.Stream, "image/jpeg", $"{Prefix}{apiKey}/image?seriesId={seriesId}&volumeId={volumeId}&chapterId={chapterId}&pageNumber=" + "{pageNumber}"); + link.TotalPages = mangaFile.Pages; + return link; + } + + private static FeedLink CreateLink(string rel, string type, string href) + { + return new FeedLink() + { + Rel = rel, + Href = href, + Type = type + }; + } + + private static Feed CreateFeed(string title, string href, string apiKey) + { + var link = CreateLink(FeedLinkRelation.Self, string.IsNullOrEmpty(href) ? + FeedLinkType.AtomNavigation : + FeedLinkType.AtomAcquisition, Prefix + href); + + return new Feed() + { + Title = title, + Icon = Prefix + $"{apiKey}/favicon", + Links = new List() + { + link, + CreateLink(FeedLinkRelation.Start, FeedLinkType.AtomNavigation, Prefix + apiKey), + CreateLink(FeedLinkRelation.Search, FeedLinkType.AtomSearch, Prefix + $"{apiKey}/search") + }, + }; + } + + private string SerializeXml(Feed feed) + { + if (feed == null) return string.Empty; + using var sm = new StringWriter(); + _xmlSerializer.Serialize(sm, feed); + return sm.ToString().Replace("utf-16", "utf-8"); // Chunky cannot accept UTF-16 feeds + } } diff --git a/API/Controllers/PluginController.cs b/API/Controllers/PluginController.cs index b176c0628..5f2d99ba3 100644 --- a/API/Controllers/PluginController.cs +++ b/API/Controllers/PluginController.cs @@ -1,7 +1,7 @@ using System.Threading.Tasks; +using API.Data; using API.DTOs; -using API.Interfaces; -using API.Interfaces.Services; +using API.Services; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; diff --git a/API/Controllers/ReaderController.cs b/API/Controllers/ReaderController.cs index 5b18cfb98..3028d1fee 100644 --- a/API/Controllers/ReaderController.cs +++ b/API/Controllers/ReaderController.cs @@ -3,13 +3,15 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; +using API.Data; using API.Data.Repositories; using API.DTOs; using API.DTOs.Reader; using API.Entities; +using API.Entities.Enums; using API.Extensions; -using API.Interfaces; -using API.Interfaces.Services; +using API.Services; +using API.Services.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; @@ -24,15 +26,21 @@ namespace API.Controllers private readonly IUnitOfWork _unitOfWork; private readonly ILogger _logger; private readonly IReaderService _readerService; + private readonly IDirectoryService _directoryService; + private readonly ICleanupService _cleanupService; /// public ReaderController(ICacheService cacheService, - IUnitOfWork unitOfWork, ILogger logger, IReaderService readerService) + IUnitOfWork unitOfWork, ILogger logger, + IReaderService readerService, IDirectoryService directoryService, + ICleanupService cleanupService) { _cacheService = cacheService; _unitOfWork = unitOfWork; _logger = logger; _readerService = readerService; + _directoryService = directoryService; + _cleanupService = cleanupService; } /// @@ -50,7 +58,7 @@ namespace API.Controllers try { - var (path, _) = await _cacheService.GetCachedPagePath(chapter, page); + var path = _cacheService.GetCachedPagePath(chapter, page); if (string.IsNullOrEmpty(path) || !System.IO.File.Exists(path)) return BadRequest($"No such image for page {page}"); var format = Path.GetExtension(path).Replace(".", ""); @@ -75,6 +83,7 @@ namespace API.Controllers if (chapter == null) return BadRequest("Could not find Chapter"); var dto = await _unitOfWork.ChapterRepository.GetChapterInfoDtoAsync(chapterId); + if (dto == null) return BadRequest("Please perform a scan on this series or library and try again"); var mangaFile = (await _unitOfWork.ChapterRepository.GetFilesForChapterAsync(chapterId)).First(); return Ok(new ChapterInfoDto() @@ -89,6 +98,7 @@ namespace API.Controllers LibraryId = dto.LibraryId, IsSpecial = dto.IsSpecial, Pages = dto.Pages, + ChapterTitle = dto.ChapterTitle ?? string.Empty }); } @@ -129,15 +139,7 @@ namespace API.Controllers user.Progresses ??= new List(); foreach (var volume in volumes) { - foreach (var chapter in volume.Chapters) - { - var userProgress = ReaderService.GetUserProgressForChapter(user, chapter); - - if (userProgress == null) continue; - userProgress.PagesRead = 0; - userProgress.SeriesId = markReadDto.SeriesId; - userProgress.VolumeId = volume.Id; - } + _readerService.MarkChaptersAsUnread(user, markReadDto.SeriesId, volume.Chapters); } _unitOfWork.UserRepository.Update(user); @@ -396,6 +398,14 @@ namespace API.Controllers if (await _unitOfWork.CommitAsync()) { + try + { + await _cleanupService.CleanupBookmarks(); + } + catch (Exception ex) + { + _logger.LogError(ex, "There was an issue cleaning up old bookmarks"); + } return Ok(); } } @@ -453,6 +463,18 @@ namespace API.Controllers var userBookmark = await _unitOfWork.UserRepository.GetBookmarkForPage(bookmarkDto.Page, bookmarkDto.ChapterId, user.Id); + // We need to get the image + var chapter = await _cacheService.Ensure(bookmarkDto.ChapterId); + if (chapter == null) return BadRequest("There was an issue finding image file for reading"); + var path = _cacheService.GetCachedPagePath(chapter, bookmarkDto.Page); + var fileInfo = new FileInfo(path); + + var bookmarkDirectory = + (await _unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.BookmarkDirectory)).Value; + _directoryService.CopyFileToDirectory(path, Path.Join(bookmarkDirectory, + $"{user.Id}", $"{bookmarkDto.SeriesId}", $"{bookmarkDto.ChapterId}")); + + if (userBookmark == null) { user.Bookmarks ??= new List(); @@ -462,22 +484,21 @@ namespace API.Controllers VolumeId = bookmarkDto.VolumeId, SeriesId = bookmarkDto.SeriesId, ChapterId = bookmarkDto.ChapterId, + FileName = Path.Join($"{user.Id}", $"{bookmarkDto.SeriesId}", $"{bookmarkDto.ChapterId}", fileInfo.Name) + }); _unitOfWork.UserRepository.Update(user); } - - if (await _unitOfWork.CommitAsync()) - { - return Ok(); - } + await _unitOfWork.CommitAsync(); } catch (Exception) { await _unitOfWork.RollbackAsync(); + return BadRequest("Could not save bookmark"); } - return BadRequest("Could not save bookmark"); + return Ok(); } /// diff --git a/API/Controllers/ReadingListController.cs b/API/Controllers/ReadingListController.cs index 19e4a4b49..9391105cb 100644 --- a/API/Controllers/ReadingListController.cs +++ b/API/Controllers/ReadingListController.cs @@ -1,13 +1,12 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using API.Comparators; +using API.Data; using API.DTOs.ReadingLists; using API.Entities; using API.Extensions; using API.Helpers; -using API.Interfaces; using Microsoft.AspNetCore.Mvc; namespace API.Controllers diff --git a/API/Controllers/SeriesController.cs b/API/Controllers/SeriesController.cs index ba0571ec3..ad2faeb0f 100644 --- a/API/Controllers/SeriesController.cs +++ b/API/Controllers/SeriesController.cs @@ -3,15 +3,18 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using API.Data; +using API.Data.Metadata; using API.Data.Repositories; using API.DTOs; using API.DTOs.Filtering; using API.Entities; +using API.Entities.Enums; using API.Extensions; using API.Helpers; -using API.Interfaces; +using API.Services; using API.SignalR; using Kavita.Common; +using Kavita.Common.Extensions; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.SignalR; @@ -80,6 +83,8 @@ namespace API.Controllers var username = User.GetUsername(); _logger.LogInformation("Series {SeriesId} is being deleted by {UserName}", seriesId, username); + var series = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(seriesId); + var chapterIds = (await _unitOfWork.SeriesRepository.GetChapterIdsForSeriesAsync(new []{seriesId})); var result = await _unitOfWork.SeriesRepository.DeleteSeriesAsync(seriesId); @@ -89,6 +94,8 @@ namespace API.Controllers await _unitOfWork.CollectionTagRepository.RemoveTagsWithoutSeries(); await _unitOfWork.CommitAsync(); _taskScheduler.CleanupChapters(chapterIds); + await _messageHub.Clients.All.SendAsync(SignalREvents.SeriesRemoved, + MessageFactory.SeriesRemovedEvent(seriesId, series.Name, series.LibraryId)); } return Ok(result); } @@ -151,7 +158,7 @@ namespace API.Controllers public async Task UpdateSeriesRating(UpdateSeriesRatingDto updateSeriesRatingDto) { var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Ratings); - var userRating = await _unitOfWork.UserRepository.GetUserRating(updateSeriesRatingDto.SeriesId, user.Id) ?? + var userRating = await _unitOfWork.UserRepository.GetUserRatingAsync(updateSeriesRatingDto.SeriesId, user.Id) ?? new AppUserRating(); userRating.Rating = updateSeriesRatingDto.UserRating; @@ -187,7 +194,7 @@ namespace API.Controllers series.Name = updateSeries.Name.Trim(); series.LocalizedName = updateSeries.LocalizedName.Trim(); series.SortName = updateSeries.SortName?.Trim(); - series.Summary = updateSeries.Summary?.Trim(); + series.Metadata.Summary = updateSeries.Summary?.Trim(); var needsRefreshMetadata = false; // This is when you hit Reset @@ -230,6 +237,23 @@ namespace API.Controllers return Ok(series); } + [HttpPost("all")] + public async Task>> GetAllSeries(FilterDto filterDto, [FromQuery] UserParams userParams, [FromQuery] int libraryId = 0) + { + var userId = await _unitOfWork.UserRepository.GetUserIdByUsernameAsync(User.GetUsername()); + var series = + await _unitOfWork.SeriesRepository.GetSeriesDtoForLibraryIdAsync(libraryId, userId, userParams, filterDto); + + // Apply progress/rating information (I can't work out how to do this in initial query) + if (series == null) return BadRequest("Could not get series"); + + await _unitOfWork.SeriesRepository.AddSeriesModifiers(userId, series); + + Response.AddPaginationHeader(series.CurrentPage, series.PageSize, series.TotalCount, series.TotalPages); + + return Ok(series); + } + /// /// Fetches series that are on deck aka have progress on them. /// @@ -294,6 +318,7 @@ namespace API.Controllers else { series.Metadata.CollectionTags ??= new List(); + // TODO: Move this merging logic into a reusable code as it can be used for any Tag var newTags = new List(); // I want a union of these 2 lists. Return only elements that are in both lists, but the list types are different @@ -313,7 +338,7 @@ namespace API.Controllers var existingTag = allTags.SingleOrDefault(t => t.Title == tag.Title); if (existingTag != null) { - if (!series.Metadata.CollectionTags.Any(t => t.Title == tag.Title)) + if (series.Metadata.CollectionTags.All(t => t.Title != tag.Title)) { newTags.Add(existingTag); } @@ -392,6 +417,12 @@ namespace API.Controllers return Ok(await _unitOfWork.SeriesRepository.GetSeriesDtoForIdsAsync(dto.SeriesIds, userId)); } + [HttpGet("age-rating")] + public ActionResult GetAgeRating(int ageRating) + { + var val = (AgeRating) ageRating; + return Ok(val.ToDescription()); + } } } diff --git a/API/Controllers/ServerController.cs b/API/Controllers/ServerController.cs index 04ffa3428..45fb22ce5 100644 --- a/API/Controllers/ServerController.cs +++ b/API/Controllers/ServerController.cs @@ -5,7 +5,7 @@ using System.Threading.Tasks; using API.DTOs.Stats; using API.DTOs.Update; using API.Extensions; -using API.Interfaces.Services; +using API.Services; using API.Services.Tasks; using Kavita.Common; using Microsoft.AspNetCore.Authorization; @@ -27,10 +27,11 @@ namespace API.Controllers private readonly ICacheService _cacheService; private readonly IVersionUpdaterService _versionUpdaterService; private readonly IStatsService _statsService; + private readonly ICleanupService _cleanupService; public ServerController(IHostApplicationLifetime applicationLifetime, ILogger logger, IConfiguration config, IBackupService backupService, IArchiveService archiveService, ICacheService cacheService, - IVersionUpdaterService versionUpdaterService, IStatsService statsService) + IVersionUpdaterService versionUpdaterService, IStatsService statsService, ICleanupService cleanupService) { _applicationLifetime = applicationLifetime; _logger = logger; @@ -40,6 +41,7 @@ namespace API.Controllers _cacheService = cacheService; _versionUpdaterService = versionUpdaterService; _statsService = statsService; + _cleanupService = cleanupService; } /// @@ -63,7 +65,7 @@ namespace API.Controllers public ActionResult ClearCache() { _logger.LogInformation("{UserName} is clearing cache of server from admin dashboard", User.GetUsername()); - _cacheService.Cleanup(); + _cleanupService.CleanupCacheDirectory(); return Ok(); } @@ -94,7 +96,7 @@ namespace API.Controllers [HttpGet("logs")] public async Task GetLogs() { - var files = _backupService.LogFiles(_config.GetMaxRollingFiles(), _config.GetLoggingFileName()); + var files = _backupService.GetLogFiles(_config.GetMaxRollingFiles(), _config.GetLoggingFileName()); try { var (fileBytes, zipPath) = await _archiveService.CreateZipForDownload(files, "logs"); diff --git a/API/Controllers/SettingsController.cs b/API/Controllers/SettingsController.cs index c8b3248ba..76b30acf8 100644 --- a/API/Controllers/SettingsController.cs +++ b/API/Controllers/SettingsController.cs @@ -3,13 +3,13 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; +using API.Data; using API.DTOs.Settings; using API.Entities.Enums; using API.Extensions; using API.Helpers.Converters; -using API.Interfaces; -using API.Interfaces.Services; using API.Services; +using AutoMapper; using Kavita.Common; using Kavita.Common.Extensions; using Microsoft.AspNetCore.Authorization; @@ -24,13 +24,18 @@ namespace API.Controllers private readonly IUnitOfWork _unitOfWork; private readonly ITaskScheduler _taskScheduler; private readonly IAccountService _accountService; + private readonly IDirectoryService _directoryService; + private readonly IMapper _mapper; - public SettingsController(ILogger logger, IUnitOfWork unitOfWork, ITaskScheduler taskScheduler, IAccountService accountService) + public SettingsController(ILogger logger, IUnitOfWork unitOfWork, ITaskScheduler taskScheduler, + IAccountService accountService, IDirectoryService directoryService, IMapper mapper) { _logger = logger; _unitOfWork = unitOfWork; _taskScheduler = taskScheduler; _accountService = accountService; + _directoryService = directoryService; + _mapper = mapper; } [AllowAnonymous] @@ -46,11 +51,21 @@ namespace API.Controllers public async Task> GetSettings() { var settingsDto = await _unitOfWork.SettingsRepository.GetSettingsDtoAsync(); + // TODO: Is this needed as it gets updated in the DB on startup settingsDto.Port = Configuration.Port; settingsDto.LoggingLevel = Configuration.LogLevel; return Ok(settingsDto); } + [Authorize(Policy = "RequireAdminRole")] + [HttpPost("reset")] + public async Task> ResetSettings() + { + _logger.LogInformation("{UserName} is resetting Server Settings", User.GetUsername()); + + return await UpdateSettings(_mapper.Map(Seed.DefaultSettings)); + } + [Authorize(Policy = "RequireAdminRole")] [HttpPost] public async Task> UpdateSettings(ServerSettingDto updateSettingsDto) @@ -70,6 +85,20 @@ namespace API.Controllers // We do not allow CacheDirectory changes, so we will ignore. var currentSettings = await _unitOfWork.SettingsRepository.GetSettingsAsync(); var updateAuthentication = false; + var updateBookmarks = false; + var originalBookmarkDirectory = _directoryService.BookmarkDirectory; + + var bookmarkDirectory = updateSettingsDto.BookmarksDirectory; + if (!updateSettingsDto.BookmarksDirectory.EndsWith("bookmarks") && + !updateSettingsDto.BookmarksDirectory.EndsWith("bookmarks/")) + { + bookmarkDirectory = _directoryService.FileSystem.Path.Join(updateSettingsDto.BookmarksDirectory, "bookmarks"); + } + + if (string.IsNullOrEmpty(updateSettingsDto.BookmarksDirectory)) + { + bookmarkDirectory = _directoryService.BookmarkDirectory; + } foreach (var setting in currentSettings) { @@ -118,6 +147,22 @@ namespace API.Controllers _unitOfWork.SettingsRepository.Update(setting); } + if (setting.Key == ServerSettingKey.BookmarkDirectory && bookmarkDirectory != setting.Value) + { + // Validate new directory can be used + if (!await _directoryService.CheckWriteAccess(bookmarkDirectory)) + { + return BadRequest("Bookmark Directory does not have correct permissions for Kavita to use"); + } + + originalBookmarkDirectory = setting.Value; + // Normalize the path deliminators. Just to look nice in DB, no functionality + setting.Value = _directoryService.FileSystem.Path.GetFullPath(bookmarkDirectory); + _unitOfWork.SettingsRepository.Update(setting); + updateBookmarks = true; + + } + if (setting.Key == ServerSettingKey.EnableAuthentication && updateSettingsDto.EnableAuthentication + string.Empty != setting.Value) { setting.Value = updateSettingsDto.EnableAuthentication + string.Empty; @@ -160,6 +205,13 @@ namespace API.Controllers _logger.LogInformation("Server authentication changed. Updated all non-admins to default password"); } + + if (updateBookmarks) + { + _directoryService.ExistOrCreate(bookmarkDirectory); + _directoryService.CopyDirectoryToDirectory(originalBookmarkDirectory, bookmarkDirectory); + _directoryService.ClearAndDeleteDirectory(originalBookmarkDirectory); + } } catch (Exception ex) { @@ -170,7 +222,7 @@ namespace API.Controllers _logger.LogInformation("Server Settings updated"); - _taskScheduler.ScheduleTasks(); + await _taskScheduler.ScheduleTasks(); return Ok(updateSettingsDto); } diff --git a/API/Controllers/UploadController.cs b/API/Controllers/UploadController.cs index 43c9b8d09..b383021e2 100644 --- a/API/Controllers/UploadController.cs +++ b/API/Controllers/UploadController.cs @@ -1,8 +1,7 @@ using System; using System.Threading.Tasks; +using API.Data; using API.DTOs.Uploads; -using API.Interfaces; -using API.Interfaces.Services; using API.Services; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; diff --git a/API/Controllers/UsersController.cs b/API/Controllers/UsersController.cs index f5171b819..7662fdf95 100644 --- a/API/Controllers/UsersController.cs +++ b/API/Controllers/UsersController.cs @@ -1,10 +1,10 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using API.Data; using API.Data.Repositories; using API.DTOs; using API.Extensions; -using API.Interfaces; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; diff --git a/API/DTOs/ChapterDto.cs b/API/DTOs/ChapterDto.cs index 8c791a395..6a4effe16 100644 --- a/API/DTOs/ChapterDto.cs +++ b/API/DTOs/ChapterDto.cs @@ -1,5 +1,7 @@ using System; using System.Collections.Generic; +using API.DTOs.Metadata; +using API.Entities; namespace API.DTOs { @@ -50,5 +52,41 @@ namespace API.DTOs /// When chapter was created /// public DateTime Created { get; init; } + /// + /// When the chapter was released. + /// + /// Metadata field + public DateTime ReleaseDate { get; init; } + /// + /// Title of the Chapter/Issue + /// + /// Metadata field + public string TitleName { get; set; } + /// + /// Summary for the Chapter/Issue + /// + public string Summary { get; set; } + /// + /// Language for the Chapter/Issue + /// + public string Language { get; set; } + /// + /// Number in the TotalCount of issues + /// + public int Count { get; set; } + /// + /// Total number of issues for the series + /// + public int TotalCount { get; set; } + public ICollection Writers { get; set; } = new List(); + public ICollection Penciller { get; set; } = new List(); + public ICollection Inker { get; set; } = new List(); + public ICollection Colorist { get; set; } = new List(); + public ICollection Letterer { get; set; } = new List(); + public ICollection CoverArtist { get; set; } = new List(); + public ICollection Editor { get; set; } = new List(); + public ICollection Publisher { get; set; } = new List(); + public ICollection Translators { get; set; } = new List(); + public ICollection Tags { get; set; } = new List(); } } diff --git a/API/DTOs/Filtering/FilterDto.cs b/API/DTOs/Filtering/FilterDto.cs index c5956f17d..863e66e6e 100644 --- a/API/DTOs/Filtering/FilterDto.cs +++ b/API/DTOs/Filtering/FilterDto.cs @@ -1,13 +1,98 @@ -using API.Entities.Enums; +using System.Collections.Generic; +using API.Entities; +using API.Entities.Enums; namespace API.DTOs.Filtering { public class FilterDto { /// - /// Pass null if you want all formats + /// The type of Formats you want to be returned. An empty list will return all formats back /// - public MangaFormat? MangaFormat { get; init; } = null; + public IList Formats { get; init; } = new List(); + + /// + /// The progress you want to be returned. This can be bitwise manipulated. Defaults to all applicable states. + /// + public ReadStatus ReadStatus { get; init; } = new ReadStatus(); + + /// + /// A list of library ids to restrict search to. Defaults to all libraries by passing empty list + /// + public IList Libraries { get; init; } = new List(); + /// + /// A list of Genre ids to restrict search to. Defaults to all genres by passing an empty list + /// + public IList Genres { get; init; } = new List(); + /// + /// A list of Writers to restrict search to. Defaults to all genres by passing an empty list + /// + public IList Writers { get; init; } = new List(); + /// + /// A list of Penciller ids to restrict search to. Defaults to all genres by passing an empty list + /// + public IList Penciller { get; init; } = new List(); + /// + /// A list of Inker ids to restrict search to. Defaults to all genres by passing an empty list + /// + public IList Inker { get; init; } = new List(); + /// + /// A list of Colorist ids to restrict search to. Defaults to all genres by passing an empty list + /// + public IList Colorist { get; init; } = new List(); + /// + /// A list of Letterer ids to restrict search to. Defaults to all genres by passing an empty list + /// + public IList Letterer { get; init; } = new List(); + /// + /// A list of CoverArtist ids to restrict search to. Defaults to all genres by passing an empty list + /// + public IList CoverArtist { get; init; } = new List(); + /// + /// A list of Editor ids to restrict search to. Defaults to all genres by passing an empty list + /// + public IList Editor { get; init; } = new List(); + /// + /// A list of Publisher ids to restrict search to. Defaults to all genres by passing an empty list + /// + public IList Publisher { get; init; } = new List(); + /// + /// A list of Character ids to restrict search to. Defaults to all genres by passing an empty list + /// + public IList Character { get; init; } = new List(); + /// + /// A list of Translator ids to restrict search to. Defaults to all genres by passing an empty list + /// + public IList Translators { get; init; } = new List(); + /// + /// A list of Collection Tag ids to restrict search to. Defaults to all genres by passing an empty list + /// + public IList CollectionTags { get; init; } = new List(); + /// + /// A list of Tag ids to restrict search to. Defaults to all genres by passing an empty list + /// + public IList Tags { get; init; } = new List(); + /// + /// Will return back everything with the rating and above + /// + /// + public int Rating { get; init; } + /// + /// Sorting Options for a query. Defaults to null, which uses the queries natural sorting order + /// + public SortOptions SortOptions { get; init; } = null; + /// + /// Age Ratings. Empty list will return everything back + /// + public IList AgeRating { get; init; } = new List(); + /// + /// Languages (ISO 639-1 code) to filter by. Empty list will return everything back + /// + public IList Languages { get; init; } = new List(); + /// + /// Publication statuses to filter by. Empty list will return everything back + /// + public IList PublicationStatus { get; init; } = new List(); } } diff --git a/API/DTOs/Filtering/LanguageDto.cs b/API/DTOs/Filtering/LanguageDto.cs new file mode 100644 index 000000000..b09aed5d1 --- /dev/null +++ b/API/DTOs/Filtering/LanguageDto.cs @@ -0,0 +1,7 @@ +namespace API.DTOs.Filtering; + +public class LanguageDto +{ + public string IsoCode { get; set; } + public string Title { get; set; } +} diff --git a/API/DTOs/Filtering/ReadStatus.cs b/API/DTOs/Filtering/ReadStatus.cs new file mode 100644 index 000000000..e2452fdc1 --- /dev/null +++ b/API/DTOs/Filtering/ReadStatus.cs @@ -0,0 +1,13 @@ +using System; + +namespace API.DTOs.Filtering; + +/// +/// Represents the Reading Status. This is a flag and allows multiple statues +/// +public class ReadStatus +{ + public bool NotRead { get; set; } = true; + public bool InProgress { get; set; } = true; + public bool Read { get; set; } = true; +} diff --git a/API/DTOs/Filtering/SortField.cs b/API/DTOs/Filtering/SortField.cs new file mode 100644 index 000000000..0e465f6aa --- /dev/null +++ b/API/DTOs/Filtering/SortField.cs @@ -0,0 +1,8 @@ +namespace API.DTOs.Filtering; + +public enum SortField +{ + SortName = 1, + CreatedDate = 2, + LastModifiedDate = 3, +} diff --git a/API/DTOs/Filtering/SortOptions.cs b/API/DTOs/Filtering/SortOptions.cs new file mode 100644 index 000000000..00bf91675 --- /dev/null +++ b/API/DTOs/Filtering/SortOptions.cs @@ -0,0 +1,10 @@ +namespace API.DTOs.Filtering; + +/// +/// Sorting Options for a query +/// +public class SortOptions +{ + public SortField SortField { get; set; } + public bool IsAscending { get; set; } = true; +} diff --git a/API/DTOs/Metadata/AgeRatingDto.cs b/API/DTOs/Metadata/AgeRatingDto.cs new file mode 100644 index 000000000..cbeb44e33 --- /dev/null +++ b/API/DTOs/Metadata/AgeRatingDto.cs @@ -0,0 +1,9 @@ +using API.Entities.Enums; + +namespace API.DTOs.Metadata; + +public class AgeRatingDto +{ + public AgeRating Value { get; set; } + public string Title { get; set; } +} diff --git a/API/DTOs/Metadata/ChapterMetadataDto.cs b/API/DTOs/Metadata/ChapterMetadataDto.cs new file mode 100644 index 000000000..77b89fe94 --- /dev/null +++ b/API/DTOs/Metadata/ChapterMetadataDto.cs @@ -0,0 +1,19 @@ +using System.Collections.Generic; + +namespace API.DTOs.Metadata +{ + public class ChapterMetadataDto + { + public int Id { get; set; } + public string Title { get; set; } + public ICollection Writers { get; set; } = new List(); + public ICollection Penciller { get; set; } = new List(); + public ICollection Inker { get; set; } = new List(); + public ICollection Colorist { get; set; } = new List(); + public ICollection Letterer { get; set; } = new List(); + public ICollection CoverArtist { get; set; } = new List(); + public ICollection Editor { get; set; } = new List(); + public ICollection Publisher { get; set; } = new List(); + public int ChapterId { get; set; } + } +} diff --git a/API/DTOs/Metadata/GenreTagDto.cs b/API/DTOs/Metadata/GenreTagDto.cs new file mode 100644 index 000000000..e6ea03130 --- /dev/null +++ b/API/DTOs/Metadata/GenreTagDto.cs @@ -0,0 +1,8 @@ +namespace API.DTOs.Metadata +{ + public class GenreTagDto + { + public int Id { get; set; } + public string Title { get; set; } + } +} diff --git a/API/DTOs/Metadata/PublicationStatusDto.cs b/API/DTOs/Metadata/PublicationStatusDto.cs new file mode 100644 index 000000000..332223428 --- /dev/null +++ b/API/DTOs/Metadata/PublicationStatusDto.cs @@ -0,0 +1,9 @@ +using API.Entities.Enums; + +namespace API.DTOs.Metadata; + +public class PublicationStatusDto +{ + public PublicationStatus Value { get; set; } + public string Title { get; set; } +} diff --git a/API/DTOs/Metadata/TagDto.cs b/API/DTOs/Metadata/TagDto.cs new file mode 100644 index 000000000..6e9b2f71e --- /dev/null +++ b/API/DTOs/Metadata/TagDto.cs @@ -0,0 +1,7 @@ +namespace API.DTOs.Metadata; + +public class TagDto +{ + public int Id { get; set; } + public string Title { get; set; } +} diff --git a/API/DTOs/OPDS/Feed.cs b/API/DTOs/OPDS/Feed.cs index 95f08448e..efbffe8ac 100644 --- a/API/DTOs/OPDS/Feed.cs +++ b/API/DTOs/OPDS/Feed.cs @@ -23,7 +23,7 @@ namespace API.DTOs.OPDS public string Icon { get; set; } = "/favicon.ico"; [XmlElement("author")] - public Author Author { get; set; } = new Author() + public FeedAuthor Author { get; set; } = new FeedAuthor() { Name = "Kavita", Uri = "https://kavitareader.com" diff --git a/API/DTOs/OPDS/Author.cs b/API/DTOs/OPDS/FeedAuthor.cs similarity index 88% rename from API/DTOs/OPDS/Author.cs rename to API/DTOs/OPDS/FeedAuthor.cs index 1758a037e..ec0446d73 100644 --- a/API/DTOs/OPDS/Author.cs +++ b/API/DTOs/OPDS/FeedAuthor.cs @@ -2,7 +2,7 @@ namespace API.DTOs.OPDS { - public class Author + public class FeedAuthor { [XmlElement("name")] public string Name { get; set; } diff --git a/API/DTOs/PersonDto.cs b/API/DTOs/PersonDto.cs index 646817c1d..0ab7a4076 100644 --- a/API/DTOs/PersonDto.cs +++ b/API/DTOs/PersonDto.cs @@ -4,7 +4,8 @@ namespace API.DTOs { public class PersonDto { + public int Id { get; set; } public string Name { get; set; } public PersonRole Role { get; set; } } -} \ No newline at end of file +} diff --git a/API/DTOs/Reader/BookInfoDto.cs b/API/DTOs/Reader/BookInfoDto.cs index 6705c9647..b881c1b10 100644 --- a/API/DTOs/Reader/BookInfoDto.cs +++ b/API/DTOs/Reader/BookInfoDto.cs @@ -14,5 +14,6 @@ namespace API.DTOs.Reader public int LibraryId { get; set; } public int Pages { get; set; } public bool IsSpecial { get; set; } + public string ChapterTitle { get; set; } } } diff --git a/API/DTOs/Reader/ChapterInfoDto.cs b/API/DTOs/Reader/ChapterInfoDto.cs index ec512670d..e29f3798c 100644 --- a/API/DTOs/Reader/ChapterInfoDto.cs +++ b/API/DTOs/Reader/ChapterInfoDto.cs @@ -1,4 +1,5 @@ -using API.Entities.Enums; +using System; +using API.Entities.Enums; namespace API.DTOs.Reader { @@ -12,7 +13,7 @@ namespace API.DTOs.Reader public MangaFormat SeriesFormat { get; set; } public int SeriesId { get; set; } public int LibraryId { get; set; } - public string ChapterTitle { get; set; } = ""; + public string ChapterTitle { get; set; } = string.Empty; public int Pages { get; set; } public string FileName { get; set; } public bool IsSpecial { get; set; } diff --git a/API/DTOs/Reader/IChapterInfoDto.cs b/API/DTOs/Reader/IChapterInfoDto.cs index 67aa6caf6..e448e5e13 100644 --- a/API/DTOs/Reader/IChapterInfoDto.cs +++ b/API/DTOs/Reader/IChapterInfoDto.cs @@ -13,6 +13,7 @@ namespace API.DTOs.Reader public int LibraryId { get; set; } public int Pages { get; set; } public bool IsSpecial { get; set; } + public string ChapterTitle { get; set; } } } diff --git a/API/DTOs/SeriesMetadataDto.cs b/API/DTOs/SeriesMetadataDto.cs index 69dcae2d9..fbee305ac 100644 --- a/API/DTOs/SeriesMetadataDto.cs +++ b/API/DTOs/SeriesMetadataDto.cs @@ -1,16 +1,61 @@ using System.Collections.Generic; using API.DTOs.CollectionTags; -using API.Entities; +using API.DTOs.Metadata; +using API.Entities.Enums; namespace API.DTOs { public class SeriesMetadataDto { public int Id { get; set; } - public ICollection Genres { get; set; } - public ICollection Tags { get; set; } - public ICollection Persons { get; set; } - public string Publisher { get; set; } + public string Summary { get; set; } + /// + /// Collections the Series belongs to + /// + public ICollection CollectionTags { get; set; } + /// + /// Genres for the Series + /// + public ICollection Genres { get; set; } + /// + /// Collection of all Tags from underlying chapters for a Series + /// + public ICollection Tags { get; set; } + public ICollection Writers { get; set; } = new List(); + public ICollection CoverArtists { get; set; } = new List(); + public ICollection Publishers { get; set; } = new List(); + public ICollection Characters { get; set; } = new List(); + public ICollection Pencillers { get; set; } = new List(); + public ICollection Inkers { get; set; } = new List(); + public ICollection Colorists { get; set; } = new List(); + public ICollection Letterers { get; set; } = new List(); + public ICollection Editors { get; set; } = new List(); + public ICollection Translators { get; set; } = new List(); + /// + /// Highest Age Rating from all Chapters + /// + public AgeRating AgeRating { get; set; } = AgeRating.Unknown; + /// + /// Earliest Year from all chapters + /// + public int ReleaseYear { get; set; } + /// + /// Language of the content (BCP-47 code) + /// + public string Language { get; set; } = string.Empty; + /// + /// Number in the TotalCount of issues + /// + public int Count { get; set; } + /// + /// Total number of issues for the series + /// + public int TotalCount { get; set; } + /// + /// Publication status of the Series + /// + public PublicationStatus PublicationStatus { get; set; } + public int SeriesId { get; set; } } -} \ No newline at end of file +} diff --git a/API/DTOs/Settings/ServerSettingDTO.cs b/API/DTOs/Settings/ServerSettingDTO.cs index aace57127..4004c65b1 100644 --- a/API/DTOs/Settings/ServerSettingDTO.cs +++ b/API/DTOs/Settings/ServerSettingDTO.cs @@ -1,4 +1,6 @@ -namespace API.DTOs.Settings +using API.Services; + +namespace API.DTOs.Settings { public class ServerSettingDto { @@ -30,5 +32,10 @@ /// Base Url for the kavita. Requires restart to take effect. /// public string BaseUrl { get; set; } + /// + /// Where Bookmarks are stored. + /// + /// If null or empty string, will default back to default install setting aka + public string BookmarksDirectory { get; set; } } } diff --git a/API/DTOs/Update/UpdateNotificationDto.cs b/API/DTOs/Update/UpdateNotificationDto.cs index 03c56c567..66c979cc4 100644 --- a/API/DTOs/Update/UpdateNotificationDto.cs +++ b/API/DTOs/Update/UpdateNotificationDto.cs @@ -1,6 +1,4 @@ -using System; - -namespace API.DTOs.Update +namespace API.DTOs.Update { /// /// Update Notification denoting a new release available for user to update to diff --git a/API/DTOs/UserPreferencesDto.cs b/API/DTOs/UserPreferencesDto.cs index 03dbeaa5e..c36c9d146 100644 --- a/API/DTOs/UserPreferencesDto.cs +++ b/API/DTOs/UserPreferencesDto.cs @@ -18,4 +18,4 @@ namespace API.DTOs public ReadingDirection BookReaderReadingDirection { get; set; } public bool SiteDarkMode { get; set; } } -} \ No newline at end of file +} diff --git a/API/Data/DataContext.cs b/API/Data/DataContext.cs index 8e4dc263e..c1e100d48 100644 --- a/API/Data/DataContext.cs +++ b/API/Data/DataContext.cs @@ -4,6 +4,7 @@ using System.Threading; using System.Threading.Tasks; using API.Entities; using API.Entities.Interfaces; +using API.Entities.Metadata; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity.EntityFrameworkCore; using Microsoft.EntityFrameworkCore; @@ -23,7 +24,6 @@ namespace API.Data public DbSet Library { get; set; } public DbSet Series { get; set; } - public DbSet Chapter { get; set; } public DbSet Volume { get; set; } public DbSet AppUser { get; set; } @@ -37,6 +37,9 @@ namespace API.Data public DbSet AppUserBookmark { get; set; } public DbSet ReadingList { get; set; } public DbSet ReadingListItem { get; set; } + public DbSet Person { get; set; } + public DbSet Genre { get; set; } + public DbSet Tag { get; set; } protected override void OnModelCreating(ModelBuilder builder) diff --git a/API/Data/DbFactory.cs b/API/Data/DbFactory.cs index a57ba4037..d5b3434f7 100644 --- a/API/Data/DbFactory.cs +++ b/API/Data/DbFactory.cs @@ -1,7 +1,11 @@ using System; using System.Collections.Generic; +using System.IO; +using API.Data.Metadata; using API.Entities; using API.Entities.Enums; +using API.Entities.Metadata; +using API.Extensions; using API.Parser; using API.Services.Tasks; @@ -21,12 +25,16 @@ namespace API.Data LocalizedName = name, NormalizedName = Parser.Parser.Normalize(name), SortName = name, - Summary = string.Empty, Volumes = new List(), Metadata = SeriesMetadata(Array.Empty()) }; } + public static SeriesMetadata SeriesMetadata(ComicInfo info) + { + return SeriesMetadata(Array.Empty()); + } + public static Volume Volume(string volumeNumber) { return new Volume() @@ -57,7 +65,8 @@ namespace API.Data { return new SeriesMetadata() { - CollectionTags = collectionTags + CollectionTags = collectionTags, + Summary = string.Empty }; } @@ -72,5 +81,47 @@ namespace API.Data Promoted = promoted }; } + + public static Genre Genre(string name, bool external) + { + return new Genre() + { + Title = name.Trim().SentenceCase(), + NormalizedTitle = Parser.Parser.Normalize(name), + ExternalTag = external + }; + } + + public static Tag Tag(string name, bool external) + { + return new Tag() + { + Title = name.Trim().SentenceCase(), + NormalizedTitle = Parser.Parser.Normalize(name), + ExternalTag = external + }; + } + + public static Person Person(string name, PersonRole role) + { + return new Person() + { + Name = name.Trim(), + NormalizedName = Parser.Parser.Normalize(name), + Role = role + }; + } + + public static MangaFile MangaFile(string filePath, MangaFormat format, int pages) + { + return new MangaFile() + { + FilePath = filePath, + Format = format, + Pages = pages, + LastModified = File.GetLastWriteTime(filePath) // NOTE: Changed this from DateTime.Now + }; + } + } } diff --git a/API/Data/Metadata/ComicInfo.cs b/API/Data/Metadata/ComicInfo.cs index 9f846ea42..cc7154f93 100644 --- a/API/Data/Metadata/ComicInfo.cs +++ b/API/Data/Metadata/ComicInfo.cs @@ -1,51 +1,121 @@ -namespace API.Data.Metadata +using System; +using System.Linq; +using API.Entities.Enums; +using Kavita.Common.Extensions; + +namespace API.Data.Metadata { /// /// A representation of a ComicInfo.xml file /// - /// See reference of the loose spec here: https://github.com/Kussie/ComicInfoStandard/blob/main/ComicInfo.xsd + /// See reference of the loose spec here: https://anansi-project.github.io/docs/comicinfo/documentation public class ComicInfo { - public string Summary { get; set; } - public string Title { get; set; } - public string Series { get; set; } - public string Number { get; set; } - public string Volume { get; set; } - public string Notes { get; set; } - public string Genre { get; set; } + public string Summary { get; set; } = string.Empty; + public string Title { get; set; } = string.Empty; + public string Series { get; set; } = string.Empty; + public string Number { get; set; } = string.Empty; + /// + /// The total number of items in the series. + /// + public int Count { get; set; } = 0; + public string Volume { get; set; } = string.Empty; + public string Notes { get; set; } = string.Empty; + public string Genre { get; set; } = string.Empty; public int PageCount { get; set; } // ReSharper disable once InconsistentNaming - public string LanguageISO { get; set; } - public string Web { get; set; } - public int Month { get; set; } - public int Year { get; set; } /// - /// Rating based on the content. Think PG-13, R for movies + /// ISO 639-1 Code to represent the language of the content /// - public string AgeRating { get; set; } + public string LanguageISO { get; set; } = string.Empty; + /// + /// This is the link to where the data was scraped from + /// + public string Web { get; set; } = string.Empty; + public int Day { get; set; } = 0; + public int Month { get; set; } = 0; + public int Year { get; set; } = 0; + + + /// + /// Rating based on the content. Think PG-13, R for movies. See for valid types + /// + public string AgeRating { get; set; } = string.Empty; /// /// User's rating of the content /// public float UserRating { get; set; } - public string AlternateSeries { get; set; } - public string StoryArc { get; set; } - public string SeriesGroup { get; set; } - public string AlternativeSeries { get; set; } - public string AlternativeNumber { get; set; } + public string AlternateSeries { get; set; } = string.Empty; + public string StoryArc { get; set; } = string.Empty; + public string SeriesGroup { get; set; } = string.Empty; + public string AlternativeSeries { get; set; } = string.Empty; + public string AlternativeNumber { get; set; } = string.Empty; + /// + /// This is Epub only: calibre:title_sort + /// Represents the sort order for the title + /// + public string TitleSort { get; set; } = string.Empty; + + /// + /// The translator, can be comma separated. This is part of ComicInfo.xml draft v2.1 + /// + /// See https://github.com/anansi-project/comicinfo/issues/2 for information about this tag + public string Translator { get; set; } = string.Empty; + /// + /// Misc tags. This is part of ComicInfo.xml draft v2.1 + /// + /// See https://github.com/anansi-project/comicinfo/issues/1 for information about this tag + public string Tags { get; set; } = string.Empty; /// /// This is the Author. For Books, we map creator tag in OPF to this field. Comma separated if multiple. /// - public string Writer { get; set; } // TODO: Validate if we should make this a list of writers - public string Penciller { get; set; } - public string Inker { get; set; } - public string Colorist { get; set; } - public string Letterer { get; set; } - public string CoverArtist { get; set; } - public string Editor { get; set; } - public string Publisher { get; set; } + public string Writer { get; set; } = string.Empty; + public string Penciller { get; set; } = string.Empty; + public string Inker { get; set; } = string.Empty; + public string Colorist { get; set; } = string.Empty; + public string Letterer { get; set; } = string.Empty; + public string CoverArtist { get; set; } = string.Empty; + public string Editor { get; set; } = string.Empty; + public string Publisher { get; set; } = string.Empty; + public string Characters { get; set; } = string.Empty; + + public static AgeRating ConvertAgeRatingToEnum(string value) + { + if (string.IsNullOrEmpty(value)) return Entities.Enums.AgeRating.Unknown; + return Enum.GetValues() + .SingleOrDefault(t => t.ToDescription().ToUpperInvariant().Equals(value.ToUpperInvariant()), Entities.Enums.AgeRating.Unknown); + } + + public static void CleanComicInfo(ComicInfo info) + { + if (info == null) return; + + info.Writer = Parser.Parser.CleanAuthor(info.Writer); + info.Colorist = Parser.Parser.CleanAuthor(info.Colorist); + info.Editor = Parser.Parser.CleanAuthor(info.Editor); + info.Inker = Parser.Parser.CleanAuthor(info.Inker); + info.Letterer = Parser.Parser.CleanAuthor(info.Letterer); + info.Penciller = Parser.Parser.CleanAuthor(info.Penciller); + info.Publisher = Parser.Parser.CleanAuthor(info.Publisher); + info.Characters = Parser.Parser.CleanAuthor(info.Characters); + info.Translator = Parser.Parser.CleanAuthor(info.Translator); + info.CoverArtist = Parser.Parser.CleanAuthor(info.CoverArtist); + + + // if (!string.IsNullOrEmpty(info.Web)) + // { + // // ComicVine stores the Issue number in Number field and does not use Volume. + // if (!info.Web.Contains("https://comicvine.gamespot.com/")) return; + // if (info.Volume.Equals("1")) + // { + // info.Volume = Parser.Parser.DefaultVolume; + // } + // } + } + } } diff --git a/API/Data/MigrateBookmarks.cs b/API/Data/MigrateBookmarks.cs new file mode 100644 index 000000000..043b3e0a4 --- /dev/null +++ b/API/Data/MigrateBookmarks.cs @@ -0,0 +1,102 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using API.Comparators; +using API.Entities.Enums; +using API.Services; +using Microsoft.Extensions.Logging; + +namespace API.Data; + +/// +/// Responsible to migrate existing bookmarks to files +/// +public static class MigrateBookmarks +{ + private static readonly Version VersionBookmarksChanged = new Version(0, 4, 9, 27); + /// + /// This will migrate existing bookmarks to bookmark folder based + /// + /// Bookmark directory is configurable. This will always use the default bookmark directory. + /// + /// + public static async Task Migrate(IDirectoryService directoryService, IUnitOfWork unitOfWork, + ILogger logger, ICacheService cacheService) + { + var bookmarkDirectory = (await unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.BookmarkDirectory)) + .Value; + if (string.IsNullOrEmpty(bookmarkDirectory)) + { + bookmarkDirectory = directoryService.BookmarkDirectory; + } + + if (directoryService.Exists(bookmarkDirectory)) return; + + logger.LogInformation("Bookmark migration is needed....This may take some time"); + + var allBookmarks = (await unitOfWork.UserRepository.GetAllBookmarksAsync()).ToList(); + + var uniqueChapterIds = allBookmarks.Select(b => b.ChapterId).Distinct().ToList(); + var uniqueUserIds = allBookmarks.Select(b => b.AppUserId).Distinct().ToList(); + foreach (var userId in uniqueUserIds) + { + foreach (var chapterId in uniqueChapterIds) + { + var chapterBookmarks = allBookmarks.Where(b => b.ChapterId == chapterId).ToList(); + var chapterPages = chapterBookmarks + .Select(b => b.Page).ToList(); + var seriesId = chapterBookmarks + .Select(b => b.SeriesId).First(); + var mangaFiles = await unitOfWork.ChapterRepository.GetFilesForChapterAsync(chapterId); + var chapterExtractPath = directoryService.FileSystem.Path.Join(directoryService.TempDirectory, $"bookmark_c{chapterId}_u{userId}_s{seriesId}"); + + var numericComparer = new NumericComparer(); + if (!mangaFiles.Any()) continue; + + switch (mangaFiles.First().Format) + { + case MangaFormat.Image: + directoryService.ExistOrCreate(chapterExtractPath); + directoryService.CopyFilesToDirectory(mangaFiles.Select(f => f.FilePath), chapterExtractPath); + break; + case MangaFormat.Archive: + case MangaFormat.Pdf: + cacheService.ExtractChapterFiles(chapterExtractPath, mangaFiles.ToList()); + break; + case MangaFormat.Epub: + continue; + default: + continue; + } + + var files = directoryService.GetFilesWithExtension(chapterExtractPath, Parser.Parser.ImageFileExtensions); + // Filter out images that aren't in bookmarks + Array.Sort(files, numericComparer); + foreach (var chapterPage in chapterPages) + { + var file = files.ElementAt(chapterPage); + var bookmark = allBookmarks.FirstOrDefault(b => + b.ChapterId == chapterId && b.SeriesId == seriesId && b.AppUserId == userId && + b.Page == chapterPage); + if (bookmark == null) continue; + + var filename = directoryService.FileSystem.Path.GetFileName(file); + var newLocation = directoryService.FileSystem.Path.Join( + ReaderService.FormatBookmarkFolderPath(String.Empty, userId, seriesId, chapterId), + filename); + bookmark.FileName = newLocation; + directoryService.CopyFileToDirectory(file, + ReaderService.FormatBookmarkFolderPath(bookmarkDirectory, userId, seriesId, chapterId)); + unitOfWork.UserRepository.Update(bookmark); + } + } + // Clear temp after each user to avoid too much space being eaten + directoryService.ClearDirectory(directoryService.TempDirectory); + } + + await unitOfWork.CommitAsync(); + // Run CleanupService as we cache a ton of files + directoryService.ClearDirectory(directoryService.TempDirectory); + + } +} diff --git a/API/Data/MigrateConfigFiles.cs b/API/Data/MigrateConfigFiles.cs index 752b03192..51ee37167 100644 --- a/API/Data/MigrateConfigFiles.cs +++ b/API/Data/MigrateConfigFiles.cs @@ -1,12 +1,16 @@ using System; using System.Collections.Generic; using System.IO; +using System.IO.Abstractions; using System.Linq; using API.Services; using Kavita.Common; namespace API.Data { + /// + /// A Migration to migrate config related files to the config/ directory for installs prior to v0.4.9. + /// public static class MigrateConfigFiles { private static readonly List LooseLeafFiles = new List() @@ -31,7 +35,7 @@ namespace API.Data /// In v0.4.8 we moved all config files to config/ to match with how docker was setup. This will move all config files from current directory /// to config/ /// - public static void Migrate(bool isDocker) + public static void Migrate(bool isDocker, IDirectoryService directoryService) { Console.WriteLine("Checking if migration to config/ is needed"); @@ -46,8 +50,8 @@ namespace API.Data Console.WriteLine( "Migrating files from pre-v0.4.8. All Kavita config files are now located in config/"); - CopyAppFolders(); - DeleteAppFolders(); + CopyAppFolders(directoryService); + DeleteAppFolders(directoryService); UpdateConfiguration(); @@ -64,14 +68,14 @@ namespace API.Data Console.WriteLine( "Migrating files from pre-v0.4.8. All Kavita config files are now located in config/"); - Console.WriteLine($"Creating {DirectoryService.ConfigDirectory}"); - DirectoryService.ExistOrCreate(DirectoryService.ConfigDirectory); + Console.WriteLine($"Creating {directoryService.ConfigDirectory}"); + directoryService.ExistOrCreate(directoryService.ConfigDirectory); try { - CopyLooseLeafFiles(); + CopyLooseLeafFiles(directoryService); - CopyAppFolders(); + CopyAppFolders(directoryService); // Then we need to update the config file to point to the new DB file UpdateConfiguration(); @@ -84,43 +88,43 @@ namespace API.Data // Finally delete everything in the source directory Console.WriteLine("Removing old files"); - DeleteLooseFiles(); - DeleteAppFolders(); + DeleteLooseFiles(directoryService); + DeleteAppFolders(directoryService); Console.WriteLine("Removing old files...DONE"); Console.WriteLine("Migration complete. All config files are now in config/ directory"); } - private static void DeleteAppFolders() + private static void DeleteAppFolders(IDirectoryService directoryService) { foreach (var folderToDelete in AppFolders) { if (!new DirectoryInfo(Path.Join(Directory.GetCurrentDirectory(), folderToDelete)).Exists) continue; - DirectoryService.ClearAndDeleteDirectory(Path.Join(Directory.GetCurrentDirectory(), folderToDelete)); + directoryService.ClearAndDeleteDirectory(Path.Join(Directory.GetCurrentDirectory(), folderToDelete)); } } - private static void DeleteLooseFiles() + private static void DeleteLooseFiles(IDirectoryService directoryService) { var configFiles = LooseLeafFiles.Select(file => new FileInfo(Path.Join(Directory.GetCurrentDirectory(), file))) .Where(f => f.Exists); - DirectoryService.DeleteFiles(configFiles.Select(f => f.FullName)); + directoryService.DeleteFiles(configFiles.Select(f => f.FullName)); } - private static void CopyAppFolders() + private static void CopyAppFolders(IDirectoryService directoryService) { Console.WriteLine("Moving folders to config"); foreach (var folderToMove in AppFolders) { - if (new DirectoryInfo(Path.Join(DirectoryService.ConfigDirectory, folderToMove)).Exists) continue; + if (new DirectoryInfo(Path.Join(directoryService.ConfigDirectory, folderToMove)).Exists) continue; try { - DirectoryService.CopyDirectoryToDirectory( - Path.Join(Directory.GetCurrentDirectory(), folderToMove), - Path.Join(DirectoryService.ConfigDirectory, folderToMove)); + directoryService.CopyDirectoryToDirectory( + Path.Join(directoryService.FileSystem.Directory.GetCurrentDirectory(), folderToMove), + Path.Join(directoryService.ConfigDirectory, folderToMove)); } catch (Exception) { @@ -132,9 +136,9 @@ namespace API.Data Console.WriteLine("Moving folders to config...DONE"); } - private static void CopyLooseLeafFiles() + private static void CopyLooseLeafFiles(IDirectoryService directoryService) { - var configFiles = LooseLeafFiles.Select(file => new FileInfo(Path.Join(Directory.GetCurrentDirectory(), file))) + var configFiles = LooseLeafFiles.Select(file => new FileInfo(Path.Join(directoryService.FileSystem.Directory.GetCurrentDirectory(), file))) .Where(f => f.Exists); // First step is to move all the files Console.WriteLine("Moving files to config/"); @@ -142,7 +146,7 @@ namespace API.Data { try { - fileInfo.CopyTo(Path.Join(DirectoryService.ConfigDirectory, fileInfo.Name)); + fileInfo.CopyTo(Path.Join(directoryService.ConfigDirectory, fileInfo.Name)); } catch (Exception) { diff --git a/API/Data/MigrateCoverImages.cs b/API/Data/MigrateCoverImages.cs index 87e65cb81..b5839509a 100644 --- a/API/Data/MigrateCoverImages.cs +++ b/API/Data/MigrateCoverImages.cs @@ -29,10 +29,10 @@ namespace API.Data /// /// Run first. Will extract byte[]s from DB and write them to the cover directory. /// - public static void ExtractToImages(DbContext context) + public static void ExtractToImages(DbContext context, IDirectoryService directoryService, IImageService imageService) { Console.WriteLine("Migrating Cover Images to disk. Expect delay."); - DirectoryService.ExistOrCreate(DirectoryService.CoverImageDirectory); + directoryService.ExistOrCreate(directoryService.CoverImageDirectory); Console.WriteLine("Extracting cover images for Series"); var lockedSeries = SqlHelper.RawSqlQuery(context, "Select Id, CoverImage From Series Where CoverImage IS NOT NULL", x => @@ -45,14 +45,14 @@ namespace API.Data foreach (var series in lockedSeries) { if (series.CoverImage == null || !series.CoverImage.Any()) continue; - if (File.Exists(Path.Join(DirectoryService.CoverImageDirectory, + if (File.Exists(directoryService.FileSystem.Path.Join(directoryService.CoverImageDirectory, $"{ImageService.GetSeriesFormat(int.Parse(series.Id))}.png"))) continue; try { var stream = new MemoryStream(series.CoverImage); stream.Position = 0; - ImageService.WriteCoverThumbnail(stream, ImageService.GetSeriesFormat(int.Parse(series.Id))); + imageService.WriteCoverThumbnail(stream, ImageService.GetSeriesFormat(int.Parse(series.Id)), directoryService.CoverImageDirectory); } catch (Exception e) { @@ -71,14 +71,14 @@ namespace API.Data foreach (var chapter in chapters) { if (chapter.CoverImage == null || !chapter.CoverImage.Any()) continue; - if (File.Exists(Path.Join(DirectoryService.CoverImageDirectory, + if (directoryService.FileSystem.File.Exists(directoryService.FileSystem.Path.Join(directoryService.CoverImageDirectory, $"{ImageService.GetChapterFormat(int.Parse(chapter.Id), int.Parse(chapter.ParentId))}.png"))) continue; try { var stream = new MemoryStream(chapter.CoverImage); stream.Position = 0; - ImageService.WriteCoverThumbnail(stream, $"{ImageService.GetChapterFormat(int.Parse(chapter.Id), int.Parse(chapter.ParentId))}"); + imageService.WriteCoverThumbnail(stream, $"{ImageService.GetChapterFormat(int.Parse(chapter.Id), int.Parse(chapter.ParentId))}", directoryService.CoverImageDirectory); } catch (Exception e) { @@ -97,13 +97,13 @@ namespace API.Data foreach (var tag in tags) { if (tag.CoverImage == null || !tag.CoverImage.Any()) continue; - if (File.Exists(Path.Join(DirectoryService.CoverImageDirectory, + if (directoryService.FileSystem.File.Exists(Path.Join(directoryService.CoverImageDirectory, $"{ImageService.GetCollectionTagFormat(int.Parse(tag.Id))}.png"))) continue; try { var stream = new MemoryStream(tag.CoverImage); stream.Position = 0; - ImageService.WriteCoverThumbnail(stream, $"{ImageService.GetCollectionTagFormat(int.Parse(tag.Id))}"); + imageService.WriteCoverThumbnail(stream, $"{ImageService.GetCollectionTagFormat(int.Parse(tag.Id))}", directoryService.CoverImageDirectory); } catch (Exception e) { @@ -116,13 +116,13 @@ namespace API.Data /// Run after . Will update the DB with names of files that were extracted. /// /// - public static async Task UpdateDatabaseWithImages(DataContext context) + public static async Task UpdateDatabaseWithImages(DataContext context, IDirectoryService directoryService) { Console.WriteLine("Updating Series entities"); var seriesCovers = await context.Series.Where(s => !string.IsNullOrEmpty(s.CoverImage)).ToListAsync(); foreach (var series in seriesCovers) { - if (!File.Exists(Path.Join(DirectoryService.CoverImageDirectory, + if (!directoryService.FileSystem.File.Exists(directoryService.FileSystem.Path.Join(directoryService.CoverImageDirectory, $"{ImageService.GetSeriesFormat(series.Id)}.png"))) continue; series.CoverImage = $"{ImageService.GetSeriesFormat(series.Id)}.png"; } @@ -131,9 +131,10 @@ namespace API.Data Console.WriteLine("Updating Chapter entities"); var chapters = await context.Chapter.ToListAsync(); + // ReSharper disable once ForeachCanBePartlyConvertedToQueryUsingAnotherGetEnumerator foreach (var chapter in chapters) { - if (File.Exists(Path.Join(DirectoryService.CoverImageDirectory, + if (directoryService.FileSystem.File.Exists(directoryService.FileSystem.Path.Join(directoryService.CoverImageDirectory, $"{ImageService.GetChapterFormat(chapter.Id, chapter.VolumeId)}.png"))) { chapter.CoverImage = $"{ImageService.GetChapterFormat(chapter.Id, chapter.VolumeId)}.png"; @@ -149,7 +150,7 @@ namespace API.Data { var firstChapter = volume.Chapters.OrderBy(x => double.Parse(x.Number), ChapterSortComparerForInChapterSorting).FirstOrDefault(); if (firstChapter == null) continue; - if (File.Exists(Path.Join(DirectoryService.CoverImageDirectory, + if (directoryService.FileSystem.File.Exists(directoryService.FileSystem.Path.Join(directoryService.CoverImageDirectory, $"{ImageService.GetChapterFormat(firstChapter.Id, firstChapter.VolumeId)}.png"))) { volume.CoverImage = $"{ImageService.GetChapterFormat(firstChapter.Id, firstChapter.VolumeId)}.png"; @@ -161,9 +162,10 @@ namespace API.Data Console.WriteLine("Updating Collection Tag entities"); var tags = await context.CollectionTag.ToListAsync(); + // ReSharper disable once ForeachCanBePartlyConvertedToQueryUsingAnotherGetEnumerator foreach (var tag in tags) { - if (File.Exists(Path.Join(DirectoryService.CoverImageDirectory, + if (directoryService.FileSystem.File.Exists(directoryService.FileSystem.Path.Join(directoryService.CoverImageDirectory, $"{ImageService.GetCollectionTagFormat(tag.Id)}.png"))) { tag.CoverImage = $"{ImageService.GetCollectionTagFormat(tag.Id)}.png"; diff --git a/API/Data/Migrations/20211127200244_MetadataFoundation.Designer.cs b/API/Data/Migrations/20211127200244_MetadataFoundation.Designer.cs new file mode 100644 index 000000000..32408164b --- /dev/null +++ b/API/Data/Migrations/20211127200244_MetadataFoundation.Designer.cs @@ -0,0 +1,1215 @@ +// +using System; +using API.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace API.Data.Migrations +{ + [DbContext(typeof(DataContext))] + [Migration("20211127200244_MetadataFoundation")] + partial class MetadataFoundation + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "6.0.0"); + + modelBuilder.Entity("API.Entities.AppRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("API.Entities.AppUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessFailedCount") + .HasColumnType("INTEGER"); + + b.Property("ApiKey") + .HasColumnType("TEXT"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("EmailConfirmed") + .HasColumnType("INTEGER"); + + b.Property("LastActive") + .HasColumnType("TEXT"); + + b.Property("LockoutEnabled") + .HasColumnType("INTEGER"); + + b.Property("LockoutEnd") + .HasColumnType("TEXT"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("PasswordHash") + .HasColumnType("TEXT"); + + b.Property("PhoneNumber") + .HasColumnType("TEXT"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SecurityStamp") + .HasColumnType("TEXT"); + + b.Property("TwoFactorEnabled") + .HasColumnType("INTEGER"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("API.Entities.AppUserBookmark", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("Page") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("AppUserBookmark"); + }); + + modelBuilder.Entity("API.Entities.AppUserPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("AutoCloseMenu") + .HasColumnType("INTEGER"); + + b.Property("BookReaderDarkMode") + .HasColumnType("INTEGER"); + + b.Property("BookReaderFontFamily") + .HasColumnType("TEXT"); + + b.Property("BookReaderFontSize") + .HasColumnType("INTEGER"); + + b.Property("BookReaderLineSpacing") + .HasColumnType("INTEGER"); + + b.Property("BookReaderMargin") + .HasColumnType("INTEGER"); + + b.Property("BookReaderReadingDirection") + .HasColumnType("INTEGER"); + + b.Property("BookReaderTapToPaginate") + .HasColumnType("INTEGER"); + + b.Property("PageSplitOption") + .HasColumnType("INTEGER"); + + b.Property("ReaderMode") + .HasColumnType("INTEGER"); + + b.Property("ReadingDirection") + .HasColumnType("INTEGER"); + + b.Property("ScalingOption") + .HasColumnType("INTEGER"); + + b.Property("SiteDarkMode") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId") + .IsUnique(); + + b.ToTable("AppUserPreferences"); + }); + + modelBuilder.Entity("API.Entities.AppUserProgress", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("BookScrollId") + .HasColumnType("TEXT"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("PagesRead") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("AppUserProgresses"); + }); + + modelBuilder.Entity("API.Entities.AppUserRating", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("Rating") + .HasColumnType("INTEGER"); + + b.Property("Review") + .HasColumnType("TEXT"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("AppUserRating"); + }); + + modelBuilder.Entity("API.Entities.AppUserRole", b => + { + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("IsSpecial") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Number") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("Range") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("VolumeId"); + + b.ToTable("Chapter"); + }); + + modelBuilder.Entity("API.Entities.ChapterMetadata", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("StoryArc") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.Property("Year") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ChapterId") + .IsUnique(); + + b.ToTable("ChapterMetadata"); + }); + + modelBuilder.Entity("API.Entities.CollectionTag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("NormalizedTitle") + .HasColumnType("TEXT"); + + b.Property("Promoted") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Id", "Promoted") + .IsUnique(); + + b.ToTable("CollectionTag"); + }); + + modelBuilder.Entity("API.Entities.FolderPath", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("LastScanned") + .HasColumnType("TEXT"); + + b.Property("LibraryId") + .HasColumnType("INTEGER"); + + b.Property("Path") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("LibraryId"); + + b.ToTable("FolderPath"); + }); + + modelBuilder.Entity("API.Entities.Genre", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique(); + + b.ToTable("Genre"); + }); + + modelBuilder.Entity("API.Entities.Library", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("LastScanned") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Library"); + }); + + modelBuilder.Entity("API.Entities.MangaFile", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("FilePath") + .HasColumnType("TEXT"); + + b.Property("Format") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ChapterId"); + + b.ToTable("MangaFile"); + }); + + modelBuilder.Entity("API.Entities.Person", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasColumnType("TEXT"); + + b.Property("Role") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Person"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Promoted") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("ReadingList"); + }); + + modelBuilder.Entity("API.Entities.ReadingListItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("Order") + .HasColumnType("INTEGER"); + + b.Property("ReadingListId") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ChapterId"); + + b.HasIndex("ReadingListId"); + + b.HasIndex("SeriesId"); + + b.HasIndex("VolumeId"); + + b.ToTable("ReadingListItem"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("Format") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("LibraryId") + .HasColumnType("INTEGER"); + + b.Property("LocalizedName") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasColumnType("TEXT"); + + b.Property("OriginalName") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("SortName") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("LibraryId"); + + b.HasIndex("Name", "NormalizedName", "LocalizedName", "LibraryId", "Format") + .IsUnique(); + + b.ToTable("Series"); + }); + + modelBuilder.Entity("API.Entities.SeriesMetadata", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("SeriesId") + .IsUnique(); + + b.HasIndex("Id", "SeriesId") + .IsUnique(); + + b.ToTable("SeriesMetadata"); + }); + + modelBuilder.Entity("API.Entities.ServerSetting", b => + { + b.Property("Key") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("Key"); + + b.ToTable("ServerSetting"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Number") + .HasColumnType("INTEGER"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("SeriesId"); + + b.ToTable("Volume"); + }); + + modelBuilder.Entity("AppUserLibrary", b => + { + b.Property("AppUsersId") + .HasColumnType("INTEGER"); + + b.Property("LibrariesId") + .HasColumnType("INTEGER"); + + b.HasKey("AppUsersId", "LibrariesId"); + + b.HasIndex("LibrariesId"); + + b.ToTable("AppUserLibrary"); + }); + + modelBuilder.Entity("ChapterMetadataPerson", b => + { + b.Property("ChapterMetadatasId") + .HasColumnType("INTEGER"); + + b.Property("PeopleId") + .HasColumnType("INTEGER"); + + b.HasKey("ChapterMetadatasId", "PeopleId"); + + b.HasIndex("PeopleId"); + + b.ToTable("ChapterMetadataPerson"); + }); + + modelBuilder.Entity("CollectionTagSeriesMetadata", b => + { + b.Property("CollectionTagsId") + .HasColumnType("INTEGER"); + + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.HasKey("CollectionTagsId", "SeriesMetadatasId"); + + b.HasIndex("SeriesMetadatasId"); + + b.ToTable("CollectionTagSeriesMetadata"); + }); + + modelBuilder.Entity("GenreSeriesMetadata", b => + { + b.Property("GenresId") + .HasColumnType("INTEGER"); + + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.HasKey("GenresId", "SeriesMetadatasId"); + + b.HasIndex("SeriesMetadatasId"); + + b.ToTable("GenreSeriesMetadata"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("ProviderKey") + .HasColumnType("TEXT"); + + b.Property("ProviderDisplayName") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("PersonSeriesMetadata", b => + { + b.Property("PeopleId") + .HasColumnType("INTEGER"); + + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.HasKey("PeopleId", "SeriesMetadatasId"); + + b.HasIndex("SeriesMetadatasId"); + + b.ToTable("PersonSeriesMetadata"); + }); + + modelBuilder.Entity("API.Entities.AppUserBookmark", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Bookmarks") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserPreferences", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithOne("UserPreferences") + .HasForeignKey("API.Entities.AppUserPreferences", "AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserProgress", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Progresses") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserRating", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Ratings") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserRole", b => + { + b.HasOne("API.Entities.AppRole", "Role") + .WithMany("UserRoles") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.AppUser", "User") + .WithMany("UserRoles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.HasOne("API.Entities.Volume", "Volume") + .WithMany("Chapters") + .HasForeignKey("VolumeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Volume"); + }); + + modelBuilder.Entity("API.Entities.ChapterMetadata", b => + { + b.HasOne("API.Entities.Chapter", "Chapter") + .WithOne("ChapterMetadata") + .HasForeignKey("API.Entities.ChapterMetadata", "ChapterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Chapter"); + }); + + modelBuilder.Entity("API.Entities.FolderPath", b => + { + b.HasOne("API.Entities.Library", "Library") + .WithMany("Folders") + .HasForeignKey("LibraryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Library"); + }); + + modelBuilder.Entity("API.Entities.MangaFile", b => + { + b.HasOne("API.Entities.Chapter", "Chapter") + .WithMany("Files") + .HasForeignKey("ChapterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Chapter"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("ReadingLists") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.ReadingListItem", b => + { + b.HasOne("API.Entities.Chapter", "Chapter") + .WithMany() + .HasForeignKey("ChapterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.ReadingList", "ReadingList") + .WithMany("Items") + .HasForeignKey("ReadingListId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Series", "Series") + .WithMany() + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Volume", "Volume") + .WithMany() + .HasForeignKey("VolumeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Chapter"); + + b.Navigation("ReadingList"); + + b.Navigation("Series"); + + b.Navigation("Volume"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.HasOne("API.Entities.Library", "Library") + .WithMany("Series") + .HasForeignKey("LibraryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Library"); + }); + + modelBuilder.Entity("API.Entities.SeriesMetadata", b => + { + b.HasOne("API.Entities.Series", "Series") + .WithOne("Metadata") + .HasForeignKey("API.Entities.SeriesMetadata", "SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.HasOne("API.Entities.Series", "Series") + .WithMany("Volumes") + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("AppUserLibrary", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("AppUsersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Library", null) + .WithMany() + .HasForeignKey("LibrariesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ChapterMetadataPerson", b => + { + b.HasOne("API.Entities.ChapterMetadata", null) + .WithMany() + .HasForeignKey("ChapterMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Person", null) + .WithMany() + .HasForeignKey("PeopleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("CollectionTagSeriesMetadata", b => + { + b.HasOne("API.Entities.CollectionTag", null) + .WithMany() + .HasForeignKey("CollectionTagsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("GenreSeriesMetadata", b => + { + b.HasOne("API.Entities.Genre", null) + .WithMany() + .HasForeignKey("GenresId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("API.Entities.AppRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("PersonSeriesMetadata", b => + { + b.HasOne("API.Entities.Person", null) + .WithMany() + .HasForeignKey("PeopleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("API.Entities.AppRole", b => + { + b.Navigation("UserRoles"); + }); + + modelBuilder.Entity("API.Entities.AppUser", b => + { + b.Navigation("Bookmarks"); + + b.Navigation("Progresses"); + + b.Navigation("Ratings"); + + b.Navigation("ReadingLists"); + + b.Navigation("UserPreferences"); + + b.Navigation("UserRoles"); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.Navigation("ChapterMetadata"); + + b.Navigation("Files"); + }); + + modelBuilder.Entity("API.Entities.Library", b => + { + b.Navigation("Folders"); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.Navigation("Items"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.Navigation("Metadata"); + + b.Navigation("Volumes"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.Navigation("Chapters"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/API/Data/Migrations/20211127200244_MetadataFoundation.cs b/API/Data/Migrations/20211127200244_MetadataFoundation.cs new file mode 100644 index 000000000..f2ea2c9c1 --- /dev/null +++ b/API/Data/Migrations/20211127200244_MetadataFoundation.cs @@ -0,0 +1,203 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace API.Data.Migrations +{ + public partial class MetadataFoundation : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "Summary", + table: "Series"); + + migrationBuilder.AddColumn( + name: "Summary", + table: "SeriesMetadata", + type: "TEXT", + nullable: true); + + migrationBuilder.CreateTable( + name: "ChapterMetadata", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + Title = table.Column(type: "TEXT", nullable: true), + Year = table.Column(type: "TEXT", nullable: true), + StoryArc = table.Column(type: "TEXT", nullable: true), + ChapterId = table.Column(type: "INTEGER", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ChapterMetadata", x => x.Id); + table.ForeignKey( + name: "FK_ChapterMetadata_Chapter_ChapterId", + column: x => x.ChapterId, + principalTable: "Chapter", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "Genre", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + Name = table.Column(type: "TEXT", nullable: true), + NormalizedName = table.Column(type: "TEXT", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Genre", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "Person", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + Name = table.Column(type: "TEXT", nullable: true), + NormalizedName = table.Column(type: "TEXT", nullable: true), + Role = table.Column(type: "INTEGER", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Person", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "GenreSeriesMetadata", + columns: table => new + { + GenresId = table.Column(type: "INTEGER", nullable: false), + SeriesMetadatasId = table.Column(type: "INTEGER", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_GenreSeriesMetadata", x => new { x.GenresId, x.SeriesMetadatasId }); + table.ForeignKey( + name: "FK_GenreSeriesMetadata_Genre_GenresId", + column: x => x.GenresId, + principalTable: "Genre", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_GenreSeriesMetadata_SeriesMetadata_SeriesMetadatasId", + column: x => x.SeriesMetadatasId, + principalTable: "SeriesMetadata", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "ChapterMetadataPerson", + columns: table => new + { + ChapterMetadatasId = table.Column(type: "INTEGER", nullable: false), + PeopleId = table.Column(type: "INTEGER", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ChapterMetadataPerson", x => new { x.ChapterMetadatasId, x.PeopleId }); + table.ForeignKey( + name: "FK_ChapterMetadataPerson_ChapterMetadata_ChapterMetadatasId", + column: x => x.ChapterMetadatasId, + principalTable: "ChapterMetadata", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_ChapterMetadataPerson_Person_PeopleId", + column: x => x.PeopleId, + principalTable: "Person", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "PersonSeriesMetadata", + columns: table => new + { + PeopleId = table.Column(type: "INTEGER", nullable: false), + SeriesMetadatasId = table.Column(type: "INTEGER", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_PersonSeriesMetadata", x => new { x.PeopleId, x.SeriesMetadatasId }); + table.ForeignKey( + name: "FK_PersonSeriesMetadata_Person_PeopleId", + column: x => x.PeopleId, + principalTable: "Person", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_PersonSeriesMetadata_SeriesMetadata_SeriesMetadatasId", + column: x => x.SeriesMetadatasId, + principalTable: "SeriesMetadata", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_ChapterMetadata_ChapterId", + table: "ChapterMetadata", + column: "ChapterId", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_ChapterMetadataPerson_PeopleId", + table: "ChapterMetadataPerson", + column: "PeopleId"); + + migrationBuilder.CreateIndex( + name: "IX_Genre_NormalizedName", + table: "Genre", + column: "NormalizedName", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_GenreSeriesMetadata_SeriesMetadatasId", + table: "GenreSeriesMetadata", + column: "SeriesMetadatasId"); + + migrationBuilder.CreateIndex( + name: "IX_PersonSeriesMetadata_SeriesMetadatasId", + table: "PersonSeriesMetadata", + column: "SeriesMetadatasId"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "ChapterMetadataPerson"); + + migrationBuilder.DropTable( + name: "GenreSeriesMetadata"); + + migrationBuilder.DropTable( + name: "PersonSeriesMetadata"); + + migrationBuilder.DropTable( + name: "ChapterMetadata"); + + migrationBuilder.DropTable( + name: "Genre"); + + migrationBuilder.DropTable( + name: "Person"); + + migrationBuilder.DropColumn( + name: "Summary", + table: "SeriesMetadata"); + + migrationBuilder.AddColumn( + name: "Summary", + table: "Series", + type: "TEXT", + nullable: true); + } + } +} diff --git a/API/Data/Migrations/20211129231007_RemoveChapterMetadata.Designer.cs b/API/Data/Migrations/20211129231007_RemoveChapterMetadata.Designer.cs new file mode 100644 index 000000000..27436b91f --- /dev/null +++ b/API/Data/Migrations/20211129231007_RemoveChapterMetadata.Designer.cs @@ -0,0 +1,1232 @@ +// +using System; +using API.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace API.Data.Migrations +{ + [DbContext(typeof(DataContext))] + [Migration("20211129231007_RemoveChapterMetadata")] + partial class RemoveChapterMetadata + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "6.0.0"); + + modelBuilder.Entity("API.Entities.AppRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("API.Entities.AppUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessFailedCount") + .HasColumnType("INTEGER"); + + b.Property("ApiKey") + .HasColumnType("TEXT"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("EmailConfirmed") + .HasColumnType("INTEGER"); + + b.Property("LastActive") + .HasColumnType("TEXT"); + + b.Property("LockoutEnabled") + .HasColumnType("INTEGER"); + + b.Property("LockoutEnd") + .HasColumnType("TEXT"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("PasswordHash") + .HasColumnType("TEXT"); + + b.Property("PhoneNumber") + .HasColumnType("TEXT"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SecurityStamp") + .HasColumnType("TEXT"); + + b.Property("TwoFactorEnabled") + .HasColumnType("INTEGER"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("API.Entities.AppUserBookmark", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("Page") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("AppUserBookmark"); + }); + + modelBuilder.Entity("API.Entities.AppUserPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("AutoCloseMenu") + .HasColumnType("INTEGER"); + + b.Property("BookReaderDarkMode") + .HasColumnType("INTEGER"); + + b.Property("BookReaderFontFamily") + .HasColumnType("TEXT"); + + b.Property("BookReaderFontSize") + .HasColumnType("INTEGER"); + + b.Property("BookReaderLineSpacing") + .HasColumnType("INTEGER"); + + b.Property("BookReaderMargin") + .HasColumnType("INTEGER"); + + b.Property("BookReaderReadingDirection") + .HasColumnType("INTEGER"); + + b.Property("BookReaderTapToPaginate") + .HasColumnType("INTEGER"); + + b.Property("PageSplitOption") + .HasColumnType("INTEGER"); + + b.Property("ReaderMode") + .HasColumnType("INTEGER"); + + b.Property("ReadingDirection") + .HasColumnType("INTEGER"); + + b.Property("ScalingOption") + .HasColumnType("INTEGER"); + + b.Property("SiteDarkMode") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId") + .IsUnique(); + + b.ToTable("AppUserPreferences"); + }); + + modelBuilder.Entity("API.Entities.AppUserProgress", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("BookScrollId") + .HasColumnType("TEXT"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("PagesRead") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("AppUserProgresses"); + }); + + modelBuilder.Entity("API.Entities.AppUserRating", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("Rating") + .HasColumnType("INTEGER"); + + b.Property("Review") + .HasColumnType("TEXT"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("AppUserRating"); + }); + + modelBuilder.Entity("API.Entities.AppUserRole", b => + { + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("IsSpecial") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Number") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("Range") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.Property("TitleName") + .HasColumnType("TEXT"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("VolumeId"); + + b.ToTable("Chapter"); + }); + + modelBuilder.Entity("API.Entities.CollectionTag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("NormalizedTitle") + .HasColumnType("TEXT"); + + b.Property("Promoted") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Id", "Promoted") + .IsUnique(); + + b.ToTable("CollectionTag"); + }); + + modelBuilder.Entity("API.Entities.FolderPath", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("LastScanned") + .HasColumnType("TEXT"); + + b.Property("LibraryId") + .HasColumnType("INTEGER"); + + b.Property("Path") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("LibraryId"); + + b.ToTable("FolderPath"); + }); + + modelBuilder.Entity("API.Entities.Genre", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique(); + + b.ToTable("Genre"); + }); + + modelBuilder.Entity("API.Entities.Library", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("LastScanned") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Library"); + }); + + modelBuilder.Entity("API.Entities.MangaFile", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("FilePath") + .HasColumnType("TEXT"); + + b.Property("Format") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ChapterId"); + + b.ToTable("MangaFile"); + }); + + modelBuilder.Entity("API.Entities.Metadata.ChapterMetadata", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("StoryArc") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.Property("Year") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ChapterId"); + + b.ToTable("ChapterMetadata"); + }); + + modelBuilder.Entity("API.Entities.Metadata.SeriesMetadata", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("SeriesId") + .IsUnique(); + + b.HasIndex("Id", "SeriesId") + .IsUnique(); + + b.ToTable("SeriesMetadata"); + }); + + modelBuilder.Entity("API.Entities.Person", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChapterMetadataId") + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasColumnType("TEXT"); + + b.Property("Role") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ChapterMetadataId"); + + b.ToTable("Person"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Promoted") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("ReadingList"); + }); + + modelBuilder.Entity("API.Entities.ReadingListItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("Order") + .HasColumnType("INTEGER"); + + b.Property("ReadingListId") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ChapterId"); + + b.HasIndex("ReadingListId"); + + b.HasIndex("SeriesId"); + + b.HasIndex("VolumeId"); + + b.ToTable("ReadingListItem"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("Format") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("LibraryId") + .HasColumnType("INTEGER"); + + b.Property("LocalizedName") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasColumnType("TEXT"); + + b.Property("OriginalName") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("SortName") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("LibraryId"); + + b.HasIndex("Name", "NormalizedName", "LocalizedName", "LibraryId", "Format") + .IsUnique(); + + b.ToTable("Series"); + }); + + modelBuilder.Entity("API.Entities.ServerSetting", b => + { + b.Property("Key") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("Key"); + + b.ToTable("ServerSetting"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Number") + .HasColumnType("INTEGER"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("SeriesId"); + + b.ToTable("Volume"); + }); + + modelBuilder.Entity("AppUserLibrary", b => + { + b.Property("AppUsersId") + .HasColumnType("INTEGER"); + + b.Property("LibrariesId") + .HasColumnType("INTEGER"); + + b.HasKey("AppUsersId", "LibrariesId"); + + b.HasIndex("LibrariesId"); + + b.ToTable("AppUserLibrary"); + }); + + modelBuilder.Entity("ChapterPerson", b => + { + b.Property("ChapterMetadatasId") + .HasColumnType("INTEGER"); + + b.Property("PeopleId") + .HasColumnType("INTEGER"); + + b.HasKey("ChapterMetadatasId", "PeopleId"); + + b.HasIndex("PeopleId"); + + b.ToTable("ChapterPerson"); + }); + + modelBuilder.Entity("CollectionTagSeriesMetadata", b => + { + b.Property("CollectionTagsId") + .HasColumnType("INTEGER"); + + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.HasKey("CollectionTagsId", "SeriesMetadatasId"); + + b.HasIndex("SeriesMetadatasId"); + + b.ToTable("CollectionTagSeriesMetadata"); + }); + + modelBuilder.Entity("GenreSeriesMetadata", b => + { + b.Property("GenresId") + .HasColumnType("INTEGER"); + + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.HasKey("GenresId", "SeriesMetadatasId"); + + b.HasIndex("SeriesMetadatasId"); + + b.ToTable("GenreSeriesMetadata"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("ProviderKey") + .HasColumnType("TEXT"); + + b.Property("ProviderDisplayName") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("PersonSeriesMetadata", b => + { + b.Property("PeopleId") + .HasColumnType("INTEGER"); + + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.HasKey("PeopleId", "SeriesMetadatasId"); + + b.HasIndex("SeriesMetadatasId"); + + b.ToTable("PersonSeriesMetadata"); + }); + + modelBuilder.Entity("API.Entities.AppUserBookmark", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Bookmarks") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserPreferences", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithOne("UserPreferences") + .HasForeignKey("API.Entities.AppUserPreferences", "AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserProgress", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Progresses") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserRating", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Ratings") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserRole", b => + { + b.HasOne("API.Entities.AppRole", "Role") + .WithMany("UserRoles") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.AppUser", "User") + .WithMany("UserRoles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.HasOne("API.Entities.Volume", "Volume") + .WithMany("Chapters") + .HasForeignKey("VolumeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Volume"); + }); + + modelBuilder.Entity("API.Entities.FolderPath", b => + { + b.HasOne("API.Entities.Library", "Library") + .WithMany("Folders") + .HasForeignKey("LibraryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Library"); + }); + + modelBuilder.Entity("API.Entities.MangaFile", b => + { + b.HasOne("API.Entities.Chapter", "Chapter") + .WithMany("Files") + .HasForeignKey("ChapterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Chapter"); + }); + + modelBuilder.Entity("API.Entities.Metadata.ChapterMetadata", b => + { + b.HasOne("API.Entities.Chapter", "Chapter") + .WithMany() + .HasForeignKey("ChapterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Chapter"); + }); + + modelBuilder.Entity("API.Entities.Metadata.SeriesMetadata", b => + { + b.HasOne("API.Entities.Series", "Series") + .WithOne("Metadata") + .HasForeignKey("API.Entities.Metadata.SeriesMetadata", "SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("API.Entities.Person", b => + { + b.HasOne("API.Entities.Metadata.ChapterMetadata", null) + .WithMany("People") + .HasForeignKey("ChapterMetadataId"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("ReadingLists") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.ReadingListItem", b => + { + b.HasOne("API.Entities.Chapter", "Chapter") + .WithMany() + .HasForeignKey("ChapterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.ReadingList", "ReadingList") + .WithMany("Items") + .HasForeignKey("ReadingListId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Series", "Series") + .WithMany() + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Volume", "Volume") + .WithMany() + .HasForeignKey("VolumeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Chapter"); + + b.Navigation("ReadingList"); + + b.Navigation("Series"); + + b.Navigation("Volume"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.HasOne("API.Entities.Library", "Library") + .WithMany("Series") + .HasForeignKey("LibraryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Library"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.HasOne("API.Entities.Series", "Series") + .WithMany("Volumes") + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("AppUserLibrary", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("AppUsersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Library", null) + .WithMany() + .HasForeignKey("LibrariesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ChapterPerson", b => + { + b.HasOne("API.Entities.Chapter", null) + .WithMany() + .HasForeignKey("ChapterMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Person", null) + .WithMany() + .HasForeignKey("PeopleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("CollectionTagSeriesMetadata", b => + { + b.HasOne("API.Entities.CollectionTag", null) + .WithMany() + .HasForeignKey("CollectionTagsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Metadata.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("GenreSeriesMetadata", b => + { + b.HasOne("API.Entities.Genre", null) + .WithMany() + .HasForeignKey("GenresId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Metadata.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("API.Entities.AppRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("PersonSeriesMetadata", b => + { + b.HasOne("API.Entities.Person", null) + .WithMany() + .HasForeignKey("PeopleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Metadata.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("API.Entities.AppRole", b => + { + b.Navigation("UserRoles"); + }); + + modelBuilder.Entity("API.Entities.AppUser", b => + { + b.Navigation("Bookmarks"); + + b.Navigation("Progresses"); + + b.Navigation("Ratings"); + + b.Navigation("ReadingLists"); + + b.Navigation("UserPreferences"); + + b.Navigation("UserRoles"); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.Navigation("Files"); + }); + + modelBuilder.Entity("API.Entities.Library", b => + { + b.Navigation("Folders"); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("API.Entities.Metadata.ChapterMetadata", b => + { + b.Navigation("People"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.Navigation("Items"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.Navigation("Metadata"); + + b.Navigation("Volumes"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.Navigation("Chapters"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/API/Data/Migrations/20211129231007_RemoveChapterMetadata.cs b/API/Data/Migrations/20211129231007_RemoveChapterMetadata.cs new file mode 100644 index 000000000..c50578ff9 --- /dev/null +++ b/API/Data/Migrations/20211129231007_RemoveChapterMetadata.cs @@ -0,0 +1,138 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace API.Data.Migrations +{ + public partial class RemoveChapterMetadata : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "ChapterMetadataPerson"); + + migrationBuilder.DropIndex( + name: "IX_ChapterMetadata_ChapterId", + table: "ChapterMetadata"); + + migrationBuilder.AddColumn( + name: "ChapterMetadataId", + table: "Person", + type: "INTEGER", + nullable: true); + + migrationBuilder.AddColumn( + name: "TitleName", + table: "Chapter", + type: "TEXT", + nullable: true); + + migrationBuilder.CreateTable( + name: "ChapterPerson", + columns: table => new + { + ChapterMetadatasId = table.Column(type: "INTEGER", nullable: false), + PeopleId = table.Column(type: "INTEGER", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ChapterPerson", x => new { x.ChapterMetadatasId, x.PeopleId }); + table.ForeignKey( + name: "FK_ChapterPerson_Chapter_ChapterMetadatasId", + column: x => x.ChapterMetadatasId, + principalTable: "Chapter", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_ChapterPerson_Person_PeopleId", + column: x => x.PeopleId, + principalTable: "Person", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_Person_ChapterMetadataId", + table: "Person", + column: "ChapterMetadataId"); + + migrationBuilder.CreateIndex( + name: "IX_ChapterMetadata_ChapterId", + table: "ChapterMetadata", + column: "ChapterId"); + + migrationBuilder.CreateIndex( + name: "IX_ChapterPerson_PeopleId", + table: "ChapterPerson", + column: "PeopleId"); + + migrationBuilder.AddForeignKey( + name: "FK_Person_ChapterMetadata_ChapterMetadataId", + table: "Person", + column: "ChapterMetadataId", + principalTable: "ChapterMetadata", + principalColumn: "Id"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_Person_ChapterMetadata_ChapterMetadataId", + table: "Person"); + + migrationBuilder.DropTable( + name: "ChapterPerson"); + + migrationBuilder.DropIndex( + name: "IX_Person_ChapterMetadataId", + table: "Person"); + + migrationBuilder.DropIndex( + name: "IX_ChapterMetadata_ChapterId", + table: "ChapterMetadata"); + + migrationBuilder.DropColumn( + name: "ChapterMetadataId", + table: "Person"); + + migrationBuilder.DropColumn( + name: "TitleName", + table: "Chapter"); + + migrationBuilder.CreateTable( + name: "ChapterMetadataPerson", + columns: table => new + { + ChapterMetadatasId = table.Column(type: "INTEGER", nullable: false), + PeopleId = table.Column(type: "INTEGER", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ChapterMetadataPerson", x => new { x.ChapterMetadatasId, x.PeopleId }); + table.ForeignKey( + name: "FK_ChapterMetadataPerson_ChapterMetadata_ChapterMetadatasId", + column: x => x.ChapterMetadatasId, + principalTable: "ChapterMetadata", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_ChapterMetadataPerson_Person_PeopleId", + column: x => x.PeopleId, + principalTable: "Person", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_ChapterMetadata_ChapterId", + table: "ChapterMetadata", + column: "ChapterId", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_ChapterMetadataPerson_PeopleId", + table: "ChapterMetadataPerson", + column: "PeopleId"); + } + } +} diff --git a/API/Data/Migrations/20211130134642_GenreProvider.Designer.cs b/API/Data/Migrations/20211130134642_GenreProvider.Designer.cs new file mode 100644 index 000000000..4b90e75ba --- /dev/null +++ b/API/Data/Migrations/20211130134642_GenreProvider.Designer.cs @@ -0,0 +1,1182 @@ +// +using System; +using API.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace API.Data.Migrations +{ + [DbContext(typeof(DataContext))] + [Migration("20211130134642_GenreProvider")] + partial class GenreProvider + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "6.0.0"); + + modelBuilder.Entity("API.Entities.AppRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("API.Entities.AppUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessFailedCount") + .HasColumnType("INTEGER"); + + b.Property("ApiKey") + .HasColumnType("TEXT"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("EmailConfirmed") + .HasColumnType("INTEGER"); + + b.Property("LastActive") + .HasColumnType("TEXT"); + + b.Property("LockoutEnabled") + .HasColumnType("INTEGER"); + + b.Property("LockoutEnd") + .HasColumnType("TEXT"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("PasswordHash") + .HasColumnType("TEXT"); + + b.Property("PhoneNumber") + .HasColumnType("TEXT"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SecurityStamp") + .HasColumnType("TEXT"); + + b.Property("TwoFactorEnabled") + .HasColumnType("INTEGER"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("API.Entities.AppUserBookmark", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("Page") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("AppUserBookmark"); + }); + + modelBuilder.Entity("API.Entities.AppUserPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("AutoCloseMenu") + .HasColumnType("INTEGER"); + + b.Property("BookReaderDarkMode") + .HasColumnType("INTEGER"); + + b.Property("BookReaderFontFamily") + .HasColumnType("TEXT"); + + b.Property("BookReaderFontSize") + .HasColumnType("INTEGER"); + + b.Property("BookReaderLineSpacing") + .HasColumnType("INTEGER"); + + b.Property("BookReaderMargin") + .HasColumnType("INTEGER"); + + b.Property("BookReaderReadingDirection") + .HasColumnType("INTEGER"); + + b.Property("BookReaderTapToPaginate") + .HasColumnType("INTEGER"); + + b.Property("PageSplitOption") + .HasColumnType("INTEGER"); + + b.Property("ReaderMode") + .HasColumnType("INTEGER"); + + b.Property("ReadingDirection") + .HasColumnType("INTEGER"); + + b.Property("ScalingOption") + .HasColumnType("INTEGER"); + + b.Property("SiteDarkMode") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId") + .IsUnique(); + + b.ToTable("AppUserPreferences"); + }); + + modelBuilder.Entity("API.Entities.AppUserProgress", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("BookScrollId") + .HasColumnType("TEXT"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("PagesRead") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("AppUserProgresses"); + }); + + modelBuilder.Entity("API.Entities.AppUserRating", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("Rating") + .HasColumnType("INTEGER"); + + b.Property("Review") + .HasColumnType("TEXT"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("AppUserRating"); + }); + + modelBuilder.Entity("API.Entities.AppUserRole", b => + { + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("IsSpecial") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Number") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("Range") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.Property("TitleName") + .HasColumnType("TEXT"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("VolumeId"); + + b.ToTable("Chapter"); + }); + + modelBuilder.Entity("API.Entities.CollectionTag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("NormalizedTitle") + .HasColumnType("TEXT"); + + b.Property("Promoted") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Id", "Promoted") + .IsUnique(); + + b.ToTable("CollectionTag"); + }); + + modelBuilder.Entity("API.Entities.FolderPath", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("LastScanned") + .HasColumnType("TEXT"); + + b.Property("LibraryId") + .HasColumnType("INTEGER"); + + b.Property("Path") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("LibraryId"); + + b.ToTable("FolderPath"); + }); + + modelBuilder.Entity("API.Entities.Genre", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ExternalTag") + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique(); + + b.ToTable("Genre"); + }); + + modelBuilder.Entity("API.Entities.Library", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("LastScanned") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Library"); + }); + + modelBuilder.Entity("API.Entities.MangaFile", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("FilePath") + .HasColumnType("TEXT"); + + b.Property("Format") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ChapterId"); + + b.ToTable("MangaFile"); + }); + + modelBuilder.Entity("API.Entities.Metadata.SeriesMetadata", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("SeriesId") + .IsUnique(); + + b.HasIndex("Id", "SeriesId") + .IsUnique(); + + b.ToTable("SeriesMetadata"); + }); + + modelBuilder.Entity("API.Entities.Person", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasColumnType("TEXT"); + + b.Property("Role") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Person"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Promoted") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("ReadingList"); + }); + + modelBuilder.Entity("API.Entities.ReadingListItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("Order") + .HasColumnType("INTEGER"); + + b.Property("ReadingListId") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ChapterId"); + + b.HasIndex("ReadingListId"); + + b.HasIndex("SeriesId"); + + b.HasIndex("VolumeId"); + + b.ToTable("ReadingListItem"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("Format") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("LibraryId") + .HasColumnType("INTEGER"); + + b.Property("LocalizedName") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasColumnType("TEXT"); + + b.Property("OriginalName") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("SortName") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("LibraryId"); + + b.HasIndex("Name", "NormalizedName", "LocalizedName", "LibraryId", "Format") + .IsUnique(); + + b.ToTable("Series"); + }); + + modelBuilder.Entity("API.Entities.ServerSetting", b => + { + b.Property("Key") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("Key"); + + b.ToTable("ServerSetting"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Number") + .HasColumnType("INTEGER"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("SeriesId"); + + b.ToTable("Volume"); + }); + + modelBuilder.Entity("AppUserLibrary", b => + { + b.Property("AppUsersId") + .HasColumnType("INTEGER"); + + b.Property("LibrariesId") + .HasColumnType("INTEGER"); + + b.HasKey("AppUsersId", "LibrariesId"); + + b.HasIndex("LibrariesId"); + + b.ToTable("AppUserLibrary"); + }); + + modelBuilder.Entity("ChapterPerson", b => + { + b.Property("ChapterMetadatasId") + .HasColumnType("INTEGER"); + + b.Property("PeopleId") + .HasColumnType("INTEGER"); + + b.HasKey("ChapterMetadatasId", "PeopleId"); + + b.HasIndex("PeopleId"); + + b.ToTable("ChapterPerson"); + }); + + modelBuilder.Entity("CollectionTagSeriesMetadata", b => + { + b.Property("CollectionTagsId") + .HasColumnType("INTEGER"); + + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.HasKey("CollectionTagsId", "SeriesMetadatasId"); + + b.HasIndex("SeriesMetadatasId"); + + b.ToTable("CollectionTagSeriesMetadata"); + }); + + modelBuilder.Entity("GenreSeriesMetadata", b => + { + b.Property("GenresId") + .HasColumnType("INTEGER"); + + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.HasKey("GenresId", "SeriesMetadatasId"); + + b.HasIndex("SeriesMetadatasId"); + + b.ToTable("GenreSeriesMetadata"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("ProviderKey") + .HasColumnType("TEXT"); + + b.Property("ProviderDisplayName") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("PersonSeriesMetadata", b => + { + b.Property("PeopleId") + .HasColumnType("INTEGER"); + + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.HasKey("PeopleId", "SeriesMetadatasId"); + + b.HasIndex("SeriesMetadatasId"); + + b.ToTable("PersonSeriesMetadata"); + }); + + modelBuilder.Entity("API.Entities.AppUserBookmark", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Bookmarks") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserPreferences", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithOne("UserPreferences") + .HasForeignKey("API.Entities.AppUserPreferences", "AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserProgress", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Progresses") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserRating", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Ratings") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserRole", b => + { + b.HasOne("API.Entities.AppRole", "Role") + .WithMany("UserRoles") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.AppUser", "User") + .WithMany("UserRoles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.HasOne("API.Entities.Volume", "Volume") + .WithMany("Chapters") + .HasForeignKey("VolumeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Volume"); + }); + + modelBuilder.Entity("API.Entities.FolderPath", b => + { + b.HasOne("API.Entities.Library", "Library") + .WithMany("Folders") + .HasForeignKey("LibraryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Library"); + }); + + modelBuilder.Entity("API.Entities.MangaFile", b => + { + b.HasOne("API.Entities.Chapter", "Chapter") + .WithMany("Files") + .HasForeignKey("ChapterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Chapter"); + }); + + modelBuilder.Entity("API.Entities.Metadata.SeriesMetadata", b => + { + b.HasOne("API.Entities.Series", "Series") + .WithOne("Metadata") + .HasForeignKey("API.Entities.Metadata.SeriesMetadata", "SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("ReadingLists") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.ReadingListItem", b => + { + b.HasOne("API.Entities.Chapter", "Chapter") + .WithMany() + .HasForeignKey("ChapterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.ReadingList", "ReadingList") + .WithMany("Items") + .HasForeignKey("ReadingListId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Series", "Series") + .WithMany() + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Volume", "Volume") + .WithMany() + .HasForeignKey("VolumeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Chapter"); + + b.Navigation("ReadingList"); + + b.Navigation("Series"); + + b.Navigation("Volume"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.HasOne("API.Entities.Library", "Library") + .WithMany("Series") + .HasForeignKey("LibraryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Library"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.HasOne("API.Entities.Series", "Series") + .WithMany("Volumes") + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("AppUserLibrary", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("AppUsersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Library", null) + .WithMany() + .HasForeignKey("LibrariesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ChapterPerson", b => + { + b.HasOne("API.Entities.Chapter", null) + .WithMany() + .HasForeignKey("ChapterMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Person", null) + .WithMany() + .HasForeignKey("PeopleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("CollectionTagSeriesMetadata", b => + { + b.HasOne("API.Entities.CollectionTag", null) + .WithMany() + .HasForeignKey("CollectionTagsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Metadata.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("GenreSeriesMetadata", b => + { + b.HasOne("API.Entities.Genre", null) + .WithMany() + .HasForeignKey("GenresId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Metadata.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("API.Entities.AppRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("PersonSeriesMetadata", b => + { + b.HasOne("API.Entities.Person", null) + .WithMany() + .HasForeignKey("PeopleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Metadata.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("API.Entities.AppRole", b => + { + b.Navigation("UserRoles"); + }); + + modelBuilder.Entity("API.Entities.AppUser", b => + { + b.Navigation("Bookmarks"); + + b.Navigation("Progresses"); + + b.Navigation("Ratings"); + + b.Navigation("ReadingLists"); + + b.Navigation("UserPreferences"); + + b.Navigation("UserRoles"); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.Navigation("Files"); + }); + + modelBuilder.Entity("API.Entities.Library", b => + { + b.Navigation("Folders"); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.Navigation("Items"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.Navigation("Metadata"); + + b.Navigation("Volumes"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.Navigation("Chapters"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/API/Data/Migrations/20211130134642_GenreProvider.cs b/API/Data/Migrations/20211130134642_GenreProvider.cs new file mode 100644 index 000000000..260210d54 --- /dev/null +++ b/API/Data/Migrations/20211130134642_GenreProvider.cs @@ -0,0 +1,86 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace API.Data.Migrations +{ + public partial class GenreProvider : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_Person_ChapterMetadata_ChapterMetadataId", + table: "Person"); + + migrationBuilder.DropTable( + name: "ChapterMetadata"); + + migrationBuilder.DropIndex( + name: "IX_Person_ChapterMetadataId", + table: "Person"); + + migrationBuilder.DropColumn( + name: "ChapterMetadataId", + table: "Person"); + + migrationBuilder.AddColumn( + name: "ExternalTag", + table: "Genre", + type: "INTEGER", + nullable: false, + defaultValue: false); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "ExternalTag", + table: "Genre"); + + migrationBuilder.AddColumn( + name: "ChapterMetadataId", + table: "Person", + type: "INTEGER", + nullable: true); + + migrationBuilder.CreateTable( + name: "ChapterMetadata", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + ChapterId = table.Column(type: "INTEGER", nullable: false), + StoryArc = table.Column(type: "TEXT", nullable: true), + Title = table.Column(type: "TEXT", nullable: true), + Year = table.Column(type: "TEXT", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_ChapterMetadata", x => x.Id); + table.ForeignKey( + name: "FK_ChapterMetadata_Chapter_ChapterId", + column: x => x.ChapterId, + principalTable: "Chapter", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_Person_ChapterMetadataId", + table: "Person", + column: "ChapterMetadataId"); + + migrationBuilder.CreateIndex( + name: "IX_ChapterMetadata_ChapterId", + table: "ChapterMetadata", + column: "ChapterId"); + + migrationBuilder.AddForeignKey( + name: "FK_Person_ChapterMetadata_ChapterMetadataId", + table: "Person", + column: "ChapterMetadataId", + principalTable: "ChapterMetadata", + principalColumn: "Id"); + } + } +} diff --git a/API/Data/Migrations/20211201230003_GenreTitle.Designer.cs b/API/Data/Migrations/20211201230003_GenreTitle.Designer.cs new file mode 100644 index 000000000..81f69b5a0 --- /dev/null +++ b/API/Data/Migrations/20211201230003_GenreTitle.Designer.cs @@ -0,0 +1,1196 @@ +// +using System; +using API.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace API.Data.Migrations +{ + [DbContext(typeof(DataContext))] + [Migration("20211201230003_GenreTitle")] + partial class GenreTitle + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "6.0.0"); + + modelBuilder.Entity("API.Entities.AppRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("API.Entities.AppUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessFailedCount") + .HasColumnType("INTEGER"); + + b.Property("ApiKey") + .HasColumnType("TEXT"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("EmailConfirmed") + .HasColumnType("INTEGER"); + + b.Property("LastActive") + .HasColumnType("TEXT"); + + b.Property("LockoutEnabled") + .HasColumnType("INTEGER"); + + b.Property("LockoutEnd") + .HasColumnType("TEXT"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("PasswordHash") + .HasColumnType("TEXT"); + + b.Property("PhoneNumber") + .HasColumnType("TEXT"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SecurityStamp") + .HasColumnType("TEXT"); + + b.Property("TwoFactorEnabled") + .HasColumnType("INTEGER"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("API.Entities.AppUserBookmark", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("Page") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("AppUserBookmark"); + }); + + modelBuilder.Entity("API.Entities.AppUserPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("AutoCloseMenu") + .HasColumnType("INTEGER"); + + b.Property("BookReaderDarkMode") + .HasColumnType("INTEGER"); + + b.Property("BookReaderFontFamily") + .HasColumnType("TEXT"); + + b.Property("BookReaderFontSize") + .HasColumnType("INTEGER"); + + b.Property("BookReaderLineSpacing") + .HasColumnType("INTEGER"); + + b.Property("BookReaderMargin") + .HasColumnType("INTEGER"); + + b.Property("BookReaderReadingDirection") + .HasColumnType("INTEGER"); + + b.Property("BookReaderTapToPaginate") + .HasColumnType("INTEGER"); + + b.Property("PageSplitOption") + .HasColumnType("INTEGER"); + + b.Property("ReaderMode") + .HasColumnType("INTEGER"); + + b.Property("ReadingDirection") + .HasColumnType("INTEGER"); + + b.Property("ScalingOption") + .HasColumnType("INTEGER"); + + b.Property("SiteDarkMode") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId") + .IsUnique(); + + b.ToTable("AppUserPreferences"); + }); + + modelBuilder.Entity("API.Entities.AppUserProgress", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("BookScrollId") + .HasColumnType("TEXT"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("PagesRead") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("AppUserProgresses"); + }); + + modelBuilder.Entity("API.Entities.AppUserRating", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("Rating") + .HasColumnType("INTEGER"); + + b.Property("Review") + .HasColumnType("TEXT"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("AppUserRating"); + }); + + modelBuilder.Entity("API.Entities.AppUserRole", b => + { + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("GenreId") + .HasColumnType("INTEGER"); + + b.Property("IsSpecial") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Number") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("Range") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.Property("TitleName") + .HasColumnType("TEXT"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GenreId"); + + b.HasIndex("VolumeId"); + + b.ToTable("Chapter"); + }); + + modelBuilder.Entity("API.Entities.CollectionTag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("NormalizedTitle") + .HasColumnType("TEXT"); + + b.Property("Promoted") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Id", "Promoted") + .IsUnique(); + + b.ToTable("CollectionTag"); + }); + + modelBuilder.Entity("API.Entities.FolderPath", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("LastScanned") + .HasColumnType("TEXT"); + + b.Property("LibraryId") + .HasColumnType("INTEGER"); + + b.Property("Path") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("LibraryId"); + + b.ToTable("FolderPath"); + }); + + modelBuilder.Entity("API.Entities.Genre", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ExternalTag") + .HasColumnType("INTEGER"); + + b.Property("NormalizedTitle") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedTitle", "ExternalTag") + .IsUnique(); + + b.ToTable("Genre"); + }); + + modelBuilder.Entity("API.Entities.Library", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("LastScanned") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Library"); + }); + + modelBuilder.Entity("API.Entities.MangaFile", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("FilePath") + .HasColumnType("TEXT"); + + b.Property("Format") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ChapterId"); + + b.ToTable("MangaFile"); + }); + + modelBuilder.Entity("API.Entities.Metadata.SeriesMetadata", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("SeriesId") + .IsUnique(); + + b.HasIndex("Id", "SeriesId") + .IsUnique(); + + b.ToTable("SeriesMetadata"); + }); + + modelBuilder.Entity("API.Entities.Person", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasColumnType("TEXT"); + + b.Property("Role") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Person"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Promoted") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("ReadingList"); + }); + + modelBuilder.Entity("API.Entities.ReadingListItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("Order") + .HasColumnType("INTEGER"); + + b.Property("ReadingListId") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ChapterId"); + + b.HasIndex("ReadingListId"); + + b.HasIndex("SeriesId"); + + b.HasIndex("VolumeId"); + + b.ToTable("ReadingListItem"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("Format") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("LibraryId") + .HasColumnType("INTEGER"); + + b.Property("LocalizedName") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasColumnType("TEXT"); + + b.Property("OriginalName") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("SortName") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("LibraryId"); + + b.HasIndex("Name", "NormalizedName", "LocalizedName", "LibraryId", "Format") + .IsUnique(); + + b.ToTable("Series"); + }); + + modelBuilder.Entity("API.Entities.ServerSetting", b => + { + b.Property("Key") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("Key"); + + b.ToTable("ServerSetting"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Number") + .HasColumnType("INTEGER"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("SeriesId"); + + b.ToTable("Volume"); + }); + + modelBuilder.Entity("AppUserLibrary", b => + { + b.Property("AppUsersId") + .HasColumnType("INTEGER"); + + b.Property("LibrariesId") + .HasColumnType("INTEGER"); + + b.HasKey("AppUsersId", "LibrariesId"); + + b.HasIndex("LibrariesId"); + + b.ToTable("AppUserLibrary"); + }); + + modelBuilder.Entity("ChapterPerson", b => + { + b.Property("ChapterMetadatasId") + .HasColumnType("INTEGER"); + + b.Property("PeopleId") + .HasColumnType("INTEGER"); + + b.HasKey("ChapterMetadatasId", "PeopleId"); + + b.HasIndex("PeopleId"); + + b.ToTable("ChapterPerson"); + }); + + modelBuilder.Entity("CollectionTagSeriesMetadata", b => + { + b.Property("CollectionTagsId") + .HasColumnType("INTEGER"); + + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.HasKey("CollectionTagsId", "SeriesMetadatasId"); + + b.HasIndex("SeriesMetadatasId"); + + b.ToTable("CollectionTagSeriesMetadata"); + }); + + modelBuilder.Entity("GenreSeriesMetadata", b => + { + b.Property("GenresId") + .HasColumnType("INTEGER"); + + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.HasKey("GenresId", "SeriesMetadatasId"); + + b.HasIndex("SeriesMetadatasId"); + + b.ToTable("GenreSeriesMetadata"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("ProviderKey") + .HasColumnType("TEXT"); + + b.Property("ProviderDisplayName") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("PersonSeriesMetadata", b => + { + b.Property("PeopleId") + .HasColumnType("INTEGER"); + + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.HasKey("PeopleId", "SeriesMetadatasId"); + + b.HasIndex("SeriesMetadatasId"); + + b.ToTable("PersonSeriesMetadata"); + }); + + modelBuilder.Entity("API.Entities.AppUserBookmark", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Bookmarks") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserPreferences", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithOne("UserPreferences") + .HasForeignKey("API.Entities.AppUserPreferences", "AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserProgress", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Progresses") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserRating", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Ratings") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserRole", b => + { + b.HasOne("API.Entities.AppRole", "Role") + .WithMany("UserRoles") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.AppUser", "User") + .WithMany("UserRoles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.HasOne("API.Entities.Genre", null) + .WithMany("Chapters") + .HasForeignKey("GenreId"); + + b.HasOne("API.Entities.Volume", "Volume") + .WithMany("Chapters") + .HasForeignKey("VolumeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Volume"); + }); + + modelBuilder.Entity("API.Entities.FolderPath", b => + { + b.HasOne("API.Entities.Library", "Library") + .WithMany("Folders") + .HasForeignKey("LibraryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Library"); + }); + + modelBuilder.Entity("API.Entities.MangaFile", b => + { + b.HasOne("API.Entities.Chapter", "Chapter") + .WithMany("Files") + .HasForeignKey("ChapterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Chapter"); + }); + + modelBuilder.Entity("API.Entities.Metadata.SeriesMetadata", b => + { + b.HasOne("API.Entities.Series", "Series") + .WithOne("Metadata") + .HasForeignKey("API.Entities.Metadata.SeriesMetadata", "SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("ReadingLists") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.ReadingListItem", b => + { + b.HasOne("API.Entities.Chapter", "Chapter") + .WithMany() + .HasForeignKey("ChapterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.ReadingList", "ReadingList") + .WithMany("Items") + .HasForeignKey("ReadingListId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Series", "Series") + .WithMany() + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Volume", "Volume") + .WithMany() + .HasForeignKey("VolumeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Chapter"); + + b.Navigation("ReadingList"); + + b.Navigation("Series"); + + b.Navigation("Volume"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.HasOne("API.Entities.Library", "Library") + .WithMany("Series") + .HasForeignKey("LibraryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Library"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.HasOne("API.Entities.Series", "Series") + .WithMany("Volumes") + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("AppUserLibrary", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("AppUsersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Library", null) + .WithMany() + .HasForeignKey("LibrariesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ChapterPerson", b => + { + b.HasOne("API.Entities.Chapter", null) + .WithMany() + .HasForeignKey("ChapterMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Person", null) + .WithMany() + .HasForeignKey("PeopleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("CollectionTagSeriesMetadata", b => + { + b.HasOne("API.Entities.CollectionTag", null) + .WithMany() + .HasForeignKey("CollectionTagsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Metadata.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("GenreSeriesMetadata", b => + { + b.HasOne("API.Entities.Genre", null) + .WithMany() + .HasForeignKey("GenresId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Metadata.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("API.Entities.AppRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("PersonSeriesMetadata", b => + { + b.HasOne("API.Entities.Person", null) + .WithMany() + .HasForeignKey("PeopleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Metadata.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("API.Entities.AppRole", b => + { + b.Navigation("UserRoles"); + }); + + modelBuilder.Entity("API.Entities.AppUser", b => + { + b.Navigation("Bookmarks"); + + b.Navigation("Progresses"); + + b.Navigation("Ratings"); + + b.Navigation("ReadingLists"); + + b.Navigation("UserPreferences"); + + b.Navigation("UserRoles"); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.Navigation("Files"); + }); + + modelBuilder.Entity("API.Entities.Genre", b => + { + b.Navigation("Chapters"); + }); + + modelBuilder.Entity("API.Entities.Library", b => + { + b.Navigation("Folders"); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.Navigation("Items"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.Navigation("Metadata"); + + b.Navigation("Volumes"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.Navigation("Chapters"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/API/Data/Migrations/20211201230003_GenreTitle.cs b/API/Data/Migrations/20211201230003_GenreTitle.cs new file mode 100644 index 000000000..ab3e65daf --- /dev/null +++ b/API/Data/Migrations/20211201230003_GenreTitle.cs @@ -0,0 +1,85 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace API.Data.Migrations +{ + public partial class GenreTitle : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "IX_Genre_NormalizedName", + table: "Genre"); + + migrationBuilder.RenameColumn( + name: "NormalizedName", + table: "Genre", + newName: "Title"); + + migrationBuilder.RenameColumn( + name: "Name", + table: "Genre", + newName: "NormalizedTitle"); + + migrationBuilder.AddColumn( + name: "GenreId", + table: "Chapter", + type: "INTEGER", + nullable: true); + + migrationBuilder.CreateIndex( + name: "IX_Genre_NormalizedTitle_ExternalTag", + table: "Genre", + columns: new[] { "NormalizedTitle", "ExternalTag" }, + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_Chapter_GenreId", + table: "Chapter", + column: "GenreId"); + + migrationBuilder.AddForeignKey( + name: "FK_Chapter_Genre_GenreId", + table: "Chapter", + column: "GenreId", + principalTable: "Genre", + principalColumn: "Id"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_Chapter_Genre_GenreId", + table: "Chapter"); + + migrationBuilder.DropIndex( + name: "IX_Genre_NormalizedTitle_ExternalTag", + table: "Genre"); + + migrationBuilder.DropIndex( + name: "IX_Chapter_GenreId", + table: "Chapter"); + + migrationBuilder.DropColumn( + name: "GenreId", + table: "Chapter"); + + migrationBuilder.RenameColumn( + name: "Title", + table: "Genre", + newName: "NormalizedName"); + + migrationBuilder.RenameColumn( + name: "NormalizedTitle", + table: "Genre", + newName: "Name"); + + migrationBuilder.CreateIndex( + name: "IX_Genre_NormalizedName", + table: "Genre", + column: "NormalizedName", + unique: true); + } + } +} diff --git a/API/Data/Migrations/20211205185207_MetadataAgeRating.Designer.cs b/API/Data/Migrations/20211205185207_MetadataAgeRating.Designer.cs new file mode 100644 index 000000000..58704e29d --- /dev/null +++ b/API/Data/Migrations/20211205185207_MetadataAgeRating.Designer.cs @@ -0,0 +1,1199 @@ +// +using System; +using API.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace API.Data.Migrations +{ + [DbContext(typeof(DataContext))] + [Migration("20211205185207_MetadataAgeRating")] + partial class MetadataAgeRating + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "6.0.0"); + + modelBuilder.Entity("API.Entities.AppRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("API.Entities.AppUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessFailedCount") + .HasColumnType("INTEGER"); + + b.Property("ApiKey") + .HasColumnType("TEXT"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("EmailConfirmed") + .HasColumnType("INTEGER"); + + b.Property("LastActive") + .HasColumnType("TEXT"); + + b.Property("LockoutEnabled") + .HasColumnType("INTEGER"); + + b.Property("LockoutEnd") + .HasColumnType("TEXT"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("PasswordHash") + .HasColumnType("TEXT"); + + b.Property("PhoneNumber") + .HasColumnType("TEXT"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SecurityStamp") + .HasColumnType("TEXT"); + + b.Property("TwoFactorEnabled") + .HasColumnType("INTEGER"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("API.Entities.AppUserBookmark", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("Page") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("AppUserBookmark"); + }); + + modelBuilder.Entity("API.Entities.AppUserPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("AutoCloseMenu") + .HasColumnType("INTEGER"); + + b.Property("BookReaderDarkMode") + .HasColumnType("INTEGER"); + + b.Property("BookReaderFontFamily") + .HasColumnType("TEXT"); + + b.Property("BookReaderFontSize") + .HasColumnType("INTEGER"); + + b.Property("BookReaderLineSpacing") + .HasColumnType("INTEGER"); + + b.Property("BookReaderMargin") + .HasColumnType("INTEGER"); + + b.Property("BookReaderReadingDirection") + .HasColumnType("INTEGER"); + + b.Property("BookReaderTapToPaginate") + .HasColumnType("INTEGER"); + + b.Property("PageSplitOption") + .HasColumnType("INTEGER"); + + b.Property("ReaderMode") + .HasColumnType("INTEGER"); + + b.Property("ReadingDirection") + .HasColumnType("INTEGER"); + + b.Property("ScalingOption") + .HasColumnType("INTEGER"); + + b.Property("SiteDarkMode") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId") + .IsUnique(); + + b.ToTable("AppUserPreferences"); + }); + + modelBuilder.Entity("API.Entities.AppUserProgress", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("BookScrollId") + .HasColumnType("TEXT"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("PagesRead") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("AppUserProgresses"); + }); + + modelBuilder.Entity("API.Entities.AppUserRating", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("Rating") + .HasColumnType("INTEGER"); + + b.Property("Review") + .HasColumnType("TEXT"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("AppUserRating"); + }); + + modelBuilder.Entity("API.Entities.AppUserRole", b => + { + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("GenreId") + .HasColumnType("INTEGER"); + + b.Property("IsSpecial") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Number") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("Range") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.Property("TitleName") + .HasColumnType("TEXT"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GenreId"); + + b.HasIndex("VolumeId"); + + b.ToTable("Chapter"); + }); + + modelBuilder.Entity("API.Entities.CollectionTag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("NormalizedTitle") + .HasColumnType("TEXT"); + + b.Property("Promoted") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Id", "Promoted") + .IsUnique(); + + b.ToTable("CollectionTag"); + }); + + modelBuilder.Entity("API.Entities.FolderPath", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("LastScanned") + .HasColumnType("TEXT"); + + b.Property("LibraryId") + .HasColumnType("INTEGER"); + + b.Property("Path") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("LibraryId"); + + b.ToTable("FolderPath"); + }); + + modelBuilder.Entity("API.Entities.Genre", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ExternalTag") + .HasColumnType("INTEGER"); + + b.Property("NormalizedTitle") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedTitle", "ExternalTag") + .IsUnique(); + + b.ToTable("Genre"); + }); + + modelBuilder.Entity("API.Entities.Library", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("LastScanned") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Library"); + }); + + modelBuilder.Entity("API.Entities.MangaFile", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("FilePath") + .HasColumnType("TEXT"); + + b.Property("Format") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ChapterId"); + + b.ToTable("MangaFile"); + }); + + modelBuilder.Entity("API.Entities.Metadata.SeriesMetadata", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AgeRating") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("SeriesId") + .IsUnique(); + + b.HasIndex("Id", "SeriesId") + .IsUnique(); + + b.ToTable("SeriesMetadata"); + }); + + modelBuilder.Entity("API.Entities.Person", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasColumnType("TEXT"); + + b.Property("Role") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Person"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Promoted") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("ReadingList"); + }); + + modelBuilder.Entity("API.Entities.ReadingListItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("Order") + .HasColumnType("INTEGER"); + + b.Property("ReadingListId") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ChapterId"); + + b.HasIndex("ReadingListId"); + + b.HasIndex("SeriesId"); + + b.HasIndex("VolumeId"); + + b.ToTable("ReadingListItem"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("Format") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("LibraryId") + .HasColumnType("INTEGER"); + + b.Property("LocalizedName") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasColumnType("TEXT"); + + b.Property("OriginalName") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("SortName") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("LibraryId"); + + b.HasIndex("Name", "NormalizedName", "LocalizedName", "LibraryId", "Format") + .IsUnique(); + + b.ToTable("Series"); + }); + + modelBuilder.Entity("API.Entities.ServerSetting", b => + { + b.Property("Key") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("Key"); + + b.ToTable("ServerSetting"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Number") + .HasColumnType("INTEGER"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("SeriesId"); + + b.ToTable("Volume"); + }); + + modelBuilder.Entity("AppUserLibrary", b => + { + b.Property("AppUsersId") + .HasColumnType("INTEGER"); + + b.Property("LibrariesId") + .HasColumnType("INTEGER"); + + b.HasKey("AppUsersId", "LibrariesId"); + + b.HasIndex("LibrariesId"); + + b.ToTable("AppUserLibrary"); + }); + + modelBuilder.Entity("ChapterPerson", b => + { + b.Property("ChapterMetadatasId") + .HasColumnType("INTEGER"); + + b.Property("PeopleId") + .HasColumnType("INTEGER"); + + b.HasKey("ChapterMetadatasId", "PeopleId"); + + b.HasIndex("PeopleId"); + + b.ToTable("ChapterPerson"); + }); + + modelBuilder.Entity("CollectionTagSeriesMetadata", b => + { + b.Property("CollectionTagsId") + .HasColumnType("INTEGER"); + + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.HasKey("CollectionTagsId", "SeriesMetadatasId"); + + b.HasIndex("SeriesMetadatasId"); + + b.ToTable("CollectionTagSeriesMetadata"); + }); + + modelBuilder.Entity("GenreSeriesMetadata", b => + { + b.Property("GenresId") + .HasColumnType("INTEGER"); + + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.HasKey("GenresId", "SeriesMetadatasId"); + + b.HasIndex("SeriesMetadatasId"); + + b.ToTable("GenreSeriesMetadata"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("ProviderKey") + .HasColumnType("TEXT"); + + b.Property("ProviderDisplayName") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("PersonSeriesMetadata", b => + { + b.Property("PeopleId") + .HasColumnType("INTEGER"); + + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.HasKey("PeopleId", "SeriesMetadatasId"); + + b.HasIndex("SeriesMetadatasId"); + + b.ToTable("PersonSeriesMetadata"); + }); + + modelBuilder.Entity("API.Entities.AppUserBookmark", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Bookmarks") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserPreferences", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithOne("UserPreferences") + .HasForeignKey("API.Entities.AppUserPreferences", "AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserProgress", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Progresses") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserRating", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Ratings") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserRole", b => + { + b.HasOne("API.Entities.AppRole", "Role") + .WithMany("UserRoles") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.AppUser", "User") + .WithMany("UserRoles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.HasOne("API.Entities.Genre", null) + .WithMany("Chapters") + .HasForeignKey("GenreId"); + + b.HasOne("API.Entities.Volume", "Volume") + .WithMany("Chapters") + .HasForeignKey("VolumeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Volume"); + }); + + modelBuilder.Entity("API.Entities.FolderPath", b => + { + b.HasOne("API.Entities.Library", "Library") + .WithMany("Folders") + .HasForeignKey("LibraryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Library"); + }); + + modelBuilder.Entity("API.Entities.MangaFile", b => + { + b.HasOne("API.Entities.Chapter", "Chapter") + .WithMany("Files") + .HasForeignKey("ChapterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Chapter"); + }); + + modelBuilder.Entity("API.Entities.Metadata.SeriesMetadata", b => + { + b.HasOne("API.Entities.Series", "Series") + .WithOne("Metadata") + .HasForeignKey("API.Entities.Metadata.SeriesMetadata", "SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("ReadingLists") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.ReadingListItem", b => + { + b.HasOne("API.Entities.Chapter", "Chapter") + .WithMany() + .HasForeignKey("ChapterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.ReadingList", "ReadingList") + .WithMany("Items") + .HasForeignKey("ReadingListId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Series", "Series") + .WithMany() + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Volume", "Volume") + .WithMany() + .HasForeignKey("VolumeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Chapter"); + + b.Navigation("ReadingList"); + + b.Navigation("Series"); + + b.Navigation("Volume"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.HasOne("API.Entities.Library", "Library") + .WithMany("Series") + .HasForeignKey("LibraryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Library"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.HasOne("API.Entities.Series", "Series") + .WithMany("Volumes") + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("AppUserLibrary", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("AppUsersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Library", null) + .WithMany() + .HasForeignKey("LibrariesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ChapterPerson", b => + { + b.HasOne("API.Entities.Chapter", null) + .WithMany() + .HasForeignKey("ChapterMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Person", null) + .WithMany() + .HasForeignKey("PeopleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("CollectionTagSeriesMetadata", b => + { + b.HasOne("API.Entities.CollectionTag", null) + .WithMany() + .HasForeignKey("CollectionTagsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Metadata.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("GenreSeriesMetadata", b => + { + b.HasOne("API.Entities.Genre", null) + .WithMany() + .HasForeignKey("GenresId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Metadata.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("API.Entities.AppRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("PersonSeriesMetadata", b => + { + b.HasOne("API.Entities.Person", null) + .WithMany() + .HasForeignKey("PeopleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Metadata.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("API.Entities.AppRole", b => + { + b.Navigation("UserRoles"); + }); + + modelBuilder.Entity("API.Entities.AppUser", b => + { + b.Navigation("Bookmarks"); + + b.Navigation("Progresses"); + + b.Navigation("Ratings"); + + b.Navigation("ReadingLists"); + + b.Navigation("UserPreferences"); + + b.Navigation("UserRoles"); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.Navigation("Files"); + }); + + modelBuilder.Entity("API.Entities.Genre", b => + { + b.Navigation("Chapters"); + }); + + modelBuilder.Entity("API.Entities.Library", b => + { + b.Navigation("Folders"); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.Navigation("Items"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.Navigation("Metadata"); + + b.Navigation("Volumes"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.Navigation("Chapters"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/API/Data/Migrations/20211205185207_MetadataAgeRating.cs b/API/Data/Migrations/20211205185207_MetadataAgeRating.cs new file mode 100644 index 000000000..8f03753f6 --- /dev/null +++ b/API/Data/Migrations/20211205185207_MetadataAgeRating.cs @@ -0,0 +1,26 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace API.Data.Migrations +{ + public partial class MetadataAgeRating : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "AgeRating", + table: "SeriesMetadata", + type: "INTEGER", + nullable: false, + defaultValue: 0); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "AgeRating", + table: "SeriesMetadata"); + } + } +} diff --git a/API/Data/Migrations/20211206193225_AgeRatingAndReleaseDate.Designer.cs b/API/Data/Migrations/20211206193225_AgeRatingAndReleaseDate.Designer.cs new file mode 100644 index 000000000..eade9e871 --- /dev/null +++ b/API/Data/Migrations/20211206193225_AgeRatingAndReleaseDate.Designer.cs @@ -0,0 +1,1208 @@ +// +using System; +using API.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace API.Data.Migrations +{ + [DbContext(typeof(DataContext))] + [Migration("20211206193225_AgeRatingAndReleaseDate")] + partial class AgeRatingAndReleaseDate + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "6.0.0"); + + modelBuilder.Entity("API.Entities.AppRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("API.Entities.AppUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessFailedCount") + .HasColumnType("INTEGER"); + + b.Property("ApiKey") + .HasColumnType("TEXT"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("EmailConfirmed") + .HasColumnType("INTEGER"); + + b.Property("LastActive") + .HasColumnType("TEXT"); + + b.Property("LockoutEnabled") + .HasColumnType("INTEGER"); + + b.Property("LockoutEnd") + .HasColumnType("TEXT"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("PasswordHash") + .HasColumnType("TEXT"); + + b.Property("PhoneNumber") + .HasColumnType("TEXT"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SecurityStamp") + .HasColumnType("TEXT"); + + b.Property("TwoFactorEnabled") + .HasColumnType("INTEGER"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("API.Entities.AppUserBookmark", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("Page") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("AppUserBookmark"); + }); + + modelBuilder.Entity("API.Entities.AppUserPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("AutoCloseMenu") + .HasColumnType("INTEGER"); + + b.Property("BookReaderDarkMode") + .HasColumnType("INTEGER"); + + b.Property("BookReaderFontFamily") + .HasColumnType("TEXT"); + + b.Property("BookReaderFontSize") + .HasColumnType("INTEGER"); + + b.Property("BookReaderLineSpacing") + .HasColumnType("INTEGER"); + + b.Property("BookReaderMargin") + .HasColumnType("INTEGER"); + + b.Property("BookReaderReadingDirection") + .HasColumnType("INTEGER"); + + b.Property("BookReaderTapToPaginate") + .HasColumnType("INTEGER"); + + b.Property("PageSplitOption") + .HasColumnType("INTEGER"); + + b.Property("ReaderMode") + .HasColumnType("INTEGER"); + + b.Property("ReadingDirection") + .HasColumnType("INTEGER"); + + b.Property("ScalingOption") + .HasColumnType("INTEGER"); + + b.Property("SiteDarkMode") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId") + .IsUnique(); + + b.ToTable("AppUserPreferences"); + }); + + modelBuilder.Entity("API.Entities.AppUserProgress", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("BookScrollId") + .HasColumnType("TEXT"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("PagesRead") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("AppUserProgresses"); + }); + + modelBuilder.Entity("API.Entities.AppUserRating", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("Rating") + .HasColumnType("INTEGER"); + + b.Property("Review") + .HasColumnType("TEXT"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("AppUserRating"); + }); + + modelBuilder.Entity("API.Entities.AppUserRole", b => + { + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AgeRating") + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("GenreId") + .HasColumnType("INTEGER"); + + b.Property("IsSpecial") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Number") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("Range") + .HasColumnType("TEXT"); + + b.Property("ReleaseDate") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.Property("TitleName") + .HasColumnType("TEXT"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GenreId"); + + b.HasIndex("VolumeId"); + + b.ToTable("Chapter"); + }); + + modelBuilder.Entity("API.Entities.CollectionTag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("NormalizedTitle") + .HasColumnType("TEXT"); + + b.Property("Promoted") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Id", "Promoted") + .IsUnique(); + + b.ToTable("CollectionTag"); + }); + + modelBuilder.Entity("API.Entities.FolderPath", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("LastScanned") + .HasColumnType("TEXT"); + + b.Property("LibraryId") + .HasColumnType("INTEGER"); + + b.Property("Path") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("LibraryId"); + + b.ToTable("FolderPath"); + }); + + modelBuilder.Entity("API.Entities.Genre", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ExternalTag") + .HasColumnType("INTEGER"); + + b.Property("NormalizedTitle") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedTitle", "ExternalTag") + .IsUnique(); + + b.ToTable("Genre"); + }); + + modelBuilder.Entity("API.Entities.Library", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("LastScanned") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Library"); + }); + + modelBuilder.Entity("API.Entities.MangaFile", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("FilePath") + .HasColumnType("TEXT"); + + b.Property("Format") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ChapterId"); + + b.ToTable("MangaFile"); + }); + + modelBuilder.Entity("API.Entities.Metadata.SeriesMetadata", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AgeRating") + .HasColumnType("INTEGER"); + + b.Property("ReleaseYear") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("SeriesId") + .IsUnique(); + + b.HasIndex("Id", "SeriesId") + .IsUnique(); + + b.ToTable("SeriesMetadata"); + }); + + modelBuilder.Entity("API.Entities.Person", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasColumnType("TEXT"); + + b.Property("Role") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Person"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Promoted") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("ReadingList"); + }); + + modelBuilder.Entity("API.Entities.ReadingListItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("Order") + .HasColumnType("INTEGER"); + + b.Property("ReadingListId") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ChapterId"); + + b.HasIndex("ReadingListId"); + + b.HasIndex("SeriesId"); + + b.HasIndex("VolumeId"); + + b.ToTable("ReadingListItem"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("Format") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("LibraryId") + .HasColumnType("INTEGER"); + + b.Property("LocalizedName") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasColumnType("TEXT"); + + b.Property("OriginalName") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("SortName") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("LibraryId"); + + b.HasIndex("Name", "NormalizedName", "LocalizedName", "LibraryId", "Format") + .IsUnique(); + + b.ToTable("Series"); + }); + + modelBuilder.Entity("API.Entities.ServerSetting", b => + { + b.Property("Key") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("Key"); + + b.ToTable("ServerSetting"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Number") + .HasColumnType("INTEGER"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("SeriesId"); + + b.ToTable("Volume"); + }); + + modelBuilder.Entity("AppUserLibrary", b => + { + b.Property("AppUsersId") + .HasColumnType("INTEGER"); + + b.Property("LibrariesId") + .HasColumnType("INTEGER"); + + b.HasKey("AppUsersId", "LibrariesId"); + + b.HasIndex("LibrariesId"); + + b.ToTable("AppUserLibrary"); + }); + + modelBuilder.Entity("ChapterPerson", b => + { + b.Property("ChapterMetadatasId") + .HasColumnType("INTEGER"); + + b.Property("PeopleId") + .HasColumnType("INTEGER"); + + b.HasKey("ChapterMetadatasId", "PeopleId"); + + b.HasIndex("PeopleId"); + + b.ToTable("ChapterPerson"); + }); + + modelBuilder.Entity("CollectionTagSeriesMetadata", b => + { + b.Property("CollectionTagsId") + .HasColumnType("INTEGER"); + + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.HasKey("CollectionTagsId", "SeriesMetadatasId"); + + b.HasIndex("SeriesMetadatasId"); + + b.ToTable("CollectionTagSeriesMetadata"); + }); + + modelBuilder.Entity("GenreSeriesMetadata", b => + { + b.Property("GenresId") + .HasColumnType("INTEGER"); + + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.HasKey("GenresId", "SeriesMetadatasId"); + + b.HasIndex("SeriesMetadatasId"); + + b.ToTable("GenreSeriesMetadata"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("ProviderKey") + .HasColumnType("TEXT"); + + b.Property("ProviderDisplayName") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("PersonSeriesMetadata", b => + { + b.Property("PeopleId") + .HasColumnType("INTEGER"); + + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.HasKey("PeopleId", "SeriesMetadatasId"); + + b.HasIndex("SeriesMetadatasId"); + + b.ToTable("PersonSeriesMetadata"); + }); + + modelBuilder.Entity("API.Entities.AppUserBookmark", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Bookmarks") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserPreferences", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithOne("UserPreferences") + .HasForeignKey("API.Entities.AppUserPreferences", "AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserProgress", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Progresses") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserRating", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Ratings") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserRole", b => + { + b.HasOne("API.Entities.AppRole", "Role") + .WithMany("UserRoles") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.AppUser", "User") + .WithMany("UserRoles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.HasOne("API.Entities.Genre", null) + .WithMany("Chapters") + .HasForeignKey("GenreId"); + + b.HasOne("API.Entities.Volume", "Volume") + .WithMany("Chapters") + .HasForeignKey("VolumeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Volume"); + }); + + modelBuilder.Entity("API.Entities.FolderPath", b => + { + b.HasOne("API.Entities.Library", "Library") + .WithMany("Folders") + .HasForeignKey("LibraryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Library"); + }); + + modelBuilder.Entity("API.Entities.MangaFile", b => + { + b.HasOne("API.Entities.Chapter", "Chapter") + .WithMany("Files") + .HasForeignKey("ChapterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Chapter"); + }); + + modelBuilder.Entity("API.Entities.Metadata.SeriesMetadata", b => + { + b.HasOne("API.Entities.Series", "Series") + .WithOne("Metadata") + .HasForeignKey("API.Entities.Metadata.SeriesMetadata", "SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("ReadingLists") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.ReadingListItem", b => + { + b.HasOne("API.Entities.Chapter", "Chapter") + .WithMany() + .HasForeignKey("ChapterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.ReadingList", "ReadingList") + .WithMany("Items") + .HasForeignKey("ReadingListId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Series", "Series") + .WithMany() + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Volume", "Volume") + .WithMany() + .HasForeignKey("VolumeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Chapter"); + + b.Navigation("ReadingList"); + + b.Navigation("Series"); + + b.Navigation("Volume"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.HasOne("API.Entities.Library", "Library") + .WithMany("Series") + .HasForeignKey("LibraryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Library"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.HasOne("API.Entities.Series", "Series") + .WithMany("Volumes") + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("AppUserLibrary", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("AppUsersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Library", null) + .WithMany() + .HasForeignKey("LibrariesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ChapterPerson", b => + { + b.HasOne("API.Entities.Chapter", null) + .WithMany() + .HasForeignKey("ChapterMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Person", null) + .WithMany() + .HasForeignKey("PeopleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("CollectionTagSeriesMetadata", b => + { + b.HasOne("API.Entities.CollectionTag", null) + .WithMany() + .HasForeignKey("CollectionTagsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Metadata.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("GenreSeriesMetadata", b => + { + b.HasOne("API.Entities.Genre", null) + .WithMany() + .HasForeignKey("GenresId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Metadata.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("API.Entities.AppRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("PersonSeriesMetadata", b => + { + b.HasOne("API.Entities.Person", null) + .WithMany() + .HasForeignKey("PeopleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Metadata.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("API.Entities.AppRole", b => + { + b.Navigation("UserRoles"); + }); + + modelBuilder.Entity("API.Entities.AppUser", b => + { + b.Navigation("Bookmarks"); + + b.Navigation("Progresses"); + + b.Navigation("Ratings"); + + b.Navigation("ReadingLists"); + + b.Navigation("UserPreferences"); + + b.Navigation("UserRoles"); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.Navigation("Files"); + }); + + modelBuilder.Entity("API.Entities.Genre", b => + { + b.Navigation("Chapters"); + }); + + modelBuilder.Entity("API.Entities.Library", b => + { + b.Navigation("Folders"); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.Navigation("Items"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.Navigation("Metadata"); + + b.Navigation("Volumes"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.Navigation("Chapters"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/API/Data/Migrations/20211206193225_AgeRatingAndReleaseDate.cs b/API/Data/Migrations/20211206193225_AgeRatingAndReleaseDate.cs new file mode 100644 index 000000000..76a7f05c6 --- /dev/null +++ b/API/Data/Migrations/20211206193225_AgeRatingAndReleaseDate.cs @@ -0,0 +1,49 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace API.Data.Migrations +{ + public partial class AgeRatingAndReleaseDate : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "ReleaseYear", + table: "SeriesMetadata", + type: "INTEGER", + nullable: false, + defaultValue: 0); + + migrationBuilder.AddColumn( + name: "AgeRating", + table: "Chapter", + type: "INTEGER", + nullable: false, + defaultValue: 0); + + migrationBuilder.AddColumn( + name: "ReleaseDate", + table: "Chapter", + type: "TEXT", + nullable: false, + defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified)); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "ReleaseYear", + table: "SeriesMetadata"); + + migrationBuilder.DropColumn( + name: "AgeRating", + table: "Chapter"); + + migrationBuilder.DropColumn( + name: "ReleaseDate", + table: "Chapter"); + } + } +} diff --git a/API/Data/Migrations/20211217013734_BookmarkRefactor.Designer.cs b/API/Data/Migrations/20211217013734_BookmarkRefactor.Designer.cs new file mode 100644 index 000000000..5db4111f6 --- /dev/null +++ b/API/Data/Migrations/20211217013734_BookmarkRefactor.Designer.cs @@ -0,0 +1,1317 @@ +// +using System; +using API.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace API.Data.Migrations +{ + [DbContext(typeof(DataContext))] + [Migration("20211217013734_BookmarkRefactor")] + partial class BookmarkRefactor + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "6.0.1"); + + modelBuilder.Entity("API.Entities.AppRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("API.Entities.AppUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessFailedCount") + .HasColumnType("INTEGER"); + + b.Property("ApiKey") + .HasColumnType("TEXT"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("EmailConfirmed") + .HasColumnType("INTEGER"); + + b.Property("LastActive") + .HasColumnType("TEXT"); + + b.Property("LockoutEnabled") + .HasColumnType("INTEGER"); + + b.Property("LockoutEnd") + .HasColumnType("TEXT"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("PasswordHash") + .HasColumnType("TEXT"); + + b.Property("PhoneNumber") + .HasColumnType("TEXT"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SecurityStamp") + .HasColumnType("TEXT"); + + b.Property("TwoFactorEnabled") + .HasColumnType("INTEGER"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("API.Entities.AppUserBookmark", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("FileName") + .HasColumnType("TEXT"); + + b.Property("Page") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("AppUserBookmark"); + }); + + modelBuilder.Entity("API.Entities.AppUserPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("AutoCloseMenu") + .HasColumnType("INTEGER"); + + b.Property("BookReaderDarkMode") + .HasColumnType("INTEGER"); + + b.Property("BookReaderFontFamily") + .HasColumnType("TEXT"); + + b.Property("BookReaderFontSize") + .HasColumnType("INTEGER"); + + b.Property("BookReaderLineSpacing") + .HasColumnType("INTEGER"); + + b.Property("BookReaderMargin") + .HasColumnType("INTEGER"); + + b.Property("BookReaderReadingDirection") + .HasColumnType("INTEGER"); + + b.Property("BookReaderTapToPaginate") + .HasColumnType("INTEGER"); + + b.Property("PageSplitOption") + .HasColumnType("INTEGER"); + + b.Property("ReaderMode") + .HasColumnType("INTEGER"); + + b.Property("ReadingDirection") + .HasColumnType("INTEGER"); + + b.Property("ScalingOption") + .HasColumnType("INTEGER"); + + b.Property("SiteDarkMode") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId") + .IsUnique(); + + b.ToTable("AppUserPreferences"); + }); + + modelBuilder.Entity("API.Entities.AppUserProgress", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("BookScrollId") + .HasColumnType("TEXT"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("PagesRead") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.HasIndex("SeriesId"); + + b.ToTable("AppUserProgresses"); + }); + + modelBuilder.Entity("API.Entities.AppUserRating", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("Rating") + .HasColumnType("INTEGER"); + + b.Property("Review") + .HasColumnType("TEXT"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.HasIndex("SeriesId"); + + b.ToTable("AppUserRating"); + }); + + modelBuilder.Entity("API.Entities.AppUserRole", b => + { + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AgeRating") + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("GenreId") + .HasColumnType("INTEGER"); + + b.Property("IsSpecial") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Number") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("Range") + .HasColumnType("TEXT"); + + b.Property("ReleaseDate") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.Property("TitleName") + .HasColumnType("TEXT"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GenreId"); + + b.HasIndex("VolumeId"); + + b.ToTable("Chapter"); + }); + + modelBuilder.Entity("API.Entities.CollectionTag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("NormalizedTitle") + .HasColumnType("TEXT"); + + b.Property("Promoted") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Id", "Promoted") + .IsUnique(); + + b.ToTable("CollectionTag"); + }); + + modelBuilder.Entity("API.Entities.FolderPath", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("LastScanned") + .HasColumnType("TEXT"); + + b.Property("LibraryId") + .HasColumnType("INTEGER"); + + b.Property("Path") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("LibraryId"); + + b.ToTable("FolderPath"); + }); + + modelBuilder.Entity("API.Entities.Genre", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ExternalTag") + .HasColumnType("INTEGER"); + + b.Property("NormalizedTitle") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedTitle", "ExternalTag") + .IsUnique(); + + b.ToTable("Genre"); + }); + + modelBuilder.Entity("API.Entities.Library", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("LastScanned") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Library"); + }); + + modelBuilder.Entity("API.Entities.MangaFile", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("FilePath") + .HasColumnType("TEXT"); + + b.Property("Format") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ChapterId"); + + b.ToTable("MangaFile"); + }); + + modelBuilder.Entity("API.Entities.Metadata.SeriesMetadata", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AgeRating") + .HasColumnType("INTEGER"); + + b.Property("Language") + .HasColumnType("TEXT"); + + b.Property("ReleaseYear") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("SeriesId") + .IsUnique(); + + b.HasIndex("Id", "SeriesId") + .IsUnique(); + + b.ToTable("SeriesMetadata"); + }); + + modelBuilder.Entity("API.Entities.Person", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasColumnType("TEXT"); + + b.Property("Role") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Person"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Promoted") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("ReadingList"); + }); + + modelBuilder.Entity("API.Entities.ReadingListItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("Order") + .HasColumnType("INTEGER"); + + b.Property("ReadingListId") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ChapterId"); + + b.HasIndex("ReadingListId"); + + b.HasIndex("SeriesId"); + + b.HasIndex("VolumeId"); + + b.ToTable("ReadingListItem"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("Format") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("LibraryId") + .HasColumnType("INTEGER"); + + b.Property("LocalizedName") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasColumnType("TEXT"); + + b.Property("OriginalName") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("SortName") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("LibraryId"); + + b.HasIndex("Name", "NormalizedName", "LocalizedName", "LibraryId", "Format") + .IsUnique(); + + b.ToTable("Series"); + }); + + modelBuilder.Entity("API.Entities.ServerSetting", b => + { + b.Property("Key") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("Key"); + + b.ToTable("ServerSetting"); + }); + + modelBuilder.Entity("API.Entities.Tag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ExternalTag") + .HasColumnType("INTEGER"); + + b.Property("NormalizedTitle") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedTitle", "ExternalTag") + .IsUnique(); + + b.ToTable("Tag"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Number") + .HasColumnType("INTEGER"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("SeriesId"); + + b.ToTable("Volume"); + }); + + modelBuilder.Entity("AppUserLibrary", b => + { + b.Property("AppUsersId") + .HasColumnType("INTEGER"); + + b.Property("LibrariesId") + .HasColumnType("INTEGER"); + + b.HasKey("AppUsersId", "LibrariesId"); + + b.HasIndex("LibrariesId"); + + b.ToTable("AppUserLibrary"); + }); + + modelBuilder.Entity("ChapterPerson", b => + { + b.Property("ChapterMetadatasId") + .HasColumnType("INTEGER"); + + b.Property("PeopleId") + .HasColumnType("INTEGER"); + + b.HasKey("ChapterMetadatasId", "PeopleId"); + + b.HasIndex("PeopleId"); + + b.ToTable("ChapterPerson"); + }); + + modelBuilder.Entity("ChapterTag", b => + { + b.Property("ChaptersId") + .HasColumnType("INTEGER"); + + b.Property("TagsId") + .HasColumnType("INTEGER"); + + b.HasKey("ChaptersId", "TagsId"); + + b.HasIndex("TagsId"); + + b.ToTable("ChapterTag"); + }); + + modelBuilder.Entity("CollectionTagSeriesMetadata", b => + { + b.Property("CollectionTagsId") + .HasColumnType("INTEGER"); + + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.HasKey("CollectionTagsId", "SeriesMetadatasId"); + + b.HasIndex("SeriesMetadatasId"); + + b.ToTable("CollectionTagSeriesMetadata"); + }); + + modelBuilder.Entity("GenreSeriesMetadata", b => + { + b.Property("GenresId") + .HasColumnType("INTEGER"); + + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.HasKey("GenresId", "SeriesMetadatasId"); + + b.HasIndex("SeriesMetadatasId"); + + b.ToTable("GenreSeriesMetadata"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("ProviderKey") + .HasColumnType("TEXT"); + + b.Property("ProviderDisplayName") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("PersonSeriesMetadata", b => + { + b.Property("PeopleId") + .HasColumnType("INTEGER"); + + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.HasKey("PeopleId", "SeriesMetadatasId"); + + b.HasIndex("SeriesMetadatasId"); + + b.ToTable("PersonSeriesMetadata"); + }); + + modelBuilder.Entity("SeriesMetadataTag", b => + { + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.Property("TagsId") + .HasColumnType("INTEGER"); + + b.HasKey("SeriesMetadatasId", "TagsId"); + + b.HasIndex("TagsId"); + + b.ToTable("SeriesMetadataTag"); + }); + + modelBuilder.Entity("API.Entities.AppUserBookmark", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Bookmarks") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserPreferences", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithOne("UserPreferences") + .HasForeignKey("API.Entities.AppUserPreferences", "AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserProgress", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Progresses") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Series", null) + .WithMany("Progress") + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserRating", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Ratings") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Series", null) + .WithMany("Ratings") + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserRole", b => + { + b.HasOne("API.Entities.AppRole", "Role") + .WithMany("UserRoles") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.AppUser", "User") + .WithMany("UserRoles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.HasOne("API.Entities.Genre", null) + .WithMany("Chapters") + .HasForeignKey("GenreId"); + + b.HasOne("API.Entities.Volume", "Volume") + .WithMany("Chapters") + .HasForeignKey("VolumeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Volume"); + }); + + modelBuilder.Entity("API.Entities.FolderPath", b => + { + b.HasOne("API.Entities.Library", "Library") + .WithMany("Folders") + .HasForeignKey("LibraryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Library"); + }); + + modelBuilder.Entity("API.Entities.MangaFile", b => + { + b.HasOne("API.Entities.Chapter", "Chapter") + .WithMany("Files") + .HasForeignKey("ChapterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Chapter"); + }); + + modelBuilder.Entity("API.Entities.Metadata.SeriesMetadata", b => + { + b.HasOne("API.Entities.Series", "Series") + .WithOne("Metadata") + .HasForeignKey("API.Entities.Metadata.SeriesMetadata", "SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("ReadingLists") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.ReadingListItem", b => + { + b.HasOne("API.Entities.Chapter", "Chapter") + .WithMany() + .HasForeignKey("ChapterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.ReadingList", "ReadingList") + .WithMany("Items") + .HasForeignKey("ReadingListId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Series", "Series") + .WithMany() + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Volume", "Volume") + .WithMany() + .HasForeignKey("VolumeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Chapter"); + + b.Navigation("ReadingList"); + + b.Navigation("Series"); + + b.Navigation("Volume"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.HasOne("API.Entities.Library", "Library") + .WithMany("Series") + .HasForeignKey("LibraryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Library"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.HasOne("API.Entities.Series", "Series") + .WithMany("Volumes") + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("AppUserLibrary", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("AppUsersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Library", null) + .WithMany() + .HasForeignKey("LibrariesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ChapterPerson", b => + { + b.HasOne("API.Entities.Chapter", null) + .WithMany() + .HasForeignKey("ChapterMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Person", null) + .WithMany() + .HasForeignKey("PeopleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ChapterTag", b => + { + b.HasOne("API.Entities.Chapter", null) + .WithMany() + .HasForeignKey("ChaptersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Tag", null) + .WithMany() + .HasForeignKey("TagsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("CollectionTagSeriesMetadata", b => + { + b.HasOne("API.Entities.CollectionTag", null) + .WithMany() + .HasForeignKey("CollectionTagsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Metadata.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("GenreSeriesMetadata", b => + { + b.HasOne("API.Entities.Genre", null) + .WithMany() + .HasForeignKey("GenresId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Metadata.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("API.Entities.AppRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("PersonSeriesMetadata", b => + { + b.HasOne("API.Entities.Person", null) + .WithMany() + .HasForeignKey("PeopleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Metadata.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("SeriesMetadataTag", b => + { + b.HasOne("API.Entities.Metadata.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Tag", null) + .WithMany() + .HasForeignKey("TagsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("API.Entities.AppRole", b => + { + b.Navigation("UserRoles"); + }); + + modelBuilder.Entity("API.Entities.AppUser", b => + { + b.Navigation("Bookmarks"); + + b.Navigation("Progresses"); + + b.Navigation("Ratings"); + + b.Navigation("ReadingLists"); + + b.Navigation("UserPreferences"); + + b.Navigation("UserRoles"); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.Navigation("Files"); + }); + + modelBuilder.Entity("API.Entities.Genre", b => + { + b.Navigation("Chapters"); + }); + + modelBuilder.Entity("API.Entities.Library", b => + { + b.Navigation("Folders"); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.Navigation("Items"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.Navigation("Metadata"); + + b.Navigation("Progress"); + + b.Navigation("Ratings"); + + b.Navigation("Volumes"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.Navigation("Chapters"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/API/Data/Migrations/20211217013734_BookmarkRefactor.cs b/API/Data/Migrations/20211217013734_BookmarkRefactor.cs new file mode 100644 index 000000000..7ac831e07 --- /dev/null +++ b/API/Data/Migrations/20211217013734_BookmarkRefactor.cs @@ -0,0 +1,25 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace API.Data.Migrations +{ + public partial class BookmarkRefactor : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "FileName", + table: "AppUserBookmark", + type: "TEXT", + nullable: true); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "FileName", + table: "AppUserBookmark"); + } + } +} diff --git a/API/Data/Migrations/20211217180457_filteringChanges.Designer.cs b/API/Data/Migrations/20211217180457_filteringChanges.Designer.cs new file mode 100644 index 000000000..39377a6c3 --- /dev/null +++ b/API/Data/Migrations/20211217180457_filteringChanges.Designer.cs @@ -0,0 +1,1314 @@ +// +using System; +using API.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace API.Data.Migrations +{ + [DbContext(typeof(DataContext))] + [Migration("20211217180457_filteringChanges")] + partial class filteringChanges + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "6.0.0"); + + modelBuilder.Entity("API.Entities.AppRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("API.Entities.AppUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessFailedCount") + .HasColumnType("INTEGER"); + + b.Property("ApiKey") + .HasColumnType("TEXT"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("EmailConfirmed") + .HasColumnType("INTEGER"); + + b.Property("LastActive") + .HasColumnType("TEXT"); + + b.Property("LockoutEnabled") + .HasColumnType("INTEGER"); + + b.Property("LockoutEnd") + .HasColumnType("TEXT"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("PasswordHash") + .HasColumnType("TEXT"); + + b.Property("PhoneNumber") + .HasColumnType("TEXT"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SecurityStamp") + .HasColumnType("TEXT"); + + b.Property("TwoFactorEnabled") + .HasColumnType("INTEGER"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("API.Entities.AppUserBookmark", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("Page") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("AppUserBookmark"); + }); + + modelBuilder.Entity("API.Entities.AppUserPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("AutoCloseMenu") + .HasColumnType("INTEGER"); + + b.Property("BookReaderDarkMode") + .HasColumnType("INTEGER"); + + b.Property("BookReaderFontFamily") + .HasColumnType("TEXT"); + + b.Property("BookReaderFontSize") + .HasColumnType("INTEGER"); + + b.Property("BookReaderLineSpacing") + .HasColumnType("INTEGER"); + + b.Property("BookReaderMargin") + .HasColumnType("INTEGER"); + + b.Property("BookReaderReadingDirection") + .HasColumnType("INTEGER"); + + b.Property("BookReaderTapToPaginate") + .HasColumnType("INTEGER"); + + b.Property("PageSplitOption") + .HasColumnType("INTEGER"); + + b.Property("ReaderMode") + .HasColumnType("INTEGER"); + + b.Property("ReadingDirection") + .HasColumnType("INTEGER"); + + b.Property("ScalingOption") + .HasColumnType("INTEGER"); + + b.Property("SiteDarkMode") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId") + .IsUnique(); + + b.ToTable("AppUserPreferences"); + }); + + modelBuilder.Entity("API.Entities.AppUserProgress", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("BookScrollId") + .HasColumnType("TEXT"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("PagesRead") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.HasIndex("SeriesId"); + + b.ToTable("AppUserProgresses"); + }); + + modelBuilder.Entity("API.Entities.AppUserRating", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("Rating") + .HasColumnType("INTEGER"); + + b.Property("Review") + .HasColumnType("TEXT"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.HasIndex("SeriesId"); + + b.ToTable("AppUserRating"); + }); + + modelBuilder.Entity("API.Entities.AppUserRole", b => + { + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AgeRating") + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("GenreId") + .HasColumnType("INTEGER"); + + b.Property("IsSpecial") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Number") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("Range") + .HasColumnType("TEXT"); + + b.Property("ReleaseDate") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.Property("TitleName") + .HasColumnType("TEXT"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GenreId"); + + b.HasIndex("VolumeId"); + + b.ToTable("Chapter"); + }); + + modelBuilder.Entity("API.Entities.CollectionTag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("NormalizedTitle") + .HasColumnType("TEXT"); + + b.Property("Promoted") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Id", "Promoted") + .IsUnique(); + + b.ToTable("CollectionTag"); + }); + + modelBuilder.Entity("API.Entities.FolderPath", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("LastScanned") + .HasColumnType("TEXT"); + + b.Property("LibraryId") + .HasColumnType("INTEGER"); + + b.Property("Path") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("LibraryId"); + + b.ToTable("FolderPath"); + }); + + modelBuilder.Entity("API.Entities.Genre", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ExternalTag") + .HasColumnType("INTEGER"); + + b.Property("NormalizedTitle") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedTitle", "ExternalTag") + .IsUnique(); + + b.ToTable("Genre"); + }); + + modelBuilder.Entity("API.Entities.Library", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("LastScanned") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Library"); + }); + + modelBuilder.Entity("API.Entities.MangaFile", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("FilePath") + .HasColumnType("TEXT"); + + b.Property("Format") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ChapterId"); + + b.ToTable("MangaFile"); + }); + + modelBuilder.Entity("API.Entities.Metadata.SeriesMetadata", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AgeRating") + .HasColumnType("INTEGER"); + + b.Property("Language") + .HasColumnType("TEXT"); + + b.Property("ReleaseYear") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("SeriesId") + .IsUnique(); + + b.HasIndex("Id", "SeriesId") + .IsUnique(); + + b.ToTable("SeriesMetadata"); + }); + + modelBuilder.Entity("API.Entities.Person", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasColumnType("TEXT"); + + b.Property("Role") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Person"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Promoted") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("ReadingList"); + }); + + modelBuilder.Entity("API.Entities.ReadingListItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("Order") + .HasColumnType("INTEGER"); + + b.Property("ReadingListId") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ChapterId"); + + b.HasIndex("ReadingListId"); + + b.HasIndex("SeriesId"); + + b.HasIndex("VolumeId"); + + b.ToTable("ReadingListItem"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("Format") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("LibraryId") + .HasColumnType("INTEGER"); + + b.Property("LocalizedName") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasColumnType("TEXT"); + + b.Property("OriginalName") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("SortName") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("LibraryId"); + + b.HasIndex("Name", "NormalizedName", "LocalizedName", "LibraryId", "Format") + .IsUnique(); + + b.ToTable("Series"); + }); + + modelBuilder.Entity("API.Entities.ServerSetting", b => + { + b.Property("Key") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("Key"); + + b.ToTable("ServerSetting"); + }); + + modelBuilder.Entity("API.Entities.Tag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ExternalTag") + .HasColumnType("INTEGER"); + + b.Property("NormalizedTitle") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedTitle", "ExternalTag") + .IsUnique(); + + b.ToTable("Tag"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Number") + .HasColumnType("INTEGER"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("SeriesId"); + + b.ToTable("Volume"); + }); + + modelBuilder.Entity("AppUserLibrary", b => + { + b.Property("AppUsersId") + .HasColumnType("INTEGER"); + + b.Property("LibrariesId") + .HasColumnType("INTEGER"); + + b.HasKey("AppUsersId", "LibrariesId"); + + b.HasIndex("LibrariesId"); + + b.ToTable("AppUserLibrary"); + }); + + modelBuilder.Entity("ChapterPerson", b => + { + b.Property("ChapterMetadatasId") + .HasColumnType("INTEGER"); + + b.Property("PeopleId") + .HasColumnType("INTEGER"); + + b.HasKey("ChapterMetadatasId", "PeopleId"); + + b.HasIndex("PeopleId"); + + b.ToTable("ChapterPerson"); + }); + + modelBuilder.Entity("ChapterTag", b => + { + b.Property("ChaptersId") + .HasColumnType("INTEGER"); + + b.Property("TagsId") + .HasColumnType("INTEGER"); + + b.HasKey("ChaptersId", "TagsId"); + + b.HasIndex("TagsId"); + + b.ToTable("ChapterTag"); + }); + + modelBuilder.Entity("CollectionTagSeriesMetadata", b => + { + b.Property("CollectionTagsId") + .HasColumnType("INTEGER"); + + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.HasKey("CollectionTagsId", "SeriesMetadatasId"); + + b.HasIndex("SeriesMetadatasId"); + + b.ToTable("CollectionTagSeriesMetadata"); + }); + + modelBuilder.Entity("GenreSeriesMetadata", b => + { + b.Property("GenresId") + .HasColumnType("INTEGER"); + + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.HasKey("GenresId", "SeriesMetadatasId"); + + b.HasIndex("SeriesMetadatasId"); + + b.ToTable("GenreSeriesMetadata"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("ProviderKey") + .HasColumnType("TEXT"); + + b.Property("ProviderDisplayName") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("PersonSeriesMetadata", b => + { + b.Property("PeopleId") + .HasColumnType("INTEGER"); + + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.HasKey("PeopleId", "SeriesMetadatasId"); + + b.HasIndex("SeriesMetadatasId"); + + b.ToTable("PersonSeriesMetadata"); + }); + + modelBuilder.Entity("SeriesMetadataTag", b => + { + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.Property("TagsId") + .HasColumnType("INTEGER"); + + b.HasKey("SeriesMetadatasId", "TagsId"); + + b.HasIndex("TagsId"); + + b.ToTable("SeriesMetadataTag"); + }); + + modelBuilder.Entity("API.Entities.AppUserBookmark", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Bookmarks") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserPreferences", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithOne("UserPreferences") + .HasForeignKey("API.Entities.AppUserPreferences", "AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserProgress", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Progresses") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Series", null) + .WithMany("Progress") + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserRating", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Ratings") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Series", null) + .WithMany("Ratings") + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserRole", b => + { + b.HasOne("API.Entities.AppRole", "Role") + .WithMany("UserRoles") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.AppUser", "User") + .WithMany("UserRoles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.HasOne("API.Entities.Genre", null) + .WithMany("Chapters") + .HasForeignKey("GenreId"); + + b.HasOne("API.Entities.Volume", "Volume") + .WithMany("Chapters") + .HasForeignKey("VolumeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Volume"); + }); + + modelBuilder.Entity("API.Entities.FolderPath", b => + { + b.HasOne("API.Entities.Library", "Library") + .WithMany("Folders") + .HasForeignKey("LibraryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Library"); + }); + + modelBuilder.Entity("API.Entities.MangaFile", b => + { + b.HasOne("API.Entities.Chapter", "Chapter") + .WithMany("Files") + .HasForeignKey("ChapterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Chapter"); + }); + + modelBuilder.Entity("API.Entities.Metadata.SeriesMetadata", b => + { + b.HasOne("API.Entities.Series", "Series") + .WithOne("Metadata") + .HasForeignKey("API.Entities.Metadata.SeriesMetadata", "SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("ReadingLists") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.ReadingListItem", b => + { + b.HasOne("API.Entities.Chapter", "Chapter") + .WithMany() + .HasForeignKey("ChapterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.ReadingList", "ReadingList") + .WithMany("Items") + .HasForeignKey("ReadingListId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Series", "Series") + .WithMany() + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Volume", "Volume") + .WithMany() + .HasForeignKey("VolumeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Chapter"); + + b.Navigation("ReadingList"); + + b.Navigation("Series"); + + b.Navigation("Volume"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.HasOne("API.Entities.Library", "Library") + .WithMany("Series") + .HasForeignKey("LibraryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Library"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.HasOne("API.Entities.Series", "Series") + .WithMany("Volumes") + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("AppUserLibrary", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("AppUsersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Library", null) + .WithMany() + .HasForeignKey("LibrariesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ChapterPerson", b => + { + b.HasOne("API.Entities.Chapter", null) + .WithMany() + .HasForeignKey("ChapterMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Person", null) + .WithMany() + .HasForeignKey("PeopleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ChapterTag", b => + { + b.HasOne("API.Entities.Chapter", null) + .WithMany() + .HasForeignKey("ChaptersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Tag", null) + .WithMany() + .HasForeignKey("TagsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("CollectionTagSeriesMetadata", b => + { + b.HasOne("API.Entities.CollectionTag", null) + .WithMany() + .HasForeignKey("CollectionTagsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Metadata.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("GenreSeriesMetadata", b => + { + b.HasOne("API.Entities.Genre", null) + .WithMany() + .HasForeignKey("GenresId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Metadata.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("API.Entities.AppRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("PersonSeriesMetadata", b => + { + b.HasOne("API.Entities.Person", null) + .WithMany() + .HasForeignKey("PeopleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Metadata.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("SeriesMetadataTag", b => + { + b.HasOne("API.Entities.Metadata.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Tag", null) + .WithMany() + .HasForeignKey("TagsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("API.Entities.AppRole", b => + { + b.Navigation("UserRoles"); + }); + + modelBuilder.Entity("API.Entities.AppUser", b => + { + b.Navigation("Bookmarks"); + + b.Navigation("Progresses"); + + b.Navigation("Ratings"); + + b.Navigation("ReadingLists"); + + b.Navigation("UserPreferences"); + + b.Navigation("UserRoles"); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.Navigation("Files"); + }); + + modelBuilder.Entity("API.Entities.Genre", b => + { + b.Navigation("Chapters"); + }); + + modelBuilder.Entity("API.Entities.Library", b => + { + b.Navigation("Folders"); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.Navigation("Items"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.Navigation("Metadata"); + + b.Navigation("Progress"); + + b.Navigation("Ratings"); + + b.Navigation("Volumes"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.Navigation("Chapters"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/API/Data/Migrations/20211217180457_filteringChanges.cs b/API/Data/Migrations/20211217180457_filteringChanges.cs new file mode 100644 index 000000000..28c4d00b3 --- /dev/null +++ b/API/Data/Migrations/20211217180457_filteringChanges.cs @@ -0,0 +1,155 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace API.Data.Migrations +{ + public partial class filteringChanges : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "Language", + table: "SeriesMetadata", + type: "TEXT", + nullable: true); + + migrationBuilder.CreateTable( + name: "Tag", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + Title = table.Column(type: "TEXT", nullable: true), + NormalizedTitle = table.Column(type: "TEXT", nullable: true), + ExternalTag = table.Column(type: "INTEGER", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Tag", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "ChapterTag", + columns: table => new + { + ChaptersId = table.Column(type: "INTEGER", nullable: false), + TagsId = table.Column(type: "INTEGER", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ChapterTag", x => new { x.ChaptersId, x.TagsId }); + table.ForeignKey( + name: "FK_ChapterTag_Chapter_ChaptersId", + column: x => x.ChaptersId, + principalTable: "Chapter", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_ChapterTag_Tag_TagsId", + column: x => x.TagsId, + principalTable: "Tag", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "SeriesMetadataTag", + columns: table => new + { + SeriesMetadatasId = table.Column(type: "INTEGER", nullable: false), + TagsId = table.Column(type: "INTEGER", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_SeriesMetadataTag", x => new { x.SeriesMetadatasId, x.TagsId }); + table.ForeignKey( + name: "FK_SeriesMetadataTag_SeriesMetadata_SeriesMetadatasId", + column: x => x.SeriesMetadatasId, + principalTable: "SeriesMetadata", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_SeriesMetadataTag_Tag_TagsId", + column: x => x.TagsId, + principalTable: "Tag", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_AppUserRating_SeriesId", + table: "AppUserRating", + column: "SeriesId"); + + migrationBuilder.CreateIndex( + name: "IX_AppUserProgresses_SeriesId", + table: "AppUserProgresses", + column: "SeriesId"); + + migrationBuilder.CreateIndex( + name: "IX_ChapterTag_TagsId", + table: "ChapterTag", + column: "TagsId"); + + migrationBuilder.CreateIndex( + name: "IX_SeriesMetadataTag_TagsId", + table: "SeriesMetadataTag", + column: "TagsId"); + + migrationBuilder.CreateIndex( + name: "IX_Tag_NormalizedTitle_ExternalTag", + table: "Tag", + columns: new[] { "NormalizedTitle", "ExternalTag" }, + unique: true); + + migrationBuilder.AddForeignKey( + name: "FK_AppUserProgresses_Series_SeriesId", + table: "AppUserProgresses", + column: "SeriesId", + principalTable: "Series", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_AppUserRating_Series_SeriesId", + table: "AppUserRating", + column: "SeriesId", + principalTable: "Series", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_AppUserProgresses_Series_SeriesId", + table: "AppUserProgresses"); + + migrationBuilder.DropForeignKey( + name: "FK_AppUserRating_Series_SeriesId", + table: "AppUserRating"); + + migrationBuilder.DropTable( + name: "ChapterTag"); + + migrationBuilder.DropTable( + name: "SeriesMetadataTag"); + + migrationBuilder.DropTable( + name: "Tag"); + + migrationBuilder.DropIndex( + name: "IX_AppUserRating_SeriesId", + table: "AppUserRating"); + + migrationBuilder.DropIndex( + name: "IX_AppUserProgresses_SeriesId", + table: "AppUserProgresses"); + + migrationBuilder.DropColumn( + name: "Language", + table: "SeriesMetadata"); + } + } +} diff --git a/API/Data/Migrations/20211227180752_FullscreenPref.Designer.cs b/API/Data/Migrations/20211227180752_FullscreenPref.Designer.cs new file mode 100644 index 000000000..b649b12b6 --- /dev/null +++ b/API/Data/Migrations/20211227180752_FullscreenPref.Designer.cs @@ -0,0 +1,1317 @@ +// +using System; +using API.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace API.Data.Migrations +{ + [DbContext(typeof(DataContext))] + [Migration("20211227180752_FullscreenPref")] + partial class FullscreenPref + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "6.0.0"); + + modelBuilder.Entity("API.Entities.AppRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("API.Entities.AppUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessFailedCount") + .HasColumnType("INTEGER"); + + b.Property("ApiKey") + .HasColumnType("TEXT"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("EmailConfirmed") + .HasColumnType("INTEGER"); + + b.Property("LastActive") + .HasColumnType("TEXT"); + + b.Property("LockoutEnabled") + .HasColumnType("INTEGER"); + + b.Property("LockoutEnd") + .HasColumnType("TEXT"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("PasswordHash") + .HasColumnType("TEXT"); + + b.Property("PhoneNumber") + .HasColumnType("TEXT"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SecurityStamp") + .HasColumnType("TEXT"); + + b.Property("TwoFactorEnabled") + .HasColumnType("INTEGER"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("API.Entities.AppUserBookmark", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("Page") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("AppUserBookmark"); + }); + + modelBuilder.Entity("API.Entities.AppUserPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("AutoCloseMenu") + .HasColumnType("INTEGER"); + + b.Property("BookReaderDarkMode") + .HasColumnType("INTEGER"); + + b.Property("BookReaderFontFamily") + .HasColumnType("TEXT"); + + b.Property("BookReaderFontSize") + .HasColumnType("INTEGER"); + + b.Property("BookReaderLineSpacing") + .HasColumnType("INTEGER"); + + b.Property("BookReaderMargin") + .HasColumnType("INTEGER"); + + b.Property("BookReaderReadingDirection") + .HasColumnType("INTEGER"); + + b.Property("BookReaderTapToPaginate") + .HasColumnType("INTEGER"); + + b.Property("FullscreenMode") + .HasColumnType("INTEGER"); + + b.Property("PageSplitOption") + .HasColumnType("INTEGER"); + + b.Property("ReaderMode") + .HasColumnType("INTEGER"); + + b.Property("ReadingDirection") + .HasColumnType("INTEGER"); + + b.Property("ScalingOption") + .HasColumnType("INTEGER"); + + b.Property("SiteDarkMode") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId") + .IsUnique(); + + b.ToTable("AppUserPreferences"); + }); + + modelBuilder.Entity("API.Entities.AppUserProgress", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("BookScrollId") + .HasColumnType("TEXT"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("PagesRead") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.HasIndex("SeriesId"); + + b.ToTable("AppUserProgresses"); + }); + + modelBuilder.Entity("API.Entities.AppUserRating", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("Rating") + .HasColumnType("INTEGER"); + + b.Property("Review") + .HasColumnType("TEXT"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.HasIndex("SeriesId"); + + b.ToTable("AppUserRating"); + }); + + modelBuilder.Entity("API.Entities.AppUserRole", b => + { + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AgeRating") + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("GenreId") + .HasColumnType("INTEGER"); + + b.Property("IsSpecial") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Number") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("Range") + .HasColumnType("TEXT"); + + b.Property("ReleaseDate") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.Property("TitleName") + .HasColumnType("TEXT"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GenreId"); + + b.HasIndex("VolumeId"); + + b.ToTable("Chapter"); + }); + + modelBuilder.Entity("API.Entities.CollectionTag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("NormalizedTitle") + .HasColumnType("TEXT"); + + b.Property("Promoted") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Id", "Promoted") + .IsUnique(); + + b.ToTable("CollectionTag"); + }); + + modelBuilder.Entity("API.Entities.FolderPath", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("LastScanned") + .HasColumnType("TEXT"); + + b.Property("LibraryId") + .HasColumnType("INTEGER"); + + b.Property("Path") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("LibraryId"); + + b.ToTable("FolderPath"); + }); + + modelBuilder.Entity("API.Entities.Genre", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ExternalTag") + .HasColumnType("INTEGER"); + + b.Property("NormalizedTitle") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedTitle", "ExternalTag") + .IsUnique(); + + b.ToTable("Genre"); + }); + + modelBuilder.Entity("API.Entities.Library", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("LastScanned") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Library"); + }); + + modelBuilder.Entity("API.Entities.MangaFile", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("FilePath") + .HasColumnType("TEXT"); + + b.Property("Format") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ChapterId"); + + b.ToTable("MangaFile"); + }); + + modelBuilder.Entity("API.Entities.Metadata.SeriesMetadata", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AgeRating") + .HasColumnType("INTEGER"); + + b.Property("Language") + .HasColumnType("TEXT"); + + b.Property("ReleaseYear") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("SeriesId") + .IsUnique(); + + b.HasIndex("Id", "SeriesId") + .IsUnique(); + + b.ToTable("SeriesMetadata"); + }); + + modelBuilder.Entity("API.Entities.Person", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasColumnType("TEXT"); + + b.Property("Role") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Person"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Promoted") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("ReadingList"); + }); + + modelBuilder.Entity("API.Entities.ReadingListItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("Order") + .HasColumnType("INTEGER"); + + b.Property("ReadingListId") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ChapterId"); + + b.HasIndex("ReadingListId"); + + b.HasIndex("SeriesId"); + + b.HasIndex("VolumeId"); + + b.ToTable("ReadingListItem"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("Format") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("LibraryId") + .HasColumnType("INTEGER"); + + b.Property("LocalizedName") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasColumnType("TEXT"); + + b.Property("OriginalName") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("SortName") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("LibraryId"); + + b.HasIndex("Name", "NormalizedName", "LocalizedName", "LibraryId", "Format") + .IsUnique(); + + b.ToTable("Series"); + }); + + modelBuilder.Entity("API.Entities.ServerSetting", b => + { + b.Property("Key") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("Key"); + + b.ToTable("ServerSetting"); + }); + + modelBuilder.Entity("API.Entities.Tag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ExternalTag") + .HasColumnType("INTEGER"); + + b.Property("NormalizedTitle") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedTitle", "ExternalTag") + .IsUnique(); + + b.ToTable("Tag"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Number") + .HasColumnType("INTEGER"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("SeriesId"); + + b.ToTable("Volume"); + }); + + modelBuilder.Entity("AppUserLibrary", b => + { + b.Property("AppUsersId") + .HasColumnType("INTEGER"); + + b.Property("LibrariesId") + .HasColumnType("INTEGER"); + + b.HasKey("AppUsersId", "LibrariesId"); + + b.HasIndex("LibrariesId"); + + b.ToTable("AppUserLibrary"); + }); + + modelBuilder.Entity("ChapterPerson", b => + { + b.Property("ChapterMetadatasId") + .HasColumnType("INTEGER"); + + b.Property("PeopleId") + .HasColumnType("INTEGER"); + + b.HasKey("ChapterMetadatasId", "PeopleId"); + + b.HasIndex("PeopleId"); + + b.ToTable("ChapterPerson"); + }); + + modelBuilder.Entity("ChapterTag", b => + { + b.Property("ChaptersId") + .HasColumnType("INTEGER"); + + b.Property("TagsId") + .HasColumnType("INTEGER"); + + b.HasKey("ChaptersId", "TagsId"); + + b.HasIndex("TagsId"); + + b.ToTable("ChapterTag"); + }); + + modelBuilder.Entity("CollectionTagSeriesMetadata", b => + { + b.Property("CollectionTagsId") + .HasColumnType("INTEGER"); + + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.HasKey("CollectionTagsId", "SeriesMetadatasId"); + + b.HasIndex("SeriesMetadatasId"); + + b.ToTable("CollectionTagSeriesMetadata"); + }); + + modelBuilder.Entity("GenreSeriesMetadata", b => + { + b.Property("GenresId") + .HasColumnType("INTEGER"); + + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.HasKey("GenresId", "SeriesMetadatasId"); + + b.HasIndex("SeriesMetadatasId"); + + b.ToTable("GenreSeriesMetadata"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("ProviderKey") + .HasColumnType("TEXT"); + + b.Property("ProviderDisplayName") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("PersonSeriesMetadata", b => + { + b.Property("PeopleId") + .HasColumnType("INTEGER"); + + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.HasKey("PeopleId", "SeriesMetadatasId"); + + b.HasIndex("SeriesMetadatasId"); + + b.ToTable("PersonSeriesMetadata"); + }); + + modelBuilder.Entity("SeriesMetadataTag", b => + { + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.Property("TagsId") + .HasColumnType("INTEGER"); + + b.HasKey("SeriesMetadatasId", "TagsId"); + + b.HasIndex("TagsId"); + + b.ToTable("SeriesMetadataTag"); + }); + + modelBuilder.Entity("API.Entities.AppUserBookmark", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Bookmarks") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserPreferences", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithOne("UserPreferences") + .HasForeignKey("API.Entities.AppUserPreferences", "AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserProgress", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Progresses") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Series", null) + .WithMany("Progress") + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserRating", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Ratings") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Series", null) + .WithMany("Ratings") + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserRole", b => + { + b.HasOne("API.Entities.AppRole", "Role") + .WithMany("UserRoles") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.AppUser", "User") + .WithMany("UserRoles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.HasOne("API.Entities.Genre", null) + .WithMany("Chapters") + .HasForeignKey("GenreId"); + + b.HasOne("API.Entities.Volume", "Volume") + .WithMany("Chapters") + .HasForeignKey("VolumeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Volume"); + }); + + modelBuilder.Entity("API.Entities.FolderPath", b => + { + b.HasOne("API.Entities.Library", "Library") + .WithMany("Folders") + .HasForeignKey("LibraryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Library"); + }); + + modelBuilder.Entity("API.Entities.MangaFile", b => + { + b.HasOne("API.Entities.Chapter", "Chapter") + .WithMany("Files") + .HasForeignKey("ChapterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Chapter"); + }); + + modelBuilder.Entity("API.Entities.Metadata.SeriesMetadata", b => + { + b.HasOne("API.Entities.Series", "Series") + .WithOne("Metadata") + .HasForeignKey("API.Entities.Metadata.SeriesMetadata", "SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("ReadingLists") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.ReadingListItem", b => + { + b.HasOne("API.Entities.Chapter", "Chapter") + .WithMany() + .HasForeignKey("ChapterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.ReadingList", "ReadingList") + .WithMany("Items") + .HasForeignKey("ReadingListId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Series", "Series") + .WithMany() + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Volume", "Volume") + .WithMany() + .HasForeignKey("VolumeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Chapter"); + + b.Navigation("ReadingList"); + + b.Navigation("Series"); + + b.Navigation("Volume"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.HasOne("API.Entities.Library", "Library") + .WithMany("Series") + .HasForeignKey("LibraryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Library"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.HasOne("API.Entities.Series", "Series") + .WithMany("Volumes") + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("AppUserLibrary", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("AppUsersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Library", null) + .WithMany() + .HasForeignKey("LibrariesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ChapterPerson", b => + { + b.HasOne("API.Entities.Chapter", null) + .WithMany() + .HasForeignKey("ChapterMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Person", null) + .WithMany() + .HasForeignKey("PeopleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ChapterTag", b => + { + b.HasOne("API.Entities.Chapter", null) + .WithMany() + .HasForeignKey("ChaptersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Tag", null) + .WithMany() + .HasForeignKey("TagsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("CollectionTagSeriesMetadata", b => + { + b.HasOne("API.Entities.CollectionTag", null) + .WithMany() + .HasForeignKey("CollectionTagsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Metadata.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("GenreSeriesMetadata", b => + { + b.HasOne("API.Entities.Genre", null) + .WithMany() + .HasForeignKey("GenresId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Metadata.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("API.Entities.AppRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("PersonSeriesMetadata", b => + { + b.HasOne("API.Entities.Person", null) + .WithMany() + .HasForeignKey("PeopleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Metadata.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("SeriesMetadataTag", b => + { + b.HasOne("API.Entities.Metadata.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Tag", null) + .WithMany() + .HasForeignKey("TagsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("API.Entities.AppRole", b => + { + b.Navigation("UserRoles"); + }); + + modelBuilder.Entity("API.Entities.AppUser", b => + { + b.Navigation("Bookmarks"); + + b.Navigation("Progresses"); + + b.Navigation("Ratings"); + + b.Navigation("ReadingLists"); + + b.Navigation("UserPreferences"); + + b.Navigation("UserRoles"); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.Navigation("Files"); + }); + + modelBuilder.Entity("API.Entities.Genre", b => + { + b.Navigation("Chapters"); + }); + + modelBuilder.Entity("API.Entities.Library", b => + { + b.Navigation("Folders"); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.Navigation("Items"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.Navigation("Metadata"); + + b.Navigation("Progress"); + + b.Navigation("Ratings"); + + b.Navigation("Volumes"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.Navigation("Chapters"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/API/Data/Migrations/20211227180752_FullscreenPref.cs b/API/Data/Migrations/20211227180752_FullscreenPref.cs new file mode 100644 index 000000000..ab6cbc8a8 --- /dev/null +++ b/API/Data/Migrations/20211227180752_FullscreenPref.cs @@ -0,0 +1,26 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace API.Data.Migrations +{ + public partial class FullscreenPref : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "FullscreenMode", + table: "AppUserPreferences", + type: "INTEGER", + nullable: false, + defaultValue: 0); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "FullscreenMode", + table: "AppUserPreferences"); + } + } +} diff --git a/API/Data/Migrations/20220107232822_ChapterMetadataOptimization.Designer.cs b/API/Data/Migrations/20220107232822_ChapterMetadataOptimization.Designer.cs new file mode 100644 index 000000000..9df425dbd --- /dev/null +++ b/API/Data/Migrations/20220107232822_ChapterMetadataOptimization.Designer.cs @@ -0,0 +1,1339 @@ +// +using System; +using API.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace API.Data.Migrations +{ + [DbContext(typeof(DataContext))] + [Migration("20220107232822_ChapterMetadataOptimization")] + partial class ChapterMetadataOptimization + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "6.0.0"); + + modelBuilder.Entity("API.Entities.AppRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("API.Entities.AppUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessFailedCount") + .HasColumnType("INTEGER"); + + b.Property("ApiKey") + .HasColumnType("TEXT"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("EmailConfirmed") + .HasColumnType("INTEGER"); + + b.Property("LastActive") + .HasColumnType("TEXT"); + + b.Property("LockoutEnabled") + .HasColumnType("INTEGER"); + + b.Property("LockoutEnd") + .HasColumnType("TEXT"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("PasswordHash") + .HasColumnType("TEXT"); + + b.Property("PhoneNumber") + .HasColumnType("TEXT"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SecurityStamp") + .HasColumnType("TEXT"); + + b.Property("TwoFactorEnabled") + .HasColumnType("INTEGER"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("API.Entities.AppUserBookmark", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("FileName") + .HasColumnType("TEXT"); + + b.Property("Page") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("AppUserBookmark"); + }); + + modelBuilder.Entity("API.Entities.AppUserPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("AutoCloseMenu") + .HasColumnType("INTEGER"); + + b.Property("BookReaderDarkMode") + .HasColumnType("INTEGER"); + + b.Property("BookReaderFontFamily") + .HasColumnType("TEXT"); + + b.Property("BookReaderFontSize") + .HasColumnType("INTEGER"); + + b.Property("BookReaderLineSpacing") + .HasColumnType("INTEGER"); + + b.Property("BookReaderMargin") + .HasColumnType("INTEGER"); + + b.Property("BookReaderReadingDirection") + .HasColumnType("INTEGER"); + + b.Property("BookReaderTapToPaginate") + .HasColumnType("INTEGER"); + + b.Property("PageSplitOption") + .HasColumnType("INTEGER"); + + b.Property("ReaderMode") + .HasColumnType("INTEGER"); + + b.Property("ReadingDirection") + .HasColumnType("INTEGER"); + + b.Property("ScalingOption") + .HasColumnType("INTEGER"); + + b.Property("SiteDarkMode") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId") + .IsUnique(); + + b.ToTable("AppUserPreferences"); + }); + + modelBuilder.Entity("API.Entities.AppUserProgress", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("BookScrollId") + .HasColumnType("TEXT"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("PagesRead") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.HasIndex("SeriesId"); + + b.ToTable("AppUserProgresses"); + }); + + modelBuilder.Entity("API.Entities.AppUserRating", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("Rating") + .HasColumnType("INTEGER"); + + b.Property("Review") + .HasColumnType("TEXT"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.HasIndex("SeriesId"); + + b.ToTable("AppUserRating"); + }); + + modelBuilder.Entity("API.Entities.AppUserRole", b => + { + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AgeRating") + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("IsSpecial") + .HasColumnType("INTEGER"); + + b.Property("Language") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Number") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("Range") + .HasColumnType("TEXT"); + + b.Property("ReleaseDate") + .HasColumnType("TEXT"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.Property("TitleName") + .HasColumnType("TEXT"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("VolumeId"); + + b.ToTable("Chapter"); + }); + + modelBuilder.Entity("API.Entities.CollectionTag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("NormalizedTitle") + .HasColumnType("TEXT"); + + b.Property("Promoted") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Id", "Promoted") + .IsUnique(); + + b.ToTable("CollectionTag"); + }); + + modelBuilder.Entity("API.Entities.FolderPath", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("LastScanned") + .HasColumnType("TEXT"); + + b.Property("LibraryId") + .HasColumnType("INTEGER"); + + b.Property("Path") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("LibraryId"); + + b.ToTable("FolderPath"); + }); + + modelBuilder.Entity("API.Entities.Genre", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ExternalTag") + .HasColumnType("INTEGER"); + + b.Property("NormalizedTitle") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedTitle", "ExternalTag") + .IsUnique(); + + b.ToTable("Genre"); + }); + + modelBuilder.Entity("API.Entities.Library", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("LastScanned") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Library"); + }); + + modelBuilder.Entity("API.Entities.MangaFile", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("FilePath") + .HasColumnType("TEXT"); + + b.Property("Format") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ChapterId"); + + b.ToTable("MangaFile"); + }); + + modelBuilder.Entity("API.Entities.Metadata.SeriesMetadata", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AgeRating") + .HasColumnType("INTEGER"); + + b.Property("Language") + .HasColumnType("TEXT"); + + b.Property("ReleaseYear") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("SeriesId") + .IsUnique(); + + b.HasIndex("Id", "SeriesId") + .IsUnique(); + + b.ToTable("SeriesMetadata"); + }); + + modelBuilder.Entity("API.Entities.Person", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasColumnType("TEXT"); + + b.Property("Role") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Person"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Promoted") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("ReadingList"); + }); + + modelBuilder.Entity("API.Entities.ReadingListItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("Order") + .HasColumnType("INTEGER"); + + b.Property("ReadingListId") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ChapterId"); + + b.HasIndex("ReadingListId"); + + b.HasIndex("SeriesId"); + + b.HasIndex("VolumeId"); + + b.ToTable("ReadingListItem"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("Format") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("LibraryId") + .HasColumnType("INTEGER"); + + b.Property("LocalizedName") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasColumnType("TEXT"); + + b.Property("OriginalName") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("SortName") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("LibraryId"); + + b.HasIndex("Name", "NormalizedName", "LocalizedName", "LibraryId", "Format") + .IsUnique(); + + b.ToTable("Series"); + }); + + modelBuilder.Entity("API.Entities.ServerSetting", b => + { + b.Property("Key") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("Key"); + + b.ToTable("ServerSetting"); + }); + + modelBuilder.Entity("API.Entities.Tag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ExternalTag") + .HasColumnType("INTEGER"); + + b.Property("NormalizedTitle") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedTitle", "ExternalTag") + .IsUnique(); + + b.ToTable("Tag"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Number") + .HasColumnType("INTEGER"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("SeriesId"); + + b.ToTable("Volume"); + }); + + modelBuilder.Entity("AppUserLibrary", b => + { + b.Property("AppUsersId") + .HasColumnType("INTEGER"); + + b.Property("LibrariesId") + .HasColumnType("INTEGER"); + + b.HasKey("AppUsersId", "LibrariesId"); + + b.HasIndex("LibrariesId"); + + b.ToTable("AppUserLibrary"); + }); + + modelBuilder.Entity("ChapterGenre", b => + { + b.Property("ChaptersId") + .HasColumnType("INTEGER"); + + b.Property("GenresId") + .HasColumnType("INTEGER"); + + b.HasKey("ChaptersId", "GenresId"); + + b.HasIndex("GenresId"); + + b.ToTable("ChapterGenre"); + }); + + modelBuilder.Entity("ChapterPerson", b => + { + b.Property("ChapterMetadatasId") + .HasColumnType("INTEGER"); + + b.Property("PeopleId") + .HasColumnType("INTEGER"); + + b.HasKey("ChapterMetadatasId", "PeopleId"); + + b.HasIndex("PeopleId"); + + b.ToTable("ChapterPerson"); + }); + + modelBuilder.Entity("ChapterTag", b => + { + b.Property("ChaptersId") + .HasColumnType("INTEGER"); + + b.Property("TagsId") + .HasColumnType("INTEGER"); + + b.HasKey("ChaptersId", "TagsId"); + + b.HasIndex("TagsId"); + + b.ToTable("ChapterTag"); + }); + + modelBuilder.Entity("CollectionTagSeriesMetadata", b => + { + b.Property("CollectionTagsId") + .HasColumnType("INTEGER"); + + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.HasKey("CollectionTagsId", "SeriesMetadatasId"); + + b.HasIndex("SeriesMetadatasId"); + + b.ToTable("CollectionTagSeriesMetadata"); + }); + + modelBuilder.Entity("GenreSeriesMetadata", b => + { + b.Property("GenresId") + .HasColumnType("INTEGER"); + + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.HasKey("GenresId", "SeriesMetadatasId"); + + b.HasIndex("SeriesMetadatasId"); + + b.ToTable("GenreSeriesMetadata"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("ProviderKey") + .HasColumnType("TEXT"); + + b.Property("ProviderDisplayName") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("PersonSeriesMetadata", b => + { + b.Property("PeopleId") + .HasColumnType("INTEGER"); + + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.HasKey("PeopleId", "SeriesMetadatasId"); + + b.HasIndex("SeriesMetadatasId"); + + b.ToTable("PersonSeriesMetadata"); + }); + + modelBuilder.Entity("SeriesMetadataTag", b => + { + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.Property("TagsId") + .HasColumnType("INTEGER"); + + b.HasKey("SeriesMetadatasId", "TagsId"); + + b.HasIndex("TagsId"); + + b.ToTable("SeriesMetadataTag"); + }); + + modelBuilder.Entity("API.Entities.AppUserBookmark", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Bookmarks") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserPreferences", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithOne("UserPreferences") + .HasForeignKey("API.Entities.AppUserPreferences", "AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserProgress", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Progresses") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Series", null) + .WithMany("Progress") + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserRating", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Ratings") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Series", null) + .WithMany("Ratings") + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserRole", b => + { + b.HasOne("API.Entities.AppRole", "Role") + .WithMany("UserRoles") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.AppUser", "User") + .WithMany("UserRoles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.HasOne("API.Entities.Volume", "Volume") + .WithMany("Chapters") + .HasForeignKey("VolumeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Volume"); + }); + + modelBuilder.Entity("API.Entities.FolderPath", b => + { + b.HasOne("API.Entities.Library", "Library") + .WithMany("Folders") + .HasForeignKey("LibraryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Library"); + }); + + modelBuilder.Entity("API.Entities.MangaFile", b => + { + b.HasOne("API.Entities.Chapter", "Chapter") + .WithMany("Files") + .HasForeignKey("ChapterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Chapter"); + }); + + modelBuilder.Entity("API.Entities.Metadata.SeriesMetadata", b => + { + b.HasOne("API.Entities.Series", "Series") + .WithOne("Metadata") + .HasForeignKey("API.Entities.Metadata.SeriesMetadata", "SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("ReadingLists") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.ReadingListItem", b => + { + b.HasOne("API.Entities.Chapter", "Chapter") + .WithMany() + .HasForeignKey("ChapterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.ReadingList", "ReadingList") + .WithMany("Items") + .HasForeignKey("ReadingListId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Series", "Series") + .WithMany() + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Volume", "Volume") + .WithMany() + .HasForeignKey("VolumeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Chapter"); + + b.Navigation("ReadingList"); + + b.Navigation("Series"); + + b.Navigation("Volume"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.HasOne("API.Entities.Library", "Library") + .WithMany("Series") + .HasForeignKey("LibraryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Library"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.HasOne("API.Entities.Series", "Series") + .WithMany("Volumes") + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("AppUserLibrary", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("AppUsersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Library", null) + .WithMany() + .HasForeignKey("LibrariesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ChapterGenre", b => + { + b.HasOne("API.Entities.Chapter", null) + .WithMany() + .HasForeignKey("ChaptersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Genre", null) + .WithMany() + .HasForeignKey("GenresId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ChapterPerson", b => + { + b.HasOne("API.Entities.Chapter", null) + .WithMany() + .HasForeignKey("ChapterMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Person", null) + .WithMany() + .HasForeignKey("PeopleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ChapterTag", b => + { + b.HasOne("API.Entities.Chapter", null) + .WithMany() + .HasForeignKey("ChaptersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Tag", null) + .WithMany() + .HasForeignKey("TagsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("CollectionTagSeriesMetadata", b => + { + b.HasOne("API.Entities.CollectionTag", null) + .WithMany() + .HasForeignKey("CollectionTagsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Metadata.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("GenreSeriesMetadata", b => + { + b.HasOne("API.Entities.Genre", null) + .WithMany() + .HasForeignKey("GenresId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Metadata.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("API.Entities.AppRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("PersonSeriesMetadata", b => + { + b.HasOne("API.Entities.Person", null) + .WithMany() + .HasForeignKey("PeopleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Metadata.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("SeriesMetadataTag", b => + { + b.HasOne("API.Entities.Metadata.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Tag", null) + .WithMany() + .HasForeignKey("TagsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("API.Entities.AppRole", b => + { + b.Navigation("UserRoles"); + }); + + modelBuilder.Entity("API.Entities.AppUser", b => + { + b.Navigation("Bookmarks"); + + b.Navigation("Progresses"); + + b.Navigation("Ratings"); + + b.Navigation("ReadingLists"); + + b.Navigation("UserPreferences"); + + b.Navigation("UserRoles"); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.Navigation("Files"); + }); + + modelBuilder.Entity("API.Entities.Library", b => + { + b.Navigation("Folders"); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.Navigation("Items"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.Navigation("Metadata"); + + b.Navigation("Progress"); + + b.Navigation("Ratings"); + + b.Navigation("Volumes"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.Navigation("Chapters"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/API/Data/Migrations/20220107232822_ChapterMetadataOptimization.cs b/API/Data/Migrations/20220107232822_ChapterMetadataOptimization.cs new file mode 100644 index 000000000..28e874f03 --- /dev/null +++ b/API/Data/Migrations/20220107232822_ChapterMetadataOptimization.cs @@ -0,0 +1,108 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace API.Data.Migrations +{ + public partial class ChapterMetadataOptimization : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_Chapter_Genre_GenreId", + table: "Chapter"); + + migrationBuilder.DropIndex( + name: "IX_Chapter_GenreId", + table: "Chapter"); + + migrationBuilder.DropColumn( + name: "GenreId", + table: "Chapter"); + + migrationBuilder.DropColumn( + name: "FullscreenMode", + table: "AppUserPreferences"); + + migrationBuilder.AddColumn( + name: "Language", + table: "Chapter", + type: "TEXT", + nullable: true); + + migrationBuilder.AddColumn( + name: "Summary", + table: "Chapter", + type: "TEXT", + nullable: true); + + migrationBuilder.CreateTable( + name: "ChapterGenre", + columns: table => new + { + ChaptersId = table.Column(type: "INTEGER", nullable: false), + GenresId = table.Column(type: "INTEGER", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ChapterGenre", x => new { x.ChaptersId, x.GenresId }); + table.ForeignKey( + name: "FK_ChapterGenre_Chapter_ChaptersId", + column: x => x.ChaptersId, + principalTable: "Chapter", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_ChapterGenre_Genre_GenresId", + column: x => x.GenresId, + principalTable: "Genre", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_ChapterGenre_GenresId", + table: "ChapterGenre", + column: "GenresId"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "ChapterGenre"); + + migrationBuilder.DropColumn( + name: "Language", + table: "Chapter"); + + migrationBuilder.DropColumn( + name: "Summary", + table: "Chapter"); + + migrationBuilder.AddColumn( + name: "GenreId", + table: "Chapter", + type: "INTEGER", + nullable: true); + + migrationBuilder.AddColumn( + name: "FullscreenMode", + table: "AppUserPreferences", + type: "INTEGER", + nullable: false, + defaultValue: 0); + + migrationBuilder.CreateIndex( + name: "IX_Chapter_GenreId", + table: "Chapter", + column: "GenreId"); + + migrationBuilder.AddForeignKey( + name: "FK_Chapter_Genre_GenreId", + table: "Chapter", + column: "GenreId", + principalTable: "Genre", + principalColumn: "Id"); + } + } +} diff --git a/API/Data/Migrations/20220108200822_CountMetadata.Designer.cs b/API/Data/Migrations/20220108200822_CountMetadata.Designer.cs new file mode 100644 index 000000000..1866b6e58 --- /dev/null +++ b/API/Data/Migrations/20220108200822_CountMetadata.Designer.cs @@ -0,0 +1,1345 @@ +// +using System; +using API.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace API.Data.Migrations +{ + [DbContext(typeof(DataContext))] + [Migration("20220108200822_CountMetadata")] + partial class CountMetadata + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "6.0.0"); + + modelBuilder.Entity("API.Entities.AppRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("API.Entities.AppUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessFailedCount") + .HasColumnType("INTEGER"); + + b.Property("ApiKey") + .HasColumnType("TEXT"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("EmailConfirmed") + .HasColumnType("INTEGER"); + + b.Property("LastActive") + .HasColumnType("TEXT"); + + b.Property("LockoutEnabled") + .HasColumnType("INTEGER"); + + b.Property("LockoutEnd") + .HasColumnType("TEXT"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("PasswordHash") + .HasColumnType("TEXT"); + + b.Property("PhoneNumber") + .HasColumnType("TEXT"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SecurityStamp") + .HasColumnType("TEXT"); + + b.Property("TwoFactorEnabled") + .HasColumnType("INTEGER"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("API.Entities.AppUserBookmark", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("FileName") + .HasColumnType("TEXT"); + + b.Property("Page") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("AppUserBookmark"); + }); + + modelBuilder.Entity("API.Entities.AppUserPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("AutoCloseMenu") + .HasColumnType("INTEGER"); + + b.Property("BookReaderDarkMode") + .HasColumnType("INTEGER"); + + b.Property("BookReaderFontFamily") + .HasColumnType("TEXT"); + + b.Property("BookReaderFontSize") + .HasColumnType("INTEGER"); + + b.Property("BookReaderLineSpacing") + .HasColumnType("INTEGER"); + + b.Property("BookReaderMargin") + .HasColumnType("INTEGER"); + + b.Property("BookReaderReadingDirection") + .HasColumnType("INTEGER"); + + b.Property("BookReaderTapToPaginate") + .HasColumnType("INTEGER"); + + b.Property("PageSplitOption") + .HasColumnType("INTEGER"); + + b.Property("ReaderMode") + .HasColumnType("INTEGER"); + + b.Property("ReadingDirection") + .HasColumnType("INTEGER"); + + b.Property("ScalingOption") + .HasColumnType("INTEGER"); + + b.Property("SiteDarkMode") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId") + .IsUnique(); + + b.ToTable("AppUserPreferences"); + }); + + modelBuilder.Entity("API.Entities.AppUserProgress", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("BookScrollId") + .HasColumnType("TEXT"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("PagesRead") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.HasIndex("SeriesId"); + + b.ToTable("AppUserProgresses"); + }); + + modelBuilder.Entity("API.Entities.AppUserRating", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("Rating") + .HasColumnType("INTEGER"); + + b.Property("Review") + .HasColumnType("TEXT"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.HasIndex("SeriesId"); + + b.ToTable("AppUserRating"); + }); + + modelBuilder.Entity("API.Entities.AppUserRole", b => + { + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AgeRating") + .HasColumnType("INTEGER"); + + b.Property("Count") + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("IsSpecial") + .HasColumnType("INTEGER"); + + b.Property("Language") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Number") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("Range") + .HasColumnType("TEXT"); + + b.Property("ReleaseDate") + .HasColumnType("TEXT"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.Property("TitleName") + .HasColumnType("TEXT"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("VolumeId"); + + b.ToTable("Chapter"); + }); + + modelBuilder.Entity("API.Entities.CollectionTag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("NormalizedTitle") + .HasColumnType("TEXT"); + + b.Property("Promoted") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Id", "Promoted") + .IsUnique(); + + b.ToTable("CollectionTag"); + }); + + modelBuilder.Entity("API.Entities.FolderPath", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("LastScanned") + .HasColumnType("TEXT"); + + b.Property("LibraryId") + .HasColumnType("INTEGER"); + + b.Property("Path") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("LibraryId"); + + b.ToTable("FolderPath"); + }); + + modelBuilder.Entity("API.Entities.Genre", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ExternalTag") + .HasColumnType("INTEGER"); + + b.Property("NormalizedTitle") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedTitle", "ExternalTag") + .IsUnique(); + + b.ToTable("Genre"); + }); + + modelBuilder.Entity("API.Entities.Library", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("LastScanned") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Library"); + }); + + modelBuilder.Entity("API.Entities.MangaFile", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("FilePath") + .HasColumnType("TEXT"); + + b.Property("Format") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ChapterId"); + + b.ToTable("MangaFile"); + }); + + modelBuilder.Entity("API.Entities.Metadata.SeriesMetadata", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AgeRating") + .HasColumnType("INTEGER"); + + b.Property("Count") + .HasColumnType("INTEGER"); + + b.Property("Language") + .HasColumnType("TEXT"); + + b.Property("ReleaseYear") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("SeriesId") + .IsUnique(); + + b.HasIndex("Id", "SeriesId") + .IsUnique(); + + b.ToTable("SeriesMetadata"); + }); + + modelBuilder.Entity("API.Entities.Person", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasColumnType("TEXT"); + + b.Property("Role") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Person"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Promoted") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("ReadingList"); + }); + + modelBuilder.Entity("API.Entities.ReadingListItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("Order") + .HasColumnType("INTEGER"); + + b.Property("ReadingListId") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ChapterId"); + + b.HasIndex("ReadingListId"); + + b.HasIndex("SeriesId"); + + b.HasIndex("VolumeId"); + + b.ToTable("ReadingListItem"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("Format") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("LibraryId") + .HasColumnType("INTEGER"); + + b.Property("LocalizedName") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasColumnType("TEXT"); + + b.Property("OriginalName") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("SortName") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("LibraryId"); + + b.HasIndex("Name", "NormalizedName", "LocalizedName", "LibraryId", "Format") + .IsUnique(); + + b.ToTable("Series"); + }); + + modelBuilder.Entity("API.Entities.ServerSetting", b => + { + b.Property("Key") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("Key"); + + b.ToTable("ServerSetting"); + }); + + modelBuilder.Entity("API.Entities.Tag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ExternalTag") + .HasColumnType("INTEGER"); + + b.Property("NormalizedTitle") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedTitle", "ExternalTag") + .IsUnique(); + + b.ToTable("Tag"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Number") + .HasColumnType("INTEGER"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("SeriesId"); + + b.ToTable("Volume"); + }); + + modelBuilder.Entity("AppUserLibrary", b => + { + b.Property("AppUsersId") + .HasColumnType("INTEGER"); + + b.Property("LibrariesId") + .HasColumnType("INTEGER"); + + b.HasKey("AppUsersId", "LibrariesId"); + + b.HasIndex("LibrariesId"); + + b.ToTable("AppUserLibrary"); + }); + + modelBuilder.Entity("ChapterGenre", b => + { + b.Property("ChaptersId") + .HasColumnType("INTEGER"); + + b.Property("GenresId") + .HasColumnType("INTEGER"); + + b.HasKey("ChaptersId", "GenresId"); + + b.HasIndex("GenresId"); + + b.ToTable("ChapterGenre"); + }); + + modelBuilder.Entity("ChapterPerson", b => + { + b.Property("ChapterMetadatasId") + .HasColumnType("INTEGER"); + + b.Property("PeopleId") + .HasColumnType("INTEGER"); + + b.HasKey("ChapterMetadatasId", "PeopleId"); + + b.HasIndex("PeopleId"); + + b.ToTable("ChapterPerson"); + }); + + modelBuilder.Entity("ChapterTag", b => + { + b.Property("ChaptersId") + .HasColumnType("INTEGER"); + + b.Property("TagsId") + .HasColumnType("INTEGER"); + + b.HasKey("ChaptersId", "TagsId"); + + b.HasIndex("TagsId"); + + b.ToTable("ChapterTag"); + }); + + modelBuilder.Entity("CollectionTagSeriesMetadata", b => + { + b.Property("CollectionTagsId") + .HasColumnType("INTEGER"); + + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.HasKey("CollectionTagsId", "SeriesMetadatasId"); + + b.HasIndex("SeriesMetadatasId"); + + b.ToTable("CollectionTagSeriesMetadata"); + }); + + modelBuilder.Entity("GenreSeriesMetadata", b => + { + b.Property("GenresId") + .HasColumnType("INTEGER"); + + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.HasKey("GenresId", "SeriesMetadatasId"); + + b.HasIndex("SeriesMetadatasId"); + + b.ToTable("GenreSeriesMetadata"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("ProviderKey") + .HasColumnType("TEXT"); + + b.Property("ProviderDisplayName") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("PersonSeriesMetadata", b => + { + b.Property("PeopleId") + .HasColumnType("INTEGER"); + + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.HasKey("PeopleId", "SeriesMetadatasId"); + + b.HasIndex("SeriesMetadatasId"); + + b.ToTable("PersonSeriesMetadata"); + }); + + modelBuilder.Entity("SeriesMetadataTag", b => + { + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.Property("TagsId") + .HasColumnType("INTEGER"); + + b.HasKey("SeriesMetadatasId", "TagsId"); + + b.HasIndex("TagsId"); + + b.ToTable("SeriesMetadataTag"); + }); + + modelBuilder.Entity("API.Entities.AppUserBookmark", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Bookmarks") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserPreferences", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithOne("UserPreferences") + .HasForeignKey("API.Entities.AppUserPreferences", "AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserProgress", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Progresses") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Series", null) + .WithMany("Progress") + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserRating", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Ratings") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Series", null) + .WithMany("Ratings") + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserRole", b => + { + b.HasOne("API.Entities.AppRole", "Role") + .WithMany("UserRoles") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.AppUser", "User") + .WithMany("UserRoles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.HasOne("API.Entities.Volume", "Volume") + .WithMany("Chapters") + .HasForeignKey("VolumeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Volume"); + }); + + modelBuilder.Entity("API.Entities.FolderPath", b => + { + b.HasOne("API.Entities.Library", "Library") + .WithMany("Folders") + .HasForeignKey("LibraryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Library"); + }); + + modelBuilder.Entity("API.Entities.MangaFile", b => + { + b.HasOne("API.Entities.Chapter", "Chapter") + .WithMany("Files") + .HasForeignKey("ChapterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Chapter"); + }); + + modelBuilder.Entity("API.Entities.Metadata.SeriesMetadata", b => + { + b.HasOne("API.Entities.Series", "Series") + .WithOne("Metadata") + .HasForeignKey("API.Entities.Metadata.SeriesMetadata", "SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("ReadingLists") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.ReadingListItem", b => + { + b.HasOne("API.Entities.Chapter", "Chapter") + .WithMany() + .HasForeignKey("ChapterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.ReadingList", "ReadingList") + .WithMany("Items") + .HasForeignKey("ReadingListId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Series", "Series") + .WithMany() + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Volume", "Volume") + .WithMany() + .HasForeignKey("VolumeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Chapter"); + + b.Navigation("ReadingList"); + + b.Navigation("Series"); + + b.Navigation("Volume"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.HasOne("API.Entities.Library", "Library") + .WithMany("Series") + .HasForeignKey("LibraryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Library"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.HasOne("API.Entities.Series", "Series") + .WithMany("Volumes") + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("AppUserLibrary", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("AppUsersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Library", null) + .WithMany() + .HasForeignKey("LibrariesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ChapterGenre", b => + { + b.HasOne("API.Entities.Chapter", null) + .WithMany() + .HasForeignKey("ChaptersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Genre", null) + .WithMany() + .HasForeignKey("GenresId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ChapterPerson", b => + { + b.HasOne("API.Entities.Chapter", null) + .WithMany() + .HasForeignKey("ChapterMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Person", null) + .WithMany() + .HasForeignKey("PeopleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ChapterTag", b => + { + b.HasOne("API.Entities.Chapter", null) + .WithMany() + .HasForeignKey("ChaptersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Tag", null) + .WithMany() + .HasForeignKey("TagsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("CollectionTagSeriesMetadata", b => + { + b.HasOne("API.Entities.CollectionTag", null) + .WithMany() + .HasForeignKey("CollectionTagsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Metadata.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("GenreSeriesMetadata", b => + { + b.HasOne("API.Entities.Genre", null) + .WithMany() + .HasForeignKey("GenresId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Metadata.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("API.Entities.AppRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("PersonSeriesMetadata", b => + { + b.HasOne("API.Entities.Person", null) + .WithMany() + .HasForeignKey("PeopleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Metadata.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("SeriesMetadataTag", b => + { + b.HasOne("API.Entities.Metadata.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Tag", null) + .WithMany() + .HasForeignKey("TagsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("API.Entities.AppRole", b => + { + b.Navigation("UserRoles"); + }); + + modelBuilder.Entity("API.Entities.AppUser", b => + { + b.Navigation("Bookmarks"); + + b.Navigation("Progresses"); + + b.Navigation("Ratings"); + + b.Navigation("ReadingLists"); + + b.Navigation("UserPreferences"); + + b.Navigation("UserRoles"); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.Navigation("Files"); + }); + + modelBuilder.Entity("API.Entities.Library", b => + { + b.Navigation("Folders"); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.Navigation("Items"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.Navigation("Metadata"); + + b.Navigation("Progress"); + + b.Navigation("Ratings"); + + b.Navigation("Volumes"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.Navigation("Chapters"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/API/Data/Migrations/20220108200822_CountMetadata.cs b/API/Data/Migrations/20220108200822_CountMetadata.cs new file mode 100644 index 000000000..98a7f7e11 --- /dev/null +++ b/API/Data/Migrations/20220108200822_CountMetadata.cs @@ -0,0 +1,37 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace API.Data.Migrations +{ + public partial class CountMetadata : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "Count", + table: "SeriesMetadata", + type: "INTEGER", + nullable: false, + defaultValue: 0); + + migrationBuilder.AddColumn( + name: "Count", + table: "Chapter", + type: "INTEGER", + nullable: false, + defaultValue: 0); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "Count", + table: "SeriesMetadata"); + + migrationBuilder.DropColumn( + name: "Count", + table: "Chapter"); + } + } +} diff --git a/API/Data/Migrations/20220108202027_PublicationStatus.Designer.cs b/API/Data/Migrations/20220108202027_PublicationStatus.Designer.cs new file mode 100644 index 000000000..8479775bf --- /dev/null +++ b/API/Data/Migrations/20220108202027_PublicationStatus.Designer.cs @@ -0,0 +1,1351 @@ +// +using System; +using API.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace API.Data.Migrations +{ + [DbContext(typeof(DataContext))] + [Migration("20220108202027_PublicationStatus")] + partial class PublicationStatus + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "6.0.0"); + + modelBuilder.Entity("API.Entities.AppRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("API.Entities.AppUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessFailedCount") + .HasColumnType("INTEGER"); + + b.Property("ApiKey") + .HasColumnType("TEXT"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("EmailConfirmed") + .HasColumnType("INTEGER"); + + b.Property("LastActive") + .HasColumnType("TEXT"); + + b.Property("LockoutEnabled") + .HasColumnType("INTEGER"); + + b.Property("LockoutEnd") + .HasColumnType("TEXT"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("PasswordHash") + .HasColumnType("TEXT"); + + b.Property("PhoneNumber") + .HasColumnType("TEXT"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SecurityStamp") + .HasColumnType("TEXT"); + + b.Property("TwoFactorEnabled") + .HasColumnType("INTEGER"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("API.Entities.AppUserBookmark", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("FileName") + .HasColumnType("TEXT"); + + b.Property("Page") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("AppUserBookmark"); + }); + + modelBuilder.Entity("API.Entities.AppUserPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("AutoCloseMenu") + .HasColumnType("INTEGER"); + + b.Property("BookReaderDarkMode") + .HasColumnType("INTEGER"); + + b.Property("BookReaderFontFamily") + .HasColumnType("TEXT"); + + b.Property("BookReaderFontSize") + .HasColumnType("INTEGER"); + + b.Property("BookReaderLineSpacing") + .HasColumnType("INTEGER"); + + b.Property("BookReaderMargin") + .HasColumnType("INTEGER"); + + b.Property("BookReaderReadingDirection") + .HasColumnType("INTEGER"); + + b.Property("BookReaderTapToPaginate") + .HasColumnType("INTEGER"); + + b.Property("PageSplitOption") + .HasColumnType("INTEGER"); + + b.Property("ReaderMode") + .HasColumnType("INTEGER"); + + b.Property("ReadingDirection") + .HasColumnType("INTEGER"); + + b.Property("ScalingOption") + .HasColumnType("INTEGER"); + + b.Property("SiteDarkMode") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId") + .IsUnique(); + + b.ToTable("AppUserPreferences"); + }); + + modelBuilder.Entity("API.Entities.AppUserProgress", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("BookScrollId") + .HasColumnType("TEXT"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("PagesRead") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.HasIndex("SeriesId"); + + b.ToTable("AppUserProgresses"); + }); + + modelBuilder.Entity("API.Entities.AppUserRating", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("Rating") + .HasColumnType("INTEGER"); + + b.Property("Review") + .HasColumnType("TEXT"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.HasIndex("SeriesId"); + + b.ToTable("AppUserRating"); + }); + + modelBuilder.Entity("API.Entities.AppUserRole", b => + { + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AgeRating") + .HasColumnType("INTEGER"); + + b.Property("Count") + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("IsSpecial") + .HasColumnType("INTEGER"); + + b.Property("Language") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Number") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("Range") + .HasColumnType("TEXT"); + + b.Property("ReleaseDate") + .HasColumnType("TEXT"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.Property("TitleName") + .HasColumnType("TEXT"); + + b.Property("TotalCount") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("VolumeId"); + + b.ToTable("Chapter"); + }); + + modelBuilder.Entity("API.Entities.CollectionTag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("NormalizedTitle") + .HasColumnType("TEXT"); + + b.Property("Promoted") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Id", "Promoted") + .IsUnique(); + + b.ToTable("CollectionTag"); + }); + + modelBuilder.Entity("API.Entities.FolderPath", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("LastScanned") + .HasColumnType("TEXT"); + + b.Property("LibraryId") + .HasColumnType("INTEGER"); + + b.Property("Path") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("LibraryId"); + + b.ToTable("FolderPath"); + }); + + modelBuilder.Entity("API.Entities.Genre", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ExternalTag") + .HasColumnType("INTEGER"); + + b.Property("NormalizedTitle") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedTitle", "ExternalTag") + .IsUnique(); + + b.ToTable("Genre"); + }); + + modelBuilder.Entity("API.Entities.Library", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("LastScanned") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Library"); + }); + + modelBuilder.Entity("API.Entities.MangaFile", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("FilePath") + .HasColumnType("TEXT"); + + b.Property("Format") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ChapterId"); + + b.ToTable("MangaFile"); + }); + + modelBuilder.Entity("API.Entities.Metadata.SeriesMetadata", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AgeRating") + .HasColumnType("INTEGER"); + + b.Property("Count") + .HasColumnType("INTEGER"); + + b.Property("Language") + .HasColumnType("TEXT"); + + b.Property("PublicationStatus") + .HasColumnType("INTEGER"); + + b.Property("ReleaseYear") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("SeriesId") + .IsUnique(); + + b.HasIndex("Id", "SeriesId") + .IsUnique(); + + b.ToTable("SeriesMetadata"); + }); + + modelBuilder.Entity("API.Entities.Person", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasColumnType("TEXT"); + + b.Property("Role") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Person"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Promoted") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("ReadingList"); + }); + + modelBuilder.Entity("API.Entities.ReadingListItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("Order") + .HasColumnType("INTEGER"); + + b.Property("ReadingListId") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ChapterId"); + + b.HasIndex("ReadingListId"); + + b.HasIndex("SeriesId"); + + b.HasIndex("VolumeId"); + + b.ToTable("ReadingListItem"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("Format") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("LibraryId") + .HasColumnType("INTEGER"); + + b.Property("LocalizedName") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasColumnType("TEXT"); + + b.Property("OriginalName") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("SortName") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("LibraryId"); + + b.HasIndex("Name", "NormalizedName", "LocalizedName", "LibraryId", "Format") + .IsUnique(); + + b.ToTable("Series"); + }); + + modelBuilder.Entity("API.Entities.ServerSetting", b => + { + b.Property("Key") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("Key"); + + b.ToTable("ServerSetting"); + }); + + modelBuilder.Entity("API.Entities.Tag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ExternalTag") + .HasColumnType("INTEGER"); + + b.Property("NormalizedTitle") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedTitle", "ExternalTag") + .IsUnique(); + + b.ToTable("Tag"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Number") + .HasColumnType("INTEGER"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("SeriesId"); + + b.ToTable("Volume"); + }); + + modelBuilder.Entity("AppUserLibrary", b => + { + b.Property("AppUsersId") + .HasColumnType("INTEGER"); + + b.Property("LibrariesId") + .HasColumnType("INTEGER"); + + b.HasKey("AppUsersId", "LibrariesId"); + + b.HasIndex("LibrariesId"); + + b.ToTable("AppUserLibrary"); + }); + + modelBuilder.Entity("ChapterGenre", b => + { + b.Property("ChaptersId") + .HasColumnType("INTEGER"); + + b.Property("GenresId") + .HasColumnType("INTEGER"); + + b.HasKey("ChaptersId", "GenresId"); + + b.HasIndex("GenresId"); + + b.ToTable("ChapterGenre"); + }); + + modelBuilder.Entity("ChapterPerson", b => + { + b.Property("ChapterMetadatasId") + .HasColumnType("INTEGER"); + + b.Property("PeopleId") + .HasColumnType("INTEGER"); + + b.HasKey("ChapterMetadatasId", "PeopleId"); + + b.HasIndex("PeopleId"); + + b.ToTable("ChapterPerson"); + }); + + modelBuilder.Entity("ChapterTag", b => + { + b.Property("ChaptersId") + .HasColumnType("INTEGER"); + + b.Property("TagsId") + .HasColumnType("INTEGER"); + + b.HasKey("ChaptersId", "TagsId"); + + b.HasIndex("TagsId"); + + b.ToTable("ChapterTag"); + }); + + modelBuilder.Entity("CollectionTagSeriesMetadata", b => + { + b.Property("CollectionTagsId") + .HasColumnType("INTEGER"); + + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.HasKey("CollectionTagsId", "SeriesMetadatasId"); + + b.HasIndex("SeriesMetadatasId"); + + b.ToTable("CollectionTagSeriesMetadata"); + }); + + modelBuilder.Entity("GenreSeriesMetadata", b => + { + b.Property("GenresId") + .HasColumnType("INTEGER"); + + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.HasKey("GenresId", "SeriesMetadatasId"); + + b.HasIndex("SeriesMetadatasId"); + + b.ToTable("GenreSeriesMetadata"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("ProviderKey") + .HasColumnType("TEXT"); + + b.Property("ProviderDisplayName") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("PersonSeriesMetadata", b => + { + b.Property("PeopleId") + .HasColumnType("INTEGER"); + + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.HasKey("PeopleId", "SeriesMetadatasId"); + + b.HasIndex("SeriesMetadatasId"); + + b.ToTable("PersonSeriesMetadata"); + }); + + modelBuilder.Entity("SeriesMetadataTag", b => + { + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.Property("TagsId") + .HasColumnType("INTEGER"); + + b.HasKey("SeriesMetadatasId", "TagsId"); + + b.HasIndex("TagsId"); + + b.ToTable("SeriesMetadataTag"); + }); + + modelBuilder.Entity("API.Entities.AppUserBookmark", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Bookmarks") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserPreferences", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithOne("UserPreferences") + .HasForeignKey("API.Entities.AppUserPreferences", "AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserProgress", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Progresses") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Series", null) + .WithMany("Progress") + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserRating", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Ratings") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Series", null) + .WithMany("Ratings") + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserRole", b => + { + b.HasOne("API.Entities.AppRole", "Role") + .WithMany("UserRoles") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.AppUser", "User") + .WithMany("UserRoles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.HasOne("API.Entities.Volume", "Volume") + .WithMany("Chapters") + .HasForeignKey("VolumeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Volume"); + }); + + modelBuilder.Entity("API.Entities.FolderPath", b => + { + b.HasOne("API.Entities.Library", "Library") + .WithMany("Folders") + .HasForeignKey("LibraryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Library"); + }); + + modelBuilder.Entity("API.Entities.MangaFile", b => + { + b.HasOne("API.Entities.Chapter", "Chapter") + .WithMany("Files") + .HasForeignKey("ChapterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Chapter"); + }); + + modelBuilder.Entity("API.Entities.Metadata.SeriesMetadata", b => + { + b.HasOne("API.Entities.Series", "Series") + .WithOne("Metadata") + .HasForeignKey("API.Entities.Metadata.SeriesMetadata", "SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("ReadingLists") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.ReadingListItem", b => + { + b.HasOne("API.Entities.Chapter", "Chapter") + .WithMany() + .HasForeignKey("ChapterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.ReadingList", "ReadingList") + .WithMany("Items") + .HasForeignKey("ReadingListId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Series", "Series") + .WithMany() + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Volume", "Volume") + .WithMany() + .HasForeignKey("VolumeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Chapter"); + + b.Navigation("ReadingList"); + + b.Navigation("Series"); + + b.Navigation("Volume"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.HasOne("API.Entities.Library", "Library") + .WithMany("Series") + .HasForeignKey("LibraryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Library"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.HasOne("API.Entities.Series", "Series") + .WithMany("Volumes") + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("AppUserLibrary", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("AppUsersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Library", null) + .WithMany() + .HasForeignKey("LibrariesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ChapterGenre", b => + { + b.HasOne("API.Entities.Chapter", null) + .WithMany() + .HasForeignKey("ChaptersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Genre", null) + .WithMany() + .HasForeignKey("GenresId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ChapterPerson", b => + { + b.HasOne("API.Entities.Chapter", null) + .WithMany() + .HasForeignKey("ChapterMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Person", null) + .WithMany() + .HasForeignKey("PeopleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ChapterTag", b => + { + b.HasOne("API.Entities.Chapter", null) + .WithMany() + .HasForeignKey("ChaptersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Tag", null) + .WithMany() + .HasForeignKey("TagsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("CollectionTagSeriesMetadata", b => + { + b.HasOne("API.Entities.CollectionTag", null) + .WithMany() + .HasForeignKey("CollectionTagsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Metadata.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("GenreSeriesMetadata", b => + { + b.HasOne("API.Entities.Genre", null) + .WithMany() + .HasForeignKey("GenresId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Metadata.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("API.Entities.AppRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("PersonSeriesMetadata", b => + { + b.HasOne("API.Entities.Person", null) + .WithMany() + .HasForeignKey("PeopleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Metadata.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("SeriesMetadataTag", b => + { + b.HasOne("API.Entities.Metadata.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Tag", null) + .WithMany() + .HasForeignKey("TagsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("API.Entities.AppRole", b => + { + b.Navigation("UserRoles"); + }); + + modelBuilder.Entity("API.Entities.AppUser", b => + { + b.Navigation("Bookmarks"); + + b.Navigation("Progresses"); + + b.Navigation("Ratings"); + + b.Navigation("ReadingLists"); + + b.Navigation("UserPreferences"); + + b.Navigation("UserRoles"); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.Navigation("Files"); + }); + + modelBuilder.Entity("API.Entities.Library", b => + { + b.Navigation("Folders"); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.Navigation("Items"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.Navigation("Metadata"); + + b.Navigation("Progress"); + + b.Navigation("Ratings"); + + b.Navigation("Volumes"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.Navigation("Chapters"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/API/Data/Migrations/20220108202027_PublicationStatus.cs b/API/Data/Migrations/20220108202027_PublicationStatus.cs new file mode 100644 index 000000000..a8d676ed0 --- /dev/null +++ b/API/Data/Migrations/20220108202027_PublicationStatus.cs @@ -0,0 +1,37 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace API.Data.Migrations +{ + public partial class PublicationStatus : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "PublicationStatus", + table: "SeriesMetadata", + type: "INTEGER", + nullable: false, + defaultValue: 0); + + migrationBuilder.AddColumn( + name: "TotalCount", + table: "Chapter", + type: "INTEGER", + nullable: false, + defaultValue: 0); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "PublicationStatus", + table: "SeriesMetadata"); + + migrationBuilder.DropColumn( + name: "TotalCount", + table: "Chapter"); + } + } +} diff --git a/API/Data/Migrations/DataContextModelSnapshot.cs b/API/Data/Migrations/DataContextModelSnapshot.cs index 21a9d930a..c0aefbcd2 100644 --- a/API/Data/Migrations/DataContextModelSnapshot.cs +++ b/API/Data/Migrations/DataContextModelSnapshot.cs @@ -5,6 +5,8 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +#nullable disable + namespace API.Data.Migrations { [DbContext(typeof(DataContext))] @@ -13,8 +15,7 @@ namespace API.Data.Migrations protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "5.0.8"); + modelBuilder.HasAnnotation("ProductVersion", "6.0.0"); modelBuilder.Entity("API.Entities.AppRole", b => { @@ -40,7 +41,7 @@ namespace API.Data.Migrations .IsUnique() .HasDatabaseName("RoleNameIndex"); - b.ToTable("AspNetRoles"); + b.ToTable("AspNetRoles", (string)null); }); modelBuilder.Entity("API.Entities.AppUser", b => @@ -118,7 +119,7 @@ namespace API.Data.Migrations .IsUnique() .HasDatabaseName("UserNameIndex"); - b.ToTable("AspNetUsers"); + b.ToTable("AspNetUsers", (string)null); }); modelBuilder.Entity("API.Entities.AppUserBookmark", b => @@ -133,6 +134,9 @@ namespace API.Data.Migrations b.Property("ChapterId") .HasColumnType("INTEGER"); + b.Property("FileName") + .HasColumnType("TEXT"); + b.Property("Page") .HasColumnType("INTEGER"); @@ -239,6 +243,8 @@ namespace API.Data.Migrations b.HasIndex("AppUserId"); + b.HasIndex("SeriesId"); + b.ToTable("AppUserProgresses"); }); @@ -264,6 +270,8 @@ namespace API.Data.Migrations b.HasIndex("AppUserId"); + b.HasIndex("SeriesId"); + b.ToTable("AppUserRating"); }); @@ -279,7 +287,7 @@ namespace API.Data.Migrations b.HasIndex("RoleId"); - b.ToTable("AspNetUserRoles"); + b.ToTable("AspNetUserRoles", (string)null); }); modelBuilder.Entity("API.Entities.Chapter", b => @@ -288,6 +296,12 @@ namespace API.Data.Migrations .ValueGeneratedOnAdd() .HasColumnType("INTEGER"); + b.Property("AgeRating") + .HasColumnType("INTEGER"); + + b.Property("Count") + .HasColumnType("INTEGER"); + b.Property("CoverImage") .HasColumnType("TEXT"); @@ -300,6 +314,9 @@ namespace API.Data.Migrations b.Property("IsSpecial") .HasColumnType("INTEGER"); + b.Property("Language") + .HasColumnType("TEXT"); + b.Property("LastModified") .HasColumnType("TEXT"); @@ -312,9 +329,21 @@ namespace API.Data.Migrations b.Property("Range") .HasColumnType("TEXT"); + b.Property("ReleaseDate") + .HasColumnType("TEXT"); + + b.Property("Summary") + .HasColumnType("TEXT"); + b.Property("Title") .HasColumnType("TEXT"); + b.Property("TitleName") + .HasColumnType("TEXT"); + + b.Property("TotalCount") + .HasColumnType("INTEGER"); + b.Property("VolumeId") .HasColumnType("INTEGER"); @@ -382,6 +411,29 @@ namespace API.Data.Migrations b.ToTable("FolderPath"); }); + modelBuilder.Entity("API.Entities.Genre", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ExternalTag") + .HasColumnType("INTEGER"); + + b.Property("NormalizedTitle") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedTitle", "ExternalTag") + .IsUnique(); + + b.ToTable("Genre"); + }); + modelBuilder.Entity("API.Entities.Library", b => { b.Property("Id") @@ -439,6 +491,68 @@ namespace API.Data.Migrations b.ToTable("MangaFile"); }); + modelBuilder.Entity("API.Entities.Metadata.SeriesMetadata", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AgeRating") + .HasColumnType("INTEGER"); + + b.Property("Count") + .HasColumnType("INTEGER"); + + b.Property("Language") + .HasColumnType("TEXT"); + + b.Property("PublicationStatus") + .HasColumnType("INTEGER"); + + b.Property("ReleaseYear") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("SeriesId") + .IsUnique(); + + b.HasIndex("Id", "SeriesId") + .IsUnique(); + + b.ToTable("SeriesMetadata"); + }); + + modelBuilder.Entity("API.Entities.Person", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasColumnType("TEXT"); + + b.Property("Role") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Person"); + }); + modelBuilder.Entity("API.Entities.ReadingList", b => { b.Property("Id") @@ -546,9 +660,6 @@ namespace API.Data.Migrations b.Property("SortName") .HasColumnType("TEXT"); - b.Property("Summary") - .HasColumnType("TEXT"); - b.HasKey("Id"); b.HasIndex("LibraryId"); @@ -559,30 +670,6 @@ namespace API.Data.Migrations b.ToTable("Series"); }); - modelBuilder.Entity("API.Entities.SeriesMetadata", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("SeriesId") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("SeriesId") - .IsUnique(); - - b.HasIndex("Id", "SeriesId") - .IsUnique(); - - b.ToTable("SeriesMetadata"); - }); - modelBuilder.Entity("API.Entities.ServerSetting", b => { b.Property("Key") @@ -600,6 +687,29 @@ namespace API.Data.Migrations b.ToTable("ServerSetting"); }); + modelBuilder.Entity("API.Entities.Tag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ExternalTag") + .HasColumnType("INTEGER"); + + b.Property("NormalizedTitle") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedTitle", "ExternalTag") + .IsUnique(); + + b.ToTable("Tag"); + }); + modelBuilder.Entity("API.Entities.Volume", b => { b.Property("Id") @@ -649,6 +759,51 @@ namespace API.Data.Migrations b.ToTable("AppUserLibrary"); }); + modelBuilder.Entity("ChapterGenre", b => + { + b.Property("ChaptersId") + .HasColumnType("INTEGER"); + + b.Property("GenresId") + .HasColumnType("INTEGER"); + + b.HasKey("ChaptersId", "GenresId"); + + b.HasIndex("GenresId"); + + b.ToTable("ChapterGenre"); + }); + + modelBuilder.Entity("ChapterPerson", b => + { + b.Property("ChapterMetadatasId") + .HasColumnType("INTEGER"); + + b.Property("PeopleId") + .HasColumnType("INTEGER"); + + b.HasKey("ChapterMetadatasId", "PeopleId"); + + b.HasIndex("PeopleId"); + + b.ToTable("ChapterPerson"); + }); + + modelBuilder.Entity("ChapterTag", b => + { + b.Property("ChaptersId") + .HasColumnType("INTEGER"); + + b.Property("TagsId") + .HasColumnType("INTEGER"); + + b.HasKey("ChaptersId", "TagsId"); + + b.HasIndex("TagsId"); + + b.ToTable("ChapterTag"); + }); + modelBuilder.Entity("CollectionTagSeriesMetadata", b => { b.Property("CollectionTagsId") @@ -664,6 +819,21 @@ namespace API.Data.Migrations b.ToTable("CollectionTagSeriesMetadata"); }); + modelBuilder.Entity("GenreSeriesMetadata", b => + { + b.Property("GenresId") + .HasColumnType("INTEGER"); + + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.HasKey("GenresId", "SeriesMetadatasId"); + + b.HasIndex("SeriesMetadatasId"); + + b.ToTable("GenreSeriesMetadata"); + }); + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => { b.Property("Id") @@ -683,7 +853,7 @@ namespace API.Data.Migrations b.HasIndex("RoleId"); - b.ToTable("AspNetRoleClaims"); + b.ToTable("AspNetRoleClaims", (string)null); }); modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => @@ -705,7 +875,7 @@ namespace API.Data.Migrations b.HasIndex("UserId"); - b.ToTable("AspNetUserClaims"); + b.ToTable("AspNetUserClaims", (string)null); }); modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => @@ -726,7 +896,7 @@ namespace API.Data.Migrations b.HasIndex("UserId"); - b.ToTable("AspNetUserLogins"); + b.ToTable("AspNetUserLogins", (string)null); }); modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => @@ -745,7 +915,37 @@ namespace API.Data.Migrations b.HasKey("UserId", "LoginProvider", "Name"); - b.ToTable("AspNetUserTokens"); + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("PersonSeriesMetadata", b => + { + b.Property("PeopleId") + .HasColumnType("INTEGER"); + + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.HasKey("PeopleId", "SeriesMetadatasId"); + + b.HasIndex("SeriesMetadatasId"); + + b.ToTable("PersonSeriesMetadata"); + }); + + modelBuilder.Entity("SeriesMetadataTag", b => + { + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.Property("TagsId") + .HasColumnType("INTEGER"); + + b.HasKey("SeriesMetadatasId", "TagsId"); + + b.HasIndex("TagsId"); + + b.ToTable("SeriesMetadataTag"); }); modelBuilder.Entity("API.Entities.AppUserBookmark", b => @@ -778,6 +978,12 @@ namespace API.Data.Migrations .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + b.HasOne("API.Entities.Series", null) + .WithMany("Progress") + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + b.Navigation("AppUser"); }); @@ -789,6 +995,12 @@ namespace API.Data.Migrations .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + b.HasOne("API.Entities.Series", null) + .WithMany("Ratings") + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + b.Navigation("AppUser"); }); @@ -844,6 +1056,17 @@ namespace API.Data.Migrations b.Navigation("Chapter"); }); + modelBuilder.Entity("API.Entities.Metadata.SeriesMetadata", b => + { + b.HasOne("API.Entities.Series", "Series") + .WithOne("Metadata") + .HasForeignKey("API.Entities.Metadata.SeriesMetadata", "SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Series"); + }); + modelBuilder.Entity("API.Entities.ReadingList", b => { b.HasOne("API.Entities.AppUser", "AppUser") @@ -901,17 +1124,6 @@ namespace API.Data.Migrations b.Navigation("Library"); }); - modelBuilder.Entity("API.Entities.SeriesMetadata", b => - { - b.HasOne("API.Entities.Series", "Series") - .WithOne("Metadata") - .HasForeignKey("API.Entities.SeriesMetadata", "SeriesId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Series"); - }); - modelBuilder.Entity("API.Entities.Volume", b => { b.HasOne("API.Entities.Series", "Series") @@ -938,6 +1150,51 @@ namespace API.Data.Migrations .IsRequired(); }); + modelBuilder.Entity("ChapterGenre", b => + { + b.HasOne("API.Entities.Chapter", null) + .WithMany() + .HasForeignKey("ChaptersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Genre", null) + .WithMany() + .HasForeignKey("GenresId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ChapterPerson", b => + { + b.HasOne("API.Entities.Chapter", null) + .WithMany() + .HasForeignKey("ChapterMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Person", null) + .WithMany() + .HasForeignKey("PeopleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ChapterTag", b => + { + b.HasOne("API.Entities.Chapter", null) + .WithMany() + .HasForeignKey("ChaptersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Tag", null) + .WithMany() + .HasForeignKey("TagsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + modelBuilder.Entity("CollectionTagSeriesMetadata", b => { b.HasOne("API.Entities.CollectionTag", null) @@ -946,7 +1203,22 @@ namespace API.Data.Migrations .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("API.Entities.SeriesMetadata", null) + b.HasOne("API.Entities.Metadata.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("GenreSeriesMetadata", b => + { + b.HasOne("API.Entities.Genre", null) + .WithMany() + .HasForeignKey("GenresId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Metadata.SeriesMetadata", null) .WithMany() .HasForeignKey("SeriesMetadatasId") .OnDelete(DeleteBehavior.Cascade) @@ -989,6 +1261,36 @@ namespace API.Data.Migrations .IsRequired(); }); + modelBuilder.Entity("PersonSeriesMetadata", b => + { + b.HasOne("API.Entities.Person", null) + .WithMany() + .HasForeignKey("PeopleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Metadata.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("SeriesMetadataTag", b => + { + b.HasOne("API.Entities.Metadata.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Tag", null) + .WithMany() + .HasForeignKey("TagsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + modelBuilder.Entity("API.Entities.AppRole", b => { b.Navigation("UserRoles"); @@ -1030,6 +1332,10 @@ namespace API.Data.Migrations { b.Navigation("Metadata"); + b.Navigation("Progress"); + + b.Navigation("Ratings"); + b.Navigation("Volumes"); }); diff --git a/API/Data/Repositories/AppUserProgressRepository.cs b/API/Data/Repositories/AppUserProgressRepository.cs index c91e61cd0..37fc68693 100644 --- a/API/Data/Repositories/AppUserProgressRepository.cs +++ b/API/Data/Repositories/AppUserProgressRepository.cs @@ -2,78 +2,84 @@ using System.Threading.Tasks; using API.Entities; using API.Entities.Enums; -using API.Interfaces.Repositories; using Microsoft.EntityFrameworkCore; -namespace API.Data.Repositories +namespace API.Data.Repositories; + +public interface IAppUserProgressRepository { - public class AppUserProgressRepository : IAppUserProgressRepository + void Update(AppUserProgress userProgress); + Task CleanupAbandonedChapters(); + Task UserHasProgress(LibraryType libraryType, int userId); + Task GetUserProgressAsync(int chapterId, int userId); +} + +public class AppUserProgressRepository : IAppUserProgressRepository +{ + private readonly DataContext _context; + + public AppUserProgressRepository(DataContext context) { - private readonly DataContext _context; + _context = context; + } - public AppUserProgressRepository(DataContext context) - { - _context = context; - } + public void Update(AppUserProgress userProgress) + { + _context.Entry(userProgress).State = EntityState.Modified; + } - public void Update(AppUserProgress userProgress) - { - _context.Entry(userProgress).State = EntityState.Modified; - } + /// + /// This will remove any entries that have chapterIds that no longer exists. This will execute the save as well. + /// + public async Task CleanupAbandonedChapters() + { + var chapterIds = _context.Chapter.Select(c => c.Id); - /// - /// This will remove any entries that have chapterIds that no longer exists. This will execute the save as well. - /// - public async Task CleanupAbandonedChapters() - { - var chapterIds = _context.Chapter.Select(c => c.Id); + var rowsToRemove = await _context.AppUserProgresses + .Where(progress => !chapterIds.Contains(progress.ChapterId)) + .ToListAsync(); - var rowsToRemove = await _context.AppUserProgresses - .Where(progress => !chapterIds.Contains(progress.ChapterId)) - .ToListAsync(); + var rowsToRemoveBookmarks = await _context.AppUserBookmark + .Where(progress => !chapterIds.Contains(progress.ChapterId)) + .ToListAsync(); - var rowsToRemoveBookmarks = await _context.AppUserBookmark - .Where(progress => !chapterIds.Contains(progress.ChapterId)) - .ToListAsync(); + var rowsToRemoveReadingLists = await _context.ReadingListItem + .Where(item => !chapterIds.Contains(item.ChapterId)) + .ToListAsync(); - var rowsToRemoveReadingLists = await _context.ReadingListItem - .Where(item => !chapterIds.Contains(item.ChapterId)) - .ToListAsync(); + _context.RemoveRange(rowsToRemove); + _context.RemoveRange(rowsToRemoveBookmarks); + _context.RemoveRange(rowsToRemoveReadingLists); + return await _context.SaveChangesAsync() > 0 ? rowsToRemove.Count : 0; + } - _context.RemoveRange(rowsToRemove); - _context.RemoveRange(rowsToRemoveBookmarks); - _context.RemoveRange(rowsToRemoveReadingLists); - return await _context.SaveChangesAsync() > 0 ? rowsToRemove.Count : 0; - } + /// + /// Checks if user has any progress against a library of passed type + /// + /// + /// + /// + public async Task UserHasProgress(LibraryType libraryType, int userId) + { + var seriesIds = await _context.AppUserProgresses + .Where(aup => aup.PagesRead > 0 && aup.AppUserId == userId) + .AsNoTracking() + .Select(aup => aup.SeriesId) + .ToListAsync(); - /// - /// Checks if user has any progress against a library of passed type - /// - /// - /// - /// - public async Task UserHasProgress(LibraryType libraryType, int userId) - { - var seriesIds = await _context.AppUserProgresses - .Where(aup => aup.PagesRead > 0 && aup.AppUserId == userId) - .AsNoTracking() - .Select(aup => aup.SeriesId) - .ToListAsync(); + if (seriesIds.Count == 0) return false; - if (seriesIds.Count == 0) return false; + return await _context.Series + .Include(s => s.Library) + .Where(s => seriesIds.Contains(s.Id) && s.Library.Type == libraryType) + .AsNoTracking() + .AnyAsync(); + } - return await _context.Series - .Include(s => s.Library) - .Where(s => seriesIds.Contains(s.Id) && s.Library.Type == libraryType) - .AsNoTracking() - .AnyAsync(); - } - - public async Task GetUserProgressAsync(int chapterId, int userId) - { - return await _context.AppUserProgresses - .Where(p => p.ChapterId == chapterId && p.AppUserId == userId) - .FirstOrDefaultAsync(); - } + public async Task GetUserProgressAsync(int chapterId, int userId) + { + return await _context.AppUserProgresses + .Where(p => p.ChapterId == chapterId && p.AppUserId == userId) + .FirstOrDefaultAsync(); } } diff --git a/API/Data/Repositories/ChapterRepository.cs b/API/Data/Repositories/ChapterRepository.cs index 54c808d9c..f89304f74 100644 --- a/API/Data/Repositories/ChapterRepository.cs +++ b/API/Data/Repositories/ChapterRepository.cs @@ -4,186 +4,205 @@ using System.Threading.Tasks; using API.DTOs; using API.DTOs.Reader; using API.Entities; -using API.Interfaces.Repositories; using AutoMapper; using AutoMapper.QueryableExtensions; using Microsoft.EntityFrameworkCore; -namespace API.Data.Repositories +namespace API.Data.Repositories; + +public interface IChapterRepository { - public class ChapterRepository : IChapterRepository + void Update(Chapter chapter); + Task> GetChaptersByIdsAsync(IList chapterIds); + Task GetChapterInfoDtoAsync(int chapterId); + Task GetChapterTotalPagesAsync(int chapterId); + Task GetChapterAsync(int chapterId); + Task GetChapterDtoAsync(int chapterId); + Task> GetFilesForChapterAsync(int chapterId); + Task> GetChaptersAsync(int volumeId); + Task> GetFilesForChaptersAsync(IReadOnlyList chapterIds); + Task GetChapterCoverImageAsync(int chapterId); + Task> GetAllCoverImagesAsync(); + Task> GetCoverImagesForLockedChaptersAsync(); +} +public class ChapterRepository : IChapterRepository +{ + private readonly DataContext _context; + private readonly IMapper _mapper; + + public ChapterRepository(DataContext context, IMapper mapper) { - private readonly DataContext _context; - private readonly IMapper _mapper; + _context = context; + _mapper = mapper; + } - public ChapterRepository(DataContext context, IMapper mapper) - { - _context = context; - _mapper = mapper; - } + public void Update(Chapter chapter) + { + _context.Entry(chapter).State = EntityState.Modified; + } - public void Update(Chapter chapter) - { - _context.Entry(chapter).State = EntityState.Modified; - } + public async Task> GetChaptersByIdsAsync(IList chapterIds) + { + return await _context.Chapter + .Where(c => chapterIds.Contains(c.Id)) + .Include(c => c.Volume) + .ToListAsync(); + } - public async Task> GetChaptersByIdsAsync(IList chapterIds) - { - return await _context.Chapter - .Where(c => chapterIds.Contains(c.Id)) - .Include(c => c.Volume) - .ToListAsync(); - } + /// + /// Populates a partial IChapterInfoDto + /// + /// + public async Task GetChapterInfoDtoAsync(int chapterId) + { + var chapterInfo = await _context.Chapter + .Where(c => c.Id == chapterId) + .Join(_context.Volume, c => c.VolumeId, v => v.Id, (chapter, volume) => new + { + ChapterNumber = chapter.Range, + VolumeNumber = volume.Number, + VolumeId = volume.Id, + chapter.IsSpecial, + chapter.TitleName, + volume.SeriesId, + chapter.Pages, + }) + .Join(_context.Series, data => data.SeriesId, series => series.Id, (data, series) => new + { + data.ChapterNumber, + data.VolumeNumber, + data.VolumeId, + data.IsSpecial, + data.SeriesId, + data.Pages, + data.TitleName, + SeriesFormat = series.Format, + SeriesName = series.Name, + series.LibraryId + }) + .Select(data => new ChapterInfoDto() + { + ChapterNumber = data.ChapterNumber, + VolumeNumber = data.VolumeNumber + string.Empty, + VolumeId = data.VolumeId, + IsSpecial = data.IsSpecial, + SeriesId =data.SeriesId, + SeriesFormat = data.SeriesFormat, + SeriesName = data.SeriesName, + LibraryId = data.LibraryId, + Pages = data.Pages, + ChapterTitle = data.TitleName + }) + .AsNoTracking() + .AsSplitQuery() + .SingleOrDefaultAsync(); - /// - /// Populates a partial IChapterInfoDto - /// - /// - public async Task GetChapterInfoDtoAsync(int chapterId) - { - return await _context.Chapter - .Where(c => c.Id == chapterId) - .Join(_context.Volume, c => c.VolumeId, v => v.Id, (chapter, volume) => new - { - ChapterNumber = chapter.Range, - VolumeNumber = volume.Number, - VolumeId = volume.Id, - chapter.IsSpecial, - volume.SeriesId, - chapter.Pages - }) - .Join(_context.Series, data => data.SeriesId, series => series.Id, (data, series) => new - { - data.ChapterNumber, - data.VolumeNumber, - data.VolumeId, - data.IsSpecial, - data.SeriesId, - data.Pages, - SeriesFormat = series.Format, - SeriesName = series.Name, - series.LibraryId - }) - .Select(data => new BookInfoDto() - { - ChapterNumber = data.ChapterNumber, - VolumeNumber = data.VolumeNumber + string.Empty, - VolumeId = data.VolumeId, - IsSpecial = data.IsSpecial, - SeriesId =data.SeriesId, - SeriesFormat = data.SeriesFormat, - SeriesName = data.SeriesName, - LibraryId = data.LibraryId, - Pages = data.Pages - }) - .AsNoTracking() - .SingleAsync(); - } + return chapterInfo; + } - public Task GetChapterTotalPagesAsync(int chapterId) - { - return _context.Chapter - .Where(c => c.Id == chapterId) - .Select(c => c.Pages) - .SingleOrDefaultAsync(); - } - public async Task GetChapterDtoAsync(int chapterId) - { - var chapter = await _context.Chapter - .Include(c => c.Files) - .ProjectTo(_mapper.ConfigurationProvider) - .AsNoTracking() - .SingleOrDefaultAsync(c => c.Id == chapterId); + public Task GetChapterTotalPagesAsync(int chapterId) + { + return _context.Chapter + .Where(c => c.Id == chapterId) + .Select(c => c.Pages) + .SingleOrDefaultAsync(); + } + public async Task GetChapterDtoAsync(int chapterId) + { + var chapter = await _context.Chapter + .Include(c => c.Files) + .ProjectTo(_mapper.ConfigurationProvider) + .AsNoTracking() + .SingleOrDefaultAsync(c => c.Id == chapterId); - return chapter; - } + return chapter; + } - /// - /// Returns non-tracked files for a given chapterId - /// - /// - /// - public async Task> GetFilesForChapterAsync(int chapterId) - { - return await _context.MangaFile - .Where(c => chapterId == c.ChapterId) - .AsNoTracking() - .ToListAsync(); - } + /// + /// Returns non-tracked files for a given chapterId + /// + /// + /// + public async Task> GetFilesForChapterAsync(int chapterId) + { + return await _context.MangaFile + .Where(c => chapterId == c.ChapterId) + .AsNoTracking() + .ToListAsync(); + } - /// - /// Returns a Chapter for an Id. Includes linked s. - /// - /// - /// - public async Task GetChapterAsync(int chapterId) - { - return await _context.Chapter - .Include(c => c.Files) - .SingleOrDefaultAsync(c => c.Id == chapterId); - } + /// + /// Returns a Chapter for an Id. Includes linked s. + /// + /// + /// + public async Task GetChapterAsync(int chapterId) + { + return await _context.Chapter + .Include(c => c.Files) + .SingleOrDefaultAsync(c => c.Id == chapterId); + } - /// - /// Returns Chapters for a volume id. - /// - /// - /// - public async Task> GetChaptersAsync(int volumeId) - { - return await _context.Chapter - .Where(c => c.VolumeId == volumeId) - .ToListAsync(); - } + /// + /// Returns Chapters for a volume id. + /// + /// + /// + public async Task> GetChaptersAsync(int volumeId) + { + return await _context.Chapter + .Where(c => c.VolumeId == volumeId) + .ToListAsync(); + } - /// - /// Returns the cover image for a chapter id. - /// - /// - /// - public async Task GetChapterCoverImageAsync(int chapterId) - { + /// + /// Returns the cover image for a chapter id. + /// + /// + /// + public async Task GetChapterCoverImageAsync(int chapterId) + { - return await _context.Chapter - .Where(c => c.Id == chapterId) - .Select(c => c.CoverImage) - .AsNoTracking() - .SingleOrDefaultAsync(); - } + return await _context.Chapter + .Where(c => c.Id == chapterId) + .Select(c => c.CoverImage) + .AsNoTracking() + .SingleOrDefaultAsync(); + } - public async Task> GetAllCoverImagesAsync() - { - return await _context.Chapter - .Select(c => c.CoverImage) - .Where(t => !string.IsNullOrEmpty(t)) - .AsNoTracking() - .ToListAsync(); - } + public async Task> GetAllCoverImagesAsync() + { + return await _context.Chapter + .Select(c => c.CoverImage) + .Where(t => !string.IsNullOrEmpty(t)) + .AsNoTracking() + .ToListAsync(); + } - /// - /// Returns cover images for locked chapters - /// - /// - public async Task> GetCoverImagesForLockedChaptersAsync() - { - return await _context.Chapter - .Where(c => c.CoverImageLocked) - .Select(c => c.CoverImage) - .Where(t => !string.IsNullOrEmpty(t)) - .AsNoTracking() - .ToListAsync(); - } + /// + /// Returns cover images for locked chapters + /// + /// + public async Task> GetCoverImagesForLockedChaptersAsync() + { + return await _context.Chapter + .Where(c => c.CoverImageLocked) + .Select(c => c.CoverImage) + .Where(t => !string.IsNullOrEmpty(t)) + .AsNoTracking() + .ToListAsync(); + } - /// - /// Returns non-tracked files for a set of - /// - /// List of chapter Ids - /// - public async Task> GetFilesForChaptersAsync(IReadOnlyList chapterIds) - { - return await _context.MangaFile - .Where(c => chapterIds.Contains(c.ChapterId)) - .AsNoTracking() - .ToListAsync(); - } + /// + /// Returns non-tracked files for a set of + /// + /// List of chapter Ids + /// + public async Task> GetFilesForChaptersAsync(IReadOnlyList chapterIds) + { + return await _context.MangaFile + .Where(c => chapterIds.Contains(c.ChapterId)) + .AsNoTracking() + .ToListAsync(); } } diff --git a/API/Data/Repositories/CollectionTagRepository.cs b/API/Data/Repositories/CollectionTagRepository.cs index f47ce721f..a519c774f 100644 --- a/API/Data/Repositories/CollectionTagRepository.cs +++ b/API/Data/Repositories/CollectionTagRepository.cs @@ -2,126 +2,138 @@ using System.IO; using System.Linq; using System.Threading.Tasks; -using API.DTOs; using API.DTOs.CollectionTags; using API.Entities; -using API.Interfaces.Repositories; using AutoMapper; using AutoMapper.QueryableExtensions; using Microsoft.EntityFrameworkCore; -namespace API.Data.Repositories +namespace API.Data.Repositories; + +public interface ICollectionTagRepository { - public class CollectionTagRepository : ICollectionTagRepository + void Add(CollectionTag tag); + void Remove(CollectionTag tag); + Task> GetAllTagDtosAsync(); + Task> SearchTagDtosAsync(string searchQuery); + Task GetCoverImageAsync(int collectionTagId); + Task> GetAllPromotedTagDtosAsync(); + Task GetTagAsync(int tagId); + Task GetFullTagAsync(int tagId); + void Update(CollectionTag tag); + Task RemoveTagsWithoutSeries(); + Task> GetAllTagsAsync(); + Task> GetAllCoverImagesAsync(); +} +public class CollectionTagRepository : ICollectionTagRepository +{ + private readonly DataContext _context; + private readonly IMapper _mapper; + + public CollectionTagRepository(DataContext context, IMapper mapper) { - private readonly DataContext _context; - private readonly IMapper _mapper; + _context = context; + _mapper = mapper; + } - public CollectionTagRepository(DataContext context, IMapper mapper) - { - _context = context; - _mapper = mapper; - } + public void Add(CollectionTag tag) + { + _context.CollectionTag.Add(tag); + } - public void Add(CollectionTag tag) - { - _context.CollectionTag.Add(tag); - } + public void Remove(CollectionTag tag) + { + _context.CollectionTag.Remove(tag); + } - public void Remove(CollectionTag tag) - { - _context.CollectionTag.Remove(tag); - } + public void Update(CollectionTag tag) + { + _context.Entry(tag).State = EntityState.Modified; + } - public void Update(CollectionTag tag) - { - _context.Entry(tag).State = EntityState.Modified; - } + /// + /// Removes any collection tags without any series + /// + public async Task RemoveTagsWithoutSeries() + { + var tagsToDelete = await _context.CollectionTag + .Include(c => c.SeriesMetadatas) + .Where(c => c.SeriesMetadatas.Count == 0) + .ToListAsync(); + _context.RemoveRange(tagsToDelete); - /// - /// Removes any collection tags without any series - /// - public async Task RemoveTagsWithoutSeries() - { - var tagsToDelete = await _context.CollectionTag - .Include(c => c.SeriesMetadatas) - .Where(c => c.SeriesMetadatas.Count == 0) - .ToListAsync(); - _context.RemoveRange(tagsToDelete); + return await _context.SaveChangesAsync(); + } - return await _context.SaveChangesAsync(); - } + public async Task> GetAllTagsAsync() + { + return await _context.CollectionTag + .OrderBy(c => c.NormalizedTitle) + .ToListAsync(); + } - public async Task> GetAllTagsAsync() - { - return await _context.CollectionTag - .OrderBy(c => c.NormalizedTitle) - .ToListAsync(); - } + public async Task> GetAllCoverImagesAsync() + { + return await _context.CollectionTag + .Select(t => t.CoverImage) + .Where(t => !string.IsNullOrEmpty(t)) + .AsNoTracking() + .ToListAsync(); + } - public async Task> GetAllCoverImagesAsync() - { - return await _context.CollectionTag - .Select(t => t.CoverImage) - .Where(t => !string.IsNullOrEmpty(t)) - .AsNoTracking() - .ToListAsync(); - } + public async Task> GetAllTagDtosAsync() + { + return await _context.CollectionTag + .Select(c => c) + .OrderBy(c => c.NormalizedTitle) + .AsNoTracking() + .ProjectTo(_mapper.ConfigurationProvider) + .ToListAsync(); + } - public async Task> GetAllTagDtosAsync() - { - return await _context.CollectionTag - .Select(c => c) - .OrderBy(c => c.NormalizedTitle) - .AsNoTracking() - .ProjectTo(_mapper.ConfigurationProvider) - .ToListAsync(); - } + public async Task> GetAllPromotedTagDtosAsync() + { + return await _context.CollectionTag + .Where(c => c.Promoted) + .OrderBy(c => c.NormalizedTitle) + .AsNoTracking() + .ProjectTo(_mapper.ConfigurationProvider) + .ToListAsync(); + } - public async Task> GetAllPromotedTagDtosAsync() - { - return await _context.CollectionTag - .Where(c => c.Promoted) - .OrderBy(c => c.NormalizedTitle) - .AsNoTracking() - .ProjectTo(_mapper.ConfigurationProvider) - .ToListAsync(); - } + public async Task GetTagAsync(int tagId) + { + return await _context.CollectionTag + .Where(c => c.Id == tagId) + .SingleOrDefaultAsync(); + } - public async Task GetTagAsync(int tagId) - { - return await _context.CollectionTag - .Where(c => c.Id == tagId) - .SingleOrDefaultAsync(); - } + public async Task GetFullTagAsync(int tagId) + { + return await _context.CollectionTag + .Where(c => c.Id == tagId) + .Include(c => c.SeriesMetadatas) + .SingleOrDefaultAsync(); + } - public async Task GetFullTagAsync(int tagId) - { - return await _context.CollectionTag - .Where(c => c.Id == tagId) - .Include(c => c.SeriesMetadatas) - .SingleOrDefaultAsync(); - } + public async Task> SearchTagDtosAsync(string searchQuery) + { + return await _context.CollectionTag + .Where(s => EF.Functions.Like(s.Title, $"%{searchQuery}%") + || EF.Functions.Like(s.NormalizedTitle, $"%{searchQuery}%")) + .OrderBy(s => s.Title) + .AsNoTracking() + .OrderBy(c => c.NormalizedTitle) + .ProjectTo(_mapper.ConfigurationProvider) + .ToListAsync(); + } - public async Task> SearchTagDtosAsync(string searchQuery) - { - return await _context.CollectionTag - .Where(s => EF.Functions.Like(s.Title, $"%{searchQuery}%") - || EF.Functions.Like(s.NormalizedTitle, $"%{searchQuery}%")) - .OrderBy(s => s.Title) - .AsNoTracking() - .OrderBy(c => c.NormalizedTitle) - .ProjectTo(_mapper.ConfigurationProvider) - .ToListAsync(); - } - - public async Task GetCoverImageAsync(int collectionTagId) - { - return await _context.CollectionTag - .Where(c => c.Id == collectionTagId) - .Select(c => c.CoverImage) - .AsNoTracking() - .SingleOrDefaultAsync(); - } + public async Task GetCoverImageAsync(int collectionTagId) + { + return await _context.CollectionTag + .Where(c => c.Id == collectionTagId) + .Select(c => c.CoverImage) + .AsNoTracking() + .SingleOrDefaultAsync(); } } diff --git a/API/Data/Repositories/FileRepository.cs b/API/Data/Repositories/FileRepository.cs deleted file mode 100644 index 4665dac7e..000000000 --- a/API/Data/Repositories/FileRepository.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Threading.Tasks; -using API.Interfaces.Repositories; -using Microsoft.EntityFrameworkCore; - -namespace API.Data.Repositories -{ - public class FileRepository : IFileRepository - { - private readonly DataContext _dbContext; - - public FileRepository(DataContext context) - { - _dbContext = context; - } - - public async Task> GetFileExtensions() - { - var fileExtensions = await _dbContext.MangaFile - .AsNoTracking() - .Select(x => x.FilePath.ToLower()) - .Distinct() - .ToArrayAsync(); - - var uniqueFileTypes = fileExtensions - .Select(Path.GetExtension) - .Where(x => x is not null) - .Distinct(); - - return uniqueFileTypes; - } - } -} diff --git a/API/Data/Repositories/GenreRepository.cs b/API/Data/Repositories/GenreRepository.cs new file mode 100644 index 000000000..05f2052f4 --- /dev/null +++ b/API/Data/Repositories/GenreRepository.cs @@ -0,0 +1,86 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using API.DTOs.Metadata; +using API.Entities; +using AutoMapper; +using AutoMapper.QueryableExtensions; +using Microsoft.EntityFrameworkCore; + +namespace API.Data.Repositories; + +public interface IGenreRepository +{ + void Attach(Genre genre); + void Remove(Genre genre); + Task FindByNameAsync(string genreName); + Task> GetAllGenresAsync(); + Task> GetAllGenreDtosAsync(); + Task RemoveAllGenreNoLongerAssociated(bool removeExternal = false); + Task> GetAllGenreDtosForLibrariesAsync(IList libraryIds); +} + +public class GenreRepository : IGenreRepository +{ + private readonly DataContext _context; + private readonly IMapper _mapper; + + public GenreRepository(DataContext context, IMapper mapper) + { + _context = context; + _mapper = mapper; + } + + public void Attach(Genre genre) + { + _context.Genre.Attach(genre); + } + + public void Remove(Genre genre) + { + _context.Genre.Remove(genre); + } + + public async Task FindByNameAsync(string genreName) + { + var normalizedName = Parser.Parser.Normalize(genreName); + return await _context.Genre + .FirstOrDefaultAsync(g => g.NormalizedTitle.Equals(normalizedName)); + } + + public async Task RemoveAllGenreNoLongerAssociated(bool removeExternal = false) + { + var genresWithNoConnections = await _context.Genre + .Include(p => p.SeriesMetadatas) + .Include(p => p.Chapters) + .Where(p => p.SeriesMetadatas.Count == 0 && p.Chapters.Count == 0 && p.ExternalTag == removeExternal) + .ToListAsync(); + + _context.Genre.RemoveRange(genresWithNoConnections); + + await _context.SaveChangesAsync(); + } + + public async Task> GetAllGenreDtosForLibrariesAsync(IList libraryIds) + { + return await _context.Series + .Where(s => libraryIds.Contains(s.LibraryId)) + .SelectMany(s => s.Metadata.Genres) + .Distinct() + .ProjectTo(_mapper.ConfigurationProvider) + .ToListAsync(); + } + + public async Task> GetAllGenresAsync() + { + return await _context.Genre.ToListAsync(); + } + + public async Task> GetAllGenreDtosAsync() + { + return await _context.Genre + .AsNoTracking() + .ProjectTo(_mapper.ConfigurationProvider) + .ToListAsync(); + } +} diff --git a/API/Data/Repositories/LibraryRepository.cs b/API/Data/Repositories/LibraryRepository.cs index caae93dd6..26fc517a2 100644 --- a/API/Data/Repositories/LibraryRepository.cs +++ b/API/Data/Repositories/LibraryRepository.cs @@ -5,194 +5,208 @@ using System.Threading.Tasks; using API.DTOs; using API.Entities; using API.Entities.Enums; -using API.Interfaces.Repositories; using AutoMapper; using AutoMapper.QueryableExtensions; using Microsoft.EntityFrameworkCore; -namespace API.Data.Repositories +namespace API.Data.Repositories; + +[Flags] +public enum LibraryIncludes { - - [Flags] - public enum LibraryIncludes - { - None = 1, - Series = 2, - AppUser = 4, - Folders = 8, - // Ratings = 16 - } - - public class LibraryRepository : ILibraryRepository - { - private readonly DataContext _context; - private readonly IMapper _mapper; - - public LibraryRepository(DataContext context, IMapper mapper) - { - _context = context; - _mapper = mapper; - } - - public void Add(Library library) - { - _context.Library.Add(library); - } - - public void Update(Library library) - { - _context.Entry(library).State = EntityState.Modified; - } - - public void Delete(Library library) - { - _context.Library.Remove(library); - } - - public async Task> GetLibraryDtosForUsernameAsync(string userName) - { - return await _context.Library - .Include(l => l.AppUsers) - .Where(library => library.AppUsers.Any(x => x.UserName == userName)) - .OrderBy(l => l.Name) - .ProjectTo(_mapper.ConfigurationProvider) - .AsNoTracking() - .AsSingleQuery() - .ToListAsync(); - } - - public async Task> GetLibrariesAsync() - { - return await _context.Library - .Include(l => l.AppUsers) - .ToListAsync(); - } - - public async Task DeleteLibrary(int libraryId) - { - var library = await GetLibraryForIdAsync(libraryId, LibraryIncludes.Folders | LibraryIncludes.Series); - _context.Library.Remove(library); - return await _context.SaveChangesAsync() > 0; - } - - public async Task> GetLibrariesForUserIdAsync(int userId) - { - return await _context.Library - .Include(l => l.AppUsers) - .Where(l => l.AppUsers.Select(ap => ap.Id).Contains(userId)) - .AsNoTracking() - .ToListAsync(); - } - - public async Task GetLibraryTypeAsync(int libraryId) - { - return await _context.Library - .Where(l => l.Id == libraryId) - .AsNoTracking() - .Select(l => l.Type) - .SingleAsync(); - } - - public async Task> GetLibraryDtosAsync() - { - return await _context.Library - .Include(f => f.Folders) - .OrderBy(l => l.Name) - .ProjectTo(_mapper.ConfigurationProvider) - .AsNoTracking() - .ToListAsync(); - } - - public async Task GetLibraryForIdAsync(int libraryId, LibraryIncludes includes) - { - - var query = _context.Library - .Where(x => x.Id == libraryId); - - query = AddIncludesToQuery(query, includes); - return await query.SingleAsync(); - } - - private static IQueryable AddIncludesToQuery(IQueryable query, LibraryIncludes includeFlags) - { - if (includeFlags.HasFlag(LibraryIncludes.Folders)) - { - query = query.Include(l => l.Folders); - } - - if (includeFlags.HasFlag(LibraryIncludes.Series)) - { - query = query.Include(l => l.Series); - } - - if (includeFlags.HasFlag(LibraryIncludes.AppUser)) - { - query = query.Include(l => l.AppUsers); - } - - return query; - } - - - /// - /// This returns a Library with all it's Series -> Volumes -> Chapters. This is expensive. Should only be called when needed. - /// - /// - /// - public async Task GetFullLibraryForIdAsync(int libraryId) - { - return await _context.Library - .Where(x => x.Id == libraryId) - .Include(f => f.Folders) - .Include(l => l.Series) - .ThenInclude(s => s.Metadata) - .Include(l => l.Series) - .ThenInclude(s => s.Volumes) - .ThenInclude(v => v.Chapters) - .ThenInclude(c => c.Files) - .AsSplitQuery() - .SingleAsync(); - } - - /// - /// This is a heavy call, pulls all entities for a Library, except this version only grabs for one series id - /// - /// - /// - /// - public async Task GetFullLibraryForIdAsync(int libraryId, int seriesId) - { - - return await _context.Library - .Where(x => x.Id == libraryId) - .Include(f => f.Folders) - .Include(l => l.Series.Where(s => s.Id == seriesId)) - .ThenInclude(s => s.Metadata) - .Include(l => l.Series.Where(s => s.Id == seriesId)) - .ThenInclude(s => s.Volumes) - .ThenInclude(v => v.Chapters) - .ThenInclude(c => c.Files) - .AsSplitQuery() - .SingleAsync(); - } - - public async Task LibraryExists(string libraryName) - { - return await _context.Library - .AsNoTracking() - .AnyAsync(x => x.Name == libraryName); - } - - public async Task> GetLibrariesForUserAsync(AppUser user) - { - return await _context.Library - .Where(library => library.AppUsers.Contains(user)) - .Include(l => l.Folders) - .AsNoTracking() - .ProjectTo(_mapper.ConfigurationProvider) - .ToListAsync(); - } - - - } + None = 1, + Series = 2, + AppUser = 4, + Folders = 8, + // Ratings = 16 +} + +public interface ILibraryRepository +{ + void Add(Library library); + void Update(Library library); + void Delete(Library library); + Task> GetLibraryDtosAsync(); + Task LibraryExists(string libraryName); + Task GetLibraryForIdAsync(int libraryId, LibraryIncludes includes); + Task GetFullLibraryForIdAsync(int libraryId); + Task GetFullLibraryForIdAsync(int libraryId, int seriesId); + Task> GetLibraryDtosForUsernameAsync(string userName); + Task> GetLibrariesAsync(); + Task DeleteLibrary(int libraryId); + Task> GetLibrariesForUserIdAsync(int userId); + Task GetLibraryTypeAsync(int libraryId); +} + +public class LibraryRepository : ILibraryRepository +{ + private readonly DataContext _context; + private readonly IMapper _mapper; + + public LibraryRepository(DataContext context, IMapper mapper) + { + _context = context; + _mapper = mapper; + } + + public void Add(Library library) + { + _context.Library.Add(library); + } + + public void Update(Library library) + { + _context.Entry(library).State = EntityState.Modified; + } + + public void Delete(Library library) + { + _context.Library.Remove(library); + } + + public async Task> GetLibraryDtosForUsernameAsync(string userName) + { + return await _context.Library + .Include(l => l.AppUsers) + .Where(library => library.AppUsers.Any(x => x.UserName == userName)) + .OrderBy(l => l.Name) + .ProjectTo(_mapper.ConfigurationProvider) + .AsNoTracking() + .AsSingleQuery() + .ToListAsync(); + } + + public async Task> GetLibrariesAsync() + { + return await _context.Library + .Include(l => l.AppUsers) + .ToListAsync(); + } + + public async Task DeleteLibrary(int libraryId) + { + var library = await GetLibraryForIdAsync(libraryId, LibraryIncludes.Folders | LibraryIncludes.Series); + _context.Library.Remove(library); + return await _context.SaveChangesAsync() > 0; + } + + public async Task> GetLibrariesForUserIdAsync(int userId) + { + return await _context.Library + .Include(l => l.AppUsers) + .Where(l => l.AppUsers.Select(ap => ap.Id).Contains(userId)) + .AsNoTracking() + .ToListAsync(); + } + + public async Task GetLibraryTypeAsync(int libraryId) + { + return await _context.Library + .Where(l => l.Id == libraryId) + .AsNoTracking() + .Select(l => l.Type) + .SingleAsync(); + } + + public async Task> GetLibraryDtosAsync() + { + return await _context.Library + .Include(f => f.Folders) + .OrderBy(l => l.Name) + .ProjectTo(_mapper.ConfigurationProvider) + .AsNoTracking() + .ToListAsync(); + } + + public async Task GetLibraryForIdAsync(int libraryId, LibraryIncludes includes) + { + + var query = _context.Library + .Where(x => x.Id == libraryId); + + query = AddIncludesToQuery(query, includes); + return await query.SingleAsync(); + } + + private static IQueryable AddIncludesToQuery(IQueryable query, LibraryIncludes includeFlags) + { + if (includeFlags.HasFlag(LibraryIncludes.Folders)) + { + query = query.Include(l => l.Folders); + } + + if (includeFlags.HasFlag(LibraryIncludes.Series)) + { + query = query.Include(l => l.Series); + } + + if (includeFlags.HasFlag(LibraryIncludes.AppUser)) + { + query = query.Include(l => l.AppUsers); + } + + return query; + } + + + /// + /// This returns a Library with all it's Series -> Volumes -> Chapters. This is expensive. Should only be called when needed. + /// + /// + /// + public async Task GetFullLibraryForIdAsync(int libraryId) + { + return await _context.Library + .Where(x => x.Id == libraryId) + .Include(f => f.Folders) + .Include(l => l.Series) + .ThenInclude(s => s.Metadata) + .Include(l => l.Series) + .ThenInclude(s => s.Volumes) + .ThenInclude(v => v.Chapters) + .ThenInclude(c => c.Files) + .AsSplitQuery() + .SingleAsync(); + } + + /// + /// This is a heavy call, pulls all entities for a Library, except this version only grabs for one series id + /// + /// + /// + /// + public async Task GetFullLibraryForIdAsync(int libraryId, int seriesId) + { + + return await _context.Library + .Where(x => x.Id == libraryId) + .Include(f => f.Folders) + .Include(l => l.Series.Where(s => s.Id == seriesId)) + .ThenInclude(s => s.Metadata) + .Include(l => l.Series.Where(s => s.Id == seriesId)) + .ThenInclude(s => s.Volumes) + .ThenInclude(v => v.Chapters) + .ThenInclude(c => c.Files) + .AsSplitQuery() + .SingleAsync(); + } + + public async Task LibraryExists(string libraryName) + { + return await _context.Library + .AsNoTracking() + .AnyAsync(x => x.Name == libraryName); + } + + public async Task> GetLibrariesForUserAsync(AppUser user) + { + return await _context.Library + .Where(library => library.AppUsers.Contains(user)) + .Include(l => l.Folders) + .AsNoTracking() + .ProjectTo(_mapper.ConfigurationProvider) + .ToListAsync(); + } + + } diff --git a/API/Data/Repositories/PersonRepository.cs b/API/Data/Repositories/PersonRepository.cs new file mode 100644 index 000000000..71ec69639 --- /dev/null +++ b/API/Data/Repositories/PersonRepository.cs @@ -0,0 +1,79 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using API.DTOs; +using API.Entities; +using AutoMapper; +using AutoMapper.QueryableExtensions; +using Microsoft.EntityFrameworkCore; + +namespace API.Data.Repositories; + +public interface IPersonRepository +{ + void Attach(Person person); + void Remove(Person person); + Task> GetAllPeople(); + Task RemoveAllPeopleNoLongerAssociated(bool removeExternal = false); + Task> GetAllPeopleDtosForLibrariesAsync(List libraryIds); +} + +public class PersonRepository : IPersonRepository +{ + private readonly DataContext _context; + private readonly IMapper _mapper; + + public PersonRepository(DataContext context, IMapper mapper) + { + _context = context; + _mapper = mapper; + } + + public void Attach(Person person) + { + _context.Person.Attach(person); + } + + public void Remove(Person person) + { + _context.Person.Remove(person); + } + + public async Task FindByNameAsync(string name) + { + var normalizedName = Parser.Parser.Normalize(name); + return await _context.Person + .Where(p => normalizedName.Equals(p.NormalizedName)) + .SingleOrDefaultAsync(); + } + + public async Task RemoveAllPeopleNoLongerAssociated(bool removeExternal = false) + { + var peopleWithNoConnections = await _context.Person + .Include(p => p.SeriesMetadatas) + .Include(p => p.ChapterMetadatas) + .Where(p => p.SeriesMetadatas.Count == 0 && p.ChapterMetadatas.Count == 0) + .ToListAsync(); + + _context.Person.RemoveRange(peopleWithNoConnections); + + await _context.SaveChangesAsync(); + } + + public async Task> GetAllPeopleDtosForLibrariesAsync(List libraryIds) + { + return await _context.Series + .Where(s => libraryIds.Contains(s.LibraryId)) + .SelectMany(s => s.Metadata.People) + .Distinct() + .ProjectTo(_mapper.ConfigurationProvider) + .ToListAsync(); + } + + + public async Task> GetAllPeople() + { + return await _context.Person + .ToListAsync(); + } +} diff --git a/API/Data/Repositories/ReadingListRepository.cs b/API/Data/Repositories/ReadingListRepository.cs index fc9199ccb..329ec47a8 100644 --- a/API/Data/Repositories/ReadingListRepository.cs +++ b/API/Data/Repositories/ReadingListRepository.cs @@ -4,175 +4,187 @@ using System.Threading.Tasks; using API.DTOs.ReadingLists; using API.Entities; using API.Helpers; -using API.Interfaces.Repositories; using AutoMapper; using AutoMapper.QueryableExtensions; using Microsoft.EntityFrameworkCore; -namespace API.Data.Repositories +namespace API.Data.Repositories; + +public interface IReadingListRepository { - public class ReadingListRepository : IReadingListRepository + Task> GetReadingListDtosForUserAsync(int userId, bool includePromoted, UserParams userParams); + Task GetReadingListByIdAsync(int readingListId); + Task> GetReadingListItemDtosByIdAsync(int readingListId, int userId); + Task GetReadingListDtoByIdAsync(int readingListId, int userId); + Task> AddReadingProgressModifiers(int userId, IList items); + Task GetReadingListDtoByTitleAsync(string title); + Task> GetReadingListItemsByIdAsync(int readingListId); + void Remove(ReadingListItem item); + void BulkRemove(IEnumerable items); + void Update(ReadingList list); +} + +public class ReadingListRepository : IReadingListRepository +{ + private readonly DataContext _context; + private readonly IMapper _mapper; + + public ReadingListRepository(DataContext context, IMapper mapper) { - private readonly DataContext _context; - private readonly IMapper _mapper; + _context = context; + _mapper = mapper; + } - public ReadingListRepository(DataContext context, IMapper mapper) - { - _context = context; - _mapper = mapper; - } + public void Update(ReadingList list) + { + _context.Entry(list).State = EntityState.Modified; + } - public void Update(ReadingList list) - { - _context.Entry(list).State = EntityState.Modified; - } + public void Remove(ReadingListItem item) + { + _context.ReadingListItem.Remove(item); + } - public void Remove(ReadingListItem item) - { - _context.ReadingListItem.Remove(item); - } - - public void BulkRemove(IEnumerable items) - { - _context.ReadingListItem.RemoveRange(items); - } + public void BulkRemove(IEnumerable items) + { + _context.ReadingListItem.RemoveRange(items); + } - public async Task> GetReadingListDtosForUserAsync(int userId, bool includePromoted, UserParams userParams) - { - var query = _context.ReadingList - .Where(l => l.AppUserId == userId || (includePromoted && l.Promoted )) - .OrderBy(l => l.LastModified) - .ProjectTo(_mapper.ConfigurationProvider) - .AsNoTracking(); + public async Task> GetReadingListDtosForUserAsync(int userId, bool includePromoted, UserParams userParams) + { + var query = _context.ReadingList + .Where(l => l.AppUserId == userId || (includePromoted && l.Promoted )) + .OrderBy(l => l.LastModified) + .ProjectTo(_mapper.ConfigurationProvider) + .AsNoTracking(); - return await PagedList.CreateAsync(query, userParams.PageNumber, userParams.PageSize); - } + return await PagedList.CreateAsync(query, userParams.PageNumber, userParams.PageSize); + } - public async Task GetReadingListByIdAsync(int readingListId) - { - return await _context.ReadingList - .Where(r => r.Id == readingListId) - .Include(r => r.Items.OrderBy(item => item.Order)) - .SingleOrDefaultAsync(); - } + public async Task GetReadingListByIdAsync(int readingListId) + { + return await _context.ReadingList + .Where(r => r.Id == readingListId) + .Include(r => r.Items.OrderBy(item => item.Order)) + .SingleOrDefaultAsync(); + } - public async Task> GetReadingListItemDtosByIdAsync(int readingListId, int userId) - { - var userLibraries = _context.Library - .Include(l => l.AppUsers) - .Where(library => library.AppUsers.Any(user => user.Id == userId)) - .AsNoTracking() - .Select(library => library.Id) - .ToList(); + public async Task> GetReadingListItemDtosByIdAsync(int readingListId, int userId) + { + var userLibraries = _context.Library + .Include(l => l.AppUsers) + .Where(library => library.AppUsers.Any(user => user.Id == userId)) + .AsNoTracking() + .Select(library => library.Id) + .ToList(); - var items = await _context.ReadingListItem - .Where(s => s.ReadingListId == readingListId) - .Join(_context.Chapter, s => s.ChapterId, chapter => chapter.Id, (data, chapter) => new - { - TotalPages = chapter.Pages, - ChapterNumber = chapter.Range, - readingListItem = data - }) - .Join(_context.Volume, s => s.readingListItem.VolumeId, volume => volume.Id, (data, volume) => new + var items = await _context.ReadingListItem + .Where(s => s.ReadingListId == readingListId) + .Join(_context.Chapter, s => s.ChapterId, chapter => chapter.Id, (data, chapter) => new + { + TotalPages = chapter.Pages, + ChapterNumber = chapter.Range, + readingListItem = data + }) + .Join(_context.Volume, s => s.readingListItem.VolumeId, volume => volume.Id, (data, volume) => new + { + data.readingListItem, + data.TotalPages, + data.ChapterNumber, + VolumeId = volume.Id, + VolumeNumber = volume.Name, + }) + .Join(_context.Series, s => s.readingListItem.SeriesId, series => series.Id, + (data, s) => new { + SeriesName = s.Name, + SeriesFormat = s.Format, + s.LibraryId, data.readingListItem, data.TotalPages, data.ChapterNumber, - VolumeId = volume.Id, - VolumeNumber = volume.Name, + data.VolumeNumber, + data.VolumeId }) - .Join(_context.Series, s => s.readingListItem.SeriesId, series => series.Id, - (data, s) => new - { - SeriesName = s.Name, - SeriesFormat = s.Format, - s.LibraryId, - data.readingListItem, - data.TotalPages, - data.ChapterNumber, - data.VolumeNumber, - data.VolumeId - }) - .Select(data => new ReadingListItemDto() - { - Id = data.readingListItem.Id, - ChapterId = data.readingListItem.ChapterId, - Order = data.readingListItem.Order, - SeriesId = data.readingListItem.SeriesId, - SeriesName = data.SeriesName, - SeriesFormat = data.SeriesFormat, - PagesTotal = data.TotalPages, - ChapterNumber = data.ChapterNumber, - VolumeNumber = data.VolumeNumber, - LibraryId = data.LibraryId, - VolumeId = data.VolumeId, - ReadingListId = data.readingListItem.ReadingListId - }) - .Where(o => userLibraries.Contains(o.LibraryId)) - .OrderBy(rli => rli.Order) - .AsNoTracking() - .ToListAsync(); - - // Attach progress information - var fetchedChapterIds = items.Select(i => i.ChapterId); - var progresses = await _context.AppUserProgresses - .Where(p => fetchedChapterIds.Contains(p.ChapterId)) - .AsNoTracking() - .ToListAsync(); - - foreach (var progress in progresses) + .Select(data => new ReadingListItemDto() { - var progressItem = items.SingleOrDefault(i => i.ChapterId == progress.ChapterId && i.ReadingListId == readingListId); - if (progressItem == null) continue; + Id = data.readingListItem.Id, + ChapterId = data.readingListItem.ChapterId, + Order = data.readingListItem.Order, + SeriesId = data.readingListItem.SeriesId, + SeriesName = data.SeriesName, + SeriesFormat = data.SeriesFormat, + PagesTotal = data.TotalPages, + ChapterNumber = data.ChapterNumber, + VolumeNumber = data.VolumeNumber, + LibraryId = data.LibraryId, + VolumeId = data.VolumeId, + ReadingListId = data.readingListItem.ReadingListId + }) + .Where(o => userLibraries.Contains(o.LibraryId)) + .OrderBy(rli => rli.Order) + .AsNoTracking() + .ToListAsync(); - progressItem.PagesRead = progress.PagesRead; - } + // Attach progress information + var fetchedChapterIds = items.Select(i => i.ChapterId); + var progresses = await _context.AppUserProgresses + .Where(p => fetchedChapterIds.Contains(p.ChapterId)) + .AsNoTracking() + .ToListAsync(); - return items; - } - - public async Task GetReadingListDtoByIdAsync(int readingListId, int userId) + foreach (var progress in progresses) { - return await _context.ReadingList - .Where(r => r.Id == readingListId && (r.AppUserId == userId || r.Promoted)) - .ProjectTo(_mapper.ConfigurationProvider) - .SingleOrDefaultAsync(); + var progressItem = items.SingleOrDefault(i => i.ChapterId == progress.ChapterId && i.ReadingListId == readingListId); + if (progressItem == null) continue; + + progressItem.PagesRead = progress.PagesRead; } - public async Task> AddReadingProgressModifiers(int userId, IList items) - { - var chapterIds = items.Select(i => i.ChapterId).Distinct().ToList(); - var userProgress = await _context.AppUserProgresses - .Where(p => p.AppUserId == userId && chapterIds.Contains(p.ChapterId)) - .AsNoTracking() - .ToListAsync(); - - foreach (var item in items) - { - var progress = userProgress.Where(p => p.ChapterId == item.ChapterId); - item.PagesRead = progress.Sum(p => p.PagesRead); - } - - return items; - } - - public async Task GetReadingListDtoByTitleAsync(string title) - { - return await _context.ReadingList - .Where(r => r.Title.Equals(title)) - .ProjectTo(_mapper.ConfigurationProvider) - .SingleOrDefaultAsync(); - } - - public async Task> GetReadingListItemsByIdAsync(int readingListId) - { - return await _context.ReadingListItem - .Where(r => r.ReadingListId == readingListId) - .OrderBy(r => r.Order) - .ToListAsync(); - } - - + return items; } + + public async Task GetReadingListDtoByIdAsync(int readingListId, int userId) + { + return await _context.ReadingList + .Where(r => r.Id == readingListId && (r.AppUserId == userId || r.Promoted)) + .ProjectTo(_mapper.ConfigurationProvider) + .SingleOrDefaultAsync(); + } + + public async Task> AddReadingProgressModifiers(int userId, IList items) + { + var chapterIds = items.Select(i => i.ChapterId).Distinct().ToList(); + var userProgress = await _context.AppUserProgresses + .Where(p => p.AppUserId == userId && chapterIds.Contains(p.ChapterId)) + .AsNoTracking() + .ToListAsync(); + + foreach (var item in items) + { + var progress = userProgress.Where(p => p.ChapterId == item.ChapterId); + item.PagesRead = progress.Sum(p => p.PagesRead); + } + + return items; + } + + public async Task GetReadingListDtoByTitleAsync(string title) + { + return await _context.ReadingList + .Where(r => r.Title.Equals(title)) + .ProjectTo(_mapper.ConfigurationProvider) + .SingleOrDefaultAsync(); + } + + public async Task> GetReadingListItemsByIdAsync(int readingListId) + { + return await _context.ReadingListItem + .Where(r => r.ReadingListId == readingListId) + .OrderBy(r => r.Order) + .ToListAsync(); + } + + } diff --git a/API/Data/Repositories/SeriesMetadataRepository.cs b/API/Data/Repositories/SeriesMetadataRepository.cs index 32ab0f4e2..0a3efee26 100644 --- a/API/Data/Repositories/SeriesMetadataRepository.cs +++ b/API/Data/Repositories/SeriesMetadataRepository.cs @@ -1,20 +1,23 @@ -using API.Entities; -using API.Interfaces.Repositories; +using API.Entities.Metadata; -namespace API.Data.Repositories +namespace API.Data.Repositories; + +public interface ISeriesMetadataRepository { - public class SeriesMetadataRepository : ISeriesMetadataRepository + void Update(SeriesMetadata seriesMetadata); +} + +public class SeriesMetadataRepository : ISeriesMetadataRepository +{ + private readonly DataContext _context; + + public SeriesMetadataRepository(DataContext context) { - private readonly DataContext _context; + _context = context; + } - public SeriesMetadataRepository(DataContext context) - { - _context = context; - } - - public void Update(SeriesMetadata seriesMetadata) - { - _context.SeriesMetadata.Update(seriesMetadata); - } + public void Update(SeriesMetadata seriesMetadata) + { + _context.SeriesMetadata.Update(seriesMetadata); } } diff --git a/API/Data/Repositories/SeriesRepository.cs b/API/Data/Repositories/SeriesRepository.cs index baa55330f..e8ffa9e16 100644 --- a/API/Data/Repositories/SeriesRepository.cs +++ b/API/Data/Repositories/SeriesRepository.cs @@ -1,527 +1,805 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Threading.Tasks; using API.Data.Scanner; using API.DTOs; using API.DTOs.CollectionTags; using API.DTOs.Filtering; +using API.DTOs.Metadata; using API.Entities; using API.Entities.Enums; +using API.Entities.Metadata; using API.Extensions; using API.Helpers; -using API.Interfaces.Repositories; using API.Services.Tasks; using AutoMapper; using AutoMapper.QueryableExtensions; +using Kavita.Common.Extensions; using Microsoft.EntityFrameworkCore; -namespace API.Data.Repositories +namespace API.Data.Repositories; + +public interface ISeriesRepository { - public class SeriesRepository : ISeriesRepository + void Attach(Series series); + void Update(Series series); + void Remove(Series series); + void Remove(IEnumerable series); + Task DoesSeriesNameExistInLibrary(string name, MangaFormat format); + /// + /// Adds user information like progress, ratings, etc + /// + /// + /// + /// + /// + Task> GetSeriesDtoForLibraryIdAsync(int libraryId, int userId, UserParams userParams, FilterDto filter); + /// + /// Does not add user information like progress, ratings, etc. + /// + /// + /// Series name to search for + /// + Task> SearchSeries(int[] libraryIds, string searchQuery); + Task> GetSeriesForLibraryIdAsync(int libraryId); + Task GetSeriesDtoByIdAsync(int seriesId, int userId); + Task DeleteSeriesAsync(int seriesId); + Task GetSeriesByIdAsync(int seriesId); + Task> GetSeriesByIdsAsync(IList seriesIds); + Task GetChapterIdsForSeriesAsync(IList seriesIds); + Task>> GetChapterIdWithSeriesIdForSeriesAsync(int[] seriesIds); + /// + /// Used to add Progress/Rating information to series list. + /// + /// + /// + /// + Task AddSeriesModifiers(int userId, List series); + Task GetSeriesCoverImageAsync(int seriesId); + Task> GetOnDeck(int userId, int libraryId, UserParams userParams, FilterDto filter); + Task> GetRecentlyAdded(int libraryId, int userId, UserParams userParams, FilterDto filter); // NOTE: Probably put this in LibraryRepo + Task GetSeriesMetadata(int seriesId); + Task> GetSeriesDtoForCollectionAsync(int collectionId, int userId, UserParams userParams); + Task> GetFilesForSeries(int seriesId); + Task> GetSeriesDtoForIdsAsync(IEnumerable seriesIds, int userId); + Task> GetAllCoverImagesAsync(); + Task> GetLockedCoverImagesAsync(); + Task> GetFullSeriesForLibraryIdAsync(int libraryId, UserParams userParams); + Task GetFullSeriesForSeriesIdAsync(int seriesId); + Task GetChunkInfo(int libraryId = 0); + Task> GetSeriesMetadataForIdsAsync(IEnumerable seriesIds); + Task> GetAllAgeRatingsDtosForLibrariesAsync(List libraryIds); + Task> GetAllLanguagesForLibrariesAsync(List libraryIds); + Task> GetAllPublicationStatusesDtosForLibrariesAsync(List libraryIds); +} + +public class SeriesRepository : ISeriesRepository +{ + private readonly DataContext _context; + private readonly IMapper _mapper; + public SeriesRepository(DataContext context, IMapper mapper) { - private readonly DataContext _context; - private readonly IMapper _mapper; - public SeriesRepository(DataContext context, IMapper mapper) + _context = context; + _mapper = mapper; + } + + public void Attach(Series series) + { + _context.Series.Attach(series); + } + + public void Update(Series series) + { + _context.Entry(series).State = EntityState.Modified; + } + + public void Remove(Series series) + { + _context.Series.Remove(series); + } + + public void Remove(IEnumerable series) + { + _context.Series.RemoveRange(series); + } + + /// + /// Returns if a series name and format exists already in a library + /// + /// Name of series + /// Format of series + /// + public async Task DoesSeriesNameExistInLibrary(string name, MangaFormat format) + { + var libraries = _context.Series + .AsNoTracking() + .Where(x => x.Name.Equals(name) && x.Format == format) + .Select(s => s.LibraryId); + + return await _context.Series + .AsNoTracking() + .Where(s => libraries.Contains(s.LibraryId) && s.Name.Equals(name) && s.Format == format) + .CountAsync() > 1; + } + + public async Task> GetSeriesForLibraryIdAsync(int libraryId) + { + return await _context.Series + .Where(s => s.LibraryId == libraryId) + .OrderBy(s => s.SortName) + .ToListAsync(); + } + + /// + /// Used for to + /// + /// + /// + public async Task> GetFullSeriesForLibraryIdAsync(int libraryId, UserParams userParams) + { + var query = _context.Series + .Where(s => s.LibraryId == libraryId) + + .Include(s => s.Metadata) + .ThenInclude(m => m.People) + + .Include(s => s.Metadata) + .ThenInclude(m => m.Genres) + + .Include(s => s.Metadata) + .ThenInclude(m => m.Tags) + + .Include(s => s.Volumes) + .ThenInclude(v => v.Chapters) + .ThenInclude(cm => cm.People) + + .Include(s => s.Volumes) + .ThenInclude(v => v.Chapters) + .ThenInclude(c => c.Genres) + + .Include(s => s.Volumes) + .ThenInclude(v => v.Chapters) + .ThenInclude(c => c.Tags) + + .Include(s => s.Volumes) + .ThenInclude(v => v.Chapters) + .ThenInclude(c => c.Files) + .AsSplitQuery() + .OrderBy(s => s.SortName); + + return await PagedList.CreateAsync(query, userParams.PageNumber, userParams.PageSize); + } + + /// + /// This is a heavy call. Returns all entities down to Files and Library and Series Metadata. + /// + /// + /// + public async Task GetFullSeriesForSeriesIdAsync(int seriesId) + { + return await _context.Series + .Where(s => s.Id == seriesId) + .Include(s => s.Metadata) + .ThenInclude(m => m.People) + .Include(s => s.Metadata) + .ThenInclude(m => m.Genres) + .Include(s => s.Library) + .Include(s => s.Volumes) + .ThenInclude(v => v.Chapters) + .ThenInclude(cm => cm.People) + + .Include(s => s.Volumes) + .ThenInclude(v => v.Chapters) + .ThenInclude(c => c.Tags) + + .Include(s => s.Volumes) + .ThenInclude(v => v.Chapters) + .ThenInclude(c => c.Genres) + + + .Include(s => s.Metadata) + .ThenInclude(m => m.Tags) + + .Include(s => s.Volumes) + .ThenInclude(v => v.Chapters) + .ThenInclude(c => c.Files) + .AsSplitQuery() + .SingleOrDefaultAsync(); + } + + public async Task> GetSeriesDtoForLibraryIdAsync(int libraryId, int userId, UserParams userParams, FilterDto filter) + { + var query = await CreateFilteredSearchQueryable(userId, libraryId, filter); + + if (filter.SortOptions == null) { - _context = context; - _mapper = mapper; + query = query.OrderBy(s => s.SortName); } - public void Attach(Series series) + var retSeries = query + .ProjectTo(_mapper.ConfigurationProvider) + .AsSplitQuery() + .AsNoTracking(); + + return await PagedList.CreateAsync(retSeries, userParams.PageNumber, userParams.PageSize); + } + + private async Task> GetUserLibraries(int libraryId, int userId) + { + if (libraryId == 0) { - _context.Series.Attach(series); - } - - public void Update(Series series) - { - _context.Entry(series).State = EntityState.Modified; - } - - public void Remove(Series series) - { - _context.Series.Remove(series); - } - - public void Remove(IEnumerable series) - { - _context.Series.RemoveRange(series); - } - - /// - /// Returns if a series name and format exists already in a library - /// - /// Name of series - /// Format of series - /// - public async Task DoesSeriesNameExistInLibrary(string name, MangaFormat format) - { - var libraries = _context.Series - .AsNoTracking() - .Where(x => x.Name.Equals(name) && x.Format == format) - .Select(s => s.LibraryId); - - return await _context.Series - .AsNoTracking() - .Where(s => libraries.Contains(s.LibraryId) && s.Name.Equals(name) && s.Format == format) - .CountAsync() > 1; - } - - public async Task> GetSeriesForLibraryIdAsync(int libraryId) - { - return await _context.Series - .Where(s => s.LibraryId == libraryId) - .OrderBy(s => s.SortName) - .ToListAsync(); - } - - /// - /// Used for to - /// - /// - /// - public async Task> GetFullSeriesForLibraryIdAsync(int libraryId, UserParams userParams) - { - var query = _context.Series - .Where(s => s.LibraryId == libraryId) - .Include(s => s.Metadata) - .Include(s => s.Volumes) - .ThenInclude(v => v.Chapters) - .ThenInclude(c => c.Files) - .AsSplitQuery() - .OrderBy(s => s.SortName); - - return await PagedList.CreateAsync(query, userParams.PageNumber, userParams.PageSize); - } - - /// - /// This is a heavy call. Returns all entities down to Files and Library and Series Metadata. - /// - /// - /// - public async Task GetFullSeriesForSeriesIdAsync(int seriesId) - { - return await _context.Series - .Where(s => s.Id == seriesId) - .Include(s => s.Metadata) - .Include(s => s.Library) - .Include(s => s.Volumes) - .ThenInclude(v => v.Chapters) - .ThenInclude(c => c.Files) - .AsSplitQuery() - .SingleOrDefaultAsync(); - } - - public async Task> GetSeriesDtoForLibraryIdAsync(int libraryId, int userId, UserParams userParams, FilterDto filter) - { - var formats = filter.GetSqlFilter(); - var query = _context.Series - .Where(s => s.LibraryId == libraryId && formats.Contains(s.Format)) - .OrderBy(s => s.SortName) - .ProjectTo(_mapper.ConfigurationProvider) - .AsNoTracking(); - - return await PagedList.CreateAsync(query, userParams.PageNumber, userParams.PageSize); - } - - public async Task> SearchSeries(int[] libraryIds, string searchQuery) - { - return await _context.Series - .Where(s => libraryIds.Contains(s.LibraryId)) - .Where(s => EF.Functions.Like(s.Name, $"%{searchQuery}%") - || EF.Functions.Like(s.OriginalName, $"%{searchQuery}%") - || EF.Functions.Like(s.LocalizedName, $"%{searchQuery}%")) - .Include(s => s.Library) - .OrderBy(s => s.SortName) - .AsNoTracking() - .ProjectTo(_mapper.ConfigurationProvider) - .ToListAsync(); - } - - - - - - - - - public async Task GetSeriesDtoByIdAsync(int seriesId, int userId) - { - var series = await _context.Series.Where(x => x.Id == seriesId) - .ProjectTo(_mapper.ConfigurationProvider) - .SingleAsync(); - - var seriesList = new List() {series}; - await AddSeriesModifiers(userId, seriesList); - - return seriesList[0]; - } - - - - - public async Task DeleteSeriesAsync(int seriesId) - { - var series = await _context.Series.Where(s => s.Id == seriesId).SingleOrDefaultAsync(); - _context.Series.Remove(series); - - return await _context.SaveChangesAsync() > 0; - } - - - /// - /// Returns Volumes, Metadata, and Collection Tags - /// - /// - /// - public async Task GetSeriesByIdAsync(int seriesId) - { - return await _context.Series - .Include(s => s.Volumes) - .Include(s => s.Metadata) - .ThenInclude(m => m.CollectionTags) - .Where(s => s.Id == seriesId) - .SingleOrDefaultAsync(); - } - - /// - /// Returns Volumes, Metadata, and Collection Tags - /// - /// - /// - public async Task> GetSeriesByIdsAsync(IList seriesIds) - { - return await _context.Series - .Include(s => s.Volumes) - .Include(s => s.Metadata) - .ThenInclude(m => m.CollectionTags) - .Where(s => seriesIds.Contains(s.Id)) - .ToListAsync(); - } - - public async Task GetChapterIdsForSeriesAsync(int[] seriesIds) - { - var volumes = await _context.Volume - .Where(v => seriesIds.Contains(v.SeriesId)) - .Include(v => v.Chapters) - .ToListAsync(); - - IList chapterIds = new List(); - foreach (var v in volumes) - { - foreach (var c in v.Chapters) - { - chapterIds.Add(c.Id); - } - } - - return chapterIds.ToArray(); - } - - /// - /// This returns a dictonary mapping seriesId -> list of chapters back for each series id passed - /// - /// - /// - public async Task>> GetChapterIdWithSeriesIdForSeriesAsync(int[] seriesIds) - { - var volumes = await _context.Volume - .Where(v => seriesIds.Contains(v.SeriesId)) - .Include(v => v.Chapters) - .ToListAsync(); - - var seriesChapters = new Dictionary>(); - foreach (var v in volumes) - { - foreach (var c in v.Chapters) - { - if (!seriesChapters.ContainsKey(v.SeriesId)) - { - var list = new List(); - seriesChapters.Add(v.SeriesId, list); - } - seriesChapters[v.SeriesId].Add(c.Id); - } - } - - return seriesChapters; - } - - public async Task AddSeriesModifiers(int userId, List series) - { - var userProgress = await _context.AppUserProgresses - .Where(p => p.AppUserId == userId && series.Select(s => s.Id).Contains(p.SeriesId)) - .ToListAsync(); - - var userRatings = await _context.AppUserRating - .Where(r => r.AppUserId == userId && series.Select(s => s.Id).Contains(r.SeriesId)) - .ToListAsync(); - - foreach (var s in series) - { - s.PagesRead = userProgress.Where(p => p.SeriesId == s.Id).Sum(p => p.PagesRead); - var rating = userRatings.SingleOrDefault(r => r.SeriesId == s.Id); - if (rating == null) continue; - s.UserRating = rating.Rating; - s.UserReview = rating.Review; - } - } - - public async Task GetSeriesCoverImageAsync(int seriesId) - { - return await _context.Series - .Where(s => s.Id == seriesId) - .Select(s => s.CoverImage) - .AsNoTracking() - .SingleOrDefaultAsync(); - } - - - - /// - /// Returns a list of Series that were added, ordered by Created desc - /// - /// - /// Library to restrict to, if 0, will apply to all libraries - /// Contains pagination information - /// Optional filter on query - /// - public async Task> GetRecentlyAdded(int libraryId, int userId, UserParams userParams, FilterDto filter) - { - var formats = filter.GetSqlFilter(); - - if (libraryId == 0) - { - var userLibraries = _context.Library - .Include(l => l.AppUsers) - .Where(library => library.AppUsers.Any(user => user.Id == userId)) - .AsNoTracking() - .Select(library => library.Id) - .ToList(); - - var allQuery = _context.Series - .Where(s => userLibraries.Contains(s.LibraryId) && formats.Contains(s.Format)) - .OrderByDescending(s => s.Created) - .ProjectTo(_mapper.ConfigurationProvider) - .AsNoTracking(); - - return await PagedList.CreateAsync(allQuery, userParams.PageNumber, userParams.PageSize); - } - - var query = _context.Series - .Where(s => s.LibraryId == libraryId && formats.Contains(s.Format)) - .OrderByDescending(s => s.Created) - .ProjectTo(_mapper.ConfigurationProvider) - .AsSplitQuery() - .AsNoTracking(); - - return await PagedList.CreateAsync(query, userParams.PageNumber, userParams.PageSize); - } - - /// - /// Returns Series that the user has some partial progress on. Sorts based on activity. Sort first by User progress, but if a series - /// has been updated recently, bump it to the front. - /// - /// - /// Library to restrict to, if 0, will apply to all libraries - /// Pagination information - /// Optional (default null) filter on query - /// - public async Task> GetOnDeck(int userId, int libraryId, UserParams userParams, FilterDto filter) - { - var formats = filter.GetSqlFilter(); - IList userLibraries; - if (libraryId == 0) - { - userLibraries = _context.Library - .Include(l => l.AppUsers) - .Where(library => library.AppUsers.Any(user => user.Id == userId)) - .AsNoTracking() - .Select(library => library.Id) - .ToList(); - } - else - { - userLibraries = new List() {libraryId}; - } - - var series = _context.Series - .Where(s => formats.Contains(s.Format) && userLibraries.Contains(s.LibraryId)) - .Join(_context.AppUserProgresses, s => s.Id, progress => progress.SeriesId, (s, progress) => new - { - Series = s, - PagesRead = _context.AppUserProgresses.Where(s1 => s1.SeriesId == s.Id && s1.AppUserId == userId).Sum(s1 => s1.PagesRead), - progress.AppUserId, - LastModified = _context.AppUserProgresses.Where(p => p.Id == progress.Id && p.AppUserId == userId).Max(p => p.LastModified) - }) - .AsNoTracking(); - - var retSeries = series.Where(s => s.AppUserId == userId - && s.PagesRead > 0 - && s.PagesRead < s.Series.Pages) - .OrderByDescending(s => s.LastModified) - .ThenByDescending(s => s.Series.LastModified) - .Select(s => s.Series) - .ProjectTo(_mapper.ConfigurationProvider) - .AsSplitQuery() - .AsNoTracking(); - - // Pagination does not work for this query as when we pull the data back, we get multiple rows of the same series. See controller for pagination code - return await retSeries.ToListAsync(); - } - - public async Task GetSeriesMetadata(int seriesId) - { - var metadataDto = await _context.SeriesMetadata - .Where(metadata => metadata.SeriesId == seriesId) - .AsNoTracking() - .ProjectTo(_mapper.ConfigurationProvider) - .SingleOrDefaultAsync(); - - if (metadataDto != null) - { - metadataDto.Tags = await _context.CollectionTag - .Include(t => t.SeriesMetadatas) - .Where(t => t.SeriesMetadatas.Select(s => s.SeriesId).Contains(seriesId)) - .ProjectTo(_mapper.ConfigurationProvider) - .AsNoTracking() - .ToListAsync(); - } - - return metadataDto; - } - - public async Task> GetSeriesDtoForCollectionAsync(int collectionId, int userId, UserParams userParams) - { - var userLibraries = _context.Library + return await _context.Library .Include(l => l.AppUsers) .Where(library => library.AppUsers.Any(user => user.Id == userId)) .AsNoTracking() .Select(library => library.Id) - .ToList(); - - var query = _context.CollectionTag - .Where(s => s.Id == collectionId) - .Include(c => c.SeriesMetadatas) - .ThenInclude(m => m.Series) - .SelectMany(c => c.SeriesMetadatas.Select(sm => sm.Series).Where(s => userLibraries.Contains(s.LibraryId))) - .OrderBy(s => s.LibraryId) - .ThenBy(s => s.SortName) - .ProjectTo(_mapper.ConfigurationProvider) - .AsNoTracking(); - - return await PagedList.CreateAsync(query, userParams.PageNumber, userParams.PageSize); - } - - public async Task> GetFilesForSeries(int seriesId) - { - return await _context.Volume - .Where(v => v.SeriesId == seriesId) - .Include(v => v.Chapters) - .ThenInclude(c => c.Files) - .SelectMany(v => v.Chapters.SelectMany(c => c.Files)) - .AsNoTracking() .ToListAsync(); } - public async Task> GetSeriesDtoForIdsAsync(IEnumerable seriesIds, int userId) + return new List() { - var allowedLibraries = _context.Library - .Include(l => l.AppUsers) - .Where(library => library.AppUsers.Any(x => x.Id == userId)) - .Select(l => l.Id); + libraryId + }; + } - return await _context.Series - .Where(s => seriesIds.Contains(s.Id) && allowedLibraries.Contains(s.LibraryId)) - .OrderBy(s => s.SortName) - .ProjectTo(_mapper.ConfigurationProvider) + public async Task> SearchSeries(int[] libraryIds, string searchQuery) + { + return await _context.Series + .Where(s => libraryIds.Contains(s.LibraryId)) + .Where(s => EF.Functions.Like(s.Name, $"%{searchQuery}%") + || EF.Functions.Like(s.OriginalName, $"%{searchQuery}%") + || EF.Functions.Like(s.LocalizedName, $"%{searchQuery}%")) + .Include(s => s.Library) + .OrderBy(s => s.SortName) + .AsNoTracking() + .ProjectTo(_mapper.ConfigurationProvider) + .ToListAsync(); + } + + + + + + + + + public async Task GetSeriesDtoByIdAsync(int seriesId, int userId) + { + var series = await _context.Series.Where(x => x.Id == seriesId) + .ProjectTo(_mapper.ConfigurationProvider) + .SingleAsync(); + + var seriesList = new List() {series}; + await AddSeriesModifiers(userId, seriesList); + + return seriesList[0]; + } + + + + + public async Task DeleteSeriesAsync(int seriesId) + { + var series = await _context.Series.Where(s => s.Id == seriesId).SingleOrDefaultAsync(); + if (series != null) _context.Series.Remove(series); + + return await _context.SaveChangesAsync() > 0; + } + + + /// + /// Returns Volumes, Metadata, and Collection Tags + /// + /// + /// + public async Task GetSeriesByIdAsync(int seriesId) + { + return await _context.Series + .Include(s => s.Volumes) + .Include(s => s.Metadata) + .ThenInclude(m => m.CollectionTags) + .Include(s => s.Metadata) + .ThenInclude(m => m.Genres) + .Include(s => s.Metadata) + .ThenInclude(m => m.People) + .Where(s => s.Id == seriesId) + .AsSplitQuery() + .SingleOrDefaultAsync(); + } + + /// + /// Returns Volumes, Metadata, and Collection Tags + /// + /// + /// + public async Task> GetSeriesByIdsAsync(IList seriesIds) + { + return await _context.Series + .Include(s => s.Volumes) + .Include(s => s.Metadata) + .ThenInclude(m => m.CollectionTags) + .Where(s => seriesIds.Contains(s.Id)) + .AsSplitQuery() + .ToListAsync(); + } + + public async Task GetChapterIdsForSeriesAsync(IList seriesIds) + { + var volumes = await _context.Volume + .Where(v => seriesIds.Contains(v.SeriesId)) + .Include(v => v.Chapters) + .ToListAsync(); + + IList chapterIds = new List(); + foreach (var v in volumes) + { + foreach (var c in v.Chapters) + { + chapterIds.Add(c.Id); + } + } + + return chapterIds.ToArray(); + } + + /// + /// This returns a dictonary mapping seriesId -> list of chapters back for each series id passed + /// + /// + /// + public async Task>> GetChapterIdWithSeriesIdForSeriesAsync(int[] seriesIds) + { + var volumes = await _context.Volume + .Where(v => seriesIds.Contains(v.SeriesId)) + .Include(v => v.Chapters) + .ToListAsync(); + + var seriesChapters = new Dictionary>(); + foreach (var v in volumes) + { + foreach (var c in v.Chapters) + { + if (!seriesChapters.ContainsKey(v.SeriesId)) + { + var list = new List(); + seriesChapters.Add(v.SeriesId, list); + } + seriesChapters[v.SeriesId].Add(c.Id); + } + } + + return seriesChapters; + } + + public async Task AddSeriesModifiers(int userId, List series) + { + var userProgress = await _context.AppUserProgresses + .Where(p => p.AppUserId == userId && series.Select(s => s.Id).Contains(p.SeriesId)) + .ToListAsync(); + + var userRatings = await _context.AppUserRating + .Where(r => r.AppUserId == userId && series.Select(s => s.Id).Contains(r.SeriesId)) + .ToListAsync(); + + foreach (var s in series) + { + s.PagesRead = userProgress.Where(p => p.SeriesId == s.Id).Sum(p => p.PagesRead); + var rating = userRatings.SingleOrDefault(r => r.SeriesId == s.Id); + if (rating == null) continue; + s.UserRating = rating.Rating; + s.UserReview = rating.Review; + } + } + + public async Task GetSeriesCoverImageAsync(int seriesId) + { + return await _context.Series + .Where(s => s.Id == seriesId) + .Select(s => s.CoverImage) + .AsNoTracking() + .SingleOrDefaultAsync(); + } + + + + /// + /// Returns a list of Series that were added, ordered by Created desc + /// + /// + /// Library to restrict to, if 0, will apply to all libraries + /// Contains pagination information + /// Optional filter on query + /// + public async Task> GetRecentlyAdded(int libraryId, int userId, UserParams userParams, FilterDto filter) + { + var query = await CreateFilteredSearchQueryable(userId, libraryId, filter); + + var retSeries = query + .OrderByDescending(s => s.Created) + .ProjectTo(_mapper.ConfigurationProvider) + .AsSplitQuery() + .AsNoTracking(); + + return await PagedList.CreateAsync(retSeries, userParams.PageNumber, userParams.PageSize); + } + + private IList ExtractFilters(int libraryId, int userId, FilterDto filter, ref List userLibraries, + out List allPeopleIds, out bool hasPeopleFilter, out bool hasGenresFilter, out bool hasCollectionTagFilter, + out bool hasRatingFilter, out bool hasProgressFilter, out IList seriesIds, out bool hasAgeRating, out bool hasTagsFilter, + out bool hasLanguageFilter, out bool hasPublicationFilter) + { + var formats = filter.GetSqlFilter(); + + if (filter.Libraries.Count > 0) + { + userLibraries = userLibraries.Where(l => filter.Libraries.Contains(l)).ToList(); + } + else if (libraryId > 0) + { + userLibraries = userLibraries.Where(l => l == libraryId).ToList(); + } + + allPeopleIds = new List(); + allPeopleIds.AddRange(filter.Writers); + allPeopleIds.AddRange(filter.Character); + allPeopleIds.AddRange(filter.Colorist); + allPeopleIds.AddRange(filter.Editor); + allPeopleIds.AddRange(filter.Inker); + allPeopleIds.AddRange(filter.Letterer); + allPeopleIds.AddRange(filter.Penciller); + allPeopleIds.AddRange(filter.Publisher); + allPeopleIds.AddRange(filter.CoverArtist); + allPeopleIds.AddRange(filter.Translators); + //allPeopleIds.AddRange(filter.Artist); + + hasPeopleFilter = allPeopleIds.Count > 0; + hasGenresFilter = filter.Genres.Count > 0; + hasCollectionTagFilter = filter.CollectionTags.Count > 0; + hasRatingFilter = filter.Rating > 0; + hasProgressFilter = !filter.ReadStatus.Read || !filter.ReadStatus.InProgress || !filter.ReadStatus.NotRead; + hasAgeRating = filter.AgeRating.Count > 0; + hasTagsFilter = filter.Tags.Count > 0; + hasLanguageFilter = filter.Languages.Count > 0; + hasPublicationFilter = filter.PublicationStatus.Count > 0; + + + bool ProgressComparison(int pagesRead, int totalPages) + { + var result = false; + if (filter.ReadStatus.NotRead) + { + result = (pagesRead == 0); + } + + if (filter.ReadStatus.Read) + { + result = result || (pagesRead == totalPages); + } + + if (filter.ReadStatus.InProgress) + { + result = result || (pagesRead > 0 && pagesRead < totalPages); + } + + return result; + } + + seriesIds = new List(); + if (hasProgressFilter) + { + seriesIds = _context.Series + .Include(s => s.Progress) + .Select(s => new + { + Series = s, + PagesRead = s.Progress.Where(p => p.AppUserId == userId).Sum(p => p.PagesRead), + }) + .AsEnumerable() + .Where(s => ProgressComparison(s.PagesRead, s.Series.Pages)) + .Select(s => s.Series.Id) + .ToList(); + } + + return formats; + } + + /// + /// Returns Series that the user has some partial progress on. Sorts based on activity. Sort first by User progress, but if a series + /// has been updated recently, bump it to the front. + /// + /// + /// Library to restrict to, if 0, will apply to all libraries + /// Pagination information + /// Optional (default null) filter on query + /// + public async Task> GetOnDeck(int userId, int libraryId, UserParams userParams, FilterDto filter) + { + //var allSeriesWithProgress = await _context.AppUserProgresses.Select(p => p.SeriesId).ToListAsync(); + //var allChapters = await GetChapterIdsForSeriesAsync(allSeriesWithProgress); + + var query = (await CreateFilteredSearchQueryable(userId, libraryId, filter)) + .Join(_context.AppUserProgresses, s => s.Id, progress => progress.SeriesId, (s, progress) => + new + { + Series = s, + PagesRead = _context.AppUserProgresses.Where(s1 => s1.SeriesId == s.Id && s1.AppUserId == userId) + .Sum(s1 => s1.PagesRead), + progress.AppUserId, + LastReadingProgress = _context.AppUserProgresses.Where(p => p.Id == progress.Id && p.AppUserId == userId) + .Max(p => p.LastModified), + // This is only taking into account chapters that have progress on them, not all chapters in said series + LastChapterCreated = _context.Chapter.Where(c => progress.ChapterId == c.Id).Max(c => c.Created) + //LastChapterCreated = _context.Chapter.Where(c => allChapters.Contains(c.Id)).Max(c => c.Created) + }); + // I think I need another Join statement. The problem is the chapters are still limited to progress + + + + var retSeries = query.Where(s => s.AppUserId == userId + && s.PagesRead > 0 + && s.PagesRead < s.Series.Pages) + .OrderByDescending(s => s.LastReadingProgress) + .ThenByDescending(s => s.LastChapterCreated) + .Select(s => s.Series) + .ProjectTo(_mapper.ConfigurationProvider) + .AsSplitQuery() + .AsNoTracking(); + + // Pagination does not work for this query as when we pull the data back, we get multiple rows of the same series. See controller for pagination code + return await retSeries.ToListAsync(); + } + + private async Task> CreateFilteredSearchQueryable(int userId, int libraryId, FilterDto filter) + { + var userLibraries = await GetUserLibraries(libraryId, userId); + var formats = ExtractFilters(libraryId, userId, filter, ref userLibraries, + out var allPeopleIds, out var hasPeopleFilter, out var hasGenresFilter, + out var hasCollectionTagFilter, out var hasRatingFilter, out var hasProgressFilter, + out var seriesIds, out var hasAgeRating, out var hasTagsFilter, out var hasLanguageFilter, out var hasPublicationFilter); + + var query = _context.Series + .Where(s => userLibraries.Contains(s.LibraryId) + && formats.Contains(s.Format) + && (!hasGenresFilter || s.Metadata.Genres.Any(g => filter.Genres.Contains(g.Id))) + && (!hasPeopleFilter || s.Metadata.People.Any(p => allPeopleIds.Contains(p.Id))) + && (!hasCollectionTagFilter || + s.Metadata.CollectionTags.Any(t => filter.CollectionTags.Contains(t.Id))) + && (!hasRatingFilter || s.Ratings.Any(r => r.Rating >= filter.Rating)) + && (!hasProgressFilter || seriesIds.Contains(s.Id)) + && (!hasAgeRating || filter.AgeRating.Contains(s.Metadata.AgeRating)) + && (!hasTagsFilter || s.Metadata.Tags.Any(t => filter.Tags.Contains(t.Id))) + && (!hasLanguageFilter || filter.Languages.Contains(s.Metadata.Language)) + && (!hasPublicationFilter || filter.PublicationStatus.Contains(s.Metadata.PublicationStatus)) + ) + .AsNoTracking(); + + if (filter.SortOptions != null) + { + if (filter.SortOptions.IsAscending) + { + if (filter.SortOptions.SortField == SortField.SortName) + { + query = query.OrderBy(s => s.SortName); + } else if (filter.SortOptions.SortField == SortField.CreatedDate) + { + query = query.OrderBy(s => s.Created); + } else if (filter.SortOptions.SortField == SortField.LastModifiedDate) + { + query = query.OrderBy(s => s.LastModified); + } + } + else + { + if (filter.SortOptions.SortField == SortField.SortName) + { + query = query.OrderByDescending(s => s.SortName); + } else if (filter.SortOptions.SortField == SortField.CreatedDate) + { + query = query.OrderByDescending(s => s.Created); + } else if (filter.SortOptions.SortField == SortField.LastModifiedDate) + { + query = query.OrderByDescending(s => s.LastModified); + } + } + } + + return query; + } + + public async Task GetSeriesMetadata(int seriesId) + { + var metadataDto = await _context.SeriesMetadata + .Where(metadata => metadata.SeriesId == seriesId) + .Include(m => m.Genres) + .Include(m => m.Tags) + .Include(m => m.People) + .AsNoTracking() + .ProjectTo(_mapper.ConfigurationProvider) + .AsSplitQuery() + .SingleOrDefaultAsync(); + + if (metadataDto != null) + { + metadataDto.CollectionTags = await _context.CollectionTag + .Include(t => t.SeriesMetadatas) + .Where(t => t.SeriesMetadatas.Select(s => s.SeriesId).Contains(seriesId)) + .ProjectTo(_mapper.ConfigurationProvider) .AsNoTracking() .AsSplitQuery() .ToListAsync(); } - public async Task> GetAllCoverImagesAsync() + return metadataDto; + } + + public async Task> GetSeriesDtoForCollectionAsync(int collectionId, int userId, UserParams userParams) + { + var userLibraries = _context.Library + .Include(l => l.AppUsers) + .Where(library => library.AppUsers.Any(user => user.Id == userId)) + .AsNoTracking() + .Select(library => library.Id) + .ToList(); + + var query = _context.CollectionTag + .Where(s => s.Id == collectionId) + .Include(c => c.SeriesMetadatas) + .ThenInclude(m => m.Series) + .SelectMany(c => c.SeriesMetadatas.Select(sm => sm.Series).Where(s => userLibraries.Contains(s.LibraryId))) + .OrderBy(s => s.LibraryId) + .ThenBy(s => s.SortName) + .ProjectTo(_mapper.ConfigurationProvider) + .AsSplitQuery() + .AsNoTracking(); + + return await PagedList.CreateAsync(query, userParams.PageNumber, userParams.PageSize); + } + + public async Task> GetFilesForSeries(int seriesId) + { + return await _context.Volume + .Where(v => v.SeriesId == seriesId) + .Include(v => v.Chapters) + .ThenInclude(c => c.Files) + .SelectMany(v => v.Chapters.SelectMany(c => c.Files)) + .AsNoTracking() + .ToListAsync(); + } + + public async Task> GetSeriesDtoForIdsAsync(IEnumerable seriesIds, int userId) + { + var allowedLibraries = _context.Library + .Include(l => l.AppUsers) + .Where(library => library.AppUsers.Any(x => x.Id == userId)) + .Select(l => l.Id); + + return await _context.Series + .Where(s => seriesIds.Contains(s.Id) && allowedLibraries.Contains(s.LibraryId)) + .OrderBy(s => s.SortName) + .ProjectTo(_mapper.ConfigurationProvider) + .AsNoTracking() + .AsSplitQuery() + .ToListAsync(); + } + + public async Task> GetAllCoverImagesAsync() + { + return await _context.Series + .Select(s => s.CoverImage) + .Where(t => !string.IsNullOrEmpty(t)) + .AsNoTracking() + .ToListAsync(); + } + + public async Task> GetLockedCoverImagesAsync() + { + return await _context.Series + .Where(s => s.CoverImageLocked && !string.IsNullOrEmpty(s.CoverImage)) + .Select(s => s.CoverImage) + .AsNoTracking() + .ToListAsync(); + } + + /// + /// Returns the number of series for a given library (or all libraries if libraryId is 0) + /// + /// Defaults to 0, library to restrict count to + /// + private async Task GetSeriesCount(int libraryId = 0) + { + if (libraryId > 0) { return await _context.Series - .Select(s => s.CoverImage) - .Where(t => !string.IsNullOrEmpty(t)) - .AsNoTracking() - .ToListAsync(); + .Where(s => s.LibraryId == libraryId) + .CountAsync(); } + return await _context.Series.CountAsync(); + } - public async Task> GetLockedCoverImagesAsync() - { - return await _context.Series - .Where(s => s.CoverImageLocked && !string.IsNullOrEmpty(s.CoverImage)) - .Select(s => s.CoverImage) - .AsNoTracking() - .ToListAsync(); - } + /// + /// Returns the number of series that should be processed in parallel to optimize speed and memory. Minimum of 50 + /// + /// Defaults to 0 meaning no library + /// + private async Task> GetChunkSize(int libraryId = 0) + { + var totalSeries = await GetSeriesCount(libraryId); + return new Tuple(totalSeries, 50); + } - /// - /// Returns the number of series for a given library (or all libraries if libraryId is 0) - /// - /// Defaults to 0, library to restrict count to - /// - private async Task GetSeriesCount(int libraryId = 0) + public async Task GetChunkInfo(int libraryId = 0) + { + var (totalSeries, chunkSize) = await GetChunkSize(libraryId); + + if (totalSeries == 0) return new Chunk() { - if (libraryId > 0) + TotalChunks = 0, + TotalSize = 0, + ChunkSize = 0 + }; + + var totalChunks = Math.Max((int) Math.Ceiling((totalSeries * 1.0) / chunkSize), 1); + + return new Chunk() + { + TotalSize = totalSeries, + ChunkSize = chunkSize, + TotalChunks = totalChunks + }; + } + + public async Task> GetSeriesMetadataForIdsAsync(IEnumerable seriesIds) + { + return await _context.SeriesMetadata + .Where(sm => seriesIds.Contains(sm.SeriesId)) + .Include(sm => sm.CollectionTags) + .ToListAsync(); + } + + public async Task> GetAllAgeRatingsDtosForLibrariesAsync(List libraryIds) + { + return await _context.Series + .Where(s => libraryIds.Contains(s.LibraryId)) + .Select(s => s.Metadata.AgeRating) + .Distinct() + .Select(s => new AgeRatingDto() { - return await _context.Series - .Where(s => s.LibraryId == libraryId) - .CountAsync(); - } - return await _context.Series.CountAsync(); - } + Value = s, + Title = s.ToDescription() + }) + .ToListAsync(); + } - /// - /// Returns the number of series that should be processed in parallel to optimize speed and memory. Minimum of 50 - /// - /// Defaults to 0 meaning no library - /// - private async Task> GetChunkSize(int libraryId = 0) - { - // TODO: Think about making this bigger depending on number of files a user has in said library - // and number of cores and amount of memory. We can then make an optimal choice - var totalSeries = await GetSeriesCount(libraryId); - // var procCount = Math.Max(Environment.ProcessorCount - 1, 1); - // - // if (totalSeries < procCount * 2 || totalSeries < 50) - // { - // return new Tuple(totalSeries, totalSeries); - // } - // - // return new Tuple(totalSeries, Math.Max(totalSeries / procCount, 50)); - return new Tuple(totalSeries, 50); - } + public async Task> GetAllLanguagesForLibrariesAsync(List libraryIds) + { + var ret = await _context.Series + .Where(s => libraryIds.Contains(s.LibraryId)) + .Select(s => s.Metadata.Language) + .Distinct() + .ToListAsync(); - public async Task GetChunkInfo(int libraryId = 0) - { - var (totalSeries, chunkSize) = await GetChunkSize(libraryId); - - if (totalSeries == 0) return new Chunk() + return ret + .Where(s => !string.IsNullOrEmpty(s)) + .Select(s => new LanguageDto() { - TotalChunks = 0, - TotalSize = 0, - ChunkSize = 0 - }; + Title = CultureInfo.GetCultureInfo(s).DisplayName, + IsoCode = s + }).ToList(); + } - var totalChunks = Math.Max((int) Math.Ceiling((totalSeries * 1.0) / chunkSize), 1); - - return new Chunk() + public async Task> GetAllPublicationStatusesDtosForLibrariesAsync(List libraryIds) + { + return await _context.Series + .Where(s => libraryIds.Contains(s.LibraryId)) + .Select(s => s.Metadata.PublicationStatus) + .Distinct() + .Select(s => new PublicationStatusDto() { - TotalSize = totalSeries, - ChunkSize = chunkSize, - TotalChunks = totalChunks - }; - } - - public async Task> GetSeriesMetadataForIdsAsync(IEnumerable seriesIds) - { - return await _context.SeriesMetadata - .Where(sm => seriesIds.Contains(sm.SeriesId)) - .Include(sm => sm.CollectionTags) - .ToListAsync(); - } + Value = s, + Title = s.ToDescription() + }) + .ToListAsync(); } } diff --git a/API/Data/Repositories/SettingsRepository.cs b/API/Data/Repositories/SettingsRepository.cs index 4489cf3bd..be66cbe62 100644 --- a/API/Data/Repositories/SettingsRepository.cs +++ b/API/Data/Repositories/SettingsRepository.cs @@ -4,45 +4,50 @@ using System.Threading.Tasks; using API.DTOs.Settings; using API.Entities; using API.Entities.Enums; -using API.Interfaces.Repositories; using AutoMapper; using Microsoft.EntityFrameworkCore; -namespace API.Data.Repositories +namespace API.Data.Repositories; + +public interface ISettingsRepository { - public class SettingsRepository : ISettingsRepository + void Update(ServerSetting settings); + Task GetSettingsDtoAsync(); + Task GetSettingAsync(ServerSettingKey key); + Task> GetSettingsAsync(); +} +public class SettingsRepository : ISettingsRepository +{ + private readonly DataContext _context; + private readonly IMapper _mapper; + + public SettingsRepository(DataContext context, IMapper mapper) { - private readonly DataContext _context; - private readonly IMapper _mapper; + _context = context; + _mapper = mapper; + } - public SettingsRepository(DataContext context, IMapper mapper) - { - _context = context; - _mapper = mapper; - } + public void Update(ServerSetting settings) + { + _context.Entry(settings).State = EntityState.Modified; + } - public void Update(ServerSetting settings) - { - _context.Entry(settings).State = EntityState.Modified; - } + public async Task GetSettingsDtoAsync() + { + var settings = await _context.ServerSetting + .Select(x => x) + .AsNoTracking() + .ToListAsync(); + return _mapper.Map(settings); + } - public async Task GetSettingsDtoAsync() - { - var settings = await _context.ServerSetting - .Select(x => x) - .AsNoTracking() - .ToListAsync(); - return _mapper.Map(settings); - } + public Task GetSettingAsync(ServerSettingKey key) + { + return _context.ServerSetting.SingleOrDefaultAsync(x => x.Key == key); + } - public Task GetSettingAsync(ServerSettingKey key) - { - return _context.ServerSetting.SingleOrDefaultAsync(x => x.Key == key); - } - - public async Task> GetSettingsAsync() - { - return await _context.ServerSetting.ToListAsync(); - } + public async Task> GetSettingsAsync() + { + return await _context.ServerSetting.ToListAsync(); } } diff --git a/API/Data/Repositories/TagRepository.cs b/API/Data/Repositories/TagRepository.cs new file mode 100644 index 000000000..772957aa9 --- /dev/null +++ b/API/Data/Repositories/TagRepository.cs @@ -0,0 +1,86 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using API.DTOs.Metadata; +using API.Entities; +using AutoMapper; +using AutoMapper.QueryableExtensions; +using Microsoft.EntityFrameworkCore; + +namespace API.Data.Repositories; + +public interface ITagRepository +{ + void Attach(Tag tag); + void Remove(Tag tag); + Task FindByNameAsync(string tagName); + Task> GetAllTagsAsync(); + Task> GetAllTagDtosAsync(); + Task RemoveAllTagNoLongerAssociated(bool removeExternal = false); + Task> GetAllTagDtosForLibrariesAsync(IList libraryIds); +} + +public class TagRepository : ITagRepository +{ + private readonly DataContext _context; + private readonly IMapper _mapper; + + public TagRepository(DataContext context, IMapper mapper) + { + _context = context; + _mapper = mapper; + } + + public void Attach(Tag tag) + { + _context.Tag.Attach(tag); + } + + public void Remove(Tag tag) + { + _context.Tag.Remove(tag); + } + + public async Task FindByNameAsync(string tagName) + { + var normalizedName = Parser.Parser.Normalize(tagName); + return await _context.Tag + .FirstOrDefaultAsync(g => g.NormalizedTitle.Equals(normalizedName)); + } + + public async Task RemoveAllTagNoLongerAssociated(bool removeExternal = false) + { + var TagsWithNoConnections = await _context.Tag + .Include(p => p.SeriesMetadatas) + .Include(p => p.Chapters) + .Where(p => p.SeriesMetadatas.Count == 0 && p.Chapters.Count == 0 && p.ExternalTag == removeExternal) + .ToListAsync(); + + _context.Tag.RemoveRange(TagsWithNoConnections); + + await _context.SaveChangesAsync(); + } + + public async Task> GetAllTagDtosForLibrariesAsync(IList libraryIds) + { + return await _context.Series + .Where(s => libraryIds.Contains(s.LibraryId)) + .SelectMany(s => s.Metadata.Tags) + .Distinct() + .ProjectTo(_mapper.ConfigurationProvider) + .ToListAsync(); + } + + public async Task> GetAllTagsAsync() + { + return await _context.Tag.ToListAsync(); + } + + public async Task> GetAllTagDtosAsync() + { + return await _context.Tag + .AsNoTracking() + .ProjectTo(_mapper.ConfigurationProvider) + .ToListAsync(); + } +} diff --git a/API/Data/Repositories/UserRepository.cs b/API/Data/Repositories/UserRepository.cs index ece1356fd..138ef15b8 100644 --- a/API/Data/Repositories/UserRepository.cs +++ b/API/Data/Repositories/UserRepository.cs @@ -6,254 +6,303 @@ using API.Constants; using API.DTOs; using API.DTOs.Reader; using API.Entities; -using API.Interfaces.Repositories; using AutoMapper; using AutoMapper.QueryableExtensions; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; -namespace API.Data.Repositories +namespace API.Data.Repositories; + +[Flags] +public enum AppUserIncludes { - [Flags] - public enum AppUserIncludes + None = 1, + Progress = 2, + Bookmarks = 4, + ReadingLists = 8, + Ratings = 16 +} + +public interface IUserRepository +{ + void Update(AppUser user); + void Update(AppUserPreferences preferences); + void Update(AppUserBookmark bookmark); + public void Delete(AppUser user); + Task> GetMembersAsync(); + Task> GetAdminUsersAsync(); + Task> GetNonAdminUsersAsync(); + Task IsUserAdminAsync(AppUser user); + Task GetUserRatingAsync(int seriesId, int userId); + Task GetPreferencesAsync(string username); + Task> GetBookmarkDtosForSeries(int userId, int seriesId); + Task> GetBookmarkDtosForVolume(int userId, int volumeId); + Task> GetBookmarkDtosForChapter(int userId, int chapterId); + Task> GetAllBookmarkDtos(int userId); + Task> GetAllBookmarksAsync(); + Task GetBookmarkForPage(int page, int chapterId, int userId); + Task GetBookmarkAsync(int bookmarkId); + Task GetUserIdByApiKeyAsync(string apiKey); + Task GetUserByUsernameAsync(string username, AppUserIncludes includeFlags = AppUserIncludes.None); + Task GetUserByIdAsync(int userId, AppUserIncludes includeFlags = AppUserIncludes.None); + Task GetUserIdByUsernameAsync(string username); + Task GetUserWithReadingListsByUsernameAsync(string username); + Task> GetAllBookmarksByIds(IList bookmarkIds); +} + +public class UserRepository : IUserRepository +{ + private readonly DataContext _context; + private readonly UserManager _userManager; + private readonly IMapper _mapper; + + public UserRepository(DataContext context, UserManager userManager, IMapper mapper) { - None = 1, - Progress = 2, - Bookmarks = 4, - ReadingLists = 8, - Ratings = 16 + _context = context; + _userManager = userManager; + _mapper = mapper; } - public class UserRepository : IUserRepository + public void Update(AppUser user) { - private readonly DataContext _context; - private readonly UserManager _userManager; - private readonly IMapper _mapper; + _context.Entry(user).State = EntityState.Modified; + } - public UserRepository(DataContext context, UserManager userManager, IMapper mapper) + public void Update(AppUserPreferences preferences) + { + _context.Entry(preferences).State = EntityState.Modified; + } + + public void Update(AppUserBookmark bookmark) + { + _context.Entry(bookmark).State = EntityState.Modified; + } + + public void Delete(AppUser user) + { + _context.AppUser.Remove(user); + } + + /// + /// A one stop shop to get a tracked AppUser instance with any number of JOINs generated by passing bitwise flags. + /// + /// + /// Includes() you want. Pass multiple with flag1 | flag2 + /// + public async Task GetUserByUsernameAsync(string username, AppUserIncludes includeFlags = AppUserIncludes.None) + { + var query = _context.Users + .Where(x => x.UserName == username); + + query = AddIncludesToQuery(query, includeFlags); + + return await query.SingleOrDefaultAsync(); + } + + /// + /// A one stop shop to get a tracked AppUser instance with any number of JOINs generated by passing bitwise flags. + /// + /// + /// Includes() you want. Pass multiple with flag1 | flag2 + /// + public async Task GetUserByIdAsync(int userId, AppUserIncludes includeFlags = AppUserIncludes.None) + { + var query = _context.Users + .Where(x => x.Id == userId); + + query = AddIncludesToQuery(query, includeFlags); + + return await query.SingleOrDefaultAsync(); + } + + public async Task> GetAllBookmarksAsync() + { + return await _context.AppUserBookmark.ToListAsync(); + } + + public async Task GetBookmarkForPage(int page, int chapterId, int userId) + { + return await _context.AppUserBookmark + .Where(b => b.Page == page && b.ChapterId == chapterId && b.AppUserId == userId) + .SingleOrDefaultAsync(); + } + + public async Task GetBookmarkAsync(int bookmarkId) + { + return await _context.AppUserBookmark + .Where(b => b.Id == bookmarkId) + .SingleOrDefaultAsync(); + } + + private static IQueryable AddIncludesToQuery(IQueryable query, AppUserIncludes includeFlags) + { + if (includeFlags.HasFlag(AppUserIncludes.Bookmarks)) { - _context = context; - _userManager = userManager; - _mapper = mapper; + query = query.Include(u => u.Bookmarks); } - public void Update(AppUser user) + if (includeFlags.HasFlag(AppUserIncludes.Progress)) { - _context.Entry(user).State = EntityState.Modified; + query = query.Include(u => u.Progresses); } - public void Update(AppUserPreferences preferences) + if (includeFlags.HasFlag(AppUserIncludes.ReadingLists)) { - _context.Entry(preferences).State = EntityState.Modified; + query = query.Include(u => u.ReadingLists); } - public void Update(AppUserBookmark bookmark) + if (includeFlags.HasFlag(AppUserIncludes.Ratings)) { - _context.Entry(bookmark).State = EntityState.Modified; + query = query.Include(u => u.Ratings); } - public void Delete(AppUser user) - { - _context.AppUser.Remove(user); - } + return query; + } - /// - /// A one stop shop to get a tracked AppUser instance with any number of JOINs generated by passing bitwise flags. - /// - /// - /// Includes() you want. Pass multiple with flag1 | flag2 - /// - public async Task GetUserByUsernameAsync(string username, AppUserIncludes includeFlags = AppUserIncludes.None) - { - var query = _context.Users - .Where(x => x.UserName == username); - query = AddIncludesToQuery(query, includeFlags); + /// + /// This fetches the Id for a user. Use whenever you just need an ID. + /// + /// + /// + public async Task GetUserIdByUsernameAsync(string username) + { + return await _context.Users + .Where(x => x.UserName == username) + .Select(u => u.Id) + .SingleOrDefaultAsync(); + } - return await query.SingleOrDefaultAsync(); - } + /// + /// Gets an AppUser by username. Returns back Reading List and their Items. + /// + /// + /// + public async Task GetUserWithReadingListsByUsernameAsync(string username) + { + return await _context.Users + .Include(u => u.ReadingLists) + .ThenInclude(l => l.Items) + .SingleOrDefaultAsync(x => x.UserName == username); + } - /// - /// A one stop shop to get a tracked AppUser instance with any number of JOINs generated by passing bitwise flags. - /// - /// - /// Includes() you want. Pass multiple with flag1 | flag2 - /// - public async Task GetUserByIdAsync(int userId, AppUserIncludes includeFlags = AppUserIncludes.None) - { - var query = _context.Users - .Where(x => x.Id == userId); + /// + /// Returns all Bookmarks for a given set of Ids + /// + /// + /// + public async Task> GetAllBookmarksByIds(IList bookmarkIds) + { + return await _context.AppUserBookmark + .Where(b => bookmarkIds.Contains(b.Id)) + .ToListAsync(); + } - query = AddIncludesToQuery(query, includeFlags); + public async Task> GetAdminUsersAsync() + { + return await _userManager.GetUsersInRoleAsync(PolicyConstants.AdminRole); + } - return await query.SingleOrDefaultAsync(); - } + public async Task> GetNonAdminUsersAsync() + { + return await _userManager.GetUsersInRoleAsync(PolicyConstants.PlebRole); + } - public async Task GetBookmarkForPage(int page, int chapterId, int userId) - { - return await _context.AppUserBookmark - .Where(b => b.Page == page && b.ChapterId == chapterId && b.AppUserId == userId) - .SingleOrDefaultAsync(); - } + public async Task IsUserAdminAsync(AppUser user) + { + return await _userManager.IsInRoleAsync(user, PolicyConstants.AdminRole); + } - private static IQueryable AddIncludesToQuery(IQueryable query, AppUserIncludes includeFlags) - { - if (includeFlags.HasFlag(AppUserIncludes.Bookmarks)) + public async Task GetUserRatingAsync(int seriesId, int userId) + { + return await _context.AppUserRating.Where(r => r.SeriesId == seriesId && r.AppUserId == userId) + .SingleOrDefaultAsync(); + } + + public async Task GetPreferencesAsync(string username) + { + return await _context.AppUserPreferences + .Include(p => p.AppUser) + .SingleOrDefaultAsync(p => p.AppUser.UserName == username); + } + + public async Task> GetBookmarkDtosForSeries(int userId, int seriesId) + { + return await _context.AppUserBookmark + .Where(x => x.AppUserId == userId && x.SeriesId == seriesId) + .OrderBy(x => x.Page) + .AsNoTracking() + .ProjectTo(_mapper.ConfigurationProvider) + .ToListAsync(); + } + + public async Task> GetBookmarkDtosForVolume(int userId, int volumeId) + { + return await _context.AppUserBookmark + .Where(x => x.AppUserId == userId && x.VolumeId == volumeId) + .OrderBy(x => x.Page) + .AsNoTracking() + .ProjectTo(_mapper.ConfigurationProvider) + .ToListAsync(); + } + + public async Task> GetBookmarkDtosForChapter(int userId, int chapterId) + { + return await _context.AppUserBookmark + .Where(x => x.AppUserId == userId && x.ChapterId == chapterId) + .OrderBy(x => x.Page) + .AsNoTracking() + .ProjectTo(_mapper.ConfigurationProvider) + .ToListAsync(); + } + + public async Task> GetAllBookmarkDtos(int userId) + { + return await _context.AppUserBookmark + .Where(x => x.AppUserId == userId) + .OrderBy(x => x.Page) + .AsNoTracking() + .ProjectTo(_mapper.ConfigurationProvider) + .ToListAsync(); + } + + /// + /// Fetches the UserId by API Key. This does not include any extra information + /// + /// + /// + public async Task GetUserIdByApiKeyAsync(string apiKey) + { + return await _context.AppUser + .Where(u => u.ApiKey.Equals(apiKey)) + .Select(u => u.Id) + .SingleOrDefaultAsync(); + } + + + public async Task> GetMembersAsync() + { + return await _context.Users + .Include(x => x.Libraries) + .Include(r => r.UserRoles) + .ThenInclude(r => r.Role) + .OrderBy(u => u.UserName) + .Select(u => new MemberDto { - query = query.Include(u => u.Bookmarks); - } - - if (includeFlags.HasFlag(AppUserIncludes.Progress)) - { - query = query.Include(u => u.Progresses); - } - - if (includeFlags.HasFlag(AppUserIncludes.ReadingLists)) - { - query = query.Include(u => u.ReadingLists); - } - - if (includeFlags.HasFlag(AppUserIncludes.Ratings)) - { - query = query.Include(u => u.Ratings); - } - - return query; - } - - - /// - /// This fetches the Id for a user. Use whenever you just need an ID. - /// - /// - /// - public async Task GetUserIdByUsernameAsync(string username) - { - return await _context.Users - .Where(x => x.UserName == username) - .Select(u => u.Id) - .SingleOrDefaultAsync(); - } - - /// - /// Gets an AppUser by username. Returns back Reading List and their Items. - /// - /// - /// - public async Task GetUserWithReadingListsByUsernameAsync(string username) - { - return await _context.Users - .Include(u => u.ReadingLists) - .ThenInclude(l => l.Items) - .SingleOrDefaultAsync(x => x.UserName == username); - } - - public async Task> GetAdminUsersAsync() - { - return await _userManager.GetUsersInRoleAsync(PolicyConstants.AdminRole); - } - - public async Task> GetNonAdminUsersAsync() - { - return await _userManager.GetUsersInRoleAsync(PolicyConstants.PlebRole); - } - - public async Task IsUserAdmin(AppUser user) - { - return await _userManager.IsInRoleAsync(user, PolicyConstants.AdminRole); - } - - public async Task GetUserRating(int seriesId, int userId) - { - return await _context.AppUserRating.Where(r => r.SeriesId == seriesId && r.AppUserId == userId) - .SingleOrDefaultAsync(); - } - - public async Task GetPreferencesAsync(string username) - { - return await _context.AppUserPreferences - .Include(p => p.AppUser) - .SingleOrDefaultAsync(p => p.AppUser.UserName == username); - } - - public async Task> GetBookmarkDtosForSeries(int userId, int seriesId) - { - return await _context.AppUserBookmark - .Where(x => x.AppUserId == userId && x.SeriesId == seriesId) - .OrderBy(x => x.Page) - .AsNoTracking() - .ProjectTo(_mapper.ConfigurationProvider) - .ToListAsync(); - } - - public async Task> GetBookmarkDtosForVolume(int userId, int volumeId) - { - return await _context.AppUserBookmark - .Where(x => x.AppUserId == userId && x.VolumeId == volumeId) - .OrderBy(x => x.Page) - .AsNoTracking() - .ProjectTo(_mapper.ConfigurationProvider) - .ToListAsync(); - } - - public async Task> GetBookmarkDtosForChapter(int userId, int chapterId) - { - return await _context.AppUserBookmark - .Where(x => x.AppUserId == userId && x.ChapterId == chapterId) - .OrderBy(x => x.Page) - .AsNoTracking() - .ProjectTo(_mapper.ConfigurationProvider) - .ToListAsync(); - } - - public async Task> GetAllBookmarkDtos(int userId) - { - return await _context.AppUserBookmark - .Where(x => x.AppUserId == userId) - .OrderBy(x => x.Page) - .AsNoTracking() - .ProjectTo(_mapper.ConfigurationProvider) - .ToListAsync(); - } - - /// - /// Fetches the UserId by API Key. This does not include any extra information - /// - /// - /// - public async Task GetUserIdByApiKeyAsync(string apiKey) - { - return await _context.AppUser - .Where(u => u.ApiKey.Equals(apiKey)) - .Select(u => u.Id) - .SingleOrDefaultAsync(); - } - - - public async Task> GetMembersAsync() - { - return await _context.Users - .Include(x => x.Libraries) - .Include(r => r.UserRoles) - .ThenInclude(r => r.Role) - .OrderBy(u => u.UserName) - .Select(u => new MemberDto + Id = u.Id, + Username = u.UserName, + Created = u.Created, + LastActive = u.LastActive, + Roles = u.UserRoles.Select(r => r.Role.Name).ToList(), + Libraries = u.Libraries.Select(l => new LibraryDto { - Id = u.Id, - Username = u.UserName, - Created = u.Created, - LastActive = u.LastActive, - Roles = u.UserRoles.Select(r => r.Role.Name).ToList(), - Libraries = u.Libraries.Select(l => new LibraryDto - { - Name = l.Name, - Type = l.Type, - LastScanned = l.LastScanned, - Folders = l.Folders.Select(x => x.Path).ToList() - }).ToList() - }) - .AsNoTracking() - .ToListAsync(); - } + Name = l.Name, + Type = l.Type, + LastScanned = l.LastScanned, + Folders = l.Folders.Select(x => x.Path).ToList() + }).ToList() + }) + .AsNoTracking() + .ToListAsync(); } } diff --git a/API/Data/Repositories/VolumeRepository.cs b/API/Data/Repositories/VolumeRepository.cs index 339da798d..e63b469e6 100644 --- a/API/Data/Repositories/VolumeRepository.cs +++ b/API/Data/Repositories/VolumeRepository.cs @@ -4,205 +4,223 @@ using System.Threading.Tasks; using API.Comparators; using API.DTOs; using API.Entities; -using API.Interfaces.Repositories; +using API.Extensions; using AutoMapper; using AutoMapper.QueryableExtensions; using Microsoft.EntityFrameworkCore; -namespace API.Data.Repositories +namespace API.Data.Repositories; + +public interface IVolumeRepository { - public class VolumeRepository : IVolumeRepository - { - private readonly DataContext _context; - private readonly IMapper _mapper; - - public VolumeRepository(DataContext context, IMapper mapper) - { - _context = context; - _mapper = mapper; - } - - public void Add(Volume volume) - { - _context.Volume.Add(volume); - } - - public void Update(Volume volume) - { - _context.Entry(volume).State = EntityState.Modified; - } - - public void Remove(Volume volume) - { - _context.Volume.Remove(volume); - } - - /// - /// Returns a list of non-tracked files for a given volume. - /// - /// - /// - public async Task> GetFilesForVolume(int volumeId) - { - return await _context.Chapter - .Where(c => volumeId == c.VolumeId) - .Include(c => c.Files) - .SelectMany(c => c.Files) - .AsNoTracking() - .ToListAsync(); - } - - /// - /// Returns the cover image file for the given volume - /// - /// - /// - public async Task GetVolumeCoverImageAsync(int volumeId) - { - return await _context.Volume - .Where(v => v.Id == volumeId) - .Select(v => v.CoverImage) - .AsNoTracking() - .SingleOrDefaultAsync(); - } - - /// - /// Returns all chapter Ids belonging to a list of Volume Ids - /// - /// - /// - public async Task> GetChapterIdsByVolumeIds(IReadOnlyList volumeIds) - { - return await _context.Chapter - .Where(c => volumeIds.Contains(c.VolumeId)) - .Select(c => c.Id) - .ToListAsync(); - } - - /// - /// Returns all volumes that contain a seriesId in passed array. - /// - /// - /// - public async Task> GetVolumesForSeriesAsync(IList seriesIds, bool includeChapters = false) - { - var query = _context.Volume - .Where(v => seriesIds.Contains(v.SeriesId)); - - if (includeChapters) - { - query = query.Include(v => v.Chapters); - } - return await query.ToListAsync(); - } - - /// - /// Returns an individual Volume including Chapters and Files and Reading Progress for a given volumeId - /// - /// - /// - /// - public async Task GetVolumeDtoAsync(int volumeId, int userId) - { - var volume = await _context.Volume - .Where(vol => vol.Id == volumeId) - .Include(vol => vol.Chapters) - .ThenInclude(c => c.Files) - .ProjectTo(_mapper.ConfigurationProvider) - .SingleAsync(vol => vol.Id == volumeId); - - var volumeList = new List() {volume}; - await AddVolumeModifiers(userId, volumeList); - - return volumeList[0]; - } - - /// - /// Returns the full Volumes including Chapters and Files for a given series - /// - /// - /// - public async Task> GetVolumes(int seriesId) - { - return await _context.Volume - .Where(vol => vol.SeriesId == seriesId) - .Include(vol => vol.Chapters) - .ThenInclude(c => c.Files) - .OrderBy(vol => vol.Number) - .ToListAsync(); - } - - /// - /// Returns a single volume with Chapter and Files - /// - /// - /// - public async Task GetVolumeAsync(int volumeId) - { - return await _context.Volume - .Include(vol => vol.Chapters) - .ThenInclude(c => c.Files) - .SingleOrDefaultAsync(vol => vol.Id == volumeId); - } - - - /// - /// Returns all volumes for a given series with progress information attached. Includes all Chapters as well. - /// - /// - /// - /// - public async Task> GetVolumesDtoAsync(int seriesId, int userId) - { - var volumes = await _context.Volume - .Where(vol => vol.SeriesId == seriesId) - .Include(vol => vol.Chapters) - .OrderBy(volume => volume.Number) - .ProjectTo(_mapper.ConfigurationProvider) - .AsNoTracking() - .ToListAsync(); - - await AddVolumeModifiers(userId, volumes); - SortSpecialChapters(volumes); - - return volumes; - } - - public async Task GetVolumeByIdAsync(int volumeId) - { - return await _context.Volume.SingleOrDefaultAsync(x => x.Id == volumeId); - } - - - private static void SortSpecialChapters(IEnumerable volumes) - { - var sorter = new NaturalSortComparer(); - foreach (var v in volumes.Where(vDto => vDto.Number == 0)) - { - v.Chapters = v.Chapters.OrderBy(x => x.Range, sorter).ToList(); - } - } - - - private async Task AddVolumeModifiers(int userId, IReadOnlyCollection volumes) - { - var volIds = volumes.Select(s => s.Id); - var userProgress = await _context.AppUserProgresses - .Where(p => p.AppUserId == userId && volIds.Contains(p.VolumeId)) - .AsNoTracking() - .ToListAsync(); - - foreach (var v in volumes) - { - foreach (var c in v.Chapters) - { - c.PagesRead = userProgress.Where(p => p.ChapterId == c.Id).Sum(p => p.PagesRead); - } - - v.PagesRead = userProgress.Where(p => p.VolumeId == v.Id).Sum(p => p.PagesRead); - } - } - - - } + void Add(Volume volume); + void Update(Volume volume); + void Remove(Volume volume); + Task> GetFilesForVolume(int volumeId); + Task GetVolumeCoverImageAsync(int volumeId); + Task> GetChapterIdsByVolumeIds(IReadOnlyList volumeIds); + Task> GetVolumesDtoAsync(int seriesId, int userId); + Task GetVolumeAsync(int volumeId); + Task GetVolumeDtoAsync(int volumeId, int userId); + Task> GetVolumesForSeriesAsync(IList seriesIds, bool includeChapters = false); + Task> GetVolumes(int seriesId); + Task GetVolumeByIdAsync(int volumeId); +} +public class VolumeRepository : IVolumeRepository +{ + private readonly DataContext _context; + private readonly IMapper _mapper; + + public VolumeRepository(DataContext context, IMapper mapper) + { + _context = context; + _mapper = mapper; + } + + public void Add(Volume volume) + { + _context.Volume.Add(volume); + } + + public void Update(Volume volume) + { + _context.Entry(volume).State = EntityState.Modified; + } + + public void Remove(Volume volume) + { + _context.Volume.Remove(volume); + } + + /// + /// Returns a list of non-tracked files for a given volume. + /// + /// + /// + public async Task> GetFilesForVolume(int volumeId) + { + return await _context.Chapter + .Where(c => volumeId == c.VolumeId) + .Include(c => c.Files) + .SelectMany(c => c.Files) + .AsNoTracking() + .ToListAsync(); + } + + /// + /// Returns the cover image file for the given volume + /// + /// + /// + public async Task GetVolumeCoverImageAsync(int volumeId) + { + return await _context.Volume + .Where(v => v.Id == volumeId) + .Select(v => v.CoverImage) + .AsNoTracking() + .SingleOrDefaultAsync(); + } + + /// + /// Returns all chapter Ids belonging to a list of Volume Ids + /// + /// + /// + public async Task> GetChapterIdsByVolumeIds(IReadOnlyList volumeIds) + { + return await _context.Chapter + .Where(c => volumeIds.Contains(c.VolumeId)) + .Select(c => c.Id) + .ToListAsync(); + } + + /// + /// Returns all volumes that contain a seriesId in passed array. + /// + /// + /// Include chapter entities + /// + public async Task> GetVolumesForSeriesAsync(IList seriesIds, bool includeChapters = false) + { + var query = _context.Volume + .Where(v => seriesIds.Contains(v.SeriesId)); + + if (includeChapters) + { + query = query.Include(v => v.Chapters); + } + return await query.ToListAsync(); + } + + /// + /// Returns an individual Volume including Chapters and Files and Reading Progress for a given volumeId + /// + /// + /// + /// + public async Task GetVolumeDtoAsync(int volumeId, int userId) + { + var volume = await _context.Volume + .Where(vol => vol.Id == volumeId) + .Include(vol => vol.Chapters) + .ThenInclude(c => c.Files) + .ProjectTo(_mapper.ConfigurationProvider) + .SingleAsync(vol => vol.Id == volumeId); + + var volumeList = new List() {volume}; + await AddVolumeModifiers(userId, volumeList); + + return volumeList[0]; + } + + /// + /// Returns the full Volumes including Chapters and Files for a given series + /// + /// + /// + public async Task> GetVolumes(int seriesId) + { + return await _context.Volume + .Where(vol => vol.SeriesId == seriesId) + .Include(vol => vol.Chapters) + .ThenInclude(c => c.Files) + .OrderBy(vol => vol.Number) + .ToListAsync(); + } + + /// + /// Returns a single volume with Chapter and Files + /// + /// + /// + public async Task GetVolumeAsync(int volumeId) + { + return await _context.Volume + .Include(vol => vol.Chapters) + .ThenInclude(c => c.Files) + .SingleOrDefaultAsync(vol => vol.Id == volumeId); + } + + + /// + /// Returns all volumes for a given series with progress information attached. Includes all Chapters as well. + /// + /// + /// + /// + public async Task> GetVolumesDtoAsync(int seriesId, int userId) + { + var volumes = await _context.Volume + .Where(vol => vol.SeriesId == seriesId) + .Include(vol => vol.Chapters) + .ThenInclude(c => c.People) + .Include(vol => vol.Chapters) + .ThenInclude(c => c.Tags) + .OrderBy(volume => volume.Number) + .ProjectTo(_mapper.ConfigurationProvider) + .AsNoTracking() + .AsSplitQuery() + .ToListAsync(); + + await AddVolumeModifiers(userId, volumes); + SortSpecialChapters(volumes); + + return volumes; + } + + public async Task GetVolumeByIdAsync(int volumeId) + { + return await _context.Volume.SingleOrDefaultAsync(x => x.Id == volumeId); + } + + + private static void SortSpecialChapters(IEnumerable volumes) + { + foreach (var v in volumes.Where(vDto => vDto.Number == 0)) + { + v.Chapters = v.Chapters.OrderByNatural(x => x.Range).ToList(); + } + } + + + private async Task AddVolumeModifiers(int userId, IReadOnlyCollection volumes) + { + var volIds = volumes.Select(s => s.Id); + var userProgress = await _context.AppUserProgresses + .Where(p => p.AppUserId == userId && volIds.Contains(p.VolumeId)) + .AsNoTracking() + .ToListAsync(); + + foreach (var v in volumes) + { + foreach (var c in v.Chapters) + { + c.PagesRead = userProgress.Where(p => p.ChapterId == c.Id).Sum(p => p.PagesRead); + } + + v.PagesRead = userProgress.Where(p => p.VolumeId == v.Id).Sum(p => p.PagesRead); + } + } + + } diff --git a/API/Data/Seed.cs b/API/Data/Seed.cs index 9cfbaeaa4..b7590e168 100644 --- a/API/Data/Seed.cs +++ b/API/Data/Seed.cs @@ -8,6 +8,7 @@ using API.Entities; using API.Entities.Enums; using API.Services; using Kavita.Common; +using Kavita.Common.EnvironmentInfo; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; @@ -15,6 +16,11 @@ namespace API.Data { public static class Seed { + /// + /// Generated on Startup. Seed.SeedSettings must run before + /// + public static IList DefaultSettings; + public static async Task SeedRoles(RoleManager roleManager) { var roles = typeof(PolicyConstants) @@ -35,16 +41,16 @@ namespace API.Data } } - public static async Task SeedSettings(DataContext context) + public static async Task SeedSettings(DataContext context, IDirectoryService directoryService) { await context.Database.EnsureCreatedAsync(); - IList defaultSettings = new List() + DefaultSettings = new List() { - new () {Key = ServerSettingKey.CacheDirectory, Value = DirectoryService.CacheDirectory}, + new () {Key = ServerSettingKey.CacheDirectory, Value = directoryService.CacheDirectory}, new () {Key = ServerSettingKey.TaskScan, Value = "daily"}, new () {Key = ServerSettingKey.LoggingLevel, Value = "Information"}, // Not used from DB, but DB is sync with appSettings.json - new () {Key = ServerSettingKey.TaskBackup, Value = "weekly"}, + new () {Key = ServerSettingKey.TaskBackup, Value = "daily"}, new () {Key = ServerSettingKey.BackupDirectory, Value = Path.GetFullPath(DirectoryService.BackupDirectory)}, new () {Key = ServerSettingKey.Port, Value = "5000"}, // Not used from DB, but DB is sync with appSettings.json new () {Key = ServerSettingKey.AllowStatCollection, Value = "true"}, @@ -52,9 +58,11 @@ namespace API.Data new () {Key = ServerSettingKey.EnableAuthentication, Value = "true"}, new () {Key = ServerSettingKey.BaseUrl, Value = "/"}, new () {Key = ServerSettingKey.InstallId, Value = HashUtil.AnonymousToken()}, + new () {Key = ServerSettingKey.InstallVersion, Value = BuildInfo.Version.ToString()}, + new () {Key = ServerSettingKey.BookmarkDirectory, Value = directoryService.BookmarkDirectory}, }; - foreach (var defaultSetting in defaultSettings) + foreach (var defaultSetting in DefaultSettings) { var existing = context.ServerSetting.FirstOrDefault(s => s.Key == defaultSetting.Key); if (existing == null) @@ -71,7 +79,7 @@ namespace API.Data context.ServerSetting.First(s => s.Key == ServerSettingKey.LoggingLevel).Value = Configuration.LogLevel + string.Empty; context.ServerSetting.First(s => s.Key == ServerSettingKey.CacheDirectory).Value = - DirectoryService.CacheDirectory + string.Empty; + directoryService.CacheDirectory + string.Empty; context.ServerSetting.First(s => s.Key == ServerSettingKey.BackupDirectory).Value = DirectoryService.BackupDirectory + string.Empty; diff --git a/API/Data/UnitOfWork.cs b/API/Data/UnitOfWork.cs index a1f797188..82046ca2a 100644 --- a/API/Data/UnitOfWork.cs +++ b/API/Data/UnitOfWork.cs @@ -1,84 +1,104 @@ using System.Threading.Tasks; using API.Data.Repositories; using API.Entities; -using API.Interfaces; -using API.Interfaces.Repositories; using AutoMapper; using Microsoft.AspNetCore.Identity; -namespace API.Data +namespace API.Data; + +public interface IUnitOfWork { - public class UnitOfWork : IUnitOfWork + ISeriesRepository SeriesRepository { get; } + IUserRepository UserRepository { get; } + ILibraryRepository LibraryRepository { get; } + IVolumeRepository VolumeRepository { get; } + ISettingsRepository SettingsRepository { get; } + IAppUserProgressRepository AppUserProgressRepository { get; } + ICollectionTagRepository CollectionTagRepository { get; } + IChapterRepository ChapterRepository { get; } + IReadingListRepository ReadingListRepository { get; } + ISeriesMetadataRepository SeriesMetadataRepository { get; } + IPersonRepository PersonRepository { get; } + IGenreRepository GenreRepository { get; } + ITagRepository TagRepository { get; } + bool Commit(); + Task CommitAsync(); + bool HasChanges(); + bool Rollback(); + Task RollbackAsync(); +} +public class UnitOfWork : IUnitOfWork +{ + private readonly DataContext _context; + private readonly IMapper _mapper; + private readonly UserManager _userManager; + + public UnitOfWork(DataContext context, IMapper mapper, UserManager userManager) { - private readonly DataContext _context; - private readonly IMapper _mapper; - private readonly UserManager _userManager; + _context = context; + _mapper = mapper; + _userManager = userManager; + } - public UnitOfWork(DataContext context, IMapper mapper, UserManager userManager) - { - _context = context; - _mapper = mapper; - _userManager = userManager; - } + public ISeriesRepository SeriesRepository => new SeriesRepository(_context, _mapper); + public IUserRepository UserRepository => new UserRepository(_context, _userManager, _mapper); + public ILibraryRepository LibraryRepository => new LibraryRepository(_context, _mapper); - public ISeriesRepository SeriesRepository => new SeriesRepository(_context, _mapper); - public IUserRepository UserRepository => new UserRepository(_context, _userManager, _mapper); - public ILibraryRepository LibraryRepository => new LibraryRepository(_context, _mapper); + public IVolumeRepository VolumeRepository => new VolumeRepository(_context, _mapper); - public IVolumeRepository VolumeRepository => new VolumeRepository(_context, _mapper); + public ISettingsRepository SettingsRepository => new SettingsRepository(_context, _mapper); - public ISettingsRepository SettingsRepository => new SettingsRepository(_context, _mapper); + public IAppUserProgressRepository AppUserProgressRepository => new AppUserProgressRepository(_context); + public ICollectionTagRepository CollectionTagRepository => new CollectionTagRepository(_context, _mapper); + public IChapterRepository ChapterRepository => new ChapterRepository(_context, _mapper); + public IReadingListRepository ReadingListRepository => new ReadingListRepository(_context, _mapper); + public ISeriesMetadataRepository SeriesMetadataRepository => new SeriesMetadataRepository(_context); + public IPersonRepository PersonRepository => new PersonRepository(_context, _mapper); + public IGenreRepository GenreRepository => new GenreRepository(_context, _mapper); + public ITagRepository TagRepository => new TagRepository(_context, _mapper); - public IAppUserProgressRepository AppUserProgressRepository => new AppUserProgressRepository(_context); - public ICollectionTagRepository CollectionTagRepository => new CollectionTagRepository(_context, _mapper); - public IFileRepository FileRepository => new FileRepository(_context); - public IChapterRepository ChapterRepository => new ChapterRepository(_context, _mapper); - public IReadingListRepository ReadingListRepository => new ReadingListRepository(_context, _mapper); - public ISeriesMetadataRepository SeriesMetadataRepository => new SeriesMetadataRepository(_context); + /// + /// Commits changes to the DB. Completes the open transaction. + /// + /// + public bool Commit() + { + return _context.SaveChanges() > 0; + } + /// + /// Commits changes to the DB. Completes the open transaction. + /// + /// + public async Task CommitAsync() + { + return await _context.SaveChangesAsync() > 0; + } - /// - /// Commits changes to the DB. Completes the open transaction. - /// - /// - public bool Commit() - { - return _context.SaveChanges() > 0; - } - /// - /// Commits changes to the DB. Completes the open transaction. - /// - /// - public async Task CommitAsync() - { - return await _context.SaveChangesAsync() > 0; - } + /// + /// Is the DB Context aware of Changes in loaded entities + /// + /// + public bool HasChanges() + { + return _context.ChangeTracker.HasChanges(); + } - /// - /// Is the DB Context aware of Changes in loaded entities - /// - /// - public bool HasChanges() - { - return _context.ChangeTracker.HasChanges(); - } - - /// - /// Rollback transaction - /// - /// - public async Task RollbackAsync() - { - await _context.DisposeAsync(); - return true; - } - /// - /// Rollback transaction - /// - /// - public bool Rollback() - { - _context.Dispose(); - return true; - } + /// + /// Rollback transaction + /// + /// + public async Task RollbackAsync() + { + await _context.DisposeAsync(); + return true; + } + /// + /// Rollback transaction + /// + /// + public bool Rollback() + { + _context.Dispose(); + return true; } } diff --git a/API/Dockerfile b/API/Dockerfile index 4289aaa3d..ce607a02f 100644 --- a/API/Dockerfile +++ b/API/Dockerfile @@ -1,5 +1,5 @@ #This Dockerfile pulls the latest git commit and builds Kavita from source -FROM mcr.microsoft.com/dotnet/sdk:5.0-focal AS builder +FROM mcr.microsoft.com/dotnet/sdk:6.0-focal AS builder ENV DEBIAN_FRONTEND=noninteractive ARG TARGETPLATFORM @@ -37,4 +37,4 @@ EXPOSE 5000 WORKDIR /kavita ENTRYPOINT ["/bin/bash"] -CMD ["/entrypoint.sh"] \ No newline at end of file +CMD ["/entrypoint.sh"] diff --git a/API/Entities/AppUserBookmark.cs b/API/Entities/AppUserBookmark.cs index cfb9aa29a..81a26a08b 100644 --- a/API/Entities/AppUserBookmark.cs +++ b/API/Entities/AppUserBookmark.cs @@ -13,6 +13,11 @@ namespace API.Entities public int SeriesId { get; set; } public int ChapterId { get; set; } + /// + /// Filename in the Bookmark Directory + /// + public string FileName { get; set; } = string.Empty; + // Relationships [JsonIgnore] diff --git a/API/Entities/Chapter.cs b/API/Entities/Chapter.cs index ef12de8ce..e6e7926e3 100644 --- a/API/Entities/Chapter.cs +++ b/API/Entities/Chapter.cs @@ -41,6 +41,50 @@ namespace API.Entities /// Used for books/specials to display custom title. For non-specials/books, will be set to /// public string Title { get; set; } + /// + /// Age Rating for the issue/chapter + /// + public AgeRating AgeRating { get; set; } + + /// + /// Chapter title + /// + /// This should not be confused with Title which is used for special filenames. + public string TitleName { get; set; } = string.Empty; + /// + /// Date which chapter was released + /// + public DateTime ReleaseDate { get; set; } + /// + /// Summary for the Chapter/Issue + /// + public string Summary { get; set; } + /// + /// Language for the Chapter/Issue + /// + public string Language { get; set; } + /// + /// Total number of issues in the series + /// + public int TotalCount { get; set; } = 0; + /// + /// Number in the Total Count + /// + public int Count { get; set; } = 0; + + + /// + /// All people attached at a Chapter level. Usually Comics will have different people per issue. + /// + public ICollection People { get; set; } = new List(); + /// + /// Genres for the Chapter + /// + public ICollection Genres { get; set; } = new List(); + public ICollection Tags { get; set; } = new List(); + + + // Relationships public Volume Volume { get; set; } diff --git a/API/Entities/CollectionTag.cs b/API/Entities/CollectionTag.cs index ee966cafc..b38960f89 100644 --- a/API/Entities/CollectionTag.cs +++ b/API/Entities/CollectionTag.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using API.Entities.Metadata; using Microsoft.EntityFrameworkCore; namespace API.Entities diff --git a/API/Entities/Enums/AgeRating.cs b/API/Entities/Enums/AgeRating.cs new file mode 100644 index 000000000..ddb288ee1 --- /dev/null +++ b/API/Entities/Enums/AgeRating.cs @@ -0,0 +1,43 @@ +using System.ComponentModel; + +namespace API.Entities.Enums; + +/// +/// Represents Age Rating for content. +/// +/// Based on ComicInfo.xml v2.1 https://github.com/anansi-project/comicinfo/blob/main/drafts/v2.1/ComicInfo.xsd +public enum AgeRating +{ + [Description("Unknown")] + Unknown = 0, + [Description("Rating Pending")] + RatingPending = 1, + [Description("Early Childhood")] + EarlyChildhood = 2, + [Description("Everyone")] + Everyone = 3, + [Description("G")] + G = 4, + [Description("Everyone 10+")] + Everyone10Plus = 5, + [Description("PG")] + PG = 6, + [Description("Kids to Adults")] + KidsToAdults = 7, + [Description("Teen")] + Teen = 8, + [Description("MA 15+")] + Mature15Plus = 9, + [Description("Mature 17+")] + Mature17Plus = 10, + [Description("M")] + Mature = 11, + [Description("R18+")] + R18Plus = 12, + [Description("Adults Only 18+")] + AdultsOnly = 13, + [Description("X18+")] + X18Plus = 14 + + +} diff --git a/API/Entities/Enums/LibraryType.cs b/API/Entities/Enums/LibraryType.cs index 23bb8df25..dd2c83b92 100644 --- a/API/Entities/Enums/LibraryType.cs +++ b/API/Entities/Enums/LibraryType.cs @@ -4,10 +4,19 @@ namespace API.Entities.Enums { public enum LibraryType { + /// + /// Uses Manga regex for filename parsing + /// [Description("Manga")] Manga = 0, + /// + /// Uses Comic regex for filename parsing + /// [Description("Comic")] Comic = 1, + /// + /// Uses Manga regex for filename parsing also uses epub metadata + /// [Description("Book")] Book = 2, } diff --git a/API/Entities/Enums/PersonRole.cs b/API/Entities/Enums/PersonRole.cs index 47e60721b..714e1d534 100644 --- a/API/Entities/Enums/PersonRole.cs +++ b/API/Entities/Enums/PersonRole.cs @@ -5,15 +5,31 @@ /// /// Another role, not covered by other types /// - Other = 0, - /// - /// Author - /// - Author = 1, + Other = 1, /// /// Artist /// - Artist = 2, - + //Artist = 2, + /// + /// Author or Writer + /// + Writer = 3, + Penciller = 4, + Inker = 5, + Colorist = 6, + Letterer = 7, + CoverArtist = 8, + Editor = 9, + Publisher = 10, + /// + /// Represents a character/person within the story + /// + Character = 11, + /// + /// The Translator + /// + Translator = 12 + + } -} \ No newline at end of file +} diff --git a/API/Entities/Enums/PublicationStatus.cs b/API/Entities/Enums/PublicationStatus.cs new file mode 100644 index 000000000..4d8124391 --- /dev/null +++ b/API/Entities/Enums/PublicationStatus.cs @@ -0,0 +1,23 @@ +using System.ComponentModel; + +namespace API.Entities.Enums; + +public enum PublicationStatus +{ + /// + /// Default Status. Publication is currently in progress + /// + [Description("On Going")] + OnGoing = 0, + /// + /// Series is on temp or indefinite Hiatus + /// + [Description("Hiatus")] + Hiatus = 1, + /// + /// Publication has finished releasing + /// + [Description("Completed")] + Completed = 2 + +} diff --git a/API/Entities/Enums/ServerSettingKey.cs b/API/Entities/Enums/ServerSettingKey.cs index 3f097c675..80484d693 100644 --- a/API/Entities/Enums/ServerSettingKey.cs +++ b/API/Entities/Enums/ServerSettingKey.cs @@ -58,7 +58,18 @@ namespace API.Entities.Enums /// Represents this installation of Kavita. Is tied to Stat reporting but has no information about user or files. /// [Description("InstallId")] - InstallId = 10 + InstallId = 10, + /// + /// Represents the version the software is running. + /// + /// This will be updated on Startup to the latest release. Provides ability to detect if certain migrations need to be run. + [Description("InstallVersion")] + InstallVersion = 11, + /// + /// Location of where bookmarks are stored + /// + [Description("BookmarkDirectory")] + BookmarkDirectory = 12, } } diff --git a/API/Entities/Genre.cs b/API/Entities/Genre.cs index 9490c03e7..447f14943 100644 --- a/API/Entities/Genre.cs +++ b/API/Entities/Genre.cs @@ -1,22 +1,18 @@ -using System.ComponentModel.DataAnnotations; -using API.Entities.Interfaces; +using System.Collections.Generic; +using API.Entities.Metadata; +using Microsoft.EntityFrameworkCore; namespace API.Entities { - public class Genre : IHasConcurrencyToken + [Index(nameof(NormalizedTitle), nameof(ExternalTag), IsUnique = true)] + public class Genre { public int Id { get; set; } - public string Name { get; set; } - // MetadataUpdate add ProviderId + public string Title { get; set; } + public string NormalizedTitle { get; set; } + public bool ExternalTag { get; set; } - /// - [ConcurrencyCheck] - public uint RowVersion { get; private set; } - - /// - public void OnSavingChanges() - { - RowVersion++; - } + public ICollection SeriesMetadatas { get; set; } + public ICollection Chapters { get; set; } } } diff --git a/API/Entities/MangaFile.cs b/API/Entities/MangaFile.cs index 2865178c7..8cd99f3e1 100644 --- a/API/Entities/MangaFile.cs +++ b/API/Entities/MangaFile.cs @@ -23,24 +23,17 @@ namespace API.Entities /// /// Last time underlying file was modified /// + /// This gets updated anytime the file is scanned public DateTime LastModified { get; set; } + // Relationship Mapping public Chapter Chapter { get; set; } public int ChapterId { get; set; } - // Methods - /// - /// If the File on disk's last modified time is after what is stored in MangaFile - /// - /// - public bool HasFileBeenModified() - { - return File.GetLastWriteTime(FilePath) > LastModified; - } /// - /// Updates the Last Modified time of the underlying file + /// Updates the Last Modified time of the underlying file to the LastWriteTime /// public void UpdateLastModified() { diff --git a/API/Entities/Metadata/ChapterMetadata.cs b/API/Entities/Metadata/ChapterMetadata.cs new file mode 100644 index 000000000..ef4836c23 --- /dev/null +++ b/API/Entities/Metadata/ChapterMetadata.cs @@ -0,0 +1,34 @@ +using System.Collections.Generic; + +namespace API.Entities.Metadata +{ + /// + /// Has a 1-to-1 relationship with a Chapter. Represents metadata about a chapter. + /// + public class ChapterMetadata + { + public int Id { get; set; } + + /// + /// Chapter title + /// + /// This should not be confused with Chapter.Title which is used for special filenames. + public string Title { get; set; } = string.Empty; + public string Year { get; set; } // Only time I can think this will be more than 1 year is for a volume which will be a spread + public string StoryArc { get; set; } // This might be a list + + /// + /// All people attached at a Chapter level. Usually Comics will have different people per issue. + /// + public ICollection People { get; set; } = new List(); + + + + + + // Relationships + public Chapter Chapter { get; set; } + public int ChapterId { get; set; } + + } +} diff --git a/API/Entities/Metadata/SeriesMetadata.cs b/API/Entities/Metadata/SeriesMetadata.cs new file mode 100644 index 000000000..54ea8ccc0 --- /dev/null +++ b/API/Entities/Metadata/SeriesMetadata.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using API.Entities.Enums; +using API.Entities.Interfaces; +using Microsoft.EntityFrameworkCore; + +namespace API.Entities.Metadata +{ + [Index(nameof(Id), nameof(SeriesId), IsUnique = true)] + public class SeriesMetadata : IHasConcurrencyToken + { + public int Id { get; set; } + + public string Summary { get; set; } + + public ICollection CollectionTags { get; set; } + + public ICollection Genres { get; set; } = new List(); + public ICollection Tags { get; set; } = new List(); + /// + /// All people attached at a Series level. + /// + public ICollection People { get; set; } = new List(); + + /// + /// Highest Age Rating from all Chapters + /// + public AgeRating AgeRating { get; set; } + /// + /// Earliest Year from all chapters + /// + public int ReleaseYear { get; set; } + /// + /// Language of the content (BCP-47 code) + /// + public string Language { get; set; } = string.Empty; + /// + /// Total number of issues in the series + /// + public int Count { get; set; } = 0; + public PublicationStatus PublicationStatus { get; set; } + + // Relationship + public Series Series { get; set; } + public int SeriesId { get; set; } + + /// + [ConcurrencyCheck] + public uint RowVersion { get; private set; } + + /// + public void OnSavingChanges() + { + RowVersion++; + } + } +} diff --git a/API/Entities/Person.cs b/API/Entities/Person.cs index c9f182215..785a037bd 100644 --- a/API/Entities/Person.cs +++ b/API/Entities/Person.cs @@ -1,23 +1,24 @@ -using System.ComponentModel.DataAnnotations; +using System.Collections.Generic; using API.Entities.Enums; -using API.Entities.Interfaces; +using API.Entities.Metadata; namespace API.Entities { - public class Person : IHasConcurrencyToken + public enum ProviderSource + { + Local = 1, + External = 2 + } + public class Person { public int Id { get; set; } public string Name { get; set; } + public string NormalizedName { get; set; } public PersonRole Role { get; set; } + //public ProviderSource Source { get; set; } - /// - [ConcurrencyCheck] - public uint RowVersion { get; private set; } - - /// - public void OnSavingChanges() - { - RowVersion++; - } + // Relationships + public ICollection SeriesMetadatas { get; set; } + public ICollection ChapterMetadatas { get; set; } } } diff --git a/API/Entities/Series.cs b/API/Entities/Series.cs index de02ad427..a532028bb 100644 --- a/API/Entities/Series.cs +++ b/API/Entities/Series.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using API.Entities.Enums; using API.Entities.Interfaces; +using API.Entities.Metadata; using Microsoft.EntityFrameworkCore; namespace API.Entities @@ -30,10 +31,6 @@ namespace API.Entities /// Original Name on disk. Not exposed to UI. /// public string OriginalName { get; set; } - /// - /// Summary information related to the Series - /// - public string Summary { get; set; } // NOTE: Migrate into SeriesMetdata (with Metadata update) public DateTime Created { get; set; } public DateTime LastModified { get; set; } /// @@ -56,6 +53,8 @@ namespace API.Entities public MangaFormat Format { get; set; } = MangaFormat.Unknown; public SeriesMetadata Metadata { get; set; } + public ICollection Ratings { get; set; } = new List(); + public ICollection Progress { get; set; } = new List(); // Relationships public List Volumes { get; set; } diff --git a/API/Entities/SeriesMetadata.cs b/API/Entities/SeriesMetadata.cs deleted file mode 100644 index f86c5430e..000000000 --- a/API/Entities/SeriesMetadata.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using API.Entities.Interfaces; -using Microsoft.EntityFrameworkCore; - -namespace API.Entities -{ - [Index(nameof(Id), nameof(SeriesId), IsUnique = true)] - public class SeriesMetadata : IHasConcurrencyToken - { - public int Id { get; set; } - - public ICollection CollectionTags { get; set; } - - // Relationship - public Series Series { get; set; } - public int SeriesId { get; set; } - - /// - [ConcurrencyCheck] - public uint RowVersion { get; private set; } - - /// - public void OnSavingChanges() - { - RowVersion++; - } - } -} diff --git a/API/Entities/Tag.cs b/API/Entities/Tag.cs new file mode 100644 index 000000000..5d1631760 --- /dev/null +++ b/API/Entities/Tag.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; +using API.Entities.Metadata; +using Microsoft.EntityFrameworkCore; + +namespace API.Entities; + +[Index(nameof(NormalizedTitle), nameof(ExternalTag), IsUnique = true)] +public class Tag +{ + public int Id { get; set; } + public string Title { get; set; } + public string NormalizedTitle { get; set; } + public bool ExternalTag { get; set; } + + public ICollection SeriesMetadatas { get; set; } + public ICollection Chapters { get; set; } +} diff --git a/API/Extensions/ApplicationServiceExtensions.cs b/API/Extensions/ApplicationServiceExtensions.cs index cd5a621fc..fd0c5f5ca 100644 --- a/API/Extensions/ApplicationServiceExtensions.cs +++ b/API/Extensions/ApplicationServiceExtensions.cs @@ -1,7 +1,6 @@ -using API.Data; +using System.IO.Abstractions; +using API.Data; using API.Helpers; -using API.Interfaces; -using API.Interfaces.Services; using API.Services; using API.Services.Tasks; using API.SignalR.Presence; @@ -36,8 +35,14 @@ namespace API.Extensions services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); services.AddScoped(); + + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); services.AddSqLite(config, env); @@ -51,6 +56,7 @@ namespace API.Extensions services.AddDbContext(options => { options.UseSqlite(config.GetConnectionString("DefaultConnection")); + options.EnableDetailedErrors(); options.EnableSensitiveDataLogging(env.IsDevelopment() || Configuration.LogLevel.Equals("Debug")); }); } diff --git a/API/Extensions/DateTimeExtensions.cs b/API/Extensions/DateTimeExtensions.cs new file mode 100644 index 000000000..da205608c --- /dev/null +++ b/API/Extensions/DateTimeExtensions.cs @@ -0,0 +1,18 @@ +using System; + +namespace API.Extensions; + +public static class DateTimeExtensions +{ + /// + /// Truncates a DateTime to a specified resolution. + /// A convenient source for resolution is TimeSpan.TicksPerXXXX constants. + /// + /// The DateTime object to truncate + /// e.g. to round to nearest second, TimeSpan.TicksPerSecond + /// Truncated DateTime + public static DateTime Truncate(this DateTime date, long resolution) + { + return new DateTime(date.Ticks - (date.Ticks % resolution), date.Kind); + } +} diff --git a/API/Extensions/DirectoryInfoExtensions.cs b/API/Extensions/DirectoryInfoExtensions.cs deleted file mode 100644 index b92901046..000000000 --- a/API/Extensions/DirectoryInfoExtensions.cs +++ /dev/null @@ -1,86 +0,0 @@ -using System.IO; -using System.Linq; -using API.Comparators; - -namespace API.Extensions -{ - public static class DirectoryInfoExtensions - { - private static readonly NaturalSortComparer Comparer = new NaturalSortComparer(); - public static void Empty(this DirectoryInfo directory) - { - // NOTE: We have this in DirectoryService.Empty(), do we need this here? - foreach(FileInfo file in directory.EnumerateFiles()) file.Delete(); - foreach(DirectoryInfo subDirectory in directory.EnumerateDirectories()) subDirectory.Delete(true); - } - - public static void RemoveNonImages(this DirectoryInfo directory) - { - foreach (var file in directory.EnumerateFiles()) - { - if (!Parser.Parser.IsImage(file.FullName)) - { - file.Delete(); - } - } - } - - /// - /// Flattens all files in subfolders to the passed directory recursively. - /// - /// - /// foo - /// ├── 1.txt - /// ├── 2.txt - /// ├── 3.txt - /// ├── 4.txt - /// └── bar - /// ├── 1.txt - /// ├── 2.txt - /// └── 5.txt - /// - /// becomes: - /// foo - /// ├── 1.txt - /// ├── 2.txt - /// ├── 3.txt - /// ├── 4.txt - /// ├── bar_1.txt - /// ├── bar_2.txt - /// └── bar_5.txt - /// - /// - public static void Flatten(this DirectoryInfo directory) - { - var index = 0; - FlattenDirectory(directory, directory, ref index); - } - - private static void FlattenDirectory(DirectoryInfo root, DirectoryInfo directory, ref int directoryIndex) - { - if (!root.FullName.Equals(directory.FullName)) - { - var fileIndex = 1; - - foreach (var file in directory.EnumerateFiles().OrderBy(file => file.FullName, Comparer)) - { - if (file.Directory == null) continue; - var paddedIndex = Parser.Parser.PadZeros(directoryIndex + ""); - // We need to rename the files so that after flattening, they are in the order we found them - var newName = $"{paddedIndex}_{Parser.Parser.PadZeros(fileIndex + "")}{file.Extension}"; - var newPath = Path.Join(root.FullName, newName); - if (!File.Exists(newPath)) file.MoveTo(newPath); - fileIndex++; - } - - directoryIndex++; - } - - var sort = new NaturalSortComparer(); - foreach (var subDirectory in directory.EnumerateDirectories().OrderBy(d => d.FullName, sort)) - { - FlattenDirectory(root, subDirectory, ref directoryIndex); - } - } - } -} diff --git a/API/Extensions/EnumerableExtensions.cs b/API/Extensions/EnumerableExtensions.cs index b8293436e..c1dd412e2 100644 --- a/API/Extensions/EnumerableExtensions.cs +++ b/API/Extensions/EnumerableExtensions.cs @@ -1,21 +1,30 @@ using System; using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; namespace API.Extensions { public static class EnumerableExtensions { - public static IEnumerable DistinctBy - (this IEnumerable source, Func keySelector) + private static readonly Regex Regex = new Regex(@"\d+", RegexOptions.Compiled, TimeSpan.FromMilliseconds(500)); + + /// + /// A natural sort implementation + /// + /// IEnumerable to process + /// Function that produces a string. Does not support null values + /// Defaults to CurrentCulture + /// + /// Sorted Enumerable + public static IEnumerable OrderByNatural(this IEnumerable items, Func selector, StringComparer stringComparer = null) { - var seenKeys = new HashSet(); - foreach (var element in source) - { - if (seenKeys.Add(keySelector(element))) - { - yield return element; - } - } + var maxDigits = items + .SelectMany(i => Regex.Matches(selector(i)) + .Select(digitChunk => (int?)digitChunk.Value.Length)) + .Max() ?? 0; + + return items.OrderBy(i => Regex.Replace(selector(i), match => match.Value.PadLeft(maxDigits, '0')), stringComparer ?? StringComparer.CurrentCulture); } } -} \ No newline at end of file +} diff --git a/API/Extensions/FilterDtoExtensions.cs b/API/Extensions/FilterDtoExtensions.cs index 7e5a818ec..b0d9f80f6 100644 --- a/API/Extensions/FilterDtoExtensions.cs +++ b/API/Extensions/FilterDtoExtensions.cs @@ -11,15 +11,12 @@ namespace API.Extensions public static IList GetSqlFilter(this FilterDto filter) { - var format = filter.MangaFormat; - if (format != null) + if (filter.Formats == null || filter.Formats.Count == 0) { - return new List() - { - (MangaFormat) format - }; + return AllFormats; } - return AllFormats; + + return filter.Formats; } } } diff --git a/API/Extensions/HttpExtensions.cs b/API/Extensions/HttpExtensions.cs index 975cbde5f..68655f43d 100644 --- a/API/Extensions/HttpExtensions.cs +++ b/API/Extensions/HttpExtensions.cs @@ -1,5 +1,7 @@ using System.IO; using System.Linq; +using System.Runtime.Intrinsics.Arm; +using System.Security.Cryptography; using System.Text; using System.Text.Json; using API.Helpers; @@ -30,7 +32,8 @@ namespace API.Extensions public static void AddCacheHeader(this HttpResponse response, byte[] content) { if (content == null || content.Length <= 0) return; - using var sha1 = new System.Security.Cryptography.SHA256CryptoServiceProvider(); + using var sha1 = SHA256.Create(); + response.Headers.Add("ETag", string.Concat(sha1.ComputeHash(content).Select(x => x.ToString("X2")))); } @@ -43,7 +46,7 @@ namespace API.Extensions { if (filename == null || filename.Length <= 0) return; var hashContent = filename + File.GetLastWriteTimeUtc(filename); - using var sha1 = new System.Security.Cryptography.SHA256CryptoServiceProvider(); + using var sha1 = SHA256.Create(); response.Headers.Add("ETag", string.Concat(sha1.ComputeHash(Encoding.UTF8.GetBytes(hashContent)).Select(x => x.ToString("X2")))); } diff --git a/API/Extensions/IdentityServiceExtensions.cs b/API/Extensions/IdentityServiceExtensions.cs index 9b32c9320..1d0638e67 100644 --- a/API/Extensions/IdentityServiceExtensions.cs +++ b/API/Extensions/IdentityServiceExtensions.cs @@ -17,8 +17,13 @@ namespace API.Extensions { services.AddIdentityCore(opt => { - // Change password / signin requirements here opt.Password.RequireNonAlphanumeric = false; + opt.Password.RequireDigit = false; + opt.Password.RequireDigit = false; + opt.Password.RequireLowercase = false; + opt.Password.RequireUppercase = false; + opt.Password.RequireNonAlphanumeric = false; + opt.Password.RequiredLength = 6; }) .AddRoles() .AddRoleManager>() diff --git a/API/Extensions/ParserInfoListExtensions.cs b/API/Extensions/ParserInfoListExtensions.cs index 0ea098b20..31a65c819 100644 --- a/API/Extensions/ParserInfoListExtensions.cs +++ b/API/Extensions/ParserInfoListExtensions.cs @@ -31,15 +31,15 @@ namespace API.Extensions : infos.Any(v => v.Chapters == chapter.Range); } - /// - /// Returns the MangaFormat that is common to all the files. Unknown if files are mixed (should never happen) or no infos - /// - /// - /// - public static MangaFormat GetFormat(this IList infos) - { - if (infos.Count == 0) return MangaFormat.Unknown; - return infos.DistinctBy(x => x.Format).First().Format; - } + // /// + // /// Returns the MangaFormat that is common to all the files. Unknown if files are mixed (should never happen) or no infos + // /// + // /// + // /// + // public static MangaFormat GetFormat(this IList infos) + // { + // if (infos.Count == 0) return MangaFormat.Unknown; + // return infos.DistinctBy(x => x.Format).First().Format; + // } } } diff --git a/API/Extensions/PathExtensions.cs b/API/Extensions/PathExtensions.cs new file mode 100644 index 000000000..f45787d1a --- /dev/null +++ b/API/Extensions/PathExtensions.cs @@ -0,0 +1,14 @@ +using System.IO; + +namespace API.Extensions; + +public static class PathExtensions +{ + public static string GetFullPathWithoutExtension(this string filepath) + { + if (string.IsNullOrEmpty(filepath)) return filepath; + var extension = Path.GetExtension(filepath); + if (string.IsNullOrEmpty(extension)) return filepath; + return Path.GetFullPath(filepath.Replace(extension, string.Empty)); + } +} diff --git a/API/Extensions/SeriesExtensions.cs b/API/Extensions/SeriesExtensions.cs index 30a7b1b5b..cd3254e34 100644 --- a/API/Extensions/SeriesExtensions.cs +++ b/API/Extensions/SeriesExtensions.cs @@ -9,7 +9,7 @@ namespace API.Extensions public static class SeriesExtensions { /// - /// Checks against all the name variables of the Series if it matches anything in the list. + /// Checks against all the name variables of the Series if it matches anything in the list. This does not check against format. /// /// /// diff --git a/API/Extensions/StringExtensions.cs b/API/Extensions/StringExtensions.cs new file mode 100644 index 000000000..b172c0e46 --- /dev/null +++ b/API/Extensions/StringExtensions.cs @@ -0,0 +1,13 @@ +using System.Text.RegularExpressions; + +namespace API.Extensions; + +public static class StringExtensions +{ + private static readonly Regex SentenceCaseRegex = new Regex(@"(^[a-z])|\.\s+(.)", RegexOptions.ExplicitCapture | RegexOptions.Compiled); + + public static string SentenceCase(this string value) + { + return SentenceCaseRegex.Replace(value.ToLower(), s => s.Value.ToUpper()); + } +} diff --git a/API/Extensions/VolumeListExtensions.cs b/API/Extensions/VolumeListExtensions.cs index 4752cce5b..97126e28f 100644 --- a/API/Extensions/VolumeListExtensions.cs +++ b/API/Extensions/VolumeListExtensions.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Linq; +using API.Comparators; using API.Entities; using API.Entities.Enums; @@ -7,11 +8,12 @@ namespace API.Extensions { public static class VolumeListExtensions { - public static Volume FirstWithChapters(this IList volumes, bool inBookSeries) + public static Volume FirstWithChapters(this IEnumerable volumes, bool inBookSeries) { return inBookSeries ? volumes.FirstOrDefault(v => v.Chapters.Any()) - : volumes.FirstOrDefault(v => v.Chapters.Any() && (v.Number == 1)); + : volumes.OrderBy(v => v.Number, new ChapterSortComparer()) + .FirstOrDefault(v => v.Chapters.Any()); } /// diff --git a/API/Helpers/AutoMapperProfiles.cs b/API/Helpers/AutoMapperProfiles.cs index 74bd8d57c..0b3f89161 100644 --- a/API/Helpers/AutoMapperProfiles.cs +++ b/API/Helpers/AutoMapperProfiles.cs @@ -2,10 +2,13 @@ using System.Linq; using API.DTOs; using API.DTOs.CollectionTags; +using API.DTOs.Metadata; using API.DTOs.Reader; using API.DTOs.ReadingLists; using API.DTOs.Settings; using API.Entities; +using API.Entities.Enums; +using API.Entities.Metadata; using API.Helpers.Converters; using AutoMapper; @@ -21,15 +24,101 @@ namespace API.Helpers CreateMap(); - CreateMap(); + CreateMap() + .ForMember(dest => dest.Writers, + opt => + opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.Writer))) + .ForMember(dest => dest.CoverArtist, + opt => + opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.CoverArtist))) + .ForMember(dest => dest.Colorist, + opt => + opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.Colorist))) + .ForMember(dest => dest.Inker, + opt => + opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.Inker))) + .ForMember(dest => dest.Letterer, + opt => + opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.Letterer))) + .ForMember(dest => dest.Penciller, + opt => + opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.Penciller))) + .ForMember(dest => dest.Publisher, + opt => + opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.Publisher))) + .ForMember(dest => dest.Editor, + opt => + opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.Editor))) + .ForMember(dest => dest.Translators, + opt => + opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.Translator))); CreateMap(); - CreateMap(); - - CreateMap(); - CreateMap(); + CreateMap(); + CreateMap(); + + CreateMap() + .ForMember(dest => dest.Writers, + opt => + opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.Writer))) + .ForMember(dest => dest.CoverArtists, + opt => + opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.CoverArtist))) + .ForMember(dest => dest.Characters, + opt => + opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.Character))) + .ForMember(dest => dest.Publishers, + opt => + opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.Publisher))) + .ForMember(dest => dest.Colorists, + opt => + opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.Colorist))) + .ForMember(dest => dest.Inkers, + opt => + opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.Inker))) + .ForMember(dest => dest.Letterers, + opt => + opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.Letterer))) + .ForMember(dest => dest.Pencillers, + opt => + opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.Penciller))) + .ForMember(dest => dest.Translators, + opt => + opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.Translator))) + .ForMember(dest => dest.Editors, + opt => + opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.Editor))); + + CreateMap() + .ForMember(dest => dest.Writers, + opt => + opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.Writer))) + .ForMember(dest => dest.CoverArtist, + opt => + opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.CoverArtist))) + .ForMember(dest => dest.Colorist, + opt => + opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.Colorist))) + .ForMember(dest => dest.Inker, + opt => + opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.Inker))) + .ForMember(dest => dest.Letterer, + opt => + opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.Letterer))) + .ForMember(dest => dest.Penciller, + opt => + opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.Penciller))) + .ForMember(dest => dest.Publisher, + opt => + opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.Publisher))) + .ForMember(dest => dest.Editor, + opt => + opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.Editor))); + + + CreateMap(); @@ -55,8 +144,10 @@ namespace API.Helpers CreateMap(); + CreateMap, ServerSettingDto>() .ConvertUsing(); + } } } diff --git a/API/Helpers/CacheHelper.cs b/API/Helpers/CacheHelper.cs new file mode 100644 index 000000000..80a63490d --- /dev/null +++ b/API/Helpers/CacheHelper.cs @@ -0,0 +1,73 @@ +using System; +using API.Entities; +using API.Entities.Interfaces; +using API.Services; + +namespace API.Helpers; + +public interface ICacheHelper +{ + bool ShouldUpdateCoverImage(string coverPath, MangaFile firstFile, DateTime chapterCreated, + bool forceUpdate = false, + bool isCoverLocked = false); + + bool CoverImageExists(string path); + + bool HasFileNotChangedSinceCreationOrLastScan(IEntityDate chapter, bool forceUpdate, MangaFile firstFile); + +} + +public class CacheHelper : ICacheHelper +{ + private readonly IFileService _fileService; + + public CacheHelper(IFileService fileService) + { + _fileService = fileService; + } + + /// + /// Determines whether an entity should regenerate cover image. + /// + /// If a cover image is locked but the underlying file has been deleted, this will allow regenerating. + /// This should just be the filename, no path information + /// + /// If the user has told us to force the refresh + /// If cover has been locked by user. This will force false + /// + public bool ShouldUpdateCoverImage(string coverPath, MangaFile firstFile, DateTime chapterCreated, bool forceUpdate = false, + bool isCoverLocked = false) + { + + var fileExists = !string.IsNullOrEmpty(coverPath) && _fileService.Exists(coverPath); + if (isCoverLocked && fileExists) return false; + if (forceUpdate) return true; + if (firstFile == null) return true; + return (_fileService.HasFileBeenModifiedSince(firstFile.FilePath, firstFile.LastModified)) || !fileExists; + } + + /// + /// Has the file been modified since last scan or is user forcing an update + /// + /// + /// + /// + /// + public bool HasFileNotChangedSinceCreationOrLastScan(IEntityDate chapter, bool forceUpdate, MangaFile firstFile) + { + return firstFile != null && + (!forceUpdate && + !(_fileService.HasFileBeenModifiedSince(firstFile.FilePath, chapter.Created) + || _fileService.HasFileBeenModifiedSince(firstFile.FilePath, firstFile.LastModified))); + } + + /// + /// Determines if a given coverImage path exists + /// + /// + /// + public bool CoverImageExists(string path) + { + return !string.IsNullOrEmpty(path) && _fileService.Exists(path); + } +} diff --git a/API/Helpers/Converters/CronConverter.cs b/API/Helpers/Converters/CronConverter.cs index cacf018b1..32df46753 100644 --- a/API/Helpers/Converters/CronConverter.cs +++ b/API/Helpers/Converters/CronConverter.cs @@ -26,16 +26,16 @@ namespace API.Helpers.Converters return destination; } - public static string ConvertFromCronNotation(string cronNotation) - { - var destination = string.Empty; - destination = cronNotation.ToLower() switch - { - "0 0 31 2 *" => "disabled", - _ => destination - }; - - return destination; - } + // public static string ConvertFromCronNotation(string cronNotation) + // { + // var destination = string.Empty; + // destination = cronNotation.ToLower() switch + // { + // "0 0 31 2 *" => "disabled", + // _ => destination + // }; + // + // return destination; + // } } -} \ No newline at end of file +} diff --git a/API/Helpers/Converters/ServerSettingConverter.cs b/API/Helpers/Converters/ServerSettingConverter.cs index 86ed6235e..50a839010 100644 --- a/API/Helpers/Converters/ServerSettingConverter.cs +++ b/API/Helpers/Converters/ServerSettingConverter.cs @@ -42,6 +42,9 @@ namespace API.Helpers.Converters case ServerSettingKey.BaseUrl: destination.BaseUrl = row.Value; break; + case ServerSettingKey.BookmarkDirectory: + destination.BookmarksDirectory = row.Value; + break; } } diff --git a/API/Helpers/GenreHelper.cs b/API/Helpers/GenreHelper.cs new file mode 100644 index 000000000..aa465f58e --- /dev/null +++ b/API/Helpers/GenreHelper.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using API.Data; +using API.Entities; + +namespace API.Helpers; + +public static class GenreHelper +{ + /// + /// + /// + /// + /// + /// + /// + public static void UpdateGenre(ICollection allGenres, IEnumerable names, bool isExternal, Action action) + { + foreach (var name in names) + { + if (string.IsNullOrEmpty(name.Trim())) continue; + + var normalizedName = Parser.Parser.Normalize(name); + var genre = allGenres.FirstOrDefault(p => + p.NormalizedTitle.Equals(normalizedName) && p.ExternalTag == isExternal); + if (genre == null) + { + genre = DbFactory.Genre(name, false); + allGenres.Add(genre); + } + + action(genre); + } + } + + public static void KeepOnlySameGenreBetweenLists(ICollection existingGenres, ICollection removeAllExcept, Action action = null) + { + var existing = existingGenres.ToList(); + foreach (var genre in existing) + { + var existingPerson = removeAllExcept.FirstOrDefault(g => g.ExternalTag == genre.ExternalTag && genre.NormalizedTitle.Equals(g.NormalizedTitle)); + if (existingPerson != null) continue; + existingGenres.Remove(genre); + action?.Invoke(genre); + } + + } + + /// + /// Adds the genre to the list if it's not already in there. This will ignore the ExternalTag. + /// + /// + /// + public static void AddGenreIfNotExists(ICollection metadataGenres, Genre genre) + { + var existingGenre = metadataGenres.FirstOrDefault(p => + p.NormalizedTitle == Parser.Parser.Normalize(genre.Title)); + if (existingGenre == null) + { + metadataGenres.Add(genre); + } + } +} diff --git a/API/Helpers/ParserInfoHelpers.cs b/API/Helpers/ParserInfoHelpers.cs new file mode 100644 index 000000000..48421cd70 --- /dev/null +++ b/API/Helpers/ParserInfoHelpers.cs @@ -0,0 +1,50 @@ +using System.Collections.Generic; +using API.Entities; +using API.Entities.Enums; +using API.Extensions; +using API.Parser; +using API.Services.Tasks.Scanner; + +namespace API.Helpers; + +public static class ParserInfoHelpers +{ + /// + /// Checks each parser info to see if there is a name match and if so, checks if the format matches the Series object. + /// This accounts for if the Series has an Unknown type and if so, considers it matching. + /// + /// + /// + /// + public static bool SeriesHasMatchingParserInfoFormat(Series series, + Dictionary> parsedSeries) + { + var format = MangaFormat.Unknown; + foreach (var pSeries in parsedSeries.Keys) + { + var name = pSeries.Name; + var normalizedName = Parser.Parser.Normalize(name); + + //if (series.NameInParserInfo(pSeries.)) + if (normalizedName == series.NormalizedName || + normalizedName == Parser.Parser.Normalize(series.Name) || + name == series.Name || name == series.LocalizedName || + name == series.OriginalName || + normalizedName == Parser.Parser.Normalize(series.OriginalName)) + { + format = pSeries.Format; + if (format == series.Format) + { + return true; + } + } + } + + if (series.Format == MangaFormat.Unknown && format != MangaFormat.Unknown) + { + return true; + } + + return format == series.Format; + } +} diff --git a/API/Helpers/PersonHelper.cs b/API/Helpers/PersonHelper.cs new file mode 100644 index 000000000..36d544d4d --- /dev/null +++ b/API/Helpers/PersonHelper.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using API.Data; +using API.Entities; +using API.Entities.Enums; + +namespace API.Helpers; + +public static class PersonHelper +{ + /// + /// Given a list of all existing people, this will check the new names and roles and if it doesn't exist in allPeople, will create and + /// add an entry. For each person in name, the callback will be executed. + /// + /// This is used to add new people to a list without worrying about duplicating rows in the DB + /// + /// + /// + /// + public static void UpdatePeople(ICollection allPeople, IEnumerable names, PersonRole role, Action action) + { + var allPeopleTypeRole = allPeople.Where(p => p.Role == role).ToList(); + + foreach (var name in names) + { + var normalizedName = Parser.Parser.Normalize(name); + var person = allPeopleTypeRole.FirstOrDefault(p => + p.NormalizedName.Equals(normalizedName)); + if (person == null) + { + person = DbFactory.Person(name, role); + allPeople.Add(person); + } + + action(person); + } + } + + /// + /// Remove people on a list for a given role + /// + /// Used to remove before we update/add new people + /// Existing people on Entity + /// People from metadata + /// Role to filter on + /// Callback which will be executed for each person removed + public static void RemovePeople(ICollection existingPeople, IEnumerable people, PersonRole role, Action action = null) + { + var normalizedPeople = people.Select(Parser.Parser.Normalize).ToList(); + foreach (var person in normalizedPeople) + { + var existingPerson = existingPeople.FirstOrDefault(p => p.Role == role && person.Equals(p.NormalizedName)); + if (existingPerson == null) continue; + + existingPeople.Remove(existingPerson); + action?.Invoke(existingPerson); + } + + } + + /// + /// Removes all people that are not present in the removeAllExcept list. + /// + /// + /// + /// Callback for all entities that was removed + public static void KeepOnlySamePeopleBetweenLists(ICollection existingPeople, ICollection removeAllExcept, Action action = null) + { + var existing = existingPeople.ToList(); + foreach (var person in existing) + { + var existingPerson = removeAllExcept.FirstOrDefault(p => p.Role == person.Role && person.NormalizedName.Equals(p.NormalizedName)); + if (existingPerson == null) + { + existingPeople.Remove(person); + action?.Invoke(person); + } + } + } + + /// + /// Adds the person to the list if it's not already in there + /// + /// + /// + public static void AddPersonIfNotExists(ICollection metadataPeople, Person person) + { + var existingPerson = metadataPeople.SingleOrDefault(p => + p.NormalizedName == Parser.Parser.Normalize(person.Name) && p.Role == person.Role); + if (existingPerson == null) + { + metadataPeople.Add(person); + } + } +} diff --git a/API/Helpers/SQLHelper.cs b/API/Helpers/SQLHelper.cs index fcd44e7da..d06d246ef 100644 --- a/API/Helpers/SQLHelper.cs +++ b/API/Helpers/SQLHelper.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Data; using System.Data.Common; +using API.DTOs; using Microsoft.EntityFrameworkCore; namespace API.Helpers diff --git a/API/Helpers/SeriesHelper.cs b/API/Helpers/SeriesHelper.cs new file mode 100644 index 000000000..b03ebad18 --- /dev/null +++ b/API/Helpers/SeriesHelper.cs @@ -0,0 +1,46 @@ +using System.Collections.Generic; +using System.Linq; +using API.Entities; +using API.Entities.Enums; +using API.Services.Tasks.Scanner; + +namespace API.Helpers; + +public static class SeriesHelper +{ + /// + /// Given a parsedSeries checks if any of the names match against said Series and the format matches + /// + /// + /// + /// + public static bool FindSeries(Series series, ParsedSeries parsedInfoKey) + { + return (series.NormalizedName.Equals(parsedInfoKey.NormalizedName) + || Parser.Parser.Normalize(series.OriginalName).Equals(parsedInfoKey.NormalizedName) + || Parser.Parser.Normalize(series.LocalizedName).Equals(parsedInfoKey.NormalizedName)) + && (series.Format == parsedInfoKey.Format || series.Format == MangaFormat.Unknown); + } + + /// + /// Removes all instances of missingSeries' Series from existingSeries Collection. Existing series is updated by + /// reference and the removed element count is returned. + /// + /// Existing Series in DB + /// Series not found on disk or can't be parsed + /// + /// the updated existingSeries + public static IEnumerable RemoveMissingSeries(IList existingSeries, IEnumerable missingSeries, out int removeCount) + { + var existingCount = existingSeries.Count; + var missingList = missingSeries.ToList(); + + existingSeries = existingSeries.Where( + s => !missingList.Exists( + m => m.NormalizedName.Equals(s.NormalizedName) && m.Format == s.Format)).ToList(); + + removeCount = existingCount - existingSeries.Count; + + return existingSeries; + } +} diff --git a/API/Helpers/TagHelper.cs b/API/Helpers/TagHelper.cs new file mode 100644 index 000000000..4c230a053 --- /dev/null +++ b/API/Helpers/TagHelper.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using API.Data; +using API.Entities; + +namespace API.Helpers; + +public static class TagHelper +{ + /// + /// + /// + /// + /// + /// + /// Callback for every item. Will give said item back and a bool if item was added + public static void UpdateTag(ICollection allTags, IEnumerable names, bool isExternal, Action action) + { + foreach (var name in names) + { + if (string.IsNullOrEmpty(name.Trim())) continue; + + var added = false; + var normalizedName = Parser.Parser.Normalize(name); + + var genre = allTags.FirstOrDefault(p => + p.NormalizedTitle.Equals(normalizedName) && p.ExternalTag == isExternal); + if (genre == null) + { + added = true; + genre = DbFactory.Tag(name, false); + allTags.Add(genre); + } + + action(genre, added); + } + } + + public static void KeepOnlySameTagBetweenLists(ICollection existingTags, ICollection removeAllExcept, Action action = null) + { + var existing = existingTags.ToList(); + foreach (var genre in existing) + { + var existingPerson = removeAllExcept.FirstOrDefault(g => g.ExternalTag == genre.ExternalTag && genre.NormalizedTitle.Equals(g.NormalizedTitle)); + if (existingPerson != null) continue; + existingTags.Remove(genre); + action?.Invoke(genre); + } + + } + + /// + /// Adds the tag to the list if it's not already in there. This will ignore the ExternalTag. + /// + /// + /// + public static void AddTagIfNotExists(ICollection metadataTags, Tag tag) + { + var existingGenre = metadataTags.FirstOrDefault(p => + p.NormalizedTitle == Parser.Parser.Normalize(tag.Title)); + if (existingGenre == null) + { + metadataTags.Add(tag); + } + } + + /// + /// Remove tags on a list + /// + /// Used to remove before we update/add new tags + /// Existing tags on Entity + /// Tags from metadata + /// Remove external tags? + /// Callback which will be executed for each tag removed + public static void RemoveTags(ICollection existingTags, IEnumerable tags, bool isExternal, Action action = null) + { + var normalizedTags = tags.Select(Parser.Parser.Normalize).ToList(); + foreach (var person in normalizedTags) + { + var existingTag = existingTags.FirstOrDefault(p => p.ExternalTag == isExternal && person.Equals(p.NormalizedTitle)); + if (existingTag == null) continue; + + existingTags.Remove(existingTag); + action?.Invoke(existingTag); + } + + } +} + diff --git a/API/Interfaces/ITaskScheduler.cs b/API/Interfaces/ITaskScheduler.cs deleted file mode 100644 index 215cccf80..000000000 --- a/API/Interfaces/ITaskScheduler.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System.Threading.Tasks; - -namespace API.Interfaces -{ - public interface ITaskScheduler - { - /// - /// For use on Server startup - /// - void ScheduleTasks(); - Task ScheduleStatsTasks(); - void ScheduleUpdaterTasks(); - void ScanLibrary(int libraryId, bool forceUpdate = false); - void CleanupChapters(int[] chapterIds); - void RefreshMetadata(int libraryId, bool forceUpdate = true); - void CleanupTemp(); - void RefreshSeriesMetadata(int libraryId, int seriesId, bool forceUpdate = false); - void ScanSeries(int libraryId, int seriesId, bool forceUpdate = false); - void CancelStatsTasks(); - Task RunStatCollection(); - } -} diff --git a/API/Interfaces/IUnitOfWork.cs b/API/Interfaces/IUnitOfWork.cs deleted file mode 100644 index 733008192..000000000 --- a/API/Interfaces/IUnitOfWork.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System.Threading.Tasks; -using API.Interfaces.Repositories; - -namespace API.Interfaces -{ - public interface IUnitOfWork - { - ISeriesRepository SeriesRepository { get; } - IUserRepository UserRepository { get; } - ILibraryRepository LibraryRepository { get; } - IVolumeRepository VolumeRepository { get; } - ISettingsRepository SettingsRepository { get; } - IAppUserProgressRepository AppUserProgressRepository { get; } - ICollectionTagRepository CollectionTagRepository { get; } - IFileRepository FileRepository { get; } - IChapterRepository ChapterRepository { get; } - IReadingListRepository ReadingListRepository { get; } - ISeriesMetadataRepository SeriesMetadataRepository { get; } - bool Commit(); - Task CommitAsync(); - bool HasChanges(); - bool Rollback(); - Task RollbackAsync(); - } -} diff --git a/API/Interfaces/Repositories/IAppUserProgressRepository.cs b/API/Interfaces/Repositories/IAppUserProgressRepository.cs deleted file mode 100644 index d37198fb2..000000000 --- a/API/Interfaces/Repositories/IAppUserProgressRepository.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Threading.Tasks; -using API.Entities; -using API.Entities.Enums; - -namespace API.Interfaces.Repositories -{ - public interface IAppUserProgressRepository - { - void Update(AppUserProgress userProgress); - Task CleanupAbandonedChapters(); - Task UserHasProgress(LibraryType libraryType, int userId); - Task GetUserProgressAsync(int chapterId, int userId); - } -} diff --git a/API/Interfaces/Repositories/IChapterRepository.cs b/API/Interfaces/Repositories/IChapterRepository.cs deleted file mode 100644 index 9ce145f4c..000000000 --- a/API/Interfaces/Repositories/IChapterRepository.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; -using API.DTOs; -using API.DTOs.Reader; -using API.Entities; - -namespace API.Interfaces.Repositories -{ - public interface IChapterRepository - { - void Update(Chapter chapter); - Task> GetChaptersByIdsAsync(IList chapterIds); - Task GetChapterInfoDtoAsync(int chapterId); - Task GetChapterTotalPagesAsync(int chapterId); - Task GetChapterAsync(int chapterId); - Task GetChapterDtoAsync(int chapterId); - Task> GetFilesForChapterAsync(int chapterId); - Task> GetChaptersAsync(int volumeId); - Task> GetFilesForChaptersAsync(IReadOnlyList chapterIds); - Task GetChapterCoverImageAsync(int chapterId); - Task> GetAllCoverImagesAsync(); - Task> GetCoverImagesForLockedChaptersAsync(); - } -} diff --git a/API/Interfaces/Repositories/ICollectionTagRepository.cs b/API/Interfaces/Repositories/ICollectionTagRepository.cs deleted file mode 100644 index 18c9f490b..000000000 --- a/API/Interfaces/Repositories/ICollectionTagRepository.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; -using API.DTOs; -using API.DTOs.CollectionTags; -using API.Entities; - -namespace API.Interfaces.Repositories -{ - public interface ICollectionTagRepository - { - void Add(CollectionTag tag); - void Remove(CollectionTag tag); - Task> GetAllTagDtosAsync(); - Task> SearchTagDtosAsync(string searchQuery); - Task GetCoverImageAsync(int collectionTagId); - Task> GetAllPromotedTagDtosAsync(); - Task GetTagAsync(int tagId); - Task GetFullTagAsync(int tagId); - void Update(CollectionTag tag); - Task RemoveTagsWithoutSeries(); - Task> GetAllTagsAsync(); - Task> GetAllCoverImagesAsync(); - } -} diff --git a/API/Interfaces/Repositories/IFileRepository.cs b/API/Interfaces/Repositories/IFileRepository.cs deleted file mode 100644 index a852032d7..000000000 --- a/API/Interfaces/Repositories/IFileRepository.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; - -namespace API.Interfaces.Repositories -{ - public interface IFileRepository - { - Task> GetFileExtensions(); - } -} diff --git a/API/Interfaces/Repositories/ILibraryRepository.cs b/API/Interfaces/Repositories/ILibraryRepository.cs deleted file mode 100644 index 1ba6ac910..000000000 --- a/API/Interfaces/Repositories/ILibraryRepository.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; -using API.Data.Repositories; -using API.DTOs; -using API.Entities; -using API.Entities.Enums; - -namespace API.Interfaces.Repositories -{ - public interface ILibraryRepository - { - void Add(Library library); - void Update(Library library); - void Delete(Library library); - Task> GetLibraryDtosAsync(); - Task LibraryExists(string libraryName); - Task GetLibraryForIdAsync(int libraryId, LibraryIncludes includes); - Task GetFullLibraryForIdAsync(int libraryId); - Task GetFullLibraryForIdAsync(int libraryId, int seriesId); - Task> GetLibraryDtosForUsernameAsync(string userName); - Task> GetLibrariesAsync(); - Task DeleteLibrary(int libraryId); - Task> GetLibrariesForUserIdAsync(int userId); - Task GetLibraryTypeAsync(int libraryId); - } -} diff --git a/API/Interfaces/Repositories/IReadingListRepository.cs b/API/Interfaces/Repositories/IReadingListRepository.cs deleted file mode 100644 index 8b5ab085d..000000000 --- a/API/Interfaces/Repositories/IReadingListRepository.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; -using API.DTOs.ReadingLists; -using API.Entities; -using API.Helpers; - -namespace API.Interfaces.Repositories -{ - public interface IReadingListRepository - { - Task> GetReadingListDtosForUserAsync(int userId, bool includePromoted, UserParams userParams); - Task GetReadingListByIdAsync(int readingListId); - Task> GetReadingListItemDtosByIdAsync(int readingListId, int userId); - Task GetReadingListDtoByIdAsync(int readingListId, int userId); - Task> AddReadingProgressModifiers(int userId, IList items); - Task GetReadingListDtoByTitleAsync(string title); - Task> GetReadingListItemsByIdAsync(int readingListId); - void Remove(ReadingListItem item); - void BulkRemove(IEnumerable items); - void Update(ReadingList list); - } -} diff --git a/API/Interfaces/Repositories/ISeriesMetadataRepository.cs b/API/Interfaces/Repositories/ISeriesMetadataRepository.cs deleted file mode 100644 index 00dd234ee..000000000 --- a/API/Interfaces/Repositories/ISeriesMetadataRepository.cs +++ /dev/null @@ -1,9 +0,0 @@ -using API.Entities; - -namespace API.Interfaces.Repositories -{ - public interface ISeriesMetadataRepository - { - void Update(SeriesMetadata seriesMetadata); - } -} diff --git a/API/Interfaces/Repositories/ISeriesRepository.cs b/API/Interfaces/Repositories/ISeriesRepository.cs deleted file mode 100644 index 4c8b2e74e..000000000 --- a/API/Interfaces/Repositories/ISeriesRepository.cs +++ /dev/null @@ -1,62 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; -using API.Data.Scanner; -using API.DTOs; -using API.DTOs.Filtering; -using API.Entities; -using API.Entities.Enums; -using API.Helpers; - -namespace API.Interfaces.Repositories -{ - public interface ISeriesRepository - { - void Attach(Series series); - void Update(Series series); - void Remove(Series series); - void Remove(IEnumerable series); - Task DoesSeriesNameExistInLibrary(string name, MangaFormat format); - /// - /// Adds user information like progress, ratings, etc - /// - /// - /// - /// - /// - Task> GetSeriesDtoForLibraryIdAsync(int libraryId, int userId, UserParams userParams, FilterDto filter); - /// - /// Does not add user information like progress, ratings, etc. - /// - /// - /// Series name to search for - /// - Task> SearchSeries(int[] libraryIds, string searchQuery); - Task> GetSeriesForLibraryIdAsync(int libraryId); - Task GetSeriesDtoByIdAsync(int seriesId, int userId); - Task DeleteSeriesAsync(int seriesId); - Task GetSeriesByIdAsync(int seriesId); - Task> GetSeriesByIdsAsync(IList seriesIds); - Task GetChapterIdsForSeriesAsync(int[] seriesIds); - Task>> GetChapterIdWithSeriesIdForSeriesAsync(int[] seriesIds); - /// - /// Used to add Progress/Rating information to series list. - /// - /// - /// - /// - Task AddSeriesModifiers(int userId, List series); - Task GetSeriesCoverImageAsync(int seriesId); - Task> GetOnDeck(int userId, int libraryId, UserParams userParams, FilterDto filter); - Task> GetRecentlyAdded(int libraryId, int userId, UserParams userParams, FilterDto filter); // NOTE: Probably put this in LibraryRepo - Task GetSeriesMetadata(int seriesId); - Task> GetSeriesDtoForCollectionAsync(int collectionId, int userId, UserParams userParams); - Task> GetFilesForSeries(int seriesId); - Task> GetSeriesDtoForIdsAsync(IEnumerable seriesIds, int userId); - Task> GetAllCoverImagesAsync(); - Task> GetLockedCoverImagesAsync(); - Task> GetFullSeriesForLibraryIdAsync(int libraryId, UserParams userParams); - Task GetFullSeriesForSeriesIdAsync(int seriesId); - Task GetChunkInfo(int libraryId = 0); - Task> GetSeriesMetadataForIdsAsync(IEnumerable seriesIds); - } -} diff --git a/API/Interfaces/Repositories/ISettingsRepository.cs b/API/Interfaces/Repositories/ISettingsRepository.cs deleted file mode 100644 index 95178ea79..000000000 --- a/API/Interfaces/Repositories/ISettingsRepository.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; -using API.DTOs.Settings; -using API.Entities; -using API.Entities.Enums; - -namespace API.Interfaces.Repositories -{ - public interface ISettingsRepository - { - void Update(ServerSetting settings); - Task GetSettingsDtoAsync(); - Task GetSettingAsync(ServerSettingKey key); - Task> GetSettingsAsync(); - - } -} diff --git a/API/Interfaces/Repositories/IUserRepository.cs b/API/Interfaces/Repositories/IUserRepository.cs deleted file mode 100644 index 65d943623..000000000 --- a/API/Interfaces/Repositories/IUserRepository.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; -using API.Data.Repositories; -using API.DTOs; -using API.DTOs.Reader; -using API.Entities; - -namespace API.Interfaces.Repositories -{ - public interface IUserRepository - { - void Update(AppUser user); - void Update(AppUserPreferences preferences); - void Update(AppUserBookmark bookmark); - public void Delete(AppUser user); - Task> GetMembersAsync(); - Task> GetAdminUsersAsync(); - Task> GetNonAdminUsersAsync(); - Task IsUserAdmin(AppUser user); - Task GetUserRating(int seriesId, int userId); - Task GetPreferencesAsync(string username); - Task> GetBookmarkDtosForSeries(int userId, int seriesId); - Task> GetBookmarkDtosForVolume(int userId, int volumeId); - Task> GetBookmarkDtosForChapter(int userId, int chapterId); - Task> GetAllBookmarkDtos(int userId); - Task GetBookmarkForPage(int page, int chapterId, int userId); - Task GetUserIdByApiKeyAsync(string apiKey); - Task GetUserByUsernameAsync(string username, AppUserIncludes includeFlags = AppUserIncludes.None); - Task GetUserByIdAsync(int userId, AppUserIncludes includeFlags = AppUserIncludes.None); - Task GetUserIdByUsernameAsync(string username); - Task GetUserWithReadingListsByUsernameAsync(string username); - } -} diff --git a/API/Interfaces/Repositories/IVolumeRepository.cs b/API/Interfaces/Repositories/IVolumeRepository.cs deleted file mode 100644 index 63045a38d..000000000 --- a/API/Interfaces/Repositories/IVolumeRepository.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; -using API.DTOs; -using API.Entities; - -namespace API.Interfaces.Repositories -{ - public interface IVolumeRepository - { - void Add(Volume volume); - void Update(Volume volume); - void Remove(Volume volume); - Task> GetFilesForVolume(int volumeId); - Task GetVolumeCoverImageAsync(int volumeId); - Task> GetChapterIdsByVolumeIds(IReadOnlyList volumeIds); - - // From Series Repo - Task> GetVolumesDtoAsync(int seriesId, int userId); - Task GetVolumeAsync(int volumeId); - Task GetVolumeDtoAsync(int volumeId, int userId); - Task> GetVolumesForSeriesAsync(IList seriesIds, bool includeChapters = false); - Task> GetVolumes(int seriesId); - Task GetVolumeByIdAsync(int volumeId); - } -} diff --git a/API/Interfaces/Services/IAccountService.cs b/API/Interfaces/Services/IAccountService.cs deleted file mode 100644 index e07ce2f79..000000000 --- a/API/Interfaces/Services/IAccountService.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; -using API.Entities; -using API.Errors; - -namespace API.Interfaces.Services -{ - public interface IAccountService - { - Task> ChangeUserPassword(AppUser user, string newPassword); - } -} diff --git a/API/Interfaces/Services/IArchiveService.cs b/API/Interfaces/Services/IArchiveService.cs deleted file mode 100644 index f2567341a..000000000 --- a/API/Interfaces/Services/IArchiveService.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO.Compression; -using System.Threading.Tasks; -using API.Archive; -using API.Data.Metadata; - -namespace API.Interfaces.Services -{ - public interface IArchiveService - { - void ExtractArchive(string archivePath, string extractPath); - int GetNumberOfPagesFromArchive(string archivePath); - string GetCoverImage(string archivePath, string fileName); - bool IsValidArchive(string archivePath); - ComicInfo GetComicInfo(string archivePath); - ArchiveLibrary CanOpen(string archivePath); - bool ArchiveNeedsFlattening(ZipArchive archive); - Task> CreateZipForDownload(IEnumerable files, string tempFolder); - } -} diff --git a/API/Interfaces/Services/IBackupService.cs b/API/Interfaces/Services/IBackupService.cs deleted file mode 100644 index 315b852f0..000000000 --- a/API/Interfaces/Services/IBackupService.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; -using Microsoft.Extensions.Configuration; - -namespace API.Interfaces.Services -{ - public interface IBackupService - { - Task BackupDatabase(); - /// - /// Returns a list of full paths of the logs files detailed in . - /// - /// - /// - /// - IEnumerable LogFiles(int maxRollingFiles, string logFileName); - - void CleanupBackups(); - } -} \ No newline at end of file diff --git a/API/Interfaces/Services/IBookService.cs b/API/Interfaces/Services/IBookService.cs deleted file mode 100644 index e78669755..000000000 --- a/API/Interfaces/Services/IBookService.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; -using API.Data.Metadata; -using API.Parser; -using VersOne.Epub; - -namespace API.Interfaces.Services -{ - public interface IBookService - { - int GetNumberOfPages(string filePath); - string GetCoverImage(string fileFilePath, string fileName); - Task> CreateKeyToPageMappingAsync(EpubBookRef book); - - /// - /// Scopes styles to .reading-section and replaces img src to the passed apiBase - /// - /// - /// - /// If the stylesheetHtml contains Import statements, when scoping the filename, scope needs to be wrt filepath. - /// Book Reference, needed for if you expect Import statements - /// - Task ScopeStyles(string stylesheetHtml, string apiBase, string filename, EpubBookRef book); - ComicInfo GetComicInfo(string filePath); - ParserInfo ParseInfo(string filePath); - /// - /// Extracts a PDF file's pages as images to an target directory - /// - /// - /// Where the files will be extracted to. If doesn't exist, will be created. - void ExtractPdfImages(string fileFilePath, string targetDirectory); - } -} diff --git a/API/Interfaces/Services/ICacheService.cs b/API/Interfaces/Services/ICacheService.cs deleted file mode 100644 index 395898dc2..000000000 --- a/API/Interfaces/Services/ICacheService.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; -using API.Entities; - -namespace API.Interfaces.Services -{ - public interface ICacheService - { - /// - /// Ensures the cache is created for the given chapter and if not, will create it. Should be called before any other - /// cache operations (except cleanup). - /// - /// - /// Chapter for the passed chapterId. Side-effect from ensuring cache. - Task Ensure(int chapterId); - - /// - /// Clears cache directory of all folders and files. - /// - void Cleanup(); - - /// - /// Clears cache directory of all volumes. This can be invoked from deleting a library or a series. - /// - /// Volumes that belong to that library. Assume the library might have been deleted before this invocation. - void CleanupChapters(IEnumerable chapterIds); - - - /// - /// Returns the absolute path of a cached page. - /// - /// Chapter entity with Files populated. - /// Page number to look for - /// - Task<(string path, MangaFile file)> GetCachedPagePath(Chapter chapter, int page); - - void EnsureCacheDirectory(); - string GetCachedEpubFile(int chapterId, Chapter chapter); - public void ExtractChapterFiles(string extractPath, IReadOnlyList files); - } -} diff --git a/API/Interfaces/Services/ICleanupService.cs b/API/Interfaces/Services/ICleanupService.cs deleted file mode 100644 index afabb9900..000000000 --- a/API/Interfaces/Services/ICleanupService.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Threading.Tasks; - -namespace API.Interfaces.Services -{ - public interface ICleanupService - { - Task Cleanup(); - void CleanupCacheDirectory(); - } -} diff --git a/API/Interfaces/Services/IDirectoryService.cs b/API/Interfaces/Services/IDirectoryService.cs deleted file mode 100644 index a8ae8c05f..000000000 --- a/API/Interfaces/Services/IDirectoryService.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.Collections.Generic; -using System.IO; -using System.Threading.Tasks; - -namespace API.Interfaces.Services -{ - public interface IDirectoryService - { - /// - /// Lists out top-level folders for a given directory. Filters out System and Hidden folders. - /// - /// Absolute path of directory to scan. - /// List of folder names - IEnumerable ListDirectory(string rootPath); - Task ReadFileAsync(string path); - bool CopyFilesToDirectory(IEnumerable filePaths, string directoryPath, string prepend = ""); - bool Exists(string directory); - void CopyFileToDirectory(string fullFilePath, string targetDirectory); - } -} diff --git a/API/Interfaces/Services/IImageService.cs b/API/Interfaces/Services/IImageService.cs deleted file mode 100644 index 0aba07f39..000000000 --- a/API/Interfaces/Services/IImageService.cs +++ /dev/null @@ -1,23 +0,0 @@ -using API.Entities; -using API.Services; - -namespace API.Interfaces.Services -{ - public interface IImageService - { - string GetCoverImage(string path, string fileName); - string GetCoverFile(MangaFile file); - /// - /// Creates a Thumbnail version of an image - /// - /// Path to the image file - /// File name with extension of the file. This will always write to - public string CreateThumbnail(string path, string fileName); - /// - /// Creates a Thumbnail version of a base64 image - /// - /// base64 encoded image - /// File name with extension of the file. This will always write to - public string CreateThumbnailFromBase64(string encodedImage, string fileName); - } -} diff --git a/API/Interfaces/Services/IMetadataService.cs b/API/Interfaces/Services/IMetadataService.cs deleted file mode 100644 index 6d4d725cf..000000000 --- a/API/Interfaces/Services/IMetadataService.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System.Threading.Tasks; -using API.Entities; - -namespace API.Interfaces.Services -{ - public interface IMetadataService - { - /// - /// Recalculates metadata for all entities in a library. - /// - /// - /// - Task RefreshMetadata(int libraryId, bool forceUpdate = false); - - public bool UpdateMetadata(Chapter chapter, bool forceUpdate); - public bool UpdateMetadata(Volume volume, bool forceUpdate); - public bool UpdateMetadata(Series series, bool forceUpdate); - /// - /// Performs a forced refresh of metatdata just for a series and it's nested entities - /// - /// - /// - Task RefreshMetadataForSeries(int libraryId, int seriesId, bool forceUpdate = false); - } -} diff --git a/API/Interfaces/Services/IReaderService.cs b/API/Interfaces/Services/IReaderService.cs deleted file mode 100644 index a72b90699..000000000 --- a/API/Interfaces/Services/IReaderService.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; -using API.DTOs; -using API.Entities; - -namespace API.Interfaces.Services -{ - public interface IReaderService - { - void MarkChaptersAsRead(AppUser user, int seriesId, IEnumerable chapters); - void MarkChaptersAsUnread(AppUser user, int seriesId, IEnumerable chapters); - Task SaveReadingProgress(ProgressDto progressDto, int userId); - Task CapPageToChapter(int chapterId, int page); - Task GetNextChapterIdAsync(int seriesId, int volumeId, int currentChapterId, int userId); - Task GetPrevChapterIdAsync(int seriesId, int volumeId, int currentChapterId, int userId); - } -} diff --git a/API/Interfaces/Services/IScannerService.cs b/API/Interfaces/Services/IScannerService.cs deleted file mode 100644 index bab0ca588..000000000 --- a/API/Interfaces/Services/IScannerService.cs +++ /dev/null @@ -1,18 +0,0 @@ - -using System.Threading; -using System.Threading.Tasks; - -namespace API.Interfaces.Services -{ - public interface IScannerService - { - /// - /// Given a library id, scans folders for said library. Parses files and generates DB updates. Will overwrite - /// cover images if forceUpdate is true. - /// - /// Library to scan against - Task ScanLibrary(int libraryId); - Task ScanLibraries(); - Task ScanSeries(int libraryId, int seriesId, CancellationToken token); - } -} diff --git a/API/Interfaces/Services/IStartupTask.cs b/API/Interfaces/Services/IStartupTask.cs deleted file mode 100644 index e2a99ecad..000000000 --- a/API/Interfaces/Services/IStartupTask.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Threading; -using System.Threading.Tasks; - -namespace API.Interfaces.Services -{ - public interface IStartupTask - { - Task ExecuteAsync(CancellationToken cancellationToken = default); - } -} \ No newline at end of file diff --git a/API/Interfaces/Services/IStatsService.cs b/API/Interfaces/Services/IStatsService.cs deleted file mode 100644 index 685c3057d..000000000 --- a/API/Interfaces/Services/IStatsService.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Threading.Tasks; -using API.DTOs.Stats; - -namespace API.Interfaces.Services -{ - public interface IStatsService - { - Task Send(); - Task GetServerInfo(); - } -} diff --git a/API/Interfaces/Services/ITokenService.cs b/API/Interfaces/Services/ITokenService.cs deleted file mode 100644 index 14765f2f0..000000000 --- a/API/Interfaces/Services/ITokenService.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Threading.Tasks; -using API.Entities; - -namespace API.Interfaces.Services -{ - public interface ITokenService - { - Task CreateToken(AppUser user); - } -} \ No newline at end of file diff --git a/API/Interfaces/Services/IVersionUpdaterService.cs b/API/Interfaces/Services/IVersionUpdaterService.cs deleted file mode 100644 index ddde09960..000000000 --- a/API/Interfaces/Services/IVersionUpdaterService.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; -using API.DTOs.Update; - -namespace API.Interfaces.Services -{ - public interface IVersionUpdaterService - { - Task CheckForUpdate(); - Task PushUpdate(UpdateNotificationDto update); - Task> GetAllReleases(); - } -} diff --git a/API/Interfaces/Services/ReaderService.cs b/API/Interfaces/Services/ReaderService.cs deleted file mode 100644 index 7eb2e1118..000000000 --- a/API/Interfaces/Services/ReaderService.cs +++ /dev/null @@ -1,310 +0,0 @@ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using API.Comparators; -using API.Data.Repositories; -using API.DTOs; -using API.Entities; -using Microsoft.Extensions.Logging; - -namespace API.Interfaces.Services -{ - public class ReaderService : IReaderService - { - private readonly IUnitOfWork _unitOfWork; - private readonly ILogger _logger; - private readonly ChapterSortComparer _chapterSortComparer = new ChapterSortComparer(); - private readonly ChapterSortComparerZeroFirst _chapterSortComparerForInChapterSorting = new ChapterSortComparerZeroFirst(); - - public ReaderService(IUnitOfWork unitOfWork, ILogger logger) - { - _unitOfWork = unitOfWork; - _logger = logger; - } - - /// - /// Marks all Chapters as Read by creating or updating UserProgress rows. Does not commit. - /// - /// - /// - /// - public void MarkChaptersAsRead(AppUser user, int seriesId, IEnumerable chapters) - { - foreach (var chapter in chapters) - { - var userProgress = GetUserProgressForChapter(user, chapter); - - if (userProgress == null) - { - user.Progresses.Add(new AppUserProgress - { - PagesRead = chapter.Pages, - VolumeId = chapter.VolumeId, - SeriesId = seriesId, - ChapterId = chapter.Id - }); - } - else - { - userProgress.PagesRead = chapter.Pages; - userProgress.SeriesId = seriesId; - userProgress.VolumeId = chapter.VolumeId; - } - } - } - - /// - /// Marks all Chapters as Unread by creating or updating UserProgress rows. Does not commit. - /// - /// - /// - /// - public void MarkChaptersAsUnread(AppUser user, int seriesId, IEnumerable chapters) - { - foreach (var chapter in chapters) - { - var userProgress = GetUserProgressForChapter(user, chapter); - - if (userProgress == null) - { - user.Progresses.Add(new AppUserProgress - { - PagesRead = 0, - VolumeId = chapter.VolumeId, - SeriesId = seriesId, - ChapterId = chapter.Id - }); - } - else - { - userProgress.PagesRead = 0; - userProgress.SeriesId = seriesId; - userProgress.VolumeId = chapter.VolumeId; - } - } - } - - /// - /// Gets the User Progress for a given Chapter. This will handle any duplicates that might have occured in past versions and will delete them. Does not commit. - /// - /// - /// - /// - public static AppUserProgress GetUserProgressForChapter(AppUser user, Chapter chapter) - { - AppUserProgress userProgress = null; - try - { - userProgress = - user.Progresses.SingleOrDefault(x => x.ChapterId == chapter.Id && x.AppUserId == user.Id); - } - catch (Exception) - { - // There is a very rare chance that user progress will duplicate current row. If that happens delete one with less pages - var progresses = user.Progresses.Where(x => x.ChapterId == chapter.Id && x.AppUserId == user.Id).ToList(); - if (progresses.Count > 1) - { - user.Progresses = new List() - { - user.Progresses.First() - }; - userProgress = user.Progresses.First(); - } - } - - return userProgress; - } - - /// - /// Saves progress to DB - /// - /// - /// - /// - public async Task SaveReadingProgress(ProgressDto progressDto, int userId) - { - // Don't let user save past total pages. - progressDto.PageNum = await CapPageToChapter(progressDto.ChapterId, progressDto.PageNum); - - try - { - var userProgress = - await _unitOfWork.AppUserProgressRepository.GetUserProgressAsync(progressDto.ChapterId, userId); - - if (userProgress == null) - { - // Create a user object - var userWithProgress = - await _unitOfWork.UserRepository.GetUserByIdAsync(userId, AppUserIncludes.Progress); - userWithProgress.Progresses ??= new List(); - userWithProgress.Progresses.Add(new AppUserProgress - { - PagesRead = progressDto.PageNum, - VolumeId = progressDto.VolumeId, - SeriesId = progressDto.SeriesId, - ChapterId = progressDto.ChapterId, - BookScrollId = progressDto.BookScrollId, - LastModified = DateTime.Now - }); - _unitOfWork.UserRepository.Update(userWithProgress); - } - else - { - userProgress.PagesRead = progressDto.PageNum; - userProgress.SeriesId = progressDto.SeriesId; - userProgress.VolumeId = progressDto.VolumeId; - userProgress.BookScrollId = progressDto.BookScrollId; - userProgress.LastModified = DateTime.Now; - _unitOfWork.AppUserProgressRepository.Update(userProgress); - } - - if (await _unitOfWork.CommitAsync()) - { - return true; - } - } - catch (Exception exception) - { - _logger.LogError(exception, "Could not save progress"); - await _unitOfWork.RollbackAsync(); - } - - return false; - } - - /// - /// Ensures that the page is within 0 and total pages for a chapter. Makes one DB call. - /// - /// - /// - /// - public async Task CapPageToChapter(int chapterId, int page) - { - var totalPages = await _unitOfWork.ChapterRepository.GetChapterTotalPagesAsync(chapterId); - if (page > totalPages) - { - page = totalPages; - } - - if (page < 0) - { - page = 0; - } - - return page; - } - - /// - /// Tries to find the next logical Chapter - /// - /// - /// V1 → V2 → V3 chapter 0 → V3 chapter 10 → SP 01 → SP 02 - /// - /// - /// - /// - /// - /// -1 if nothing can be found - public async Task GetNextChapterIdAsync(int seriesId, int volumeId, int currentChapterId, int userId) - { - var volumes = (await _unitOfWork.VolumeRepository.GetVolumesDtoAsync(seriesId, userId)).ToList(); - var currentVolume = volumes.Single(v => v.Id == volumeId); - var currentChapter = currentVolume.Chapters.Single(c => c.Id == currentChapterId); - - if (currentVolume.Number == 0) - { - // Handle specials by sorting on their Filename aka Range - var chapterId = GetNextChapterId(currentVolume.Chapters.OrderBy(x => x.Range, new NaturalSortComparer()), currentChapter.Number); - if (chapterId > 0) return chapterId; - } - - foreach (var volume in volumes) - { - if (volume.Number == currentVolume.Number && volume.Chapters.Count > 1) - { - // Handle Chapters within current Volume - // In this case, i need 0 first because 0 represents a full volume file. - var chapterId = GetNextChapterId(currentVolume.Chapters.OrderBy(x => double.Parse(x.Number), _chapterSortComparerForInChapterSorting), currentChapter.Number); - if (chapterId > 0) return chapterId; - } - - if (volume.Number != currentVolume.Number + 1) continue; - - // Handle Chapters within next Volume - // ! When selecting the chapter for the next volume, we need to make sure a c0 comes before a c1+ - var chapters = volume.Chapters.OrderBy(x => double.Parse(x.Number), _chapterSortComparer).ToList(); - if (currentChapter.Number.Equals("0") && chapters.Last().Number.Equals("0")) - { - return chapters.Last().Id; - } - - var firstChapter = chapters.FirstOrDefault(); - if (firstChapter == null) return -1; - return firstChapter.Id; - - } - - return -1; - } - /// - /// Tries to find the prev logical Chapter - /// - /// - /// V1 ← V2 ← V3 chapter 0 ← V3 chapter 10 ← SP 01 ← SP 02 - /// - /// - /// - /// - /// - /// -1 if nothing can be found - public async Task GetPrevChapterIdAsync(int seriesId, int volumeId, int currentChapterId, int userId) - { - var volumes = (await _unitOfWork.VolumeRepository.GetVolumesDtoAsync(seriesId, userId)).Reverse().ToList(); - var currentVolume = volumes.Single(v => v.Id == volumeId); - var currentChapter = currentVolume.Chapters.Single(c => c.Id == currentChapterId); - - if (currentVolume.Number == 0) - { - var chapterId = GetNextChapterId(currentVolume.Chapters.OrderBy(x => x.Range, new NaturalSortComparer()).Reverse(), currentChapter.Number); - if (chapterId > 0) return chapterId; - } - - foreach (var volume in volumes) - { - if (volume.Number == currentVolume.Number) - { - var chapterId = GetNextChapterId(currentVolume.Chapters.OrderBy(x => double.Parse(x.Number), _chapterSortComparerForInChapterSorting).Reverse(), currentChapter.Number); - if (chapterId > 0) return chapterId; - } - if (volume.Number == currentVolume.Number - 1) - { - var lastChapter = volume.Chapters - .OrderBy(x => double.Parse(x.Number), _chapterSortComparerForInChapterSorting).LastOrDefault(); - if (lastChapter == null) return -1; - return lastChapter.Id; - } - } - return -1; - } - - private static int GetNextChapterId(IEnumerable chapters, string currentChapterNumber) - { - var next = false; - var chaptersList = chapters.ToList(); - foreach (var chapter in chaptersList) - { - if (next) - { - return chapter.Id; - } - if (currentChapterNumber.Equals(chapter.Number)) next = true; - } - - return -1; - } - - - } -} diff --git a/API/Middleware/ExceptionMiddleware.cs b/API/Middleware/ExceptionMiddleware.cs index 8badfeb96..0712eaea1 100644 --- a/API/Middleware/ExceptionMiddleware.cs +++ b/API/Middleware/ExceptionMiddleware.cs @@ -14,7 +14,7 @@ namespace API.Middleware private readonly RequestDelegate _next; private readonly ILogger _logger; private readonly IHostEnvironment _env; - + public ExceptionMiddleware(RequestDelegate next, ILogger logger, IHostEnvironment env) { @@ -34,14 +34,14 @@ namespace API.Middleware _logger.LogError(ex, "There was an exception"); context.Response.ContentType = "application/json"; context.Response.StatusCode = (int) HttpStatusCode.InternalServerError; - - var response = _env.IsDevelopment() + + var response = _env.IsDevelopment() ? new ApiException(context.Response.StatusCode, ex.Message, ex.StackTrace) - : new ApiException(context.Response.StatusCode, "Internal Server Error"); - + : new ApiException(context.Response.StatusCode, "Internal Server Error", ex.StackTrace); + var options = new JsonSerializerOptions { - PropertyNamingPolicy = + PropertyNamingPolicy = JsonNamingPolicy.CamelCase }; @@ -52,4 +52,4 @@ namespace API.Middleware } } } -} \ No newline at end of file +} diff --git a/API/Parser/DefaultParser.cs b/API/Parser/DefaultParser.cs new file mode 100644 index 000000000..23b5c1d58 --- /dev/null +++ b/API/Parser/DefaultParser.cs @@ -0,0 +1,160 @@ +using System.IO; +using System.Linq; +using API.Entities.Enums; +using API.Services; + +namespace API.Parser; + +/// +/// This is an implementation of the Parser that is the basis for everything +/// +public class DefaultParser +{ + private readonly IDirectoryService _directoryService; + + public DefaultParser(IDirectoryService directoryService) + { + _directoryService = directoryService; + } + + /// + /// Parses information out of a file path. Will fallback to using directory name if Series couldn't be parsed + /// from filename. + /// + /// + /// Root folder + /// Defaults to Manga. Allows different Regex to be used for parsing. + /// or null if Series was empty + public ParserInfo Parse(string filePath, string rootPath, LibraryType type = LibraryType.Manga) + { + var fileName = _directoryService.FileSystem.Path.GetFileNameWithoutExtension(filePath); + ParserInfo ret; + + if (Parser.IsEpub(filePath)) + { + ret = new ParserInfo() + { + Chapters = Parser.ParseChapter(fileName) ?? Parser.ParseComicChapter(fileName), + Series = Parser.ParseSeries(fileName) ?? Parser.ParseComicSeries(fileName), + Volumes = Parser.ParseVolume(fileName) ?? Parser.ParseComicVolume(fileName), + Filename = Path.GetFileName(filePath), + Format = Parser.ParseFormat(filePath), + FullFilePath = filePath + }; + } + else + { + ret = new ParserInfo() + { + Chapters = type == LibraryType.Manga ? Parser.ParseChapter(fileName) : Parser.ParseComicChapter(fileName), + Series = type == LibraryType.Manga ? Parser.ParseSeries(fileName) : Parser.ParseComicSeries(fileName), + Volumes = type == LibraryType.Manga ? Parser.ParseVolume(fileName) : Parser.ParseComicVolume(fileName), + Filename = Path.GetFileName(filePath), + Format = Parser.ParseFormat(filePath), + Title = Path.GetFileNameWithoutExtension(fileName), + FullFilePath = filePath + }; + } + + if (Parser.IsImage(filePath) && Parser.IsCoverImage(filePath)) return null; + + if (Parser.IsImage(filePath)) + { + // Reset Chapters, Volumes, and Series as images are not good to parse information out of. Better to use folders. + ret.Volumes = Parser.DefaultVolume; + ret.Chapters = Parser.DefaultChapter; + ret.Series = string.Empty; + } + + if (ret.Series == string.Empty || Parser.IsImage(filePath)) + { + // Try to parse information out of each folder all the way to rootPath + ParseFromFallbackFolders(filePath, rootPath, type, ref ret); + } + + var edition = Parser.ParseEdition(fileName); + if (!string.IsNullOrEmpty(edition)) + { + ret.Series = Parser.CleanTitle(ret.Series.Replace(edition, ""), type is LibraryType.Comic); + ret.Edition = edition; + } + + var isSpecial = type == LibraryType.Comic ? Parser.ParseComicSpecial(fileName) : Parser.ParseMangaSpecial(fileName); + // We must ensure that we can only parse a special out. As some files will have v20 c171-180+Omake and that + // could cause a problem as Omake is a special term, but there is valid volume/chapter information. + if (ret.Chapters == Parser.DefaultChapter && ret.Volumes == Parser.DefaultVolume && !string.IsNullOrEmpty(isSpecial)) + { + ret.IsSpecial = true; + ParseFromFallbackFolders(filePath, rootPath, type, ref ret); + } + + // If we are a special with marker, we need to ensure we use the correct series name. we can do this by falling back to Folder name + if (Parser.HasSpecialMarker(fileName)) + { + ret.IsSpecial = true; + ret.Chapters = Parser.DefaultChapter; + ret.Volumes = Parser.DefaultVolume; + + ParseFromFallbackFolders(filePath, rootPath, type, ref ret); + } + + if (string.IsNullOrEmpty(ret.Series)) + { + ret.Series = Parser.CleanTitle(fileName, type is LibraryType.Comic); + } + + // Pdfs may have .pdf in the series name, remove that + if (Parser.IsPdf(filePath) && ret.Series.ToLower().EndsWith(".pdf")) + { + ret.Series = ret.Series.Substring(0, ret.Series.Length - ".pdf".Length); + } + + return ret.Series == string.Empty ? null : ret; + } + + /// + /// Fills out by trying to parse volume, chapters, and series from folders + /// + /// + /// + /// + /// Expects a non-null ParserInfo which this method will populate + public void ParseFromFallbackFolders(string filePath, string rootPath, LibraryType type, ref ParserInfo ret) + { + var fallbackFolders = _directoryService.GetFoldersTillRoot(rootPath, filePath).ToList(); + for (var i = 0; i < fallbackFolders.Count; i++) + { + var folder = fallbackFolders[i]; + if (!string.IsNullOrEmpty(Parser.ParseMangaSpecial(folder))) continue; + + var parsedVolume = type is LibraryType.Manga ? Parser.ParseVolume(folder) : Parser.ParseComicVolume(folder); + var parsedChapter = type is LibraryType.Manga ? Parser.ParseChapter(folder) : Parser.ParseComicChapter(folder); + + if (!parsedVolume.Equals(Parser.DefaultVolume) || !parsedChapter.Equals(Parser.DefaultChapter)) + { + if ((ret.Volumes.Equals(Parser.DefaultVolume) || string.IsNullOrEmpty(ret.Volumes)) && !parsedVolume.Equals(Parser.DefaultVolume)) + { + ret.Volumes = parsedVolume; + } + if ((ret.Chapters.Equals(Parser.DefaultChapter) || string.IsNullOrEmpty(ret.Chapters)) && !parsedChapter.Equals(Parser.DefaultChapter)) + { + ret.Chapters = parsedChapter; + } + } + + var series = Parser.ParseSeries(folder); + + if ((string.IsNullOrEmpty(series) && i == fallbackFolders.Count - 1)) + { + ret.Series = Parser.CleanTitle(folder, type is LibraryType.Comic); + break; + } + + if (!string.IsNullOrEmpty(series)) + { + ret.Series = series; + break; + } + } + } +} diff --git a/API/Parser/Parser.cs b/API/Parser/Parser.cs index 02dc6894c..c17290c5b 100644 --- a/API/Parser/Parser.cs +++ b/API/Parser/Parser.cs @@ -28,7 +28,8 @@ namespace API.Parser /// Matches against font-family css syntax. Does not match if url import has data: starting, as that is binary data /// /// See here for some examples https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face - public static readonly Regex FontSrcUrlRegex = new Regex(@"(?(src:\s?)?url\((?!data:).(?!data:))" + "(?(?!data:)[^\"']*)" + @"(?.{1}\))", + public static readonly Regex FontSrcUrlRegex = new Regex(@"(?(?:src:\s?)?(?:url|local)\((?!data:)" + "(?:[\"']?)" + @"(?!data:))" + + "(?(?!data:)[^\"']+?)" + "(?[\"']?" + @"\);?)", MatchOptions, RegexTimeout); /// /// https://developer.mozilla.org/en-US/docs/Web/CSS/@import @@ -48,11 +49,13 @@ namespace API.Parser MatchOptions, RegexTimeout); private static readonly Regex ArchiveFileRegex = new Regex(ArchiveFileExtensions, MatchOptions, RegexTimeout); + private static readonly Regex ComicInfoArchiveRegex = new Regex(@"\.cbz|\.cbr|\.cb7|\.cbt", + MatchOptions, RegexTimeout); private static readonly Regex XmlRegex = new Regex(XmlRegexExtensions, MatchOptions, RegexTimeout); private static readonly Regex BookFileRegex = new Regex(BookFileExtensions, MatchOptions, RegexTimeout); - private static readonly Regex CoverImageRegex = new Regex(@"(?.*) (?\d+) (?:\(\d{4}\)) ", + @"(?.*)\s+(?\d+)\s+(?:\(\d{4}\))\s", MatchOptions, RegexTimeout), // Goblin Slayer - Brand New Day 006.5 (2019) (Digital) (danke-Empire) new Regex( @@ -207,7 +210,6 @@ namespace API.Parser new Regex( @"^(?!Vol\.?)(?.*)( |_|-)(?.*)ch\d+-?\d?", @@ -236,9 +238,13 @@ namespace API.Parser private static readonly Regex[] ComicSeriesRegex = new[] { + // Tintin - T22 Vol 714 pour Sydney + new Regex( + @"(?.+?)\s?(\b|_|-)\s?((vol|tome|t)\.?)(?\d+(-\d+)?)", + MatchOptions, RegexTimeout), // Invincible Vol 01 Family matters (2005) (Digital) new Regex( - @"(?.*)(\b|_)(vol\.?)( |_)(?\d+(-\d+)?)", + @"(?.+?)(\b|_)((vol|tome|t)\.?)(\s|_)(?\d+(-\d+)?)", MatchOptions, RegexTimeout), // Batman Beyond 2.0 001 (2013) new Regex( @@ -256,9 +262,9 @@ namespace API.Parser new Regex( @"(?.*(\d{4})?)( |_)(?:\((?\d+) of \d+)", MatchOptions, RegexTimeout), - // Teen Titans v1 001 (1966-02) (digital) (OkC.O.M.P.U.T.O.-Novus) + // Teen Titans v1 001 (1966-02) (digital) (OkC.O.M.P.U.T.O.-Novus), Aldebaran-Antares-t6 new Regex( - @"^(?.+?)(?: |_)v\d+", + @"^(?.+?)(?: |_|-)(v|t)\d+", MatchOptions, RegexTimeout), // Amazing Man Comics chapter 25 new Regex( @@ -306,11 +312,11 @@ namespace API.Parser { // Teen Titans v1 001 (1966-02) (digital) (OkC.O.M.P.U.T.O.-Novus) new Regex( - @"^(?.*)(?: |_)v(?\d+)", + @"^(?.*)(?: |_)(t|v)(?\d+)", MatchOptions, RegexTimeout), // Batgirl Vol.2000 #57 (December, 2004) new Regex( - @"^(?.+?)(?:\s|_)vol\.?\s?(?\d+)", + @"^(?.+?)(?:\s|_)(v|vol|tome|t)\.?(\s|_)?(?\d+)", MatchOptions, RegexTimeout), }; @@ -407,7 +413,7 @@ namespace API.Parser MatchOptions, RegexTimeout), // Hinowa ga CRUSH! 018 (2019) (Digital) (LuCaZ).cbz, Hinowa ga CRUSH! 018.5 (2019) (Digital) (LuCaZ).cbz new Regex( - @"^(?!Vol)(?.+?)(?\d+(?:.\d+|-\d+)?)(?:\s\(\d{4}\))?(\b|_|-)", + @"^(?!Vol)(?.+?)(?\d+(?:\.\d+|-\d+)?)(?:\s\(\d{4}\))?(\b|_|-)", MatchOptions, RegexTimeout), // Tower Of God S01 014 (CBT) (digital).cbz new Regex( @@ -470,7 +476,7 @@ namespace API.Parser { // All Keywords, does not account for checking if contains volume/chapter identification. Parser.Parse() will handle. new Regex( - @"(?Specials?|OneShot|One\-Shot|Omake|Extra( Chapter)?|Art Collection|Side( |_)Stories|Bonus)", + @"(?Specials?|OneShot|One\-Shot|Omake|Extra(?:(\sChapter)?[^\S])|Art Collection|Side( |_)Stories|Bonus)", MatchOptions, RegexTimeout), }; @@ -478,7 +484,15 @@ namespace API.Parser { // All Keywords, does not account for checking if contains volume/chapter identification. Parser.Parse() will handle. new Regex( - @"(?Specials?|OneShot|One\-Shot|Extra( Chapter)?|Book \d.+?|Compendium \d.+?|Omnibus \d.+?|[_\s\-]TPB[_\s\-]|FCBD \d.+?|Absolute \d.+?|Preview \d.+?|Art Collection|Side( |_)Stories|Bonus)", + @"(?Specials?|OneShot|One\-Shot|Extra(?:(\sChapter)?[^\S])|Book \d.+?|Compendium \d.+?|Omnibus \d.+?|[_\s\-]TPB[_\s\-]|FCBD \d.+?|Absolute \d.+?|Preview \d.+?|Art Collection|Side(\s|_)Stories|Bonus|Hors Série|(\W|_|-)HS(\W|_|-)|(\W|_|-)THS(\W|_|-))", + MatchOptions, RegexTimeout), + }; + + private static readonly Regex[] EuropeanComicRegex = + { + // All Keywords, does not account for checking if contains volume/chapter identification. Parser.Parse() will handle. + new Regex( + @"(?Bd(\s|_|-)Fr)", MatchOptions, RegexTimeout), }; @@ -488,147 +502,10 @@ namespace API.Parser MatchOptions, RegexTimeout ); - - /// - /// Parses information out of a file path. Will fallback to using directory name if Series couldn't be parsed - /// from filename. - /// - /// - /// Root folder - /// Defaults to Manga. Allows different Regex to be used for parsing. - /// or null if Series was empty - public static ParserInfo Parse(string filePath, string rootPath, LibraryType type = LibraryType.Manga) - { - var fileName = Path.GetFileNameWithoutExtension(filePath); - ParserInfo ret; - - if (IsEpub(filePath)) - { - ret = new ParserInfo() - { - Chapters = ParseChapter(fileName) ?? ParseComicChapter(fileName), - Series = ParseSeries(fileName) ?? ParseComicSeries(fileName), - Volumes = ParseVolume(fileName) ?? ParseComicVolume(fileName), - Filename = Path.GetFileName(filePath), - Format = ParseFormat(filePath), - FullFilePath = filePath - }; - } - else - { - ret = new ParserInfo() - { - Chapters = type == LibraryType.Manga ? ParseChapter(fileName) : ParseComicChapter(fileName), - Series = type == LibraryType.Manga ? ParseSeries(fileName) : ParseComicSeries(fileName), - Volumes = type == LibraryType.Manga ? ParseVolume(fileName) : ParseComicVolume(fileName), - Filename = Path.GetFileName(filePath), - Format = ParseFormat(filePath), - Title = Path.GetFileNameWithoutExtension(fileName), - FullFilePath = filePath - }; - } - - if (IsImage(filePath) && IsCoverImage(filePath)) return null; - - if (IsImage(filePath)) - { - // Reset Chapters, Volumes, and Series as images are not good to parse information out of. Better to use folders. - ret.Volumes = DefaultVolume; - ret.Chapters = DefaultChapter; - ret.Series = string.Empty; - } - - if (ret.Series == string.Empty || IsImage(filePath)) - { - // Try to parse information out of each folder all the way to rootPath - ParseFromFallbackFolders(filePath, rootPath, type, ref ret); - } - - var edition = ParseEdition(fileName); - if (!string.IsNullOrEmpty(edition)) - { - ret.Series = CleanTitle(ret.Series.Replace(edition, ""), type is LibraryType.Comic); - ret.Edition = edition; - } - - var isSpecial = type == LibraryType.Comic ? ParseComicSpecial(fileName) : ParseMangaSpecial(fileName); - // We must ensure that we can only parse a special out. As some files will have v20 c171-180+Omake and that - // could cause a problem as Omake is a special term, but there is valid volume/chapter information. - if (ret.Chapters == DefaultChapter && ret.Volumes == DefaultVolume && !string.IsNullOrEmpty(isSpecial)) - { - ret.IsSpecial = true; - ParseFromFallbackFolders(filePath, rootPath, type, ref ret); - } - - // If we are a special with marker, we need to ensure we use the correct series name. we can do this by falling back to Folder name - if (HasSpecialMarker(fileName)) - { - ret.IsSpecial = true; - ret.Chapters = DefaultChapter; - ret.Volumes = DefaultVolume; - - ParseFromFallbackFolders(filePath, rootPath, type, ref ret); - } - - if (string.IsNullOrEmpty(ret.Series)) - { - ret.Series = CleanTitle(fileName, type is LibraryType.Comic); - } - - // Pdfs may have .pdf in the series name, remove that - if (IsPdf(filePath) && ret.Series.ToLower().EndsWith(".pdf")) - { - ret.Series = ret.Series.Substring(0, ret.Series.Length - ".pdf".Length); - } - - return ret.Series == string.Empty ? null : ret; - } - - /// - /// - /// - /// - /// - /// - /// Expects a non-null ParserInfo which this method will populate - public static void ParseFromFallbackFolders(string filePath, string rootPath, LibraryType type, ref ParserInfo ret) - { - var fallbackFolders = DirectoryService.GetFoldersTillRoot(rootPath, filePath).ToList(); - for (var i = 0; i < fallbackFolders.Count; i++) - { - var folder = fallbackFolders[i]; - if (!string.IsNullOrEmpty(ParseMangaSpecial(folder))) continue; - - var parsedVolume = type is LibraryType.Manga ? ParseVolume(folder) : ParseComicVolume(folder); - var parsedChapter = type is LibraryType.Manga ? ParseChapter(folder) : ParseComicChapter(folder); - - if (!parsedVolume.Equals(DefaultVolume) || !parsedChapter.Equals(DefaultChapter)) - { - if ((ret.Volumes.Equals(DefaultVolume) || string.IsNullOrEmpty(ret.Volumes)) && !parsedVolume.Equals(DefaultVolume)) - { - ret.Volumes = parsedVolume; - } - if ((ret.Chapters.Equals(DefaultChapter) || string.IsNullOrEmpty(ret.Chapters)) && !parsedChapter.Equals(DefaultChapter)) - { - ret.Chapters = parsedChapter; - } - } - - var series = ParseSeries(folder); - - if ((string.IsNullOrEmpty(series) && i == fallbackFolders.Count - 1)) - { - ret.Series = CleanTitle(folder, type is LibraryType.Comic); - break; - } - - if (!string.IsNullOrEmpty(series)) - { - ret.Series = series; - break; - } - } - } + private static readonly Regex EmptySpaceRegex = new Regex( + @"(?!=.+)(\s{2,})(?!=.+)", + MatchOptions, RegexTimeout + ); public static MangaFormat ParseFormat(string filePath) { @@ -862,7 +739,6 @@ namespace API.Parser } } - // TODO: Since we have loops like this, think about using a method foreach (var regex in MangaEditionRegex) { var matches = regex.Matches(title); @@ -895,6 +771,23 @@ namespace API.Parser return title; } + private static string RemoveEuropeanTags(string title) + { + foreach (var regex in EuropeanComicRegex) + { + var matches = regex.Matches(title); + foreach (Match match in matches) + { + if (match.Success) + { + title = title.Replace(match.Value, string.Empty).Trim(); + } + } + } + + return title; + } + private static string RemoveComicSpecialTags(string title) { foreach (var regex in ComicSpecialRegex) @@ -931,6 +824,16 @@ namespace API.Parser title = isComic ? RemoveComicSpecialTags(title) : RemoveMangaSpecialTags(title); + if (isComic) + { + title = RemoveComicSpecialTags(title); + title = RemoveEuropeanTags(title); + } + else + { + title = RemoveMangaSpecialTags(title); + } + title = title.Replace("_", " ").Trim(); if (title.EndsWith("-") || title.EndsWith(",")) @@ -938,6 +841,13 @@ namespace API.Parser title = title.Substring(0, title.Length - 1); } + if (title.StartsWith("-") || title.StartsWith(",")) + { + title = title.Substring(1); + } + + title = EmptySpaceRegex.Replace(title, " "); + return title.Trim(); } @@ -997,15 +907,18 @@ namespace API.Parser { return ArchiveFileRegex.IsMatch(Path.GetExtension(filePath)); } + public static bool IsComicInfoExtension(string filePath) + { + return ComicInfoArchiveRegex.IsMatch(Path.GetExtension(filePath)); + } public static bool IsBook(string filePath) { return BookFileRegex.IsMatch(Path.GetExtension(filePath)); } - public static bool IsImage(string filePath, bool suppressExtraChecks = false) + public static bool IsImage(string filePath) { - if (filePath.StartsWith(".") || (!suppressExtraChecks && filePath.StartsWith("!"))) return false; - return ImageRegex.IsMatch(Path.GetExtension(filePath)); + return !filePath.StartsWith(".") && ImageRegex.IsMatch(Path.GetExtension(filePath)); } public static bool IsXml(string filePath) @@ -1040,16 +953,17 @@ namespace API.Parser /// /// Tests whether the file is a cover image such that: contains "cover", is named "folder", and is an image /// - /// + /// If the path has "backcover" in it, it will be ignored + /// Filename with extension /// - public static bool IsCoverImage(string name) + public static bool IsCoverImage(string filename) { - return IsImage(name, true) && (CoverImageRegex.IsMatch(name)); + return IsImage(filename) && CoverImageRegex.IsMatch(filename); } public static bool HasBlacklistedFolderInPath(string path) { - return path.Contains("__MACOSX"); + return path.Contains("__MACOSX") || path.StartsWith("@Recently-Snapshot") || path.StartsWith("._"); } @@ -1062,5 +976,28 @@ namespace API.Parser { return Path.GetExtension(filePath).ToLower() == ".pdf"; } + + /// + /// Cleans an author's name + /// + /// If the author is Last, First, this will not reverse + /// + /// + public static string CleanAuthor(string author) + { + if (string.IsNullOrEmpty(author)) return string.Empty; + return author.Trim(); + } + + /// + /// Normalizes the slashes in a path to be + /// + /// /manga/1\1 -> /manga/1/1 + /// + /// + public static string NormalizePath(string path) + { + return path.Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); + } } } diff --git a/API/Parser/ParserInfo.cs b/API/Parser/ParserInfo.cs index a2c4a9c51..cb55bd18e 100644 --- a/API/Parser/ParserInfo.cs +++ b/API/Parser/ParserInfo.cs @@ -1,4 +1,5 @@ -using API.Entities.Enums; +using API.Data.Metadata; +using API.Entities.Enums; namespace API.Parser { @@ -15,7 +16,11 @@ namespace API.Parser /// /// Represents the parsed series from the file or folder /// - public string Series { get; set; } = ""; + public string Series { get; set; } = string.Empty; + /// + /// This can be filled in from ComicInfo.xml/Epub during scanning. Will update the SortName field on + /// + public string SeriesSort { get; set; } = string.Empty; /// /// Represents the parsed volumes from a file. By default, will be 0 which means that nothing could be parsed. /// If Volumes is 0 and Chapters is 0, the file is a special. If Chapters is non-zero, then no volume could be parsed. @@ -43,6 +48,7 @@ namespace API.Parser /// /// This can potentially story things like "Omnibus, Color, Full Contact Edition, Extra, Final, etc" /// + /// Not Used in Database public string Edition { get; set; } = ""; /// @@ -55,16 +61,22 @@ namespace API.Parser /// Manga does not use this field /// public string Title { get; set; } = string.Empty; - + /// /// If the ParserInfo has the IsSpecial tag or both volumes and chapters are default aka 0 /// /// public bool IsSpecialInfo() - { + { return (IsSpecial || (Volumes == "0" && Chapters == "0")); } + /// + /// This will contain any EXTRA comicInfo information parsed from the epub or archive. If there is an archive with comicInfo.xml AND it contains + /// series, volume information, that will override what we parsed. + /// + public ComicInfo ComicInfo { get; set; } + /// /// Merges non empty/null properties from info2 into this entity. /// @@ -80,4 +92,4 @@ namespace API.Parser IsSpecial = IsSpecial || info2.IsSpecial; } } -} \ No newline at end of file +} diff --git a/API/Program.cs b/API/Program.cs index f35bf8bd3..4ed8ce56a 100644 --- a/API/Program.cs +++ b/API/Program.cs @@ -1,12 +1,14 @@ using System; -using System.Collections.Generic; using System.IO; +using System.IO.Abstractions; using System.Linq; using System.Security.Cryptography; using System.Threading.Tasks; using API.Data; using API.Entities; +using API.Entities.Enums; using API.Services; +using API.Services.Tasks; using Kavita.Common; using Kavita.Common.EnvironmentInfo; using Microsoft.AspNetCore.Hosting; @@ -33,7 +35,9 @@ namespace API Console.OutputEncoding = System.Text.Encoding.UTF8; var isDocker = new OsInfo(Array.Empty()).IsDocker; - MigrateConfigFiles.Migrate(isDocker); + + var directoryService = new DirectoryService(null, new FileSystem()); + MigrateConfigFiles.Migrate(isDocker, directoryService); // Before anything, check if JWT has been generated properly or if user still has default if (!Configuration.CheckIfJwtTokenSet() && @@ -41,7 +45,7 @@ namespace API { Console.WriteLine("Generating JWT TokenKey for encrypting user sessions..."); var rBytes = new byte[128]; - using (var crypto = new RNGCryptoServiceProvider()) crypto.GetBytes(rBytes); + RandomNumberGenerator.Create().GetBytes(rBytes); Configuration.JwtToken = Convert.ToBase64String(rBytes).Replace("/", string.Empty); } @@ -52,47 +56,33 @@ namespace API try { + var logger = services.GetRequiredService>(); var context = services.GetRequiredService(); + var pendingMigrations = await context.Database.GetPendingMigrationsAsync(); + if (pendingMigrations.Any()) + { + logger.LogInformation("Performing backup as migrations are needed. Backup will be kavita.db in temp folder"); + directoryService.CopyFileToDirectory(directoryService.FileSystem.Path.Join(directoryService.ConfigDirectory, "kavita.db"), directoryService.TempDirectory); + } + + await context.Database.MigrateAsync(); var roleManager = services.GetRequiredService>(); + await Seed.SeedRoles(roleManager); + await Seed.SeedSettings(context, directoryService); + await Seed.SeedUserApiKeys(context); + + if (isDocker && new FileInfo("data/appsettings.json").Exists) { - var logger = services.GetRequiredService>(); logger.LogCritical("WARNING! Mount point is incorrect, nothing here will persist. Please change your container mount from /kavita/data to /kavita/config"); return; } - - - var requiresCoverImageMigration = !Directory.Exists(DirectoryService.CoverImageDirectory); - try - { - // If this is a new install, tables wont exist yet - if (requiresCoverImageMigration) - { - MigrateCoverImages.ExtractToImages(context); - } - } - catch (Exception) - { - requiresCoverImageMigration = false; - } - - // Apply all migrations on startup - await context.Database.MigrateAsync(); - - if (requiresCoverImageMigration) - { - await MigrateCoverImages.UpdateDatabaseWithImages(context); - } - - await Seed.SeedRoles(roleManager); - await Seed.SeedSettings(context); - await Seed.SeedUserApiKeys(context); } catch (Exception ex) { var logger = services.GetRequiredService>(); - logger.LogError(ex, "An error occurred during migration"); + logger.LogCritical(ex, "An error occurred during migration"); } await host.RunAsync(); diff --git a/API/Services/AccountService.cs b/API/Services/AccountService.cs index 0cc720bb6..0591770ec 100644 --- a/API/Services/AccountService.cs +++ b/API/Services/AccountService.cs @@ -3,12 +3,16 @@ using System.Linq; using System.Threading.Tasks; using API.Entities; using API.Errors; -using API.Interfaces.Services; using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.Logging; namespace API.Services { + public interface IAccountService + { + Task> ChangeUserPassword(AppUser user, string newPassword); + } + public class AccountService : IAccountService { private readonly UserManager _userManager; diff --git a/API/Services/ArchiveService.cs b/API/Services/ArchiveService.cs index 2eb59a9fc..11042ed34 100644 --- a/API/Services/ArchiveService.cs +++ b/API/Services/ArchiveService.cs @@ -10,7 +10,6 @@ using API.Archive; using API.Comparators; using API.Data.Metadata; using API.Extensions; -using API.Interfaces.Services; using API.Services.Tasks; using Kavita.Common; using Microsoft.Extensions.Logging; @@ -19,6 +18,19 @@ using SharpCompress.Common; namespace API.Services { + public interface IArchiveService + { + void ExtractArchive(string archivePath, string extractPath); + int GetNumberOfPagesFromArchive(string archivePath); + string GetCoverImage(string archivePath, string fileName, string outputDirectory); + bool IsValidArchive(string archivePath); + ComicInfo GetComicInfo(string archivePath); + ArchiveLibrary CanOpen(string archivePath); + bool ArchiveNeedsFlattening(ZipArchive archive); + Task> CreateZipForDownload(IEnumerable files, string tempFolder); + string FindCoverImageFilename(string archivePath, IList entryNames); + } + /// /// Responsible for manipulating Archive files. Used by and /// @@ -27,12 +39,14 @@ namespace API.Services { private readonly ILogger _logger; private readonly IDirectoryService _directoryService; + private readonly IImageService _imageService; private const string ComicInfoFilename = "comicinfo"; - public ArchiveService(ILogger logger, IDirectoryService directoryService) + public ArchiveService(ILogger logger, IDirectoryService directoryService, IImageService imageService) { _logger = logger; _directoryService = directoryService; + _imageService = imageService; } /// @@ -42,7 +56,10 @@ namespace API.Services /// public virtual ArchiveLibrary CanOpen(string archivePath) { - if (!(File.Exists(archivePath) && Parser.Parser.IsArchive(archivePath) || Parser.Parser.IsEpub(archivePath))) return ArchiveLibrary.NotSupported; + if (string.IsNullOrEmpty(archivePath) || !(File.Exists(archivePath) && Parser.Parser.IsArchive(archivePath) || Parser.Parser.IsEpub(archivePath))) return ArchiveLibrary.NotSupported; + + var ext = _directoryService.FileSystem.Path.GetExtension(archivePath).ToUpper(); + if (ext.Equals(".CBR") || ext.Equals(".RAR")) return ArchiveLibrary.SharpCompress; try { @@ -108,46 +125,47 @@ namespace API.Services /// /// /// Entry name of match, null if no match - public string FindFolderEntry(IEnumerable entryFullNames) + public static string FindFolderEntry(IEnumerable entryFullNames) { var result = entryFullNames - .FirstOrDefault(x => !Path.EndsInDirectorySeparator(x) && !Parser.Parser.HasBlacklistedFolderInPath(x) - && Parser.Parser.IsCoverImage(x) - && !x.StartsWith(Parser.Parser.MacOsMetadataFileStartsWith)); + .OrderByNatural(Path.GetFileNameWithoutExtension) + .Where(path => !(Path.EndsInDirectorySeparator(path) || Parser.Parser.HasBlacklistedFolderInPath(path) || path.StartsWith(Parser.Parser.MacOsMetadataFileStartsWith))) + .FirstOrDefault(Parser.Parser.IsCoverImage); return string.IsNullOrEmpty(result) ? null : result; } /// - /// Returns first entry that is an image and is not in a blacklisted folder path. Uses for ordering files + /// Returns first entry that is an image and is not in a blacklisted folder path. Uses for ordering files /// /// /// Entry name of match, null if no match - public static string FirstFileEntry(IEnumerable entryFullNames, string archiveName) + public static string? FirstFileEntry(IEnumerable entryFullNames, string archiveName) { // First check if there are any files that are not in a nested folder before just comparing by filename. This is needed // because NaturalSortComparer does not work with paths and doesn't seem 001.jpg as before chapter 1/001.jpg. - var fullNames = entryFullNames.Where(x =>!Parser.Parser.HasBlacklistedFolderInPath(x) - && Parser.Parser.IsImage(x) - && !x.StartsWith(Parser.Parser.MacOsMetadataFileStartsWith)).ToList(); + var fullNames = entryFullNames + .OrderByNatural(c => c.GetFullPathWithoutExtension()) + .Where(path => !(Path.EndsInDirectorySeparator(path) || Parser.Parser.HasBlacklistedFolderInPath(path) || path.StartsWith(Parser.Parser.MacOsMetadataFileStartsWith)) && Parser.Parser.IsImage(path)) + .ToList(); if (fullNames.Count == 0) return null; var nonNestedFile = fullNames.Where(entry => (Path.GetDirectoryName(entry) ?? string.Empty).Equals(archiveName)) - .OrderBy(Path.GetFullPath, new NaturalSortComparer()) + .OrderByNatural(c => c.GetFullPathWithoutExtension()) .FirstOrDefault(); if (!string.IsNullOrEmpty(nonNestedFile)) return nonNestedFile; // Check the first folder and sort within that to see if we can find a file, else fallback to first file with basic sort. // Get first folder, then sort within that - var firstDirectoryFile = fullNames.OrderBy(Path.GetDirectoryName, new NaturalSortComparer()).FirstOrDefault(); + var firstDirectoryFile = fullNames.OrderByNatural(Path.GetDirectoryName).FirstOrDefault(); if (!string.IsNullOrEmpty(firstDirectoryFile)) { var firstDirectory = Path.GetDirectoryName(firstDirectoryFile); if (!string.IsNullOrEmpty(firstDirectory)) { var firstDirectoryResult = fullNames.Where(f => firstDirectory.Equals(Path.GetDirectoryName(f))) - .OrderBy(Path.GetFileName, new NaturalSortComparer()) + .OrderByNatural(Path.GetFileNameWithoutExtension) .FirstOrDefault(); if (!string.IsNullOrEmpty(firstDirectoryResult)) return firstDirectoryResult; @@ -155,7 +173,7 @@ namespace API.Services } var result = fullNames - .OrderBy(Path.GetFileName, new NaturalSortComparer()) + .OrderByNatural(Path.GetFileNameWithoutExtension) .FirstOrDefault(); return string.IsNullOrEmpty(result) ? null : result; @@ -173,7 +191,7 @@ namespace API.Services /// /// File name to use based on context of entity. /// - public string GetCoverImage(string archivePath, string fileName) + public string GetCoverImage(string archivePath, string fileName, string outputDirectory) { if (archivePath == null || !IsValidArchive(archivePath)) return string.Empty; try @@ -184,25 +202,24 @@ namespace API.Services case ArchiveLibrary.Default: { using var archive = ZipFile.OpenRead(archivePath); - var entryNames = archive.Entries.Select(e => e.FullName).ToArray(); + var entryNames = archive.Entries.Select(e => e.FullName).ToList(); - var entryName = FindFolderEntry(entryNames) ?? FirstFileEntry(entryNames, Path.GetFileName(archivePath)); + var entryName = FindCoverImageFilename(archivePath, entryNames); var entry = archive.Entries.Single(e => e.FullName == entryName); - using var stream = entry.Open(); - return CreateThumbnail(archivePath + " - " + entry.FullName, stream, fileName); + using var stream = entry.Open(); + return _imageService.WriteCoverThumbnail(stream, fileName, outputDirectory); } case ArchiveLibrary.SharpCompress: { using var archive = ArchiveFactory.Open(archivePath); var entryNames = archive.Entries.Where(archiveEntry => !archiveEntry.IsDirectory).Select(e => e.Key).ToList(); - var entryName = FindFolderEntry(entryNames) ?? FirstFileEntry(entryNames, Path.GetFileName(archivePath)); + var entryName = FindCoverImageFilename(archivePath, entryNames); var entry = archive.Entries.Single(e => e.Key == entryName); using var stream = entry.OpenEntryStream(); - - return CreateThumbnail(archivePath + " - " + entry.Key, stream, fileName); + return _imageService.WriteCoverThumbnail(stream, fileName, outputDirectory); } case ArchiveLibrary.NotSupported: _logger.LogWarning("[GetCoverImage] This archive cannot be read: {ArchivePath}. Defaulting to no cover image", archivePath); @@ -220,6 +237,18 @@ namespace API.Services return string.Empty; } + /// + /// Given a list of image paths (assume within an archive), find the filename that corresponds to the cover + /// + /// + /// + /// + public string FindCoverImageFilename(string archivePath, IList entryNames) + { + var entryName = FindFolderEntry(entryNames) ?? FirstFileEntry(entryNames, Path.GetFileName(archivePath)); + return entryName; + } + /// /// Given an archive stream, will assess whether directory needs to be flattened so that the extracted archive files are directly /// under extract path and not nested in subfolders. See Flatten method. @@ -235,18 +264,25 @@ namespace API.Services } // TODO: Refactor CreateZipForDownload to return the temp file so we can stream it from temp + /// + /// + /// + /// + /// Temp folder name to use for preparing the files. Will be created and deleted + /// + /// public async Task> CreateZipForDownload(IEnumerable files, string tempFolder) { var dateString = DateTime.Now.ToShortDateString().Replace("/", "_"); - var tempLocation = Path.Join(DirectoryService.TempDirectory, $"{tempFolder}_{dateString}"); - DirectoryService.ExistOrCreate(tempLocation); + var tempLocation = Path.Join(_directoryService.TempDirectory, $"{tempFolder}_{dateString}"); + _directoryService.ExistOrCreate(tempLocation); if (!_directoryService.CopyFilesToDirectory(files, tempLocation)) { throw new KavitaException("Unable to copy files to temp directory archive download."); } - var zipPath = Path.Join(DirectoryService.TempDirectory, $"kavita_{tempFolder}_{dateString}.zip"); + var zipPath = Path.Join(_directoryService.TempDirectory, $"kavita_{tempFolder}_{dateString}.zip"); try { ZipFile.CreateFromDirectory(tempLocation, zipPath); @@ -260,25 +296,12 @@ namespace API.Services var fileBytes = await _directoryService.ReadFileAsync(zipPath); - DirectoryService.ClearAndDeleteDirectory(tempLocation); + _directoryService.ClearAndDeleteDirectory(tempLocation); // NOTE: For sending back just zip, just schedule this to be called after the file is returned or let next temp storage cleanup take care of it (new FileInfo(zipPath)).Delete(); return Tuple.Create(fileBytes, zipPath); } - private string CreateThumbnail(string entryName, Stream stream, string fileName) - { - try - { - return ImageService.WriteCoverThumbnail(stream, fileName); - } - catch (Exception ex) - { - _logger.LogWarning(ex, "[GetCoverImage] There was an error and prevented thumbnail generation on {EntryName}. Defaulting to no cover image", entryName); - } - - return string.Empty; - } /// /// Test if the archive path exists and an archive @@ -322,7 +345,12 @@ namespace API.Services return null; } - public ComicInfo GetComicInfo(string archivePath) + /// + /// This can be null if nothing is found or any errors occur during access + /// + /// + /// + public ComicInfo? GetComicInfo(string archivePath) { if (!IsValidArchive(archivePath)) return null; @@ -336,7 +364,7 @@ namespace API.Services case ArchiveLibrary.Default: { using var archive = ZipFile.OpenRead(archivePath); - var entry = archive.Entries.SingleOrDefault(x => + var entry = archive.Entries.FirstOrDefault(x => !Parser.Parser.HasBlacklistedFolderInPath(x.FullName) && Path.GetFileNameWithoutExtension(x.Name)?.ToLower() == ComicInfoFilename && !Path.GetFileNameWithoutExtension(x.Name) @@ -346,7 +374,9 @@ namespace API.Services { using var stream = entry.Open(); var serializer = new XmlSerializer(typeof(ComicInfo)); - return (ComicInfo) serializer.Deserialize(stream); + var info = (ComicInfo) serializer.Deserialize(stream); + ComicInfo.CleanComicInfo(info); + return info; } break; @@ -354,7 +384,7 @@ namespace API.Services case ArchiveLibrary.SharpCompress: { using var archive = ArchiveFactory.Open(archivePath); - return FindComicInfoXml(archive.Entries.Where(entry => !entry.IsDirectory + var info = FindComicInfoXml(archive.Entries.Where(entry => !entry.IsDirectory && !Parser.Parser .HasBlacklistedFolderInPath( Path.GetDirectoryName( @@ -365,6 +395,9 @@ namespace API.Services .Parser .MacOsMetadataFileStartsWith) && Parser.Parser.IsXml(entry.Key))); + ComicInfo.CleanComicInfo(info); + + return info; } case ArchiveLibrary.NotSupported: _logger.LogWarning("[GetComicInfo] This archive cannot be read: {ArchivePath}", archivePath); @@ -385,9 +418,9 @@ namespace API.Services } - private static void ExtractArchiveEntities(IEnumerable entries, string extractPath) + private void ExtractArchiveEntities(IEnumerable entries, string extractPath) { - DirectoryService.ExistOrCreate(extractPath); + _directoryService.ExistOrCreate(extractPath); foreach (var entry in entries) { entry.WriteToDirectory(extractPath, new ExtractionOptions() @@ -400,7 +433,7 @@ namespace API.Services private void ExtractArchiveEntries(ZipArchive archive, string extractPath) { - // NOTE: In cases where we try to extract, but there are InvalidPathChars, we need to inform the user + // TODO: In cases where we try to extract, but there are InvalidPathChars, we need to inform the user (throw exception, let middleware inform user) var needsFlattening = ArchiveNeedsFlattening(archive); if (!archive.HasFiles() && !needsFlattening) return; @@ -408,7 +441,7 @@ namespace API.Services if (!needsFlattening) return; _logger.LogDebug("Extracted archive is nested in root folder, flattening..."); - new DirectoryInfo(extractPath).Flatten(); + _directoryService.Flatten(extractPath); } /// @@ -447,10 +480,10 @@ namespace API.Services break; } case ArchiveLibrary.NotSupported: - _logger.LogWarning("[ExtractArchive] This archive cannot be read: {ArchivePath}. Defaulting to 0 pages", archivePath); + _logger.LogWarning("[ExtractArchive] This archive cannot be read: {ArchivePath}", archivePath); return; default: - _logger.LogWarning("[ExtractArchive] There was an exception when reading archive stream: {ArchivePath}. Defaulting to 0 pages", archivePath); + _logger.LogWarning("[ExtractArchive] There was an exception when reading archive stream: {ArchivePath}", archivePath); return; } diff --git a/API/Services/BookService.cs b/API/Services/BookService.cs index 137f21dca..871b7dd32 100644 --- a/API/Services/BookService.cs +++ b/API/Services/BookService.cs @@ -1,17 +1,13 @@ using System; using System.Collections.Generic; -using System.Drawing; -using System.Drawing.Imaging; using System.IO; using System.Linq; -using System.Runtime.InteropServices; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; using System.Web; using API.Data.Metadata; using API.Entities.Enums; -using API.Interfaces.Services; using API.Parser; using Docnet.Core; using Docnet.Core.Converters; @@ -21,21 +17,54 @@ using ExCSS; using HtmlAgilityPack; using Microsoft.Extensions.Logging; using Microsoft.IO; +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.PixelFormats; using VersOne.Epub; +using Image = SixLabors.ImageSharp.Image; namespace API.Services { + public interface IBookService + { + int GetNumberOfPages(string filePath); + string GetCoverImage(string fileFilePath, string fileName, string outputDirectory); + Task> CreateKeyToPageMappingAsync(EpubBookRef book); + + /// + /// Scopes styles to .reading-section and replaces img src to the passed apiBase + /// + /// + /// + /// If the stylesheetHtml contains Import statements, when scoping the filename, scope needs to be wrt filepath. + /// Book Reference, needed for if you expect Import statements + /// + Task ScopeStyles(string stylesheetHtml, string apiBase, string filename, EpubBookRef book); + ComicInfo GetComicInfo(string filePath); + ParserInfo ParseInfo(string filePath); + /// + /// Extracts a PDF file's pages as images to an target directory + /// + /// + /// Where the files will be extracted to. If doesn't exist, will be created. + void ExtractPdfImages(string fileFilePath, string targetDirectory); + + Task ScopePage(HtmlDocument doc, EpubBookRef book, string apiBase, HtmlNode body, Dictionary mappings, int page); + } + public class BookService : IBookService { private readonly ILogger _logger; + private readonly IDirectoryService _directoryService; + private readonly IImageService _imageService; private readonly StylesheetParser _cssParser = new (); private static readonly RecyclableMemoryStreamManager StreamManager = new (); private const string CssScopeClass = ".book-content"; - public BookService(ILogger logger) + public BookService(ILogger logger, IDirectoryService directoryService, IImageService imageService) { _logger = logger; - + _directoryService = directoryService; + _imageService = imageService; } private static bool HasClickableHrefPart(HtmlNode anchor) @@ -141,13 +170,10 @@ namespace API.Services } stylesheetHtml = stylesheetHtml.Insert(0, importBuilder.ToString()); - var importMatches = Parser.Parser.CssImportUrlRegex.Matches(stylesheetHtml); - foreach (Match match in importMatches) - { - if (!match.Success) continue; - var importFile = match.Groups["Filename"].Value; - stylesheetHtml = stylesheetHtml.Replace(importFile, apiBase + prepend + importFile); - } + + EscapeCSSImportReferences(ref stylesheetHtml, apiBase, prepend); + + EscapeFontFamilyReferences(ref stylesheetHtml, apiBase, prepend); // Check if there are any background images and rewrite those urls EscapeCssImageReferences(ref stylesheetHtml, apiBase, book); @@ -174,6 +200,26 @@ namespace API.Services return RemoveWhiteSpaceFromStylesheets(stylesheet.ToCss()); } + private static void EscapeCSSImportReferences(ref string stylesheetHtml, string apiBase, string prepend) + { + foreach (Match match in Parser.Parser.CssImportUrlRegex.Matches(stylesheetHtml)) + { + if (!match.Success) continue; + var importFile = match.Groups["Filename"].Value; + stylesheetHtml = stylesheetHtml.Replace(importFile, apiBase + prepend + importFile); + } + } + + private static void EscapeFontFamilyReferences(ref string stylesheetHtml, string apiBase, string prepend) + { + foreach (Match match in Parser.Parser.FontSrcUrlRegex.Matches(stylesheetHtml)) + { + if (!match.Success) continue; + var importFile = match.Groups["Filename"].Value; + stylesheetHtml = stylesheetHtml.Replace(importFile, apiBase + prepend + importFile); + } + } + private static void EscapeCssImageReferences(ref string stylesheetHtml, string apiBase, EpubBookRef book) { var matches = Parser.Parser.CssImageUrlRegex.Matches(stylesheetHtml); @@ -189,6 +235,139 @@ namespace API.Services } } + private static void ScopeImages(HtmlDocument doc, EpubBookRef book, string apiBase) + { + var images = doc.DocumentNode.SelectNodes("//img"); + if (images != null) + { + foreach (var image in images) + { + if (image.Name != "img") continue; + + // Need to do for xlink:href + if (image.Attributes["src"] != null) + { + var imageFile = image.Attributes["src"].Value; + if (!book.Content.Images.ContainsKey(imageFile)) + { + // TODO: Refactor the Key code to a method to allow the hacks to be tested + var correctedKey = book.Content.Images.Keys.SingleOrDefault(s => s.EndsWith(imageFile)); + if (correctedKey != null) + { + imageFile = correctedKey; + } else if (imageFile.StartsWith("..")) + { + // There are cases where the key is defined static like OEBPS/Images/1-4.jpg but reference is ../Images/1-4.jpg + correctedKey = book.Content.Images.Keys.SingleOrDefault(s => s.EndsWith(imageFile.Replace("..", string.Empty))); + if (correctedKey != null) + { + imageFile = correctedKey; + } + } + + + + } + + image.Attributes.Remove("src"); + image.Attributes.Add("src", $"{apiBase}" + imageFile); + } + } + } + + images = doc.DocumentNode.SelectNodes("//image"); + if (images != null) + { + foreach (var image in images) + { + if (image.Name != "image") continue; + + if (image.Attributes["xlink:href"] != null) + { + var imageFile = image.Attributes["xlink:href"].Value; + if (!book.Content.Images.ContainsKey(imageFile)) + { + var correctedKey = book.Content.Images.Keys.SingleOrDefault(s => s.EndsWith(imageFile)); + if (correctedKey != null) + { + imageFile = correctedKey; + } + } + + image.Attributes.Remove("xlink:href"); + image.Attributes.Add("xlink:href", $"{apiBase}" + imageFile); + } + } + } + } + + private static string PrepareFinalHtml(HtmlDocument doc, HtmlNode body) + { + // Check if any classes on the html node (some r2l books do this) and move them to body tag for scoping + var htmlNode = doc.DocumentNode.SelectSingleNode("//html"); + if (htmlNode == null || !htmlNode.Attributes.Contains("class")) return body.InnerHtml; + + var bodyClasses = body.Attributes.Contains("class") ? body.Attributes["class"].Value : string.Empty; + var classes = htmlNode.Attributes["class"].Value + " " + bodyClasses; + body.Attributes.Add("class", $"{classes}"); + // I actually need the body tag itself for the classes, so i will create a div and put the body stuff there. + return $"
    {body.InnerHtml}
    "; + } + + private static void RewriteAnchors(int page, HtmlDocument doc, Dictionary mappings) + { + var anchors = doc.DocumentNode.SelectNodes("//a"); + if (anchors != null) + { + foreach (var anchor in anchors) + { + BookService.UpdateLinks(anchor, mappings, page); + } + } + } + + private async Task InlineStyles(HtmlDocument doc, EpubBookRef book, string apiBase, HtmlNode body) + { + var inlineStyles = doc.DocumentNode.SelectNodes("//style"); + if (inlineStyles != null) + { + foreach (var inlineStyle in inlineStyles) + { + var styleContent = await ScopeStyles(inlineStyle.InnerHtml, apiBase, "", book); + body.PrependChild(HtmlNode.CreateNode($"")); + } + } + + var styleNodes = doc.DocumentNode.SelectNodes("/html/head/link"); + if (styleNodes != null) + { + foreach (var styleLinks in styleNodes) + { + var key = BookService.CleanContentKeys(styleLinks.Attributes["href"].Value); + // Some epubs are malformed the key in content.opf might be: content/resources/filelist_0_0.xml but the actual html links to resources/filelist_0_0.xml + // In this case, we will do a search for the key that ends with + if (!book.Content.Css.ContainsKey(key)) + { + var correctedKey = book.Content.Css.Keys.SingleOrDefault(s => s.EndsWith(key)); + if (correctedKey == null) + { + _logger.LogError("Epub is Malformed, key: {Key} is not matching OPF file", key); + continue; + } + + key = correctedKey; + } + + var styleContent = await ScopeStyles(await book.Content.Css[key].ReadContentAsync(), apiBase, + book.Content.Css[key].FileName, book); + if (styleContent != null) + { + body.PrependChild(HtmlNode.CreateNode($"")); + } + } + } + } + public ComicInfo GetComicInfo(string filePath) { if (!IsValidFile(filePath) || Parser.Parser.IsPdf(filePath)) return null; @@ -202,10 +381,13 @@ namespace API.Services var info = new ComicInfo() { Summary = epubBook.Schema.Package.Metadata.Description, - Writer = string.Join(",", epubBook.Schema.Package.Metadata.Creators), + Writer = string.Join(",", epubBook.Schema.Package.Metadata.Creators.Select(c => Parser.Parser.CleanAuthor(c.Creator))), Publisher = string.Join(",", epubBook.Schema.Package.Metadata.Publishers), Month = !string.IsNullOrEmpty(publicationDate) ? DateTime.Parse(publicationDate).Month : 0, Year = !string.IsNullOrEmpty(publicationDate) ? DateTime.Parse(publicationDate).Year : 0, + Title = epubBook.Title, + Genre = string.Join(",", epubBook.Schema.Package.Metadata.Subjects.Select(s => s.ToLower().Trim())), + }; // Parse tags not exposed via Library foreach (var metadataItem in epubBook.Schema.Package.Metadata.MetaItems) @@ -215,6 +397,9 @@ namespace API.Services case "calibre:rating": info.UserRating = float.Parse(metadataItem.Content); break; + case "calibre:title_sort": + info.TitleSort = metadataItem.Content; + break; } } @@ -305,8 +490,6 @@ namespace API.Services { using var epubBook = EpubReader.OpenBook(filePath); - // If the epub has the following tags, we can group the books as Volumes - // // // // If all three are present, we can take that over dc:title and format as: @@ -323,6 +506,7 @@ namespace API.Services var series = string.Empty; var specialName = string.Empty; var groupPosition = string.Empty; + var titleSort = string.Empty; foreach (var metadataItem in epubBook.Schema.Package.Metadata.MetaItems) @@ -338,6 +522,7 @@ namespace API.Services break; case "calibre:title_sort": specialName = metadataItem.Content; + titleSort = metadataItem.Content; break; } @@ -363,18 +548,26 @@ namespace API.Services { specialName = epubBook.Title; } - return new ParserInfo() + var info = new ParserInfo() { Chapters = Parser.Parser.DefaultChapter, Edition = string.Empty, Format = MangaFormat.Epub, Filename = Path.GetFileName(filePath), - Title = specialName.Trim(), + Title = specialName?.Trim(), FullFilePath = filePath, IsSpecial = false, Series = series.Trim(), Volumes = seriesIndex }; + + // Don't set titleSort if the book belongs to a group + if (!string.IsNullOrEmpty(titleSort) && string.IsNullOrEmpty(seriesIndex)) + { + info.SeriesSort = titleSort; + } + + return info; } } catch (Exception) @@ -392,7 +585,7 @@ namespace API.Services FullFilePath = filePath, IsSpecial = false, Series = epubBook.Title.Trim(), - Volumes = Parser.Parser.DefaultVolume + Volumes = Parser.Parser.DefaultVolume, }; } catch (Exception ex) @@ -403,31 +596,46 @@ namespace API.Services return null; } - private static void AddBytesToBitmap(Bitmap bmp, byte[] rawBytes) - { - var rect = new Rectangle(0, 0, bmp.Width, bmp.Height); - - var bmpData = bmp.LockBits(rect, ImageLockMode.WriteOnly, bmp.PixelFormat); - var pNative = bmpData.Scan0; - - Marshal.Copy(rawBytes, 0, pNative, rawBytes.Length); - bmp.UnlockBits(bmpData); - } - + /// + /// Extracts a pdf into images to a target directory. Uses multi-threaded implementation since docnet is slow normally. + /// + /// + /// public void ExtractPdfImages(string fileFilePath, string targetDirectory) { - DirectoryService.ExistOrCreate(targetDirectory); + _directoryService.ExistOrCreate(targetDirectory); using var docReader = DocLib.Instance.GetDocReader(fileFilePath, new PageDimensions(1080, 1920)); var pages = docReader.GetPageCount(); - using var stream = StreamManager.GetStream("BookService.GetPdfPage"); - for (var pageNumber = 0; pageNumber < pages; pageNumber++) + Parallel.For(0, pages, pageNumber => { + using var stream = StreamManager.GetStream("BookService.GetPdfPage"); GetPdfPage(docReader, pageNumber, stream); using var fileStream = File.Create(Path.Combine(targetDirectory, "Page-" + pageNumber + ".png")); stream.Seek(0, SeekOrigin.Begin); stream.CopyTo(fileStream); - } + }); + } + + /// + /// Responsible to scope all the css, links, tags, etc to prepare a self contained html file for the page + /// + /// Html Doc that will be appended to + /// Underlying epub + /// API Url for file loading to pass through + /// Body element from the epub + /// Epub mappings + /// Page number we are loading + /// + public async Task ScopePage(HtmlDocument doc, EpubBookRef book, string apiBase, HtmlNode body, Dictionary mappings, int page) + { + await InlineStyles(doc, book, apiBase, body); + + RewriteAnchors(page, doc, mappings); + + ScopeImages(doc, book, apiBase); + + return PrepareFinalHtml(doc, body); } /// @@ -436,13 +644,13 @@ namespace API.Services /// /// Name of the new file. /// - public string GetCoverImage(string fileFilePath, string fileName) + public string GetCoverImage(string fileFilePath, string fileName, string outputDirectory) { if (!IsValidFile(fileFilePath)) return string.Empty; if (Parser.Parser.IsPdf(fileFilePath)) { - return GetPdfCoverImage(fileFilePath, fileName); + return GetPdfCoverImage(fileFilePath, fileName, outputDirectory); } using var epubBook = EpubReader.OpenBook(fileFilePath); @@ -458,7 +666,7 @@ namespace API.Services if (coverImageContent == null) return string.Empty; using var stream = coverImageContent.GetContentStream(); - return ImageService.WriteCoverThumbnail(stream, fileName); + return _imageService.WriteCoverThumbnail(stream, fileName, outputDirectory); } catch (Exception ex) { @@ -469,7 +677,7 @@ namespace API.Services } - private string GetPdfCoverImage(string fileFilePath, string fileName) + private string GetPdfCoverImage(string fileFilePath, string fileName, string outputDirectory) { try { @@ -479,7 +687,7 @@ namespace API.Services using var stream = StreamManager.GetStream("BookService.GetPdfPage"); GetPdfPage(docReader, 0, stream); - return ImageService.WriteCoverThumbnail(stream, fileName); + return _imageService.WriteCoverThumbnail(stream, fileName, outputDirectory); } catch (Exception ex) @@ -498,15 +706,10 @@ namespace API.Services var rawBytes = pageReader.GetImage(new NaiveTransparencyRemover()); var width = pageReader.GetPageWidth(); var height = pageReader.GetPageHeight(); - using var bmp = new Bitmap(width, height, PixelFormat.Format32bppArgb); - AddBytesToBitmap(bmp, rawBytes); - // Removes 1px margin on left/right side after bitmap is copied out - for (var y = 0; y < bmp.Height; y++) - { - bmp.SetPixel(bmp.Width - 1, y, bmp.GetPixel(bmp.Width - 2, y)); - } + var image = Image.LoadPixelData(rawBytes, width, height); + stream.Seek(0, SeekOrigin.Begin); - bmp.Save(stream, ImageFormat.Jpeg); + image.SaveAsPng(stream); stream.Seek(0, SeekOrigin.Begin); } diff --git a/API/Services/CacheService.cs b/API/Services/CacheService.cs index a64bde675..0b6c4aa0d 100644 --- a/API/Services/CacheService.cs +++ b/API/Services/CacheService.cs @@ -1,46 +1,54 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.IO; using System.Linq; using System.Threading.Tasks; using API.Comparators; +using API.Data; using API.Entities; using API.Entities.Enums; using API.Extensions; -using API.Interfaces; -using API.Interfaces.Services; using Microsoft.Extensions.Logging; namespace API.Services { + public interface ICacheService + { + /// + /// Ensures the cache is created for the given chapter and if not, will create it. Should be called before any other + /// cache operations (except cleanup). + /// + /// + /// Chapter for the passed chapterId. Side-effect from ensuring cache. + Task Ensure(int chapterId); + /// + /// Clears cache directory of all volumes. This can be invoked from deleting a library or a series. + /// + /// Volumes that belong to that library. Assume the library might have been deleted before this invocation. + void CleanupChapters(IEnumerable chapterIds); + string GetCachedPagePath(Chapter chapter, int page); + string GetCachedEpubFile(int chapterId, Chapter chapter); + public void ExtractChapterFiles(string extractPath, IReadOnlyList files); + } public class CacheService : ICacheService { private readonly ILogger _logger; private readonly IUnitOfWork _unitOfWork; - private readonly IArchiveService _archiveService; private readonly IDirectoryService _directoryService; - private readonly IBookService _bookService; + private readonly IReadingItemService _readingItemService; private readonly NumericComparer _numericComparer; - public CacheService(ILogger logger, IUnitOfWork unitOfWork, IArchiveService archiveService, - IDirectoryService directoryService, IBookService bookService) + public CacheService(ILogger logger, IUnitOfWork unitOfWork, + IDirectoryService directoryService, IReadingItemService readingItemService) { _logger = logger; _unitOfWork = unitOfWork; - _archiveService = archiveService; _directoryService = directoryService; - _bookService = bookService; + _readingItemService = readingItemService; _numericComparer = new NumericComparer(); } - public void EnsureCacheDirectory() - { - if (!DirectoryService.ExistOrCreate(DirectoryService.CacheDirectory)) - { - _logger.LogError("Cache directory {CacheDirectory} is not accessible or does not exist. Creating...", DirectoryService.CacheDirectory); - } - } - /// /// Returns the full path to the cached epub file. If the file does not exist, will fallback to the original. /// @@ -50,8 +58,8 @@ namespace API.Services public string GetCachedEpubFile(int chapterId, Chapter chapter) { var extractPath = GetCachePath(chapterId); - var path = Path.Join(extractPath, Path.GetFileName(chapter.Files.First().FilePath)); - if (!(new FileInfo(path).Exists)) + var path = Path.Join(extractPath, _directoryService.FileSystem.Path.GetFileName(chapter.Files.First().FilePath)); + if (!(_directoryService.FileSystem.FileInfo.FromFileName(path).Exists)) { path = chapter.Files.First().FilePath; } @@ -62,14 +70,14 @@ namespace API.Services /// Caches the files for the given chapter to CacheDirectory /// /// - /// This will always return the Chapter for the chpaterId + /// This will always return the Chapter for the chapterId public async Task Ensure(int chapterId) { - EnsureCacheDirectory(); + _directoryService.ExistOrCreate(_directoryService.CacheDirectory); var chapter = await _unitOfWork.ChapterRepository.GetChapterAsync(chapterId); var extractPath = GetCachePath(chapterId); - if (!Directory.Exists(extractPath)) + if (!_directoryService.Exists(extractPath)) { var files = chapter.Files.ToList(); ExtractChapterFiles(extractPath, files); @@ -90,22 +98,12 @@ namespace API.Services var removeNonImages = true; var fileCount = files.Count; var extraPath = ""; - var extractDi = new DirectoryInfo(extractPath); + var extractDi = _directoryService.FileSystem.DirectoryInfo.FromDirectoryName(extractPath); if (files.Count > 0 && files[0].Format == MangaFormat.Image) { - DirectoryService.ExistOrCreate(extractPath); - if (files.Count == 1) - { - _directoryService.CopyFileToDirectory(files[0].FilePath, extractPath); - } - else - { - DirectoryService.CopyDirectoryToDirectory(Path.GetDirectoryName(files[0].FilePath), extractPath, - Parser.Parser.ImageFileExtensions); - } - - extractDi.Flatten(); + _readingItemService.Extract(files[0].FilePath, extractPath, MangaFormat.Image, files.Count); + _directoryService.Flatten(extractDi.FullName); } foreach (var file in files) @@ -117,63 +115,37 @@ namespace API.Services if (file.Format == MangaFormat.Archive) { - _archiveService.ExtractArchive(file.FilePath, Path.Join(extractPath, extraPath)); + _readingItemService.Extract(file.FilePath, Path.Join(extractPath, extraPath), file.Format); } else if (file.Format == MangaFormat.Pdf) { - _bookService.ExtractPdfImages(file.FilePath, Path.Join(extractPath, extraPath)); + _readingItemService.Extract(file.FilePath, Path.Join(extractPath, extraPath), file.Format); } else if (file.Format == MangaFormat.Epub) { removeNonImages = false; - DirectoryService.ExistOrCreate(extractPath); + _directoryService.ExistOrCreate(extractPath); _directoryService.CopyFileToDirectory(files[0].FilePath, extractPath); } } - extractDi.Flatten(); + _directoryService.Flatten(extractDi.FullName); if (removeNonImages) { - extractDi.RemoveNonImages(); + _directoryService.RemoveNonImages(extractDi.FullName); } } - - public void Cleanup() - { - _logger.LogInformation("Performing cleanup of Cache directory"); - EnsureCacheDirectory(); - - try - { - DirectoryService.ClearDirectory(DirectoryService.CacheDirectory); - } - catch (Exception ex) - { - _logger.LogError(ex, "There was an issue deleting one or more folders/files during cleanup"); - } - - _logger.LogInformation("Cache directory purged"); - } - /// /// Removes the cached files and folders for a set of chapterIds /// /// public void CleanupChapters(IEnumerable chapterIds) { - _logger.LogInformation("Running Cache cleanup on Chapters"); - foreach (var chapter in chapterIds) { - var di = new DirectoryInfo(GetCachePath(chapter)); - if (di.Exists) - { - di.Delete(true); - } - + _directoryService.ClearDirectory(GetCachePath(chapter)); } - _logger.LogInformation("Cache directory purged"); } @@ -184,46 +156,32 @@ namespace API.Services /// private string GetCachePath(int chapterId) { - return Path.GetFullPath(Path.Join(DirectoryService.CacheDirectory, $"{chapterId}/")); + return _directoryService.FileSystem.Path.GetFullPath(_directoryService.FileSystem.Path.Join(_directoryService.CacheDirectory, $"{chapterId}/")); } - public async Task<(string path, MangaFile file)> GetCachedPagePath(Chapter chapter, int page) + /// + /// Returns the absolute path of a cached page. + /// + /// Chapter entity with Files populated. + /// Page number to look for + /// Page filepath or empty if no files found. + public string GetCachedPagePath(Chapter chapter, int page) { // Calculate what chapter the page belongs to - var pagesSoFar = 0; - var chapterFiles = chapter.Files ?? await _unitOfWork.ChapterRepository.GetFilesForChapterAsync(chapter.Id); - foreach (var mangaFile in chapterFiles) + var path = GetCachePath(chapter.Id); + var files = _directoryService.GetFilesWithExtension(path, Parser.Parser.ImageFileExtensions); + files = files + .AsEnumerable() + .OrderByNatural(Path.GetFileNameWithoutExtension) + .ToArray(); + + if (files.Length == 0) { - if (page <= (mangaFile.Pages + pagesSoFar)) - { - var path = GetCachePath(chapter.Id); - var files = DirectoryService.GetFilesWithExtension(path, Parser.Parser.ImageFileExtensions); - Array.Sort(files, _numericComparer); - - if (files.Length == 0) - { - return (files.ElementAt(0), mangaFile); - } - - // Since array is 0 based, we need to keep that in account (only affects last image) - if (page == files.Length) - { - return (files.ElementAt(page - 1 - pagesSoFar), mangaFile); - } - - if (mangaFile.Format == MangaFormat.Image && mangaFile.Pages == 1) - { - // Each file is one page, meaning we should just get element at page - return (files.ElementAt(page), mangaFile); - } - - return (files.ElementAt(page - pagesSoFar), mangaFile); - } - - pagesSoFar += mangaFile.Pages; + return string.Empty; } - return (string.Empty, null); + // Since array is 0 based, we need to keep that in account (only affects last image) + return page == files.Length ? files.ElementAt(page - 1) : files.ElementAt(page); } } } diff --git a/API/Services/DirectoryService.cs b/API/Services/DirectoryService.cs index 04240245a..bf3c01d25 100644 --- a/API/Services/DirectoryService.cs +++ b/API/Services/DirectoryService.cs @@ -1,31 +1,88 @@ -using System; +using System; +using System.Collections; using System.Collections.Generic; using System.Collections.Immutable; using System.IO; +using System.IO.Abstractions; using System.Linq; using System.Text.RegularExpressions; using System.Threading.Tasks; -using API.Interfaces.Services; +using API.Comparators; +using API.Extensions; using Microsoft.Extensions.Logging; namespace API.Services { + public interface IDirectoryService + { + IFileSystem FileSystem { get; } + string CacheDirectory { get; } + string CoverImageDirectory { get; } + string LogDirectory { get; } + string TempDirectory { get; } + string ConfigDirectory { get; } + /// + /// Original BookmarkDirectory. Only used for resetting directory. Use for actual path. + /// + string BookmarkDirectory { get; } + /// + /// Lists out top-level folders for a given directory. Filters out System and Hidden folders. + /// + /// Absolute path of directory to scan. + /// List of folder names + IEnumerable ListDirectory(string rootPath); + Task ReadFileAsync(string path); + bool CopyFilesToDirectory(IEnumerable filePaths, string directoryPath, string prepend = ""); + bool Exists(string directory); + void CopyFileToDirectory(string fullFilePath, string targetDirectory); + int TraverseTreeParallelForEach(string root, Action action, string searchPattern, ILogger logger); + bool IsDriveMounted(string path); + bool IsDirectoryEmpty(string path); + long GetTotalSize(IEnumerable paths); + void ClearDirectory(string directoryPath); + void ClearAndDeleteDirectory(string directoryPath); + string[] GetFilesWithExtension(string path, string searchPatternExpression = ""); + bool CopyDirectoryToDirectory(string sourceDirName, string destDirName, string searchPattern = ""); + + Dictionary FindHighestDirectoriesFromFiles(IEnumerable libraryFolders, + IList filePaths); + + IEnumerable GetFoldersTillRoot(string rootPath, string fullPath); + + IEnumerable GetFiles(string path, string fileNameRegex = "", SearchOption searchOption = SearchOption.TopDirectoryOnly); + + bool ExistOrCreate(string directoryPath); + void DeleteFiles(IEnumerable files); + void RemoveNonImages(string directoryName); + void Flatten(string directoryName); + Task CheckWriteAccess(string directoryName); + } public class DirectoryService : IDirectoryService { - private readonly ILogger _logger; - private static readonly Regex ExcludeDirectories = new Regex( - @"@eaDir|\.DS_Store", - RegexOptions.Compiled | RegexOptions.IgnoreCase); - public static readonly string TempDirectory = Path.Join(Directory.GetCurrentDirectory(), "config", "temp"); - public static readonly string LogDirectory = Path.Join(Directory.GetCurrentDirectory(), "config", "logs"); - public static readonly string CacheDirectory = Path.Join(Directory.GetCurrentDirectory(), "config", "cache"); - public static readonly string CoverImageDirectory = Path.Join(Directory.GetCurrentDirectory(), "config", "covers"); - public static readonly string BackupDirectory = Path.Join(Directory.GetCurrentDirectory(), "config", "backups"); - public static readonly string ConfigDirectory = Path.Join(Directory.GetCurrentDirectory(), "config"); + public IFileSystem FileSystem { get; } + public string CacheDirectory { get; } + public string CoverImageDirectory { get; } + public string LogDirectory { get; } + public string TempDirectory { get; } + public string ConfigDirectory { get; } + public string BookmarkDirectory { get; } + private readonly ILogger _logger; - public DirectoryService(ILogger logger) + private static readonly Regex ExcludeDirectories = new Regex( + @"@eaDir|\.DS_Store|\.qpkg", + RegexOptions.Compiled | RegexOptions.IgnoreCase); + public static readonly string BackupDirectory = Path.Join(Directory.GetCurrentDirectory(), "config", "backups"); + + public DirectoryService(ILogger logger, IFileSystem fileSystem) { - _logger = logger; + _logger = logger; + FileSystem = fileSystem; + CoverImageDirectory = FileSystem.Path.Join(FileSystem.Directory.GetCurrentDirectory(), "config", "covers"); + CacheDirectory = FileSystem.Path.Join(FileSystem.Directory.GetCurrentDirectory(), "config", "cache"); + LogDirectory = FileSystem.Path.Join(FileSystem.Directory.GetCurrentDirectory(), "config", "logs"); + TempDirectory = FileSystem.Path.Join(FileSystem.Directory.GetCurrentDirectory(), "config", "temp"); + ConfigDirectory = FileSystem.Path.Join(FileSystem.Directory.GetCurrentDirectory(), "config"); + BookmarkDirectory = FileSystem.Path.Join(FileSystem.Directory.GetCurrentDirectory(), "config", "bookmarks"); } /// @@ -36,16 +93,16 @@ namespace API.Services /// Regex version of search pattern (ie \.mp3|\.mp4). Defaults to * meaning all files. /// SearchOption to use, defaults to TopDirectoryOnly /// List of file paths - private static IEnumerable GetFilesWithCertainExtensions(string path, + private IEnumerable GetFilesWithCertainExtensions(string path, string searchPatternExpression = "", SearchOption searchOption = SearchOption.TopDirectoryOnly) { - if (!Directory.Exists(path)) return ImmutableList.Empty; + if (!FileSystem.Directory.Exists(path)) return ImmutableList.Empty; var reSearchPattern = new Regex(searchPatternExpression, RegexOptions.IgnoreCase); - return Directory.EnumerateFiles(path, "*", searchOption) + return FileSystem.Directory.EnumerateFiles(path, "*", searchOption) .Where(file => - reSearchPattern.IsMatch(Path.GetExtension(file)) && !Path.GetFileName(file).StartsWith(Parser.Parser.MacOsMetadataFileStartsWith)); + reSearchPattern.IsMatch(FileSystem.Path.GetExtension(file)) && !FileSystem.Path.GetFileName(file).StartsWith(Parser.Parser.MacOsMetadataFileStartsWith)); } @@ -57,17 +114,17 @@ namespace API.Services /// /// /// - public static IEnumerable GetFoldersTillRoot(string rootPath, string fullPath) + public IEnumerable GetFoldersTillRoot(string rootPath, string fullPath) { - var separator = Path.AltDirectorySeparatorChar; - if (fullPath.Contains(Path.DirectorySeparatorChar)) + var separator = FileSystem.Path.AltDirectorySeparatorChar; + if (fullPath.Contains(FileSystem.Path.DirectorySeparatorChar)) { - fullPath = fullPath.Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); + fullPath = fullPath.Replace(FileSystem.Path.DirectorySeparatorChar, FileSystem.Path.AltDirectorySeparatorChar); } if (rootPath.Contains(Path.DirectorySeparatorChar)) { - rootPath = rootPath.Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); + rootPath = rootPath.Replace(FileSystem.Path.DirectorySeparatorChar, FileSystem.Path.AltDirectorySeparatorChar); } @@ -76,14 +133,14 @@ namespace API.Services var root = rootPath.EndsWith(separator) ? rootPath.Substring(0, rootPath.Length - 1) : rootPath; var paths = new List(); // If a file is at the end of the path, remove it before we start processing folders - if (Path.GetExtension(path) != string.Empty) + if (FileSystem.Path.GetExtension(path) != string.Empty) { path = path.Substring(0, path.LastIndexOf(separator)); } - while (Path.GetDirectoryName(path) != Path.GetDirectoryName(root)) + while (FileSystem.Path.GetDirectoryName(path) != Path.GetDirectoryName(root)) { - var folder = new DirectoryInfo(path).Name; + var folder = FileSystem.DirectoryInfo.FromDirectoryName(path).Name; paths.Add(folder); path = path.Substring(0, path.LastIndexOf(separator)); } @@ -91,35 +148,60 @@ namespace API.Services return paths; } + /// + /// Does Directory Exist + /// + /// + /// public bool Exists(string directory) { - var di = new DirectoryInfo(directory); - return di.Exists; + var di = FileSystem.DirectoryInfo.FromDirectoryName(directory); + return di.Exists; } - public static IEnumerable GetFiles(string path, string searchPatternExpression = "", - SearchOption searchOption = SearchOption.TopDirectoryOnly) + /// + /// Get files given a path. + /// + /// This will automatically filter out restricted files, like MacOsMetadata files + /// + /// An optional regex string to search against. Will use file path to match against. + /// Defaults to top level directory only, can be given all to provide recursive searching + /// + public IEnumerable GetFiles(string path, string fileNameRegex = "", SearchOption searchOption = SearchOption.TopDirectoryOnly) { - if (searchPatternExpression != string.Empty) + if (!FileSystem.Directory.Exists(path)) return ImmutableList.Empty; + + if (fileNameRegex != string.Empty) { - if (!Directory.Exists(path)) return ImmutableList.Empty; - var reSearchPattern = new Regex(searchPatternExpression, RegexOptions.IgnoreCase); - return Directory.EnumerateFiles(path, "*", searchOption) + var reSearchPattern = new Regex(fileNameRegex, RegexOptions.IgnoreCase); + return FileSystem.Directory.EnumerateFiles(path, "*", searchOption) .Where(file => - reSearchPattern.IsMatch(file) && !file.StartsWith(Parser.Parser.MacOsMetadataFileStartsWith)); + { + var fileName = FileSystem.Path.GetFileName(file); + return reSearchPattern.IsMatch(fileName) && + !fileName.StartsWith(Parser.Parser.MacOsMetadataFileStartsWith); + }); } - return !Directory.Exists(path) ? Array.Empty() : Directory.GetFiles(path); + return FileSystem.Directory.EnumerateFiles(path, "*", searchOption).Where(file => + !FileSystem.Path.GetFileName(file).StartsWith(Parser.Parser.MacOsMetadataFileStartsWith)); } + /// + /// Copies a file into a directory. Does not maintain parent folder of file. + /// Will create target directory if doesn't exist. Automatically overwrites what is there. + /// + /// + /// public void CopyFileToDirectory(string fullFilePath, string targetDirectory) { try { - var fileInfo = new FileInfo(fullFilePath); + var fileInfo = FileSystem.FileInfo.FromFileName(fullFilePath); if (fileInfo.Exists) { - fileInfo.CopyTo(Path.Join(targetDirectory, fileInfo.Name), true); + ExistOrCreate(targetDirectory); + fileInfo.CopyTo(FileSystem.Path.Join(targetDirectory, fileInfo.Name), true); } } catch (Exception ex) @@ -129,19 +211,19 @@ namespace API.Services } /// - /// Copies a Directory with all files and subdirectories to a target location + /// Copies all files and subdirectories within a directory to a target location /// - /// - /// - /// Defaults to *, meaning all files - /// - /// - public static bool CopyDirectoryToDirectory(string sourceDirName, string destDirName, string searchPattern = "") + /// Directory to copy from. Does not copy the parent folder + /// Destination to copy to. Will be created if doesn't exist + /// Defaults to all files + /// If was successful + /// Thrown when source directory does not exist + public bool CopyDirectoryToDirectory(string sourceDirName, string destDirName, string searchPattern = "") { if (string.IsNullOrEmpty(sourceDirName)) return false; // Get the subdirectories for the specified directory. - var dir = new DirectoryInfo(sourceDirName); + var dir = FileSystem.DirectoryInfo.FromDirectoryName(sourceDirName); if (!dir.Exists) { @@ -156,17 +238,17 @@ namespace API.Services ExistOrCreate(destDirName); // Get the files in the directory and copy them to the new location. - var files = GetFilesWithExtension(dir.FullName, searchPattern).Select(n => new FileInfo(n)); + var files = GetFilesWithExtension(dir.FullName, searchPattern).Select(n => FileSystem.FileInfo.FromFileName(n)); foreach (var file in files) { - var tempPath = Path.Combine(destDirName, file.Name); + var tempPath = FileSystem.Path.Combine(destDirName, file.Name); file.CopyTo(tempPath, false); } // If copying subdirectories, copy them and their contents to new location. foreach (var subDir in dirs) { - var tempPath = Path.Combine(destDirName, subDir.Name); + var tempPath = FileSystem.Path.Combine(destDirName, subDir.Name); CopyDirectoryToDirectory(subDir.FullName, tempPath); } @@ -178,19 +260,30 @@ namespace API.Services /// /// /// - public static bool IsDriveMounted(string path) + public bool IsDriveMounted(string path) { - return new DirectoryInfo(Path.GetPathRoot(path) ?? string.Empty).Exists; + return FileSystem.DirectoryInfo.FromDirectoryName(FileSystem.Path.GetPathRoot(path) ?? string.Empty).Exists; } - public static string[] GetFilesWithExtension(string path, string searchPatternExpression = "") - { - if (searchPatternExpression != string.Empty) - { - return GetFilesWithCertainExtensions(path, searchPatternExpression).ToArray(); - } - return !Directory.Exists(path) ? Array.Empty() : Directory.GetFiles(path); + /// + /// Checks if the root path of a path is empty or not. + /// + /// + /// + public bool IsDirectoryEmpty(string path) + { + return FileSystem.Directory.Exists(path) && !FileSystem.Directory.EnumerateFileSystemEntries(path).Any(); + } + + public string[] GetFilesWithExtension(string path, string searchPatternExpression = "") + { + if (searchPatternExpression != string.Empty) + { + return GetFilesWithCertainExtensions(path, searchPatternExpression).ToArray(); + } + + return !FileSystem.Directory.Exists(path) ? Array.Empty() : FileSystem.Directory.GetFiles(path); } /// @@ -198,9 +291,9 @@ namespace API.Services /// /// /// Total bytes - public static long GetTotalSize(IEnumerable paths) + public long GetTotalSize(IEnumerable paths) { - return paths.Sum(path => new FileInfo(path).Length); + return paths.Sum(path => FileSystem.FileInfo.FromFileName(path).Length); } /// @@ -208,13 +301,13 @@ namespace API.Services /// /// /// - public static bool ExistOrCreate(string directoryPath) + public bool ExistOrCreate(string directoryPath) { - var di = new DirectoryInfo(directoryPath); + var di = FileSystem.DirectoryInfo.FromDirectoryName(directoryPath); if (di.Exists) return true; try { - Directory.CreateDirectory(directoryPath); + FileSystem.Directory.CreateDirectory(directoryPath); } catch (Exception) { @@ -227,11 +320,11 @@ namespace API.Services /// Deletes all files within the directory, then the directory itself. ///
    /// - public static void ClearAndDeleteDirectory(string directoryPath) + public void ClearAndDeleteDirectory(string directoryPath) { - if (!Directory.Exists(directoryPath)) return; + if (!FileSystem.Directory.Exists(directoryPath)) return; - DirectoryInfo di = new DirectoryInfo(directoryPath); + var di = FileSystem.DirectoryInfo.FromDirectoryName(directoryPath); ClearDirectory(directoryPath); @@ -239,13 +332,13 @@ namespace API.Services } /// - /// Deletes all files within the directory. + /// Deletes all files and folders within the directory path /// /// /// - public static void ClearDirectory(string directoryPath) + public void ClearDirectory(string directoryPath) { - var di = new DirectoryInfo(directoryPath); + var di = FileSystem.DirectoryInfo.FromDirectoryName(directoryPath); if (!di.Exists) return; foreach (var file in di.EnumerateFiles()) @@ -265,7 +358,7 @@ namespace API.Services /// /// An optional string to prepend to the target file's name /// - public static bool CopyFilesToDirectory(IEnumerable filePaths, string directoryPath, string prepend = "", ILogger logger = null) + public bool CopyFilesToDirectory(IEnumerable filePaths, string directoryPath, string prepend = "") { ExistOrCreate(directoryPath); string currentFile = null; @@ -274,36 +367,36 @@ namespace API.Services foreach (var file in filePaths) { currentFile = file; - var fileInfo = new FileInfo(file); + var fileInfo = FileSystem.FileInfo.FromFileName(file); if (fileInfo.Exists) { - fileInfo.CopyTo(Path.Join(directoryPath, prepend + fileInfo.Name)); + fileInfo.CopyTo(FileSystem.Path.Join(directoryPath, prepend + fileInfo.Name)); } else { - logger?.LogWarning("Tried to copy {File} but it doesn't exist", file); + _logger.LogWarning("Tried to copy {File} but it doesn't exist", file); } } } catch (Exception ex) { - logger?.LogError(ex, "Unable to copy {File} to {DirectoryPath}", currentFile, directoryPath); + _logger.LogError(ex, "Unable to copy {File} to {DirectoryPath}", currentFile, directoryPath); return false; } return true; } - public bool CopyFilesToDirectory(IEnumerable filePaths, string directoryPath, string prepend = "") - { - return CopyFilesToDirectory(filePaths, directoryPath, prepend, _logger); - } - + /// + /// Lists all directories in a root path. Will exclude Hidden or System directories. + /// + /// + /// public IEnumerable ListDirectory(string rootPath) { - if (!Directory.Exists(rootPath)) return ImmutableList.Empty; + if (!FileSystem.Directory.Exists(rootPath)) return ImmutableList.Empty; - var di = new DirectoryInfo(rootPath); + var di = FileSystem.DirectoryInfo.FromDirectoryName(rootPath); var dirs = di.GetDirectories() .Where(dir => !(dir.Attributes.HasFlag(FileAttributes.Hidden) || dir.Attributes.HasFlag(FileAttributes.System))) .Select(d => d.Name).ToImmutableList(); @@ -311,20 +404,26 @@ namespace API.Services return dirs; } + /// + /// Reads a file's into byte[]. Returns empty array if file doesn't exist. + /// + /// + /// public async Task ReadFileAsync(string path) { - if (!File.Exists(path)) return Array.Empty(); - return await File.ReadAllBytesAsync(path); + if (!FileSystem.File.Exists(path)) return Array.Empty(); + return await FileSystem.File.ReadAllBytesAsync(path); } /// - /// Finds the highest directories from a set of MangaFiles + /// Finds the highest directories from a set of file paths. Does not return the root path, will always select the highest non-root path. /// + /// If the file paths do not contain anything from libraryFolders, this returns an empty dictionary back /// List of top level folders which files belong to /// List of file paths that belong to libraryFolders /// - public static Dictionary FindHighestDirectoriesFromFiles(IEnumerable libraryFolders, IList filePaths) + public Dictionary FindHighestDirectoriesFromFiles(IEnumerable libraryFolders, IList filePaths) { var stopLookingForDirectories = false; var dirs = new Dictionary(); @@ -365,20 +464,19 @@ namespace API.Services /// Regex pattern to search against /// /// - public static int TraverseTreeParallelForEach(string root, Action action, string searchPattern, ILogger logger) + public int TraverseTreeParallelForEach(string root, Action action, string searchPattern, ILogger logger) { - //Count of files traversed and timer for diagnostic output + //Count of files traversed and timer for diagnostic output var fileCount = 0; - // Determine whether to parallelize file processing on each folder based on processor count. - //var procCount = Environment.ProcessorCount; // Data structure to hold names of subfolders to be examined for files. var dirs = new Stack(); - if (!Directory.Exists(root)) { - throw new ArgumentException("The directory doesn't exist"); + if (!FileSystem.Directory.Exists(root)) { + throw new ArgumentException("The directory doesn't exist"); } + dirs.Push(root); while (dirs.Count > 0) { @@ -387,7 +485,7 @@ namespace API.Services string[] files; try { - subDirs = Directory.GetDirectories(currentDir).Where(path => ExcludeDirectories.Matches(path).Count == 0); + subDirs = FileSystem.Directory.GetDirectories(currentDir).Where(path => ExcludeDirectories.Matches(path).Count == 0); } // Thrown if we do not have discovery permission on the directory. catch (UnauthorizedAccessException e) { @@ -403,7 +501,7 @@ namespace API.Services } try { - files = GetFilesWithCertainExtensions(currentDir, searchPattern) + files = GetFilesWithCertainExtensions(currentDir, searchPattern) .ToArray(); } catch (UnauthorizedAccessException e) { @@ -423,22 +521,7 @@ namespace API.Services // Otherwise, execute sequentially. Files are opened and processed // synchronously but this could be modified to perform async I/O. try { - // if (files.Length < procCount) { - // foreach (var file in files) { - // action(file); - // fileCount++; - // } - // } - // else { - // Parallel.ForEach(files, () => 0, (file, _, localCount) => - // { action(file); - // return ++localCount; - // }, - // (c) => { - // Interlocked.Add(ref fileCount, c); - // }); - // } - foreach (var file in files) { + foreach (var file in files) { action(file); fileCount++; } @@ -448,6 +531,7 @@ namespace API.Services if (ex is UnauthorizedAccessException) { // Here we just output a message and go on. Console.WriteLine(ex.Message); + _logger.LogError(ex, "Unauthorized access on file"); return true; } // Handle other exceptions here if necessary... @@ -469,13 +553,13 @@ namespace API.Services /// Attempts to delete the files passed to it. Swallows exceptions. ///
    /// Full path of files to delete - public static void DeleteFiles(IEnumerable files) + public void DeleteFiles(IEnumerable files) { foreach (var file in files) { try { - new FileInfo(file).Delete(); + FileSystem.FileInfo.FromFileName(file).Delete(); } catch (Exception) { @@ -538,5 +622,101 @@ namespace API.Services // Return formatted number with suffix return readable.ToString("0.## ") + suffix; } + + /// + /// Removes all files except images from the directory. Includes sub directories. + /// + /// Fully qualified directory + public void RemoveNonImages(string directoryName) + { + DeleteFiles(GetFiles(directoryName, searchOption:SearchOption.AllDirectories).Where(file => !Parser.Parser.IsImage(file))); + } + + + /// + /// Flattens all files in subfolders to the passed directory recursively. + /// + /// + /// foo + /// ├── 1.txt + /// ├── 2.txt + /// ├── 3.txt + /// ├── 4.txt + /// └── bar + /// ├── 1.txt + /// ├── 2.txt + /// └── 5.txt + /// + /// becomes: + /// foo + /// ├── 1.txt + /// ├── 2.txt + /// ├── 3.txt + /// ├── 4.txt + /// ├── bar_1.txt + /// ├── bar_2.txt + /// └── bar_5.txt + /// + /// Fully qualified Directory name + public void Flatten(string directoryName) + { + if (string.IsNullOrEmpty(directoryName) || !FileSystem.Directory.Exists(directoryName)) return; + + var directory = FileSystem.DirectoryInfo.FromDirectoryName(directoryName); + + var index = 0; + FlattenDirectory(directory, directory, ref index); + } + + /// + /// Checks whether a directory has write permissions + /// + /// Fully qualified path + /// + public async Task CheckWriteAccess(string directoryName) + { + try + { + ExistOrCreate(directoryName); + await FileSystem.File.WriteAllTextAsync( + FileSystem.Path.Join(directoryName, "test.txt"), + string.Empty); + } + catch (Exception ex) + { + ClearAndDeleteDirectory(directoryName); + return false; + } + + ClearAndDeleteDirectory(directoryName); + return true; + } + + + private void FlattenDirectory(IDirectoryInfo root, IDirectoryInfo directory, ref int directoryIndex) + { + if (!root.FullName.Equals(directory.FullName)) + { + var fileIndex = 1; + + foreach (var file in directory.EnumerateFiles().OrderByNatural(file => file.FullName)) + { + if (file.Directory == null) continue; + var paddedIndex = Parser.Parser.PadZeros(directoryIndex + ""); + // We need to rename the files so that after flattening, they are in the order we found them + var newName = $"{paddedIndex}_{Parser.Parser.PadZeros(fileIndex + "")}{file.Extension}"; + var newPath = Path.Join(root.FullName, newName); + if (!File.Exists(newPath)) file.MoveTo(newPath); + fileIndex++; + } + + directoryIndex++; + } + + foreach (var subDirectory in directory.EnumerateDirectories().OrderByNatural(d => d.FullName)) + { + FlattenDirectory(root, subDirectory, ref directoryIndex); + } + } } } diff --git a/API/Services/DownloadService.cs b/API/Services/DownloadService.cs index 7d0f56b3d..51830f0ab 100644 --- a/API/Services/DownloadService.cs +++ b/API/Services/DownloadService.cs @@ -3,56 +3,54 @@ using System.IO; using System.Linq; using System.Threading.Tasks; using API.Entities; -using API.Interfaces.Services; using Microsoft.AspNetCore.StaticFiles; -namespace API.Services +namespace API.Services; + +public interface IDownloadService { - public interface IDownloadService + Task<(byte[], string, string)> GetFirstFileDownload(IEnumerable files); + string GetContentTypeFromFile(string filepath); +} +public class DownloadService : IDownloadService +{ + private readonly IDirectoryService _directoryService; + private readonly FileExtensionContentTypeProvider _fileTypeProvider = new FileExtensionContentTypeProvider(); + + public DownloadService(IDirectoryService directoryService) { - Task<(byte[], string, string)> GetFirstFileDownload(IEnumerable files); - string GetContentTypeFromFile(string filepath); + _directoryService = directoryService; } - public class DownloadService : IDownloadService + + /// + /// Downloads the first file in the file enumerable for download + /// + /// + /// + public async Task<(byte[], string, string)> GetFirstFileDownload(IEnumerable files) { - private readonly IDirectoryService _directoryService; - private readonly FileExtensionContentTypeProvider _fileTypeProvider = new FileExtensionContentTypeProvider(); + var firstFile = files.Select(c => c.FilePath).First(); + return (await _directoryService.ReadFileAsync(firstFile), GetContentTypeFromFile(firstFile), Path.GetFileName(firstFile)); + } - public DownloadService(IDirectoryService directoryService) + public string GetContentTypeFromFile(string filepath) + { + // Figures out what the content type should be based on the file name. + if (!_fileTypeProvider.TryGetContentType(filepath, out var contentType)) { - _directoryService = directoryService; - } - - /// - /// Downloads the first file in the file enumerable for download - /// - /// - /// - public async Task<(byte[], string, string)> GetFirstFileDownload(IEnumerable files) - { - var firstFile = files.Select(c => c.FilePath).First(); - return (await _directoryService.ReadFileAsync(firstFile), GetContentTypeFromFile(firstFile), Path.GetFileName(firstFile)); - } - - public string GetContentTypeFromFile(string filepath) - { - // Figures out what the content type should be based on the file name. - if (!_fileTypeProvider.TryGetContentType(filepath, out var contentType)) + contentType = Path.GetExtension(filepath).ToLowerInvariant() switch { - contentType = Path.GetExtension(filepath).ToLowerInvariant() switch - { - ".cbz" => "application/zip", - ".cbr" => "application/vnd.rar", - ".cb7" => "application/x-compressed", - ".epub" => "application/epub+zip", - ".7z" => "application/x-7z-compressed", - ".7zip" => "application/x-7z-compressed", - ".pdf" => "application/pdf", - _ => contentType - }; - } - - return contentType; + ".cbz" => "application/zip", + ".cbr" => "application/vnd.rar", + ".cb7" => "application/x-compressed", + ".epub" => "application/epub+zip", + ".7z" => "application/x-7z-compressed", + ".7zip" => "application/x-7z-compressed", + ".pdf" => "application/pdf", + _ => contentType + }; } + + return contentType; } } diff --git a/API/Services/FileService.cs b/API/Services/FileService.cs new file mode 100644 index 000000000..a4194b820 --- /dev/null +++ b/API/Services/FileService.cs @@ -0,0 +1,46 @@ +using System; +using System.IO.Abstractions; +using API.Extensions; + +namespace API.Services; + +public interface IFileService +{ + IFileSystem GetFileSystem(); + bool HasFileBeenModifiedSince(string filePath, DateTime time); + bool Exists(string filePath); +} + +public class FileService : IFileService +{ + private readonly IFileSystem _fileSystem; + + public FileService(IFileSystem fileSystem) + { + _fileSystem = fileSystem; + } + + public FileService() : this(fileSystem: new FileSystem()) { } + + public IFileSystem GetFileSystem() + { + return _fileSystem; + } + + /// + /// If the File on disk's last modified time is after passed time + /// + /// This has a resolution to the minute. Will ignore seconds and milliseconds + /// Full qualified path of file + /// + /// + public bool HasFileBeenModifiedSince(string filePath, DateTime time) + { + return !string.IsNullOrEmpty(filePath) && _fileSystem.File.GetLastWriteTime(filePath).Truncate(TimeSpan.TicksPerMinute) > time.Truncate(TimeSpan.TicksPerMinute); + } + + public bool Exists(string filePath) + { + return _fileSystem.File.Exists(filePath); + } +} diff --git a/API/Services/HostedServices/StartupTasksHostedService.cs b/API/Services/HostedServices/StartupTasksHostedService.cs index 486b45513..099c44cc8 100644 --- a/API/Services/HostedServices/StartupTasksHostedService.cs +++ b/API/Services/HostedServices/StartupTasksHostedService.cs @@ -1,7 +1,6 @@ using System; using System.Threading; using System.Threading.Tasks; -using API.Interfaces; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; @@ -21,7 +20,7 @@ namespace API.Services.HostedServices using var scope = _provider.CreateScope(); var taskScheduler = scope.ServiceProvider.GetRequiredService(); - taskScheduler.ScheduleTasks(); + await taskScheduler.ScheduleTasks(); taskScheduler.ScheduleUpdaterTasks(); try diff --git a/API/Services/ImageService.cs b/API/Services/ImageService.cs index 7f663c37d..29a528e71 100644 --- a/API/Services/ImageService.cs +++ b/API/Services/ImageService.cs @@ -1,21 +1,32 @@ using System; using System.IO; -using System.Linq; -using API.Comparators; -using API.Entities; -using API.Interfaces.Services; using Microsoft.Extensions.Logging; using NetVips; -namespace API.Services -{ +namespace API.Services; - public class ImageService : IImageService - { +public interface IImageService +{ + void ExtractImages(string fileFilePath, string targetDirectory, int fileCount = 1); + string GetCoverImage(string path, string fileName, string outputDirectory); + + /// + /// Creates a Thumbnail version of a base64 image + /// + /// base64 encoded image + /// File name with extension of the file. This will always write to + string CreateThumbnailFromBase64(string encodedImage, string fileName); + + string WriteCoverThumbnail(Stream stream, string fileName, string outputDirectory); +} + +public class ImageService : IImageService +{ private readonly ILogger _logger; + private readonly IDirectoryService _directoryService; public const string ChapterCoverImageRegex = @"v\d+_c\d+"; - public const string SeriesCoverImageRegex = @"seres\d+"; - public const string CollectionTagCoverImageRegex = @"tag\d+"; + public const string SeriesCoverImageRegex = @"series_\d+"; + public const string CollectionTagCoverImageRegex = @"tag_\d+"; /// @@ -23,60 +34,40 @@ namespace API.Services /// private const int ThumbnailWidth = 320; - public ImageService(ILogger logger) + public ImageService(ILogger logger, IDirectoryService directoryService) { - _logger = logger; + _logger = logger; + _directoryService = directoryService; } - /// - /// Finds the first image in the directory of the first file. Does not check for "cover/folder".ext files to override. - /// - /// - /// - public string GetCoverFile(MangaFile file) + public void ExtractImages(string fileFilePath, string targetDirectory, int fileCount) { - var directory = Path.GetDirectoryName(file.FilePath); - if (string.IsNullOrEmpty(directory)) - { - _logger.LogError("Could not find Directory for {File}", file.FilePath); - return null; - } - - var firstImage = DirectoryService.GetFilesWithExtension(directory, Parser.Parser.ImageFileExtensions) - .OrderBy(f => f, new NaturalSortComparer()).FirstOrDefault(); - - return firstImage; + _directoryService.ExistOrCreate(targetDirectory); + if (fileCount == 1) + { + _directoryService.CopyFileToDirectory(fileFilePath, targetDirectory); + } + else + { + _directoryService.CopyDirectoryToDirectory(Path.GetDirectoryName(fileFilePath), targetDirectory, + Parser.Parser.ImageFileExtensions); + } } - public string GetCoverImage(string path, string fileName) + public string GetCoverImage(string path, string fileName, string outputDirectory) { - if (string.IsNullOrEmpty(path)) return string.Empty; + if (string.IsNullOrEmpty(path)) return string.Empty; - try - { - return CreateThumbnail(path, fileName); - } - catch (Exception ex) - { - _logger.LogWarning(ex, "[GetCoverImage] There was an error and prevented thumbnail generation on {ImageFile}. Defaulting to no cover image", path); - } - - return string.Empty; - } - - /// - public string CreateThumbnail(string path, string fileName) - { try { using var thumbnail = Image.Thumbnail(path, ThumbnailWidth); var filename = fileName + ".png"; - thumbnail.WriteToFile(Path.Join(DirectoryService.CoverImageDirectory, filename)); + thumbnail.WriteToFile(_directoryService.FileSystem.Path.Join(outputDirectory, filename)); return filename; } - catch (Exception e) + catch (Exception ex) { - _logger.LogError(e, "Error creating thumbnail from url"); + _logger.LogWarning(ex, "[GetCoverImage] There was an error and prevented thumbnail generation on {ImageFile}. Defaulting to no cover image", path); } return string.Empty; @@ -89,11 +80,16 @@ namespace API.Services /// Stream to write to disk. Ensure this is rewinded. /// filename to save as without extension /// File name with extension of the file. This will always write to - public static string WriteCoverThumbnail(Stream stream, string fileName) + public string WriteCoverThumbnail(Stream stream, string fileName, string outputDirectory) { using var thumbnail = Image.ThumbnailStream(stream, ThumbnailWidth); var filename = fileName + ".png"; - thumbnail.WriteToFile(Path.Join(DirectoryService.CoverImageDirectory, fileName + ".png")); + _directoryService.ExistOrCreate(outputDirectory); + try + { + _directoryService.FileSystem.File.Delete(_directoryService.FileSystem.Path.Join(outputDirectory, filename)); + } catch (Exception ex) {/* Swallow exception */} + thumbnail.WriteToFile(_directoryService.FileSystem.Path.Join(outputDirectory, filename)); return filename; } @@ -105,7 +101,7 @@ namespace API.Services { using var thumbnail = Image.ThumbnailBuffer(Convert.FromBase64String(encodedImage), ThumbnailWidth); var filename = fileName + ".png"; - thumbnail.WriteToFile(Path.Join(DirectoryService.CoverImageDirectory, fileName + ".png")); + thumbnail.WriteToFile(_directoryService.FileSystem.Path.Join(_directoryService.CoverImageDirectory, fileName + ".png")); return filename; } catch (Exception e) @@ -146,5 +142,4 @@ namespace API.Services { return $"tag{tagId}"; } - } } diff --git a/API/Services/MetadataService.cs b/API/Services/MetadataService.cs index 09161f42a..b6d45c77e 100644 --- a/API/Services/MetadataService.cs +++ b/API/Services/MetadataService.cs @@ -5,329 +5,364 @@ using System.IO; using System.Linq; using System.Threading.Tasks; using API.Comparators; +using API.Data; using API.Data.Metadata; using API.Data.Repositories; +using API.Data.Scanner; using API.Entities; using API.Entities.Enums; using API.Extensions; using API.Helpers; -using API.Interfaces; -using API.Interfaces.Services; using API.SignalR; using Microsoft.AspNetCore.SignalR; using Microsoft.Extensions.Logging; -namespace API.Services +namespace API.Services; + +public interface IMetadataService { - public class MetadataService : IMetadataService + /// + /// Recalculates metadata for all entities in a library. + /// + /// + /// + Task RefreshMetadata(int libraryId, bool forceUpdate = false); + /// + /// Performs a forced refresh of metadata just for a series and it's nested entities + /// + /// + /// + Task RefreshMetadataForSeries(int libraryId, int seriesId, bool forceUpdate = false); +} + +public class MetadataService : IMetadataService +{ + private readonly IUnitOfWork _unitOfWork; + private readonly ILogger _logger; + private readonly IHubContext _messageHub; + private readonly ICacheHelper _cacheHelper; + private readonly IReadingItemService _readingItemService; + private readonly IDirectoryService _directoryService; + private readonly ChapterSortComparerZeroFirst _chapterSortComparerForInChapterSorting = new ChapterSortComparerZeroFirst(); + public MetadataService(IUnitOfWork unitOfWork, ILogger logger, + IHubContext messageHub, ICacheHelper cacheHelper, + IReadingItemService readingItemService, IDirectoryService directoryService) { - private readonly IUnitOfWork _unitOfWork; - private readonly ILogger _logger; - private readonly IArchiveService _archiveService; - private readonly IBookService _bookService; - private readonly IImageService _imageService; - private readonly IHubContext _messageHub; - private readonly ChapterSortComparerZeroFirst _chapterSortComparerForInChapterSorting = new ChapterSortComparerZeroFirst(); + _unitOfWork = unitOfWork; + _logger = logger; + _messageHub = messageHub; + _cacheHelper = cacheHelper; + _readingItemService = readingItemService; + _directoryService = directoryService; + } - public MetadataService(IUnitOfWork unitOfWork, ILogger logger, - IArchiveService archiveService, IBookService bookService, IImageService imageService, IHubContext messageHub) - { - _unitOfWork = unitOfWork; - _logger = logger; - _archiveService = archiveService; - _bookService = bookService; - _imageService = imageService; - _messageHub = messageHub; - } - - /// - /// Determines whether an entity should regenerate cover image. - /// - /// If a cover image is locked but the underlying file has been deleted, this will allow regenerating. - /// - /// - /// - /// - /// Directory where cover images are. Defaults to - /// - public static bool ShouldUpdateCoverImage(string coverImage, MangaFile firstFile, bool forceUpdate = false, - bool isCoverLocked = false, string coverImageDirectory = null) - { - if (string.IsNullOrEmpty(coverImageDirectory)) - { - coverImageDirectory = DirectoryService.CoverImageDirectory; - } - - var fileExists = File.Exists(Path.Join(coverImageDirectory, coverImage)); - if (isCoverLocked && fileExists) return false; - if (forceUpdate) return true; - return (firstFile != null && firstFile.HasFileBeenModified()) || !HasCoverImage(coverImage, fileExists); - } - - - private static bool HasCoverImage(string coverImage) - { - return HasCoverImage(coverImage, File.Exists(coverImage)); - } - - private static bool HasCoverImage(string coverImage, bool fileExists) - { - return !string.IsNullOrEmpty(coverImage) && fileExists; - } - - private string GetCoverImage(MangaFile file, int volumeId, int chapterId) - { - file.UpdateLastModified(); - switch (file.Format) - { - case MangaFormat.Pdf: - case MangaFormat.Epub: - return _bookService.GetCoverImage(file.FilePath, ImageService.GetChapterFormat(chapterId, volumeId)); - case MangaFormat.Image: - var coverImage = _imageService.GetCoverFile(file); - return _imageService.GetCoverImage(coverImage, ImageService.GetChapterFormat(chapterId, volumeId)); - case MangaFormat.Archive: - return _archiveService.GetCoverImage(file.FilePath, ImageService.GetChapterFormat(chapterId, volumeId)); - default: - return string.Empty; - } - - } - - /// - /// Updates the metadata for a Chapter - /// - /// - /// Force updating cover image even if underlying file has not been modified or chapter already has a cover image - public bool UpdateMetadata(Chapter chapter, bool forceUpdate) - { - var firstFile = chapter.Files.OrderBy(x => x.Chapter).FirstOrDefault(); - - if (ShouldUpdateCoverImage(chapter.CoverImage, firstFile, forceUpdate, chapter.CoverImageLocked)) - { - _logger.LogDebug("[MetadataService] Generating cover image for {File}", firstFile?.FilePath); - chapter.CoverImage = GetCoverImage(firstFile, chapter.VolumeId, chapter.Id); - return true; - } + /// + /// Updates the metadata for a Chapter + /// + /// + /// Force updating cover image even if underlying file has not been modified or chapter already has a cover image + private bool UpdateChapterCoverImage(Chapter chapter, bool forceUpdate) + { + var firstFile = chapter.Files.OrderBy(x => x.Chapter).FirstOrDefault(); + if (!_cacheHelper.ShouldUpdateCoverImage(_directoryService.FileSystem.Path.Join(_directoryService.CoverImageDirectory, chapter.CoverImage), firstFile, chapter.Created, forceUpdate, chapter.CoverImageLocked)) return false; - } - /// - /// Updates the metadata for a Volume - /// - /// - /// Force updating cover image even if underlying file has not been modified or chapter already has a cover image - public bool UpdateMetadata(Volume volume, bool forceUpdate) + if (firstFile == null) return false; + + _logger.LogDebug("[MetadataService] Generating cover image for {File}", firstFile?.FilePath); + chapter.CoverImage = _readingItemService.GetCoverImage(firstFile.FilePath, ImageService.GetChapterFormat(chapter.Id, chapter.VolumeId), firstFile.Format); + + return true; + } + + private void UpdateChapterLastModified(Chapter chapter, bool forceUpdate) + { + var firstFile = chapter.Files.OrderBy(x => x.Chapter).FirstOrDefault(); + if (firstFile == null || _cacheHelper.HasFileNotChangedSinceCreationOrLastScan(chapter, forceUpdate, firstFile)) return; + + firstFile.UpdateLastModified(); + } + + /// + /// Updates the cover image for a Volume + /// + /// + /// Force updating cover image even if underlying file has not been modified or chapter already has a cover image + private bool UpdateVolumeCoverImage(Volume volume, bool forceUpdate) + { + // We need to check if Volume coverImage matches first chapters if forceUpdate is false + if (volume == null || !_cacheHelper.ShouldUpdateCoverImage( + _directoryService.FileSystem.Path.Join(_directoryService.CoverImageDirectory, volume.CoverImage), + null, volume.Created, forceUpdate)) return false; + + volume.Chapters ??= new List(); + var firstChapter = volume.Chapters.OrderBy(x => double.Parse(x.Number), _chapterSortComparerForInChapterSorting).FirstOrDefault(); + if (firstChapter == null) return false; + + volume.CoverImage = firstChapter.CoverImage; + return true; + } + + /// + /// Updates cover image for Series + /// + /// + /// Force updating cover image even if underlying file has not been modified or chapter already has a cover image + private void UpdateSeriesCoverImage(Series series, bool forceUpdate) + { + if (series == null) return; + + if (!_cacheHelper.ShouldUpdateCoverImage(_directoryService.FileSystem.Path.Join(_directoryService.CoverImageDirectory, series.CoverImage), + null, series.Created, forceUpdate, series.CoverImageLocked)) + return; + + series.Volumes ??= new List(); + var firstCover = series.Volumes.GetCoverImage(series.Format); + string coverImage = null; + if (firstCover == null && series.Volumes.Any()) { - // We need to check if Volume coverImage matches first chapters if forceUpdate is false - if (volume == null || !ShouldUpdateCoverImage(volume.CoverImage, null, forceUpdate)) return false; - - volume.Chapters ??= new List(); - var firstChapter = volume.Chapters.OrderBy(x => double.Parse(x.Number), _chapterSortComparerForInChapterSorting).FirstOrDefault(); - if (firstChapter == null) return false; - - volume.CoverImage = firstChapter.CoverImage; - return true; - } - - /// - /// Updates metadata for Series - /// - /// - /// Force updating cover image even if underlying file has not been modified or chapter already has a cover image - public bool UpdateMetadata(Series series, bool forceUpdate) - { - var madeUpdate = false; - if (series == null) return false; - - // NOTE: This will fail if we replace the cover of the first volume on a first scan. Because the series will already have a cover image - if (ShouldUpdateCoverImage(series.CoverImage, null, forceUpdate, series.CoverImageLocked)) + // If firstCover is null and one volume, the whole series is Chapters under Vol 0. + if (series.Volumes.Count == 1) { - series.Volumes ??= new List(); - var firstCover = series.Volumes.GetCoverImage(series.Format); - string coverImage = null; - if (firstCover == null && series.Volumes.Any()) - { - // If firstCover is null and one volume, the whole series is Chapters under Vol 0. - if (series.Volumes.Count == 1) - { - coverImage = series.Volumes[0].Chapters.OrderBy(c => double.Parse(c.Number), _chapterSortComparerForInChapterSorting) - .FirstOrDefault(c => !c.IsSpecial)?.CoverImage; - madeUpdate = true; - } - - if (!HasCoverImage(coverImage)) - { - coverImage = series.Volumes[0].Chapters.OrderBy(c => double.Parse(c.Number), _chapterSortComparerForInChapterSorting) - .FirstOrDefault()?.CoverImage; - madeUpdate = true; - } - } - series.CoverImage = firstCover?.CoverImage ?? coverImage; + coverImage = series.Volumes[0].Chapters.OrderBy(c => double.Parse(c.Number), _chapterSortComparerForInChapterSorting) + .FirstOrDefault(c => !c.IsSpecial)?.CoverImage; } - return UpdateSeriesSummary(series, forceUpdate) || madeUpdate ; - } - - private bool UpdateSeriesSummary(Series series, bool forceUpdate) - { - // NOTE: This can be problematic when the file changes and a summary already exists, but it is likely - // better to let the user kick off a refresh metadata on an individual Series than having overhead of - // checking File last write time. - if (!string.IsNullOrEmpty(series.Summary) && !forceUpdate) return false; - - var isBook = series.Library.Type == LibraryType.Book; - var firstVolume = series.Volumes.FirstWithChapters(isBook); - var firstChapter = firstVolume?.Chapters.GetFirstChapterWithFiles(); - - var firstFile = firstChapter?.Files.FirstOrDefault(); - if (firstFile == null || (!forceUpdate && !firstFile.HasFileBeenModified())) return false; - if (Parser.Parser.IsPdf(firstFile.FilePath)) return false; - - var comicInfo = GetComicInfo(series.Format, firstFile); - if (string.IsNullOrEmpty(comicInfo?.Summary)) return false; - - series.Summary = comicInfo.Summary; - return true; - } - - private ComicInfo GetComicInfo(MangaFormat format, MangaFile firstFile) - { - if (format is MangaFormat.Archive or MangaFormat.Epub) + if (!_cacheHelper.CoverImageExists(coverImage)) { - return Parser.Parser.IsEpub(firstFile.FilePath) ? _bookService.GetComicInfo(firstFile.FilePath) : _archiveService.GetComicInfo(firstFile.FilePath); + coverImage = series.Volumes[0].Chapters.OrderBy(c => double.Parse(c.Number), _chapterSortComparerForInChapterSorting) + .FirstOrDefault()?.CoverImage; } - - return null; } + series.CoverImage = firstCover?.CoverImage ?? coverImage; + } - /// - /// Refreshes Metadata for a whole library - /// - /// This can be heavy on memory first run - /// - /// Force updating cover image even if underlying file has not been modified or chapter already has a cover image - public async Task RefreshMetadata(int libraryId, bool forceUpdate = false) + /// + /// + /// + /// + /// + private void ProcessSeriesMetadataUpdate(Series series, ICollection allPeople, ICollection allGenres, ICollection allTags, bool forceUpdate) + { + _logger.LogDebug("[MetadataService] Processing series {SeriesName}", series.OriginalName); + try { - var library = await _unitOfWork.LibraryRepository.GetLibraryForIdAsync(libraryId, LibraryIncludes.None); - _logger.LogInformation("[MetadataService] Beginning metadata refresh of {LibraryName}", library.Name); - - var chunkInfo = await _unitOfWork.SeriesRepository.GetChunkInfo(library.Id); - var stopwatch = Stopwatch.StartNew(); - var totalTime = 0L; - _logger.LogInformation("[MetadataService] Refreshing Library {LibraryName}. Total Items: {TotalSize}. Total Chunks: {TotalChunks} with {ChunkSize} size", library.Name, chunkInfo.TotalSize, chunkInfo.TotalChunks, chunkInfo.ChunkSize); - await _messageHub.Clients.All.SendAsync(SignalREvents.RefreshMetadataProgress, - MessageFactory.RefreshMetadataProgressEvent(library.Id, 0F)); - - var i = 0; - for (var chunk = 1; chunk <= chunkInfo.TotalChunks; chunk++, i++) - { - if (chunkInfo.TotalChunks == 0) continue; - totalTime += stopwatch.ElapsedMilliseconds; - stopwatch.Restart(); - _logger.LogInformation("[MetadataService] Processing chunk {ChunkNumber} / {TotalChunks} with size {ChunkSize}. Series ({SeriesStart} - {SeriesEnd}", - chunk, chunkInfo.TotalChunks, chunkInfo.ChunkSize, chunk * chunkInfo.ChunkSize, (chunk + 1) * chunkInfo.ChunkSize); - - var nonLibrarySeries = await _unitOfWork.SeriesRepository.GetFullSeriesForLibraryIdAsync(library.Id, - new UserParams() - { - PageNumber = chunk, - PageSize = chunkInfo.ChunkSize - }); - _logger.LogDebug("[MetadataService] Fetched {SeriesCount} series for refresh", nonLibrarySeries.Count); - - Parallel.ForEach(nonLibrarySeries, series => - { - try - { - _logger.LogDebug("[MetadataService] Processing series {SeriesName}", series.OriginalName); - var volumeUpdated = false; - foreach (var volume in series.Volumes) - { - var chapterUpdated = false; - foreach (var chapter in volume.Chapters) - { - chapterUpdated = UpdateMetadata(chapter, forceUpdate); - } - - volumeUpdated = UpdateMetadata(volume, chapterUpdated || forceUpdate); - } - - UpdateMetadata(series, volumeUpdated || forceUpdate); - } - catch (Exception) - { - /* Swallow exception */ - } - }); - - if (_unitOfWork.HasChanges() && await _unitOfWork.CommitAsync()) - { - _logger.LogInformation( - "[MetadataService] Processed {SeriesStart} - {SeriesEnd} out of {TotalSeries} series in {ElapsedScanTime} milliseconds for {LibraryName}", - chunk * chunkInfo.ChunkSize, (chunk * chunkInfo.ChunkSize) + nonLibrarySeries.Count, chunkInfo.TotalSize, stopwatch.ElapsedMilliseconds, library.Name); - - foreach (var series in nonLibrarySeries) - { - await _messageHub.Clients.All.SendAsync(SignalREvents.RefreshMetadata, MessageFactory.RefreshMetadataEvent(library.Id, series.Id)); - } - } - else - { - _logger.LogInformation( - "[MetadataService] Processed {SeriesStart} - {SeriesEnd} out of {TotalSeries} series in {ElapsedScanTime} milliseconds for {LibraryName}", - chunk * chunkInfo.ChunkSize, (chunk * chunkInfo.ChunkSize) + nonLibrarySeries.Count, chunkInfo.TotalSize, stopwatch.ElapsedMilliseconds, library.Name); - } - var progress = Math.Max(0F, Math.Min(1F, i * 1F / chunkInfo.TotalChunks)); - await _messageHub.Clients.All.SendAsync(SignalREvents.RefreshMetadataProgress, - MessageFactory.RefreshMetadataProgressEvent(library.Id, progress)); - } - - await _messageHub.Clients.All.SendAsync(SignalREvents.RefreshMetadataProgress, - MessageFactory.RefreshMetadataProgressEvent(library.Id, 1F)); - - _logger.LogInformation("[MetadataService] Updated metadata for {SeriesNumber} series in library {LibraryName} in {ElapsedMilliseconds} milliseconds total", chunkInfo.TotalSize, library.Name, totalTime); - } - - - /// - /// Refreshes Metadata for a Series. Will always force updates. - /// - /// - /// - public async Task RefreshMetadataForSeries(int libraryId, int seriesId, bool forceUpdate = false) - { - var sw = Stopwatch.StartNew(); - var series = await _unitOfWork.SeriesRepository.GetFullSeriesForSeriesIdAsync(seriesId); - if (series == null) - { - _logger.LogError("[MetadataService] Series {SeriesId} was not found on Library {LibraryId}", seriesId, libraryId); - return; - } - _logger.LogInformation("[MetadataService] Beginning metadata refresh of {SeriesName}", series.Name); - var volumeUpdated = false; + var volumeIndex = 0; + var firstVolumeUpdated = false; foreach (var volume in series.Volumes) { - var chapterUpdated = false; + var firstChapterUpdated = false; // This only needs to be FirstChapter updated + var index = 0; foreach (var chapter in volume.Chapters) { - chapterUpdated = UpdateMetadata(chapter, forceUpdate); + var chapterUpdated = UpdateChapterCoverImage(chapter, forceUpdate); + // If cover was update, either the file has changed or first scan and we should force a metadata update + UpdateChapterLastModified(chapter, forceUpdate || chapterUpdated); + if (index == 0 && chapterUpdated) + { + firstChapterUpdated = true; + } + + index++; } - volumeUpdated = UpdateMetadata(volume, chapterUpdated || forceUpdate); + var volumeUpdated = UpdateVolumeCoverImage(volume, firstChapterUpdated || forceUpdate); + if (volumeIndex == 0 && volumeUpdated) + { + firstVolumeUpdated = true; + } + volumeIndex++; } - UpdateMetadata(series, volumeUpdated || forceUpdate); - - - if (_unitOfWork.HasChanges() && await _unitOfWork.CommitAsync()) - { - await _messageHub.Clients.All.SendAsync(SignalREvents.RefreshMetadata, MessageFactory.RefreshMetadataEvent(series.LibraryId, series.Id)); - } - - _logger.LogInformation("[MetadataService] Updated metadata for {SeriesName} in {ElapsedMilliseconds} milliseconds", series.Name, sw.ElapsedMilliseconds); + UpdateSeriesCoverImage(series, firstVolumeUpdated || forceUpdate); + } + catch (Exception ex) + { + _logger.LogError(ex, "[MetadataService] There was an exception during updating metadata for {SeriesName} ", series.Name); } } + + + /// + /// Refreshes Metadata for a whole library + /// + /// This can be heavy on memory first run + /// + /// Force updating cover image even if underlying file has not been modified or chapter already has a cover image + public async Task RefreshMetadata(int libraryId, bool forceUpdate = false) + { + var library = await _unitOfWork.LibraryRepository.GetLibraryForIdAsync(libraryId, LibraryIncludes.None); + _logger.LogInformation("[MetadataService] Beginning metadata refresh of {LibraryName}", library.Name); + + var chunkInfo = await _unitOfWork.SeriesRepository.GetChunkInfo(library.Id); + var stopwatch = Stopwatch.StartNew(); + var totalTime = 0L; + _logger.LogInformation("[MetadataService] Refreshing Library {LibraryName}. Total Items: {TotalSize}. Total Chunks: {TotalChunks} with {ChunkSize} size", library.Name, chunkInfo.TotalSize, chunkInfo.TotalChunks, chunkInfo.ChunkSize); + await _messageHub.Clients.All.SendAsync(SignalREvents.RefreshMetadataProgress, + MessageFactory.RefreshMetadataProgressEvent(library.Id, 0F)); + + for (var chunk = 1; chunk <= chunkInfo.TotalChunks; chunk++) + { + if (chunkInfo.TotalChunks == 0) continue; + totalTime += stopwatch.ElapsedMilliseconds; + stopwatch.Restart(); + + _logger.LogInformation("[MetadataService] Processing chunk {ChunkNumber} / {TotalChunks} with size {ChunkSize}. Series ({SeriesStart} - {SeriesEnd}", + chunk, chunkInfo.TotalChunks, chunkInfo.ChunkSize, chunk * chunkInfo.ChunkSize, (chunk + 1) * chunkInfo.ChunkSize); + + var nonLibrarySeries = await _unitOfWork.SeriesRepository.GetFullSeriesForLibraryIdAsync(library.Id, + new UserParams() + { + PageNumber = chunk, + PageSize = chunkInfo.ChunkSize + }); + _logger.LogDebug("[MetadataService] Fetched {SeriesCount} series for refresh", nonLibrarySeries.Count); + + var allPeople = await _unitOfWork.PersonRepository.GetAllPeople(); + var allGenres = await _unitOfWork.GenreRepository.GetAllGenresAsync(); + var allTags = await _unitOfWork.TagRepository.GetAllTagsAsync(); + + + var seriesIndex = 0; + foreach (var series in nonLibrarySeries) + { + try + { + ProcessSeriesMetadataUpdate(series, allPeople, allGenres, allTags, forceUpdate); + } + catch (Exception ex) + { + _logger.LogError(ex, "[MetadataService] There was an exception during metadata refresh for {SeriesName}", series.Name); + } + var index = chunk * seriesIndex; + var progress = Math.Max(0F, Math.Min(1F, index * 1F / chunkInfo.TotalSize)); + + await _messageHub.Clients.All.SendAsync(SignalREvents.RefreshMetadataProgress, + MessageFactory.RefreshMetadataProgressEvent(library.Id, progress)); + seriesIndex++; + } + + await _unitOfWork.CommitAsync(); + foreach (var series in nonLibrarySeries) + { + await _messageHub.Clients.All.SendAsync(SignalREvents.RefreshMetadata, MessageFactory.RefreshMetadataEvent(library.Id, series.Id)); + } + _logger.LogInformation( + "[MetadataService] Processed {SeriesStart} - {SeriesEnd} out of {TotalSeries} series in {ElapsedScanTime} milliseconds for {LibraryName}", + chunk * chunkInfo.ChunkSize, (chunk * chunkInfo.ChunkSize) + nonLibrarySeries.Count, chunkInfo.TotalSize, stopwatch.ElapsedMilliseconds, library.Name); + } + + await _messageHub.Clients.All.SendAsync(SignalREvents.RefreshMetadataProgress, + MessageFactory.RefreshMetadataProgressEvent(library.Id, 1F)); + + await RemoveAbandonedMetadataKeys(); + + + _logger.LogInformation("[MetadataService] Updated metadata for {SeriesNumber} series in library {LibraryName} in {ElapsedMilliseconds} milliseconds total", chunkInfo.TotalSize, library.Name, totalTime); + } + + private async Task RemoveAbandonedMetadataKeys() + { + await _unitOfWork.TagRepository.RemoveAllTagNoLongerAssociated(); + await _unitOfWork.PersonRepository.RemoveAllPeopleNoLongerAssociated(); + await _unitOfWork.GenreRepository.RemoveAllGenreNoLongerAssociated(); + } + + // TODO: I can probably refactor RefreshMetadata and RefreshMetadataForSeries to be the same by utilizing chunk size of 1, so most of the code can be the same. + private async Task PerformScan(Library library, bool forceUpdate, Action action) + { + var chunkInfo = await _unitOfWork.SeriesRepository.GetChunkInfo(library.Id); + var stopwatch = Stopwatch.StartNew(); + var totalTime = 0L; + _logger.LogInformation("[MetadataService] Refreshing Library {LibraryName}. Total Items: {TotalSize}. Total Chunks: {TotalChunks} with {ChunkSize} size", library.Name, chunkInfo.TotalSize, chunkInfo.TotalChunks, chunkInfo.ChunkSize); + await _messageHub.Clients.All.SendAsync(SignalREvents.RefreshMetadataProgress, + MessageFactory.RefreshMetadataProgressEvent(library.Id, 0F)); + + for (var chunk = 1; chunk <= chunkInfo.TotalChunks; chunk++) + { + if (chunkInfo.TotalChunks == 0) continue; + totalTime += stopwatch.ElapsedMilliseconds; + stopwatch.Restart(); + + action(chunk, chunkInfo); + + // _logger.LogInformation("[MetadataService] Processing chunk {ChunkNumber} / {TotalChunks} with size {ChunkSize}. Series ({SeriesStart} - {SeriesEnd}", + // chunk, chunkInfo.TotalChunks, chunkInfo.ChunkSize, chunk * chunkInfo.ChunkSize, (chunk + 1) * chunkInfo.ChunkSize); + // var nonLibrarySeries = await _unitOfWork.SeriesRepository.GetFullSeriesForLibraryIdAsync(library.Id, + // new UserParams() + // { + // PageNumber = chunk, + // PageSize = chunkInfo.ChunkSize + // }); + // _logger.LogDebug("[MetadataService] Fetched {SeriesCount} series for refresh", nonLibrarySeries.Count); + // + // var chapterIds = await _unitOfWork.SeriesRepository.GetChapterIdWithSeriesIdForSeriesAsync(nonLibrarySeries.Select(s => s.Id).ToArray()); + // var allPeople = await _unitOfWork.PersonRepository.GetAllPeople(); + // var allGenres = await _unitOfWork.GenreRepository.GetAllGenres(); + // + // + // var seriesIndex = 0; + // foreach (var series in nonLibrarySeries) + // { + // try + // { + // ProcessSeriesMetadataUpdate(series, chapterIds, allPeople, allGenres, forceUpdate); + // } + // catch (Exception ex) + // { + // _logger.LogError(ex, "[MetadataService] There was an exception during metadata refresh for {SeriesName}", series.Name); + // } + // var index = chunk * seriesIndex; + // var progress = Math.Max(0F, Math.Min(1F, index * 1F / chunkInfo.TotalSize)); + // + // await _messageHub.Clients.All.SendAsync(SignalREvents.RefreshMetadataProgress, + // MessageFactory.RefreshMetadataProgressEvent(library.Id, progress)); + // seriesIndex++; + // } + + await _unitOfWork.CommitAsync(); + } + } + + + + /// + /// Refreshes Metadata for a Series. Will always force updates. + /// + /// + /// + public async Task RefreshMetadataForSeries(int libraryId, int seriesId, bool forceUpdate = true) + { + var sw = Stopwatch.StartNew(); + var series = await _unitOfWork.SeriesRepository.GetFullSeriesForSeriesIdAsync(seriesId); + if (series == null) + { + _logger.LogError("[MetadataService] Series {SeriesId} was not found on Library {LibraryId}", seriesId, libraryId); + return; + } + + await _messageHub.Clients.All.SendAsync(SignalREvents.RefreshMetadataProgress, + MessageFactory.RefreshMetadataProgressEvent(libraryId, 0F)); + + var allPeople = await _unitOfWork.PersonRepository.GetAllPeople(); + var allGenres = await _unitOfWork.GenreRepository.GetAllGenresAsync(); + var allTags = await _unitOfWork.TagRepository.GetAllTagsAsync(); + + ProcessSeriesMetadataUpdate(series, allPeople, allGenres, allTags, forceUpdate); + + await _messageHub.Clients.All.SendAsync(SignalREvents.RefreshMetadataProgress, + MessageFactory.RefreshMetadataProgressEvent(libraryId, 1F)); + + + if (_unitOfWork.HasChanges() && await _unitOfWork.CommitAsync()) + { + await _messageHub.Clients.All.SendAsync(SignalREvents.RefreshMetadata, MessageFactory.RefreshMetadataEvent(series.LibraryId, series.Id)); + } + + await RemoveAbandonedMetadataKeys(); + + _logger.LogInformation("[MetadataService] Updated metadata for {SeriesName} in {ElapsedMilliseconds} milliseconds", series.Name, sw.ElapsedMilliseconds); + } } diff --git a/API/Services/ReaderService.cs b/API/Services/ReaderService.cs new file mode 100644 index 000000000..b9862cf05 --- /dev/null +++ b/API/Services/ReaderService.cs @@ -0,0 +1,326 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using API.Comparators; +using API.Data; +using API.Data.Repositories; +using API.DTOs; +using API.Entities; +using API.Extensions; +using Kavita.Common; +using Microsoft.Extensions.Logging; + +namespace API.Services; + +public interface IReaderService +{ + void MarkChaptersAsRead(AppUser user, int seriesId, IEnumerable chapters); + void MarkChaptersAsUnread(AppUser user, int seriesId, IEnumerable chapters); + Task SaveReadingProgress(ProgressDto progressDto, int userId); + Task CapPageToChapter(int chapterId, int page); + Task GetNextChapterIdAsync(int seriesId, int volumeId, int currentChapterId, int userId); + Task GetPrevChapterIdAsync(int seriesId, int volumeId, int currentChapterId, int userId); +} + +public class ReaderService : IReaderService +{ + private readonly IUnitOfWork _unitOfWork; + private readonly ILogger _logger; + private readonly IDirectoryService _directoryService; + private readonly ICacheService _cacheService; + private readonly ChapterSortComparer _chapterSortComparer = new ChapterSortComparer(); + private readonly ChapterSortComparerZeroFirst _chapterSortComparerForInChapterSorting = new ChapterSortComparerZeroFirst(); + + public ReaderService(IUnitOfWork unitOfWork, ILogger logger, IDirectoryService directoryService, ICacheService cacheService) + { + _unitOfWork = unitOfWork; + _logger = logger; + _directoryService = directoryService; + _cacheService = cacheService; + } + + public static string FormatBookmarkFolderPath(string baseDirectory, int userId, int seriesId, int chapterId) + { + return Parser.Parser.NormalizePath(Path.Join(baseDirectory, $"{userId}", $"{seriesId}", $"{chapterId}")); + } + + /// + /// Marks all Chapters as Read by creating or updating UserProgress rows. Does not commit. + /// + /// + /// + /// + public void MarkChaptersAsRead(AppUser user, int seriesId, IEnumerable chapters) + { + foreach (var chapter in chapters) + { + var userProgress = GetUserProgressForChapter(user, chapter); + + if (userProgress == null) + { + user.Progresses.Add(new AppUserProgress + { + PagesRead = chapter.Pages, + VolumeId = chapter.VolumeId, + SeriesId = seriesId, + ChapterId = chapter.Id + }); + } + else + { + userProgress.PagesRead = chapter.Pages; + userProgress.SeriesId = seriesId; + userProgress.VolumeId = chapter.VolumeId; + } + } + } + + /// + /// Marks all Chapters as Unread by creating or updating UserProgress rows. Does not commit. + /// + /// + /// + /// + public void MarkChaptersAsUnread(AppUser user, int seriesId, IEnumerable chapters) + { + foreach (var chapter in chapters) + { + var userProgress = GetUserProgressForChapter(user, chapter); + + if (userProgress == null) continue; + + userProgress.PagesRead = 0; + userProgress.SeriesId = seriesId; + userProgress.VolumeId = chapter.VolumeId; + } + } + + /// + /// Gets the User Progress for a given Chapter. This will handle any duplicates that might have occured in past versions and will delete them. Does not commit. + /// + /// Must have Progresses populated + /// + /// + private static AppUserProgress GetUserProgressForChapter(AppUser user, Chapter chapter) + { + AppUserProgress userProgress = null; + + if (user.Progresses == null) + { + throw new KavitaException("Progresses must exist on user"); + } + try + { + userProgress = + user.Progresses.SingleOrDefault(x => x.ChapterId == chapter.Id && x.AppUserId == user.Id); + } + catch (Exception) + { + // There is a very rare chance that user progress will duplicate current row. If that happens delete one with less pages + var progresses = user.Progresses.Where(x => x.ChapterId == chapter.Id && x.AppUserId == user.Id).ToList(); + if (progresses.Count > 1) + { + user.Progresses = new List() + { + user.Progresses.First() + }; + userProgress = user.Progresses.First(); + } + } + + return userProgress; + } + + /// + /// Saves progress to DB + /// + /// + /// + /// + public async Task SaveReadingProgress(ProgressDto progressDto, int userId) + { + // Don't let user save past total pages. + progressDto.PageNum = await CapPageToChapter(progressDto.ChapterId, progressDto.PageNum); + + try + { + var userProgress = + await _unitOfWork.AppUserProgressRepository.GetUserProgressAsync(progressDto.ChapterId, userId); + + if (userProgress == null) + { + // Create a user object + var userWithProgress = + await _unitOfWork.UserRepository.GetUserByIdAsync(userId, AppUserIncludes.Progress); + userWithProgress.Progresses ??= new List(); + userWithProgress.Progresses.Add(new AppUserProgress + { + PagesRead = progressDto.PageNum, + VolumeId = progressDto.VolumeId, + SeriesId = progressDto.SeriesId, + ChapterId = progressDto.ChapterId, + BookScrollId = progressDto.BookScrollId, + LastModified = DateTime.Now + }); + _unitOfWork.UserRepository.Update(userWithProgress); + } + else + { + userProgress.PagesRead = progressDto.PageNum; + userProgress.SeriesId = progressDto.SeriesId; + userProgress.VolumeId = progressDto.VolumeId; + userProgress.BookScrollId = progressDto.BookScrollId; + userProgress.LastModified = DateTime.Now; + _unitOfWork.AppUserProgressRepository.Update(userProgress); + } + + if (await _unitOfWork.CommitAsync()) + { + return true; + } + } + catch (Exception exception) + { + _logger.LogError(exception, "Could not save progress"); + await _unitOfWork.RollbackAsync(); + } + + return false; + } + + /// + /// Ensures that the page is within 0 and total pages for a chapter. Makes one DB call. + /// + /// + /// + /// + public async Task CapPageToChapter(int chapterId, int page) + { + var totalPages = await _unitOfWork.ChapterRepository.GetChapterTotalPagesAsync(chapterId); + if (page > totalPages) + { + page = totalPages; + } + + if (page < 0) + { + page = 0; + } + + return page; + } + + /// + /// Tries to find the next logical Chapter + /// + /// + /// V1 → V2 → V3 chapter 0 → V3 chapter 10 → SP 01 → SP 02 + /// + /// + /// + /// + /// + /// -1 if nothing can be found + public async Task GetNextChapterIdAsync(int seriesId, int volumeId, int currentChapterId, int userId) + { + var volumes = (await _unitOfWork.VolumeRepository.GetVolumesDtoAsync(seriesId, userId)).ToList(); + var currentVolume = volumes.Single(v => v.Id == volumeId); + var currentChapter = currentVolume.Chapters.Single(c => c.Id == currentChapterId); + + if (currentVolume.Number == 0) + { + // Handle specials by sorting on their Filename aka Range + var chapterId = GetNextChapterId(currentVolume.Chapters.OrderByNatural(x => x.Range), currentChapter.Number); + if (chapterId > 0) return chapterId; + } + + foreach (var volume in volumes) + { + if (volume.Number == currentVolume.Number && volume.Chapters.Count > 1) + { + // Handle Chapters within current Volume + // In this case, i need 0 first because 0 represents a full volume file. + var chapterId = GetNextChapterId(currentVolume.Chapters.OrderBy(x => double.Parse(x.Number), _chapterSortComparerForInChapterSorting), currentChapter.Number); + if (chapterId > 0) return chapterId; + } + + if (volume.Number != currentVolume.Number + 1) continue; + + // Handle Chapters within next Volume + // ! When selecting the chapter for the next volume, we need to make sure a c0 comes before a c1+ + var chapters = volume.Chapters.OrderBy(x => double.Parse(x.Number), _chapterSortComparer).ToList(); + if (currentChapter.Number.Equals("0") && chapters.Last().Number.Equals("0")) + { + return chapters.Last().Id; + } + + var firstChapter = chapters.FirstOrDefault(); + if (firstChapter == null) return -1; + return firstChapter.Id; + + } + + return -1; + } + /// + /// Tries to find the prev logical Chapter + /// + /// + /// V1 ← V2 ← V3 chapter 0 ← V3 chapter 10 ← SP 01 ← SP 02 + /// + /// + /// + /// + /// + /// -1 if nothing can be found + public async Task GetPrevChapterIdAsync(int seriesId, int volumeId, int currentChapterId, int userId) + { + var volumes = (await _unitOfWork.VolumeRepository.GetVolumesDtoAsync(seriesId, userId)).Reverse().ToList(); + var currentVolume = volumes.Single(v => v.Id == volumeId); + var currentChapter = currentVolume.Chapters.Single(c => c.Id == currentChapterId); + + if (currentVolume.Number == 0) + { + var chapterId = GetNextChapterId(currentVolume.Chapters.OrderByNatural(x => x.Range).Reverse(), currentChapter.Number); + if (chapterId > 0) return chapterId; + } + + foreach (var volume in volumes) + { + if (volume.Number == currentVolume.Number) + { + var chapterId = GetNextChapterId(currentVolume.Chapters.OrderBy(x => double.Parse(x.Number), _chapterSortComparerForInChapterSorting).Reverse(), currentChapter.Number); + if (chapterId > 0) return chapterId; + } + if (volume.Number == currentVolume.Number - 1) + { + var lastChapter = volume.Chapters + .OrderBy(x => double.Parse(x.Number), _chapterSortComparerForInChapterSorting).LastOrDefault(); + if (lastChapter == null) return -1; + return lastChapter.Id; + } + } + return -1; + } + + + private static int GetNextChapterId(IEnumerable chapters, string currentChapterNumber) + { + var next = false; + var chaptersList = chapters.ToList(); + foreach (var chapter in chaptersList) + { + if (next) + { + return chapter.Id; + } + if (currentChapterNumber.Equals(chapter.Number)) next = true; + } + + return -1; + } + + +} diff --git a/API/Services/ReadingItemService.cs b/API/Services/ReadingItemService.cs new file mode 100644 index 000000000..d791efd55 --- /dev/null +++ b/API/Services/ReadingItemService.cs @@ -0,0 +1,141 @@ +using System; +using API.Data.Metadata; +using API.Entities.Enums; +using API.Parser; + +namespace API.Services; + +public interface IReadingItemService +{ + ComicInfo GetComicInfo(string filePath); + int GetNumberOfPages(string filePath, MangaFormat format); + string GetCoverImage(string filePath, string fileName, MangaFormat format); + void Extract(string fileFilePath, string targetDirectory, MangaFormat format, int imageCount = 1); + ParserInfo Parse(string path, string rootPath, LibraryType type); +} + +public class ReadingItemService : IReadingItemService +{ + private readonly IArchiveService _archiveService; + private readonly IBookService _bookService; + private readonly IImageService _imageService; + private readonly IDirectoryService _directoryService; + private readonly DefaultParser _defaultParser; + + public ReadingItemService(IArchiveService archiveService, IBookService bookService, IImageService imageService, IDirectoryService directoryService) + { + _archiveService = archiveService; + _bookService = bookService; + _imageService = imageService; + _directoryService = directoryService; + + _defaultParser = new DefaultParser(directoryService); + } + + /// + /// Gets the ComicInfo for the file if it exists. Null otherewise. + /// + /// Fully qualified path of file + /// + public ComicInfo? GetComicInfo(string filePath) + { + if (Parser.Parser.IsEpub(filePath)) + { + return _bookService.GetComicInfo(filePath); + } + + if (Parser.Parser.IsComicInfoExtension(filePath)) + { + return _archiveService.GetComicInfo(filePath); + } + + return null; + } + + /// + /// + /// + /// + /// + /// + public int GetNumberOfPages(string filePath, MangaFormat format) + { + switch (format) + { + case MangaFormat.Archive: + { + return _archiveService.GetNumberOfPagesFromArchive(filePath); + } + case MangaFormat.Pdf: + case MangaFormat.Epub: + { + return _bookService.GetNumberOfPages(filePath); + } + case MangaFormat.Image: + { + return 1; + } + case MangaFormat.Unknown: + default: + return 0; + } + } + + public string GetCoverImage(string filePath, string fileName, MangaFormat format) + { + if (string.IsNullOrEmpty(filePath) || string.IsNullOrEmpty(fileName)) + { + return string.Empty; + } + + return format switch + { + MangaFormat.Epub => _bookService.GetCoverImage(filePath, fileName, _directoryService.CoverImageDirectory), + MangaFormat.Archive => _archiveService.GetCoverImage(filePath, fileName, _directoryService.CoverImageDirectory), + MangaFormat.Image => _imageService.GetCoverImage(filePath, fileName, _directoryService.CoverImageDirectory), + MangaFormat.Pdf => _bookService.GetCoverImage(filePath, fileName, _directoryService.CoverImageDirectory), + _ => string.Empty + }; + } + + /// + /// Extracts the reading item to the target directory using the appropriate method + /// + /// File to extract + /// Where to extract to. Will be created if does not exist + /// Format of the File + /// If the file is of type image, pass number of files needed. If > 0, will copy the whole directory. + /// + public void Extract(string fileFilePath, string targetDirectory, MangaFormat format, int imageCount = 1) + { + switch (format) + { + case MangaFormat.Pdf: + _bookService.ExtractPdfImages(fileFilePath, targetDirectory); + break; + case MangaFormat.Archive: + _archiveService.ExtractArchive(fileFilePath, targetDirectory); + break; + case MangaFormat.Image: + _imageService.ExtractImages(fileFilePath, targetDirectory, imageCount); + break; + case MangaFormat.Unknown: + case MangaFormat.Epub: + break; + default: + throw new ArgumentOutOfRangeException(nameof(format), format, null); + } + } + + /// + /// Parses information out of a file. If file is a book (epub), it will use book metadata regardless of LibraryType + /// + /// + /// + /// + /// + public ParserInfo Parse(string path, string rootPath, LibraryType type) + { + return Parser.Parser.IsEpub(path) ? _bookService.ParseInfo(path) : _defaultParser.Parse(path, rootPath, type); + } +} diff --git a/API/Services/TaskScheduler.cs b/API/Services/TaskScheduler.cs index 77c745535..9f91bf75c 100644 --- a/API/Services/TaskScheduler.cs +++ b/API/Services/TaskScheduler.cs @@ -1,178 +1,187 @@ using System; -using System.IO; using System.Threading; using System.Threading.Tasks; +using API.Data; using API.Entities.Enums; using API.Helpers.Converters; -using API.Interfaces; -using API.Interfaces.Services; +using API.Services.Tasks; using Hangfire; using Microsoft.Extensions.Logging; -namespace API.Services +namespace API.Services; + +public interface ITaskScheduler { - public class TaskScheduler : ITaskScheduler + Task ScheduleTasks(); + Task ScheduleStatsTasks(); + void ScheduleUpdaterTasks(); + void ScanLibrary(int libraryId, bool forceUpdate = false); + void CleanupChapters(int[] chapterIds); + void RefreshMetadata(int libraryId, bool forceUpdate = true); + void RefreshSeriesMetadata(int libraryId, int seriesId, bool forceUpdate = false); + void ScanSeries(int libraryId, int seriesId, bool forceUpdate = false); + void CancelStatsTasks(); + Task RunStatCollection(); +} +public class TaskScheduler : ITaskScheduler +{ + private readonly ICacheService _cacheService; + private readonly ILogger _logger; + private readonly IScannerService _scannerService; + private readonly IUnitOfWork _unitOfWork; + private readonly IMetadataService _metadataService; + private readonly IBackupService _backupService; + private readonly ICleanupService _cleanupService; + + private readonly IStatsService _statsService; + private readonly IVersionUpdaterService _versionUpdaterService; + private readonly IDirectoryService _directoryService; + + public static BackgroundJobServer Client => new BackgroundJobServer(); + private static readonly Random Rnd = new Random(); + + + public TaskScheduler(ICacheService cacheService, ILogger logger, IScannerService scannerService, + IUnitOfWork unitOfWork, IMetadataService metadataService, IBackupService backupService, + ICleanupService cleanupService, IStatsService statsService, IVersionUpdaterService versionUpdaterService, + IDirectoryService directoryService) { - private readonly ICacheService _cacheService; - private readonly ILogger _logger; - private readonly IScannerService _scannerService; - private readonly IUnitOfWork _unitOfWork; - private readonly IMetadataService _metadataService; - private readonly IBackupService _backupService; - private readonly ICleanupService _cleanupService; + _cacheService = cacheService; + _logger = logger; + _scannerService = scannerService; + _unitOfWork = unitOfWork; + _metadataService = metadataService; + _backupService = backupService; + _cleanupService = cleanupService; + _statsService = statsService; + _versionUpdaterService = versionUpdaterService; + _directoryService = directoryService; + } - private readonly IStatsService _statsService; - private readonly IVersionUpdaterService _versionUpdaterService; + public async Task ScheduleTasks() + { + _logger.LogInformation("Scheduling reoccurring tasks"); - public static BackgroundJobServer Client => new BackgroundJobServer(); - private static readonly Random Rnd = new Random(); - - - public TaskScheduler(ICacheService cacheService, ILogger logger, IScannerService scannerService, - IUnitOfWork unitOfWork, IMetadataService metadataService, IBackupService backupService, - ICleanupService cleanupService, IStatsService statsService, IVersionUpdaterService versionUpdaterService) + var setting = (await _unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.TaskScan)).Value; + if (setting != null) { - _cacheService = cacheService; - _logger = logger; - _scannerService = scannerService; - _unitOfWork = unitOfWork; - _metadataService = metadataService; - _backupService = backupService; - _cleanupService = cleanupService; - _statsService = statsService; - _versionUpdaterService = versionUpdaterService; + var scanLibrarySetting = setting; + _logger.LogDebug("Scheduling Scan Library Task for {Setting}", scanLibrarySetting); + RecurringJob.AddOrUpdate("scan-libraries", () => _scannerService.ScanLibraries(), + () => CronConverter.ConvertToCronNotation(scanLibrarySetting), TimeZoneInfo.Local); + } + else + { + RecurringJob.AddOrUpdate("scan-libraries", () => _scannerService.ScanLibraries(), Cron.Daily, TimeZoneInfo.Local); } - public void ScheduleTasks() + setting = (await _unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.TaskBackup)).Value; + if (setting != null) { - _logger.LogInformation("Scheduling reoccurring tasks"); - - var setting = Task.Run(() => _unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.TaskScan)).GetAwaiter().GetResult().Value; - if (setting != null) - { - var scanLibrarySetting = setting; - _logger.LogDebug("Scheduling Scan Library Task for {Setting}", scanLibrarySetting); - RecurringJob.AddOrUpdate("scan-libraries", () => _scannerService.ScanLibraries(), - () => CronConverter.ConvertToCronNotation(scanLibrarySetting), TimeZoneInfo.Local); - } - else - { - RecurringJob.AddOrUpdate("scan-libraries", () => _scannerService.ScanLibraries(), Cron.Daily, TimeZoneInfo.Local); - } - - setting = Task.Run(() => _unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.TaskBackup)).Result.Value; - if (setting != null) - { - _logger.LogDebug("Scheduling Backup Task for {Setting}", setting); - RecurringJob.AddOrUpdate("backup", () => _backupService.BackupDatabase(), () => CronConverter.ConvertToCronNotation(setting), TimeZoneInfo.Local); - } - else - { - RecurringJob.AddOrUpdate("backup", () => _backupService.BackupDatabase(), Cron.Weekly, TimeZoneInfo.Local); - } - - RecurringJob.AddOrUpdate("cleanup", () => _cleanupService.Cleanup(), Cron.Daily, TimeZoneInfo.Local); - + _logger.LogDebug("Scheduling Backup Task for {Setting}", setting); + RecurringJob.AddOrUpdate("backup", () => _backupService.BackupDatabase(), () => CronConverter.ConvertToCronNotation(setting), TimeZoneInfo.Local); + } + else + { + RecurringJob.AddOrUpdate("backup", () => _backupService.BackupDatabase(), Cron.Weekly, TimeZoneInfo.Local); } - #region StatsTasks + RecurringJob.AddOrUpdate("cleanup", () => _cleanupService.Cleanup(), Cron.Daily, TimeZoneInfo.Local); + RecurringJob.AddOrUpdate("cleanup-db", () => _cleanupService.CleanupDbEntries(), Cron.Daily, TimeZoneInfo.Local); + } + + #region StatsTasks - public async Task ScheduleStatsTasks() + public async Task ScheduleStatsTasks() + { + var allowStatCollection = (await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).AllowStatCollection; + if (!allowStatCollection) { - var allowStatCollection = (await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).AllowStatCollection; - if (!allowStatCollection) - { - _logger.LogDebug("User has opted out of stat collection, not registering tasks"); - return; - } - - _logger.LogDebug("Scheduling stat collection daily"); - RecurringJob.AddOrUpdate("report-stats", () => _statsService.Send(), Cron.Daily(Rnd.Next(0, 22)), TimeZoneInfo.Local); + _logger.LogDebug("User has opted out of stat collection, not registering tasks"); + return; } - public void CancelStatsTasks() + _logger.LogDebug("Scheduling stat collection daily"); + RecurringJob.AddOrUpdate("report-stats", () => _statsService.Send(), Cron.Daily(Rnd.Next(0, 22)), TimeZoneInfo.Local); + } + + public void CancelStatsTasks() + { + _logger.LogDebug("Cancelling/Removing StatsTasks"); + + RecurringJob.RemoveIfExists("report-stats"); + } + + /// + /// First time run stat collection. Executes immediately on a background thread. Does not block. + /// + public async Task RunStatCollection() + { + var allowStatCollection = (await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).AllowStatCollection; + if (!allowStatCollection) { - _logger.LogDebug("Cancelling/Removing StatsTasks"); - - RecurringJob.RemoveIfExists("report-stats"); + _logger.LogDebug("User has opted out of stat collection, not sending stats"); + return; } + BackgroundJob.Enqueue(() => _statsService.Send()); + } - /// - /// First time run stat collection. Executes immediately on a background thread. Does not block. - /// - public async Task RunStatCollection() - { - var allowStatCollection = (await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).AllowStatCollection; - if (!allowStatCollection) - { - _logger.LogDebug("User has opted out of stat collection, not sending stats"); - return; - } - BackgroundJob.Enqueue(() => _statsService.Send()); - } + #endregion - #endregion + #region UpdateTasks - #region UpdateTasks + public void ScheduleUpdaterTasks() + { + _logger.LogInformation("Scheduling Auto-Update tasks"); + // Schedule update check between noon and 6pm local time + RecurringJob.AddOrUpdate("check-updates", () => CheckForUpdate(), Cron.Daily(Rnd.Next(12, 18)), TimeZoneInfo.Local); + } + #endregion - public void ScheduleUpdaterTasks() - { - _logger.LogInformation("Scheduling Auto-Update tasks"); - // Schedule update check between noon and 6pm local time - RecurringJob.AddOrUpdate("check-updates", () => _versionUpdaterService.CheckForUpdate(), Cron.Daily(Rnd.Next(12, 18)), TimeZoneInfo.Local); - } - #endregion + public void ScanLibrary(int libraryId, bool forceUpdate = false) + { + _logger.LogInformation("Enqueuing library scan for: {LibraryId}", libraryId); + BackgroundJob.Enqueue(() => _scannerService.ScanLibrary(libraryId)); + // When we do a scan, force cache to re-unpack in case page numbers change + BackgroundJob.Enqueue(() => _cleanupService.CleanupCacheDirectory()); + } - public void ScanLibrary(int libraryId, bool forceUpdate = false) - { - _logger.LogInformation("Enqueuing library scan for: {LibraryId}", libraryId); - BackgroundJob.Enqueue(() => _scannerService.ScanLibrary(libraryId)); - // When we do a scan, force cache to re-unpack in case page numbers change - BackgroundJob.Enqueue(() => _cleanupService.CleanupCacheDirectory()); - } + public void CleanupChapters(int[] chapterIds) + { + BackgroundJob.Enqueue(() => _cacheService.CleanupChapters(chapterIds)); + } - public void CleanupChapters(int[] chapterIds) - { - BackgroundJob.Enqueue(() => _cacheService.CleanupChapters(chapterIds)); - } + public void RefreshMetadata(int libraryId, bool forceUpdate = true) + { + _logger.LogInformation("Enqueuing library metadata refresh for: {LibraryId}", libraryId); + BackgroundJob.Enqueue(() => _metadataService.RefreshMetadata(libraryId, forceUpdate)); + } - public void RefreshMetadata(int libraryId, bool forceUpdate = true) - { - _logger.LogInformation("Enqueuing library metadata refresh for: {LibraryId}", libraryId); - BackgroundJob.Enqueue(() => _metadataService.RefreshMetadata(libraryId, forceUpdate)); - } + public void RefreshSeriesMetadata(int libraryId, int seriesId, bool forceUpdate = true) + { + _logger.LogInformation("Enqueuing series metadata refresh for: {SeriesId}", seriesId); + BackgroundJob.Enqueue(() => _metadataService.RefreshMetadataForSeries(libraryId, seriesId, forceUpdate)); + } - public void CleanupTemp() - { - BackgroundJob.Enqueue(() => DirectoryService.ClearDirectory(DirectoryService.TempDirectory)); - } + public void ScanSeries(int libraryId, int seriesId, bool forceUpdate = false) + { + _logger.LogInformation("Enqueuing series scan for: {SeriesId}", seriesId); + BackgroundJob.Enqueue(() => _scannerService.ScanSeries(libraryId, seriesId, CancellationToken.None)); + } - public void RefreshSeriesMetadata(int libraryId, int seriesId, bool forceUpdate = true) - { - _logger.LogInformation("Enqueuing series metadata refresh for: {SeriesId}", seriesId); - BackgroundJob.Enqueue(() => _metadataService.RefreshMetadataForSeries(libraryId, seriesId, forceUpdate)); - } + public void BackupDatabase() + { + BackgroundJob.Enqueue(() => _backupService.BackupDatabase()); + } - public void ScanSeries(int libraryId, int seriesId, bool forceUpdate = false) - { - _logger.LogInformation("Enqueuing series scan for: {SeriesId}", seriesId); - BackgroundJob.Enqueue(() => _scannerService.ScanSeries(libraryId, seriesId, CancellationToken.None)); - } - - public void BackupDatabase() - { - BackgroundJob.Enqueue(() => _backupService.BackupDatabase()); - } - - /// - /// Not an external call. Only public so that we can call this for a Task - /// - // ReSharper disable once MemberCanBePrivate.Global - public async Task CheckForUpdate() - { - var update = await _versionUpdaterService.CheckForUpdate(); - await _versionUpdaterService.PushUpdate(update); - } + /// + /// Not an external call. Only public so that we can call this for a Task + /// + // ReSharper disable once MemberCanBePrivate.Global + public async Task CheckForUpdate() + { + var update = await _versionUpdaterService.CheckForUpdate(); + await _versionUpdaterService.PushUpdate(update); } } diff --git a/API/Services/Tasks/BackupService.cs b/API/Services/Tasks/BackupService.cs index 04cb279ec..12f4f1083 100644 --- a/API/Services/Tasks/BackupService.cs +++ b/API/Services/Tasks/BackupService.cs @@ -4,204 +4,195 @@ using System.IO; using System.IO.Compression; using System.Linq; using System.Threading.Tasks; +using API.Data; using API.Entities.Enums; using API.Extensions; -using API.Interfaces; -using API.Interfaces.Services; using API.SignalR; using Hangfire; using Microsoft.AspNetCore.SignalR; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; -namespace API.Services.Tasks +namespace API.Services.Tasks; + +public interface IBackupService { - public class BackupService : IBackupService + Task BackupDatabase(); + /// + /// Returns a list of full paths of the logs files detailed in . + /// + /// + /// + /// + IEnumerable GetLogFiles(int maxRollingFiles, string logFileName); +} +public class BackupService : IBackupService +{ + private readonly IUnitOfWork _unitOfWork; + private readonly ILogger _logger; + private readonly IDirectoryService _directoryService; + private readonly IHubContext _messageHub; + + private readonly IList _backupFiles; + + public BackupService(ILogger logger, IUnitOfWork unitOfWork, + IDirectoryService directoryService, IConfiguration config, IHubContext messageHub) { - private readonly IUnitOfWork _unitOfWork; - private readonly ILogger _logger; - private readonly IDirectoryService _directoryService; - private readonly IHubContext _messageHub; + _unitOfWork = unitOfWork; + _logger = logger; + _directoryService = directoryService; + _messageHub = messageHub; - private readonly IList _backupFiles; + var maxRollingFiles = config.GetMaxRollingFiles(); + var loggingSection = config.GetLoggingFileName(); + var files = GetLogFiles(maxRollingFiles, loggingSection); - public BackupService(IUnitOfWork unitOfWork, ILogger logger, - IDirectoryService directoryService, IConfiguration config, IHubContext messageHub) + + _backupFiles = new List() { - _unitOfWork = unitOfWork; - _logger = logger; - _directoryService = directoryService; - _messageHub = messageHub; + "appsettings.json", + "Hangfire.db", // This is not used atm + "Hangfire-log.db", // This is not used atm + "kavita.db", + "kavita.db-shm", // This wont always be there + "kavita.db-wal" // This wont always be there + }; - var maxRollingFiles = config.GetMaxRollingFiles(); - var loggingSection = config.GetLoggingFileName(); - var files = LogFiles(maxRollingFiles, loggingSection); - - - _backupFiles = new List() - { - "appsettings.json", - "Hangfire.db", // This is not used atm - "Hangfire-log.db", // This is not used atm - "kavita.db", - "kavita.db-shm", // This wont always be there - "kavita.db-wal" // This wont always be there - }; - - foreach (var file in files.Select(f => (new FileInfo(f)).Name).ToList()) - { - _backupFiles.Add(file); - } + foreach (var file in files.Select(f => (_directoryService.FileSystem.FileInfo.FromFileName(f)).Name).ToList()) + { + _backupFiles.Add(file); } - public IEnumerable LogFiles(int maxRollingFiles, string logFileName) - { - var multipleFileRegex = maxRollingFiles > 0 ? @"\d*" : string.Empty; - var fi = new FileInfo(logFileName); - - var files = maxRollingFiles > 0 - ? DirectoryService.GetFiles(DirectoryService.LogDirectory, $@"{Path.GetFileNameWithoutExtension(fi.Name)}{multipleFileRegex}\.log") - : new[] {"kavita.log"}; - return files; - } - - /// - /// Will backup anything that needs to be backed up. This includes logs, setting files, bare minimum cover images (just locked and first cover). - /// - [AutomaticRetry(Attempts = 3, LogEvents = false, OnAttemptsExceeded = AttemptsExceededAction.Fail)] - public async Task BackupDatabase() - { - _logger.LogInformation("Beginning backup of Database at {BackupTime}", DateTime.Now); - var backupDirectory = Task.Run(() => _unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.BackupDirectory)).Result.Value; - - _logger.LogDebug("Backing up to {BackupDirectory}", backupDirectory); - if (!DirectoryService.ExistOrCreate(backupDirectory)) - { - _logger.LogCritical("Could not write to {BackupDirectory}; aborting backup", backupDirectory); - return; - } - - await SendProgress(0F); - - var dateString = $"{DateTime.Now.ToShortDateString()}_{DateTime.Now.ToLongTimeString()}".Replace("/", "_").Replace(":", "_"); - var zipPath = Path.Join(backupDirectory, $"kavita_backup_{dateString}.zip"); - - if (File.Exists(zipPath)) - { - _logger.LogInformation("{ZipFile} already exists, aborting", zipPath); - return; - } - - var tempDirectory = Path.Join(DirectoryService.TempDirectory, dateString); - DirectoryService.ExistOrCreate(tempDirectory); - DirectoryService.ClearDirectory(tempDirectory); - - _directoryService.CopyFilesToDirectory( - _backupFiles.Select(file => Path.Join(DirectoryService.ConfigDirectory, file)).ToList(), tempDirectory); - - await SendProgress(0.25F); - - await CopyCoverImagesToBackupDirectory(tempDirectory); - - await SendProgress(0.75F); - - try - { - ZipFile.CreateFromDirectory(tempDirectory, zipPath); - } - catch (AggregateException ex) - { - _logger.LogError(ex, "There was an issue when archiving library backup"); - } - - DirectoryService.ClearAndDeleteDirectory(tempDirectory); - _logger.LogInformation("Database backup completed"); - await SendProgress(1F); - } - - private async Task CopyCoverImagesToBackupDirectory(string tempDirectory) - { - var outputTempDir = Path.Join(tempDirectory, "covers"); - DirectoryService.ExistOrCreate(outputTempDir); - - try - { - var seriesImages = await _unitOfWork.SeriesRepository.GetLockedCoverImagesAsync(); - _directoryService.CopyFilesToDirectory( - seriesImages.Select(s => Path.Join(DirectoryService.CoverImageDirectory, s)), outputTempDir); - - var collectionTags = await _unitOfWork.CollectionTagRepository.GetAllCoverImagesAsync(); - _directoryService.CopyFilesToDirectory( - collectionTags.Select(s => Path.Join(DirectoryService.CoverImageDirectory, s)), outputTempDir); - - var chapterImages = await _unitOfWork.ChapterRepository.GetCoverImagesForLockedChaptersAsync(); - _directoryService.CopyFilesToDirectory( - chapterImages.Select(s => Path.Join(DirectoryService.CoverImageDirectory, s)), outputTempDir); - } - catch (IOException) - { - // Swallow exception. This can be a duplicate cover being copied as chapter and volumes can share same file. - } - - if (!DirectoryService.GetFiles(outputTempDir).Any()) - { - DirectoryService.ClearAndDeleteDirectory(outputTempDir); - } - } - - private async Task SendProgress(float progress) - { - await _messageHub.Clients.All.SendAsync(SignalREvents.BackupDatabaseProgress, - MessageFactory.BackupDatabaseProgressEvent(progress)); - } - - /// - /// Removes Database backups older than 30 days. If all backups are older than 30 days, the latest is kept. - /// - public void CleanupBackups() - { - const int dayThreshold = 30; - _logger.LogInformation("Beginning cleanup of Database backups at {Time}", DateTime.Now); - var backupDirectory = Task.Run(() => _unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.BackupDirectory)).Result.Value; - if (!_directoryService.Exists(backupDirectory)) return; - var deltaTime = DateTime.Today.Subtract(TimeSpan.FromDays(dayThreshold)); - var allBackups = DirectoryService.GetFiles(backupDirectory).ToList(); - var expiredBackups = allBackups.Select(filename => new FileInfo(filename)) - .Where(f => f.CreationTime > deltaTime) - .ToList(); - if (expiredBackups.Count == allBackups.Count) - { - _logger.LogInformation("All expired backups are older than {Threshold} days. Removing all but last backup", dayThreshold); - var toDelete = expiredBackups.OrderByDescending(f => f.CreationTime).ToList(); - for (var i = 1; i < toDelete.Count; i++) - { - try - { - toDelete[i].Delete(); - } - catch (Exception ex) - { - _logger.LogError(ex, "There was an issue deleting {FileName}", toDelete[i].Name); - } - } - } - else - { - foreach (var file in expiredBackups) - { - try - { - file.Delete(); - } - catch (Exception ex) - { - _logger.LogError(ex, "There was an issue deleting {FileName}", file.Name); - } - } - - } - _logger.LogInformation("Finished cleanup of Database backups at {Time}", DateTime.Now); - } } + + public IEnumerable GetLogFiles(int maxRollingFiles, string logFileName) + { + var multipleFileRegex = maxRollingFiles > 0 ? @"\d*" : string.Empty; + var fi = _directoryService.FileSystem.FileInfo.FromFileName(logFileName); + + var files = maxRollingFiles > 0 + ? _directoryService.GetFiles(_directoryService.LogDirectory, + $@"{_directoryService.FileSystem.Path.GetFileNameWithoutExtension(fi.Name)}{multipleFileRegex}\.log") + : new[] {"kavita.log"}; + return files; + } + + /// + /// Will backup anything that needs to be backed up. This includes logs, setting files, bare minimum cover images (just locked and first cover). + /// + [AutomaticRetry(Attempts = 3, LogEvents = false, OnAttemptsExceeded = AttemptsExceededAction.Fail)] + public async Task BackupDatabase() + { + _logger.LogInformation("Beginning backup of Database at {BackupTime}", DateTime.Now); + var backupDirectory = (await _unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.BackupDirectory)).Value; + + _logger.LogDebug("Backing up to {BackupDirectory}", backupDirectory); + if (!_directoryService.ExistOrCreate(backupDirectory)) + { + _logger.LogCritical("Could not write to {BackupDirectory}; aborting backup", backupDirectory); + return; + } + + await SendProgress(0F); + + var dateString = $"{DateTime.Now.ToShortDateString()}_{DateTime.Now.ToLongTimeString()}".Replace("/", "_").Replace(":", "_"); + var zipPath = _directoryService.FileSystem.Path.Join(backupDirectory, $"kavita_backup_{dateString}.zip"); + + if (File.Exists(zipPath)) + { + _logger.LogInformation("{ZipFile} already exists, aborting", zipPath); + return; + } + + var tempDirectory = Path.Join(_directoryService.TempDirectory, dateString); + _directoryService.ExistOrCreate(tempDirectory); + _directoryService.ClearDirectory(tempDirectory); + + _directoryService.CopyFilesToDirectory( + _backupFiles.Select(file => _directoryService.FileSystem.Path.Join(_directoryService.ConfigDirectory, file)).ToList(), tempDirectory); + + await SendProgress(0.25F); + + await CopyCoverImagesToBackupDirectory(tempDirectory); + + await SendProgress(0.5F); + + await CopyBookmarksToBackupDirectory(tempDirectory); + + await SendProgress(0.75F); + + try + { + ZipFile.CreateFromDirectory(tempDirectory, zipPath); + } + catch (AggregateException ex) + { + _logger.LogError(ex, "There was an issue when archiving library backup"); + } + + _directoryService.ClearAndDeleteDirectory(tempDirectory); + _logger.LogInformation("Database backup completed"); + await SendProgress(1F); + } + + private async Task CopyCoverImagesToBackupDirectory(string tempDirectory) + { + var outputTempDir = Path.Join(tempDirectory, "covers"); + _directoryService.ExistOrCreate(outputTempDir); + + try + { + var seriesImages = await _unitOfWork.SeriesRepository.GetLockedCoverImagesAsync(); + _directoryService.CopyFilesToDirectory( + seriesImages.Select(s => _directoryService.FileSystem.Path.Join(_directoryService.CoverImageDirectory, s)), outputTempDir); + + var collectionTags = await _unitOfWork.CollectionTagRepository.GetAllCoverImagesAsync(); + _directoryService.CopyFilesToDirectory( + collectionTags.Select(s => _directoryService.FileSystem.Path.Join(_directoryService.CoverImageDirectory, s)), outputTempDir); + + var chapterImages = await _unitOfWork.ChapterRepository.GetCoverImagesForLockedChaptersAsync(); + _directoryService.CopyFilesToDirectory( + chapterImages.Select(s => _directoryService.FileSystem.Path.Join(_directoryService.CoverImageDirectory, s)), outputTempDir); + } + catch (IOException) + { + // Swallow exception. This can be a duplicate cover being copied as chapter and volumes can share same file. + } + + if (!_directoryService.GetFiles(outputTempDir, searchOption: SearchOption.AllDirectories).Any()) + { + _directoryService.ClearAndDeleteDirectory(outputTempDir); + } + } + + private async Task CopyBookmarksToBackupDirectory(string tempDirectory) + { + var bookmarkDirectory = + (await _unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.BookmarkDirectory)).Value; + + var outputTempDir = Path.Join(tempDirectory, "bookmarks"); + _directoryService.ExistOrCreate(outputTempDir); + + try + { + _directoryService.CopyDirectoryToDirectory(bookmarkDirectory, outputTempDir); + } + catch (IOException) + { + // Swallow exception. + } + + if (!_directoryService.GetFiles(outputTempDir, searchOption: SearchOption.AllDirectories).Any()) + { + _directoryService.ClearAndDeleteDirectory(outputTempDir); + } + } + + private async Task SendProgress(float progress) + { + await _messageHub.Clients.All.SendAsync(SignalREvents.BackupDatabaseProgress, + MessageFactory.BackupDatabaseProgressEvent(progress)); + } + } diff --git a/API/Services/Tasks/CleanupService.cs b/API/Services/Tasks/CleanupService.cs index 1ecc9cec5..d31e50a22 100644 --- a/API/Services/Tasks/CleanupService.cs +++ b/API/Services/Tasks/CleanupService.cs @@ -1,7 +1,9 @@ -using System.IO; +using System; +using System.IO; +using System.Linq; using System.Threading.Tasks; -using API.Interfaces; -using API.Interfaces.Services; +using API.Data; +using API.Entities.Enums; using API.SignalR; using Hangfire; using Microsoft.AspNetCore.SignalR; @@ -9,32 +11,37 @@ using Microsoft.Extensions.Logging; namespace API.Services.Tasks { + public interface ICleanupService + { + Task Cleanup(); + Task CleanupDbEntries(); + void CleanupCacheDirectory(); + Task DeleteSeriesCoverImages(); + Task DeleteChapterCoverImages(); + Task DeleteTagCoverImages(); + Task CleanupBackups(); + Task CleanupBookmarks(); + } /// /// Cleans up after operations on reoccurring basis /// public class CleanupService : ICleanupService { - private readonly ICacheService _cacheService; private readonly ILogger _logger; - private readonly IBackupService _backupService; private readonly IUnitOfWork _unitOfWork; private readonly IHubContext _messageHub; + private readonly IDirectoryService _directoryService; - public CleanupService(ICacheService cacheService, ILogger logger, - IBackupService backupService, IUnitOfWork unitOfWork, IHubContext messageHub) + public CleanupService(ILogger logger, + IUnitOfWork unitOfWork, IHubContext messageHub, + IDirectoryService directoryService) { - _cacheService = cacheService; _logger = logger; - _backupService = backupService; _unitOfWork = unitOfWork; _messageHub = messageHub; + _directoryService = directoryService; } - public void CleanupCacheDirectory() - { - _logger.LogInformation("Cleaning cache directory"); - _cacheService.Cleanup(); - } ///
    /// Cleans up Temp, cache, deleted cover images, and old database backups @@ -45,12 +52,12 @@ namespace API.Services.Tasks _logger.LogInformation("Starting Cleanup"); await SendProgress(0F); _logger.LogInformation("Cleaning temp directory"); - DirectoryService.ClearDirectory(DirectoryService.TempDirectory); + _directoryService.ClearDirectory(_directoryService.TempDirectory); await SendProgress(0.1F); CleanupCacheDirectory(); await SendProgress(0.25F); _logger.LogInformation("Cleaning old database backups"); - _backupService.CleanupBackups(); + await CleanupBackups(); await SendProgress(0.50F); _logger.LogInformation("Cleaning deleted cover images"); await DeleteSeriesCoverImages(); @@ -58,49 +65,137 @@ namespace API.Services.Tasks await DeleteChapterCoverImages(); await SendProgress(0.7F); await DeleteTagCoverImages(); + await SendProgress(0.8F); + _logger.LogInformation("Cleaning old bookmarks"); + await CleanupBookmarks(); await SendProgress(1F); _logger.LogInformation("Cleanup finished"); } + /// + /// Cleans up abandon rows in the DB + /// + public async Task CleanupDbEntries() + { + await _unitOfWork.AppUserProgressRepository.CleanupAbandonedChapters(); + await _unitOfWork.PersonRepository.RemoveAllPeopleNoLongerAssociated(); + await _unitOfWork.GenreRepository.RemoveAllGenreNoLongerAssociated(); + await _unitOfWork.CollectionTagRepository.RemoveTagsWithoutSeries(); + } + private async Task SendProgress(float progress) { await _messageHub.Clients.All.SendAsync(SignalREvents.CleanupProgress, MessageFactory.CleanupProgressEvent(progress)); } - private async Task DeleteSeriesCoverImages() + /// + /// Removes all series images that are not in the database. They must follow filename pattern. + /// + public async Task DeleteSeriesCoverImages() { var images = await _unitOfWork.SeriesRepository.GetAllCoverImagesAsync(); - var files = DirectoryService.GetFiles(DirectoryService.CoverImageDirectory, ImageService.SeriesCoverImageRegex); - foreach (var file in files) - { - if (images.Contains(Path.GetFileName(file))) continue; - File.Delete(file); - - } + var files = _directoryService.GetFiles(_directoryService.CoverImageDirectory, ImageService.SeriesCoverImageRegex); + _directoryService.DeleteFiles(files.Where(file => !images.Contains(_directoryService.FileSystem.Path.GetFileName(file)))); } - private async Task DeleteChapterCoverImages() + /// + /// Removes all chapter/volume images that are not in the database. They must follow filename pattern. + /// + public async Task DeleteChapterCoverImages() { var images = await _unitOfWork.ChapterRepository.GetAllCoverImagesAsync(); - var files = DirectoryService.GetFiles(DirectoryService.CoverImageDirectory, ImageService.ChapterCoverImageRegex); - foreach (var file in files) - { - if (images.Contains(Path.GetFileName(file))) continue; - File.Delete(file); - - } + var files = _directoryService.GetFiles(_directoryService.CoverImageDirectory, ImageService.ChapterCoverImageRegex); + _directoryService.DeleteFiles(files.Where(file => !images.Contains(_directoryService.FileSystem.Path.GetFileName(file)))); } - private async Task DeleteTagCoverImages() + /// + /// Removes all collection tag images that are not in the database. They must follow filename pattern. + /// + public async Task DeleteTagCoverImages() { var images = await _unitOfWork.CollectionTagRepository.GetAllCoverImagesAsync(); - var files = DirectoryService.GetFiles(DirectoryService.CoverImageDirectory, ImageService.CollectionTagCoverImageRegex); - foreach (var file in files) - { - if (images.Contains(Path.GetFileName(file))) continue; - File.Delete(file); + var files = _directoryService.GetFiles(_directoryService.CoverImageDirectory, ImageService.CollectionTagCoverImageRegex); + _directoryService.DeleteFiles(files.Where(file => !images.Contains(_directoryService.FileSystem.Path.GetFileName(file)))); + } + /// + /// Removes all files and directories in the cache directory + /// + public void CleanupCacheDirectory() + { + _logger.LogInformation("Performing cleanup of Cache directory"); + _directoryService.ExistOrCreate(_directoryService.CacheDirectory); + + try + { + _directoryService.ClearDirectory(_directoryService.CacheDirectory); + } + catch (Exception ex) + { + _logger.LogError(ex, "There was an issue deleting one or more folders/files during cleanup"); + } + + _logger.LogInformation("Cache directory purged"); + } + + /// + /// Removes Database backups older than 30 days. If all backups are older than 30 days, the latest is kept. + /// + public async Task CleanupBackups() + { + const int dayThreshold = 30; + _logger.LogInformation("Beginning cleanup of Database backups at {Time}", DateTime.Now); + var backupDirectory = + (await _unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.BackupDirectory)).Value; + if (!_directoryService.Exists(backupDirectory)) return; + + var deltaTime = DateTime.Today.Subtract(TimeSpan.FromDays(dayThreshold)); + var allBackups = _directoryService.GetFiles(backupDirectory).ToList(); + var expiredBackups = allBackups.Select(filename => _directoryService.FileSystem.FileInfo.FromFileName(filename)) + .Where(f => f.CreationTime < deltaTime) + .ToList(); + + if (expiredBackups.Count == allBackups.Count) + { + _logger.LogInformation("All expired backups are older than {Threshold} days. Removing all but last backup", dayThreshold); + var toDelete = expiredBackups.OrderByDescending(f => f.CreationTime).ToList(); + _directoryService.DeleteFiles(toDelete.Take(toDelete.Count - 1).Select(f => f.FullName)); + } + else + { + _directoryService.DeleteFiles(expiredBackups.Select(f => f.FullName)); + } + _logger.LogInformation("Finished cleanup of Database backups at {Time}", DateTime.Now); + } + + /// + /// Removes all files in the BookmarkDirectory that don't currently have bookmarks in the Database + /// + public async Task CleanupBookmarks() + { + // Search all files in bookmarks/ except bookmark files and delete those + var bookmarkDirectory = + (await _unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.BookmarkDirectory)).Value; + var allBookmarkFiles = _directoryService.GetFiles(bookmarkDirectory, searchOption: SearchOption.AllDirectories).Select(Parser.Parser.NormalizePath); + var bookmarks = (await _unitOfWork.UserRepository.GetAllBookmarksAsync()) + .Select(b => Parser.Parser.NormalizePath(_directoryService.FileSystem.Path.Join(bookmarkDirectory, + b.FileName))); + + + var filesToDelete = allBookmarkFiles.ToList().Except(bookmarks).ToList(); + _logger.LogDebug("[Bookmarks] Bookmark cleanup wants to delete {Count} files", filesToDelete.Count()); + + _directoryService.DeleteFiles(filesToDelete); + + // Clear all empty directories + foreach (var directory in _directoryService.FileSystem.Directory.GetDirectories(bookmarkDirectory)) + { + if (_directoryService.FileSystem.Directory.GetFiles(directory).Length == 0 && + _directoryService.FileSystem.Directory.GetDirectories(directory).Length == 0) + { + _directoryService.FileSystem.Directory.Delete(directory, false); + } } } } diff --git a/API/Services/Tasks/Scanner/ParseScannedFiles.cs b/API/Services/Tasks/Scanner/ParseScannedFiles.cs index f88caab89..50cb98da9 100644 --- a/API/Services/Tasks/Scanner/ParseScannedFiles.cs +++ b/API/Services/Tasks/Scanner/ParseScannedFiles.cs @@ -6,7 +6,7 @@ using System.IO; using System.Linq; using API.Entities; using API.Entities.Enums; -using API.Interfaces.Services; +using API.Helpers; using API.Parser; using Microsoft.Extensions.Logging; @@ -23,34 +23,46 @@ namespace API.Services.Tasks.Scanner public class ParseScannedFiles { private readonly ConcurrentDictionary> _scannedSeries; - private readonly IBookService _bookService; private readonly ILogger _logger; + private readonly IDirectoryService _directoryService; + private readonly IReadingItemService _readingItemService; + private readonly DefaultParser _defaultParser; /// /// An instance of a pipeline for processing files and returning a Map of Series -> ParserInfos. /// Each instance is separate from other threads, allowing for no cross over. /// - /// - /// - public ParseScannedFiles(IBookService bookService, ILogger logger) + /// Logger of the parent class that invokes this + /// Directory Service + /// ReadingItemService Service for extracting information on a number of formats + public ParseScannedFiles(ILogger logger, IDirectoryService directoryService, + IReadingItemService readingItemService) { - _bookService = bookService; _logger = logger; + _directoryService = directoryService; + _readingItemService = readingItemService; _scannedSeries = new ConcurrentDictionary>(); + _defaultParser = new DefaultParser(_directoryService); } /// - /// Gets the list of parserInfos given a Series. If the series does not exist within, return empty list. + /// Gets the list of all parserInfos given a Series (Will match on Name, LocalizedName, OriginalName). If the series does not exist within, return empty list. /// /// /// /// public static IList GetInfosByName(Dictionary> parsedSeries, Series series) { - var existingKey = parsedSeries.Keys.FirstOrDefault(ps => - ps.Format == series.Format && ps.NormalizedName.Equals(Parser.Parser.Normalize(series.OriginalName))); + var allKeys = parsedSeries.Keys.Where(ps => + SeriesHelper.FindSeries(series, ps)); - return existingKey != null ? parsedSeries[existingKey] : new List(); + var infos = new List(); + foreach (var key in allKeys) + { + infos.AddRange(parsedSeries[key]); + } + + return infos; } /// @@ -62,20 +74,12 @@ namespace API.Services.Tasks.Scanner /// Library type to determine parsing to perform private void ProcessFile(string path, string rootPath, LibraryType type) { - ParserInfo info; + // TODO: Emit event with what is being processed. It can look like Kavita isn't doing anything during file scan - if (Parser.Parser.IsEpub(path)) - { - info = _bookService.ParseInfo(path); - } - else - { - info = Parser.Parser.Parse(path, rootPath, type); - } - - // If we couldn't match, log. But don't log if the file parses as a cover image + var info = _readingItemService.Parse(path, rootPath, type); if (info == null) { + // If the file is an image and literally a cover image, skip processing. if (!(Parser.Parser.IsImage(path) && Parser.Parser.IsCoverImage(path))) { _logger.LogWarning("[Scanner] Could not parse series from {Path}", path); @@ -83,16 +87,36 @@ namespace API.Services.Tasks.Scanner return; } - if (Parser.Parser.IsEpub(path) && Parser.Parser.ParseVolume(info.Series) != Parser.Parser.DefaultVolume) + + // This catches when original library type is Manga/Comic and when parsing with non + if (Parser.Parser.IsEpub(path) && Parser.Parser.ParseVolume(info.Series) != Parser.Parser.DefaultVolume) // Shouldn't this be info.Volume != DefaultVolume? { - info = Parser.Parser.Parse(path, rootPath, type); - var info2 = _bookService.ParseInfo(path); + info = _defaultParser.Parse(path, rootPath, LibraryType.Book); + var info2 = _readingItemService.Parse(path, rootPath, type); info.Merge(info2); } + info.ComicInfo = _readingItemService.GetComicInfo(path); + if (info.ComicInfo != null) + { + if (!string.IsNullOrEmpty(info.ComicInfo.Volume)) + { + info.Volumes = info.ComicInfo.Volume; + } + if (!string.IsNullOrEmpty(info.ComicInfo.Series)) + { + info.Series = info.ComicInfo.Series; + } + if (!string.IsNullOrEmpty(info.ComicInfo.Number)) + { + info.Chapters = info.ComicInfo.Number; + } + } + TrackSeries(info); } + /// /// Attempts to either add a new instance of a show mapping to the _scannedSeries bag or adds to an existing. /// This will check if the name matches an existing series name (multiple fields) @@ -133,7 +157,7 @@ namespace API.Services.Tasks.Scanner /// same normalized name, it merges into the existing one. This is important as some manga may have a slight difference with punctuation or capitalization. /// /// - /// + /// Series Name to group this info into public string MergeName(ParserInfo info) { var normalizedSeries = Parser.Parser.Normalize(info.Series); @@ -161,12 +185,11 @@ namespace API.Services.Tasks.Scanner { var sw = Stopwatch.StartNew(); totalFiles = 0; - var searchPattern = GetLibrarySearchPattern(); foreach (var folderPath in folders) { try { - totalFiles += DirectoryService.TraverseTreeParallelForEach(folderPath, (f) => + totalFiles += _directoryService.TraverseTreeParallelForEach(folderPath, (f) => { try { @@ -176,7 +199,7 @@ namespace API.Services.Tasks.Scanner { _logger.LogError(exception, "The file {Filename} could not be found", f); } - }, searchPattern, _logger); + }, Parser.Parser.SupportedExtensions, _logger); } catch (ArgumentException ex) { @@ -191,11 +214,6 @@ namespace API.Services.Tasks.Scanner return SeriesWithInfos(); } - private static string GetLibrarySearchPattern() - { - return Parser.Parser.SupportedExtensions; - } - /// /// Returns any series where there were parsed infos /// diff --git a/API/Services/Tasks/ScannerService.cs b/API/Services/Tasks/ScannerService.cs index f1d5a2b96..7c6a51f2c 100644 --- a/API/Services/Tasks/ScannerService.cs +++ b/API/Services/Tasks/ScannerService.cs @@ -7,13 +7,12 @@ using System.Threading; using System.Threading.Tasks; using API.Comparators; using API.Data; +using API.Data.Metadata; using API.Data.Repositories; using API.Entities; using API.Entities.Enums; using API.Extensions; using API.Helpers; -using API.Interfaces; -using API.Interfaces.Services; using API.Parser; using API.Services.Tasks.Scanner; using API.SignalR; @@ -21,697 +20,875 @@ using Hangfire; using Microsoft.AspNetCore.SignalR; using Microsoft.Extensions.Logging; -namespace API.Services.Tasks +namespace API.Services.Tasks; +public interface IScannerService { - public class ScannerService : IScannerService + /// + /// Given a library id, scans folders for said library. Parses files and generates DB updates. Will overwrite + /// cover images if forceUpdate is true. + /// + /// Library to scan against + Task ScanLibrary(int libraryId); + Task ScanLibraries(); + Task ScanSeries(int libraryId, int seriesId, CancellationToken token); +} + +public class ScannerService : IScannerService +{ + private readonly IUnitOfWork _unitOfWork; + private readonly ILogger _logger; + private readonly IMetadataService _metadataService; + private readonly ICacheService _cacheService; + private readonly IHubContext _messageHub; + private readonly IFileService _fileService; + private readonly IDirectoryService _directoryService; + private readonly IReadingItemService _readingItemService; + private readonly ICacheHelper _cacheHelper; + + public ScannerService(IUnitOfWork unitOfWork, ILogger logger, + IMetadataService metadataService, ICacheService cacheService, IHubContext messageHub, + IFileService fileService, IDirectoryService directoryService, IReadingItemService readingItemService, + ICacheHelper cacheHelper) { - private readonly IUnitOfWork _unitOfWork; - private readonly ILogger _logger; - private readonly IArchiveService _archiveService; - private readonly IMetadataService _metadataService; - private readonly IBookService _bookService; - private readonly ICacheService _cacheService; - private readonly IHubContext _messageHub; - private readonly NaturalSortComparer _naturalSort = new (); + _unitOfWork = unitOfWork; + _logger = logger; + _metadataService = metadataService; + _cacheService = cacheService; + _messageHub = messageHub; + _fileService = fileService; + _directoryService = directoryService; + _readingItemService = readingItemService; + _cacheHelper = cacheHelper; + } - public ScannerService(IUnitOfWork unitOfWork, ILogger logger, IArchiveService archiveService, - IMetadataService metadataService, IBookService bookService, ICacheService cacheService, IHubContext messageHub) - { - _unitOfWork = unitOfWork; - _logger = logger; - _archiveService = archiveService; - _metadataService = metadataService; - _bookService = bookService; - _cacheService = cacheService; - _messageHub = messageHub; - } + [DisableConcurrentExecution(timeoutInSeconds: 360)] + [AutomaticRetry(Attempts = 0, OnAttemptsExceeded = AttemptsExceededAction.Delete)] + public async Task ScanSeries(int libraryId, int seriesId, CancellationToken token) + { + var sw = new Stopwatch(); + var files = await _unitOfWork.SeriesRepository.GetFilesForSeries(seriesId); + var series = await _unitOfWork.SeriesRepository.GetFullSeriesForSeriesIdAsync(seriesId); + var chapterIds = await _unitOfWork.SeriesRepository.GetChapterIdsForSeriesAsync(new[] {seriesId}); + var library = await _unitOfWork.LibraryRepository.GetLibraryForIdAsync(libraryId, LibraryIncludes.Folders); + var folderPaths = library.Folders.Select(f => f.Path).ToList(); - [DisableConcurrentExecution(timeoutInSeconds: 360)] - [AutomaticRetry(Attempts = 0, OnAttemptsExceeded = AttemptsExceededAction.Delete)] - public async Task ScanSeries(int libraryId, int seriesId, CancellationToken token) - { - var sw = new Stopwatch(); - var files = await _unitOfWork.SeriesRepository.GetFilesForSeries(seriesId); - var series = await _unitOfWork.SeriesRepository.GetFullSeriesForSeriesIdAsync(seriesId); - var chapterIds = await _unitOfWork.SeriesRepository.GetChapterIdsForSeriesAsync(new[] {seriesId}); - var library = await _unitOfWork.LibraryRepository.GetLibraryForIdAsync(libraryId, LibraryIncludes.Folders); - var folderPaths = library.Folders.Select(f => f.Path).ToList(); + // Check if any of the folder roots are not available (ie disconnected from network, etc) and fail if any of them are + if (folderPaths.Any(f => !_directoryService.IsDriveMounted(f))) + { + _logger.LogError("Some of the root folders for library are not accessible. Please check that drives are connected and rescan. Scan will be aborted"); + return; + } - // Check if any of the folder roots are not available (ie disconnected from network, etc) and fail if any of them are - if (folderPaths.Any(f => !DirectoryService.IsDriveMounted(f))) - { - _logger.LogError("Some of the root folders for library are not accessible. Please check that drives are connected and rescan. Scan will be aborted"); - return; - } + var allPeople = await _unitOfWork.PersonRepository.GetAllPeople(); + var allGenres = await _unitOfWork.GenreRepository.GetAllGenresAsync(); + var allTags = await _unitOfWork.TagRepository.GetAllTagsAsync(); - var dirs = DirectoryService.FindHighestDirectoriesFromFiles(folderPaths, files.Select(f => f.FilePath).ToList()); + var dirs = _directoryService.FindHighestDirectoriesFromFiles(folderPaths, files.Select(f => f.FilePath).ToList()); - _logger.LogInformation("Beginning file scan on {SeriesName}", series.Name); - var scanner = new ParseScannedFiles(_bookService, _logger); - var parsedSeries = scanner.ScanLibrariesForSeries(library.Type, dirs.Keys, out var totalFiles, out var scanElapsedTime); + _logger.LogInformation("Beginning file scan on {SeriesName}", series.Name); + var scanner = new ParseScannedFiles(_logger, _directoryService, _readingItemService); + var parsedSeries = scanner.ScanLibrariesForSeries(library.Type, dirs.Keys, out var totalFiles, out var scanElapsedTime); - // Remove any parsedSeries keys that don't belong to our series. This can occur when users store 2 series in the same folder - RemoveParsedInfosNotForSeries(parsedSeries, series); + // Remove any parsedSeries keys that don't belong to our series. This can occur when users store 2 series in the same folder + RemoveParsedInfosNotForSeries(parsedSeries, series); - // If nothing was found, first validate any of the files still exist. If they don't then we have a deletion and can skip the rest of the logic flow - if (parsedSeries.Count == 0) - { - var anyFilesExist = - (await _unitOfWork.SeriesRepository.GetFilesForSeries(series.Id)).Any(m => File.Exists(m.FilePath)); + // If nothing was found, first validate any of the files still exist. If they don't then we have a deletion and can skip the rest of the logic flow + if (parsedSeries.Count == 0) + { + var anyFilesExist = + (await _unitOfWork.SeriesRepository.GetFilesForSeries(series.Id)).Any(m => File.Exists(m.FilePath)); - if (!anyFilesExist) - { - try - { - _unitOfWork.SeriesRepository.Remove(series); - await CommitAndSend(totalFiles, parsedSeries, sw, scanElapsedTime, series); - } - catch (Exception ex) - { - _logger.LogCritical(ex, "There was an error during ScanSeries to delete the series"); - await _unitOfWork.RollbackAsync(); - } + if (!anyFilesExist) + { + try + { + _unitOfWork.SeriesRepository.Remove(series); + await CommitAndSend(totalFiles, parsedSeries, sw, scanElapsedTime, series); + } + catch (Exception ex) + { + _logger.LogCritical(ex, "There was an error during ScanSeries to delete the series"); + await _unitOfWork.RollbackAsync(); + } - } - else - { - // We need to do an additional check for an edge case: If the scan ran and the files do not match the existing Series name, then it is very likely, - // the files have crap naming and if we don't correct, the series will get deleted due to the parser not being able to fallback onto folder parsing as the root - // is the series folder. - var existingFolder = dirs.Keys.FirstOrDefault(key => key.Contains(series.OriginalName)); - if (dirs.Keys.Count == 1 && !string.IsNullOrEmpty(existingFolder)) - { - dirs = new Dictionary(); - var path = Directory.GetParent(existingFolder)?.FullName; - if (!folderPaths.Contains(path) || !folderPaths.Any(p => p.Contains(path ?? string.Empty))) - { - _logger.LogInformation("[ScanService] Aborted: {SeriesName} has bad naming convention and sits at root of library. Cannot scan series without deletion occuring. Correct file names to have Series Name within it or perform Scan Library", series.OriginalName); - return; - } - if (!string.IsNullOrEmpty(path)) - { - dirs[path] = string.Empty; - } - } + } + else + { + // We need to do an additional check for an edge case: If the scan ran and the files do not match the existing Series name, then it is very likely, + // the files have crap naming and if we don't correct, the series will get deleted due to the parser not being able to fallback onto folder parsing as the root + // is the series folder. + var existingFolder = dirs.Keys.FirstOrDefault(key => key.Contains(series.OriginalName)); + if (dirs.Keys.Count == 1 && !string.IsNullOrEmpty(existingFolder)) + { + dirs = new Dictionary(); + var path = Directory.GetParent(existingFolder)?.FullName; + if (!folderPaths.Contains(path) || !folderPaths.Any(p => p.Contains(path ?? string.Empty))) + { + _logger.LogInformation("[ScanService] Aborted: {SeriesName} has bad naming convention and sits at root of library. Cannot scan series without deletion occuring. Correct file names to have Series Name within it or perform Scan Library", series.OriginalName); + return; + } + if (!string.IsNullOrEmpty(path)) + { + dirs[path] = string.Empty; + } + } - _logger.LogInformation("{SeriesName} has bad naming convention, forcing rescan at a higher directory", series.OriginalName); - scanner = new ParseScannedFiles(_bookService, _logger); - parsedSeries = scanner.ScanLibrariesForSeries(library.Type, dirs.Keys, out var totalFiles2, out var scanElapsedTime2); - totalFiles += totalFiles2; - scanElapsedTime += scanElapsedTime2; - RemoveParsedInfosNotForSeries(parsedSeries, series); - } - } + _logger.LogInformation("{SeriesName} has bad naming convention, forcing rescan at a higher directory", series.OriginalName); + scanner = new ParseScannedFiles(_logger, _directoryService, _readingItemService); + parsedSeries = scanner.ScanLibrariesForSeries(library.Type, dirs.Keys, out var totalFiles2, out var scanElapsedTime2); + totalFiles += totalFiles2; + scanElapsedTime += scanElapsedTime2; + RemoveParsedInfosNotForSeries(parsedSeries, series); + } + } - // At this point, parsedSeries will have at least one key and we can perform the update. If it still doesn't, just return and don't do anything - if (parsedSeries.Count == 0) return; + // At this point, parsedSeries will have at least one key and we can perform the update. If it still doesn't, just return and don't do anything + if (parsedSeries.Count == 0) return; - try - { - UpdateSeries(series, parsedSeries); - await CommitAndSend(totalFiles, parsedSeries, sw, scanElapsedTime, series); - } - catch (Exception ex) - { - _logger.LogCritical(ex, "There was an error during ScanSeries to update the series"); - await _unitOfWork.RollbackAsync(); - } - // Tell UI that this series is done - await _messageHub.Clients.All.SendAsync(SignalREvents.ScanSeries, MessageFactory.ScanSeriesEvent(seriesId, series.Name), token); - await CleanupDbEntities(); - BackgroundJob.Enqueue(() => _cacheService.CleanupChapters(chapterIds)); - BackgroundJob.Enqueue(() => _metadataService.RefreshMetadataForSeries(libraryId, series.Id, false)); - } + // Merge any series together that might have different ParsedSeries but belong to another group of ParsedSeries + try + { + UpdateSeries(series, parsedSeries, allPeople, allTags, allGenres, library.Type); - private static void RemoveParsedInfosNotForSeries(Dictionary> parsedSeries, Series series) - { - var keys = parsedSeries.Keys; - foreach (var key in keys.Where(key => - !series.NameInParserInfo(parsedSeries[key].FirstOrDefault()) || series.Format != key.Format)) - { - parsedSeries.Remove(key); - } - } + await CommitAndSend(totalFiles, parsedSeries, sw, scanElapsedTime, series); + } + catch (Exception ex) + { + _logger.LogCritical(ex, "There was an error during ScanSeries to update the series"); + await _unitOfWork.RollbackAsync(); + } + // Tell UI that this series is done + await _messageHub.Clients.All.SendAsync(SignalREvents.ScanSeries, MessageFactory.ScanSeriesEvent(seriesId, series.Name), token); + await CleanupDbEntities(); + BackgroundJob.Enqueue(() => _cacheService.CleanupChapters(chapterIds)); + BackgroundJob.Enqueue(() => _metadataService.RefreshMetadataForSeries(libraryId, series.Id, false)); + } - private async Task CommitAndSend(int totalFiles, - Dictionary> parsedSeries, Stopwatch sw, long scanElapsedTime, Series series) - { - if (_unitOfWork.HasChanges()) - { - await _unitOfWork.CommitAsync(); - _logger.LogInformation( - "Processed {TotalFiles} files and {ParsedSeriesCount} series in {ElapsedScanTime} milliseconds for {SeriesName}", - totalFiles, parsedSeries.Keys.Count, sw.ElapsedMilliseconds + scanElapsedTime, series.Name); - } - } + private static void RemoveParsedInfosNotForSeries(Dictionary> parsedSeries, Series series) + { + var keys = parsedSeries.Keys; + foreach (var key in keys.Where(key => + series.Format != key.Format || !SeriesHelper.FindSeries(series, key))) + { + parsedSeries.Remove(key); + } + } + + private async Task CommitAndSend(int totalFiles, + Dictionary> parsedSeries, Stopwatch sw, long scanElapsedTime, Series series) + { + if (_unitOfWork.HasChanges()) + { + await _unitOfWork.CommitAsync(); + _logger.LogInformation( + "Processed {TotalFiles} files and {ParsedSeriesCount} series in {ElapsedScanTime} milliseconds for {SeriesName}", + totalFiles, parsedSeries.Keys.Count, sw.ElapsedMilliseconds + scanElapsedTime, series.Name); + } + } - [DisableConcurrentExecution(timeoutInSeconds: 360)] - [AutomaticRetry(Attempts = 0, OnAttemptsExceeded = AttemptsExceededAction.Delete)] - public async Task ScanLibraries() - { - _logger.LogInformation("Starting Scan of All Libraries"); - var libraries = await _unitOfWork.LibraryRepository.GetLibrariesAsync(); - foreach (var lib in libraries) - { - await ScanLibrary(lib.Id); - } - _logger.LogInformation("Scan of All Libraries Finished"); - } + [DisableConcurrentExecution(timeoutInSeconds: 360)] + [AutomaticRetry(Attempts = 0, OnAttemptsExceeded = AttemptsExceededAction.Delete)] + public async Task ScanLibraries() + { + _logger.LogInformation("Starting Scan of All Libraries"); + var libraries = await _unitOfWork.LibraryRepository.GetLibrariesAsync(); + foreach (var lib in libraries) + { + await ScanLibrary(lib.Id); + } + _logger.LogInformation("Scan of All Libraries Finished"); + } - /// - /// Scans a library for file changes. - /// Will kick off a scheduled background task to refresh metadata, - /// ie) all entities will be rechecked for new cover images and comicInfo.xml changes - /// - /// - [DisableConcurrentExecution(360)] - [AutomaticRetry(Attempts = 0, OnAttemptsExceeded = AttemptsExceededAction.Delete)] - public async Task ScanLibrary(int libraryId) - { - Library library; - try - { - library = await _unitOfWork.LibraryRepository.GetLibraryForIdAsync(libraryId, LibraryIncludes.Folders); - } - catch (Exception ex) - { - // This usually only fails if user is not authenticated. - _logger.LogError(ex, "[ScannerService] There was an issue fetching Library {LibraryId}", libraryId); - return; - } + /// + /// Scans a library for file changes. + /// Will kick off a scheduled background task to refresh metadata, + /// ie) all entities will be rechecked for new cover images and comicInfo.xml changes + /// + /// + [DisableConcurrentExecution(360)] + [AutomaticRetry(Attempts = 0, OnAttemptsExceeded = AttemptsExceededAction.Delete)] + public async Task ScanLibrary(int libraryId) + { + Library library; + try + { + library = await _unitOfWork.LibraryRepository.GetLibraryForIdAsync(libraryId, LibraryIncludes.Folders); + } + catch (Exception ex) + { + // This usually only fails if user is not authenticated. + _logger.LogError(ex, "[ScannerService] There was an issue fetching Library {LibraryId}", libraryId); + return; + } - // Check if any of the folder roots are not available (ie disconnected from network, etc) and fail if any of them are - if (library.Folders.Any(f => !DirectoryService.IsDriveMounted(f.Path))) - { - _logger.LogError("Some of the root folders for library are not accessible. Please check that drives are connected and rescan. Scan will be aborted"); - return; - } + // Check if any of the folder roots are not available (ie disconnected from network, etc) and fail if any of them are + if (library.Folders.Any(f => !_directoryService.IsDriveMounted(f.Path))) + { + _logger.LogCritical("Some of the root folders for library are not accessible. Please check that drives are connected and rescan. Scan will be aborted"); + await _messageHub.Clients.All.SendAsync(SignalREvents.ScanLibraryProgress, + MessageFactory.ScanLibraryProgressEvent(libraryId, 1F)); + return; + } + + // For Docker instances check if any of the folder roots are not available (ie disconnected volumes, etc) and fail if any of them are + if (library.Folders.Any(f => _directoryService.IsDirectoryEmpty(f.Path))) + { + _logger.LogCritical("Some of the root folders for the library are empty. " + + "Either your mount has been disconnected or you are trying to delete all series in the library. " + + "Scan will be aborted. " + + "Check that your mount is connected or change the library's root folder and rescan"); + await _messageHub.Clients.All.SendAsync(SignalREvents.ScanLibraryProgress, + MessageFactory.ScanLibraryProgressEvent(libraryId, 1F)); + return; + } + + _logger.LogInformation("[ScannerService] Beginning file scan on {LibraryName}", library.Name); + await _messageHub.Clients.All.SendAsync(SignalREvents.ScanLibraryProgress, + MessageFactory.ScanLibraryProgressEvent(libraryId, 0)); + + var scanner = new ParseScannedFiles(_logger, _directoryService, _readingItemService); + var series = scanner.ScanLibrariesForSeries(library.Type, library.Folders.Select(fp => fp.Path), out var totalFiles, out var scanElapsedTime); + + foreach (var folderPath in library.Folders) + { + folderPath.LastScanned = DateTime.Now; + } + var sw = Stopwatch.StartNew(); + + await UpdateLibrary(library, series); + + library.LastScanned = DateTime.Now; + _unitOfWork.LibraryRepository.Update(library); + if (await _unitOfWork.CommitAsync()) + { + _logger.LogInformation( + "[ScannerService] Processed {TotalFiles} files and {ParsedSeriesCount} series in {ElapsedScanTime} milliseconds for {LibraryName}", + totalFiles, series.Keys.Count, sw.ElapsedMilliseconds + scanElapsedTime, library.Name); + } + else + { + _logger.LogCritical( + "[ScannerService] There was a critical error that resulted in a failed scan. Please check logs and rescan"); + } + + await CleanupDbEntities(); + + await _messageHub.Clients.All.SendAsync(SignalREvents.ScanLibraryProgress, + MessageFactory.ScanLibraryProgressEvent(libraryId, 1F)); + BackgroundJob.Enqueue(() => _metadataService.RefreshMetadata(libraryId, false)); + } + + /// + /// Remove any user progress rows that no longer exist since scan library ran and deleted series/volumes/chapters + /// + private async Task CleanupAbandonedChapters() + { + var cleanedUp = await _unitOfWork.AppUserProgressRepository.CleanupAbandonedChapters(); + _logger.LogInformation("Removed {Count} abandoned progress rows", cleanedUp); + } - _logger.LogInformation("[ScannerService] Beginning file scan on {LibraryName}", library.Name); - await _messageHub.Clients.All.SendAsync(SignalREvents.ScanLibraryProgress, - MessageFactory.ScanLibraryProgressEvent(libraryId, 0)); + /// + /// Cleans up any abandoned rows due to removals from Scan loop + /// + private async Task CleanupDbEntities() + { + await CleanupAbandonedChapters(); + var cleanedUp = await _unitOfWork.CollectionTagRepository.RemoveTagsWithoutSeries(); + _logger.LogInformation("Removed {Count} abandoned collection tags", cleanedUp); + } - var scanner = new ParseScannedFiles(_bookService, _logger); - var series = scanner.ScanLibrariesForSeries(library.Type, library.Folders.Select(fp => fp.Path), out var totalFiles, out var scanElapsedTime); + private async Task UpdateLibrary(Library library, Dictionary> parsedSeries) + { + if (parsedSeries == null) return; - foreach (var folderPath in library.Folders) - { - folderPath.LastScanned = DateTime.Now; - } - var sw = Stopwatch.StartNew(); + // Library contains no Series, so we need to fetch series in groups of ChunkSize + var chunkInfo = await _unitOfWork.SeriesRepository.GetChunkInfo(library.Id); + var stopwatch = Stopwatch.StartNew(); + var totalTime = 0L; - await UpdateLibrary(library, series); + var allPeople = await _unitOfWork.PersonRepository.GetAllPeople(); + var allGenres = await _unitOfWork.GenreRepository.GetAllGenresAsync(); + var allTags = await _unitOfWork.TagRepository.GetAllTagsAsync(); - library.LastScanned = DateTime.Now; - _unitOfWork.LibraryRepository.Update(library); - if (await _unitOfWork.CommitAsync()) - { - _logger.LogInformation( - "[ScannerService] Processed {TotalFiles} files and {ParsedSeriesCount} series in {ElapsedScanTime} milliseconds for {LibraryName}", - totalFiles, series.Keys.Count, sw.ElapsedMilliseconds + scanElapsedTime, library.Name); - } - else - { - _logger.LogCritical( - "[ScannerService] There was a critical error that resulted in a failed scan. Please check logs and rescan"); - } + // Update existing series + _logger.LogInformation("[ScannerService] Updating existing series for {LibraryName}. Total Items: {TotalSize}. Total Chunks: {TotalChunks} with {ChunkSize} size", + library.Name, chunkInfo.TotalSize, chunkInfo.TotalChunks, chunkInfo.ChunkSize); + for (var chunk = 1; chunk <= chunkInfo.TotalChunks; chunk++) + { + if (chunkInfo.TotalChunks == 0) continue; + totalTime += stopwatch.ElapsedMilliseconds; + stopwatch.Restart(); + _logger.LogInformation("[ScannerService] Processing chunk {ChunkNumber} / {TotalChunks} with size {ChunkSize}. Series ({SeriesStart} - {SeriesEnd}", + chunk, chunkInfo.TotalChunks, chunkInfo.ChunkSize, chunk * chunkInfo.ChunkSize, (chunk + 1) * chunkInfo.ChunkSize); + var nonLibrarySeries = await _unitOfWork.SeriesRepository.GetFullSeriesForLibraryIdAsync(library.Id, new UserParams() + { + PageNumber = chunk, + PageSize = chunkInfo.ChunkSize + }); - await CleanupDbEntities(); + // First, remove any series that are not in parsedSeries list + var missingSeries = FindSeriesNotOnDisk(nonLibrarySeries, parsedSeries).ToList(); - BackgroundJob.Enqueue(() => _metadataService.RefreshMetadata(libraryId, false)); - await _messageHub.Clients.All.SendAsync(SignalREvents.ScanLibraryProgress, - MessageFactory.ScanLibraryProgressEvent(libraryId, 1F)); - } + foreach (var missing in missingSeries) + { + _unitOfWork.SeriesRepository.Remove(missing); + } - /// - /// Remove any user progress rows that no longer exist since scan library ran and deleted series/volumes/chapters - /// - private async Task CleanupAbandonedChapters() - { - var cleanedUp = await _unitOfWork.AppUserProgressRepository.CleanupAbandonedChapters(); - _logger.LogInformation("Removed {Count} abandoned progress rows", cleanedUp); - } + var cleanedSeries = SeriesHelper.RemoveMissingSeries(nonLibrarySeries, missingSeries, out var removeCount); + if (removeCount > 0) + { + _logger.LogInformation("[ScannerService] Removed {RemoveMissingSeries} series that are no longer on disk:", removeCount); + foreach (var s in missingSeries) + { + _logger.LogDebug("[ScannerService] Removed {SeriesName} ({Format})", s.Name, s.Format); + } + } + + // Now, we only have to deal with series that exist on disk. Let's recalculate the volumes for each series + var librarySeries = cleanedSeries.ToList(); + Parallel.ForEach(librarySeries, (series) => + { + UpdateSeries(series, parsedSeries, allPeople, allTags, allGenres, library.Type); + }); + + try + { + await _unitOfWork.CommitAsync(); + } + catch (Exception ex) + { + _logger.LogCritical(ex, "[ScannerService] There was an issue writing to the DB. Chunk {ChunkNumber} did not save to DB. If debug mode, series to check will be printed", chunk); + foreach (var series in nonLibrarySeries) + { + _logger.LogDebug("[ScannerService] There may be a constraint issue with {SeriesName}", series.OriginalName); + } + await _messageHub.Clients.All.SendAsync(SignalREvents.ScanLibraryError, + MessageFactory.ScanLibraryError(library.Id)); + continue; + } + _logger.LogInformation( + "[ScannerService] Processed {SeriesStart} - {SeriesEnd} series in {ElapsedScanTime} milliseconds for {LibraryName}", + chunk * chunkInfo.ChunkSize, (chunk * chunkInfo.ChunkSize) + nonLibrarySeries.Count, totalTime, library.Name); + + // Emit any series removed + foreach (var missing in missingSeries) + { + await _messageHub.Clients.All.SendAsync(SignalREvents.SeriesRemoved, MessageFactory.SeriesRemovedEvent(missing.Id, missing.Name, library.Id)); + } + + var progress = Math.Max(0, Math.Min(1, ((chunk + 1F) * chunkInfo.ChunkSize) / chunkInfo.TotalSize)); + await _messageHub.Clients.All.SendAsync(SignalREvents.ScanLibraryProgress, + MessageFactory.ScanLibraryProgressEvent(library.Id, progress)); + } - /// - /// Cleans up any abandoned rows due to removals from Scan loop - /// - private async Task CleanupDbEntities() - { - await CleanupAbandonedChapters(); - var cleanedUp = await _unitOfWork.CollectionTagRepository.RemoveTagsWithoutSeries(); - _logger.LogInformation("Removed {Count} abandoned collection tags", cleanedUp); - } + // Add new series that have parsedInfos + _logger.LogDebug("[ScannerService] Adding new series"); + var newSeries = new List(); + var allSeries = (await _unitOfWork.SeriesRepository.GetSeriesForLibraryIdAsync(library.Id)).ToList(); + _logger.LogDebug("[ScannerService] Fetched {AllSeriesCount} series for comparing new series with. There should be {DeltaToParsedSeries} new series", + allSeries.Count, parsedSeries.Count - allSeries.Count); + foreach (var (key, infos) in parsedSeries) + { + // Key is normalized already + Series existingSeries; + try + { + existingSeries = allSeries.SingleOrDefault(s => SeriesHelper.FindSeries(s, key)); + } + catch (Exception e) + { + // NOTE: If I ever want to put Duplicates table, this is where it can go + _logger.LogCritical(e, "[ScannerService] There are multiple series that map to normalized key {Key}. You can manually delete the entity via UI and rescan to fix it. This will be skipped", key.NormalizedName); + var duplicateSeries = allSeries.Where(s => SeriesHelper.FindSeries(s, key)); + foreach (var series in duplicateSeries) + { + _logger.LogCritical("[ScannerService] Duplicate Series Found: {Key} maps with {Series}", key.Name, series.OriginalName); + } - private async Task UpdateLibrary(Library library, Dictionary> parsedSeries) - { - if (parsedSeries == null) return; + continue; + } - // Library contains no Series, so we need to fetch series in groups of ChunkSize - var chunkInfo = await _unitOfWork.SeriesRepository.GetChunkInfo(library.Id); - var stopwatch = Stopwatch.StartNew(); - var totalTime = 0L; + if (existingSeries != null) continue; - // Update existing series - _logger.LogInformation("[ScannerService] Updating existing series for {LibraryName}. Total Items: {TotalSize}. Total Chunks: {TotalChunks} with {ChunkSize} size", - library.Name, chunkInfo.TotalSize, chunkInfo.TotalChunks, chunkInfo.ChunkSize); - for (var chunk = 1; chunk <= chunkInfo.TotalChunks; chunk++) - { - if (chunkInfo.TotalChunks == 0) continue; - totalTime += stopwatch.ElapsedMilliseconds; - stopwatch.Restart(); - _logger.LogInformation("[ScannerService] Processing chunk {ChunkNumber} / {TotalChunks} with size {ChunkSize}. Series ({SeriesStart} - {SeriesEnd}", - chunk, chunkInfo.TotalChunks, chunkInfo.ChunkSize, chunk * chunkInfo.ChunkSize, (chunk + 1) * chunkInfo.ChunkSize); - var nonLibrarySeries = await _unitOfWork.SeriesRepository.GetFullSeriesForLibraryIdAsync(library.Id, new UserParams() - { - PageNumber = chunk, - PageSize = chunkInfo.ChunkSize - }); - - // First, remove any series that are not in parsedSeries list - var missingSeries = FindSeriesNotOnDisk(nonLibrarySeries, parsedSeries).ToList(); - - foreach (var missing in missingSeries) - { - _unitOfWork.SeriesRepository.Remove(missing); - } - - var cleanedSeries = RemoveMissingSeries(nonLibrarySeries, missingSeries, out var removeCount); - if (removeCount > 0) - { - _logger.LogInformation("[ScannerService] Removed {RemoveMissingSeries} series that are no longer on disk:", removeCount); - foreach (var s in missingSeries) - { - _logger.LogDebug("[ScannerService] Removed {SeriesName} ({Format})", s.Name, s.Format); - } - } - - // Now, we only have to deal with series that exist on disk. Let's recalculate the volumes for each series - var librarySeries = cleanedSeries.ToList(); - Parallel.ForEach(librarySeries, (series) => - { - UpdateSeries(series, parsedSeries); - }); - - try - { - await _unitOfWork.CommitAsync(); - } - catch (Exception ex) - { - _logger.LogCritical(ex, "[ScannerService] There was an issue writing to the DB. Chunk {ChunkNumber} did not save to DB. If debug mode, series to check will be printed", chunk); - foreach (var series in nonLibrarySeries) - { - _logger.LogDebug("[ScannerService] There may be a constraint issue with {SeriesName}", series.OriginalName); - } - await _messageHub.Clients.All.SendAsync(SignalREvents.ScanLibraryError, - MessageFactory.ScanLibraryError(library.Id)); - continue; - } - _logger.LogInformation( - "[ScannerService] Processed {SeriesStart} - {SeriesEnd} series in {ElapsedScanTime} milliseconds for {LibraryName}", - chunk * chunkInfo.ChunkSize, (chunk * chunkInfo.ChunkSize) + nonLibrarySeries.Count, totalTime, library.Name); - - // Emit any series removed - foreach (var missing in missingSeries) - { - await _messageHub.Clients.All.SendAsync(SignalREvents.SeriesRemoved, MessageFactory.SeriesRemovedEvent(missing.Id, missing.Name, library.Id)); - } - - var progress = Math.Max(0, Math.Min(1, ((chunk + 1F) * chunkInfo.ChunkSize) / chunkInfo.TotalSize)); - await _messageHub.Clients.All.SendAsync(SignalREvents.ScanLibraryProgress, - MessageFactory.ScanLibraryProgressEvent(library.Id, progress)); - } + var s = DbFactory.Series(infos[0].Series); + if (!string.IsNullOrEmpty(infos[0].SeriesSort)) + { + s.SortName = infos[0].SeriesSort; + } + s.Format = key.Format; + s.LibraryId = library.Id; // We have to manually set this since we aren't adding the series to the Library's series. + newSeries.Add(s); + } - // Add new series that have parsedInfos - _logger.LogDebug("[ScannerService] Adding new series"); - var newSeries = new List(); - var allSeries = (await _unitOfWork.SeriesRepository.GetSeriesForLibraryIdAsync(library.Id)).ToList(); - _logger.LogDebug("[ScannerService] Fetched {AllSeriesCount} series for comparing new series with. There should be {DeltaToParsedSeries} new series", - allSeries.Count, parsedSeries.Count - allSeries.Count); - foreach (var (key, infos) in parsedSeries) - { - // Key is normalized already - Series existingSeries; - try - { - existingSeries = allSeries.SingleOrDefault(s => FindSeries(s, key)); - } - catch (Exception e) - { - // NOTE: If I ever want to put Duplicates table, this is where it can go - _logger.LogCritical(e, "[ScannerService] There are multiple series that map to normalized key {Key}. You can manually delete the entity via UI and rescan to fix it. This will be skipped", key.NormalizedName); - var duplicateSeries = allSeries.Where(s => FindSeries(s, key)); - foreach (var series in duplicateSeries) - { - _logger.LogCritical("[ScannerService] Duplicate Series Found: {Key} maps with {Series}", key.Name, series.OriginalName); - } + var i = 0; + foreach(var series in newSeries) + { + _logger.LogDebug("[ScannerService] Processing series {SeriesName}", series.OriginalName); + UpdateSeries(series, parsedSeries, allPeople, allTags, allGenres, library.Type); + _unitOfWork.SeriesRepository.Attach(series); + try + { + await _unitOfWork.CommitAsync(); + _logger.LogInformation( + "[ScannerService] Added {NewSeries} series in {ElapsedScanTime} milliseconds for {LibraryName}", + newSeries.Count, stopwatch.ElapsedMilliseconds, library.Name); - continue; - } + // Inform UI of new series added + await _messageHub.Clients.All.SendAsync(SignalREvents.SeriesAdded, MessageFactory.SeriesAddedEvent(series.Id, series.Name, library.Id)); + } + catch (Exception ex) + { + _logger.LogCritical(ex, "[ScannerService] There was a critical exception adding new series entry for {SeriesName} with a duplicate index key: {IndexKey} ", + series.Name, $"{series.Name}_{series.NormalizedName}_{series.LocalizedName}_{series.LibraryId}_{series.Format}"); + } - if (existingSeries != null) continue; + var progress = Math.Max(0F, Math.Min(1F, i * 1F / newSeries.Count)); + await _messageHub.Clients.All.SendAsync(SignalREvents.ScanLibraryProgress, + MessageFactory.ScanLibraryProgressEvent(library.Id, progress)); + i++; + } - var s = DbFactory.Series(infos[0].Series); - s.Format = key.Format; - s.LibraryId = library.Id; // We have to manually set this since we aren't adding the series to the Library's series. - newSeries.Add(s); - } + _logger.LogInformation( + "[ScannerService] Added {NewSeries} series in {ElapsedScanTime} milliseconds for {LibraryName}", + newSeries.Count, stopwatch.ElapsedMilliseconds, library.Name); + } - var i = 0; - foreach(var series in newSeries) - { - _logger.LogDebug("[ScannerService] Processing series {SeriesName}", series.OriginalName); - UpdateSeries(series, parsedSeries); - _unitOfWork.SeriesRepository.Attach(series); - try - { - await _unitOfWork.CommitAsync(); - _logger.LogInformation( - "[ScannerService] Added {NewSeries} series in {ElapsedScanTime} milliseconds for {LibraryName}", - newSeries.Count, stopwatch.ElapsedMilliseconds, library.Name); + private void UpdateSeries(Series series, Dictionary> parsedSeries, + ICollection allPeople, ICollection allTags, ICollection allGenres, LibraryType libraryType) + { + try + { + _logger.LogInformation("[ScannerService] Processing series {SeriesName}", series.OriginalName); - // Inform UI of new series added - await _messageHub.Clients.All.SendAsync(SignalREvents.SeriesAdded, MessageFactory.SeriesAddedEvent(series.Id, series.Name, library.Id)); - } - catch (Exception ex) - { - _logger.LogCritical(ex, "[ScannerService] There was a critical exception adding new series entry for {SeriesName} with a duplicate index key: {IndexKey} ", - series.Name, $"{series.Name}_{series.NormalizedName}_{series.LocalizedName}_{series.LibraryId}_{series.Format}"); - } + // Get all associated ParsedInfos to the series. This includes infos that use a different filename that matches Series LocalizedName + var parsedInfos = ParseScannedFiles.GetInfosByName(parsedSeries, series); + UpdateVolumes(series, parsedInfos, allPeople, allTags, allGenres); + series.Pages = series.Volumes.Sum(v => v.Pages); - var progress = Math.Max(0F, Math.Min(1F, i * 1F / newSeries.Count)); - await _messageHub.Clients.All.SendAsync(SignalREvents.ScanLibraryProgress, - MessageFactory.ScanLibraryProgressEvent(library.Id, progress)); - i++; - } + series.NormalizedName = Parser.Parser.Normalize(series.Name); + series.Metadata ??= DbFactory.SeriesMetadata(new List()); + if (series.Format == MangaFormat.Unknown) + { + series.Format = parsedInfos[0].Format; + } + series.OriginalName ??= parsedInfos[0].Series; + series.SortName ??= parsedInfos[0].SeriesSort; - _logger.LogInformation( - "[ScannerService] Added {NewSeries} series in {ElapsedScanTime} milliseconds for {LibraryName}", - newSeries.Count, stopwatch.ElapsedMilliseconds, library.Name); - } + UpdateSeriesMetadata(series, allPeople, allGenres, allTags, libraryType); + } + catch (Exception ex) + { + _logger.LogError(ex, "[ScannerService] There was an exception updating volumes for {SeriesName}", series.Name); + } + } - private static bool FindSeries(Series series, ParsedSeries parsedInfoKey) - { - return (series.NormalizedName.Equals(parsedInfoKey.NormalizedName) || Parser.Parser.Normalize(series.OriginalName).Equals(parsedInfoKey.NormalizedName)) - && (series.Format == parsedInfoKey.Format || series.Format == MangaFormat.Unknown); - } + public static IEnumerable FindSeriesNotOnDisk(IEnumerable existingSeries, Dictionary> parsedSeries) + { + return existingSeries.Where(es => !ParserInfoHelpers.SeriesHasMatchingParserInfoFormat(es, parsedSeries)); + } - private void UpdateSeries(Series series, Dictionary> parsedSeries) - { - try - { - _logger.LogInformation("[ScannerService] Processing series {SeriesName}", series.OriginalName); - var parsedInfos = ParseScannedFiles.GetInfosByName(parsedSeries, series); - UpdateVolumes(series, parsedInfos); - series.Pages = series.Volumes.Sum(v => v.Pages); + private static void UpdateSeriesMetadata(Series series, ICollection allPeople, ICollection allGenres, ICollection allTags, LibraryType libraryType) + { + var isBook = libraryType == LibraryType.Book; + var firstVolume = series.Volumes.OrderBy(c => c.Number, new ChapterSortComparer()).FirstWithChapters(isBook); + var firstChapter = firstVolume?.Chapters.GetFirstChapterWithFiles(); - series.NormalizedName = Parser.Parser.Normalize(series.Name); - series.Metadata ??= DbFactory.SeriesMetadata(new List()); - if (series.Format == MangaFormat.Unknown) - { - series.Format = parsedInfos[0].Format; - } - series.OriginalName ??= parsedInfos[0].Series; - } - catch (Exception ex) - { - _logger.LogError(ex, "[ScannerService] There was an exception updating volumes for {SeriesName}", series.Name); - } - } + var firstFile = firstChapter?.Files.FirstOrDefault(); + if (firstFile == null) return; + if (Parser.Parser.IsPdf(firstFile.FilePath)) return; - public static IEnumerable FindSeriesNotOnDisk(IEnumerable existingSeries, Dictionary> parsedSeries) - { - var foundSeries = parsedSeries.Select(s => s.Key.Name).ToList(); - return existingSeries.Where(es => !es.NameInList(foundSeries) && !SeriesHasMatchingParserInfoFormat(es, parsedSeries)); - } + var chapters = series.Volumes.SelectMany(volume => volume.Chapters).ToList(); - /// - /// Checks each parser info to see if there is a name match and if so, checks if the format matches the Series object. - /// This accounts for if the Series has an Unknown type and if so, considers it matching. - /// - /// - /// - /// - private static bool SeriesHasMatchingParserInfoFormat(Series series, - Dictionary> parsedSeries) - { - var format = MangaFormat.Unknown; - foreach (var pSeries in parsedSeries.Keys) - { - var name = pSeries.Name; - var normalizedName = Parser.Parser.Normalize(name); + // Update Metadata based on Chapter metadata + series.Metadata.ReleaseYear = chapters.Min(c => c.ReleaseDate.Year); - if (normalizedName == series.NormalizedName || - normalizedName == Parser.Parser.Normalize(series.Name) || - name == series.Name || name == series.LocalizedName || - name == series.OriginalName || - normalizedName == Parser.Parser.Normalize(series.OriginalName)) - { - format = pSeries.Format; - break; - } - } + if (series.Metadata.ReleaseYear < 1000) + { + // Not a valid year, default to 0 + series.Metadata.ReleaseYear = 0; + } - if (series.Format == MangaFormat.Unknown && format != MangaFormat.Unknown) - { - return true; - } + // Set the AgeRating as highest in all the comicInfos + series.Metadata.AgeRating = chapters.Max(chapter => chapter.AgeRating); - return format == series.Format; - } - /// - /// Removes all instances of missingSeries' Series from existingSeries Collection. Existing series is updated by - /// reference and the removed element count is returned. - /// - /// Existing Series in DB - /// Series not found on disk or can't be parsed - /// - /// the updated existingSeries - public static IEnumerable RemoveMissingSeries(IList existingSeries, IEnumerable missingSeries, out int removeCount) - { - var existingCount = existingSeries.Count; - var missingList = missingSeries.ToList(); + series.Metadata.Count = chapters.Max(chapter => chapter.TotalCount); + series.Metadata.PublicationStatus = PublicationStatus.OnGoing; + if (chapters.Max(chapter => chapter.Count) >= series.Metadata.Count && series.Metadata.Count > 0) + { + series.Metadata.PublicationStatus = PublicationStatus.Completed; + } - existingSeries = existingSeries.Where( - s => !missingList.Exists( - m => m.NormalizedName.Equals(s.NormalizedName) && m.Format == s.Format)).ToList(); + if (!string.IsNullOrEmpty(firstChapter.Summary)) + { + series.Metadata.Summary = firstChapter.Summary; + } - removeCount = existingCount - existingSeries.Count; + if (!string.IsNullOrEmpty(firstChapter.Language)) + { + series.Metadata.Language = firstChapter.Language; + } - return existingSeries; - } - private void UpdateVolumes(Series series, IList parsedInfos) - { - var startingVolumeCount = series.Volumes.Count; - // Add new volumes and update chapters per volume - var distinctVolumes = parsedInfos.DistinctVolumes(); - _logger.LogDebug("[ScannerService] Updating {DistinctVolumes} volumes on {SeriesName}", distinctVolumes.Count, series.Name); - foreach (var volumeNumber in distinctVolumes) - { - var volume = series.Volumes.SingleOrDefault(s => s.Name == volumeNumber); - if (volume == null) - { + // Handle People + foreach (var chapter in chapters) + { + PersonHelper.UpdatePeople(allPeople, chapter.People.Where(p => p.Role == PersonRole.Writer).Select(p => p.Name), PersonRole.Writer, + person => PersonHelper.AddPersonIfNotExists(series.Metadata.People, person)); + + PersonHelper.UpdatePeople(allPeople, chapter.People.Where(p => p.Role == PersonRole.CoverArtist).Select(p => p.Name), PersonRole.CoverArtist, + person => PersonHelper.AddPersonIfNotExists(series.Metadata.People, person)); + + PersonHelper.UpdatePeople(allPeople, chapter.People.Where(p => p.Role == PersonRole.Publisher).Select(p => p.Name), PersonRole.Publisher, + person => PersonHelper.AddPersonIfNotExists(series.Metadata.People, person)); + + PersonHelper.UpdatePeople(allPeople, chapter.People.Where(p => p.Role == PersonRole.Character).Select(p => p.Name), PersonRole.Character, + person => PersonHelper.AddPersonIfNotExists(series.Metadata.People, person)); + + PersonHelper.UpdatePeople(allPeople, chapter.People.Where(p => p.Role == PersonRole.Colorist).Select(p => p.Name), PersonRole.Colorist, + person => PersonHelper.AddPersonIfNotExists(series.Metadata.People, person)); + + PersonHelper.UpdatePeople(allPeople, chapter.People.Where(p => p.Role == PersonRole.Editor).Select(p => p.Name), PersonRole.Editor, + person => PersonHelper.AddPersonIfNotExists(series.Metadata.People, person)); + + PersonHelper.UpdatePeople(allPeople, chapter.People.Where(p => p.Role == PersonRole.Inker).Select(p => p.Name), PersonRole.Inker, + person => PersonHelper.AddPersonIfNotExists(series.Metadata.People, person)); + + PersonHelper.UpdatePeople(allPeople, chapter.People.Where(p => p.Role == PersonRole.Letterer).Select(p => p.Name), PersonRole.Letterer, + person => PersonHelper.AddPersonIfNotExists(series.Metadata.People, person)); + + PersonHelper.UpdatePeople(allPeople, chapter.People.Where(p => p.Role == PersonRole.Penciller).Select(p => p.Name), PersonRole.Penciller, + person => PersonHelper.AddPersonIfNotExists(series.Metadata.People, person)); + + PersonHelper.UpdatePeople(allPeople, chapter.People.Where(p => p.Role == PersonRole.Translator).Select(p => p.Name), PersonRole.Translator, + person => PersonHelper.AddPersonIfNotExists(series.Metadata.People, person)); + + TagHelper.UpdateTag(allTags, chapter.Tags.Select(t => t.Title), false, (tag, added) => + TagHelper.AddTagIfNotExists(series.Metadata.Tags, tag)); + + GenreHelper.UpdateGenre(allGenres, chapter.Genres.Select(t => t.Title), false, genre => + GenreHelper.AddGenreIfNotExists(series.Metadata.Genres, genre)); + } + + var people = chapters.SelectMany(c => c.People).ToList(); + PersonHelper.KeepOnlySamePeopleBetweenLists(series.Metadata.People, + people, person => series.Metadata.People.Remove(person)); + } + + + + private void UpdateVolumes(Series series, IList parsedInfos, ICollection allPeople, ICollection allTags, ICollection allGenres) + { + var startingVolumeCount = series.Volumes.Count; + // Add new volumes and update chapters per volume + var distinctVolumes = parsedInfos.DistinctVolumes(); + _logger.LogDebug("[ScannerService] Updating {DistinctVolumes} volumes on {SeriesName}", distinctVolumes.Count, series.Name); + foreach (var volumeNumber in distinctVolumes) + { + var volume = series.Volumes.SingleOrDefault(s => s.Name == volumeNumber); + if (volume == null) + { volume = DbFactory.Volume(volumeNumber); series.Volumes.Add(volume); _unitOfWork.VolumeRepository.Add(volume); - } + } - _logger.LogDebug("[ScannerService] Parsing {SeriesName} - Volume {VolumeNumber}", series.Name, volume.Name); - var infos = parsedInfos.Where(p => p.Volumes == volumeNumber).ToArray(); - UpdateChapters(volume, infos); - volume.Pages = volume.Chapters.Sum(c => c.Pages); - } + _logger.LogDebug("[ScannerService] Parsing {SeriesName} - Volume {VolumeNumber}", series.Name, volume.Name); + var infos = parsedInfos.Where(p => p.Volumes == volumeNumber).ToArray(); + UpdateChapters(volume, infos); + volume.Pages = volume.Chapters.Sum(c => c.Pages); - // Remove existing volumes that aren't in parsedInfos - var nonDeletedVolumes = series.Volumes.Where(v => parsedInfos.Select(p => p.Volumes).Contains(v.Name)).ToList(); - if (series.Volumes.Count != nonDeletedVolumes.Count) - { - _logger.LogDebug("[ScannerService] Removed {Count} volumes from {SeriesName} where parsed infos were not mapping with volume name", + // Update all the metadata on the Chapters + foreach (var chapter in volume.Chapters) + { + var firstFile = chapter.Files.OrderBy(x => x.Chapter).FirstOrDefault(); + if (firstFile == null || _cacheHelper.HasFileNotChangedSinceCreationOrLastScan(chapter, false, firstFile)) continue; + try + { + var firstChapterInfo = infos.SingleOrDefault(i => i.FullFilePath.Equals(firstFile.FilePath)); + UpdateChapterFromComicInfo(chapter, allPeople, allTags, allGenres, firstChapterInfo?.ComicInfo); + } + catch (Exception ex) + { + _logger.LogError(ex, "There was some issue when updating chapter's metadata"); + } + } + } + + // Remove existing volumes that aren't in parsedInfos + var nonDeletedVolumes = series.Volumes.Where(v => parsedInfos.Select(p => p.Volumes).Contains(v.Name)).ToList(); + if (series.Volumes.Count != nonDeletedVolumes.Count) + { + _logger.LogDebug("[ScannerService] Removed {Count} volumes from {SeriesName} where parsed infos were not mapping with volume name", (series.Volumes.Count - nonDeletedVolumes.Count), series.Name); - var deletedVolumes = series.Volumes.Except(nonDeletedVolumes); - foreach (var volume in deletedVolumes) - { - var file = volume.Chapters.FirstOrDefault()?.Files?.FirstOrDefault()?.FilePath ?? ""; - if (!string.IsNullOrEmpty(file) && File.Exists(file)) - { - _logger.LogError( - "[ScannerService] Volume cleanup code was trying to remove a volume with a file still existing on disk. File: {File}", - file); - } + var deletedVolumes = series.Volumes.Except(nonDeletedVolumes); + foreach (var volume in deletedVolumes) + { + var file = volume.Chapters.FirstOrDefault()?.Files?.FirstOrDefault()?.FilePath ?? ""; + if (!string.IsNullOrEmpty(file) && File.Exists(file)) + { + _logger.LogError( + "[ScannerService] Volume cleanup code was trying to remove a volume with a file still existing on disk. File: {File}", + file); + } - _logger.LogDebug("[ScannerService] Removed {SeriesName} - Volume {Volume}: {File}", series.Name, volume.Name, file); - } + _logger.LogDebug("[ScannerService] Removed {SeriesName} - Volume {Volume}: {File}", series.Name, volume.Name, file); + } - series.Volumes = nonDeletedVolumes; - } + series.Volumes = nonDeletedVolumes; + } - _logger.LogDebug("[ScannerService] Updated {SeriesName} volumes from {StartingVolumeCount} to {VolumeCount}", - series.Name, startingVolumeCount, series.Volumes.Count); - } + _logger.LogDebug("[ScannerService] Updated {SeriesName} volumes from {StartingVolumeCount} to {VolumeCount}", + series.Name, startingVolumeCount, series.Volumes.Count); + } - /// - /// - /// - /// - /// - private void UpdateChapters(Volume volume, IList parsedInfos) - { - // Add new chapters - foreach (var info in parsedInfos) - { - // Specials go into their own chapters with Range being their filename and IsSpecial = True. Non-Specials with Vol and Chap as 0 - // also are treated like specials for UI grouping. - Chapter chapter; - try - { + private void UpdateChapters(Volume volume, IList parsedInfos) + { + // Add new chapters + foreach (var info in parsedInfos) + { + // Specials go into their own chapters with Range being their filename and IsSpecial = True. Non-Specials with Vol and Chap as 0 + // also are treated like specials for UI grouping. + Chapter chapter; + try + { chapter = volume.Chapters.GetChapterByRange(info); - } - catch (Exception ex) - { + } + catch (Exception ex) + { _logger.LogError(ex, "{FileName} mapped as '{Series} - Vol {Volume} Ch {Chapter}' is a duplicate, skipping", info.FullFilePath, info.Series, info.Volumes, info.Chapters); continue; - } + } - if (chapter == null) - { + if (chapter == null) + { _logger.LogDebug( - "[ScannerService] Adding new chapter, {Series} - Vol {Volume} Ch {Chapter}", info.Series, info.Volumes, info.Chapters); + "[ScannerService] Adding new chapter, {Series} - Vol {Volume} Ch {Chapter}", info.Series, info.Volumes, info.Chapters); volume.Chapters.Add(DbFactory.Chapter(info)); - } - else - { + } + else + { chapter.UpdateFrom(info); - } + } - } + } - // Add files - foreach (var info in parsedInfos) - { - var specialTreatment = info.IsSpecialInfo(); - Chapter chapter; - try - { + // Add files + foreach (var info in parsedInfos) + { + var specialTreatment = info.IsSpecialInfo(); + Chapter chapter; + try + { chapter = volume.Chapters.GetChapterByRange(info); - } - catch (Exception ex) - { + } + catch (Exception ex) + { _logger.LogError(ex, "There was an exception parsing chapter. Skipping {SeriesName} Vol {VolumeNumber} Chapter {ChapterNumber} - Special treatment: {NeedsSpecialTreatment}", info.Series, volume.Name, info.Chapters, specialTreatment); continue; - } - if (chapter == null) continue; - AddOrUpdateFileForChapter(chapter, info); - chapter.Number = Parser.Parser.MinimumNumberFromRange(info.Chapters) + string.Empty; - chapter.Range = specialTreatment ? info.Filename : info.Chapters; - } + } + if (chapter == null) continue; + AddOrUpdateFileForChapter(chapter, info); + chapter.Number = Parser.Parser.MinimumNumberFromRange(info.Chapters) + string.Empty; + chapter.Range = specialTreatment ? info.Filename : info.Chapters; + } - // Remove chapters that aren't in parsedInfos or have no files linked - var existingChapters = volume.Chapters.ToList(); - foreach (var existingChapter in existingChapters) - { - if (existingChapter.Files.Count == 0 || !parsedInfos.HasInfo(existingChapter)) - { + // Remove chapters that aren't in parsedInfos or have no files linked + var existingChapters = volume.Chapters.ToList(); + foreach (var existingChapter in existingChapters) + { + if (existingChapter.Files.Count == 0 || !parsedInfos.HasInfo(existingChapter)) + { _logger.LogDebug("[ScannerService] Removed chapter {Chapter} for Volume {VolumeNumber} on {SeriesName}", existingChapter.Range, volume.Name, parsedInfos[0].Series); volume.Chapters.Remove(existingChapter); - } - else - { + } + else + { // Ensure we remove any files that no longer exist AND order existingChapter.Files = existingChapter.Files - .Where(f => parsedInfos.Any(p => p.FullFilePath == f.FilePath)) - .OrderBy(f => f.FilePath, _naturalSort).ToList(); + .Where(f => parsedInfos.Any(p => p.FullFilePath == f.FilePath)) + .OrderByNatural(f => f.FilePath).ToList(); existingChapter.Pages = existingChapter.Files.Sum(f => f.Pages); - } - } - } + } + } + } - private MangaFile CreateMangaFile(ParserInfo info) - { - MangaFile mangaFile = null; - switch (info.Format) - { - case MangaFormat.Archive: - { - mangaFile = new MangaFile() + private void AddOrUpdateFileForChapter(Chapter chapter, ParserInfo info) + { + chapter.Files ??= new List(); + var existingFile = chapter.Files.SingleOrDefault(f => f.FilePath == info.FullFilePath); + if (existingFile != null) + { + existingFile.Format = info.Format; + if (!_fileService.HasFileBeenModifiedSince(existingFile.FilePath, existingFile.LastModified) && existingFile.Pages != 0) return; + existingFile.Pages = _readingItemService.GetNumberOfPages(info.FullFilePath, info.Format); + // We skip updating DB here with last modified time so that metadata refresh can do it + } + else + { + var file = DbFactory.MangaFile(info.FullFilePath, info.Format, _readingItemService.GetNumberOfPages(info.FullFilePath, info.Format)); + if (file == null) return; + + chapter.Files.Add(file); + } + } + + private void UpdateChapterFromComicInfo(Chapter chapter, ICollection allPeople, ICollection allTags, ICollection allGenres, ComicInfo? info) + { + var firstFile = chapter.Files.OrderBy(x => x.Chapter).FirstOrDefault(); + if (firstFile == null || + _cacheHelper.HasFileNotChangedSinceCreationOrLastScan(chapter, false, firstFile)) return; + + var comicInfo = info; + if (info == null) + { + comicInfo = _readingItemService.GetComicInfo(firstFile.FilePath); + } + + if (comicInfo == null) return; + + chapter.AgeRating = ComicInfo.ConvertAgeRatingToEnum(comicInfo.AgeRating); + + if (!string.IsNullOrEmpty(comicInfo.Title)) + { + chapter.TitleName = comicInfo.Title.Trim(); + } + + if (!string.IsNullOrEmpty(comicInfo.Summary)) + { + chapter.Summary = comicInfo.Summary; + } + + if (!string.IsNullOrEmpty(comicInfo.LanguageISO)) + { + chapter.Language = comicInfo.LanguageISO; + } + + if (comicInfo.Count > 0) + { + chapter.TotalCount = comicInfo.Count; + } + + if (!string.IsNullOrEmpty(comicInfo.Number) && int.Parse(comicInfo.Number) > 0) + { + chapter.Count = int.Parse(comicInfo.Number); + } + + + + + if (comicInfo.Year > 0) + { + var day = Math.Max(comicInfo.Day, 1); + var month = Math.Max(comicInfo.Month, 1); + chapter.ReleaseDate = DateTime.Parse($"{month}/{day}/{comicInfo.Year}"); + } + + if (!string.IsNullOrEmpty(comicInfo.Colorist)) + { + var people = comicInfo.Colorist.Split(","); + PersonHelper.RemovePeople(chapter.People, people, PersonRole.Colorist); + PersonHelper.UpdatePeople(allPeople, people, PersonRole.Colorist, + person => PersonHelper.AddPersonIfNotExists(chapter.People, person)); + } + + if (!string.IsNullOrEmpty(comicInfo.Characters)) + { + var people = comicInfo.Characters.Split(","); + PersonHelper.RemovePeople(chapter.People, people, PersonRole.Character); + PersonHelper.UpdatePeople(allPeople, people, PersonRole.Character, + person => PersonHelper.AddPersonIfNotExists(chapter.People, person)); + } + + if (!string.IsNullOrEmpty(comicInfo.Translator)) + { + var people = comicInfo.Translator.Split(","); + PersonHelper.RemovePeople(chapter.People, people, PersonRole.Translator); + PersonHelper.UpdatePeople(allPeople, people, PersonRole.Translator, + person => PersonHelper.AddPersonIfNotExists(chapter.People, person)); + } + + if (!string.IsNullOrEmpty(comicInfo.Tags)) + { + var tags = comicInfo.Tags.Split(",").Select(s => s.Trim()).ToList(); + // Remove all tags that aren't matching between chapter tags and metadata + TagHelper.KeepOnlySameTagBetweenLists(chapter.Tags, tags.Select(t => DbFactory.Tag(t, false)).ToList()); + TagHelper.UpdateTag(allTags, tags, false, + (tag, added) => { - FilePath = info.FullFilePath, - Format = info.Format, - Pages = _archiveService.GetNumberOfPagesFromArchive(info.FullFilePath) - }; - break; - } - case MangaFormat.Pdf: - case MangaFormat.Epub: - { - mangaFile = new MangaFile() - { - FilePath = info.FullFilePath, - Format = info.Format, - Pages = _bookService.GetNumberOfPages(info.FullFilePath) - }; - break; - } - case MangaFormat.Image: - { - mangaFile = new MangaFile() - { - FilePath = info.FullFilePath, - Format = info.Format, - Pages = 1 - }; - break; - } - default: - _logger.LogWarning("[Scanner] Ignoring {Filename}. File type is not supported", info.Filename); - break; - } + chapter.Tags.Add(tag); + }); + } - mangaFile?.UpdateLastModified(); - return mangaFile; - } + if (!string.IsNullOrEmpty(comicInfo.Writer)) + { + var people = comicInfo.Writer.Split(","); + PersonHelper.RemovePeople(chapter.People, people, PersonRole.Writer); + PersonHelper.UpdatePeople(allPeople, people, PersonRole.Writer, + person => PersonHelper.AddPersonIfNotExists(chapter.People, person)); + } - private void AddOrUpdateFileForChapter(Chapter chapter, ParserInfo info) - { - chapter.Files ??= new List(); - var existingFile = chapter.Files.SingleOrDefault(f => f.FilePath == info.FullFilePath); - if (existingFile != null) - { - existingFile.Format = info.Format; - if (!existingFile.HasFileBeenModified() && existingFile.Pages != 0) return; - switch (existingFile.Format) - { - case MangaFormat.Epub: - case MangaFormat.Pdf: - existingFile.Pages = _bookService.GetNumberOfPages(info.FullFilePath); - break; - case MangaFormat.Image: - existingFile.Pages = 1; - break; - case MangaFormat.Unknown: - existingFile.Pages = 0; - break; - case MangaFormat.Archive: - existingFile.Pages = _archiveService.GetNumberOfPagesFromArchive(info.FullFilePath); - break; - } - existingFile.LastModified = File.GetLastWriteTime(info.FullFilePath); - } - else - { - var file = CreateMangaFile(info); - if (file == null) return; + if (!string.IsNullOrEmpty(comicInfo.Editor)) + { + var people = comicInfo.Editor.Split(","); + PersonHelper.RemovePeople(chapter.People, people, PersonRole.Editor); + PersonHelper.UpdatePeople(allPeople, people, PersonRole.Editor, + person => PersonHelper.AddPersonIfNotExists(chapter.People, person)); + } - chapter.Files.Add(file); - } - } + if (!string.IsNullOrEmpty(comicInfo.Inker)) + { + var people = comicInfo.Inker.Split(","); + PersonHelper.RemovePeople(chapter.People, people, PersonRole.Inker); + PersonHelper.UpdatePeople(allPeople, people, PersonRole.Inker, + person => PersonHelper.AddPersonIfNotExists(chapter.People, person)); + } + + if (!string.IsNullOrEmpty(comicInfo.Letterer)) + { + var people = comicInfo.Letterer.Split(","); + PersonHelper.RemovePeople(chapter.People, people, PersonRole.Letterer); + PersonHelper.UpdatePeople(allPeople, people, PersonRole.Letterer, + person => PersonHelper.AddPersonIfNotExists(chapter.People, person)); + } + + if (!string.IsNullOrEmpty(comicInfo.Penciller)) + { + var people = comicInfo.Penciller.Split(","); + PersonHelper.RemovePeople(chapter.People, people, PersonRole.Penciller); + PersonHelper.UpdatePeople(allPeople, people, PersonRole.Penciller, + person => PersonHelper.AddPersonIfNotExists(chapter.People, person)); + } + + if (!string.IsNullOrEmpty(comicInfo.CoverArtist)) + { + var people = comicInfo.CoverArtist.Split(","); + PersonHelper.RemovePeople(chapter.People, people, PersonRole.CoverArtist); + PersonHelper.UpdatePeople(allPeople, people, PersonRole.CoverArtist, + person => PersonHelper.AddPersonIfNotExists(chapter.People, person)); + } + + if (!string.IsNullOrEmpty(comicInfo.Publisher)) + { + var people = comicInfo.Publisher.Split(","); + PersonHelper.RemovePeople(chapter.People, people, PersonRole.Publisher); + PersonHelper.UpdatePeople(allPeople, people, PersonRole.Publisher, + person => PersonHelper.AddPersonIfNotExists(chapter.People, person)); + } + + if (!string.IsNullOrEmpty(comicInfo.Genre)) + { + var genres = comicInfo.Genre.Split(","); + GenreHelper.KeepOnlySameGenreBetweenLists(chapter.Genres, genres.Select(g => DbFactory.Genre(g, false)).ToList()); + GenreHelper.UpdateGenre(allGenres, genres, false, + genre => chapter.Genres.Add(genre)); + } } } diff --git a/API/Services/Tasks/StatsService.cs b/API/Services/Tasks/StatsService.cs index 0052e0cb4..1b9f25593 100644 --- a/API/Services/Tasks/StatsService.cs +++ b/API/Services/Tasks/StatsService.cs @@ -2,108 +2,111 @@ using System.Net.Http; using System.Runtime.InteropServices; using System.Threading.Tasks; +using API.Data; using API.DTOs.Stats; using API.Entities.Enums; -using API.Interfaces; -using API.Interfaces.Services; using Flurl.Http; using Kavita.Common.EnvironmentInfo; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; -namespace API.Services.Tasks +namespace API.Services.Tasks; + +public interface IStatsService { - public class StatsService : IStatsService + Task Send(); + Task GetServerInfo(); +} +public class StatsService : IStatsService +{ + private readonly ILogger _logger; + private readonly IUnitOfWork _unitOfWork; + private const string ApiUrl = "https://stats.kavitareader.com"; + + public StatsService(ILogger logger, IUnitOfWork unitOfWork) { - private readonly ILogger _logger; - private readonly IUnitOfWork _unitOfWork; - private const string ApiUrl = "https://stats.kavitareader.com"; + _logger = logger; + _unitOfWork = unitOfWork; - public StatsService(ILogger logger, IUnitOfWork unitOfWork) + FlurlHttp.ConfigureClient(ApiUrl, cli => + cli.Settings.HttpClientFactory = new UntrustedCertClientFactory()); + } + + /// + /// Due to all instances firing this at the same time, we can DDOS our server. This task when fired will schedule the task to be run + /// randomly over a 6 hour spread + /// + public async Task Send() + { + var allowStatCollection = (await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).AllowStatCollection; + if (!allowStatCollection) { - _logger = logger; - _unitOfWork = unitOfWork; - - FlurlHttp.ConfigureClient(ApiUrl, cli => - cli.Settings.HttpClientFactory = new UntrustedCertClientFactory()); + return; } - /// - /// Due to all instances firing this at the same time, we can DDOS our server. This task when fired will schedule the task to be run - /// randomly over a 6 hour spread - /// - public async Task Send() + await SendData(); + } + + /// + /// This must be public for Hangfire. Do not call this directly. + /// + // ReSharper disable once MemberCanBePrivate.Global + public async Task SendData() + { + var data = await GetServerInfo(); + await SendDataToStatsServer(data); + } + + + private async Task SendDataToStatsServer(ServerInfoDto data) + { + var responseContent = string.Empty; + + try { - var allowStatCollection = (await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).AllowStatCollection; - if (!allowStatCollection) + var response = await (ApiUrl + "/api/v2/stats") + .WithHeader("Accept", "application/json") + .WithHeader("User-Agent", "Kavita") + .WithHeader("x-api-key", "MsnvA2DfQqxSK5jh") + .WithHeader("x-kavita-version", BuildInfo.Version) + .WithHeader("Content-Type", "application/json") + .WithTimeout(TimeSpan.FromSeconds(30)) + .PostJsonAsync(data); + + if (response.StatusCode != StatusCodes.Status200OK) { - return; - } - - await SendData(); - } - - /// - /// This must be public for Hangfire. Do not call this directly. - /// - // ReSharper disable once MemberCanBePrivate.Global - public async Task SendData() - { - var data = await GetServerInfo(); - await SendDataToStatsServer(data); - } - - - private async Task SendDataToStatsServer(ServerInfoDto data) - { - var responseContent = string.Empty; - - try - { - var response = await (ApiUrl + "/api/v2/stats") - .WithHeader("Accept", "application/json") - .WithHeader("User-Agent", "Kavita") - .WithHeader("x-api-key", "MsnvA2DfQqxSK5jh") - .WithHeader("x-kavita-version", BuildInfo.Version) - .WithHeader("Content-Type", "application/json") - .WithTimeout(TimeSpan.FromSeconds(30)) - .PostJsonAsync(data); - - if (response.StatusCode != StatusCodes.Status200OK) - { - _logger.LogError("KavitaStats did not respond successfully. {Content}", response); - } - } - catch (HttpRequestException e) - { - var info = new - { - dataSent = data, - response = responseContent - }; - - _logger.LogError(e, "KavitaStats did not respond successfully. {Content}", info); - } - catch (Exception e) - { - _logger.LogError(e, "An error happened during the request to KavitaStats"); + _logger.LogError("KavitaStats did not respond successfully. {Content}", response); } } - - public async Task GetServerInfo() + catch (HttpRequestException e) { - var installId = await _unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.InstallId); - var serverInfo = new ServerInfoDto + var info = new { - InstallId = installId.Value, - Os = RuntimeInformation.OSDescription, - KavitaVersion = BuildInfo.Version.ToString(), - DotnetVersion = Environment.Version.ToString(), - IsDocker = new OsInfo(Array.Empty()).IsDocker, - NumOfCores = Math.Max(Environment.ProcessorCount, 1) + dataSent = data, + response = responseContent }; - return serverInfo; + _logger.LogError(e, "KavitaStats did not respond successfully. {Content}", info); + } + catch (Exception e) + { + _logger.LogError(e, "An error happened during the request to KavitaStats"); } } + + public async Task GetServerInfo() + { + var installId = await _unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.InstallId); + var serverInfo = new ServerInfoDto + { + InstallId = installId.Value, + Os = RuntimeInformation.OSDescription, + KavitaVersion = BuildInfo.Version.ToString(), + DotnetVersion = Environment.Version.ToString(), + IsDocker = new OsInfo(Array.Empty()).IsDocker, + NumOfCores = Math.Max(Environment.ProcessorCount, 1) + }; + + return serverInfo; + } } diff --git a/API/Services/Tasks/VersionUpdaterService.cs b/API/Services/Tasks/VersionUpdaterService.cs index 64e21d39a..178111051 100644 --- a/API/Services/Tasks/VersionUpdaterService.cs +++ b/API/Services/Tasks/VersionUpdaterService.cs @@ -4,7 +4,6 @@ using System.Linq; using System.Net.Http; using System.Threading.Tasks; using API.DTOs.Update; -using API.Interfaces.Services; using API.SignalR; using API.SignalR.Presence; using Flurl.Http; @@ -15,159 +14,155 @@ using Microsoft.AspNetCore.SignalR; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; -namespace API.Services.Tasks +namespace API.Services.Tasks; + +internal class GithubReleaseMetadata { - internal class GithubReleaseMetadata - { - /// - /// Name of the Tag - /// v0.4.3 - /// - // ReSharper disable once InconsistentNaming - public string Tag_Name { get; init; } - /// - /// Name of the Release - /// - public string Name { get; init; } - /// - /// Body of the Release - /// - public string Body { get; init; } - /// - /// Url of the release on Github - /// - // ReSharper disable once InconsistentNaming - public string Html_Url { get; init; } - /// - /// Date Release was Published - /// - // ReSharper disable once InconsistentNaming - public string Published_At { get; init; } - } + /// + /// Name of the Tag + /// v0.4.3 + /// + // ReSharper disable once InconsistentNaming + public string Tag_Name { get; init; } + /// + /// Name of the Release + /// + public string Name { get; init; } + /// + /// Body of the Release + /// + public string Body { get; init; } + /// + /// Url of the release on Github + /// + // ReSharper disable once InconsistentNaming + public string Html_Url { get; init; } + /// + /// Date Release was Published + /// + // ReSharper disable once InconsistentNaming + public string Published_At { get; init; } +} - public class UntrustedCertClientFactory : DefaultHttpClientFactory - { - public override HttpMessageHandler CreateMessageHandler() { - return new HttpClientHandler { - ServerCertificateCustomValidationCallback = (_, _, _, _) => true - }; - } - } - - public class VersionUpdaterService : IVersionUpdaterService - { - private readonly ILogger _logger; - private readonly IHubContext _messageHub; - private readonly IPresenceTracker _tracker; - private readonly Markdown _markdown = new MarkdownDeep.Markdown(); -#pragma warning disable S1075 - private static readonly string GithubLatestReleasesUrl = "https://api.github.com/repos/Kareadita/Kavita/releases/latest"; - private static readonly string GithubAllReleasesUrl = "https://api.github.com/repos/Kareadita/Kavita/releases"; -#pragma warning restore S1075 - - public VersionUpdaterService(ILogger logger, IHubContext messageHub, IPresenceTracker tracker) - { - _logger = logger; - _messageHub = messageHub; - _tracker = tracker; - - FlurlHttp.ConfigureClient(GithubLatestReleasesUrl, cli => - cli.Settings.HttpClientFactory = new UntrustedCertClientFactory()); - FlurlHttp.ConfigureClient(GithubAllReleasesUrl, cli => - cli.Settings.HttpClientFactory = new UntrustedCertClientFactory()); - } - - /// - /// Fetches the latest release from Github - /// - public async Task CheckForUpdate() - { - var update = await GetGithubRelease(); - return CreateDto(update); - } - - /// - /// - /// - /// - public async Task> GetAllReleases() - { - var updates = await GetGithubReleases(); - return updates.Select(CreateDto); - } - - private UpdateNotificationDto CreateDto(GithubReleaseMetadata update) - { - if (update == null || string.IsNullOrEmpty(update.Tag_Name)) return null; - var updateVersion = new Version(update.Tag_Name.Replace("v", string.Empty)); - var currentVersion = BuildInfo.Version.ToString(); - - if (updateVersion.Revision == -1) - { - currentVersion = currentVersion.Substring(0, currentVersion.LastIndexOf(".", StringComparison.Ordinal)); - } - - return new UpdateNotificationDto() - { - CurrentVersion = currentVersion, - UpdateVersion = updateVersion.ToString(), - UpdateBody = _markdown.Transform(update.Body.Trim()), - UpdateTitle = update.Name, - UpdateUrl = update.Html_Url, - IsDocker = new OsInfo(Array.Empty()).IsDocker, - PublishDate = update.Published_At - }; - } - - public async Task PushUpdate(UpdateNotificationDto update) - { - if (update == null) return; - - var admins = await _tracker.GetOnlineAdmins(); - var updateVersion = new Version(update.CurrentVersion); - - if (BuildInfo.Version < updateVersion) - { - _logger.LogInformation("Server is out of date. Current: {CurrentVersion}. Available: {AvailableUpdate}", BuildInfo.Version, updateVersion); - await SendEvent(update, admins); - } - else if (Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == Environments.Development) - { - _logger.LogInformation("Server is up to date. Current: {CurrentVersion}", BuildInfo.Version); - await SendEvent(update, admins); - } - } - - private async Task SendEvent(UpdateNotificationDto update, IReadOnlyList admins) - { - var connections = new List(); - foreach (var admin in admins) - { - connections.AddRange(await _tracker.GetConnectionsForUser(admin)); - } - - await _messageHub.Clients.Users(admins).SendAsync(SignalREvents.UpdateVersion, MessageFactory.UpdateVersionEvent(update)); - } - - - private static async Task GetGithubRelease() - { - var update = await GithubLatestReleasesUrl - .WithHeader("Accept", "application/json") - .WithHeader("User-Agent", "Kavita") - .GetJsonAsync(); - - return update; - } - - private static async Task> GetGithubReleases() - { - var update = await GithubAllReleasesUrl - .WithHeader("Accept", "application/json") - .WithHeader("User-Agent", "Kavita") - .GetJsonAsync>(); - - return update; - } +public class UntrustedCertClientFactory : DefaultHttpClientFactory +{ + public override HttpMessageHandler CreateMessageHandler() { + return new HttpClientHandler { + ServerCertificateCustomValidationCallback = (_, _, _, _) => true + }; + } +} + +public interface IVersionUpdaterService +{ + Task CheckForUpdate(); + Task PushUpdate(UpdateNotificationDto update); + Task> GetAllReleases(); +} + +public class VersionUpdaterService : IVersionUpdaterService +{ + private readonly ILogger _logger; + private readonly IHubContext _messageHub; + private readonly IPresenceTracker _tracker; + private readonly Markdown _markdown = new MarkdownDeep.Markdown(); +#pragma warning disable S1075 + private static readonly string GithubLatestReleasesUrl = "https://api.github.com/repos/Kareadita/Kavita/releases/latest"; + private static readonly string GithubAllReleasesUrl = "https://api.github.com/repos/Kareadita/Kavita/releases"; +#pragma warning restore S1075 + + public VersionUpdaterService(ILogger logger, IHubContext messageHub, IPresenceTracker tracker) + { + _logger = logger; + _messageHub = messageHub; + _tracker = tracker; + + FlurlHttp.ConfigureClient(GithubLatestReleasesUrl, cli => + cli.Settings.HttpClientFactory = new UntrustedCertClientFactory()); + FlurlHttp.ConfigureClient(GithubAllReleasesUrl, cli => + cli.Settings.HttpClientFactory = new UntrustedCertClientFactory()); + } + + /// + /// Fetches the latest release from Github + /// + public async Task CheckForUpdate() + { + var update = await GetGithubRelease(); + return CreateDto(update); + } + + public async Task> GetAllReleases() + { + var updates = await GetGithubReleases(); + return updates.Select(CreateDto); + } + + private UpdateNotificationDto CreateDto(GithubReleaseMetadata update) + { + if (update == null || string.IsNullOrEmpty(update.Tag_Name)) return null; + var updateVersion = new Version(update.Tag_Name.Replace("v", string.Empty)); + var currentVersion = BuildInfo.Version.ToString(); + + if (updateVersion.Revision == -1) + { + currentVersion = currentVersion.Substring(0, currentVersion.LastIndexOf(".", StringComparison.Ordinal)); + } + + return new UpdateNotificationDto() + { + CurrentVersion = currentVersion, + UpdateVersion = updateVersion.ToString(), + UpdateBody = _markdown.Transform(update.Body.Trim()), + UpdateTitle = update.Name, + UpdateUrl = update.Html_Url, + IsDocker = new OsInfo(Array.Empty()).IsDocker, + PublishDate = update.Published_At + }; + } + + public async Task PushUpdate(UpdateNotificationDto update) + { + if (update == null) return; + + var admins = await _tracker.GetOnlineAdmins(); + var updateVersion = new Version(update.CurrentVersion); + + if (BuildInfo.Version < updateVersion) + { + _logger.LogInformation("Server is out of date. Current: {CurrentVersion}. Available: {AvailableUpdate}", BuildInfo.Version, updateVersion); + await SendEvent(update, admins); + } + else if (Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == Environments.Development) + { + _logger.LogInformation("Server is up to date. Current: {CurrentVersion}", BuildInfo.Version); + await SendEvent(update, admins); + } + } + + private async Task SendEvent(UpdateNotificationDto update, IReadOnlyList admins) + { + await _messageHub.Clients.Users(admins).SendAsync(SignalREvents.UpdateAvailable, MessageFactory.UpdateVersionEvent(update)); + } + + + private static async Task GetGithubRelease() + { + var update = await GithubLatestReleasesUrl + .WithHeader("Accept", "application/json") + .WithHeader("User-Agent", "Kavita") + .GetJsonAsync(); + + return update; + } + + private static async Task> GetGithubReleases() + { + var update = await GithubAllReleasesUrl + .WithHeader("Accept", "application/json") + .WithHeader("User-Agent", "Kavita") + .GetJsonAsync>(); + + return update; } } diff --git a/API/Services/TokenService.cs b/API/Services/TokenService.cs index 3b292cb8c..8145b330e 100644 --- a/API/Services/TokenService.cs +++ b/API/Services/TokenService.cs @@ -6,51 +6,54 @@ using System.Security.Claims; using System.Text; using System.Threading.Tasks; using API.Entities; -using API.Interfaces.Services; using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.Configuration; using Microsoft.IdentityModel.Tokens; using JwtRegisteredClaimNames = Microsoft.IdentityModel.JsonWebTokens.JwtRegisteredClaimNames; -namespace API.Services +namespace API.Services; + +public interface ITokenService { - public class TokenService : ITokenService + Task CreateToken(AppUser user); +} + +public class TokenService : ITokenService +{ + private readonly UserManager _userManager; + private readonly SymmetricSecurityKey _key; + + public TokenService(IConfiguration config, UserManager userManager) { - private readonly UserManager _userManager; - private readonly SymmetricSecurityKey _key; - public TokenService(IConfiguration config, UserManager userManager) - { - - _userManager = userManager; - _key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(config["TokenKey"])); - } - - public async Task CreateToken(AppUser user) - { - var claims = new List - { - new Claim(JwtRegisteredClaimNames.NameId, user.UserName) - }; - - var roles = await _userManager.GetRolesAsync(user); - - claims.AddRange(roles.Select(role => new Claim(ClaimTypes.Role, role))); - - var creds = new SigningCredentials(_key, SecurityAlgorithms.HmacSha512Signature); - - var tokenDescriptor = new SecurityTokenDescriptor() - { - Subject = new ClaimsIdentity(claims), - Expires = DateTime.Now.AddDays(7), - SigningCredentials = creds - }; - - var tokenHandler = new JwtSecurityTokenHandler(); - var token = tokenHandler.CreateToken(tokenDescriptor); - - return tokenHandler.WriteToken(token); - } + _userManager = userManager; + _key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(config["TokenKey"])); } -} \ No newline at end of file + + public async Task CreateToken(AppUser user) + { + var claims = new List + { + new Claim(JwtRegisteredClaimNames.NameId, user.UserName) + }; + + var roles = await _userManager.GetRolesAsync(user); + + claims.AddRange(roles.Select(role => new Claim(ClaimTypes.Role, role))); + + var creds = new SigningCredentials(_key, SecurityAlgorithms.HmacSha512Signature); + + var tokenDescriptor = new SecurityTokenDescriptor() + { + Subject = new ClaimsIdentity(claims), + Expires = DateTime.Now.AddDays(7), + SigningCredentials = creds + }; + + var tokenHandler = new JwtSecurityTokenHandler(); + var token = tokenHandler.CreateToken(tokenDescriptor); + + return tokenHandler.WriteToken(token); + } +} diff --git a/API/Services/WarmupServiceStartupTask.cs b/API/Services/WarmupServiceStartupTask.cs deleted file mode 100644 index 36463451a..000000000 --- a/API/Services/WarmupServiceStartupTask.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using API.Interfaces.Services; -using Microsoft.Extensions.DependencyInjection; - -namespace API.Services -{ - public class WarmupServicesStartupTask : IStartupTask - { - private readonly IServiceCollection _services; - private readonly IServiceProvider _provider; - public WarmupServicesStartupTask(IServiceCollection services, IServiceProvider provider) - { - _services = services; - _provider = provider; - } - - public Task ExecuteAsync(CancellationToken cancellationToken = default) - { - using var scope = _provider.CreateScope(); - foreach (var singleton in GetServices(_services)) - { - Console.WriteLine("DI preloading of " + singleton.FullName); - scope.ServiceProvider.GetServices(singleton); - } - - return Task.CompletedTask; - } - - static IEnumerable GetServices(IServiceCollection services) - { - return services - .Where(descriptor => descriptor.ImplementationType != typeof(WarmupServicesStartupTask)) - .Where(descriptor => !descriptor.ServiceType.ContainsGenericParameters) - .Select(descriptor => descriptor.ServiceType) - .Distinct(); - } - } - -} \ No newline at end of file diff --git a/API/SignalR/MessageFactory.cs b/API/SignalR/MessageFactory.cs index 3ab6c646c..25262430a 100644 --- a/API/SignalR/MessageFactory.cs +++ b/API/SignalR/MessageFactory.cs @@ -50,7 +50,7 @@ namespace API.SignalR { return new SignalRMessage() { - Name = SignalREvents.ScanLibrary, + Name = SignalREvents.ScanLibraryProgress, Body = new { LibraryId = libraryId, @@ -118,7 +118,7 @@ namespace API.SignalR { return new SignalRMessage { - Name = SignalREvents.UpdateVersion, + Name = SignalREvents.UpdateAvailable, Body = update }; } @@ -127,7 +127,7 @@ namespace API.SignalR { return new SignalRMessage { - Name = SignalREvents.UpdateVersion, + Name = SignalREvents.UpdateAvailable, Body = new { TagId = tagId, @@ -147,5 +147,19 @@ namespace API.SignalR } }; } + + public static SignalRMessage DownloadProgressEvent(string username, string downloadName, float progress) + { + return new SignalRMessage() + { + Name = SignalREvents.DownloadProgress, + Body = new + { + UserName = username, + DownloadName = downloadName, + Progress = progress + } + }; + } } } diff --git a/API/SignalR/Presence/PresenceTracker.cs b/API/SignalR/Presence/PresenceTracker.cs index 1453bd0f7..73d6479ff 100644 --- a/API/SignalR/Presence/PresenceTracker.cs +++ b/API/SignalR/Presence/PresenceTracker.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using API.Interfaces; +using API.Data; namespace API.SignalR.Presence { diff --git a/API/SignalR/SignalREvents.cs b/API/SignalR/SignalREvents.cs index 06908c2be..15590f426 100644 --- a/API/SignalR/SignalREvents.cs +++ b/API/SignalR/SignalREvents.cs @@ -2,7 +2,7 @@ { public static class SignalREvents { - public const string UpdateVersion = "UpdateVersion"; + public const string UpdateAvailable = "UpdateAvailable"; public const string ScanSeries = "ScanSeries"; /// /// Event during Refresh Metadata for cover image change @@ -12,12 +12,29 @@ /// Event sent out during Refresh Metadata for progress tracking /// public const string RefreshMetadataProgress = "RefreshMetadataProgress"; - public const string ScanLibrary = "ScanLibrary"; + /// + /// Series is added to server + /// public const string SeriesAdded = "SeriesAdded"; + /// + /// Series is removed from server + /// public const string SeriesRemoved = "SeriesRemoved"; + /// + /// Progress event for Scan library + /// public const string ScanLibraryProgress = "ScanLibraryProgress"; + /// + /// When a user is connects/disconnects from server + /// public const string OnlineUsers = "OnlineUsers"; + /// + /// When a series is added to a collection + /// public const string SeriesAddedToCollection = "SeriesAddedToCollection"; + /// + /// When an error occurs during a scan library task + /// public const string ScanLibraryError = "ScanLibraryError"; /// /// Event sent out during backing up the database @@ -27,5 +44,10 @@ /// Event sent out during cleaning up temp and cache folders /// public const string CleanupProgress = "CleanupProgress"; + /// + /// Event sent out during downloading of files + /// + public const string DownloadProgress = "DownloadProgress"; + } } diff --git a/API/SignalR/SignalRMessage.cs b/API/SignalR/SignalRMessage.cs index 89b992b4b..dfb181105 100644 --- a/API/SignalR/SignalRMessage.cs +++ b/API/SignalR/SignalRMessage.cs @@ -1,5 +1,8 @@ namespace API.SignalR { + /// + /// Payload for SignalR messages to Frontend + /// public class SignalRMessage { public object Body { get; set; } diff --git a/API/Startup.cs b/API/Startup.cs index 6668927b4..00bfdd589 100644 --- a/API/Startup.cs +++ b/API/Startup.cs @@ -4,12 +4,14 @@ using System.IO.Compression; using System.Linq; using System.Net; using System.Net.Sockets; +using System.Threading.Tasks; +using API.Data; +using API.Entities; using API.Extensions; -using API.Interfaces; -using API.Interfaces.Repositories; using API.Middleware; using API.Services; using API.Services.HostedServices; +using API.Services.Tasks; using API.SignalR; using Hangfire; using Hangfire.MemoryStorage; @@ -19,13 +21,16 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.HttpOverrides; +using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.ResponseCompression; using Microsoft.AspNetCore.StaticFiles; +using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Microsoft.OpenApi.Models; +using TaskScheduler = API.Services.TaskScheduler; namespace API { @@ -128,8 +133,66 @@ namespace API // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IBackgroundJobClient backgroundJobs, IWebHostEnvironment env, - IHostApplicationLifetime applicationLifetime, IServiceProvider serviceProvider) + IHostApplicationLifetime applicationLifetime, IServiceProvider serviceProvider, ICacheService cacheService, + IDirectoryService directoryService, IUnitOfWork unitOfWork, IBackupService backupService, IImageService imageService) { + + // Apply Migrations + try + { + Task.Run(async () => + { + // Apply all migrations on startup + // If we have pending migrations, make a backup first + //var isDocker = new OsInfo(Array.Empty()).IsDocker; + var logger = serviceProvider.GetRequiredService>(); + var context = serviceProvider.GetRequiredService(); + // var pendingMigrations = await context.Database.GetPendingMigrationsAsync(); + // if (pendingMigrations.Any()) + // { + // logger.LogInformation("Performing backup as migrations are needed"); + // await backupService.BackupDatabase(); + // } + // + // await context.Database.MigrateAsync(); + // var roleManager = serviceProvider.GetRequiredService>(); + // + // await Seed.SeedRoles(roleManager); + // await Seed.SeedSettings(context, directoryService); + // await Seed.SeedUserApiKeys(context); + + await MigrateBookmarks.Migrate(directoryService, unitOfWork, + logger, cacheService); + + var requiresCoverImageMigration = !Directory.Exists(directoryService.CoverImageDirectory); + try + { + // If this is a new install, tables wont exist yet + if (requiresCoverImageMigration) + { + MigrateCoverImages.ExtractToImages(context, directoryService, imageService); + } + } + catch (Exception) + { + requiresCoverImageMigration = false; + } + + if (requiresCoverImageMigration) + { + await MigrateCoverImages.UpdateDatabaseWithImages(context, directoryService); + } + }).GetAwaiter() + .GetResult(); + } + catch (Exception ex) + { + var logger = serviceProvider.GetRequiredService>(); + logger.LogCritical(ex, "An error occurred during migration"); + } + + + app.UseMiddleware(); if (env.IsDevelopment()) @@ -146,7 +209,7 @@ namespace API app.UseForwardedHeaders(new ForwardedHeadersOptions { - ForwardedHeaders = ForwardedHeaders.All + ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto | ForwardedHeaders.XForwardedHost }); app.UseRouting(); diff --git a/Kavita.Common/Configuration.cs b/Kavita.Common/Configuration.cs index 6e6899f3f..7593ae84a 100644 --- a/Kavita.Common/Configuration.cs +++ b/Kavita.Common/Configuration.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using System.Linq; using System.Text.Json; using Kavita.Common.EnvironmentInfo; using Microsoft.Extensions.Hosting; @@ -193,12 +194,9 @@ namespace Kavita.Common foreach (var property in tokenElement.EnumerateObject()) { if (!property.Name.Equals("LogLevel")) continue; - foreach (var logProperty in property.Value.EnumerateObject()) + foreach (var logProperty in property.Value.EnumerateObject().Where(logProperty => logProperty.Name.Equals("Default"))) { - if (logProperty.Name.Equals("Default")) - { - return logProperty.Value.GetString(); - } + return logProperty.Value.GetString(); } } } diff --git a/Kavita.Common/Kavita.Common.csproj b/Kavita.Common/Kavita.Common.csproj index 005b8a5b8..8285453bb 100644 --- a/Kavita.Common/Kavita.Common.csproj +++ b/Kavita.Common/Kavita.Common.csproj @@ -1,17 +1,17 @@ - net5.0 + net6.0 kavitareader.com Kavita - 0.4.9.2 + 0.5.0.0 en - - - + + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/UI/Web/package-lock.json b/UI/Web/package-lock.json index 5f8160aba..8a71fcd8b 100644 --- a/UI/Web/package-lock.json +++ b/UI/Web/package-lock.json @@ -5326,9 +5326,9 @@ "dev": true }, "decimal.js": { - "version": "10.2.1", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.2.1.tgz", - "integrity": "sha512-KaL7+6Fw6i5A2XSnsbhm/6B+NuEA7TZ4vqxnd5tXz9sbKtrN9Srj8ab4vKVdK8YAqZO9P1kg45Y6YLoduPf+kw==", + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz", + "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==", "dev": true }, "decode-uri-component": { @@ -5352,9 +5352,9 @@ } }, "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "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 }, "deepmerge": { @@ -5956,18 +5956,24 @@ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, "escodegen": { - "version": "1.14.3", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", - "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", + "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", "dev": true, "requires": { "esprima": "^4.0.1", - "estraverse": "^4.2.0", + "estraverse": "^5.2.0", "esutils": "^2.0.2", "optionator": "^0.8.1", "source-map": "~0.6.1" }, "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -6623,9 +6629,9 @@ } }, "follow-redirects": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.0.tgz", - "integrity": "sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA==", + "version": "1.14.7", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.7.tgz", + "integrity": "sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ==", "dev": true }, "for-in": { @@ -7856,9 +7862,9 @@ } }, "is-potential-custom-element-name": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.0.tgz", - "integrity": "sha1-DFLlS8yjkbssSUsh6GJtczbG45c=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", "dev": true }, "is-regex": { @@ -9593,66 +9599,91 @@ "dev": true }, "jsdom": { - "version": "16.4.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.4.0.tgz", - "integrity": "sha512-lYMm3wYdgPhrl7pDcRmvzPhhrGVBeVhPIqeHjzeiHN3DFmD1RBpbExbi8vU7BJdH8VAZYovR8DMt0PNNDM7k8w==", + "version": "16.7.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", + "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", "dev": true, "requires": { - "abab": "^2.0.3", - "acorn": "^7.1.1", + "abab": "^2.0.5", + "acorn": "^8.2.4", "acorn-globals": "^6.0.0", "cssom": "^0.4.4", - "cssstyle": "^2.2.0", + "cssstyle": "^2.3.0", "data-urls": "^2.0.0", - "decimal.js": "^10.2.0", + "decimal.js": "^10.2.1", "domexception": "^2.0.1", - "escodegen": "^1.14.1", + "escodegen": "^2.0.0", + "form-data": "^3.0.0", "html-encoding-sniffer": "^2.0.1", - "is-potential-custom-element-name": "^1.0.0", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-potential-custom-element-name": "^1.0.1", "nwsapi": "^2.2.0", - "parse5": "5.1.1", - "request": "^2.88.2", - "request-promise-native": "^1.0.8", - "saxes": "^5.0.0", + "parse5": "6.0.1", + "saxes": "^5.0.1", "symbol-tree": "^3.2.4", - "tough-cookie": "^3.0.1", + "tough-cookie": "^4.0.0", "w3c-hr-time": "^1.0.2", "w3c-xmlserializer": "^2.0.0", "webidl-conversions": "^6.1.0", "whatwg-encoding": "^1.0.5", "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.0.0", - "ws": "^7.2.3", + "whatwg-url": "^8.5.0", + "ws": "^7.4.6", "xml-name-validator": "^3.0.0" }, "dependencies": { "acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.6.0.tgz", + "integrity": "sha512-U1riIR+lBSNi3IbxtaHOIKdH8sLFv3NYfNv8sg7ZsNhcfl4HF2++BfqqrNAxoCLQW1iiylOj76ecnaUxz+z9yw==", "dev": true }, - "parse5": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", - "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==", - "dev": true - }, - "tough-cookie": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.1.tgz", - "integrity": "sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg==", + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", "dev": true, "requires": { - "ip-regex": "^2.1.0", - "psl": "^1.1.28", - "punycode": "^2.1.1" + "debug": "4" + } + }, + "form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "https-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "dev": true, + "requires": { + "agent-base": "6", + "debug": "4" + } + }, + "tough-cookie": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", + "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", + "dev": true, + "requires": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.1.2" } }, "ws": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.5.tgz", - "integrity": "sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w==", + "version": "7.5.6", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.6.tgz", + "integrity": "sha512-6GLgCqo2cy2A2rjCNFlxQS6ZljG/coZfZXclldI8FB/1G3CCI36Zd8xy2HrFVACi8tfk5XrgLQEk+P0Tnz9UcA==", "dev": true } } @@ -9675,9 +9706,9 @@ "dev": true }, "json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", "dev": true }, "json-schema-traverse": { @@ -9728,14 +9759,14 @@ "dev": true }, "jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", "dev": true, "requires": { "assert-plus": "1.0.0", "extsprintf": "1.3.0", - "json-schema": "0.2.3", + "json-schema": "0.4.0", "verror": "1.10.0" } }, @@ -9955,12 +9986,6 @@ "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", "dev": true }, - "lodash.sortby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", - "dev": true - }, "lodash.uniq": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", @@ -13093,26 +13118,6 @@ } } }, - "request-promise-core": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz", - "integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==", - "dev": true, - "requires": { - "lodash": "^4.17.19" - } - }, - "request-promise-native": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.9.tgz", - "integrity": "sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g==", - "dev": true, - "requires": { - "request-promise-core": "1.1.4", - "stealthy-require": "^1.1.1", - "tough-cookie": "^2.3.3" - } - }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -14442,12 +14447,6 @@ "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", "dev": true }, - "stealthy-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", - "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", - "dev": true - }, "stream-browserify": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", @@ -15009,9 +15008,9 @@ } }, "tr46": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.0.2.tgz", - "integrity": "sha512-3n1qG+/5kg+jrbTzwAykB5yRYtQCTqOGKq5U5PE3b0a1/mzo6snDhjGS0zJVJunO0NrT3Dg1MLy5TjWP/UJppg==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", + "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", "dev": true, "requires": { "punycode": "^2.1.1" @@ -16651,13 +16650,13 @@ "dev": true }, "whatwg-url": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.4.0.tgz", - "integrity": "sha512-vwTUFf6V4zhcPkWp/4CQPr1TW9Ml6SF4lVyaIMBdJw5i6qUUJ1QWM4Z6YYVkfka0OUIzVo/0aNtGVGk256IKWw==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", + "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", "dev": true, "requires": { - "lodash.sortby": "^4.7.0", - "tr46": "^2.0.2", + "lodash": "^4.7.0", + "tr46": "^2.1.0", "webidl-conversions": "^6.1.0" } }, @@ -16819,9 +16818,9 @@ } }, "ws": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz", - "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.2.tgz", + "integrity": "sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==", "requires": { "async-limiter": "~1.0.0" } diff --git a/UI/Web/src/app/_models/chapter-metadata.ts b/UI/Web/src/app/_models/chapter-metadata.ts new file mode 100644 index 000000000..56f400210 --- /dev/null +++ b/UI/Web/src/app/_models/chapter-metadata.ts @@ -0,0 +1,16 @@ +import { Person } from "./person"; + +export interface ChapterMetadata { + id: number; + chapterId: number; + title: string; + year: string; + writers: Array; + penciller: Array; + inker: Array; + colorist: Array; + letterer: Array; + coverArtist: Array; + editor: Array; + publishers: Array; +} \ No newline at end of file diff --git a/UI/Web/src/app/_models/chapter.ts b/UI/Web/src/app/_models/chapter.ts index 4a9399489..1a66e2471 100644 --- a/UI/Web/src/app/_models/chapter.ts +++ b/UI/Web/src/app/_models/chapter.ts @@ -1,4 +1,6 @@ import { MangaFile } from './manga-file'; +import { Person } from './person'; +import { Tag } from './tag'; export interface Chapter { id: number; @@ -16,4 +18,19 @@ export interface Chapter { isSpecial: boolean; title: string; created: string; + + titleName: string; + /** + * This is only Year and Month, Day is not supported from underlying sources + */ + releaseDate: string; + writers: Array; + penciller: Array; + inker: Array; + colorist: Array; + letterer: Array; + coverArtist: Array; + editor: Array; + publisher: Array; + tags: Array; } diff --git a/UI/Web/src/app/_models/genre.ts b/UI/Web/src/app/_models/genre.ts new file mode 100644 index 000000000..f1160230d --- /dev/null +++ b/UI/Web/src/app/_models/genre.ts @@ -0,0 +1,4 @@ +export interface Genre { + id: number, + title: string; +} \ No newline at end of file diff --git a/UI/Web/src/app/_models/metadata/age-rating-dto.ts b/UI/Web/src/app/_models/metadata/age-rating-dto.ts new file mode 100644 index 000000000..ebf0728b9 --- /dev/null +++ b/UI/Web/src/app/_models/metadata/age-rating-dto.ts @@ -0,0 +1,6 @@ +import { AgeRating } from "./age-rating"; + +export interface AgeRatingDto { + value: AgeRating; + title: string; +} \ No newline at end of file diff --git a/UI/Web/src/app/_models/metadata/age-rating.ts b/UI/Web/src/app/_models/metadata/age-rating.ts new file mode 100644 index 000000000..d44a8e250 --- /dev/null +++ b/UI/Web/src/app/_models/metadata/age-rating.ts @@ -0,0 +1,15 @@ +export enum AgeRating { + Unknown = 0, + AdultsOnly = 1, + EarlyChildhood = 2, + Everyone = 3, + Everyone10Plus = 4, + G = 5, + KidsToAdults = 6, + Mature = 7, + Mature15Plus = 8, + Mature17Plus = 9, + RatingPending = 10, + Teen = 11, + X18Plus = 12 +} \ No newline at end of file diff --git a/UI/Web/src/app/_models/metadata/language.ts b/UI/Web/src/app/_models/metadata/language.ts new file mode 100644 index 000000000..c88ff3939 --- /dev/null +++ b/UI/Web/src/app/_models/metadata/language.ts @@ -0,0 +1,4 @@ +export interface Language { + isoCode: string; + title: string; +} \ No newline at end of file diff --git a/UI/Web/src/app/_models/metadata/publication-status-dto.ts b/UI/Web/src/app/_models/metadata/publication-status-dto.ts new file mode 100644 index 000000000..74281c2d2 --- /dev/null +++ b/UI/Web/src/app/_models/metadata/publication-status-dto.ts @@ -0,0 +1,6 @@ +import { PublicationStatus } from "./publication-status"; + +export interface PublicationStatusDto { + value: PublicationStatus; + title: string; +} \ No newline at end of file diff --git a/UI/Web/src/app/_models/metadata/publication-status.ts b/UI/Web/src/app/_models/metadata/publication-status.ts new file mode 100644 index 000000000..7881da383 --- /dev/null +++ b/UI/Web/src/app/_models/metadata/publication-status.ts @@ -0,0 +1,5 @@ +export enum PublicationStatus { + OnGoing = 0, + Hiatus = 1, + Completed = 2 +} \ No newline at end of file diff --git a/UI/Web/src/app/_models/page-bookmark.ts b/UI/Web/src/app/_models/page-bookmark.ts index 6d46bfe4d..e47ef0a06 100644 --- a/UI/Web/src/app/_models/page-bookmark.ts +++ b/UI/Web/src/app/_models/page-bookmark.ts @@ -4,4 +4,5 @@ export interface PageBookmark { seriesId: number; volumeId: number; chapterId: number; + fileName: string; } \ No newline at end of file diff --git a/UI/Web/src/app/_models/person.ts b/UI/Web/src/app/_models/person.ts index a8a60436d..e23925cef 100644 --- a/UI/Web/src/app/_models/person.ts +++ b/UI/Web/src/app/_models/person.ts @@ -1,10 +1,20 @@ export enum PersonRole { - Other = 0, - Author = 1, - Artist = 2 + Other = 1, + Artist = 2, + Writer = 3, + Penciller = 4, + Inker = 5, + Colorist = 6, + Letterer = 7, + CoverArtist = 8, + Editor = 9, + Publisher = 10, + Character = 11, + Translator = 12 } export interface Person { + id: number; name: string; role: PersonRole; } \ No newline at end of file diff --git a/UI/Web/src/app/_models/preferences/preferences.ts b/UI/Web/src/app/_models/preferences/preferences.ts index 7e44dbbee..664afb7f7 100644 --- a/UI/Web/src/app/_models/preferences/preferences.ts +++ b/UI/Web/src/app/_models/preferences/preferences.ts @@ -1,3 +1,4 @@ + import { PageSplitOption } from './page-split-option'; import { READER_MODE } from './reader-mode'; import { ReadingDirection } from './reading-direction'; diff --git a/UI/Web/src/app/_models/series-filter.ts b/UI/Web/src/app/_models/series-filter.ts index a81cfe381..068054a27 100644 --- a/UI/Web/src/app/_models/series-filter.ts +++ b/UI/Web/src/app/_models/series-filter.ts @@ -1,38 +1,70 @@ import { MangaFormat } from "./manga-format"; -export interface FilterItem { +export interface FilterItem { title: string; - value: any; + value: T; selected: boolean; } export interface SeriesFilter { - mangaFormat: MangaFormat | null; + formats: Array; + libraries: Array, + readStatus: ReadStatus; + genres: Array; + writers: Array; + penciller: Array; + inker: Array; + colorist: Array; + letterer: Array; + coverArtist: Array; + editor: Array; + publisher: Array; + character: Array; + translators: Array; + collectionTags: Array; + rating: number; + ageRating: Array; + sortOptions: SortOptions | null; + tags: Array; + languages: Array; + publicationStatus: Array; +} + +export interface SortOptions { + sortField: SortField; + isAscending: boolean; +} + +export enum SortField { + SortName = 1, + Created = 2, + LastModified = 3 +} + +export interface ReadStatus { + notRead: boolean, + inProgress: boolean, + read: boolean, } export const mangaFormatFilters = [ { - title: 'Format: All', - value: null, - selected: false - }, - { - title: 'Format: Images', + title: 'Images', value: MangaFormat.IMAGE, selected: false }, { - title: 'Format: EPUB', + title: 'EPUB', value: MangaFormat.EPUB, selected: false }, { - title: 'Format: PDF', + title: 'PDF', value: MangaFormat.PDF, selected: false }, { - title: 'Format: ARCHIVE', + title: 'ARCHIVE', value: MangaFormat.ARCHIVE, selected: false } diff --git a/UI/Web/src/app/_models/series-metadata.ts b/UI/Web/src/app/_models/series-metadata.ts index 4cba7848f..e143a9639 100644 --- a/UI/Web/src/app/_models/series-metadata.ts +++ b/UI/Web/src/app/_models/series-metadata.ts @@ -1,10 +1,29 @@ import { CollectionTag } from "./collection-tag"; +import { Genre } from "./genre"; +import { AgeRating } from "./metadata/age-rating"; +import { PublicationStatus } from "./metadata/publication-status"; import { Person } from "./person"; +import { Tag } from "./tag"; export interface SeriesMetadata { publisher: string; - genres: Array; - tags: Array; - persons: Array; + summary: string; + genres: Array; + tags: Array; + collectionTags: Array; + writers: Array; + coverArtists: Array; + publishers: Array; + characters: Array; + pencillers: Array; + inkers: Array; + colorists: Array; + letterers: Array; + editors: Array; + translators: Array; + ageRating: AgeRating; + releaseYear: number; + language: string; seriesId: number; + publicationStatus: PublicationStatus; } \ No newline at end of file diff --git a/UI/Web/src/app/_models/series.ts b/UI/Web/src/app/_models/series.ts index be233122b..332407105 100644 --- a/UI/Web/src/app/_models/series.ts +++ b/UI/Web/src/app/_models/series.ts @@ -7,7 +7,6 @@ export interface Series { originalName: string; // This is not shown to user localizedName: string; sortName: string; - summary: string; coverImageLocked: boolean; volumes: Volume[]; pages: number; // Total pages in series diff --git a/UI/Web/src/app/_models/tag.ts b/UI/Web/src/app/_models/tag.ts new file mode 100644 index 000000000..c75d48be6 --- /dev/null +++ b/UI/Web/src/app/_models/tag.ts @@ -0,0 +1,4 @@ +export interface Tag { + id: number, + title: string; +} \ No newline at end of file diff --git a/UI/Web/src/app/_services/action-factory.service.ts b/UI/Web/src/app/_services/action-factory.service.ts index 0df929e8f..a0d1609ff 100644 --- a/UI/Web/src/app/_services/action-factory.service.ts +++ b/UI/Web/src/app/_services/action-factory.service.ts @@ -79,7 +79,7 @@ export class ActionFactoryService { this.seriesActions.push({ action: Action.RefreshMetadata, - title: 'Refresh Metadata', + title: 'Refresh Covers', callback: this.dummyCallback, requiresAdmin: true }); @@ -114,7 +114,7 @@ export class ActionFactoryService { this.libraryActions.push({ action: Action.RefreshMetadata, - title: 'Refresh Metadata', + title: 'Refresh Covers', callback: this.dummyCallback, requiresAdmin: true }); diff --git a/UI/Web/src/app/_services/action.service.ts b/UI/Web/src/app/_services/action.service.ts index 5ada05dc2..66615388c 100644 --- a/UI/Web/src/app/_services/action.service.ts +++ b/UI/Web/src/app/_services/action.service.ts @@ -23,6 +23,7 @@ export type VolumeActionCallback = (volume: Volume) => void; export type ChapterActionCallback = (chapter: Chapter) => void; export type ReadingListActionCallback = (readingList: ReadingList) => void; export type VoidActionCallback = () => void; +export type BooleanActionCallback = (result: boolean) => void; /** * Responsible for executing actions @@ -57,7 +58,7 @@ export class ActionService implements OnDestroy { return; } this.libraryService.scan(library?.id).pipe(take(1)).subscribe((res: any) => { - this.toastr.success('Scan started for ' + library.name); + this.toastr.success('Scan queued for ' + library.name); if (callback) { callback(library); } @@ -75,12 +76,15 @@ export class ActionService implements OnDestroy { return; } - if (!await this.confirmService.confirm('Refresh metadata will force all cover images and metadata to be recalculated. This is a heavy operation. Are you sure you don\'t want to perform a Scan instead?')) { + if (!await this.confirmService.confirm('Refresh covers will force all cover images to be recalculated. This is a heavy operation. Are you sure you don\'t want to perform a Scan instead?')) { + if (callback) { + callback(library); + } return; } this.libraryService.refreshMetadata(library?.id).pipe(take(1)).subscribe((res: any) => { - this.toastr.success('Scan started for ' + library.name); + this.toastr.success('Scan queued for ' + library.name); if (callback) { callback(library); } @@ -124,7 +128,7 @@ export class ActionService implements OnDestroy { */ scanSeries(series: Series, callback?: SeriesActionCallback) { this.seriesService.scan(series.libraryId, series.id).pipe(take(1)).subscribe((res: any) => { - this.toastr.success('Scan started for ' + series.name); + this.toastr.success('Scan queued for ' + series.name); if (callback) { callback(series); } @@ -137,7 +141,10 @@ export class ActionService implements OnDestroy { * @param callback Optional callback to perform actions after API completes */ async refreshMetdata(series: Series, callback?: SeriesActionCallback) { - if (!await this.confirmService.confirm('Refresh metadata will force all cover images and metadata to be recalculated. This is a heavy operation. Are you sure you don\'t want to perform a Scan instead?')) { + if (!await this.confirmService.confirm('Refresh covers will force all cover images and metadata to be recalculated. This is a heavy operation. Are you sure you don\'t want to perform a Scan instead?')) { + if (callback) { + callback(series); + } return; } @@ -484,4 +491,20 @@ export class ActionService implements OnDestroy { }); } + async deleteSeries(series: Series, callback?: BooleanActionCallback) { + if (!await this.confirmService.confirm('Are you sure you want to delete this series? It will not modify files on disk.')) { + if (callback) { + callback(false); + } + return; + } + + this.seriesService.delete(series.id).subscribe((res: boolean) => { + if (callback) { + this.toastr.success('Series deleted'); + callback(res); + } + }); + } + } diff --git a/UI/Web/src/app/_services/image.service.ts b/UI/Web/src/app/_services/image.service.ts index 2141d3e4d..4cb21c299 100644 --- a/UI/Web/src/app/_services/image.service.ts +++ b/UI/Web/src/app/_services/image.service.ts @@ -1,18 +1,24 @@ -import { Injectable } from '@angular/core'; +import { Injectable, OnDestroy } from '@angular/core'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; import { environment } from 'src/environments/environment'; +import { AccountService } from './account.service'; import { NavService } from './nav.service'; @Injectable({ providedIn: 'root' }) -export class ImageService { +export class ImageService implements OnDestroy { baseUrl = environment.apiUrl; + apiKey: string = ''; public placeholderImage = 'assets/images/image-placeholder-min.png'; public errorImage = 'assets/images/error-placeholder2-min.png'; public resetCoverImage = 'assets/images/image-reset-cover-min.png'; - constructor(private navSerivce: NavService) { + private onDestroy: Subject = new Subject(); + + constructor(private navSerivce: NavService, private accountService: AccountService) { this.navSerivce.darkMode$.subscribe(res => { if (res) { this.placeholderImage = 'assets/images/image-placeholder.dark-min.png'; @@ -22,6 +28,17 @@ export class ImageService { this.errorImage = 'assets/images/error-placeholder2-min.png'; } }); + + this.accountService.currentUser$.pipe(takeUntil(this.onDestroy)).subscribe(user => { + if (user) { + this.apiKey = user.apiKey; + } + }); + } + + ngOnDestroy(): void { + this.onDestroy.next(); + this.onDestroy.complete(); } getVolumeCoverImage(volumeId: number) { @@ -41,7 +58,7 @@ export class ImageService { } getBookmarkedImage(chapterId: number, pageNum: number) { - return this.baseUrl + 'image/chapter-cover?chapterId=' + chapterId + '&pageNum=' + pageNum; + return this.baseUrl + 'image/bookmark?chapterId=' + chapterId + '&pageNum=' + pageNum + '&apiKey=' + encodeURIComponent(this.apiKey); } updateErroredImage(event: any) { diff --git a/UI/Web/src/app/_services/message-hub.service.ts b/UI/Web/src/app/_services/message-hub.service.ts index 85a543322..259f2a4c1 100644 --- a/UI/Web/src/app/_services/message-hub.service.ts +++ b/UI/Web/src/app/_services/message-hub.service.ts @@ -24,7 +24,8 @@ export enum EVENTS { SeriesAddedToCollection = 'SeriesAddedToCollection', ScanLibraryError = 'ScanLibraryError', BackupDatabaseProgress = 'BackupDatabaseProgress', - CleanupProgress = 'CleanupProgress' + CleanupProgress = 'CleanupProgress', + DownloadProgress = 'DownloadProgress' } export interface Message { @@ -38,7 +39,6 @@ export interface Message { export class MessageHubService { hubUrl = environment.hubUrl; private hubConnection!: HubConnection; - private updateNotificationModalRef: NgbModalRef | null = null; private messagesSource = new ReplaySubject>(1); public messages$ = this.messagesSource.asObservable(); @@ -53,7 +53,7 @@ export class MessageHubService { isAdmin: boolean = false; - constructor(private modalService: NgbModal, private toastr: ToastrService, private router: Router) { + constructor(private toastr: ToastrService, private router: Router) { } @@ -106,6 +106,13 @@ export class MessageHubService { }); }); + this.hubConnection.on(EVENTS.DownloadProgress, resp => { + this.messagesSource.next({ + event: EVENTS.DownloadProgress, + payload: resp.body + }); + }); + this.hubConnection.on(EVENTS.RefreshMetadataProgress, resp => { this.messagesSource.next({ event: EVENTS.RefreshMetadataProgress, @@ -162,16 +169,6 @@ export class MessageHubService { event: EVENTS.UpdateAvailable, payload: resp.body }); - // Ensure only 1 instance of UpdateNotificationModal can be open at once - if (this.updateNotificationModalRef != null) { return; } - this.updateNotificationModalRef = this.modalService.open(UpdateNotificationModalComponent, { scrollable: true, size: 'lg' }); - this.updateNotificationModalRef.componentInstance.updateData = resp.body; - this.updateNotificationModalRef.closed.subscribe(() => { - this.updateNotificationModalRef = null; - }); - this.updateNotificationModalRef.dismissed.subscribe(() => { - this.updateNotificationModalRef = null; - }); }); } diff --git a/UI/Web/src/app/_services/metadata.service.ts b/UI/Web/src/app/_services/metadata.service.ts new file mode 100644 index 000000000..4d64a7920 --- /dev/null +++ b/UI/Web/src/app/_services/metadata.service.ts @@ -0,0 +1,87 @@ +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { of } from 'rxjs'; +import { map } from 'rxjs/operators'; +import { environment } from 'src/environments/environment'; +import { ChapterMetadata } from '../_models/chapter-metadata'; +import { Genre } from '../_models/genre'; +import { AgeRating } from '../_models/metadata/age-rating'; +import { AgeRatingDto } from '../_models/metadata/age-rating-dto'; +import { Language } from '../_models/metadata/language'; +import { PublicationStatusDto } from '../_models/metadata/publication-status-dto'; +import { Person } from '../_models/person'; +import { Tag } from '../_models/tag'; + +@Injectable({ + providedIn: 'root' +}) +export class MetadataService { + + baseUrl = environment.apiUrl; + + private ageRatingTypes: {[key: number]: string} | undefined = undefined; + + constructor(private httpClient: HttpClient) { } + + getAgeRating(ageRating: AgeRating) { + if (this.ageRatingTypes != undefined && this.ageRatingTypes.hasOwnProperty(ageRating)) { + return of(this.ageRatingTypes[ageRating]); + } + return this.httpClient.get(this.baseUrl + 'series/age-rating?ageRating=' + ageRating, {responseType: 'text' as 'json'}).pipe(map(ratingString => { + if (this.ageRatingTypes === undefined) { + this.ageRatingTypes = {}; + } + + this.ageRatingTypes[ageRating] = ratingString; + return this.ageRatingTypes[ageRating]; + })); + } + + getAllAgeRatings(libraries?: Array) { + let method = 'metadata/age-ratings' + if (libraries != undefined && libraries.length > 0) { + method += '?libraryIds=' + libraries.join(','); + } + return this.httpClient.get>(this.baseUrl + method);; + } + + getAllPublicationStatus(libraries?: Array) { + let method = 'metadata/publication-status' + if (libraries != undefined && libraries.length > 0) { + method += '?libraryIds=' + libraries.join(','); + } + return this.httpClient.get>(this.baseUrl + method);; + } + + getAllTags(libraries?: Array) { + let method = 'metadata/tags' + if (libraries != undefined && libraries.length > 0) { + method += '?libraryIds=' + libraries.join(','); + } + return this.httpClient.get>(this.baseUrl + method);; + } + + getAllGenres(libraries?: Array) { + let method = 'metadata/genres' + if (libraries != undefined && libraries.length > 0) { + method += '?libraryIds=' + libraries.join(','); + } + return this.httpClient.get(this.baseUrl + method); + } + + getAllLanguages(libraries?: Array) { + let method = 'metadata/languages' + if (libraries != undefined && libraries.length > 0) { + method += '?libraryIds=' + libraries.join(','); + } + return this.httpClient.get(this.baseUrl + method); + } + + getAllPeople(libraries?: Array) { + let method = 'metadata/people' + if (libraries != undefined && libraries.length > 0) { + method += '?libraryIds=' + libraries.join(','); + } + return this.httpClient.get(this.baseUrl + method); + } +} diff --git a/UI/Web/src/app/_services/nav.service.ts b/UI/Web/src/app/_services/nav.service.ts index 2412c794a..74ccc3339 100644 --- a/UI/Web/src/app/_services/nav.service.ts +++ b/UI/Web/src/app/_services/nav.service.ts @@ -1,4 +1,4 @@ -import { Injectable } from '@angular/core'; +import { Injectable, Renderer2, RendererFactory2 } from '@angular/core'; import { ReplaySubject } from 'rxjs'; @Injectable({ @@ -13,7 +13,10 @@ export class NavService { private darkModeSource = new ReplaySubject(1); darkMode$ = this.darkModeSource.asObservable(); - constructor() { + private renderer: Renderer2; + + constructor(rendererFactory: RendererFactory2) { + this.renderer = rendererFactory.createRenderer(null, null); this.showNavBar(); } @@ -27,13 +30,23 @@ export class NavService { toggleDarkMode() { this.darkMode = !this.darkMode; + this.updateColorScheme(); this.darkModeSource.next(this.darkMode); } setDarkMode(mode: boolean) { this.darkMode = mode; + this.updateColorScheme(); this.darkModeSource.next(this.darkMode); } + private updateColorScheme() { + if (this.darkMode) { + this.renderer.setStyle(document.querySelector('html'), 'color-scheme', 'dark'); + } else { + this.renderer.setStyle(document.querySelector('html'), 'color-scheme', 'light'); + } + } + } diff --git a/UI/Web/src/app/_services/reader.service.ts b/UI/Web/src/app/_services/reader.service.ts index 8281ab9e9..16c2ea656 100644 --- a/UI/Web/src/app/_services/reader.service.ts +++ b/UI/Web/src/app/_services/reader.service.ts @@ -193,4 +193,34 @@ export class ReaderService { } return params; } + + enterFullscreen(el: Element, callback?: VoidFunction) { + if (!document.fullscreenElement) { + if (el.requestFullscreen) { + el.requestFullscreen().then(() => { + if (callback) { + callback(); + } + }); + } + } + } + + exitFullscreen(callback?: VoidFunction) { + if (document.exitFullscreen && this.checkFullscreenMode()) { + document.exitFullscreen().then(() => { + if (callback) { + callback(); + } + }); + } + } + + /** + * + * @returns If document is in fullscreen mode + */ + checkFullscreenMode() { + return document.fullscreenElement != null; + } } diff --git a/UI/Web/src/app/_services/reading-list.service.ts b/UI/Web/src/app/_services/reading-list.service.ts index e520154d6..3ad5255f6 100644 --- a/UI/Web/src/app/_services/reading-list.service.ts +++ b/UI/Web/src/app/_services/reading-list.service.ts @@ -75,7 +75,7 @@ export class ReadingListService { } removeRead(readingListId: number) { - return this.httpClient.post(this.baseUrl + 'readinglist/remove-read?readingListId=' + readingListId, { responseType: 'text' as 'json' }); + return this.httpClient.post(this.baseUrl + 'readinglist/remove-read?readingListId=' + readingListId, {}, { responseType: 'text' as 'json' }); } actionListFilter(action: ActionItem, readingList: ReadingList, isAdmin: boolean) { diff --git a/UI/Web/src/app/_services/series.service.ts b/UI/Web/src/app/_services/series.service.ts index 8ed258c45..af02b8e88 100644 --- a/UI/Web/src/app/_services/series.service.ts +++ b/UI/Web/src/app/_services/series.service.ts @@ -8,7 +8,7 @@ import { CollectionTag } from '../_models/collection-tag'; import { InProgressChapter } from '../_models/in-progress-chapter'; import { PaginatedResult } from '../_models/pagination'; import { Series } from '../_models/series'; -import { SeriesFilter } from '../_models/series-filter'; +import { ReadStatus, SeriesFilter } from '../_models/series-filter'; import { SeriesMetadata } from '../_models/series-metadata'; import { Volume } from '../_models/volume'; import { ImageService } from './image.service'; @@ -39,6 +39,18 @@ export class SeriesService { return paginatedVariable; } + getAllSeries(pageNum?: number, itemsPerPage?: number, filter?: SeriesFilter) { + let params = new HttpParams(); + params = this._addPaginationIfExists(params, pageNum, itemsPerPage); + const data = this.createSeriesFilter(filter); + + return this.httpClient.post>(this.baseUrl + 'series/all', data, {observe: 'response', params}).pipe( + map((response: any) => { + return this._cachePaginatedResults(response, this.paginatedResults); + }) + ); + } + getSeriesForLibrary(libraryId: number, pageNum?: number, itemsPerPage?: number, filter?: SeriesFilter) { let params = new HttpParams(); params = this._addPaginationIfExists(params, pageNum, itemsPerPage); @@ -137,7 +149,7 @@ export class SeriesService { getMetadata(seriesId: number) { return this.httpClient.get(this.baseUrl + 'series/metadata?seriesId=' + seriesId).pipe(map(items => { - items?.tags.forEach(tag => tag.coverImage = this.imageService.getCollectionCoverImage(tag.id)); + items?.collectionTags.forEach(tag => tag.coverImage = this.imageService.getCollectionCoverImage(tag.id)); return items; })); } @@ -177,13 +189,35 @@ export class SeriesService { createSeriesFilter(filter?: SeriesFilter) { const data: SeriesFilter = { - mangaFormat: null + formats: [], + libraries: [], + genres: [], + writers: [], + penciller: [], + inker: [], + colorist: [], + letterer: [], + coverArtist: [], + editor: [], + publisher: [], + character: [], + translators: [], + collectionTags: [], + rating: 0, + readStatus: { + read: true, + inProgress: true, + notRead: true + }, + sortOptions: null, + ageRating: [], + tags: [], + languages: [], + publicationStatus: [], }; - if (filter) { - data.mangaFormat = filter.mangaFormat; - } + if (filter === undefined) return data; - return data; + return filter; } } diff --git a/UI/Web/src/app/admin/_modals/directory-picker/directory-picker.component.html b/UI/Web/src/app/admin/_modals/directory-picker/directory-picker.component.html index 6f6d02630..60debc54d 100644 --- a/UI/Web/src/app/admin/_modals/directory-picker/directory-picker.component.html +++ b/UI/Web/src/app/admin/_modals/directory-picker/directory-picker.component.html @@ -36,6 +36,7 @@ Back + @@ -50,6 +51,6 @@ diff --git a/UI/Web/src/app/admin/_modals/directory-picker/directory-picker.component.ts b/UI/Web/src/app/admin/_modals/directory-picker/directory-picker.component.ts index 85fa530bb..2885c40de 100644 --- a/UI/Web/src/app/admin/_modals/directory-picker/directory-picker.component.ts +++ b/UI/Web/src/app/admin/_modals/directory-picker/directory-picker.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, Input, OnInit } from '@angular/core'; import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; import { Stack } from 'src/app/shared/data-structures/stack'; import { LibraryService } from '../../../_services/library.service'; @@ -17,6 +17,12 @@ export interface DirectoryPickerResult { }) export class DirectoryPickerComponent implements OnInit { + @Input() startingFolder: string = ''; + /** + * Url to give more information about selecting directories. Passing nothing will suppress. + */ + @Input() helpUrl: string = 'https://wiki.kavitareader.com/en/guides/adding-a-library'; + currentRoot = ''; folders: string[] = []; routeStack: Stack = new Stack(); @@ -27,7 +33,22 @@ export class DirectoryPickerComponent implements OnInit { } ngOnInit(): void { - this.loadChildren(this.currentRoot); + if (this.startingFolder && this.startingFolder.length > 0) { + let folders = this.startingFolder.split('/'); + let folders2 = this.startingFolder.split('\\'); + if (folders.length === 1 && folders2.length > 1) { + folders = folders2; + } + if (!folders[0].endsWith('/')) { + folders[0] = folders[0] + '/'; + } + folders.forEach(folder => this.routeStack.push(folder)); + + const fullPath = this.routeStack.items.join('/'); + this.loadChildren(fullPath); + } else { + this.loadChildren(this.currentRoot); + } } filterFolder = (folder: string) => { @@ -38,7 +59,7 @@ export class DirectoryPickerComponent implements OnInit { this.currentRoot = folderName; this.routeStack.push(folderName); const fullPath = this.routeStack.items.join('/'); - this.loadChildren(fullPath); + this.loadChildren(fullPath); } goBack() { @@ -86,7 +107,7 @@ export class DirectoryPickerComponent implements OnInit { if (lastPath && lastPath != path) { let replaced = path.replace(lastPath, ''); if (replaced.startsWith('/') || replaced.startsWith('\\')) { - replaced = replaced.substr(1, replaced.length); + replaced = replaced.substring(1, replaced.length); } return replaced; } @@ -95,14 +116,11 @@ export class DirectoryPickerComponent implements OnInit { } navigateTo(index: number) { - const numberOfPops = this.routeStack.items.length - index; - if (this.routeStack.items.length - numberOfPops > this.routeStack.items.length) { - this.routeStack.items = []; - } - for (let i = 0; i < numberOfPops; i++) { + while(this.routeStack.items.length - 1 > index) { this.routeStack.pop(); } - - this.loadChildren(this.routeStack.peek() || ''); + + const fullPath = this.routeStack.items.join('/'); + this.loadChildren(fullPath); } } diff --git a/UI/Web/src/app/admin/_modals/library-editor-modal/library-editor-modal.component.html b/UI/Web/src/app/admin/_modals/library-editor-modal/library-editor-modal.component.html index 867be0a4a..a972328c3 100644 --- a/UI/Web/src/app/admin/_modals/library-editor-modal/library-editor-modal.component.html +++ b/UI/Web/src/app/admin/_modals/library-editor-modal/library-editor-modal.component.html @@ -16,8 +16,10 @@
    - -
    diff --git a/UI/Web/src/app/admin/_models/server-settings.ts b/UI/Web/src/app/admin/_models/server-settings.ts index fbcb2a0f0..1f5b398e9 100644 --- a/UI/Web/src/app/admin/_models/server-settings.ts +++ b/UI/Web/src/app/admin/_models/server-settings.ts @@ -8,4 +8,5 @@ export interface ServerSettings { enableOpds: boolean; enableAuthentication: boolean; baseUrl: string; + bookmarksDirectory: string; } diff --git a/UI/Web/src/app/admin/changelog/changelog.component.html b/UI/Web/src/app/admin/changelog/changelog.component.html index 9655fe18e..10709f0ed 100644 --- a/UI/Web/src/app/admin/changelog/changelog.component.html +++ b/UI/Web/src/app/admin/changelog/changelog.component.html @@ -3,11 +3,11 @@

    {{update.updateTitle}}  - Installed - Available + Installed + Available

    Published: {{update.publishDate | date: 'short'}}
    - +
    
               Download
             
    diff --git a/UI/Web/src/app/admin/changelog/changelog.component.ts b/UI/Web/src/app/admin/changelog/changelog.component.ts index e24ad9845..86724e92e 100644 --- a/UI/Web/src/app/admin/changelog/changelog.component.ts +++ b/UI/Web/src/app/admin/changelog/changelog.component.ts @@ -11,13 +11,26 @@ export class ChangelogComponent implements OnInit { updates: Array = []; isLoading: boolean = true; + installedVersion: string = ''; constructor(private serverService: ServerService) { } ngOnInit(): void { - this.serverService.getChangelog().subscribe(updates => { - this.updates = updates; - this.isLoading = false; + + this.serverService.getServerInfo().subscribe(info => { + this.installedVersion = info.kavitaVersion; + this.serverService.getChangelog().subscribe(updates => { + this.updates = updates; + this.isLoading = false; + + if (this.updates.filter(u => u.updateVersion === this.installedVersion).length === 0) { + // User is on a nightly version. Tell them the last stable is installed + this.installedVersion = this.updates[0].updateVersion; + } + }); }); + + + } } diff --git a/UI/Web/src/app/admin/manage-library/manage-library.component.ts b/UI/Web/src/app/admin/manage-library/manage-library.component.ts index d7a694ac1..d6e5a2364 100644 --- a/UI/Web/src/app/admin/manage-library/manage-library.component.ts +++ b/UI/Web/src/app/admin/manage-library/manage-library.component.ts @@ -39,14 +39,16 @@ export class ManageLibraryComponent implements OnInit, OnDestroy { // when a progress event comes in, show it on the UI next to library this.hubService.messages$.pipe(takeUntil(this.onDestroy)).subscribe((event) => { if (event.event !== EVENTS.ScanLibraryProgress) return; + + console.log('scan event: ', event.payload); const scanEvent = event.payload as ProgressEvent; - this.scanInProgress[scanEvent.libraryId] = {progress: scanEvent.progress !== 100}; + this.scanInProgress[scanEvent.libraryId] = {progress: scanEvent.progress !== 1}; if (scanEvent.progress === 0) { this.scanInProgress[scanEvent.libraryId].timestamp = scanEvent.eventTime; } - if (this.scanInProgress[scanEvent.libraryId].progress === false && scanEvent.progress === 100) { + if (this.scanInProgress[scanEvent.libraryId].progress === false && scanEvent.progress === 1) { this.libraryService.getLibraries().pipe(take(1)).subscribe(libraries => { const newLibrary = libraries.find(lib => lib.id === scanEvent.libraryId); const existingLibrary = this.libraries.find(lib => lib.id === scanEvent.libraryId); diff --git a/UI/Web/src/app/admin/manage-settings/manage-settings.component.html b/UI/Web/src/app/admin/manage-settings/manage-settings.component.html index 727d1069f..ecda0b4ac 100644 --- a/UI/Web/src/app/admin/manage-settings/manage-settings.component.html +++ b/UI/Web/src/app/admin/manage-settings/manage-settings.component.html @@ -8,6 +8,20 @@
    +
    +   + Location where bookmarks will be stored. Bookmarks are source files and can be large. Choose a location with adequate storage. Directory is managed, other files within directory will be deleted. + +
    + +
    + +
    +
    +
    + -
    -   - Port the server listens on. This is fixed if you are running on Docker. Requires restart to take effect. - Port the server listens on. This is fixed if you are running on Docker. Requires restart to take effect. - -
    - -
    -   - Use debug to help identify issues. Debug can eat up a lot of disk space. Requires restart to take effect. - Port the server listens on. Requires restart to take effect. - +
    +
    +   + Port the server listens on. This is fixed if you are running on Docker. Requires restart to take effect. + Port the server listens on. This is fixed if you are running on Docker. Requires restart to take effect. + +
    + +
    +   + Use debug to help identify issues. Debug can eat up a lot of disk space. Requires restart to take effect. + Port the server listens on. Requires restart to take effect. + +
    @@ -78,6 +94,7 @@
    +
    diff --git a/UI/Web/src/app/admin/manage-settings/manage-settings.component.ts b/UI/Web/src/app/admin/manage-settings/manage-settings.component.ts index 94509776a..eadfe5b71 100644 --- a/UI/Web/src/app/admin/manage-settings/manage-settings.component.ts +++ b/UI/Web/src/app/admin/manage-settings/manage-settings.component.ts @@ -1,9 +1,11 @@ import { Component, OnInit } from '@angular/core'; import { FormGroup, FormControl, Validators } from '@angular/forms'; +import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; import { ToastrService } from 'ngx-toastr'; import { take } from 'rxjs/operators'; import { ConfirmService } from 'src/app/shared/confirm.service'; import { SettingsService } from '../settings.service'; +import { DirectoryPickerComponent, DirectoryPickerResult } from '../_modals/directory-picker/directory-picker.component'; import { ServerSettings } from '../_models/server-settings'; @Component({ @@ -18,7 +20,8 @@ export class ManageSettingsComponent implements OnInit { taskFrequencies: Array = []; logLevels: Array = []; - constructor(private settingsService: SettingsService, private toastr: ToastrService, private confirmService: ConfirmService) { } + constructor(private settingsService: SettingsService, private toastr: ToastrService, private confirmService: ConfirmService, + private modalService: NgbModal) { } ngOnInit(): void { this.settingsService.getTaskFrequencies().pipe(take(1)).subscribe(frequencies => { @@ -30,6 +33,7 @@ export class ManageSettingsComponent implements OnInit { this.settingsService.getServerSettings().pipe(take(1)).subscribe((settings: ServerSettings) => { this.serverSettings = settings; this.settingsForm.addControl('cacheDirectory', new FormControl(this.serverSettings.cacheDirectory, [Validators.required])); + this.settingsForm.addControl('bookmarksDirectory', new FormControl(this.serverSettings.bookmarksDirectory, [Validators.required])); this.settingsForm.addControl('taskScan', new FormControl(this.serverSettings.taskScan, [Validators.required])); this.settingsForm.addControl('taskBackup', new FormControl(this.serverSettings.taskBackup, [Validators.required])); this.settingsForm.addControl('port', new FormControl(this.serverSettings.port, [Validators.required])); @@ -43,6 +47,7 @@ export class ManageSettingsComponent implements OnInit { resetForm() { this.settingsForm.get('cacheDirectory')?.setValue(this.serverSettings.cacheDirectory); + this.settingsForm.get('bookmarksDirectory')?.setValue(this.serverSettings.bookmarksDirectory); this.settingsForm.get('scanTask')?.setValue(this.serverSettings.taskScan); this.settingsForm.get('taskBackup')?.setValue(this.serverSettings.taskBackup); this.settingsForm.get('port')?.setValue(this.serverSettings.port); @@ -77,4 +82,26 @@ export class ManageSettingsComponent implements OnInit { }); } + resetToDefaults() { + this.settingsService.resetServerSettings().pipe(take(1)).subscribe(async (settings: ServerSettings) => { + this.serverSettings = settings; + this.resetForm(); + this.toastr.success('Server settings updated'); + }, (err: any) => { + console.error('error: ', err); + }); + } + + openDirectoryChooser(existingDirectory: string, formControl: string) { + const modalRef = this.modalService.open(DirectoryPickerComponent, { scrollable: true, size: 'lg' }); + modalRef.componentInstance.startingFolder = existingDirectory || ''; + modalRef.componentInstance.helpUrl = ''; + modalRef.closed.subscribe((closeResult: DirectoryPickerResult) => { + if (closeResult.success) { + this.settingsForm.get(formControl)?.setValue(closeResult.folderPath); + this.settingsForm.markAsTouched(); + } + }); + } + } diff --git a/UI/Web/src/app/admin/settings.service.ts b/UI/Web/src/app/admin/settings.service.ts index 9f0de0b3f..646fde087 100644 --- a/UI/Web/src/app/admin/settings.service.ts +++ b/UI/Web/src/app/admin/settings.service.ts @@ -21,6 +21,10 @@ export class SettingsService { return this.http.post(this.baseUrl + 'settings', model); } + resetServerSettings() { + return this.http.post(this.baseUrl + 'settings/reset', {}); + } + getTaskFrequencies() { return this.http.get(this.baseUrl + 'settings/task-frequencies'); } diff --git a/UI/Web/src/app/all-series/all-series.component.html b/UI/Web/src/app/all-series/all-series.component.html new file mode 100644 index 000000000..dc589e566 --- /dev/null +++ b/UI/Web/src/app/all-series/all-series.component.html @@ -0,0 +1,14 @@ + + + + + + diff --git a/UI/Web/src/app/all-series/all-series.component.scss b/UI/Web/src/app/all-series/all-series.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/UI/Web/src/app/all-series/all-series.component.ts b/UI/Web/src/app/all-series/all-series.component.ts new file mode 100644 index 000000000..51a37fc59 --- /dev/null +++ b/UI/Web/src/app/all-series/all-series.component.ts @@ -0,0 +1,145 @@ +import { Component, HostListener, OnDestroy, OnInit } from '@angular/core'; +import { Title } from '@angular/platform-browser'; +import { Router } from '@angular/router'; +import { Subject } from 'rxjs'; +import { take, debounceTime, takeUntil } from 'rxjs/operators'; +import { BulkSelectionService } from '../cards/bulk-selection.service'; +import { FilterSettings } from '../cards/card-detail-layout/card-detail-layout.component'; +import { KEY_CODES } from '../shared/_services/utility.service'; +import { SeriesAddedEvent } from '../_models/events/series-added-event'; +import { Library } from '../_models/library'; +import { Pagination } from '../_models/pagination'; +import { Series } from '../_models/series'; +import { SeriesFilter } from '../_models/series-filter'; +import { ActionItem, Action } from '../_services/action-factory.service'; +import { ActionService } from '../_services/action.service'; +import { MessageHubService } from '../_services/message-hub.service'; +import { SeriesService } from '../_services/series.service'; + +@Component({ + selector: 'app-all-series', + templateUrl: './all-series.component.html', + styleUrls: ['./all-series.component.scss'] +}) +export class AllSeriesComponent implements OnInit, OnDestroy { + + series: Series[] = []; + loadingSeries = false; + pagination!: Pagination; + actions: ActionItem[] = []; + filter: SeriesFilter | undefined = undefined; + onDestroy: Subject = new Subject(); + filterSettings: FilterSettings = new FilterSettings(); + + bulkActionCallback = (action: Action, data: any) => { + const selectedSeriesIndexies = this.bulkSelectionService.getSelectedCardsForSource('series'); + const selectedSeries = this.series.filter((series, index: number) => selectedSeriesIndexies.includes(index + '')); + + switch (action) { + case Action.AddToReadingList: + this.actionService.addMultipleSeriesToReadingList(selectedSeries, () => { + this.bulkSelectionService.deselectAll(); + }); + break; + case Action.AddToCollection: + this.actionService.addMultipleSeriesToCollectionTag(selectedSeries, () => { + this.bulkSelectionService.deselectAll(); + }); + break; + case Action.MarkAsRead: + this.actionService.markMultipleSeriesAsRead(selectedSeries, () => { + this.loadPage(); + this.bulkSelectionService.deselectAll(); + }); + + break; + case Action.MarkAsUnread: + this.actionService.markMultipleSeriesAsUnread(selectedSeries, () => { + this.loadPage(); + this.bulkSelectionService.deselectAll(); + }); + break; + case Action.Delete: + this.actionService.deleteMultipleSeries(selectedSeries, () => { + this.loadPage(); + this.bulkSelectionService.deselectAll(); + }); + break; + } + } + + constructor(private router: Router, private seriesService: SeriesService, + private titleService: Title, private actionService: ActionService, + public bulkSelectionService: BulkSelectionService, private hubService: MessageHubService) { + + this.router.routeReuseStrategy.shouldReuseRoute = () => false; + + this.titleService.setTitle('Kavita - All Series'); + this.pagination = {currentPage: 0, itemsPerPage: 30, totalItems: 0, totalPages: 1}; + + this.loadPage(); + } + + ngOnInit(): void { + this.hubService.seriesAdded.pipe(debounceTime(6000), takeUntil(this.onDestroy)).subscribe((event: SeriesAddedEvent) => { + this.loadPage(); + }); + } + + ngOnDestroy() { + this.onDestroy.next(); + this.onDestroy.complete(); + } + + @HostListener('document:keydown.shift', ['$event']) + handleKeypress(event: KeyboardEvent) { + if (event.key === KEY_CODES.SHIFT) { + this.bulkSelectionService.isShiftDown = true; + } + } + + @HostListener('document:keyup.shift', ['$event']) + handleKeyUp(event: KeyboardEvent) { + if (event.key === KEY_CODES.SHIFT) { + this.bulkSelectionService.isShiftDown = false; + } + } + + updateFilter(data: SeriesFilter) { + this.filter = data; + if (this.pagination !== undefined && this.pagination !== null) { + this.pagination.currentPage = 1; + this.onPageChange(this.pagination); + } else { + this.loadPage(); + } + } + + loadPage() { + const page = this.getPage(); + if (page != null) { + this.pagination.currentPage = parseInt(page, 10); + } + this.loadingSeries = true; + + this.seriesService.getAllSeries(this.pagination?.currentPage, this.pagination?.itemsPerPage, this.filter).pipe(take(1)).subscribe(series => { + this.series = series.result; + this.pagination = series.pagination; + this.loadingSeries = false; + window.scrollTo(0, 0); + }); + } + + onPageChange(pagination: Pagination) { + window.history.replaceState(window.location.href, '', window.location.href.split('?')[0] + '?page=' + this.pagination.currentPage); + this.loadPage(); + } + + trackByIdentity = (index: number, item: Series) => `${item.name}_${item.originalName}_${item.localizedName}_${item.pagesRead}`; + + getPage() { + const urlParams = new URLSearchParams(window.location.search); + return urlParams.get('page'); + } + +} diff --git a/UI/Web/src/app/app-routing.module.ts b/UI/Web/src/app/app-routing.module.ts index 39800d8cd..7f8bd88f7 100644 --- a/UI/Web/src/app/app-routing.module.ts +++ b/UI/Web/src/app/app-routing.module.ts @@ -9,6 +9,8 @@ import { AuthGuard } from './_guards/auth.guard'; import { LibraryAccessGuard } from './_guards/library-access.guard'; import { OnDeckComponent } from './on-deck/on-deck.component'; import { DashboardComponent } from './dashboard/dashboard.component'; +import { AllSeriesComponent } from './all-series/all-series.component'; +import { AdminGuard } from './_guards/admin.guard'; // TODO: Once we modularize the components, use this and measure performance impact: https://angular.io/guide/lazy-loading-ngmodules#preloading-modules @@ -16,18 +18,22 @@ const routes: Routes = [ {path: '', component: UserLoginComponent}, { path: 'admin', + canActivate: [AdminGuard], loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule) }, { path: 'collections', + canActivate: [AuthGuard], loadChildren: () => import('./collections/collections.module').then(m => m.CollectionsModule) }, { path: 'preferences', + canActivate: [AuthGuard], loadChildren: () => import('./user-settings/user-settings.module').then(m => m.UserSettingsModule) }, { path: 'lists', + canActivate: [AuthGuard], loadChildren: () => import('./reading-list/reading-list.module').then(m => m.ReadingListModule) }, { @@ -55,6 +61,8 @@ const routes: Routes = [ {path: 'library', component: DashboardComponent}, {path: 'recently-added', component: RecentlyAddedComponent}, {path: 'on-deck', component: OnDeckComponent}, + {path: 'all-series', component: AllSeriesComponent}, + ] }, {path: 'login', component: UserLoginComponent}, diff --git a/UI/Web/src/app/app.component.ts b/UI/Web/src/app/app.component.ts index d1e778d3c..c4a8cd863 100644 --- a/UI/Web/src/app/app.component.ts +++ b/UI/Web/src/app/app.component.ts @@ -6,7 +6,7 @@ import { LibraryService } from './_services/library.service'; import { MessageHubService } from './_services/message-hub.service'; import { NavService } from './_services/nav.service'; import { filter } from 'rxjs/operators'; -import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; +import { NgbModal, NgbRatingConfig } from '@ng-bootstrap/ng-bootstrap'; @Component({ selector: 'app-root', @@ -17,7 +17,11 @@ export class AppComponent implements OnInit { constructor(private accountService: AccountService, public navService: NavService, private messageHub: MessageHubService, private libraryService: LibraryService, - private router: Router, private ngbModal: NgbModal) { + private router: Router, private ngbModal: NgbModal, private ratingConfig: NgbRatingConfig) { + + // Setup default rating config + ratingConfig.max = 5; + ratingConfig.resettable = true; // Close any open modals when a route change occurs router.events diff --git a/UI/Web/src/app/app.module.ts b/UI/Web/src/app/app.module.ts index a9cb82151..89be77453 100644 --- a/UI/Web/src/app/app.module.ts +++ b/UI/Web/src/app/app.module.ts @@ -22,7 +22,6 @@ import { AutocompleteLibModule } from 'angular-ng-autocomplete'; import { ReviewSeriesModalComponent } from './_modals/review-series-modal/review-series-modal.component'; import { CarouselModule } from './carousel/carousel.module'; -import { PersonBadgeComponent } from './person-badge/person-badge.component'; import { TypeaheadModule } from './typeahead/typeahead.module'; import { RecentlyAddedComponent } from './recently-added/recently-added.component'; import { OnDeckComponent } from './on-deck/on-deck.component'; @@ -33,6 +32,10 @@ import { ReadingListModule } from './reading-list/reading-list.module'; import { SAVER, getSaver } from './shared/_providers/saver.provider'; import { ConfigData } from './_models/config-data'; import { NavEventsToggleComponent } from './nav-events-toggle/nav-events-toggle.component'; +import { PersonRolePipe } from './person-role.pipe'; +import { SeriesMetadataDetailComponent } from './series-metadata-detail/series-metadata-detail.component'; +import { AllSeriesComponent } from './all-series/all-series.component'; +import { PublicationStatusPipe } from './publication-status.pipe'; @NgModule({ @@ -45,11 +48,14 @@ import { NavEventsToggleComponent } from './nav-events-toggle/nav-events-toggle. SeriesDetailComponent, NotConnectedComponent, // Move into ExtrasModule ReviewSeriesModalComponent, - PersonBadgeComponent, RecentlyAddedComponent, OnDeckComponent, DashboardComponent, NavEventsToggleComponent, + PersonRolePipe, + PublicationStatusPipe, + SeriesMetadataDetailComponent, + AllSeriesComponent, ], imports: [ HttpClientModule, diff --git a/UI/Web/src/app/book-reader/book-reader/book-reader.component.html b/UI/Web/src/app/book-reader/book-reader/book-reader.component.html index 181de7cea..44e05dd86 100644 --- a/UI/Web/src/app/book-reader/book-reader/book-reader.component.html +++ b/UI/Web/src/app/book-reader/book-reader/book-reader.component.html @@ -1,4 +1,4 @@ -
    +
    Skip to main content @@ -57,6 +57,17 @@ The ability to click the sides of the page to page left and right
    +
    + + Put reader in fullscreen mode + + + + +
    @@ -83,7 +94,7 @@
    -
      +
      • {{chapterGroup.title}}
      • @@ -99,13 +110,14 @@
    -
    -
    +
    -
    -
    -
    -
    +
    + +
    +
    diff --git a/UI/Web/src/app/book-reader/book-reader/book-reader.component.scss b/UI/Web/src/app/book-reader/book-reader/book-reader.component.scss index 7132626f9..12823f996 100644 --- a/UI/Web/src/app/book-reader/book-reader/book-reader.component.scss +++ b/UI/Web/src/app/book-reader/book-reader/book-reader.component.scss @@ -154,18 +154,40 @@ $primary-color: #0062cc; } .reading-section { - height: 100vh; + max-height: 100vh; width: 100%; + //overflow: auto; // This will break progress reporting +} + +.reader-container { + outline: none; // Only the reading section itself shouldn't receive any outline. We use it to shift focus in fullscreen mode + overflow: auto; } .book-content { position: relative; } +// A bunch of resets so books render correctly +::ng-deep .book-content { + & a, & :link { + color: blue; + } +} + .drawer-body { padding-bottom: 20px; } +.chapter-title { + padding-inline-start: 0px +} + +::ng-deep .scale-width { + max-width: 100%; + object-fit: contain; + object-position: top center; +} // Click to Paginate styles diff --git a/UI/Web/src/app/book-reader/book-reader/book-reader.component.ts b/UI/Web/src/app/book-reader/book-reader/book-reader.component.ts index e5019010f..74120972e 100644 --- a/UI/Web/src/app/book-reader/book-reader/book-reader.component.ts +++ b/UI/Web/src/app/book-reader/book-reader/book-reader.component.ts @@ -1,5 +1,5 @@ -import { AfterViewInit, Component, ElementRef, HostListener, OnDestroy, OnInit, Renderer2, RendererStyleFlags2, ViewChild } from '@angular/core'; -import {Location} from '@angular/common'; +import { AfterViewInit, Component, ElementRef, HostListener, Inject, OnDestroy, OnInit, Renderer2, RendererStyleFlags2, ViewChild } from '@angular/core'; +import {DOCUMENT, Location} from '@angular/common'; import { FormControl, FormGroup } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; import { ToastrService } from 'ngx-toastr'; @@ -111,6 +111,7 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy { @ViewChild('readingHtml', {static: false}) readingHtml!: ElementRef; @ViewChild('readingSection', {static: false}) readingSectionElemRef!: ElementRef; @ViewChild('stickyTop', {static: false}) stickyTopElemRef!: ElementRef; + @ViewChild('reader', {static: true}) reader!: ElementRef; /** * Next Chapter Id. This is not garunteed to be a valid ChapterId. Prefetched on page load (non-blocking). @@ -185,6 +186,11 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy { */ originalBodyColor: string | undefined; + /** + * If the web browser is in fullscreen mode + */ + isFullscreen: boolean = false; + darkModeStyles = ` *:not(input), *:not(select), *:not(code), *:not(:link), *:not(.ngx-toastr) { color: #dcdcdc !important; @@ -237,7 +243,8 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy { private seriesService: SeriesService, private readerService: ReaderService, private location: Location, private renderer: Renderer2, private navService: NavService, private toastr: ToastrService, private domSanitizer: DomSanitizer, private bookService: BookService, private memberService: MemberService, - private scrollService: ScrollService, private utilityService: UtilityService, private libraryService: LibraryService) { + private scrollService: ScrollService, private utilityService: UtilityService, private libraryService: LibraryService, + @Inject(DOCUMENT) private document: Document) { this.navService.hideNavBar(); this.darkModeStyleElem = this.renderer.createElement('style'); @@ -275,7 +282,7 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy { }); } - const bodyNode = document.querySelector('body'); + const bodyNode = this.document.querySelector('body'); if (bodyNode !== undefined && bodyNode !== null) { this.originalBodyColor = bodyNode.style.background; } @@ -290,14 +297,14 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy { */ ngAfterViewInit() { // check scroll offset and if offset is after any of the "id" markers, save progress - fromEvent(window, 'scroll') + fromEvent(this.reader.nativeElement, 'scroll') .pipe(debounceTime(200), takeUntil(this.onDestroy)).subscribe((event) => { if (this.isLoading) return; // Highlight the current chapter we are on if (Object.keys(this.pageAnchors).length !== 0) { // get the height of the document so we can capture markers that are halfway on the document viewport - const verticalOffset = this.scrollService.scrollPosition + (document.body.offsetHeight / 2); + const verticalOffset = this.scrollService.scrollPosition + (this.document.body.offsetHeight / 2); const alreadyReached = Object.values(this.pageAnchors).filter((i: number) => i <= verticalOffset); if (alreadyReached.length > 0) { @@ -344,7 +351,7 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy { } ngOnDestroy(): void { - const bodyNode = document.querySelector('body'); + const bodyNode = this.document.querySelector('body'); if (bodyNode !== undefined && bodyNode !== null && this.originalBodyColor !== undefined) { bodyNode.style.background = this.originalBodyColor; if (this.user.preferences.siteDarkMode) { @@ -353,7 +360,7 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy { } this.navService.showNavBar(); - const head = document.querySelector('head'); + const head = this.document.querySelector('head'); this.renderer.removeChild(head, this.darkModeStyleElem); if (this.clickToPaginateVisualOverlayTimeout !== undefined) { @@ -365,6 +372,8 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy { this.clickToPaginateVisualOverlayTimeout2 = undefined; } + this.readerService.exitFullscreen(); + this.onDestroy.next(); this.onDestroy.complete(); } @@ -573,8 +582,8 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy { resetSettings() { const windowWidth = window.innerWidth - || document.documentElement.clientWidth - || document.body.clientWidth; + || this.document.documentElement.clientWidth + || this.document.body.clientWidth; let margin = '15%'; if (windowWidth <= 700) { @@ -623,7 +632,7 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy { } moveFocus() { - const elems = document.getElementsByClassName('reading-section'); + const elems = this.document.getElementsByClassName('reading-section'); if (elems.length > 0) { (elems[0] as HTMLDivElement).focus(); } @@ -671,10 +680,10 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy { getPageMarkers(ids: Array) { try { - return document.querySelectorAll(ids.map(id => '#' + this.cleanIdSelector(id)).join(', ')); + return this.document.querySelectorAll(ids.map(id => '#' + this.cleanIdSelector(id)).join(', ')); } catch (Exception) { // Fallback to anchors instead. Some books have ids that are not valid for querySelectors, so anchors should be used instead - return document.querySelectorAll(ids.map(id => '[href="#' + id + '"]').join(', ')); + return this.document.querySelectorAll(ids.map(id => '[href="#' + id + '"]').join(', ')); } } @@ -709,6 +718,10 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy { this.setupPage(part, scrollTop); return; } + + // Apply scaling class to all images to ensure they scale down to max width to not blow out the reader + Array.from(imgs).forEach(img => this.renderer.addClass(img, 'scale-width')); + Promise.all(Array.from(imgs) .filter(img => !img.complete) .map(img => new Promise(resolve => { img.onload = img.onerror = resolve; }))) @@ -730,16 +743,19 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy { if (part !== undefined && part !== '') { this.scrollTo(part); } else if (scrollTop !== undefined && scrollTop !== 0) { - this.scrollService.scrollTo(scrollTop); + this.scrollService.scrollTo(scrollTop, this.reader.nativeElement); } else { - this.scrollService.scrollTo(0); + this.scrollService.scrollTo(0, this.reader.nativeElement); } + + // we need to click the document before arrow keys will scroll down. + this.reader.nativeElement.focus(); } setPageNum(pageNum: number) { if (pageNum < 0) { this.pageNum = 0; - } else if (pageNum >= this.maxPages - 1) { + } else if (pageNum >= this.maxPages) { this.pageNum = this.maxPages - 1; } else { this.pageNum = pageNum; @@ -799,13 +815,14 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy { this.setPageNum(this.pageNum - 1); } - if (this.pageNum >= this.maxPages - 1) { + if (oldPageNum + 1 === this.maxPages) { // Move to next volume/chapter automatically this.loadNextChapter(); } if (oldPageNum === this.pageNum) { return; } + this.loadPage(); } @@ -860,13 +877,27 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy { updateReaderStyles() { if (this.readingHtml != undefined && this.readingHtml.nativeElement) { + Object.entries(this.pageStyles).forEach(item => { + if (item[1] == '100%' || item[1] == '0px' || item[1] == 'inherit') { + // Remove the style or skip + this.renderer.removeStyle(this.readingHtml.nativeElement, item[0]); + return; + } + this.renderer.setStyle(this.readingHtml.nativeElement, item[0], item[1], RendererStyleFlags2.Important); + }); + for(let i = 0; i < this.readingHtml.nativeElement.children.length; i++) { const elem = this.readingHtml.nativeElement.children.item(i); - if (elem?.tagName != 'STYLE') { + if (elem?.tagName === 'STYLE') continue; Object.entries(this.pageStyles).forEach(item => { + if (item[1] == '100%' || item[1] == '0px' || item[1] == 'inherit') { + // Remove the style or skip + this.renderer.removeStyle(elem, item[0]); + return; + } this.renderer.setStyle(elem, item[0], item[1], RendererStyleFlags2.Important); }); - } + } } } @@ -895,7 +926,7 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy { } setOverrideStyles() { - const bodyNode = document.querySelector('body'); + const bodyNode = this.document.querySelector('body'); if (bodyNode !== undefined && bodyNode !== null) { if (this.user.preferences.siteDarkMode) { bodyNode.classList.remove('bg-dark'); @@ -904,7 +935,7 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy { bodyNode.style.background = this.getDarkModeBackgroundColor(); } this.backgroundColor = this.getDarkModeBackgroundColor(); - const head = document.querySelector('head'); + const head = this.document.querySelector('head'); if (this.darkMode) { this.renderer.appendChild(head, this.darkModeStyleElem) } else { @@ -940,12 +971,12 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy { // Part selector is a XPATH element = this.getElementFromXPath(partSelector); } else { - element = document.querySelector('*[id="' + partSelector + '"]'); + element = this.document.querySelector('*[id="' + partSelector + '"]'); } if (element === null) return; - this.scrollService.scrollTo(element.getBoundingClientRect().top + window.pageYOffset + TOP_OFFSET); + this.scrollService.scrollTo(element.getBoundingClientRect().top + window.pageYOffset + TOP_OFFSET, this.reader.nativeElement); } toggleClickToPaginate() { @@ -976,7 +1007,7 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy { } getElementFromXPath(path: string) { - const node = document.evaluate(path, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; + const node = this.document.evaluate(path, this.document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; if (node?.nodeType === Node.ELEMENT_NODE) { return node as Element; } @@ -986,7 +1017,7 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy { getXPathTo(element: any): string { if (element === null) return ''; if (element.id !== '') { return 'id("' + element.id + '")'; } - if (element === document.body) { return element.tagName; } + if (element === this.document.body) { return element.tagName; } let ix = 0; @@ -1014,4 +1045,21 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy { this.readerService.saveProgress(this.seriesId, this.volumeId, this.chapterId, this.pageNum).pipe(take(1)).subscribe(() => {/* No operation */}); } + toggleFullscreen() { + this.isFullscreen = this.readerService.checkFullscreenMode(); + if (this.isFullscreen) { + this.readerService.exitFullscreen(() => { + this.isFullscreen = false; + this.renderer.removeStyle(this.reader.nativeElement, 'background'); + }); + } else { + this.readerService.enterFullscreen(this.reader.nativeElement, () => { + this.isFullscreen = true; + // HACK: This is a bug with how browsers change the background color for fullscreen mode + if (!this.darkMode) { + this.renderer.setStyle(this.reader.nativeElement, 'background', 'white'); + } + }); + } + } } diff --git a/UI/Web/src/app/cards/_modals/bookmarks-modal/bookmarks-modal.component.html b/UI/Web/src/app/cards/_modals/bookmarks-modal/bookmarks-modal.component.html index 2318b61e3..2dd4b93e1 100644 --- a/UI/Web/src/app/cards/_modals/bookmarks-modal/bookmarks-modal.component.html +++ b/UI/Web/src/app/cards/_modals/bookmarks-modal/bookmarks-modal.component.html @@ -5,15 +5,16 @@
    - -
    -
    -
    -
    - - -
    -
    +
    +
    +
    -
    + +
    + +
    +

    Book Settings + +

    + +
    +
    + +
    +
    +
    + + + This is library agnostic +
    +
    +
    +
    +   + + + + {{item.title}} + + + {{item.title}} + + +
    +
    + +
    +
    + + + + {{item.name}} + + + {{item.name}} + + +
    +
    + +
    +
    +   + + + + {{item.title}} + + + {{item.title}} + + +
    +
    + +
    +
    + + + + {{item.title}} + + + {{item.title}} + + +
    +
    + +
    +
    + + + + {{item.title}} + + + {{item.title}} + + +
    +
    +
    +
    + +
    +
    + + + + {{item.name}} + + + {{item.name}} + + +
    +
    + +
    +
    + + + + {{item.name}} + + + {{item.name}} + + +
    +
    + +
    +
    + + + + {{item.name}} + + + {{item.name}} + + +
    +
    + +
    +
    + + + + {{item.name}} + + + {{item.name}} + + +
    +
    + +
    +
    + + + + {{item.name}} + + + {{item.name}} + + +
    +
    + +
    +
    + + + + {{item.name}} + + + {{item.name}} + + +
    +
    + +
    +
    + + + + {{item.name}} + + + {{item.name}} + + +
    +
    + +
    +
    + + + + {{item.name}} + + + {{item.name}} + + +
    +
    + +
    +
    + + + + {{item.name}} + + + {{item.name}} + + +
    +
    + +
    +
    + + + + {{item.name}} + + + {{item.name}} + + +
    +
    +
    +
    +
    + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    +
    + +
    + +
    + + + + + +
    +
    + +
    + + + + {{item.title}} + + + {{item.title}} + + +
    + +
    + + + + {{item.title}} + + + {{item.title}} + + +
    + +
    + + + + {{item.title}} + + + {{item.title}} + + +
    +
    +
    +
    +
    +
    +
    + + + +
    +
    +
    +
    +
    +
    +
    + +
    +
    + +
    +
    +
    +
    + diff --git a/UI/Web/src/app/cards/card-detail-layout/card-detail-layout.component.scss b/UI/Web/src/app/cards/card-detail-layout/card-detail-layout.component.scss index e69de29bb..23d8c738a 100644 --- a/UI/Web/src/app/cards/card-detail-layout/card-detail-layout.component.scss +++ b/UI/Web/src/app/cards/card-detail-layout/card-detail-layout.component.scss @@ -0,0 +1,9 @@ +@use '../../../theme/colors'; + +.star { + font-size: 1.5rem; + color: colors.$rating-empty; +} +.filled { + color: colors.$rating-filled; +} \ No newline at end of file diff --git a/UI/Web/src/app/cards/card-detail-layout/card-detail-layout.component.ts b/UI/Web/src/app/cards/card-detail-layout/card-detail-layout.component.ts index aab49eff7..1bece3ff6 100644 --- a/UI/Web/src/app/cards/card-detail-layout/card-detail-layout.component.ts +++ b/UI/Web/src/app/cards/card-detail-layout/card-detail-layout.component.ts @@ -1,39 +1,57 @@ -import { Component, ContentChild, EventEmitter, Input, OnInit, Output, TemplateRef } from '@angular/core'; -import { FormGroup, FormControl } from '@angular/forms'; +import { Component, ContentChild, EventEmitter, Input, OnDestroy, OnInit, Output, TemplateRef } from '@angular/core'; +import { FormControl, FormGroup } from '@angular/forms'; +import { forkJoin, Observable, of, ReplaySubject, Subject } from 'rxjs'; +import { map, takeUntil } from 'rxjs/operators'; +import { UtilityService } from 'src/app/shared/_services/utility.service'; +import { TypeaheadSettings } from 'src/app/typeahead/typeahead-settings'; +import { CollectionTag } from 'src/app/_models/collection-tag'; +import { Genre } from 'src/app/_models/genre'; +import { Library } from 'src/app/_models/library'; +import { MangaFormat } from 'src/app/_models/manga-format'; +import { AgeRating } from 'src/app/_models/metadata/age-rating'; +import { AgeRatingDto } from 'src/app/_models/metadata/age-rating-dto'; +import { Language } from 'src/app/_models/metadata/language'; +import { PublicationStatusDto } from 'src/app/_models/metadata/publication-status-dto'; import { Pagination } from 'src/app/_models/pagination'; -import { FilterItem } from 'src/app/_models/series-filter'; +import { Person, PersonRole } from 'src/app/_models/person'; +import { FilterItem, mangaFormatFilters, SeriesFilter, SortField } from 'src/app/_models/series-filter'; +import { Tag } from 'src/app/_models/tag'; import { ActionItem } from 'src/app/_services/action-factory.service'; +import { CollectionTagService } from 'src/app/_services/collection-tag.service'; +import { LibraryService } from 'src/app/_services/library.service'; +import { MetadataService } from 'src/app/_services/metadata.service'; +import { SeriesService } from 'src/app/_services/series.service'; const FILTER_PAG_REGEX = /[^0-9]/g; -export enum FilterAction { - /** - * If an option is selected on a multi select component - */ - Added = 0, - /** - * If an option is unselected on a multi select component - */ - Removed = 1, - /** - * If an option is selected on a single select component - */ - Selected = 2 -} - -export interface UpdateFilterEvent { - filterItem: FilterItem; - action: FilterAction; -} - const ANIMATION_SPEED = 300; +export class FilterSettings { + libraryDisabled = false; + formatDisabled = false; + collectionDisabled = false; + genresDisabled = false; + peopleDisabled = false; + readProgressDisabled = false; + ratingDisabled = false; + sortDisabled = false; + ageRatingDisabled = false; + tagsDisabled = false; + languageDisabled = false; + publicationStatusDisabled = false; + presets: SeriesFilter | undefined; + /** + * Should the filter section be open by default + */ + openByDefault = false; +} + @Component({ selector: 'app-card-detail-layout', templateUrl: './card-detail-layout.component.html', styleUrls: ['./card-detail-layout.component.scss'] }) -export class CardDetailLayoutComponent implements OnInit { +export class CardDetailLayoutComponent implements OnInit, OnDestroy { @Input() header: string = ''; @Input() isLoading: boolean = false; @@ -43,32 +61,382 @@ export class CardDetailLayoutComponent implements OnInit { * Any actions to exist on the header for the parent collection (library, collection) */ @Input() actions: ActionItem[] = []; - /** - * A list of Filters which can filter the data of the page. If nothing is passed, the control will not show. - */ - @Input() filters: Array = []; @Input() trackByIdentity!: (index: number, item: any) => string; + @Input() filterSettings!: FilterSettings; @Output() itemClicked: EventEmitter = new EventEmitter(); @Output() pageChange: EventEmitter = new EventEmitter(); - @Output() applyFilter: EventEmitter = new EventEmitter(); + @Output() applyFilter: EventEmitter = new EventEmitter(); @ContentChild('cardItem') itemTemplate!: TemplateRef; - - filterForm: FormGroup = new FormGroup({ - filter: new FormControl(0, []), - }); + + formatSettings: TypeaheadSettings> = new TypeaheadSettings(); + librarySettings: TypeaheadSettings = new TypeaheadSettings(); + genreSettings: TypeaheadSettings = new TypeaheadSettings(); + collectionSettings: TypeaheadSettings = new TypeaheadSettings(); + ageRatingSettings: TypeaheadSettings = new TypeaheadSettings(); + publicationStatusSettings: TypeaheadSettings = new TypeaheadSettings(); + tagsSettings: TypeaheadSettings = new TypeaheadSettings(); + languageSettings: TypeaheadSettings = new TypeaheadSettings(); + peopleSettings: {[PersonRole: string]: TypeaheadSettings} = {}; + resetTypeaheads: Subject = new ReplaySubject(1); /** * Controls the visiblity of extended controls that sit below the main header. */ filteringCollapsed: boolean = true; - constructor() { } + filter!: SeriesFilter; + libraries: Array> = []; + + + readProgressGroup!: FormGroup; + sortGroup!: FormGroup; + isAscendingSort: boolean = true; + + updateApplied: number = 0; + + private onDestory: Subject = new Subject(); + + get PersonRole(): typeof PersonRole { + return PersonRole; + } + + get SortField(): typeof SortField { + return SortField; + } + + constructor(private libraryService: LibraryService, private metadataService: MetadataService, private seriesService: SeriesService, + private utilityService: UtilityService, private collectionTagService: CollectionTagService) { + this.filter = this.seriesService.createSeriesFilter(); + this.readProgressGroup = new FormGroup({ + read: new FormControl(this.filter.readStatus.read, []), + notRead: new FormControl(this.filter.readStatus.notRead, []), + inProgress: new FormControl(this.filter.readStatus.inProgress, []), + }); + + this.sortGroup = new FormGroup({ + sortField: new FormControl(this.filter.sortOptions?.sortField || SortField.SortName, []), + }); + + this.readProgressGroup.valueChanges.pipe(takeUntil(this.onDestory)).subscribe(changes => { + this.filter.readStatus.read = this.readProgressGroup.get('read')?.value; + this.filter.readStatus.inProgress = this.readProgressGroup.get('inProgress')?.value; + this.filter.readStatus.notRead = this.readProgressGroup.get('notRead')?.value; + + let sum = 0; + sum += (this.filter.readStatus.read ? 1 : 0); + sum += (this.filter.readStatus.inProgress ? 1 : 0); + sum += (this.filter.readStatus.notRead ? 1 : 0); + + if (sum === 1) { + if (this.filter.readStatus.read) this.readProgressGroup.get('read')?.disable({ emitEvent: false }); + if (this.filter.readStatus.notRead) this.readProgressGroup.get('notRead')?.disable({ emitEvent: false }); + if (this.filter.readStatus.inProgress) this.readProgressGroup.get('inProgress')?.disable({ emitEvent: false }); + } else { + this.readProgressGroup.get('read')?.enable({ emitEvent: false }); + this.readProgressGroup.get('notRead')?.enable({ emitEvent: false }); + this.readProgressGroup.get('inProgress')?.enable({ emitEvent: false }); + } + }); + + this.sortGroup.valueChanges.pipe(takeUntil(this.onDestory)).subscribe(changes => { + if (this.filter.sortOptions == null) { + this.filter.sortOptions = { + isAscending: this.isAscendingSort, + sortField: parseInt(this.sortGroup.get('sortField')?.value, 10) + }; + } + this.filter.sortOptions.sortField = parseInt(this.sortGroup.get('sortField')?.value, 10); + }); + } ngOnInit(): void { - this.trackByIdentity = (index: number, item: any) => `${this.header}_${this.pagination?.currentPage}_${this.filterForm.get('filter')?.value}_${item.id}_${index}`; + this.trackByIdentity = (index: number, item: any) => `${this.header}_${this.pagination?.currentPage}_${this.updateApplied}`; + + if (this.filterSettings === undefined) { + this.filterSettings = new FilterSettings(); + } + + this.setupTypeaheads(); } + ngOnDestroy() { + this.onDestory.next(); + this.onDestory.complete(); + } + + setupTypeaheads() { + + this.setupFormatTypeahead(); + + forkJoin([ + this.setupLibraryTypeahead(), + this.setupCollectionTagTypeahead(), + this.setupAgeRatingSettings(), + this.setupPublicationStatusSettings(), + this.setupTagSettings(), + this.setupLanguageSettings(), + this.setupGenreTypeahead(), + this.setupPersonTypeahead(), + ]).subscribe(results => { + this.resetTypeaheads.next(true); + if (this.filterSettings.openByDefault) { + this.filteringCollapsed = false; + } + this.apply(); + }); + } + + + setupFormatTypeahead() { + this.formatSettings.minCharacters = 0; + this.formatSettings.multiple = true; + this.formatSettings.id = 'format'; + this.formatSettings.unique = true; + this.formatSettings.addIfNonExisting = false; + this.formatSettings.fetchFn = (filter: string) => of(mangaFormatFilters); + this.formatSettings.compareFn = (options: FilterItem[], filter: string) => { + const f = filter.toLowerCase(); + return options.filter(m => m.title.toLowerCase() === f); + } + + if (this.filterSettings.presets?.formats && this.filterSettings.presets?.formats.length > 0) { + this.formatSettings.savedData = mangaFormatFilters.filter(item => this.filterSettings.presets?.formats.includes(item.value)); + this.filter.formats = this.formatSettings.savedData.map(item => item.value); + this.resetTypeaheads.next(true); + } + } + + setupLibraryTypeahead() { + this.librarySettings.minCharacters = 0; + this.librarySettings.multiple = true; + this.librarySettings.id = 'libraries'; + this.librarySettings.unique = true; + this.librarySettings.addIfNonExisting = false; + this.librarySettings.fetchFn = (filter: string) => { + return this.libraryService.getLibrariesForMember(); + }; + this.librarySettings.compareFn = (options: Library[], filter: string) => { + const f = filter.toLowerCase(); + return options.filter(m => m.name.toLowerCase() === f); + } + + if (this.filterSettings.presets?.libraries && this.filterSettings.presets?.libraries.length > 0) { + return this.librarySettings.fetchFn('').pipe(map(libraries => { + this.librarySettings.savedData = libraries.filter(item => this.filterSettings.presets?.libraries.includes(item.id)); + this.filter.libraries = this.librarySettings.savedData.map(item => item.id); + return of(true); + })); + } + return of(true); + } + + setupGenreTypeahead() { + this.genreSettings.minCharacters = 0; + this.genreSettings.multiple = true; + this.genreSettings.id = 'genres'; + this.genreSettings.unique = true; + this.genreSettings.addIfNonExisting = false; + this.genreSettings.fetchFn = (filter: string) => { + return this.metadataService.getAllGenres(this.filter.libraries); + }; + this.genreSettings.compareFn = (options: Genre[], filter: string) => { + const f = filter.toLowerCase(); + return options.filter(m => m.title.toLowerCase() === f); + } + + if (this.filterSettings.presets?.genres && this.filterSettings.presets?.genres.length > 0) { + return this.genreSettings.fetchFn('').pipe(map(genres => { + this.genreSettings.savedData = genres.filter(item => this.filterSettings.presets?.genres.includes(item.id)); + this.filter.genres = this.genreSettings.savedData.map(item => item.id); + return of(true); + })); + } + return of(true); + } + + setupAgeRatingSettings() { + this.ageRatingSettings.minCharacters = 0; + this.ageRatingSettings.multiple = true; + this.ageRatingSettings.id = 'age-rating'; + this.ageRatingSettings.unique = true; + this.ageRatingSettings.addIfNonExisting = false; + this.ageRatingSettings.fetchFn = (filter: string) => { + return this.metadataService.getAllAgeRatings(this.filter.libraries); + }; + this.ageRatingSettings.compareFn = (options: AgeRatingDto[], filter: string) => { + const f = filter.toLowerCase(); + return options.filter(m => m.title.toLowerCase() === f && this.utilityService.filter(m.title, filter)); + } + + if (this.filterSettings.presets?.ageRating && this.filterSettings.presets?.ageRating.length > 0) { + return this.ageRatingSettings.fetchFn('').pipe(map(rating => { + this.ageRatingSettings.savedData = rating.filter(item => this.filterSettings.presets?.ageRating.includes(item.value)); + this.filter.ageRating = this.ageRatingSettings.savedData.map(item => item.value); + return of(true); + })); + } + return of(true); + } + + setupPublicationStatusSettings() { + this.publicationStatusSettings.minCharacters = 0; + this.publicationStatusSettings.multiple = true; + this.publicationStatusSettings.id = 'publication-status'; + this.publicationStatusSettings.unique = true; + this.publicationStatusSettings.addIfNonExisting = false; + this.publicationStatusSettings.fetchFn = (filter: string) => { + return this.metadataService.getAllPublicationStatus(this.filter.libraries); + }; + this.publicationStatusSettings.compareFn = (options: PublicationStatusDto[], filter: string) => { + const f = filter.toLowerCase(); + return options.filter(m => m.title.toLowerCase() === f && this.utilityService.filter(m.title, filter)); + } + + if (this.filterSettings.presets?.publicationStatus && this.filterSettings.presets?.publicationStatus.length > 0) { + return this.publicationStatusSettings.fetchFn('').pipe(map(statuses => { + this.publicationStatusSettings.savedData = statuses.filter(item => this.filterSettings.presets?.publicationStatus.includes(item.value)); + this.filter.publicationStatus = this.publicationStatusSettings.savedData.map(item => item.value); + return of(true); + })); + } + return of(true); + } + + setupTagSettings() { + this.tagsSettings.minCharacters = 0; + this.tagsSettings.multiple = true; + this.tagsSettings.id = 'tags'; + this.tagsSettings.unique = true; + this.tagsSettings.addIfNonExisting = false; + this.tagsSettings.fetchFn = (filter: string) => { + return this.metadataService.getAllTags(this.filter.libraries); + }; + this.tagsSettings.compareFn = (options: Tag[], filter: string) => { + const f = filter.toLowerCase(); + return options.filter(m => m.title.toLowerCase() === f && this.utilityService.filter(m.title, filter)); + } + + if (this.filterSettings.presets?.tags && this.filterSettings.presets?.tags.length > 0) { + return this.tagsSettings.fetchFn('').pipe(map(tags => { + this.tagsSettings.savedData = tags.filter(item => this.filterSettings.presets?.tags.includes(item.id)); + this.filter.tags = this.tagsSettings.savedData.map(item => item.id); + return of(true); + })); + } + return of(true); + } + + setupLanguageSettings() { + this.languageSettings.minCharacters = 0; + this.languageSettings.multiple = true; + this.languageSettings.id = 'languages'; + this.languageSettings.unique = true; + this.languageSettings.addIfNonExisting = false; + this.languageSettings.fetchFn = (filter: string) => { + return this.metadataService.getAllLanguages(this.filter.libraries); + }; + this.languageSettings.compareFn = (options: Language[], filter: string) => { + const f = filter.toLowerCase(); + return options.filter(m => m.title.toLowerCase() === f && this.utilityService.filter(m.title, filter)); + } + + if (this.filterSettings.presets?.languages && this.filterSettings.presets?.languages.length > 0) { + return this.languageSettings.fetchFn('').pipe(map(languages => { + this.languageSettings.savedData = languages.filter(item => this.filterSettings.presets?.languages.includes(item.isoCode)); + this.filter.languages = this.languageSettings.savedData.map(item => item.isoCode); + return of(true); + })); + } + return of(true); + } + + setupCollectionTagTypeahead() { + this.collectionSettings.minCharacters = 0; + this.collectionSettings.multiple = true; + this.collectionSettings.id = 'collections'; + this.collectionSettings.unique = true; + this.collectionSettings.addIfNonExisting = false; + this.collectionSettings.fetchFn = (filter: string) => { + return this.collectionTagService.allTags(); + }; + this.collectionSettings.compareFn = (options: CollectionTag[], filter: string) => { + const f = filter.toLowerCase(); + return options.filter(m => m.title.toLowerCase() === f); + } + + if (this.filterSettings.presets?.collectionTags && this.filterSettings.presets?.collectionTags.length > 0) { + return this.collectionSettings.fetchFn('').pipe(map(tags => { + this.collectionSettings.savedData = tags.filter(item => this.filterSettings.presets?.collectionTags.includes(item.id)); + this.filter.collectionTags = this.collectionSettings.savedData.map(item => item.id); + return of(true); + })); + } + return of(true); + } + + updateFromPreset(id: string, peopleFilterField: Array, presetField: Array | undefined, role: PersonRole) { + const personSettings = this.createBlankPersonSettings(id, role) + if (presetField && presetField.length > 0) { + const fetch = personSettings.fetchFn as ((filter: string) => Observable); + return fetch('').pipe(map(people => { + personSettings.savedData = people.filter(item => presetField.includes(item.id)); + peopleFilterField = personSettings.savedData.map(item => item.id); + this.resetTypeaheads.next(true); + this.peopleSettings[role] = personSettings; + this.updatePersonFilters(personSettings.savedData as Person[], role); + return true; + })); + } else { + this.peopleSettings[role] = personSettings; + return of(true); + } + } + + setupPersonTypeahead() { + this.peopleSettings = {}; + + return forkJoin([ + this.updateFromPreset('writers', this.filter.writers, this.filterSettings.presets?.writers, PersonRole.Writer), + this.updateFromPreset('character', this.filter.character, this.filterSettings.presets?.character, PersonRole.Character), + this.updateFromPreset('colorist', this.filter.colorist, this.filterSettings.presets?.colorist, PersonRole.Colorist), + this.updateFromPreset('cover-artist', this.filter.coverArtist, this.filterSettings.presets?.coverArtist, PersonRole.CoverArtist), + this.updateFromPreset('editor', this.filter.editor, this.filterSettings.presets?.editor, PersonRole.Editor), + this.updateFromPreset('inker', this.filter.inker, this.filterSettings.presets?.inker, PersonRole.Inker), + this.updateFromPreset('letterer', this.filter.letterer, this.filterSettings.presets?.letterer, PersonRole.Letterer), + this.updateFromPreset('penciller', this.filter.penciller, this.filterSettings.presets?.penciller, PersonRole.Penciller), + this.updateFromPreset('publisher', this.filter.publisher, this.filterSettings.presets?.publisher, PersonRole.Publisher), + this.updateFromPreset('translators', this.filter.translators, this.filterSettings.presets?.translators, PersonRole.Translator) + ]).pipe(map(results => { + this.resetTypeaheads.next(true); + return of(true); + })); + } + + fetchPeople(role: PersonRole, filter: string) { + return this.metadataService.getAllPeople(this.filter.libraries).pipe(map(people => { + return people.filter(p => p.role == role && this.utilityService.filter(p.name, filter)); + })); + } + + createBlankPersonSettings(id: string, role: PersonRole) { + var personSettings = new TypeaheadSettings(); + personSettings.minCharacters = 0; + personSettings.multiple = true; + personSettings.unique = true; + personSettings.addIfNonExisting = false; + personSettings.id = id; + personSettings.compareFn = (options: Person[], filter: string) => { + const f = filter.toLowerCase(); + return options.filter(m => m.name.toLowerCase() === f); + } + personSettings.fetchFn = (filter: string) => { + return this.fetchPeople(role, filter); + }; + return personSettings; + } + + onPageChange(page: number) { this.pageChange.emit(this.pagination); } @@ -88,11 +456,118 @@ export class CardDetailLayoutComponent implements OnInit { } } - handleFilterChange(index: string) { - this.applyFilter.emit({ - filterItem: this.filters[parseInt(index, 10)], - action: FilterAction.Selected - }); + + updateFormatFilters(formats: MangaFormat[]) { + this.filter.formats = formats.map(item => item) || []; + } + + updateLibraryFilters(libraries: Library[]) { + this.filter.libraries = libraries.map(item => item.id) || []; + } + + updateGenreFilters(genres: Genre[]) { + this.filter.genres = genres.map(item => item.id) || []; + } + + updateTagFilters(tags: Tag[]) { + this.filter.tags = tags.map(item => item.id) || []; + } + + updatePersonFilters(persons: Person[], role: PersonRole) { + switch (role) { + case PersonRole.CoverArtist: + this.filter.coverArtist = persons.map(p => p.id); + break; + case PersonRole.Character: + this.filter.character = persons.map(p => p.id); + break; + case PersonRole.Colorist: + this.filter.colorist = persons.map(p => p.id); + break; + case PersonRole.Editor: + this.filter.editor = persons.map(p => p.id); + break; + case PersonRole.Inker: + this.filter.inker = persons.map(p => p.id); + break; + case PersonRole.Letterer: + this.filter.letterer = persons.map(p => p.id); + break; + case PersonRole.Penciller: + this.filter.penciller = persons.map(p => p.id); + break; + case PersonRole.Publisher: + this.filter.publisher = persons.map(p => p.id); + break; + case PersonRole.Writer: + this.filter.writers = persons.map(p => p.id); + break; + case PersonRole.Translator: + this.filter.translators = persons.map(p => p.id); + + } + } + + updateCollectionFilters(tags: CollectionTag[]) { + this.filter.collectionTags = tags.map(item => item.id) || []; + } + + updateRating(rating: any) { + this.filter.rating = rating; + } + + updateAgeRating(ratingDtos: AgeRatingDto[]) { + this.filter.ageRating = ratingDtos.map(item => item.value) || []; + } + + updatePublicationStatus(dtos: PublicationStatusDto[]) { + this.filter.publicationStatus = dtos.map(item => item.value) || []; + } + + updateLanguageRating(languages: Language[]) { + this.filter.languages = languages.map(item => item.isoCode) || []; + } + + updateReadStatus(status: string) { + if (status === 'read') { + this.filter.readStatus.read = !this.filter.readStatus.read; + } else if (status === 'inProgress') { + this.filter.readStatus.inProgress = !this.filter.readStatus.inProgress; + } else if (status === 'notRead') { + this.filter.readStatus.notRead = !this.filter.readStatus.notRead; + } + } + + updateSortOrder() { + this.isAscendingSort = !this.isAscendingSort; + if (this.filter.sortOptions === null) { + this.filter.sortOptions = { + isAscending: this.isAscendingSort, + sortField: SortField.SortName + } + } + + this.filter.sortOptions.isAscending = this.isAscendingSort; + } + + getPersonsSettings(role: PersonRole) { + return this.peopleSettings[role]; + } + + clear() { + this.filter = this.seriesService.createSeriesFilter(); + this.readProgressGroup.get('read')?.setValue(true); + this.readProgressGroup.get('notRead')?.setValue(true); + this.readProgressGroup.get('inProgress')?.setValue(true); + this.sortGroup.get('sortField')?.setValue(SortField.SortName); + this.isAscendingSort = true; + // Apply any presets which will trigger the apply + this.setupTypeaheads(); + } + + apply() { + this.applyFilter.emit(this.filter); + this.updateApplied++; } } diff --git a/UI/Web/src/app/cards/card-item/card-item.component.html b/UI/Web/src/app/cards/card-item/card-item.component.html index 7fee96b23..c096aac5b 100644 --- a/UI/Web/src/app/cards/card-item/card-item.component.html +++ b/UI/Web/src/app/cards/card-item/card-item.component.html @@ -1,4 +1,4 @@ -
    +
    @@ -20,13 +20,13 @@
    - +
    - + (promoted) diff --git a/UI/Web/src/app/cards/card-item/card-item.component.scss b/UI/Web/src/app/cards/card-item/card-item.component.scss index 0aa5c8ef6..d1c81c155 100644 --- a/UI/Web/src/app/cards/card-item/card-item.component.scss +++ b/UI/Web/src/app/cards/card-item/card-item.component.scss @@ -1,13 +1,13 @@ -@import '../../../theme/colors'; +@use '../../../theme/colors'; -$triangle-size: 40px; +$triangle-size: 30px; $image-height: 230px; $image-width: 160px; .error-banner { width: 160px; height: 18px; - background-color: $error-color; + background-color: colors.$error-color; font-size: 12px; color: white; text-transform: uppercase; @@ -38,6 +38,9 @@ $image-width: 160px; margin-bottom: 0px; } +.selected-highlight { + outline: 2px solid colors.$primary-color; +} .img-top { @@ -49,7 +52,7 @@ $image-width: 160px; height: 5px; .progress { - color: $primary-color; + color: colors.$primary-color; background-color: transparent; } } @@ -70,7 +73,7 @@ $image-width: 160px; height: 0; border-style: solid; border-width: 0 $triangle-size $triangle-size 0; - border-color: transparent $primary-color transparent transparent; + border-color: transparent colors.$primary-color transparent transparent; } diff --git a/UI/Web/src/app/cards/card-item/card-item.component.ts b/UI/Web/src/app/cards/card-item/card-item.component.ts index b0974ba5a..6788881a3 100644 --- a/UI/Web/src/app/cards/card-item/card-item.component.ts +++ b/UI/Web/src/app/cards/card-item/card-item.component.ts @@ -8,6 +8,7 @@ import { UtilityService } from 'src/app/shared/_services/utility.service'; import { Chapter } from 'src/app/_models/chapter'; import { CollectionTag } from 'src/app/_models/collection-tag'; import { MangaFormat } from 'src/app/_models/manga-format'; +import { PageBookmark } from 'src/app/_models/page-bookmark'; import { Series } from 'src/app/_models/series'; import { Volume } from 'src/app/_models/volume'; import { Action, ActionItem } from 'src/app/_services/action-factory.service'; @@ -49,7 +50,7 @@ export class CardItemComponent implements OnInit, OnDestroy { /** * This is the entity we are representing. It will be returned if an action is executed. */ - @Input() entity!: Series | Volume | Chapter | CollectionTag; + @Input() entity!: Series | Volume | Chapter | CollectionTag | PageBookmark; /** * If the entity is selected or not. */ @@ -79,12 +80,18 @@ export class CardItemComponent implements OnInit, OnDestroy { * Format of the entity (only applies to Series) */ format: MangaFormat = MangaFormat.UNKNOWN; + chapterTitle: string = ''; download$: Observable | null = null; downloadInProgress: boolean = false; isShiftDown: boolean = false; + + get tooltipTitle() { + if (this.chapterTitle === '' || this.chapterTitle === null) return this.title; + return this.chapterTitle; + } get MangaFormat(): typeof MangaFormat { @@ -111,6 +118,15 @@ export class CardItemComponent implements OnInit, OnDestroy { }); } this.format = (this.entity as Series).format; + + if (this.utilityService.isChapter(this.entity)) { + this.chapterTitle = this.utilityService.asChapter(this.entity).titleName; + } else if (this.utilityService.isVolume(this.entity)) { + const vol = this.utilityService.asVolume(this.entity); + if (vol.chapters !== undefined && vol.chapters.length > 0) { + this.chapterTitle = vol.chapters[0].titleName; + } + } } ngOnDestroy() { diff --git a/UI/Web/src/app/cards/cards.module.ts b/UI/Web/src/app/cards/cards.module.ts index dc1a23134..8b21fe1ac 100644 --- a/UI/Web/src/app/cards/cards.module.ts +++ b/UI/Web/src/app/cards/cards.module.ts @@ -8,7 +8,7 @@ import { EditCollectionTagsComponent } from './_modals/edit-collection-tags/edit import { ChangeCoverImageModalComponent } from './_modals/change-cover-image/change-cover-image-modal.component'; import { BookmarksModalComponent } from './_modals/bookmarks-modal/bookmarks-modal.component'; import { LazyLoadImageModule } from 'ng-lazyload-image'; -import { NgbTooltipModule, NgbCollapseModule, NgbPaginationModule, NgbDropdownModule, NgbProgressbarModule, NgbNavModule, NgbAccordionModule } from '@ng-bootstrap/ng-bootstrap'; +import { NgbTooltipModule, NgbCollapseModule, NgbPaginationModule, NgbDropdownModule, NgbProgressbarModule, NgbNavModule, NgbRatingModule } from '@ng-bootstrap/ng-bootstrap'; import { CardActionablesComponent } from './card-item/card-actionables/card-actionables.component'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { NgxFileDropModule } from 'ngx-file-drop'; @@ -21,6 +21,9 @@ import { CardDetailsModalComponent } from './_modals/card-details-modal/card-det import { BulkOperationsComponent } from './bulk-operations/bulk-operations.component'; import { BulkAddToCollectionComponent } from './_modals/bulk-add-to-collection/bulk-add-to-collection.component'; import { PipeModule } from '../pipe/pipe.module'; +import { ChapterMetadataDetailComponent } from './chapter-metadata-detail/chapter-metadata-detail.component'; +import { FileInfoComponent } from './file-info/file-info.component'; +import { BookmarkComponent } from './bookmark/bookmark.component'; @@ -38,7 +41,10 @@ import { PipeModule } from '../pipe/pipe.module'; CardDetailLayoutComponent, CardDetailsModalComponent, BulkOperationsComponent, - BulkAddToCollectionComponent + BulkAddToCollectionComponent, + ChapterMetadataDetailComponent, + FileInfoComponent, + BookmarkComponent, ], imports: [ CommonModule, @@ -52,6 +58,7 @@ import { PipeModule } from '../pipe/pipe.module'; NgbNavModule, NgbTooltipModule, // Card item NgbCollapseModule, + NgbRatingModule, NgbNavModule, //Series Detail LazyLoadImageModule, @@ -75,7 +82,8 @@ import { PipeModule } from '../pipe/pipe.module'; CardActionablesComponent, CardDetailLayoutComponent, CardDetailsModalComponent, - BulkOperationsComponent + BulkOperationsComponent, + ChapterMetadataDetailComponent ] }) export class CardsModule { } diff --git a/UI/Web/src/app/cards/chapter-metadata-detail/chapter-metadata-detail.component.html b/UI/Web/src/app/cards/chapter-metadata-detail/chapter-metadata-detail.component.html new file mode 100644 index 000000000..24d7b0aed --- /dev/null +++ b/UI/Web/src/app/cards/chapter-metadata-detail/chapter-metadata-detail.component.html @@ -0,0 +1,114 @@ + +
    + + + + + + +
    +
    + Title: {{chapter.titleName || '-'}} +
    +
    + Pages: {{chapter.pages}} +
    +
    + +
    +
    + Added: {{(chapter.created | date: 'short') || '-'}} +
    +
    + Release Date: {{(chapter.releaseDate | date: 'shortDate') || '-'}} +
    +
    +
    + +
      +
    • + + + +
      +
      + + + + {{chapter.pagesRead}} / {{chapter.pages}} + UNREAD + READ + + + Files +
      +
        + +
      + + + +
      +
      +
      Writers
      +
      +
      + +
      +
      + +
      +
      +
      Artists
      +
      +
      + +
      +
      + +
      +
      +
      Publishers
      +
      +
      + +
      +
      +
      +
      +
    • +
    +
    + + + \ No newline at end of file diff --git a/UI/Web/src/app/cards/chapter-metadata-detail/chapter-metadata-detail.component.scss b/UI/Web/src/app/cards/chapter-metadata-detail/chapter-metadata-detail.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/UI/Web/src/app/cards/chapter-metadata-detail/chapter-metadata-detail.component.ts b/UI/Web/src/app/cards/chapter-metadata-detail/chapter-metadata-detail.component.ts new file mode 100644 index 000000000..2c203aed0 --- /dev/null +++ b/UI/Web/src/app/cards/chapter-metadata-detail/chapter-metadata-detail.component.ts @@ -0,0 +1,53 @@ +import { Component, Input, OnInit } from '@angular/core'; +import { MetadataService } from 'src/app/_services/metadata.service'; +import { Chapter } from 'src/app/_models/chapter'; +import { ChapterMetadata } from 'src/app/_models/chapter-metadata'; +import { UtilityService } from 'src/app/shared/_services/utility.service'; +import { LibraryType } from 'src/app/_models/library'; +import { ActionItem } from 'src/app/_services/action-factory.service'; + +@Component({ + selector: 'app-chapter-metadata-detail', + templateUrl: './chapter-metadata-detail.component.html', + styleUrls: ['./chapter-metadata-detail.component.scss'] +}) +export class ChapterMetadataDetailComponent implements OnInit { + + @Input() chapter!: Chapter; + @Input() libraryType: LibraryType = LibraryType.Manga; + //metadata!: ChapterMetadata; + + get LibraryType(): typeof LibraryType { + return LibraryType; + } + + constructor(private metadataService: MetadataService, public utilityService: UtilityService) { } + + ngOnInit(): void { + // this.metadataService.getChapterMetadata(this.chapter.id).subscribe(metadata => { + // console.log('Chapter ', this.chapter.number, ' metadata: ', metadata); + // this.metadata = metadata; + // }) + } + + performAction(action: ActionItem, chapter: Chapter) { + if (typeof action.callback === 'function') { + action.callback(action.action, chapter); + } + } + + readChapter(chapter: Chapter) { + // if (chapter.pages === 0) { + // this.toastr.error('There are no pages. Kavita was not able to read this archive.'); + // return; + // } + + // if (chapter.files.length > 0 && chapter.files[0].format === MangaFormat.EPUB) { + // this.router.navigate(['library', this.libraryId, 'series', this.seriesId, 'book', chapter.id]); + // } else { + // this.router.navigate(['library', this.libraryId, 'series', this.seriesId, 'manga', chapter.id]); + // } + } + + +} diff --git a/UI/Web/src/app/cards/file-info/file-info.component.html b/UI/Web/src/app/cards/file-info/file-info.component.html new file mode 100644 index 000000000..f409c2f09 --- /dev/null +++ b/UI/Web/src/app/cards/file-info/file-info.component.html @@ -0,0 +1,11 @@ +
  • + {{file.filePath}} +
    +
    + Pages: {{file.pages}} +
    +
    + Added: {{(created | date: 'short') || '-'}} +
    +
    +
  • \ No newline at end of file diff --git a/UI/Web/src/app/cards/file-info/file-info.component.scss b/UI/Web/src/app/cards/file-info/file-info.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/UI/Web/src/app/cards/file-info/file-info.component.ts b/UI/Web/src/app/cards/file-info/file-info.component.ts new file mode 100644 index 000000000..ce275bc45 --- /dev/null +++ b/UI/Web/src/app/cards/file-info/file-info.component.ts @@ -0,0 +1,25 @@ +import { Component, Input, OnInit } from '@angular/core'; +import { MangaFile } from 'src/app/_models/manga-file'; + +@Component({ + selector: 'app-file-info', + templateUrl: './file-info.component.html', + styleUrls: ['./file-info.component.scss'] +}) +export class FileInfoComponent implements OnInit { + + /** + * MangaFile to display + */ + @Input() file!: MangaFile; + /** + * DateTime the entity this file belongs to was created + */ + @Input() created: string | undefined = undefined; + + constructor() { } + + ngOnInit(): void { + } + +} diff --git a/UI/Web/src/app/cards/series-card/series-card.component.ts b/UI/Web/src/app/cards/series-card/series-card.component.ts index 11d869401..8966cc1be 100644 --- a/UI/Web/src/app/cards/series-card/series-card.component.ts +++ b/UI/Web/src/app/cards/series-card/series-card.component.ts @@ -109,6 +109,9 @@ export class SeriesCardComponent implements OnInit, OnChanges, OnDestroy { case(Action.AddToReadingList): this.actionService.addSeriesToReadingList(series, (series) => {/* No Operation */ }); break; + case(Action.AddToCollection): + this.actionService.addMultipleSeriesToCollectionTag([series], () => {/* No Operation */ }); + break; default: break; } @@ -132,35 +135,26 @@ export class SeriesCardComponent implements OnInit, OnChanges, OnDestroy { }); } - refreshMetdata(series: Series) { - this.seriesService.refreshMetadata(series).subscribe((res: any) => { - this.toastr.success('Refresh started for ' + series.name); - }); + async refreshMetdata(series: Series) { + this.actionService.refreshMetdata(series); } - scanLibrary(series: Series) { + async scanLibrary(series: Series) { this.seriesService.scan(series.libraryId, series.id).subscribe((res: any) => { - this.toastr.success('Scan started for ' + series.name); + this.toastr.success('Scan queued for ' + series.name); }); } async deleteSeries(series: Series) { - if (!await this.confirmService.confirm('Are you sure you want to delete this series? It will not modify files on disk.')) { - return; - } - - this.seriesService.delete(series.id).subscribe((res: boolean) => { - if (res) { - this.toastr.success('Series deleted'); + this.actionService.deleteSeries(series, (result: boolean) => { + if (result) { this.reload.emit(true); } }); } markAsUnread(series: Series) { - this.seriesService.markUnread(series.id).subscribe(res => { - this.toastr.success(series.name + ' is now unread'); - series.pagesRead = 0; + this.actionService.markSeriesAsUnread(series, () => { if (this.data) { this.data.pagesRead = 0; } @@ -170,9 +164,7 @@ export class SeriesCardComponent implements OnInit, OnChanges, OnDestroy { } markAsRead(series: Series) { - this.seriesService.markRead(series.id).subscribe(res => { - this.toastr.success(series.name + ' is now read'); - series.pagesRead = series.pages; + this.actionService.markSeriesAsRead(series, () => { if (this.data) { this.data.pagesRead = series.pages; } diff --git a/UI/Web/src/app/collections/collection-detail/collection-detail.component.html b/UI/Web/src/app/collections/collection-detail/collection-detail.component.html index 431680257..0e8516cf8 100644 --- a/UI/Web/src/app/collections/collection-detail/collection-detail.component.html +++ b/UI/Web/src/app/collections/collection-detail/collection-detail.component.html @@ -32,8 +32,8 @@ [isLoading]="isLoading" [items]="series" [pagination]="seriesPagination" + [filterSettings]="filterSettings" (pageChange)="onPageChange($event)" - [filters]="filters" (applyFilter)="updateFilter($event)" > diff --git a/UI/Web/src/app/collections/collection-detail/collection-detail.component.scss b/UI/Web/src/app/collections/collection-detail/collection-detail.component.scss index 7e13a843c..b392abee1 100644 --- a/UI/Web/src/app/collections/collection-detail/collection-detail.component.scss +++ b/UI/Web/src/app/collections/collection-detail/collection-detail.component.scss @@ -1,4 +1,4 @@ -@import '~bootstrap/scss/mixins/_breakpoints.scss'; +@import '~bootstrap/scss/mixins/breakpoints'; .poster { width: 100%; diff --git a/UI/Web/src/app/collections/collection-detail/collection-detail.component.ts b/UI/Web/src/app/collections/collection-detail/collection-detail.component.ts index 2b4f6c4a4..02f897451 100644 --- a/UI/Web/src/app/collections/collection-detail/collection-detail.component.ts +++ b/UI/Web/src/app/collections/collection-detail/collection-detail.component.ts @@ -6,15 +6,14 @@ import { ToastrService } from 'ngx-toastr'; import { Subject } from 'rxjs'; import { debounceTime, take, takeUntil, takeWhile } from 'rxjs/operators'; import { BulkSelectionService } from 'src/app/cards/bulk-selection.service'; -import { UpdateFilterEvent } from 'src/app/cards/card-detail-layout/card-detail-layout.component'; +import { FilterSettings } from 'src/app/cards/card-detail-layout/card-detail-layout.component'; import { EditCollectionTagsComponent } from 'src/app/cards/_modals/edit-collection-tags/edit-collection-tags.component'; -import { KEY_CODES } from 'src/app/shared/_services/utility.service'; +import { KEY_CODES, UtilityService } from 'src/app/shared/_services/utility.service'; import { CollectionTag } from 'src/app/_models/collection-tag'; import { SeriesAddedToCollectionEvent } from 'src/app/_models/events/series-added-to-collection-event'; -import { SeriesRemovedEvent } from 'src/app/_models/events/series-removed-event'; import { Pagination } from 'src/app/_models/pagination'; import { Series } from 'src/app/_models/series'; -import { FilterItem, mangaFormatFilters, SeriesFilter } from 'src/app/_models/series-filter'; +import { SeriesFilter } from 'src/app/_models/series-filter'; import { AccountService } from 'src/app/_services/account.service'; import { Action, ActionFactoryService, ActionItem } from 'src/app/_services/action-factory.service'; import { ActionService } from 'src/app/_services/action.service'; @@ -39,10 +38,8 @@ export class CollectionDetailComponent implements OnInit, OnDestroy { seriesPagination!: Pagination; collectionTagActions: ActionItem[] = []; isAdmin: boolean = false; - filters: Array = mangaFormatFilters; - filter: SeriesFilter = { - mangaFormat: null - }; + filter: SeriesFilter | undefined = undefined; + filterSettings: FilterSettings = new FilterSettings(); private onDestory: Subject = new Subject(); @@ -85,7 +82,8 @@ export class CollectionDetailComponent implements OnInit, OnDestroy { constructor(public imageService: ImageService, private collectionService: CollectionTagService, private router: Router, private route: ActivatedRoute, private seriesService: SeriesService, private toastr: ToastrService, private actionFactoryService: ActionFactoryService, private modalService: NgbModal, private titleService: Title, private accountService: AccountService, - public bulkSelectionService: BulkSelectionService, private actionService: ActionService, private messageHub: MessageHubService) { + public bulkSelectionService: BulkSelectionService, private actionService: ActionService, private messageHub: MessageHubService, + private utilityService: UtilityService) { this.router.routeReuseStrategy.shouldReuseRoute = () => false; this.accountService.currentUser$.pipe(take(1)).subscribe(user => { @@ -100,6 +98,10 @@ export class CollectionDetailComponent implements OnInit, OnDestroy { return; } const tagId = parseInt(routeId, 10); + + [this.filterSettings.presets, this.filterSettings.openByDefault] = this.utilityService.filterPresetsFromUrl(this.route.snapshot, this.seriesService.createSeriesFilter()); + this.filterSettings.presets.collectionTags = [tagId]; + this.updateTag(tagId); } @@ -149,7 +151,6 @@ export class CollectionDetailComponent implements OnInit, OnDestroy { this.collectionTag = matchingTags[0]; this.tagImage = this.imageService.randomize(this.imageService.getCollectionCoverImage(this.collectionTag.id)); this.titleService.setTitle('Kavita - ' + this.collectionTag.title + ' Collection'); - this.loadPage(); }); } @@ -174,8 +175,8 @@ export class CollectionDetailComponent implements OnInit, OnDestroy { }); } - updateFilter(data: UpdateFilterEvent) { - this.filter.mangaFormat = data.filterItem.value; + updateFilter(data: SeriesFilter) { + this.filter = data; if (this.seriesPagination !== undefined && this.seriesPagination !== null) { this.seriesPagination.currentPage = 1; this.onPageChange(this.seriesPagination); diff --git a/UI/Web/src/app/library-detail/library-detail.component.html b/UI/Web/src/app/library-detail/library-detail.component.html index d01cec915..cebeac178 100644 --- a/UI/Web/src/app/library-detail/library-detail.component.html +++ b/UI/Web/src/app/library-detail/library-detail.component.html @@ -1,10 +1,10 @@ - diff --git a/UI/Web/src/app/library-detail/library-detail.component.ts b/UI/Web/src/app/library-detail/library-detail.component.ts index 810f20131..13fc0e885 100644 --- a/UI/Web/src/app/library-detail/library-detail.component.ts +++ b/UI/Web/src/app/library-detail/library-detail.component.ts @@ -4,13 +4,13 @@ import { ActivatedRoute, Router } from '@angular/router'; import { Subject } from 'rxjs'; import { debounceTime, take, takeUntil, takeWhile } from 'rxjs/operators'; import { BulkSelectionService } from '../cards/bulk-selection.service'; -import { UpdateFilterEvent } from '../cards/card-detail-layout/card-detail-layout.component'; -import { KEY_CODES } from '../shared/_services/utility.service'; +import { FilterSettings } from '../cards/card-detail-layout/card-detail-layout.component'; +import { KEY_CODES, UtilityService } from '../shared/_services/utility.service'; import { SeriesAddedEvent } from '../_models/events/series-added-event'; import { Library } from '../_models/library'; import { Pagination } from '../_models/pagination'; import { Series } from '../_models/series'; -import { FilterItem, mangaFormatFilters, SeriesFilter } from '../_models/series-filter'; +import { SeriesFilter } from '../_models/series-filter'; import { Action, ActionFactoryService, ActionItem } from '../_services/action-factory.service'; import { ActionService } from '../_services/action.service'; import { LibraryService } from '../_services/library.service'; @@ -30,11 +30,9 @@ export class LibraryDetailComponent implements OnInit, OnDestroy { loadingSeries = false; pagination!: Pagination; actions: ActionItem[] = []; - filters: Array = mangaFormatFilters; - filter: SeriesFilter = { - mangaFormat: null - }; + filter: SeriesFilter | undefined = undefined; onDestroy: Subject = new Subject(); + filterSettings: FilterSettings = new FilterSettings(); bulkActionCallback = (action: Action, data: any) => { const selectedSeriesIndexies = this.bulkSelectionService.getSelectedCardsForSource('series'); @@ -75,12 +73,14 @@ export class LibraryDetailComponent implements OnInit, OnDestroy { constructor(private route: ActivatedRoute, private router: Router, private seriesService: SeriesService, private libraryService: LibraryService, private titleService: Title, private actionFactoryService: ActionFactoryService, - private actionService: ActionService, public bulkSelectionService: BulkSelectionService, private hubService: MessageHubService) { + private actionService: ActionService, public bulkSelectionService: BulkSelectionService, private hubService: MessageHubService, + private utilityService: UtilityService) { const routeId = this.route.snapshot.paramMap.get('id'); if (routeId === null) { this.router.navigateByUrl('/libraries'); return; } + this.router.routeReuseStrategy.shouldReuseRoute = () => false; this.libraryId = parseInt(routeId, 10); this.libraryService.getLibraryNames().pipe(take(1)).subscribe(names => { @@ -89,7 +89,11 @@ export class LibraryDetailComponent implements OnInit, OnDestroy { }); this.actions = this.actionFactoryService.getLibraryActions(this.handleAction.bind(this)); this.pagination = {currentPage: 0, itemsPerPage: 30, totalItems: 0, totalPages: 1}; - this.loadPage(); + + [this.filterSettings.presets, this.filterSettings.openByDefault] = this.utilityService.filterPresetsFromUrl(this.route.snapshot, this.seriesService.createSeriesFilter()); + this.filterSettings.presets.libraries = [this.libraryId]; + + //this.loadPage(); } ngOnInit(): void { @@ -134,8 +138,8 @@ export class LibraryDetailComponent implements OnInit, OnDestroy { } } - updateFilter(data: UpdateFilterEvent) { - this.filter.mangaFormat = data.filterItem.value; + updateFilter(data: SeriesFilter) { + this.filter = data; if (this.pagination !== undefined && this.pagination !== null) { this.pagination.currentPage = 1; this.onPageChange(this.pagination); @@ -151,7 +155,13 @@ export class LibraryDetailComponent implements OnInit, OnDestroy { } this.loadingSeries = true; - this.seriesService.getSeriesForLibrary(this.libraryId, this.pagination?.currentPage, this.pagination?.itemsPerPage, this.filter).pipe(take(1)).subscribe(series => { + // The filter is out of sync with the presets from typeaheads on first load but syncs afterwards + if (this.filter == undefined) { + this.filter = this.seriesService.createSeriesFilter(); + this.filter.libraries.push(this.libraryId); + } + + this.seriesService.getSeriesForLibrary(0, this.pagination?.currentPage, this.pagination?.itemsPerPage, this.filter).pipe(take(1)).subscribe(series => { this.series = series.result; this.pagination = series.pagination; this.loadingSeries = false; @@ -160,7 +170,7 @@ export class LibraryDetailComponent implements OnInit, OnDestroy { } onPageChange(pagination: Pagination) { - window.history.replaceState(window.location.href, '', window.location.href.split('?')[0] + '?page=' + this.pagination.currentPage); + window.history.replaceState(window.location.href, '', window.location.href.split('?')[0] + '?' + 'page=' + this.pagination.currentPage); this.loadPage(); } diff --git a/UI/Web/src/app/library/library.component.html b/UI/Web/src/app/library/library.component.html index 3157a7d80..52c642743 100644 --- a/UI/Web/src/app/library/library.component.html +++ b/UI/Web/src/app/library/library.component.html @@ -17,7 +17,7 @@ - + diff --git a/UI/Web/src/app/library/library.component.ts b/UI/Web/src/app/library/library.component.ts index dc5ff3228..83ff53e80 100644 --- a/UI/Web/src/app/library/library.component.ts +++ b/UI/Web/src/app/library/library.component.ts @@ -110,6 +110,8 @@ export class LibraryComponent implements OnInit, OnDestroy { this.router.navigate(['recently-added']); } else if (sectionTitle.toLowerCase() === 'on deck') { this.router.navigate(['on-deck']); + } else if (sectionTitle.toLowerCase() === 'libraries') { + this.router.navigate(['all-series']); } } diff --git a/UI/Web/src/app/manga-reader/_models/reader-enums.ts b/UI/Web/src/app/manga-reader/_models/reader-enums.ts index 9738edf9f..37ab08054 100644 --- a/UI/Web/src/app/manga-reader/_models/reader-enums.ts +++ b/UI/Web/src/app/manga-reader/_models/reader-enums.ts @@ -15,8 +15,3 @@ export enum PAGING_DIRECTION { BACKWARDS = -1, } -export enum COLOR_FILTER { - NONE = '', - SEPIA = 'filter-sepia', - DARK = 'filter-dark' -} diff --git a/UI/Web/src/app/manga-reader/infinite-scroller/infinite-scroller.component.html b/UI/Web/src/app/manga-reader/infinite-scroller/infinite-scroller.component.html index 6bc608c11..a2c1f61e1 100644 --- a/UI/Web/src/app/manga-reader/infinite-scroller/infinite-scroller.component.html +++ b/UI/Web/src/app/manga-reader/infinite-scroller/infinite-scroller.component.html @@ -26,7 +26,10 @@
    - image + image
    public PublicationStatus PublicationStatus { get; set; } + public bool LanguageLocked { get; set; } + public bool SummaryLocked { get; set; } + /// + /// Locked by user so metadata updates from scan loop will not override AgeRating + /// + public bool AgeRatingLocked { get; set; } + /// + /// Locked by user so metadata updates from scan loop will not override PublicationStatus + /// + public bool PublicationStatusLocked { get; set; } + public bool GenresLocked { get; set; } + public bool TagsLocked { get; set; } + public bool WriterLocked { get; set; } + public bool CharacterLocked { get; set; } + public bool ColoristLocked { get; set; } + public bool EditorLocked { get; set; } + public bool InkerLocked { get; set; } + public bool LettererLocked { get; set; } + public bool PencillerLocked { get; set; } + public bool PublisherLocked { get; set; } + public bool TranslatorLocked { get; set; } + public bool CoverArtistLocked { get; set; } + + public int SeriesId { get; set; } } } diff --git a/API/DTOs/Settings/ServerSettingDTO.cs b/API/DTOs/Settings/ServerSettingDTO.cs index 03f853d33..d3abaa313 100644 --- a/API/DTOs/Settings/ServerSettingDTO.cs +++ b/API/DTOs/Settings/ServerSettingDTO.cs @@ -37,5 +37,6 @@ namespace API.DTOs.Settings ///
    /// If null or empty string, will default back to default install setting aka public string EmailServiceUrl { get; set; } + public string InstallVersion { get; set; } } } diff --git a/API/DTOs/Stats/ServerInfoDto.cs b/API/DTOs/Stats/ServerInfoDto.cs index 9176a81ff..45a73236b 100644 --- a/API/DTOs/Stats/ServerInfoDto.cs +++ b/API/DTOs/Stats/ServerInfoDto.cs @@ -1,4 +1,6 @@ -namespace API.DTOs.Stats +using API.Entities.Enums; + +namespace API.DTOs.Stats { public class ServerInfoDto { @@ -10,5 +12,39 @@ public int NumOfCores { get; set; } public int NumberOfLibraries { get; set; } public bool HasBookmarks { get; set; } + /// + /// The site theme the install is using + /// + public string ActiveSiteTheme { get; set; } + + /// + /// The reading mode the main user has as a preference + /// + public ReaderMode MangaReaderMode { get; set; } + + /// + /// Number of users on the install + /// + public int NumberOfUsers { get; set; } + + /// + /// Number of collections on the install + /// + public int NumberOfCollections { get; set; } + + /// + /// Number of reading lists on the install (Sum of all users) + /// + public int NumberOfReadingLists { get; set; } + + /// + /// Is OPDS enabled + /// + public bool OPDSEnabled { get; set; } + + /// + /// Total number of files in the instance + /// + public int TotalFiles { get; set; } } } diff --git a/API/DTOs/Theme/SiteThemeDto.cs b/API/DTOs/Theme/SiteThemeDto.cs new file mode 100644 index 000000000..e8b0460f9 --- /dev/null +++ b/API/DTOs/Theme/SiteThemeDto.cs @@ -0,0 +1,30 @@ +using System; +using API.Entities.Enums.Theme; +using API.Services; + +namespace API.DTOs.Theme; + +public class SiteThemeDto +{ + public int Id { get; set; } + /// + /// Name of the Theme + /// + public string Name { get; set; } + /// + /// File path to the content. Stored under . + /// Must be a .css file + /// + public string FileName { get; set; } + /// + /// Only one theme can have this. Will auto-set this as default for new user accounts + /// + public bool IsDefault { get; set; } + /// + /// Where did the theme come from + /// + public ThemeProvider Provider { get; set; } + public DateTime Created { get; set; } + public DateTime LastModified { get; set; } + public string Selector => "bg-" + Name.ToLower(); +} diff --git a/API/DTOs/Theme/UpdateDefaultSiteThemeDto.cs b/API/DTOs/Theme/UpdateDefaultSiteThemeDto.cs new file mode 100644 index 000000000..d4bdb8e09 --- /dev/null +++ b/API/DTOs/Theme/UpdateDefaultSiteThemeDto.cs @@ -0,0 +1,6 @@ +namespace API.DTOs.Theme; + +public class UpdateDefaultSiteThemeDto +{ + public int ThemeId { get; set; } +} diff --git a/API/DTOs/UpdateSeriesDto.cs b/API/DTOs/UpdateSeriesDto.cs index 39054a032..8f10373e4 100644 --- a/API/DTOs/UpdateSeriesDto.cs +++ b/API/DTOs/UpdateSeriesDto.cs @@ -6,10 +6,10 @@ public string Name { get; init; } public string LocalizedName { get; init; } public string SortName { get; init; } - public string Summary { get; init; } - public byte[] CoverImage { get; init; } - public int UserRating { get; set; } - public string UserReview { get; set; } public bool CoverImageLocked { get; set; } + + public bool NameLocked { get; set; } + public bool SortNameLocked { get; set; } + public bool LocalizedNameLocked { get; set; } } } diff --git a/API/DTOs/UpdateSeriesMetadataDto.cs b/API/DTOs/UpdateSeriesMetadataDto.cs index dd43167c9..08d3e77e6 100644 --- a/API/DTOs/UpdateSeriesMetadataDto.cs +++ b/API/DTOs/UpdateSeriesMetadataDto.cs @@ -6,6 +6,6 @@ namespace API.DTOs public class UpdateSeriesMetadataDto { public SeriesMetadataDto SeriesMetadata { get; set; } - public ICollection Tags { get; set; } + public ICollection CollectionTags { get; set; } } -} \ No newline at end of file +} diff --git a/API/DTOs/UpdateUserRole.cs b/API/DTOs/UpdateUserRole.cs new file mode 100644 index 000000000..a37076d2c --- /dev/null +++ b/API/DTOs/UpdateUserRole.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; +using MediatR; + +namespace API.DTOs; + +public class UpdateUserRole : IRequest +{ + public string Username { get; init; } + public IList Roles { get; init; } +} diff --git a/API/DTOs/Uploads/UploadUrlDto.cs b/API/DTOs/Uploads/UploadUrlDto.cs new file mode 100644 index 000000000..cd44b78a2 --- /dev/null +++ b/API/DTOs/Uploads/UploadUrlDto.cs @@ -0,0 +1,9 @@ +namespace API.DTOs.Uploads; + +public class UploadUrlDto +{ + /// + /// External url + /// + public string Url { get; set; } +} diff --git a/API/DTOs/UserDto.cs b/API/DTOs/UserDto.cs index 7a7a234e7..dc6fc8b43 100644 --- a/API/DTOs/UserDto.cs +++ b/API/DTOs/UserDto.cs @@ -5,8 +5,8 @@ namespace API.DTOs { public string Username { get; init; } public string Email { get; init; } - public string Token { get; init; } - public string RefreshToken { get; init; } + public string Token { get; set; } + public string RefreshToken { get; set; } public string ApiKey { get; init; } public UserPreferencesDto Preferences { get; set; } } diff --git a/API/DTOs/UserPreferencesDto.cs b/API/DTOs/UserPreferencesDto.cs index c36c9d146..4bfcb2d77 100644 --- a/API/DTOs/UserPreferencesDto.cs +++ b/API/DTOs/UserPreferencesDto.cs @@ -1,21 +1,78 @@ -using API.Entities.Enums; +using API.Entities; +using API.Entities.Enums; namespace API.DTOs { public class UserPreferencesDto { + /// + /// Manga Reader Option: What direction should the next/prev page buttons go + /// public ReadingDirection ReadingDirection { get; set; } + /// + /// Manga Reader Option: How should the image be scaled to screen + /// public ScalingOption ScalingOption { get; set; } + /// + /// Manga Reader Option: Which side of a split image should we show first + /// public PageSplitOption PageSplitOption { get; set; } + /// + /// Manga Reader Option: How the manga reader should perform paging or reading of the file + /// + /// Webtoon uses scrolling to page, LeftRight uses paging by clicking left/right side of reader, UpDown uses paging + /// by clicking top/bottom sides of reader. + /// + /// public ReaderMode ReaderMode { get; set; } + /// + /// Manga Reader Option: How many pages to display in the reader at once + /// + public LayoutMode LayoutMode { get; set; } + /// + /// Manga Reader Option: Background color of the reader + /// + public string BackgroundColor { get; set; } = "#000000"; + /// + /// Manga Reader Option: Allow the menu to close after 6 seconds without interaction + /// public bool AutoCloseMenu { get; set; } + /// + /// Manga Reader Option: Show screen hints to the user on some actions, ie) pagination direction change + /// + public bool ShowScreenHints { get; set; } = true; + /// + /// Book Reader Option: Should the background color be dark + /// public bool BookReaderDarkMode { get; set; } = false; + /// + /// Book Reader Option: Override extra Margin + /// public int BookReaderMargin { get; set; } + /// + /// Book Reader Option: Override line-height + /// public int BookReaderLineSpacing { get; set; } + /// + /// Book Reader Option: Override font size + /// public int BookReaderFontSize { get; set; } + /// + /// Book Reader Option: Maps to the default Kavita font-family (inherit) or an override + /// public string BookReaderFontFamily { get; set; } + /// + /// Book Reader Option: Allows tapping on side of screens to paginate + /// public bool BookReaderTapToPaginate { get; set; } + /// + /// Book Reader Option: What direction should the next/prev page buttons go + /// public ReadingDirection BookReaderReadingDirection { get; set; } - public bool SiteDarkMode { get; set; } + /// + /// UI Site Global Setting: The UI theme the user should use. + /// + /// Should default to Dark + public SiteTheme Theme { get; set; } } } diff --git a/API/Data/DataContext.cs b/API/Data/DataContext.cs index c1e100d48..6822467a8 100644 --- a/API/Data/DataContext.cs +++ b/API/Data/DataContext.cs @@ -40,6 +40,7 @@ namespace API.Data public DbSet Person { get; set; } public DbSet Genre { get; set; } public DbSet Tag { get; set; } + public DbSet SiteTheme { get; set; } protected override void OnModelCreating(ModelBuilder builder) diff --git a/API/Data/Metadata/ComicInfo.cs b/API/Data/Metadata/ComicInfo.cs index 0f213d848..040d7f6b7 100644 --- a/API/Data/Metadata/ComicInfo.cs +++ b/API/Data/Metadata/ComicInfo.cs @@ -14,6 +14,7 @@ namespace API.Data.Metadata public string Summary { get; set; } = string.Empty; public string Title { get; set; } = string.Empty; public string Series { get; set; } = string.Empty; + public string SeriesSort { get; set; } = string.Empty; public string Number { get; set; } = string.Empty; /// /// The total number of items in the series. @@ -25,7 +26,7 @@ namespace API.Data.Metadata public int PageCount { get; set; } // ReSharper disable once InconsistentNaming /// - /// ISO 639-1 Code to represent the language of the content + /// IETF BCP 47 Code to represent the language of the content /// public string LanguageISO { get; set; } = string.Empty; /// diff --git a/API/Data/Migrations/20220215163317_SiteTheme.Designer.cs b/API/Data/Migrations/20220215163317_SiteTheme.Designer.cs new file mode 100644 index 000000000..43b538c9a --- /dev/null +++ b/API/Data/Migrations/20220215163317_SiteTheme.Designer.cs @@ -0,0 +1,1391 @@ +// +using System; +using API.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace API.Data.Migrations +{ + [DbContext(typeof(DataContext))] + [Migration("20220215163317_SiteTheme")] + partial class SiteTheme + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "6.0.1"); + + modelBuilder.Entity("API.Entities.AppRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("API.Entities.AppUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessFailedCount") + .HasColumnType("INTEGER"); + + b.Property("ApiKey") + .HasColumnType("TEXT"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("EmailConfirmed") + .HasColumnType("INTEGER"); + + b.Property("LastActive") + .HasColumnType("TEXT"); + + b.Property("LockoutEnabled") + .HasColumnType("INTEGER"); + + b.Property("LockoutEnd") + .HasColumnType("TEXT"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("PasswordHash") + .HasColumnType("TEXT"); + + b.Property("PhoneNumber") + .HasColumnType("TEXT"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SecurityStamp") + .HasColumnType("TEXT"); + + b.Property("TwoFactorEnabled") + .HasColumnType("INTEGER"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("API.Entities.AppUserBookmark", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("FileName") + .HasColumnType("TEXT"); + + b.Property("Page") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("AppUserBookmark"); + }); + + modelBuilder.Entity("API.Entities.AppUserPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("AutoCloseMenu") + .HasColumnType("INTEGER"); + + b.Property("BookReaderDarkMode") + .HasColumnType("INTEGER"); + + b.Property("BookReaderFontFamily") + .HasColumnType("TEXT"); + + b.Property("BookReaderFontSize") + .HasColumnType("INTEGER"); + + b.Property("BookReaderLineSpacing") + .HasColumnType("INTEGER"); + + b.Property("BookReaderMargin") + .HasColumnType("INTEGER"); + + b.Property("BookReaderReadingDirection") + .HasColumnType("INTEGER"); + + b.Property("BookReaderTapToPaginate") + .HasColumnType("INTEGER"); + + b.Property("PageSplitOption") + .HasColumnType("INTEGER"); + + b.Property("ReaderMode") + .HasColumnType("INTEGER"); + + b.Property("ReadingDirection") + .HasColumnType("INTEGER"); + + b.Property("ScalingOption") + .HasColumnType("INTEGER"); + + b.Property("ThemeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId") + .IsUnique(); + + b.HasIndex("ThemeId"); + + b.ToTable("AppUserPreferences"); + }); + + modelBuilder.Entity("API.Entities.AppUserProgress", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("BookScrollId") + .HasColumnType("TEXT"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("PagesRead") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.HasIndex("SeriesId"); + + b.ToTable("AppUserProgresses"); + }); + + modelBuilder.Entity("API.Entities.AppUserRating", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("Rating") + .HasColumnType("INTEGER"); + + b.Property("Review") + .HasColumnType("TEXT"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.HasIndex("SeriesId"); + + b.ToTable("AppUserRating"); + }); + + modelBuilder.Entity("API.Entities.AppUserRole", b => + { + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AgeRating") + .HasColumnType("INTEGER"); + + b.Property("Count") + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("IsSpecial") + .HasColumnType("INTEGER"); + + b.Property("Language") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Number") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("Range") + .HasColumnType("TEXT"); + + b.Property("ReleaseDate") + .HasColumnType("TEXT"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.Property("TitleName") + .HasColumnType("TEXT"); + + b.Property("TotalCount") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("VolumeId"); + + b.ToTable("Chapter"); + }); + + modelBuilder.Entity("API.Entities.CollectionTag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("NormalizedTitle") + .HasColumnType("TEXT"); + + b.Property("Promoted") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Id", "Promoted") + .IsUnique(); + + b.ToTable("CollectionTag"); + }); + + modelBuilder.Entity("API.Entities.FolderPath", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("LastScanned") + .HasColumnType("TEXT"); + + b.Property("LibraryId") + .HasColumnType("INTEGER"); + + b.Property("Path") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("LibraryId"); + + b.ToTable("FolderPath"); + }); + + modelBuilder.Entity("API.Entities.Genre", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ExternalTag") + .HasColumnType("INTEGER"); + + b.Property("NormalizedTitle") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedTitle", "ExternalTag") + .IsUnique(); + + b.ToTable("Genre"); + }); + + modelBuilder.Entity("API.Entities.Library", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("LastScanned") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Library"); + }); + + modelBuilder.Entity("API.Entities.MangaFile", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("FilePath") + .HasColumnType("TEXT"); + + b.Property("Format") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ChapterId"); + + b.ToTable("MangaFile"); + }); + + modelBuilder.Entity("API.Entities.Metadata.SeriesMetadata", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AgeRating") + .HasColumnType("INTEGER"); + + b.Property("Count") + .HasColumnType("INTEGER"); + + b.Property("Language") + .HasColumnType("TEXT"); + + b.Property("PublicationStatus") + .HasColumnType("INTEGER"); + + b.Property("ReleaseYear") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("SeriesId") + .IsUnique(); + + b.HasIndex("Id", "SeriesId") + .IsUnique(); + + b.ToTable("SeriesMetadata"); + }); + + modelBuilder.Entity("API.Entities.Person", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasColumnType("TEXT"); + + b.Property("Role") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Person"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Promoted") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("ReadingList"); + }); + + modelBuilder.Entity("API.Entities.ReadingListItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("Order") + .HasColumnType("INTEGER"); + + b.Property("ReadingListId") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ChapterId"); + + b.HasIndex("ReadingListId"); + + b.HasIndex("SeriesId"); + + b.HasIndex("VolumeId"); + + b.ToTable("ReadingListItem"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("Format") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("LibraryId") + .HasColumnType("INTEGER"); + + b.Property("LocalizedName") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasColumnType("TEXT"); + + b.Property("OriginalName") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("SortName") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("LibraryId"); + + b.HasIndex("Name", "NormalizedName", "LocalizedName", "LibraryId", "Format") + .IsUnique(); + + b.ToTable("Series"); + }); + + modelBuilder.Entity("API.Entities.ServerSetting", b => + { + b.Property("Key") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("Key"); + + b.ToTable("ServerSetting"); + }); + + modelBuilder.Entity("API.Entities.SiteTheme", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("FileName") + .HasColumnType("TEXT"); + + b.Property("IsDefault") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasColumnType("TEXT"); + + b.Property("Provider") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("SiteTheme"); + }); + + modelBuilder.Entity("API.Entities.Tag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ExternalTag") + .HasColumnType("INTEGER"); + + b.Property("NormalizedTitle") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedTitle", "ExternalTag") + .IsUnique(); + + b.ToTable("Tag"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Number") + .HasColumnType("INTEGER"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("SeriesId"); + + b.ToTable("Volume"); + }); + + modelBuilder.Entity("AppUserLibrary", b => + { + b.Property("AppUsersId") + .HasColumnType("INTEGER"); + + b.Property("LibrariesId") + .HasColumnType("INTEGER"); + + b.HasKey("AppUsersId", "LibrariesId"); + + b.HasIndex("LibrariesId"); + + b.ToTable("AppUserLibrary"); + }); + + modelBuilder.Entity("ChapterGenre", b => + { + b.Property("ChaptersId") + .HasColumnType("INTEGER"); + + b.Property("GenresId") + .HasColumnType("INTEGER"); + + b.HasKey("ChaptersId", "GenresId"); + + b.HasIndex("GenresId"); + + b.ToTable("ChapterGenre"); + }); + + modelBuilder.Entity("ChapterPerson", b => + { + b.Property("ChapterMetadatasId") + .HasColumnType("INTEGER"); + + b.Property("PeopleId") + .HasColumnType("INTEGER"); + + b.HasKey("ChapterMetadatasId", "PeopleId"); + + b.HasIndex("PeopleId"); + + b.ToTable("ChapterPerson"); + }); + + modelBuilder.Entity("ChapterTag", b => + { + b.Property("ChaptersId") + .HasColumnType("INTEGER"); + + b.Property("TagsId") + .HasColumnType("INTEGER"); + + b.HasKey("ChaptersId", "TagsId"); + + b.HasIndex("TagsId"); + + b.ToTable("ChapterTag"); + }); + + modelBuilder.Entity("CollectionTagSeriesMetadata", b => + { + b.Property("CollectionTagsId") + .HasColumnType("INTEGER"); + + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.HasKey("CollectionTagsId", "SeriesMetadatasId"); + + b.HasIndex("SeriesMetadatasId"); + + b.ToTable("CollectionTagSeriesMetadata"); + }); + + modelBuilder.Entity("GenreSeriesMetadata", b => + { + b.Property("GenresId") + .HasColumnType("INTEGER"); + + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.HasKey("GenresId", "SeriesMetadatasId"); + + b.HasIndex("SeriesMetadatasId"); + + b.ToTable("GenreSeriesMetadata"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("ProviderKey") + .HasColumnType("TEXT"); + + b.Property("ProviderDisplayName") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("PersonSeriesMetadata", b => + { + b.Property("PeopleId") + .HasColumnType("INTEGER"); + + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.HasKey("PeopleId", "SeriesMetadatasId"); + + b.HasIndex("SeriesMetadatasId"); + + b.ToTable("PersonSeriesMetadata"); + }); + + modelBuilder.Entity("SeriesMetadataTag", b => + { + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.Property("TagsId") + .HasColumnType("INTEGER"); + + b.HasKey("SeriesMetadatasId", "TagsId"); + + b.HasIndex("TagsId"); + + b.ToTable("SeriesMetadataTag"); + }); + + modelBuilder.Entity("API.Entities.AppUserBookmark", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Bookmarks") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserPreferences", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithOne("UserPreferences") + .HasForeignKey("API.Entities.AppUserPreferences", "AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.SiteTheme", "Theme") + .WithMany() + .HasForeignKey("ThemeId"); + + b.Navigation("AppUser"); + + b.Navigation("Theme"); + }); + + modelBuilder.Entity("API.Entities.AppUserProgress", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Progresses") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Series", null) + .WithMany("Progress") + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserRating", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Ratings") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Series", null) + .WithMany("Ratings") + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserRole", b => + { + b.HasOne("API.Entities.AppRole", "Role") + .WithMany("UserRoles") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.AppUser", "User") + .WithMany("UserRoles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.HasOne("API.Entities.Volume", "Volume") + .WithMany("Chapters") + .HasForeignKey("VolumeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Volume"); + }); + + modelBuilder.Entity("API.Entities.FolderPath", b => + { + b.HasOne("API.Entities.Library", "Library") + .WithMany("Folders") + .HasForeignKey("LibraryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Library"); + }); + + modelBuilder.Entity("API.Entities.MangaFile", b => + { + b.HasOne("API.Entities.Chapter", "Chapter") + .WithMany("Files") + .HasForeignKey("ChapterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Chapter"); + }); + + modelBuilder.Entity("API.Entities.Metadata.SeriesMetadata", b => + { + b.HasOne("API.Entities.Series", "Series") + .WithOne("Metadata") + .HasForeignKey("API.Entities.Metadata.SeriesMetadata", "SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("ReadingLists") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.ReadingListItem", b => + { + b.HasOne("API.Entities.Chapter", "Chapter") + .WithMany() + .HasForeignKey("ChapterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.ReadingList", "ReadingList") + .WithMany("Items") + .HasForeignKey("ReadingListId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Series", "Series") + .WithMany() + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Volume", "Volume") + .WithMany() + .HasForeignKey("VolumeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Chapter"); + + b.Navigation("ReadingList"); + + b.Navigation("Series"); + + b.Navigation("Volume"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.HasOne("API.Entities.Library", "Library") + .WithMany("Series") + .HasForeignKey("LibraryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Library"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.HasOne("API.Entities.Series", "Series") + .WithMany("Volumes") + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("AppUserLibrary", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("AppUsersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Library", null) + .WithMany() + .HasForeignKey("LibrariesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ChapterGenre", b => + { + b.HasOne("API.Entities.Chapter", null) + .WithMany() + .HasForeignKey("ChaptersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Genre", null) + .WithMany() + .HasForeignKey("GenresId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ChapterPerson", b => + { + b.HasOne("API.Entities.Chapter", null) + .WithMany() + .HasForeignKey("ChapterMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Person", null) + .WithMany() + .HasForeignKey("PeopleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ChapterTag", b => + { + b.HasOne("API.Entities.Chapter", null) + .WithMany() + .HasForeignKey("ChaptersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Tag", null) + .WithMany() + .HasForeignKey("TagsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("CollectionTagSeriesMetadata", b => + { + b.HasOne("API.Entities.CollectionTag", null) + .WithMany() + .HasForeignKey("CollectionTagsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Metadata.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("GenreSeriesMetadata", b => + { + b.HasOne("API.Entities.Genre", null) + .WithMany() + .HasForeignKey("GenresId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Metadata.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("API.Entities.AppRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("PersonSeriesMetadata", b => + { + b.HasOne("API.Entities.Person", null) + .WithMany() + .HasForeignKey("PeopleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Metadata.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("SeriesMetadataTag", b => + { + b.HasOne("API.Entities.Metadata.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Tag", null) + .WithMany() + .HasForeignKey("TagsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("API.Entities.AppRole", b => + { + b.Navigation("UserRoles"); + }); + + modelBuilder.Entity("API.Entities.AppUser", b => + { + b.Navigation("Bookmarks"); + + b.Navigation("Progresses"); + + b.Navigation("Ratings"); + + b.Navigation("ReadingLists"); + + b.Navigation("UserPreferences"); + + b.Navigation("UserRoles"); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.Navigation("Files"); + }); + + modelBuilder.Entity("API.Entities.Library", b => + { + b.Navigation("Folders"); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.Navigation("Items"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.Navigation("Metadata"); + + b.Navigation("Progress"); + + b.Navigation("Ratings"); + + b.Navigation("Volumes"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.Navigation("Chapters"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/API/Data/Migrations/20220215163317_SiteTheme.cs b/API/Data/Migrations/20220215163317_SiteTheme.cs new file mode 100644 index 000000000..e2f519f8b --- /dev/null +++ b/API/Data/Migrations/20220215163317_SiteTheme.cs @@ -0,0 +1,79 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace API.Data.Migrations +{ + public partial class SiteTheme : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "SiteDarkMode", + table: "AppUserPreferences"); + + migrationBuilder.AddColumn( + name: "ThemeId", + table: "AppUserPreferences", + type: "INTEGER", + nullable: true); + + migrationBuilder.CreateTable( + name: "SiteTheme", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + Name = table.Column(type: "TEXT", nullable: true), + NormalizedName = table.Column(type: "TEXT", nullable: true), + FileName = table.Column(type: "TEXT", nullable: true), + IsDefault = table.Column(type: "INTEGER", nullable: false), + Provider = table.Column(type: "INTEGER", nullable: false), + Created = table.Column(type: "TEXT", nullable: false), + LastModified = table.Column(type: "TEXT", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_SiteTheme", x => x.Id); + }); + + migrationBuilder.CreateIndex( + name: "IX_AppUserPreferences_ThemeId", + table: "AppUserPreferences", + column: "ThemeId"); + + migrationBuilder.AddForeignKey( + name: "FK_AppUserPreferences_SiteTheme_ThemeId", + table: "AppUserPreferences", + column: "ThemeId", + principalTable: "SiteTheme", + principalColumn: "Id"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_AppUserPreferences_SiteTheme_ThemeId", + table: "AppUserPreferences"); + + migrationBuilder.DropTable( + name: "SiteTheme"); + + migrationBuilder.DropIndex( + name: "IX_AppUserPreferences_ThemeId", + table: "AppUserPreferences"); + + migrationBuilder.DropColumn( + name: "ThemeId", + table: "AppUserPreferences"); + + migrationBuilder.AddColumn( + name: "SiteDarkMode", + table: "AppUserPreferences", + type: "INTEGER", + nullable: false, + defaultValue: false); + } + } +} diff --git a/API/Data/Migrations/20220303205301_SeriesLockedFields.Designer.cs b/API/Data/Migrations/20220303205301_SeriesLockedFields.Designer.cs new file mode 100644 index 000000000..00fc7a10f --- /dev/null +++ b/API/Data/Migrations/20220303205301_SeriesLockedFields.Designer.cs @@ -0,0 +1,1448 @@ +// +using System; +using API.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace API.Data.Migrations +{ + [DbContext(typeof(DataContext))] + [Migration("20220303205301_SeriesLockedFields")] + partial class SeriesLockedFields + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "6.0.2"); + + modelBuilder.Entity("API.Entities.AppRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("API.Entities.AppUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessFailedCount") + .HasColumnType("INTEGER"); + + b.Property("ApiKey") + .HasColumnType("TEXT"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("EmailConfirmed") + .HasColumnType("INTEGER"); + + b.Property("LastActive") + .HasColumnType("TEXT"); + + b.Property("LockoutEnabled") + .HasColumnType("INTEGER"); + + b.Property("LockoutEnd") + .HasColumnType("TEXT"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("PasswordHash") + .HasColumnType("TEXT"); + + b.Property("PhoneNumber") + .HasColumnType("TEXT"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SecurityStamp") + .HasColumnType("TEXT"); + + b.Property("TwoFactorEnabled") + .HasColumnType("INTEGER"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("API.Entities.AppUserBookmark", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("FileName") + .HasColumnType("TEXT"); + + b.Property("Page") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("AppUserBookmark"); + }); + + modelBuilder.Entity("API.Entities.AppUserPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("AutoCloseMenu") + .HasColumnType("INTEGER"); + + b.Property("BookReaderDarkMode") + .HasColumnType("INTEGER"); + + b.Property("BookReaderFontFamily") + .HasColumnType("TEXT"); + + b.Property("BookReaderFontSize") + .HasColumnType("INTEGER"); + + b.Property("BookReaderLineSpacing") + .HasColumnType("INTEGER"); + + b.Property("BookReaderMargin") + .HasColumnType("INTEGER"); + + b.Property("BookReaderReadingDirection") + .HasColumnType("INTEGER"); + + b.Property("BookReaderTapToPaginate") + .HasColumnType("INTEGER"); + + b.Property("PageSplitOption") + .HasColumnType("INTEGER"); + + b.Property("ReaderMode") + .HasColumnType("INTEGER"); + + b.Property("ReadingDirection") + .HasColumnType("INTEGER"); + + b.Property("ScalingOption") + .HasColumnType("INTEGER"); + + b.Property("ThemeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId") + .IsUnique(); + + b.HasIndex("ThemeId"); + + b.ToTable("AppUserPreferences"); + }); + + modelBuilder.Entity("API.Entities.AppUserProgress", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("BookScrollId") + .HasColumnType("TEXT"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("PagesRead") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.HasIndex("SeriesId"); + + b.ToTable("AppUserProgresses"); + }); + + modelBuilder.Entity("API.Entities.AppUserRating", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("Rating") + .HasColumnType("INTEGER"); + + b.Property("Review") + .HasColumnType("TEXT"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.HasIndex("SeriesId"); + + b.ToTable("AppUserRating"); + }); + + modelBuilder.Entity("API.Entities.AppUserRole", b => + { + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AgeRating") + .HasColumnType("INTEGER"); + + b.Property("Count") + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("IsSpecial") + .HasColumnType("INTEGER"); + + b.Property("Language") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Number") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("Range") + .HasColumnType("TEXT"); + + b.Property("ReleaseDate") + .HasColumnType("TEXT"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.Property("TitleName") + .HasColumnType("TEXT"); + + b.Property("TotalCount") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("VolumeId"); + + b.ToTable("Chapter"); + }); + + modelBuilder.Entity("API.Entities.CollectionTag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("NormalizedTitle") + .HasColumnType("TEXT"); + + b.Property("Promoted") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Id", "Promoted") + .IsUnique(); + + b.ToTable("CollectionTag"); + }); + + modelBuilder.Entity("API.Entities.FolderPath", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("LastScanned") + .HasColumnType("TEXT"); + + b.Property("LibraryId") + .HasColumnType("INTEGER"); + + b.Property("Path") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("LibraryId"); + + b.ToTable("FolderPath"); + }); + + modelBuilder.Entity("API.Entities.Genre", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ExternalTag") + .HasColumnType("INTEGER"); + + b.Property("NormalizedTitle") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedTitle", "ExternalTag") + .IsUnique(); + + b.ToTable("Genre"); + }); + + modelBuilder.Entity("API.Entities.Library", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("LastScanned") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Library"); + }); + + modelBuilder.Entity("API.Entities.MangaFile", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("FilePath") + .HasColumnType("TEXT"); + + b.Property("Format") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ChapterId"); + + b.ToTable("MangaFile"); + }); + + modelBuilder.Entity("API.Entities.Metadata.SeriesMetadata", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AgeRating") + .HasColumnType("INTEGER"); + + b.Property("AgeRatingLocked") + .HasColumnType("INTEGER"); + + b.Property("CharacterLocked") + .HasColumnType("INTEGER"); + + b.Property("ColoristLocked") + .HasColumnType("INTEGER"); + + b.Property("Count") + .HasColumnType("INTEGER"); + + b.Property("CoverArtistLocked") + .HasColumnType("INTEGER"); + + b.Property("EditorLocked") + .HasColumnType("INTEGER"); + + b.Property("GenresLocked") + .HasColumnType("INTEGER"); + + b.Property("InkerLocked") + .HasColumnType("INTEGER"); + + b.Property("Language") + .HasColumnType("TEXT"); + + b.Property("LanguageLocked") + .HasColumnType("INTEGER"); + + b.Property("LettererLocked") + .HasColumnType("INTEGER"); + + b.Property("PencillerLocked") + .HasColumnType("INTEGER"); + + b.Property("PublicationStatus") + .HasColumnType("INTEGER"); + + b.Property("PublicationStatusLocked") + .HasColumnType("INTEGER"); + + b.Property("PublisherLocked") + .HasColumnType("INTEGER"); + + b.Property("ReleaseYear") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.Property("SummaryLocked") + .HasColumnType("INTEGER"); + + b.Property("TagsLocked") + .HasColumnType("INTEGER"); + + b.Property("TranslatorLocked") + .HasColumnType("INTEGER"); + + b.Property("WriterLocked") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("SeriesId") + .IsUnique(); + + b.HasIndex("Id", "SeriesId") + .IsUnique(); + + b.ToTable("SeriesMetadata"); + }); + + modelBuilder.Entity("API.Entities.Person", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasColumnType("TEXT"); + + b.Property("Role") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Person"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Promoted") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("ReadingList"); + }); + + modelBuilder.Entity("API.Entities.ReadingListItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("Order") + .HasColumnType("INTEGER"); + + b.Property("ReadingListId") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ChapterId"); + + b.HasIndex("ReadingListId"); + + b.HasIndex("SeriesId"); + + b.HasIndex("VolumeId"); + + b.ToTable("ReadingListItem"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("Format") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("LibraryId") + .HasColumnType("INTEGER"); + + b.Property("LocalizedName") + .HasColumnType("TEXT"); + + b.Property("LocalizedNameLocked") + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("NameLocked") + .HasColumnType("INTEGER"); + + b.Property("NormalizedName") + .HasColumnType("TEXT"); + + b.Property("OriginalName") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("SortName") + .HasColumnType("TEXT"); + + b.Property("SortNameLocked") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("LibraryId"); + + b.HasIndex("Name", "NormalizedName", "LocalizedName", "LibraryId", "Format") + .IsUnique(); + + b.ToTable("Series"); + }); + + modelBuilder.Entity("API.Entities.ServerSetting", b => + { + b.Property("Key") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("Key"); + + b.ToTable("ServerSetting"); + }); + + modelBuilder.Entity("API.Entities.SiteTheme", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("FileName") + .HasColumnType("TEXT"); + + b.Property("IsDefault") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasColumnType("TEXT"); + + b.Property("Provider") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("SiteTheme"); + }); + + modelBuilder.Entity("API.Entities.Tag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ExternalTag") + .HasColumnType("INTEGER"); + + b.Property("NormalizedTitle") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedTitle", "ExternalTag") + .IsUnique(); + + b.ToTable("Tag"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Number") + .HasColumnType("INTEGER"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("SeriesId"); + + b.ToTable("Volume"); + }); + + modelBuilder.Entity("AppUserLibrary", b => + { + b.Property("AppUsersId") + .HasColumnType("INTEGER"); + + b.Property("LibrariesId") + .HasColumnType("INTEGER"); + + b.HasKey("AppUsersId", "LibrariesId"); + + b.HasIndex("LibrariesId"); + + b.ToTable("AppUserLibrary"); + }); + + modelBuilder.Entity("ChapterGenre", b => + { + b.Property("ChaptersId") + .HasColumnType("INTEGER"); + + b.Property("GenresId") + .HasColumnType("INTEGER"); + + b.HasKey("ChaptersId", "GenresId"); + + b.HasIndex("GenresId"); + + b.ToTable("ChapterGenre"); + }); + + modelBuilder.Entity("ChapterPerson", b => + { + b.Property("ChapterMetadatasId") + .HasColumnType("INTEGER"); + + b.Property("PeopleId") + .HasColumnType("INTEGER"); + + b.HasKey("ChapterMetadatasId", "PeopleId"); + + b.HasIndex("PeopleId"); + + b.ToTable("ChapterPerson"); + }); + + modelBuilder.Entity("ChapterTag", b => + { + b.Property("ChaptersId") + .HasColumnType("INTEGER"); + + b.Property("TagsId") + .HasColumnType("INTEGER"); + + b.HasKey("ChaptersId", "TagsId"); + + b.HasIndex("TagsId"); + + b.ToTable("ChapterTag"); + }); + + modelBuilder.Entity("CollectionTagSeriesMetadata", b => + { + b.Property("CollectionTagsId") + .HasColumnType("INTEGER"); + + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.HasKey("CollectionTagsId", "SeriesMetadatasId"); + + b.HasIndex("SeriesMetadatasId"); + + b.ToTable("CollectionTagSeriesMetadata"); + }); + + modelBuilder.Entity("GenreSeriesMetadata", b => + { + b.Property("GenresId") + .HasColumnType("INTEGER"); + + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.HasKey("GenresId", "SeriesMetadatasId"); + + b.HasIndex("SeriesMetadatasId"); + + b.ToTable("GenreSeriesMetadata"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("ProviderKey") + .HasColumnType("TEXT"); + + b.Property("ProviderDisplayName") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("PersonSeriesMetadata", b => + { + b.Property("PeopleId") + .HasColumnType("INTEGER"); + + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.HasKey("PeopleId", "SeriesMetadatasId"); + + b.HasIndex("SeriesMetadatasId"); + + b.ToTable("PersonSeriesMetadata"); + }); + + modelBuilder.Entity("SeriesMetadataTag", b => + { + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.Property("TagsId") + .HasColumnType("INTEGER"); + + b.HasKey("SeriesMetadatasId", "TagsId"); + + b.HasIndex("TagsId"); + + b.ToTable("SeriesMetadataTag"); + }); + + modelBuilder.Entity("API.Entities.AppUserBookmark", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Bookmarks") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserPreferences", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithOne("UserPreferences") + .HasForeignKey("API.Entities.AppUserPreferences", "AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.SiteTheme", "Theme") + .WithMany() + .HasForeignKey("ThemeId"); + + b.Navigation("AppUser"); + + b.Navigation("Theme"); + }); + + modelBuilder.Entity("API.Entities.AppUserProgress", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Progresses") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Series", null) + .WithMany("Progress") + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserRating", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Ratings") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Series", null) + .WithMany("Ratings") + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserRole", b => + { + b.HasOne("API.Entities.AppRole", "Role") + .WithMany("UserRoles") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.AppUser", "User") + .WithMany("UserRoles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.HasOne("API.Entities.Volume", "Volume") + .WithMany("Chapters") + .HasForeignKey("VolumeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Volume"); + }); + + modelBuilder.Entity("API.Entities.FolderPath", b => + { + b.HasOne("API.Entities.Library", "Library") + .WithMany("Folders") + .HasForeignKey("LibraryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Library"); + }); + + modelBuilder.Entity("API.Entities.MangaFile", b => + { + b.HasOne("API.Entities.Chapter", "Chapter") + .WithMany("Files") + .HasForeignKey("ChapterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Chapter"); + }); + + modelBuilder.Entity("API.Entities.Metadata.SeriesMetadata", b => + { + b.HasOne("API.Entities.Series", "Series") + .WithOne("Metadata") + .HasForeignKey("API.Entities.Metadata.SeriesMetadata", "SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("ReadingLists") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.ReadingListItem", b => + { + b.HasOne("API.Entities.Chapter", "Chapter") + .WithMany() + .HasForeignKey("ChapterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.ReadingList", "ReadingList") + .WithMany("Items") + .HasForeignKey("ReadingListId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Series", "Series") + .WithMany() + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Volume", "Volume") + .WithMany() + .HasForeignKey("VolumeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Chapter"); + + b.Navigation("ReadingList"); + + b.Navigation("Series"); + + b.Navigation("Volume"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.HasOne("API.Entities.Library", "Library") + .WithMany("Series") + .HasForeignKey("LibraryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Library"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.HasOne("API.Entities.Series", "Series") + .WithMany("Volumes") + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("AppUserLibrary", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("AppUsersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Library", null) + .WithMany() + .HasForeignKey("LibrariesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ChapterGenre", b => + { + b.HasOne("API.Entities.Chapter", null) + .WithMany() + .HasForeignKey("ChaptersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Genre", null) + .WithMany() + .HasForeignKey("GenresId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ChapterPerson", b => + { + b.HasOne("API.Entities.Chapter", null) + .WithMany() + .HasForeignKey("ChapterMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Person", null) + .WithMany() + .HasForeignKey("PeopleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ChapterTag", b => + { + b.HasOne("API.Entities.Chapter", null) + .WithMany() + .HasForeignKey("ChaptersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Tag", null) + .WithMany() + .HasForeignKey("TagsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("CollectionTagSeriesMetadata", b => + { + b.HasOne("API.Entities.CollectionTag", null) + .WithMany() + .HasForeignKey("CollectionTagsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Metadata.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("GenreSeriesMetadata", b => + { + b.HasOne("API.Entities.Genre", null) + .WithMany() + .HasForeignKey("GenresId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Metadata.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("API.Entities.AppRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("PersonSeriesMetadata", b => + { + b.HasOne("API.Entities.Person", null) + .WithMany() + .HasForeignKey("PeopleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Metadata.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("SeriesMetadataTag", b => + { + b.HasOne("API.Entities.Metadata.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Tag", null) + .WithMany() + .HasForeignKey("TagsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("API.Entities.AppRole", b => + { + b.Navigation("UserRoles"); + }); + + modelBuilder.Entity("API.Entities.AppUser", b => + { + b.Navigation("Bookmarks"); + + b.Navigation("Progresses"); + + b.Navigation("Ratings"); + + b.Navigation("ReadingLists"); + + b.Navigation("UserPreferences"); + + b.Navigation("UserRoles"); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.Navigation("Files"); + }); + + modelBuilder.Entity("API.Entities.Library", b => + { + b.Navigation("Folders"); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.Navigation("Items"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.Navigation("Metadata"); + + b.Navigation("Progress"); + + b.Navigation("Ratings"); + + b.Navigation("Volumes"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.Navigation("Chapters"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/API/Data/Migrations/20220303205301_SeriesLockedFields.cs b/API/Data/Migrations/20220303205301_SeriesLockedFields.cs new file mode 100644 index 000000000..e3903db9e --- /dev/null +++ b/API/Data/Migrations/20220303205301_SeriesLockedFields.cs @@ -0,0 +1,224 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace API.Data.Migrations +{ + public partial class SeriesLockedFields : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "AgeRatingLocked", + table: "SeriesMetadata", + type: "INTEGER", + nullable: false, + defaultValue: false); + + migrationBuilder.AddColumn( + name: "CharacterLocked", + table: "SeriesMetadata", + type: "INTEGER", + nullable: false, + defaultValue: false); + + migrationBuilder.AddColumn( + name: "ColoristLocked", + table: "SeriesMetadata", + type: "INTEGER", + nullable: false, + defaultValue: false); + + migrationBuilder.AddColumn( + name: "CoverArtistLocked", + table: "SeriesMetadata", + type: "INTEGER", + nullable: false, + defaultValue: false); + + migrationBuilder.AddColumn( + name: "EditorLocked", + table: "SeriesMetadata", + type: "INTEGER", + nullable: false, + defaultValue: false); + + migrationBuilder.AddColumn( + name: "GenresLocked", + table: "SeriesMetadata", + type: "INTEGER", + nullable: false, + defaultValue: false); + + migrationBuilder.AddColumn( + name: "InkerLocked", + table: "SeriesMetadata", + type: "INTEGER", + nullable: false, + defaultValue: false); + + migrationBuilder.AddColumn( + name: "LanguageLocked", + table: "SeriesMetadata", + type: "INTEGER", + nullable: false, + defaultValue: false); + + migrationBuilder.AddColumn( + name: "LettererLocked", + table: "SeriesMetadata", + type: "INTEGER", + nullable: false, + defaultValue: false); + + migrationBuilder.AddColumn( + name: "PencillerLocked", + table: "SeriesMetadata", + type: "INTEGER", + nullable: false, + defaultValue: false); + + migrationBuilder.AddColumn( + name: "PublicationStatusLocked", + table: "SeriesMetadata", + type: "INTEGER", + nullable: false, + defaultValue: false); + + migrationBuilder.AddColumn( + name: "PublisherLocked", + table: "SeriesMetadata", + type: "INTEGER", + nullable: false, + defaultValue: false); + + migrationBuilder.AddColumn( + name: "SummaryLocked", + table: "SeriesMetadata", + type: "INTEGER", + nullable: false, + defaultValue: false); + + migrationBuilder.AddColumn( + name: "TagsLocked", + table: "SeriesMetadata", + type: "INTEGER", + nullable: false, + defaultValue: false); + + migrationBuilder.AddColumn( + name: "TranslatorLocked", + table: "SeriesMetadata", + type: "INTEGER", + nullable: false, + defaultValue: false); + + migrationBuilder.AddColumn( + name: "WriterLocked", + table: "SeriesMetadata", + type: "INTEGER", + nullable: false, + defaultValue: false); + + migrationBuilder.AddColumn( + name: "LocalizedNameLocked", + table: "Series", + type: "INTEGER", + nullable: false, + defaultValue: false); + + migrationBuilder.AddColumn( + name: "NameLocked", + table: "Series", + type: "INTEGER", + nullable: false, + defaultValue: false); + + migrationBuilder.AddColumn( + name: "SortNameLocked", + table: "Series", + type: "INTEGER", + nullable: false, + defaultValue: false); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "AgeRatingLocked", + table: "SeriesMetadata"); + + migrationBuilder.DropColumn( + name: "CharacterLocked", + table: "SeriesMetadata"); + + migrationBuilder.DropColumn( + name: "ColoristLocked", + table: "SeriesMetadata"); + + migrationBuilder.DropColumn( + name: "CoverArtistLocked", + table: "SeriesMetadata"); + + migrationBuilder.DropColumn( + name: "EditorLocked", + table: "SeriesMetadata"); + + migrationBuilder.DropColumn( + name: "GenresLocked", + table: "SeriesMetadata"); + + migrationBuilder.DropColumn( + name: "InkerLocked", + table: "SeriesMetadata"); + + migrationBuilder.DropColumn( + name: "LanguageLocked", + table: "SeriesMetadata"); + + migrationBuilder.DropColumn( + name: "LettererLocked", + table: "SeriesMetadata"); + + migrationBuilder.DropColumn( + name: "PencillerLocked", + table: "SeriesMetadata"); + + migrationBuilder.DropColumn( + name: "PublicationStatusLocked", + table: "SeriesMetadata"); + + migrationBuilder.DropColumn( + name: "PublisherLocked", + table: "SeriesMetadata"); + + migrationBuilder.DropColumn( + name: "SummaryLocked", + table: "SeriesMetadata"); + + migrationBuilder.DropColumn( + name: "TagsLocked", + table: "SeriesMetadata"); + + migrationBuilder.DropColumn( + name: "TranslatorLocked", + table: "SeriesMetadata"); + + migrationBuilder.DropColumn( + name: "WriterLocked", + table: "SeriesMetadata"); + + migrationBuilder.DropColumn( + name: "LocalizedNameLocked", + table: "Series"); + + migrationBuilder.DropColumn( + name: "NameLocked", + table: "Series"); + + migrationBuilder.DropColumn( + name: "SortNameLocked", + table: "Series"); + } + } +} diff --git a/API/Data/Migrations/20220306155456_MangaReaderBackgroundAndLayoutMode.Designer.cs b/API/Data/Migrations/20220306155456_MangaReaderBackgroundAndLayoutMode.Designer.cs new file mode 100644 index 000000000..a21ca1e92 --- /dev/null +++ b/API/Data/Migrations/20220306155456_MangaReaderBackgroundAndLayoutMode.Designer.cs @@ -0,0 +1,1454 @@ +// +using System; +using API.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace API.Data.Migrations +{ + [DbContext(typeof(DataContext))] + [Migration("20220306155456_MangaReaderBackgroundAndLayoutMode")] + partial class MangaReaderBackgroundAndLayoutMode + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "6.0.2"); + + modelBuilder.Entity("API.Entities.AppRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("API.Entities.AppUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessFailedCount") + .HasColumnType("INTEGER"); + + b.Property("ApiKey") + .HasColumnType("TEXT"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("EmailConfirmed") + .HasColumnType("INTEGER"); + + b.Property("LastActive") + .HasColumnType("TEXT"); + + b.Property("LockoutEnabled") + .HasColumnType("INTEGER"); + + b.Property("LockoutEnd") + .HasColumnType("TEXT"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("PasswordHash") + .HasColumnType("TEXT"); + + b.Property("PhoneNumber") + .HasColumnType("TEXT"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SecurityStamp") + .HasColumnType("TEXT"); + + b.Property("TwoFactorEnabled") + .HasColumnType("INTEGER"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("API.Entities.AppUserBookmark", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("FileName") + .HasColumnType("TEXT"); + + b.Property("Page") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("AppUserBookmark"); + }); + + modelBuilder.Entity("API.Entities.AppUserPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("AutoCloseMenu") + .HasColumnType("INTEGER"); + + b.Property("BackgroundColor") + .HasColumnType("TEXT"); + + b.Property("BookReaderDarkMode") + .HasColumnType("INTEGER"); + + b.Property("BookReaderFontFamily") + .HasColumnType("TEXT"); + + b.Property("BookReaderFontSize") + .HasColumnType("INTEGER"); + + b.Property("BookReaderLineSpacing") + .HasColumnType("INTEGER"); + + b.Property("BookReaderMargin") + .HasColumnType("INTEGER"); + + b.Property("BookReaderReadingDirection") + .HasColumnType("INTEGER"); + + b.Property("BookReaderTapToPaginate") + .HasColumnType("INTEGER"); + + b.Property("LayoutMode") + .HasColumnType("INTEGER"); + + b.Property("PageSplitOption") + .HasColumnType("INTEGER"); + + b.Property("ReaderMode") + .HasColumnType("INTEGER"); + + b.Property("ReadingDirection") + .HasColumnType("INTEGER"); + + b.Property("ScalingOption") + .HasColumnType("INTEGER"); + + b.Property("ThemeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId") + .IsUnique(); + + b.HasIndex("ThemeId"); + + b.ToTable("AppUserPreferences"); + }); + + modelBuilder.Entity("API.Entities.AppUserProgress", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("BookScrollId") + .HasColumnType("TEXT"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("PagesRead") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.HasIndex("SeriesId"); + + b.ToTable("AppUserProgresses"); + }); + + modelBuilder.Entity("API.Entities.AppUserRating", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("Rating") + .HasColumnType("INTEGER"); + + b.Property("Review") + .HasColumnType("TEXT"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.HasIndex("SeriesId"); + + b.ToTable("AppUserRating"); + }); + + modelBuilder.Entity("API.Entities.AppUserRole", b => + { + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AgeRating") + .HasColumnType("INTEGER"); + + b.Property("Count") + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("IsSpecial") + .HasColumnType("INTEGER"); + + b.Property("Language") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Number") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("Range") + .HasColumnType("TEXT"); + + b.Property("ReleaseDate") + .HasColumnType("TEXT"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.Property("TitleName") + .HasColumnType("TEXT"); + + b.Property("TotalCount") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("VolumeId"); + + b.ToTable("Chapter"); + }); + + modelBuilder.Entity("API.Entities.CollectionTag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("NormalizedTitle") + .HasColumnType("TEXT"); + + b.Property("Promoted") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Id", "Promoted") + .IsUnique(); + + b.ToTable("CollectionTag"); + }); + + modelBuilder.Entity("API.Entities.FolderPath", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("LastScanned") + .HasColumnType("TEXT"); + + b.Property("LibraryId") + .HasColumnType("INTEGER"); + + b.Property("Path") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("LibraryId"); + + b.ToTable("FolderPath"); + }); + + modelBuilder.Entity("API.Entities.Genre", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ExternalTag") + .HasColumnType("INTEGER"); + + b.Property("NormalizedTitle") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedTitle", "ExternalTag") + .IsUnique(); + + b.ToTable("Genre"); + }); + + modelBuilder.Entity("API.Entities.Library", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("LastScanned") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Library"); + }); + + modelBuilder.Entity("API.Entities.MangaFile", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("FilePath") + .HasColumnType("TEXT"); + + b.Property("Format") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ChapterId"); + + b.ToTable("MangaFile"); + }); + + modelBuilder.Entity("API.Entities.Metadata.SeriesMetadata", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AgeRating") + .HasColumnType("INTEGER"); + + b.Property("AgeRatingLocked") + .HasColumnType("INTEGER"); + + b.Property("CharacterLocked") + .HasColumnType("INTEGER"); + + b.Property("ColoristLocked") + .HasColumnType("INTEGER"); + + b.Property("Count") + .HasColumnType("INTEGER"); + + b.Property("CoverArtistLocked") + .HasColumnType("INTEGER"); + + b.Property("EditorLocked") + .HasColumnType("INTEGER"); + + b.Property("GenresLocked") + .HasColumnType("INTEGER"); + + b.Property("InkerLocked") + .HasColumnType("INTEGER"); + + b.Property("Language") + .HasColumnType("TEXT"); + + b.Property("LanguageLocked") + .HasColumnType("INTEGER"); + + b.Property("LettererLocked") + .HasColumnType("INTEGER"); + + b.Property("PencillerLocked") + .HasColumnType("INTEGER"); + + b.Property("PublicationStatus") + .HasColumnType("INTEGER"); + + b.Property("PublicationStatusLocked") + .HasColumnType("INTEGER"); + + b.Property("PublisherLocked") + .HasColumnType("INTEGER"); + + b.Property("ReleaseYear") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.Property("SummaryLocked") + .HasColumnType("INTEGER"); + + b.Property("TagsLocked") + .HasColumnType("INTEGER"); + + b.Property("TranslatorLocked") + .HasColumnType("INTEGER"); + + b.Property("WriterLocked") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("SeriesId") + .IsUnique(); + + b.HasIndex("Id", "SeriesId") + .IsUnique(); + + b.ToTable("SeriesMetadata"); + }); + + modelBuilder.Entity("API.Entities.Person", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasColumnType("TEXT"); + + b.Property("Role") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Person"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Promoted") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("ReadingList"); + }); + + modelBuilder.Entity("API.Entities.ReadingListItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("Order") + .HasColumnType("INTEGER"); + + b.Property("ReadingListId") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ChapterId"); + + b.HasIndex("ReadingListId"); + + b.HasIndex("SeriesId"); + + b.HasIndex("VolumeId"); + + b.ToTable("ReadingListItem"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("Format") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("LibraryId") + .HasColumnType("INTEGER"); + + b.Property("LocalizedName") + .HasColumnType("TEXT"); + + b.Property("LocalizedNameLocked") + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("NameLocked") + .HasColumnType("INTEGER"); + + b.Property("NormalizedName") + .HasColumnType("TEXT"); + + b.Property("OriginalName") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("SortName") + .HasColumnType("TEXT"); + + b.Property("SortNameLocked") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("LibraryId"); + + b.HasIndex("Name", "NormalizedName", "LocalizedName", "LibraryId", "Format") + .IsUnique(); + + b.ToTable("Series"); + }); + + modelBuilder.Entity("API.Entities.ServerSetting", b => + { + b.Property("Key") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("Key"); + + b.ToTable("ServerSetting"); + }); + + modelBuilder.Entity("API.Entities.SiteTheme", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("FileName") + .HasColumnType("TEXT"); + + b.Property("IsDefault") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasColumnType("TEXT"); + + b.Property("Provider") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("SiteTheme"); + }); + + modelBuilder.Entity("API.Entities.Tag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ExternalTag") + .HasColumnType("INTEGER"); + + b.Property("NormalizedTitle") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedTitle", "ExternalTag") + .IsUnique(); + + b.ToTable("Tag"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Number") + .HasColumnType("INTEGER"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("SeriesId"); + + b.ToTable("Volume"); + }); + + modelBuilder.Entity("AppUserLibrary", b => + { + b.Property("AppUsersId") + .HasColumnType("INTEGER"); + + b.Property("LibrariesId") + .HasColumnType("INTEGER"); + + b.HasKey("AppUsersId", "LibrariesId"); + + b.HasIndex("LibrariesId"); + + b.ToTable("AppUserLibrary"); + }); + + modelBuilder.Entity("ChapterGenre", b => + { + b.Property("ChaptersId") + .HasColumnType("INTEGER"); + + b.Property("GenresId") + .HasColumnType("INTEGER"); + + b.HasKey("ChaptersId", "GenresId"); + + b.HasIndex("GenresId"); + + b.ToTable("ChapterGenre"); + }); + + modelBuilder.Entity("ChapterPerson", b => + { + b.Property("ChapterMetadatasId") + .HasColumnType("INTEGER"); + + b.Property("PeopleId") + .HasColumnType("INTEGER"); + + b.HasKey("ChapterMetadatasId", "PeopleId"); + + b.HasIndex("PeopleId"); + + b.ToTable("ChapterPerson"); + }); + + modelBuilder.Entity("ChapterTag", b => + { + b.Property("ChaptersId") + .HasColumnType("INTEGER"); + + b.Property("TagsId") + .HasColumnType("INTEGER"); + + b.HasKey("ChaptersId", "TagsId"); + + b.HasIndex("TagsId"); + + b.ToTable("ChapterTag"); + }); + + modelBuilder.Entity("CollectionTagSeriesMetadata", b => + { + b.Property("CollectionTagsId") + .HasColumnType("INTEGER"); + + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.HasKey("CollectionTagsId", "SeriesMetadatasId"); + + b.HasIndex("SeriesMetadatasId"); + + b.ToTable("CollectionTagSeriesMetadata"); + }); + + modelBuilder.Entity("GenreSeriesMetadata", b => + { + b.Property("GenresId") + .HasColumnType("INTEGER"); + + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.HasKey("GenresId", "SeriesMetadatasId"); + + b.HasIndex("SeriesMetadatasId"); + + b.ToTable("GenreSeriesMetadata"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("ProviderKey") + .HasColumnType("TEXT"); + + b.Property("ProviderDisplayName") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("PersonSeriesMetadata", b => + { + b.Property("PeopleId") + .HasColumnType("INTEGER"); + + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.HasKey("PeopleId", "SeriesMetadatasId"); + + b.HasIndex("SeriesMetadatasId"); + + b.ToTable("PersonSeriesMetadata"); + }); + + modelBuilder.Entity("SeriesMetadataTag", b => + { + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.Property("TagsId") + .HasColumnType("INTEGER"); + + b.HasKey("SeriesMetadatasId", "TagsId"); + + b.HasIndex("TagsId"); + + b.ToTable("SeriesMetadataTag"); + }); + + modelBuilder.Entity("API.Entities.AppUserBookmark", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Bookmarks") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserPreferences", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithOne("UserPreferences") + .HasForeignKey("API.Entities.AppUserPreferences", "AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.SiteTheme", "Theme") + .WithMany() + .HasForeignKey("ThemeId"); + + b.Navigation("AppUser"); + + b.Navigation("Theme"); + }); + + modelBuilder.Entity("API.Entities.AppUserProgress", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Progresses") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Series", null) + .WithMany("Progress") + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserRating", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Ratings") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Series", null) + .WithMany("Ratings") + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserRole", b => + { + b.HasOne("API.Entities.AppRole", "Role") + .WithMany("UserRoles") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.AppUser", "User") + .WithMany("UserRoles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.HasOne("API.Entities.Volume", "Volume") + .WithMany("Chapters") + .HasForeignKey("VolumeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Volume"); + }); + + modelBuilder.Entity("API.Entities.FolderPath", b => + { + b.HasOne("API.Entities.Library", "Library") + .WithMany("Folders") + .HasForeignKey("LibraryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Library"); + }); + + modelBuilder.Entity("API.Entities.MangaFile", b => + { + b.HasOne("API.Entities.Chapter", "Chapter") + .WithMany("Files") + .HasForeignKey("ChapterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Chapter"); + }); + + modelBuilder.Entity("API.Entities.Metadata.SeriesMetadata", b => + { + b.HasOne("API.Entities.Series", "Series") + .WithOne("Metadata") + .HasForeignKey("API.Entities.Metadata.SeriesMetadata", "SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("ReadingLists") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.ReadingListItem", b => + { + b.HasOne("API.Entities.Chapter", "Chapter") + .WithMany() + .HasForeignKey("ChapterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.ReadingList", "ReadingList") + .WithMany("Items") + .HasForeignKey("ReadingListId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Series", "Series") + .WithMany() + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Volume", "Volume") + .WithMany() + .HasForeignKey("VolumeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Chapter"); + + b.Navigation("ReadingList"); + + b.Navigation("Series"); + + b.Navigation("Volume"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.HasOne("API.Entities.Library", "Library") + .WithMany("Series") + .HasForeignKey("LibraryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Library"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.HasOne("API.Entities.Series", "Series") + .WithMany("Volumes") + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("AppUserLibrary", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("AppUsersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Library", null) + .WithMany() + .HasForeignKey("LibrariesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ChapterGenre", b => + { + b.HasOne("API.Entities.Chapter", null) + .WithMany() + .HasForeignKey("ChaptersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Genre", null) + .WithMany() + .HasForeignKey("GenresId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ChapterPerson", b => + { + b.HasOne("API.Entities.Chapter", null) + .WithMany() + .HasForeignKey("ChapterMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Person", null) + .WithMany() + .HasForeignKey("PeopleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ChapterTag", b => + { + b.HasOne("API.Entities.Chapter", null) + .WithMany() + .HasForeignKey("ChaptersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Tag", null) + .WithMany() + .HasForeignKey("TagsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("CollectionTagSeriesMetadata", b => + { + b.HasOne("API.Entities.CollectionTag", null) + .WithMany() + .HasForeignKey("CollectionTagsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Metadata.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("GenreSeriesMetadata", b => + { + b.HasOne("API.Entities.Genre", null) + .WithMany() + .HasForeignKey("GenresId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Metadata.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("API.Entities.AppRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("PersonSeriesMetadata", b => + { + b.HasOne("API.Entities.Person", null) + .WithMany() + .HasForeignKey("PeopleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Metadata.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("SeriesMetadataTag", b => + { + b.HasOne("API.Entities.Metadata.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Tag", null) + .WithMany() + .HasForeignKey("TagsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("API.Entities.AppRole", b => + { + b.Navigation("UserRoles"); + }); + + modelBuilder.Entity("API.Entities.AppUser", b => + { + b.Navigation("Bookmarks"); + + b.Navigation("Progresses"); + + b.Navigation("Ratings"); + + b.Navigation("ReadingLists"); + + b.Navigation("UserPreferences"); + + b.Navigation("UserRoles"); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.Navigation("Files"); + }); + + modelBuilder.Entity("API.Entities.Library", b => + { + b.Navigation("Folders"); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.Navigation("Items"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.Navigation("Metadata"); + + b.Navigation("Progress"); + + b.Navigation("Ratings"); + + b.Navigation("Volumes"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.Navigation("Chapters"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/API/Data/Migrations/20220306155456_MangaReaderBackgroundAndLayoutMode.cs b/API/Data/Migrations/20220306155456_MangaReaderBackgroundAndLayoutMode.cs new file mode 100644 index 000000000..078e51684 --- /dev/null +++ b/API/Data/Migrations/20220306155456_MangaReaderBackgroundAndLayoutMode.cs @@ -0,0 +1,38 @@ +using API.Entities.Enums; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace API.Data.Migrations +{ + public partial class MangaReaderBackgroundAndLayoutMode : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "BackgroundColor", + table: "AppUserPreferences", + type: "TEXT", + defaultValue: "#000000", + nullable: false); + + migrationBuilder.AddColumn( + name: "LayoutMode", + table: "AppUserPreferences", + type: "INTEGER", + nullable: false, + defaultValue: LayoutMode.Single); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "BackgroundColor", + table: "AppUserPreferences"); + + migrationBuilder.DropColumn( + name: "LayoutMode", + table: "AppUserPreferences"); + } + } +} diff --git a/API/Data/Migrations/20220307153053_ScreenHints.Designer.cs b/API/Data/Migrations/20220307153053_ScreenHints.Designer.cs new file mode 100644 index 000000000..f54b0ab0b --- /dev/null +++ b/API/Data/Migrations/20220307153053_ScreenHints.Designer.cs @@ -0,0 +1,1457 @@ +// +using System; +using API.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace API.Data.Migrations +{ + [DbContext(typeof(DataContext))] + [Migration("20220307153053_ScreenHints")] + partial class ScreenHints + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "6.0.2"); + + modelBuilder.Entity("API.Entities.AppRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("API.Entities.AppUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AccessFailedCount") + .HasColumnType("INTEGER"); + + b.Property("ApiKey") + .HasColumnType("TEXT"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("EmailConfirmed") + .HasColumnType("INTEGER"); + + b.Property("LastActive") + .HasColumnType("TEXT"); + + b.Property("LockoutEnabled") + .HasColumnType("INTEGER"); + + b.Property("LockoutEnd") + .HasColumnType("TEXT"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("PasswordHash") + .HasColumnType("TEXT"); + + b.Property("PhoneNumber") + .HasColumnType("TEXT"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SecurityStamp") + .HasColumnType("TEXT"); + + b.Property("TwoFactorEnabled") + .HasColumnType("INTEGER"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("API.Entities.AppUserBookmark", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("FileName") + .HasColumnType("TEXT"); + + b.Property("Page") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("AppUserBookmark"); + }); + + modelBuilder.Entity("API.Entities.AppUserPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("AutoCloseMenu") + .HasColumnType("INTEGER"); + + b.Property("BackgroundColor") + .HasColumnType("TEXT"); + + b.Property("BookReaderDarkMode") + .HasColumnType("INTEGER"); + + b.Property("BookReaderFontFamily") + .HasColumnType("TEXT"); + + b.Property("BookReaderFontSize") + .HasColumnType("INTEGER"); + + b.Property("BookReaderLineSpacing") + .HasColumnType("INTEGER"); + + b.Property("BookReaderMargin") + .HasColumnType("INTEGER"); + + b.Property("BookReaderReadingDirection") + .HasColumnType("INTEGER"); + + b.Property("BookReaderTapToPaginate") + .HasColumnType("INTEGER"); + + b.Property("LayoutMode") + .HasColumnType("INTEGER"); + + b.Property("PageSplitOption") + .HasColumnType("INTEGER"); + + b.Property("ReaderMode") + .HasColumnType("INTEGER"); + + b.Property("ReadingDirection") + .HasColumnType("INTEGER"); + + b.Property("ScalingOption") + .HasColumnType("INTEGER"); + + b.Property("ShowScreenHints") + .HasColumnType("INTEGER"); + + b.Property("ThemeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId") + .IsUnique(); + + b.HasIndex("ThemeId"); + + b.ToTable("AppUserPreferences"); + }); + + modelBuilder.Entity("API.Entities.AppUserProgress", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("BookScrollId") + .HasColumnType("TEXT"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("PagesRead") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.HasIndex("SeriesId"); + + b.ToTable("AppUserProgresses"); + }); + + modelBuilder.Entity("API.Entities.AppUserRating", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("Rating") + .HasColumnType("INTEGER"); + + b.Property("Review") + .HasColumnType("TEXT"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.HasIndex("SeriesId"); + + b.ToTable("AppUserRating"); + }); + + modelBuilder.Entity("API.Entities.AppUserRole", b => + { + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AgeRating") + .HasColumnType("INTEGER"); + + b.Property("Count") + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("IsSpecial") + .HasColumnType("INTEGER"); + + b.Property("Language") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Number") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("Range") + .HasColumnType("TEXT"); + + b.Property("ReleaseDate") + .HasColumnType("TEXT"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.Property("TitleName") + .HasColumnType("TEXT"); + + b.Property("TotalCount") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("VolumeId"); + + b.ToTable("Chapter"); + }); + + modelBuilder.Entity("API.Entities.CollectionTag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("NormalizedTitle") + .HasColumnType("TEXT"); + + b.Property("Promoted") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Id", "Promoted") + .IsUnique(); + + b.ToTable("CollectionTag"); + }); + + modelBuilder.Entity("API.Entities.FolderPath", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("LastScanned") + .HasColumnType("TEXT"); + + b.Property("LibraryId") + .HasColumnType("INTEGER"); + + b.Property("Path") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("LibraryId"); + + b.ToTable("FolderPath"); + }); + + modelBuilder.Entity("API.Entities.Genre", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ExternalTag") + .HasColumnType("INTEGER"); + + b.Property("NormalizedTitle") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedTitle", "ExternalTag") + .IsUnique(); + + b.ToTable("Genre"); + }); + + modelBuilder.Entity("API.Entities.Library", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("LastScanned") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Library"); + }); + + modelBuilder.Entity("API.Entities.MangaFile", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("FilePath") + .HasColumnType("TEXT"); + + b.Property("Format") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ChapterId"); + + b.ToTable("MangaFile"); + }); + + modelBuilder.Entity("API.Entities.Metadata.SeriesMetadata", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AgeRating") + .HasColumnType("INTEGER"); + + b.Property("AgeRatingLocked") + .HasColumnType("INTEGER"); + + b.Property("CharacterLocked") + .HasColumnType("INTEGER"); + + b.Property("ColoristLocked") + .HasColumnType("INTEGER"); + + b.Property("Count") + .HasColumnType("INTEGER"); + + b.Property("CoverArtistLocked") + .HasColumnType("INTEGER"); + + b.Property("EditorLocked") + .HasColumnType("INTEGER"); + + b.Property("GenresLocked") + .HasColumnType("INTEGER"); + + b.Property("InkerLocked") + .HasColumnType("INTEGER"); + + b.Property("Language") + .HasColumnType("TEXT"); + + b.Property("LanguageLocked") + .HasColumnType("INTEGER"); + + b.Property("LettererLocked") + .HasColumnType("INTEGER"); + + b.Property("PencillerLocked") + .HasColumnType("INTEGER"); + + b.Property("PublicationStatus") + .HasColumnType("INTEGER"); + + b.Property("PublicationStatusLocked") + .HasColumnType("INTEGER"); + + b.Property("PublisherLocked") + .HasColumnType("INTEGER"); + + b.Property("ReleaseYear") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.Property("SummaryLocked") + .HasColumnType("INTEGER"); + + b.Property("TagsLocked") + .HasColumnType("INTEGER"); + + b.Property("TranslatorLocked") + .HasColumnType("INTEGER"); + + b.Property("WriterLocked") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("SeriesId") + .IsUnique(); + + b.HasIndex("Id", "SeriesId") + .IsUnique(); + + b.ToTable("SeriesMetadata"); + }); + + modelBuilder.Entity("API.Entities.Person", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasColumnType("TEXT"); + + b.Property("Role") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Person"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AppUserId") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Promoted") + .HasColumnType("INTEGER"); + + b.Property("Summary") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("AppUserId"); + + b.ToTable("ReadingList"); + }); + + modelBuilder.Entity("API.Entities.ReadingListItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChapterId") + .HasColumnType("INTEGER"); + + b.Property("Order") + .HasColumnType("INTEGER"); + + b.Property("ReadingListId") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.Property("VolumeId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ChapterId"); + + b.HasIndex("ReadingListId"); + + b.HasIndex("SeriesId"); + + b.HasIndex("VolumeId"); + + b.ToTable("ReadingListItem"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("CoverImageLocked") + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("Format") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("LibraryId") + .HasColumnType("INTEGER"); + + b.Property("LocalizedName") + .HasColumnType("TEXT"); + + b.Property("LocalizedNameLocked") + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("NameLocked") + .HasColumnType("INTEGER"); + + b.Property("NormalizedName") + .HasColumnType("TEXT"); + + b.Property("OriginalName") + .HasColumnType("TEXT"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("SortName") + .HasColumnType("TEXT"); + + b.Property("SortNameLocked") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("LibraryId"); + + b.HasIndex("Name", "NormalizedName", "LocalizedName", "LibraryId", "Format") + .IsUnique(); + + b.ToTable("Series"); + }); + + modelBuilder.Entity("API.Entities.ServerSetting", b => + { + b.Property("Key") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("Key"); + + b.ToTable("ServerSetting"); + }); + + modelBuilder.Entity("API.Entities.SiteTheme", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("FileName") + .HasColumnType("TEXT"); + + b.Property("IsDefault") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasColumnType("TEXT"); + + b.Property("Provider") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("SiteTheme"); + }); + + modelBuilder.Entity("API.Entities.Tag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ExternalTag") + .HasColumnType("INTEGER"); + + b.Property("NormalizedTitle") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedTitle", "ExternalTag") + .IsUnique(); + + b.ToTable("Tag"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CoverImage") + .HasColumnType("TEXT"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Number") + .HasColumnType("INTEGER"); + + b.Property("Pages") + .HasColumnType("INTEGER"); + + b.Property("SeriesId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("SeriesId"); + + b.ToTable("Volume"); + }); + + modelBuilder.Entity("AppUserLibrary", b => + { + b.Property("AppUsersId") + .HasColumnType("INTEGER"); + + b.Property("LibrariesId") + .HasColumnType("INTEGER"); + + b.HasKey("AppUsersId", "LibrariesId"); + + b.HasIndex("LibrariesId"); + + b.ToTable("AppUserLibrary"); + }); + + modelBuilder.Entity("ChapterGenre", b => + { + b.Property("ChaptersId") + .HasColumnType("INTEGER"); + + b.Property("GenresId") + .HasColumnType("INTEGER"); + + b.HasKey("ChaptersId", "GenresId"); + + b.HasIndex("GenresId"); + + b.ToTable("ChapterGenre"); + }); + + modelBuilder.Entity("ChapterPerson", b => + { + b.Property("ChapterMetadatasId") + .HasColumnType("INTEGER"); + + b.Property("PeopleId") + .HasColumnType("INTEGER"); + + b.HasKey("ChapterMetadatasId", "PeopleId"); + + b.HasIndex("PeopleId"); + + b.ToTable("ChapterPerson"); + }); + + modelBuilder.Entity("ChapterTag", b => + { + b.Property("ChaptersId") + .HasColumnType("INTEGER"); + + b.Property("TagsId") + .HasColumnType("INTEGER"); + + b.HasKey("ChaptersId", "TagsId"); + + b.HasIndex("TagsId"); + + b.ToTable("ChapterTag"); + }); + + modelBuilder.Entity("CollectionTagSeriesMetadata", b => + { + b.Property("CollectionTagsId") + .HasColumnType("INTEGER"); + + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.HasKey("CollectionTagsId", "SeriesMetadatasId"); + + b.HasIndex("SeriesMetadatasId"); + + b.ToTable("CollectionTagSeriesMetadata"); + }); + + modelBuilder.Entity("GenreSeriesMetadata", b => + { + b.Property("GenresId") + .HasColumnType("INTEGER"); + + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.HasKey("GenresId", "SeriesMetadatasId"); + + b.HasIndex("SeriesMetadatasId"); + + b.ToTable("GenreSeriesMetadata"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("ProviderKey") + .HasColumnType("TEXT"); + + b.Property("ProviderDisplayName") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("PersonSeriesMetadata", b => + { + b.Property("PeopleId") + .HasColumnType("INTEGER"); + + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.HasKey("PeopleId", "SeriesMetadatasId"); + + b.HasIndex("SeriesMetadatasId"); + + b.ToTable("PersonSeriesMetadata"); + }); + + modelBuilder.Entity("SeriesMetadataTag", b => + { + b.Property("SeriesMetadatasId") + .HasColumnType("INTEGER"); + + b.Property("TagsId") + .HasColumnType("INTEGER"); + + b.HasKey("SeriesMetadatasId", "TagsId"); + + b.HasIndex("TagsId"); + + b.ToTable("SeriesMetadataTag"); + }); + + modelBuilder.Entity("API.Entities.AppUserBookmark", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Bookmarks") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserPreferences", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithOne("UserPreferences") + .HasForeignKey("API.Entities.AppUserPreferences", "AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.SiteTheme", "Theme") + .WithMany() + .HasForeignKey("ThemeId"); + + b.Navigation("AppUser"); + + b.Navigation("Theme"); + }); + + modelBuilder.Entity("API.Entities.AppUserProgress", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Progresses") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Series", null) + .WithMany("Progress") + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserRating", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("Ratings") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Series", null) + .WithMany("Ratings") + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.AppUserRole", b => + { + b.HasOne("API.Entities.AppRole", "Role") + .WithMany("UserRoles") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.AppUser", "User") + .WithMany("UserRoles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.HasOne("API.Entities.Volume", "Volume") + .WithMany("Chapters") + .HasForeignKey("VolumeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Volume"); + }); + + modelBuilder.Entity("API.Entities.FolderPath", b => + { + b.HasOne("API.Entities.Library", "Library") + .WithMany("Folders") + .HasForeignKey("LibraryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Library"); + }); + + modelBuilder.Entity("API.Entities.MangaFile", b => + { + b.HasOne("API.Entities.Chapter", "Chapter") + .WithMany("Files") + .HasForeignKey("ChapterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Chapter"); + }); + + modelBuilder.Entity("API.Entities.Metadata.SeriesMetadata", b => + { + b.HasOne("API.Entities.Series", "Series") + .WithOne("Metadata") + .HasForeignKey("API.Entities.Metadata.SeriesMetadata", "SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.HasOne("API.Entities.AppUser", "AppUser") + .WithMany("ReadingLists") + .HasForeignKey("AppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AppUser"); + }); + + modelBuilder.Entity("API.Entities.ReadingListItem", b => + { + b.HasOne("API.Entities.Chapter", "Chapter") + .WithMany() + .HasForeignKey("ChapterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.ReadingList", "ReadingList") + .WithMany("Items") + .HasForeignKey("ReadingListId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Series", "Series") + .WithMany() + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Volume", "Volume") + .WithMany() + .HasForeignKey("VolumeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Chapter"); + + b.Navigation("ReadingList"); + + b.Navigation("Series"); + + b.Navigation("Volume"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.HasOne("API.Entities.Library", "Library") + .WithMany("Series") + .HasForeignKey("LibraryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Library"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.HasOne("API.Entities.Series", "Series") + .WithMany("Volumes") + .HasForeignKey("SeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("AppUserLibrary", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("AppUsersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Library", null) + .WithMany() + .HasForeignKey("LibrariesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ChapterGenre", b => + { + b.HasOne("API.Entities.Chapter", null) + .WithMany() + .HasForeignKey("ChaptersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Genre", null) + .WithMany() + .HasForeignKey("GenresId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ChapterPerson", b => + { + b.HasOne("API.Entities.Chapter", null) + .WithMany() + .HasForeignKey("ChapterMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Person", null) + .WithMany() + .HasForeignKey("PeopleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ChapterTag", b => + { + b.HasOne("API.Entities.Chapter", null) + .WithMany() + .HasForeignKey("ChaptersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Tag", null) + .WithMany() + .HasForeignKey("TagsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("CollectionTagSeriesMetadata", b => + { + b.HasOne("API.Entities.CollectionTag", null) + .WithMany() + .HasForeignKey("CollectionTagsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Metadata.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("GenreSeriesMetadata", b => + { + b.HasOne("API.Entities.Genre", null) + .WithMany() + .HasForeignKey("GenresId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Metadata.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("API.Entities.AppRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("API.Entities.AppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("PersonSeriesMetadata", b => + { + b.HasOne("API.Entities.Person", null) + .WithMany() + .HasForeignKey("PeopleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Metadata.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("SeriesMetadataTag", b => + { + b.HasOne("API.Entities.Metadata.SeriesMetadata", null) + .WithMany() + .HasForeignKey("SeriesMetadatasId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("API.Entities.Tag", null) + .WithMany() + .HasForeignKey("TagsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("API.Entities.AppRole", b => + { + b.Navigation("UserRoles"); + }); + + modelBuilder.Entity("API.Entities.AppUser", b => + { + b.Navigation("Bookmarks"); + + b.Navigation("Progresses"); + + b.Navigation("Ratings"); + + b.Navigation("ReadingLists"); + + b.Navigation("UserPreferences"); + + b.Navigation("UserRoles"); + }); + + modelBuilder.Entity("API.Entities.Chapter", b => + { + b.Navigation("Files"); + }); + + modelBuilder.Entity("API.Entities.Library", b => + { + b.Navigation("Folders"); + + b.Navigation("Series"); + }); + + modelBuilder.Entity("API.Entities.ReadingList", b => + { + b.Navigation("Items"); + }); + + modelBuilder.Entity("API.Entities.Series", b => + { + b.Navigation("Metadata"); + + b.Navigation("Progress"); + + b.Navigation("Ratings"); + + b.Navigation("Volumes"); + }); + + modelBuilder.Entity("API.Entities.Volume", b => + { + b.Navigation("Chapters"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/API/Data/Migrations/20220307153053_ScreenHints.cs b/API/Data/Migrations/20220307153053_ScreenHints.cs new file mode 100644 index 000000000..6c7b67ade --- /dev/null +++ b/API/Data/Migrations/20220307153053_ScreenHints.cs @@ -0,0 +1,26 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace API.Data.Migrations +{ + public partial class ScreenHints : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "ShowScreenHints", + table: "AppUserPreferences", + type: "INTEGER", + nullable: false, + defaultValue: true); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "ShowScreenHints", + table: "AppUserPreferences"); + } + } +} diff --git a/API/Data/Migrations/DataContextModelSnapshot.cs b/API/Data/Migrations/DataContextModelSnapshot.cs index c0aefbcd2..d46e91af6 100644 --- a/API/Data/Migrations/DataContextModelSnapshot.cs +++ b/API/Data/Migrations/DataContextModelSnapshot.cs @@ -15,7 +15,7 @@ namespace API.Data.Migrations protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 - modelBuilder.HasAnnotation("ProductVersion", "6.0.0"); + modelBuilder.HasAnnotation("ProductVersion", "6.0.2"); modelBuilder.Entity("API.Entities.AppRole", b => { @@ -165,6 +165,9 @@ namespace API.Data.Migrations b.Property("AutoCloseMenu") .HasColumnType("INTEGER"); + b.Property("BackgroundColor") + .HasColumnType("TEXT"); + b.Property("BookReaderDarkMode") .HasColumnType("INTEGER"); @@ -186,6 +189,9 @@ namespace API.Data.Migrations b.Property("BookReaderTapToPaginate") .HasColumnType("INTEGER"); + b.Property("LayoutMode") + .HasColumnType("INTEGER"); + b.Property("PageSplitOption") .HasColumnType("INTEGER"); @@ -198,7 +204,10 @@ namespace API.Data.Migrations b.Property("ScalingOption") .HasColumnType("INTEGER"); - b.Property("SiteDarkMode") + b.Property("ShowScreenHints") + .HasColumnType("INTEGER"); + + b.Property("ThemeId") .HasColumnType("INTEGER"); b.HasKey("Id"); @@ -206,6 +215,8 @@ namespace API.Data.Migrations b.HasIndex("AppUserId") .IsUnique(); + b.HasIndex("ThemeId"); + b.ToTable("AppUserPreferences"); }); @@ -500,15 +511,51 @@ namespace API.Data.Migrations b.Property("AgeRating") .HasColumnType("INTEGER"); + b.Property("AgeRatingLocked") + .HasColumnType("INTEGER"); + + b.Property("CharacterLocked") + .HasColumnType("INTEGER"); + + b.Property("ColoristLocked") + .HasColumnType("INTEGER"); + b.Property("Count") .HasColumnType("INTEGER"); + b.Property("CoverArtistLocked") + .HasColumnType("INTEGER"); + + b.Property("EditorLocked") + .HasColumnType("INTEGER"); + + b.Property("GenresLocked") + .HasColumnType("INTEGER"); + + b.Property("InkerLocked") + .HasColumnType("INTEGER"); + b.Property("Language") .HasColumnType("TEXT"); + b.Property("LanguageLocked") + .HasColumnType("INTEGER"); + + b.Property("LettererLocked") + .HasColumnType("INTEGER"); + + b.Property("PencillerLocked") + .HasColumnType("INTEGER"); + b.Property("PublicationStatus") .HasColumnType("INTEGER"); + b.Property("PublicationStatusLocked") + .HasColumnType("INTEGER"); + + b.Property("PublisherLocked") + .HasColumnType("INTEGER"); + b.Property("ReleaseYear") .HasColumnType("INTEGER"); @@ -522,6 +569,18 @@ namespace API.Data.Migrations b.Property("Summary") .HasColumnType("TEXT"); + b.Property("SummaryLocked") + .HasColumnType("INTEGER"); + + b.Property("TagsLocked") + .HasColumnType("INTEGER"); + + b.Property("TranslatorLocked") + .HasColumnType("INTEGER"); + + b.Property("WriterLocked") + .HasColumnType("INTEGER"); + b.HasKey("Id"); b.HasIndex("SeriesId") @@ -645,9 +704,15 @@ namespace API.Data.Migrations b.Property("LocalizedName") .HasColumnType("TEXT"); + b.Property("LocalizedNameLocked") + .HasColumnType("INTEGER"); + b.Property("Name") .HasColumnType("TEXT"); + b.Property("NameLocked") + .HasColumnType("INTEGER"); + b.Property("NormalizedName") .HasColumnType("TEXT"); @@ -660,6 +725,9 @@ namespace API.Data.Migrations b.Property("SortName") .HasColumnType("TEXT"); + b.Property("SortNameLocked") + .HasColumnType("INTEGER"); + b.HasKey("Id"); b.HasIndex("LibraryId"); @@ -687,6 +755,38 @@ namespace API.Data.Migrations b.ToTable("ServerSetting"); }); + modelBuilder.Entity("API.Entities.SiteTheme", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Created") + .HasColumnType("TEXT"); + + b.Property("FileName") + .HasColumnType("TEXT"); + + b.Property("IsDefault") + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasColumnType("TEXT"); + + b.Property("Provider") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("SiteTheme"); + }); + modelBuilder.Entity("API.Entities.Tag", b => { b.Property("Id") @@ -967,7 +1067,13 @@ namespace API.Data.Migrations .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + b.HasOne("API.Entities.SiteTheme", "Theme") + .WithMany() + .HasForeignKey("ThemeId"); + b.Navigation("AppUser"); + + b.Navigation("Theme"); }); modelBuilder.Entity("API.Entities.AppUserProgress", b => diff --git a/API/Data/Repositories/AppUserProgressRepository.cs b/API/Data/Repositories/AppUserProgressRepository.cs index d9799aa22..d2acb3573 100644 --- a/API/Data/Repositories/AppUserProgressRepository.cs +++ b/API/Data/Repositories/AppUserProgressRepository.cs @@ -1,4 +1,5 @@ -using System.Linq; +using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using API.Entities; using API.Entities.Enums; @@ -13,6 +14,7 @@ public interface IAppUserProgressRepository Task UserHasProgress(LibraryType libraryType, int userId); Task GetUserProgressAsync(int chapterId, int userId); Task HasAnyProgressOnSeriesAsync(int seriesId, int userId); + Task> GetUserProgressForSeriesAsync(int seriesId, int userId); } public class AppUserProgressRepository : IAppUserProgressRepository @@ -83,6 +85,19 @@ public class AppUserProgressRepository : IAppUserProgressRepository .AnyAsync(aup => aup.PagesRead > 0 && aup.AppUserId == userId && aup.SeriesId == seriesId); } + /// + /// This will return any user progress. This filters out progress rows that have no pages read. + /// + /// + /// + /// + public async Task> GetUserProgressForSeriesAsync(int seriesId, int userId) + { + return await _context.AppUserProgresses + .Where(p => p.SeriesId == seriesId && p.AppUserId == userId && p.PagesRead > 0) + .ToListAsync(); + } + public async Task GetUserProgressAsync(int chapterId, int userId) { return await _context.AppUserProgresses diff --git a/API/Data/Repositories/ChapterRepository.cs b/API/Data/Repositories/ChapterRepository.cs index f89304f74..ab3684fa0 100644 --- a/API/Data/Repositories/ChapterRepository.cs +++ b/API/Data/Repositories/ChapterRepository.cs @@ -2,6 +2,7 @@ using System.Linq; using System.Threading.Tasks; using API.DTOs; +using API.DTOs.Metadata; using API.DTOs.Reader; using API.Entities; using AutoMapper; @@ -18,6 +19,7 @@ public interface IChapterRepository Task GetChapterTotalPagesAsync(int chapterId); Task GetChapterAsync(int chapterId); Task GetChapterDtoAsync(int chapterId); + Task GetChapterMetadataDtoAsync(int chapterId); Task> GetFilesForChapterAsync(int chapterId); Task> GetChaptersAsync(int volumeId); Task> GetFilesForChaptersAsync(IReadOnlyList chapterIds); @@ -46,6 +48,7 @@ public class ChapterRepository : IChapterRepository return await _context.Chapter .Where(c => chapterIds.Contains(c.Id)) .Include(c => c.Volume) + .AsSplitQuery() .ToListAsync(); } @@ -78,7 +81,8 @@ public class ChapterRepository : IChapterRepository data.TitleName, SeriesFormat = series.Format, SeriesName = series.Name, - series.LibraryId + series.LibraryId, + LibraryType = series.Library.Type }) .Select(data => new ChapterInfoDto() { @@ -86,12 +90,13 @@ public class ChapterRepository : IChapterRepository VolumeNumber = data.VolumeNumber + string.Empty, VolumeId = data.VolumeId, IsSpecial = data.IsSpecial, - SeriesId =data.SeriesId, + SeriesId = data.SeriesId, SeriesFormat = data.SeriesFormat, SeriesName = data.SeriesName, LibraryId = data.LibraryId, Pages = data.Pages, - ChapterTitle = data.TitleName + ChapterTitle = data.TitleName, + LibraryType = data.LibraryType }) .AsNoTracking() .AsSplitQuery() @@ -113,6 +118,19 @@ public class ChapterRepository : IChapterRepository .Include(c => c.Files) .ProjectTo(_mapper.ConfigurationProvider) .AsNoTracking() + .AsSplitQuery() + .SingleOrDefaultAsync(c => c.Id == chapterId); + + return chapter; + } + + public async Task GetChapterMetadataDtoAsync(int chapterId) + { + var chapter = await _context.Chapter + .Include(c => c.Files) + .ProjectTo(_mapper.ConfigurationProvider) + .AsNoTracking() + .AsSplitQuery() .SingleOrDefaultAsync(c => c.Id == chapterId); return chapter; @@ -140,6 +158,7 @@ public class ChapterRepository : IChapterRepository { return await _context.Chapter .Include(c => c.Files) + .AsSplitQuery() .SingleOrDefaultAsync(c => c.Id == chapterId); } diff --git a/API/Data/Repositories/LibraryRepository.cs b/API/Data/Repositories/LibraryRepository.cs index 4a3681de3..d78c5a95d 100644 --- a/API/Data/Repositories/LibraryRepository.cs +++ b/API/Data/Repositories/LibraryRepository.cs @@ -37,6 +37,7 @@ public interface ILibraryRepository Task> GetLibrariesForUserIdAsync(int userId); Task GetLibraryTypeAsync(int libraryId); Task> GetLibraryForIdsAsync(IList libraryIds); + Task GetTotalFiles(); } public class LibraryRepository : ILibraryRepository @@ -88,6 +89,7 @@ public class LibraryRepository : ILibraryRepository { var library = await GetLibraryForIdAsync(libraryId, LibraryIncludes.Folders | LibraryIncludes.Series); _context.Library.Remove(library); + return await _context.SaveChangesAsync() > 0; } @@ -116,6 +118,11 @@ public class LibraryRepository : ILibraryRepository .ToListAsync(); } + public async Task GetTotalFiles() + { + return await _context.MangaFile.CountAsync(); + } + public async Task> GetLibraryDtosAsync() { return await _context.Library diff --git a/API/Data/Repositories/ReadingListRepository.cs b/API/Data/Repositories/ReadingListRepository.cs index 329ec47a8..59c6ac5c2 100644 --- a/API/Data/Repositories/ReadingListRepository.cs +++ b/API/Data/Repositories/ReadingListRepository.cs @@ -19,9 +19,13 @@ public interface IReadingListRepository Task> AddReadingProgressModifiers(int userId, IList items); Task GetReadingListDtoByTitleAsync(string title); Task> GetReadingListItemsByIdAsync(int readingListId); + + Task> GetReadingListDtosForSeriesAndUserAsync(int userId, int seriesId, + bool includePromoted); void Remove(ReadingListItem item); void BulkRemove(IEnumerable items); void Update(ReadingList list); + Task Count(); } public class ReadingListRepository : IReadingListRepository @@ -40,6 +44,11 @@ public class ReadingListRepository : IReadingListRepository _context.Entry(list).State = EntityState.Modified; } + public async Task Count() + { + return await _context.ReadingList.CountAsync(); + } + public void Remove(ReadingListItem item) { _context.ReadingListItem.Remove(item); @@ -62,6 +71,18 @@ public class ReadingListRepository : IReadingListRepository return await PagedList.CreateAsync(query, userParams.PageNumber, userParams.PageSize); } + public async Task> GetReadingListDtosForSeriesAndUserAsync(int userId, int seriesId, bool includePromoted) + { + var query = _context.ReadingList + .Where(l => l.AppUserId == userId || (includePromoted && l.Promoted )) + .Where(l => l.Items.Any(i => i.SeriesId == seriesId)) + .OrderBy(l => l.LastModified) + .ProjectTo(_mapper.ConfigurationProvider) + .AsNoTracking(); + + return await query.ToListAsync(); + } + public async Task GetReadingListByIdAsync(int readingListId) { return await _context.ReadingList diff --git a/API/Data/Repositories/SeriesRepository.cs b/API/Data/Repositories/SeriesRepository.cs index 0c8caa2e1..ef97dfc87 100644 --- a/API/Data/Repositories/SeriesRepository.cs +++ b/API/Data/Repositories/SeriesRepository.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; +using System.Text.RegularExpressions; using System.Threading.Tasks; using API.Data.Scanner; using API.DTOs; @@ -79,8 +80,8 @@ public interface ISeriesRepository /// Task AddSeriesModifiers(int userId, List series); Task GetSeriesCoverImageAsync(int seriesId); - Task> GetOnDeck(int userId, int libraryId, UserParams userParams, FilterDto filter); - Task> GetRecentlyAdded(int libraryId, int userId, UserParams userParams, FilterDto filter); // NOTE: Probably put this in LibraryRepo + Task> GetOnDeck(int userId, int libraryId, UserParams userParams, FilterDto filter, bool cutoffOnDate = true); + Task> GetRecentlyAdded(int libraryId, int userId, UserParams userParams, FilterDto filter); Task GetSeriesMetadata(int seriesId); Task> GetSeriesDtoForCollectionAsync(int collectionId, int userId, UserParams userParams); Task> GetFilesForSeries(int seriesId); @@ -275,6 +276,7 @@ public class SeriesRepository : ISeriesRepository { var result = new SearchResultGroupDto(); + var searchQueryNormalized = Parser.Parser.Normalize(searchQuery); var seriesIds = _context.Series .Where(s => libraryIds.Contains(s.LibraryId)) @@ -283,17 +285,23 @@ public class SeriesRepository : ISeriesRepository result.Libraries = await _context.Library .Where(l => libraryIds.Contains(l.Id)) - .Where(s => EF.Functions.Like(s.Name, $"%{searchQuery}%")) + .Where(l => EF.Functions.Like(l.Name, $"%{searchQuery}%")) .OrderBy(l => l.Name) .AsSplitQuery() .ProjectTo(_mapper.ConfigurationProvider) .ToListAsync(); + var justYear = Regex.Match(searchQuery, @"\d{4}").Value; + var hasYearInQuery = !string.IsNullOrEmpty(justYear); + var yearComparison = hasYearInQuery ? int.Parse(justYear) : 0; + result.Series = await _context.Series .Where(s => libraryIds.Contains(s.LibraryId)) .Where(s => EF.Functions.Like(s.Name, $"%{searchQuery}%") || EF.Functions.Like(s.OriginalName, $"%{searchQuery}%") - || EF.Functions.Like(s.LocalizedName, $"%{searchQuery}%")) + || EF.Functions.Like(s.LocalizedName, $"%{searchQuery}%") + || EF.Functions.Like(s.NormalizedName, $"%{searchQueryNormalized}%") + || (hasYearInQuery && s.Metadata.ReleaseYear == yearComparison)) .Include(s => s.Library) .OrderBy(s => s.SortName) .AsNoTracking() @@ -301,6 +309,7 @@ public class SeriesRepository : ISeriesRepository .ProjectTo(_mapper.ConfigurationProvider) .ToListAsync(); + result.ReadingLists = await _context.ReadingList .Where(rl => rl.AppUserId == userId || rl.Promoted) .Where(rl => EF.Functions.Like(rl.Title, $"%{searchQuery}%")) @@ -310,7 +319,7 @@ public class SeriesRepository : ISeriesRepository result.Collections = await _context.CollectionTag .Where(s => EF.Functions.Like(s.Title, $"%{searchQuery}%") - || EF.Functions.Like(s.NormalizedTitle, $"%{searchQuery}%")) + || EF.Functions.Like(s.NormalizedTitle, $"%{searchQueryNormalized}%")) .Where(s => s.Promoted || isAdmin) .OrderBy(s => s.Title) .AsNoTracking() @@ -466,9 +475,16 @@ public class SeriesRepository : ISeriesRepository { s.PagesRead = userProgress.Where(p => p.SeriesId == s.Id).Sum(p => p.PagesRead); var rating = userRatings.SingleOrDefault(r => r.SeriesId == s.Id); - if (rating == null) continue; - s.UserRating = rating.Rating; - s.UserReview = rating.Review; + if (rating != null) + { + s.UserRating = rating.Rating; + s.UserReview = rating.Review; + } + + if (userProgress.Count > 0) + { + s.LatestReadDate = userProgress.Max(p => p.LastModified); + } } } @@ -507,7 +523,7 @@ public class SeriesRepository : ISeriesRepository private IList ExtractFilters(int libraryId, int userId, FilterDto filter, ref List userLibraries, out List allPeopleIds, out bool hasPeopleFilter, out bool hasGenresFilter, out bool hasCollectionTagFilter, out bool hasRatingFilter, out bool hasProgressFilter, out IList seriesIds, out bool hasAgeRating, out bool hasTagsFilter, - out bool hasLanguageFilter, out bool hasPublicationFilter) + out bool hasLanguageFilter, out bool hasPublicationFilter, out bool hasSeriesNameFilter) { var formats = filter.GetSqlFilter(); @@ -580,6 +596,8 @@ public class SeriesRepository : ISeriesRepository .ToList(); } + hasSeriesNameFilter = !string.IsNullOrEmpty(filter.SeriesNameQuery); + return formats; } @@ -592,11 +610,9 @@ public class SeriesRepository : ISeriesRepository /// Pagination information /// Optional (default null) filter on query /// - public async Task> GetOnDeck(int userId, int libraryId, UserParams userParams, FilterDto filter) + public async Task> GetOnDeck(int userId, int libraryId, UserParams userParams, FilterDto filter, bool cutoffOnDate = true) { - //var allSeriesWithProgress = await _context.AppUserProgresses.Select(p => p.SeriesId).ToListAsync(); - //var allChapters = await GetChapterIdsForSeriesAsync(allSeriesWithProgress); - + var cutoffProgressPoint = DateTime.Now - TimeSpan.FromDays(30); var query = (await CreateFilteredSearchQueryable(userId, libraryId, filter)) .Join(_context.AppUserProgresses, s => s.Id, progress => progress.SeriesId, (s, progress) => new @@ -605,12 +621,18 @@ public class SeriesRepository : ISeriesRepository PagesRead = _context.AppUserProgresses.Where(s1 => s1.SeriesId == s.Id && s1.AppUserId == userId) .Sum(s1 => s1.PagesRead), progress.AppUserId, - LastReadingProgress = _context.AppUserProgresses.Where(p => p.Id == progress.Id && p.AppUserId == userId) + LastReadingProgress = _context.AppUserProgresses + .Where(p => p.Id == progress.Id && p.AppUserId == userId) .Max(p => p.LastModified), - // This is only taking into account chapters that have progress on them, not all chapters in said series - LastChapterCreated = _context.Chapter.Where(c => progress.ChapterId == c.Id).Max(c => c.Created) + // BUG: This is only taking into account chapters that have progress on them, not all chapters in said series + LastChapterCreated = _context.Chapter.Where(c => progress.ChapterId == c.Id).Max(c => c.Created), //LastChapterCreated = _context.Chapter.Where(c => allChapters.Contains(c.Id)).Max(c => c.Created) }); + if (cutoffOnDate) + { + query = query.Where(d => d.LastReadingProgress >= cutoffProgressPoint); + } + // I think I need another Join statement. The problem is the chapters are still limited to progress @@ -635,7 +657,7 @@ public class SeriesRepository : ISeriesRepository var formats = ExtractFilters(libraryId, userId, filter, ref userLibraries, out var allPeopleIds, out var hasPeopleFilter, out var hasGenresFilter, out var hasCollectionTagFilter, out var hasRatingFilter, out var hasProgressFilter, - out var seriesIds, out var hasAgeRating, out var hasTagsFilter, out var hasLanguageFilter, out var hasPublicationFilter); + out var seriesIds, out var hasAgeRating, out var hasTagsFilter, out var hasLanguageFilter, out var hasPublicationFilter, out var hasSeriesNameFilter); var query = _context.Series .Where(s => userLibraries.Contains(s.LibraryId) @@ -649,8 +671,11 @@ public class SeriesRepository : ISeriesRepository && (!hasAgeRating || filter.AgeRating.Contains(s.Metadata.AgeRating)) && (!hasTagsFilter || s.Metadata.Tags.Any(t => filter.Tags.Contains(t.Id))) && (!hasLanguageFilter || filter.Languages.Contains(s.Metadata.Language)) - && (!hasPublicationFilter || filter.PublicationStatus.Contains(s.Metadata.PublicationStatus)) - ) + && (!hasPublicationFilter || filter.PublicationStatus.Contains(s.Metadata.PublicationStatus))) + .Where(s => !hasSeriesNameFilter || + EF.Functions.Like(s.Name, $"%{filter.SeriesNameQuery}%") + || EF.Functions.Like(s.OriginalName, $"%{filter.SeriesNameQuery}%") + || EF.Functions.Like(s.LocalizedName, $"%{filter.SeriesNameQuery}%")) .AsNoTracking(); // If no sort options, default to using SortName diff --git a/API/Data/Repositories/SiteThemeRepository.cs b/API/Data/Repositories/SiteThemeRepository.cs new file mode 100644 index 000000000..a95fcda23 --- /dev/null +++ b/API/Data/Repositories/SiteThemeRepository.cs @@ -0,0 +1,107 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using API.DTOs.Theme; +using API.Entities; +using AutoMapper; +using AutoMapper.QueryableExtensions; +using Microsoft.EntityFrameworkCore; + +namespace API.Data.Repositories; + +public interface ISiteThemeRepository +{ + void Add(SiteTheme theme); + void Remove(SiteTheme theme); + void Update(SiteTheme siteTheme); + Task> GetThemeDtos(); + Task GetThemeDto(int themeId); + Task GetThemeDtoByName(string themeName); + Task GetDefaultTheme(); + Task> GetThemes(); + + Task GetThemeById(int themeId); +} + +public class SiteThemeRepository : ISiteThemeRepository +{ + private readonly DataContext _context; + private readonly IMapper _mapper; + + public SiteThemeRepository(DataContext context, IMapper mapper) + { + _context = context; + _mapper = mapper; + } + + public void Add(SiteTheme theme) + { + _context.Add(theme); + } + + public void Remove(SiteTheme theme) + { + _context.Remove(theme); + } + + public void Update(SiteTheme siteTheme) + { + _context.Entry(siteTheme).State = EntityState.Modified; + } + + public async Task> GetThemeDtos() + { + return await _context.SiteTheme + .ProjectTo(_mapper.ConfigurationProvider) + .ToListAsync(); + } + + public async Task GetThemeDtoByName(string themeName) + { + return await _context.SiteTheme + .Where(t => t.Name.Equals(themeName)) + .ProjectTo(_mapper.ConfigurationProvider) + .SingleOrDefaultAsync(); + } + + /// + /// Returns default theme, if the default theme is not available, returns the dark theme + /// + /// + public async Task GetDefaultTheme() + { + var result = await _context.SiteTheme + .Where(t => t.IsDefault) + .SingleOrDefaultAsync(); + + if (result == null) + { + return await _context.SiteTheme + .Where(t => t.NormalizedName == "dark") + .SingleOrDefaultAsync(); + } + + return result; + } + + public async Task> GetThemes() + { + return await _context.SiteTheme + .ToListAsync(); + } + + public async Task GetThemeById(int themeId) + { + return await _context.SiteTheme + .Where(t => t.Id == themeId) + .SingleOrDefaultAsync(); + } + + public async Task GetThemeDto(int themeId) + { + return await _context.SiteTheme + .Where(t => t.Id == themeId) + .ProjectTo(_mapper.ConfigurationProvider) + .SingleOrDefaultAsync(); + } +} diff --git a/API/Data/Repositories/UserRepository.cs b/API/Data/Repositories/UserRepository.cs index b926abe9c..60c72a77c 100644 --- a/API/Data/Repositories/UserRepository.cs +++ b/API/Data/Repositories/UserRepository.cs @@ -55,6 +55,7 @@ public interface IUserRepository Task GetUserByEmailAsync(string email); Task> GetAllUsers(); + Task> GetAllPreferencesByThemeAsync(int themeId); } public class UserRepository : IUserRepository @@ -219,7 +220,8 @@ public class UserRepository : IUserRepository public async Task GetUserByEmailAsync(string email) { - return await _context.AppUser.SingleOrDefaultAsync(u => u.Email.ToLower().Equals(email.ToLower())); + var lowerEmail = email.ToLower(); + return await _context.AppUser.SingleOrDefaultAsync(u => u.Email.ToLower().Equals(lowerEmail)); } public async Task> GetAllUsers() @@ -227,6 +229,15 @@ public class UserRepository : IUserRepository return await _context.AppUser.ToListAsync(); } + public async Task> GetAllPreferencesByThemeAsync(int themeId) + { + return await _context.AppUserPreferences + .Include(p => p.Theme) + .Where(p => p.Theme.Id == themeId) + .AsSplitQuery() + .ToListAsync(); + } + public async Task> GetAdminUsersAsync() { return await _userManager.GetUsersInRoleAsync(PolicyConstants.AdminRole); @@ -244,7 +255,8 @@ public class UserRepository : IUserRepository public async Task GetUserRatingAsync(int seriesId, int userId) { - return await _context.AppUserRating.Where(r => r.SeriesId == seriesId && r.AppUserId == userId) + return await _context.AppUserRating + .Where(r => r.SeriesId == seriesId && r.AppUserId == userId) .SingleOrDefaultAsync(); } @@ -252,6 +264,8 @@ public class UserRepository : IUserRepository { return await _context.AppUserPreferences .Include(p => p.AppUser) + .Include(p => p.Theme) + .AsSplitQuery() .SingleOrDefaultAsync(p => p.AppUser.UserName == username); } diff --git a/API/Data/Seed.cs b/API/Data/Seed.cs index 3dd8ecc5f..ec0088aba 100644 --- a/API/Data/Seed.cs +++ b/API/Data/Seed.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Collections.Immutable; using System.IO; using System.Linq; using System.Reflection; @@ -6,6 +7,7 @@ using System.Threading.Tasks; using API.Constants; using API.Entities; using API.Entities.Enums; +using API.Entities.Enums.Theme; using API.Services; using Kavita.Common; using Kavita.Common.EnvironmentInfo; @@ -21,6 +23,34 @@ namespace API.Data /// public static IList DefaultSettings; + public static readonly IList DefaultThemes = new List + { + new() + { + Name = "Dark", + NormalizedName = Parser.Parser.Normalize("Dark"), + Provider = ThemeProvider.System, + FileName = "dark.scss", + IsDefault = true, + }, + new() + { + Name = "Light", + NormalizedName = Parser.Parser.Normalize("Light"), + Provider = ThemeProvider.System, + FileName = "light.scss", + IsDefault = false, + }, + new() + { + Name = "E-Ink", + NormalizedName = Parser.Parser.Normalize("E-Ink"), + Provider = ThemeProvider.System, + FileName = "e-ink.scss", + IsDefault = false, + }, + }; + public static async Task SeedRoles(RoleManager roleManager) { var roles = typeof(PolicyConstants) @@ -41,6 +71,22 @@ namespace API.Data } } + public static async Task SeedThemes(DataContext context) + { + await context.Database.EnsureCreatedAsync(); + + foreach (var theme in DefaultThemes) + { + var existing = context.SiteTheme.FirstOrDefault(s => s.Name.Equals(theme.Name)); + if (existing == null) + { + await context.SiteTheme.AddAsync(theme); + } + } + + await context.SaveChangesAsync(); + } + public static async Task SeedSettings(DataContext context, IDirectoryService directoryService) { await context.Database.EnsureCreatedAsync(); diff --git a/API/Data/UnitOfWork.cs b/API/Data/UnitOfWork.cs index 82046ca2a..fb3e28c07 100644 --- a/API/Data/UnitOfWork.cs +++ b/API/Data/UnitOfWork.cs @@ -21,6 +21,7 @@ public interface IUnitOfWork IPersonRepository PersonRepository { get; } IGenreRepository GenreRepository { get; } ITagRepository TagRepository { get; } + ISiteThemeRepository SiteThemeRepository { get; } bool Commit(); Task CommitAsync(); bool HasChanges(); @@ -56,6 +57,7 @@ public class UnitOfWork : IUnitOfWork public IPersonRepository PersonRepository => new PersonRepository(_context, _mapper); public IGenreRepository GenreRepository => new GenreRepository(_context, _mapper); public ITagRepository TagRepository => new TagRepository(_context, _mapper); + public ISiteThemeRepository SiteThemeRepository => new SiteThemeRepository(_context, _mapper); /// /// Commits changes to the DB. Completes the open transaction. diff --git a/API/Entities/AppUserPreferences.cs b/API/Entities/AppUserPreferences.cs index 01587431b..d35b82e39 100644 --- a/API/Entities/AppUserPreferences.cs +++ b/API/Entities/AppUserPreferences.cs @@ -25,12 +25,23 @@ namespace API.Entities /// /// public ReaderMode ReaderMode { get; set; } - /// /// Manga Reader Option: Allow the menu to close after 6 seconds without interaction /// public bool AutoCloseMenu { get; set; } = true; /// + /// Manga Reader Option: Show screen hints to the user on some actions, ie) pagination direction change + /// + public bool ShowScreenHints { get; set; } = true; + /// + /// Manga Reader Option: How many pages to display in the reader at once + /// + public LayoutMode LayoutMode { get; set; } = LayoutMode.Single; + /// + /// Manga Reader Option: Background color of the reader + /// + public string BackgroundColor { get; set; } = "#000000"; + /// /// Book Reader Option: Should the background color be dark /// public bool BookReaderDarkMode { get; set; } = true; @@ -58,11 +69,11 @@ namespace API.Entities /// Book Reader Option: What direction should the next/prev page buttons go /// public ReadingDirection BookReaderReadingDirection { get; set; } = ReadingDirection.LeftToRight; - /// - /// UI Site Global Setting: Whether the UI should render in Dark mode or not. + /// UI Site Global Setting: The UI theme the user should use. /// - public bool SiteDarkMode { get; set; } = true; + /// Should default to Dark + public SiteTheme Theme { get; set; } diff --git a/API/Entities/AppUserProgress.cs b/API/Entities/AppUserProgress.cs index b3e0a5dfd..1704628cb 100644 --- a/API/Entities/AppUserProgress.cs +++ b/API/Entities/AppUserProgress.cs @@ -35,6 +35,14 @@ namespace API.Entities /// on next load ///
    public string BookScrollId { get; set; } + /// + /// When this was first created + /// + public DateTime Created { get; set; } + /// + /// Last date this was updated + /// + public DateTime LastModified { get; set; } // Relationships /// @@ -45,14 +53,5 @@ namespace API.Entities /// User this progress belongs to /// public int AppUserId { get; set; } - - /// - /// When this was first created - /// - public DateTime Created { get; set; } - /// - /// Last date this was updated - /// - public DateTime LastModified { get; set; } } } diff --git a/API/Entities/Enums/LayoutMode.cs b/API/Entities/Enums/LayoutMode.cs new file mode 100644 index 000000000..37fc69293 --- /dev/null +++ b/API/Entities/Enums/LayoutMode.cs @@ -0,0 +1,13 @@ +using System.ComponentModel; + +namespace API.Entities.Enums; + +public enum LayoutMode +{ + [Description("Single")] + Single = 1, + [Description("Double")] + Double = 2, + [Description("Double (manga)")] + DoubleReversed = 3 +} diff --git a/API/Entities/Enums/ReaderMode.cs b/API/Entities/Enums/ReaderMode.cs index 01ff7878f..94776252b 100644 --- a/API/Entities/Enums/ReaderMode.cs +++ b/API/Entities/Enums/ReaderMode.cs @@ -5,13 +5,10 @@ namespace API.Entities.Enums public enum ReaderMode { [Description("Left and Right")] - // ReSharper disable once InconsistentNaming - MANGA_LR = 0, + LeftRight = 0, [Description("Up and Down")] - // ReSharper disable once InconsistentNaming - MANGA_UP = 1, + UpDown = 1, [Description("Webtoon")] - // ReSharper disable once InconsistentNaming - WEBTOON = 2 + Webtoon = 2 } } diff --git a/API/Entities/Enums/Theme/ThemeProvider.cs b/API/Entities/Enums/Theme/ThemeProvider.cs new file mode 100644 index 000000000..45af2d94b --- /dev/null +++ b/API/Entities/Enums/Theme/ThemeProvider.cs @@ -0,0 +1,17 @@ +using System.ComponentModel; + +namespace API.Entities.Enums.Theme; + +public enum ThemeProvider +{ + /// + /// Theme is provided by System + /// + [Description("System")] + System = 1, + /// + /// Theme is provided by the User (ie it's custom) + /// + [Description("User")] + User = 2 +} diff --git a/API/Entities/Metadata/ChapterMetadata.cs b/API/Entities/Metadata/ChapterMetadata.cs deleted file mode 100644 index ef4836c23..000000000 --- a/API/Entities/Metadata/ChapterMetadata.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System.Collections.Generic; - -namespace API.Entities.Metadata -{ - /// - /// Has a 1-to-1 relationship with a Chapter. Represents metadata about a chapter. - /// - public class ChapterMetadata - { - public int Id { get; set; } - - /// - /// Chapter title - /// - /// This should not be confused with Chapter.Title which is used for special filenames. - public string Title { get; set; } = string.Empty; - public string Year { get; set; } // Only time I can think this will be more than 1 year is for a volume which will be a spread - public string StoryArc { get; set; } // This might be a list - - /// - /// All people attached at a Chapter level. Usually Comics will have different people per issue. - /// - public ICollection People { get; set; } = new List(); - - - - - - // Relationships - public Chapter Chapter { get; set; } - public int ChapterId { get; set; } - - } -} diff --git a/API/Entities/Metadata/SeriesMetadata.cs b/API/Entities/Metadata/SeriesMetadata.cs index 81fcba090..0ec7038fa 100644 --- a/API/Entities/Metadata/SeriesMetadata.cs +++ b/API/Entities/Metadata/SeriesMetadata.cs @@ -40,6 +40,31 @@ namespace API.Entities.Metadata public int Count { get; set; } = 0; public PublicationStatus PublicationStatus { get; set; } + // Locks + public bool LanguageLocked { get; set; } + public bool SummaryLocked { get; set; } + /// + /// Locked by user so metadata updates from scan loop will not override AgeRating + /// + public bool AgeRatingLocked { get; set; } + /// + /// Locked by user so metadata updates from scan loop will not override PublicationStatus + /// + public bool PublicationStatusLocked { get; set; } + public bool GenresLocked { get; set; } + public bool TagsLocked { get; set; } + public bool WriterLocked { get; set; } + public bool CharacterLocked { get; set; } + public bool ColoristLocked { get; set; } + public bool EditorLocked { get; set; } + public bool InkerLocked { get; set; } + public bool LettererLocked { get; set; } + public bool PencillerLocked { get; set; } + public bool PublisherLocked { get; set; } + public bool TranslatorLocked { get; set; } + public bool CoverArtistLocked { get; set; } + + // Relationship public Series Series { get; set; } public int SeriesId { get; set; } @@ -48,6 +73,7 @@ namespace API.Entities.Metadata [ConcurrencyCheck] public uint RowVersion { get; private set; } + /// public void OnSavingChanges() { diff --git a/API/Entities/Series.cs b/API/Entities/Series.cs index 77a011d53..12e169c07 100644 --- a/API/Entities/Series.cs +++ b/API/Entities/Series.cs @@ -58,6 +58,10 @@ namespace API.Entities ///
    public MangaFormat Format { get; set; } = MangaFormat.Unknown; + public bool NameLocked { get; set; } + public bool SortNameLocked { get; set; } + public bool LocalizedNameLocked { get; set; } + public SeriesMetadata Metadata { get; set; } public ICollection Ratings { get; set; } = new List(); public ICollection Progress { get; set; } = new List(); diff --git a/API/Entities/SiteTheme.cs b/API/Entities/SiteTheme.cs new file mode 100644 index 000000000..87ebe95b1 --- /dev/null +++ b/API/Entities/SiteTheme.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using API.Entities.Enums.Theme; +using API.Entities.Interfaces; +using API.Services; + +namespace API.Entities; +/// +/// Represents a set of css overrides the user can upload to Kavita and will load into webui +/// +public class SiteTheme : IEntityDate +{ + public int Id { get; set; } + /// + /// Name of the Theme + /// + public string Name { get; set; } + /// + /// Normalized name for lookups + /// + public string NormalizedName { get; set; } + /// + /// File path to the content. Stored under . + /// Must be a .css file + /// + public string FileName { get; set; } + /// + /// Only one theme can have this. Will auto-set this as default for new user accounts + /// + public bool IsDefault { get; set; } + /// + /// Where did the theme come from + /// + public ThemeProvider Provider { get; set; } + public DateTime Created { get; set; } + public DateTime LastModified { get; set; } +} diff --git a/API/Entities/Volume.cs b/API/Entities/Volume.cs index f4f0076db..77cd41f82 100644 --- a/API/Entities/Volume.cs +++ b/API/Entities/Volume.cs @@ -9,9 +9,13 @@ namespace API.Entities { public int Id { get; set; } /// - /// A String representation of the volume number. Allows for floats + /// A String representation of the volume number. Allows for floats. /// + /// For Books with Series_index, this will map to the Series Index. public string Name { get; set; } + /// + /// The minimum number in the Name field in Int form + /// public int Number { get; set; } public IList Chapters { get; set; } public DateTime Created { get; set; } diff --git a/API/Extensions/ApplicationServiceExtensions.cs b/API/Extensions/ApplicationServiceExtensions.cs index 102a7e107..395ffe62b 100644 --- a/API/Extensions/ApplicationServiceExtensions.cs +++ b/API/Extensions/ApplicationServiceExtensions.cs @@ -3,6 +3,7 @@ using API.Data; using API.Helpers; using API.Services; using API.Services.Tasks; +using API.SignalR; using API.SignalR.Presence; using Kavita.Common; using Microsoft.AspNetCore.Hosting; @@ -39,6 +40,9 @@ namespace API.Extensions services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); services.AddScoped(); @@ -50,6 +54,7 @@ namespace API.Extensions services.AddScoped(); services.AddScoped(); + services.AddScoped(); services.AddSqLite(config, env); services.AddLogging(config); diff --git a/API/Extensions/EnumerableExtensions.cs b/API/Extensions/EnumerableExtensions.cs index c1dd412e2..30a75a9eb 100644 --- a/API/Extensions/EnumerableExtensions.cs +++ b/API/Extensions/EnumerableExtensions.cs @@ -19,12 +19,13 @@ namespace API.Extensions /// Sorted Enumerable public static IEnumerable OrderByNatural(this IEnumerable items, Func selector, StringComparer stringComparer = null) { - var maxDigits = items + var list = items.ToList(); + var maxDigits = list .SelectMany(i => Regex.Matches(selector(i)) .Select(digitChunk => (int?)digitChunk.Value.Length)) .Max() ?? 0; - return items.OrderBy(i => Regex.Replace(selector(i), match => match.Value.PadLeft(maxDigits, '0')), stringComparer ?? StringComparer.CurrentCulture); + return list.OrderBy(i => Regex.Replace(selector(i), match => match.Value.PadLeft(maxDigits, '0')), stringComparer ?? StringComparer.CurrentCulture); } } } diff --git a/API/Extensions/HttpExtensions.cs b/API/Extensions/HttpExtensions.cs index f0b3d5399..c468ef7ce 100644 --- a/API/Extensions/HttpExtensions.cs +++ b/API/Extensions/HttpExtensions.cs @@ -1,4 +1,5 @@ -using System.IO; +using System; +using System.IO; using System.Linq; using System.Security.Cryptography; using System.Text; @@ -41,12 +42,17 @@ namespace API.Extensions ///
    /// /// - public static void AddCacheHeader(this HttpResponse response, string filename) + /// Maximum amount of seconds to set for Cache-Control + public static void AddCacheHeader(this HttpResponse response, string filename, int maxAge = 10) { - if (filename == null || filename.Length <= 0) return; + if (filename is not {Length: > 0}) return; var hashContent = filename + File.GetLastWriteTimeUtc(filename); using var sha1 = SHA256.Create(); response.Headers.Add("ETag", string.Concat(sha1.ComputeHash(Encoding.UTF8.GetBytes(hashContent)).Select(x => x.ToString("X2")))); + if (maxAge != 10) + { + response.Headers.CacheControl = $"max-age={maxAge}"; + } } } diff --git a/API/Extensions/IdentityServiceExtensions.cs b/API/Extensions/IdentityServiceExtensions.cs index 16404949b..043e5c919 100644 --- a/API/Extensions/IdentityServiceExtensions.cs +++ b/API/Extensions/IdentityServiceExtensions.cs @@ -15,6 +15,12 @@ namespace API.Extensions { public static IServiceCollection AddIdentityServices(this IServiceCollection services, IConfiguration config) { + services.Configure(options => + { + options.User.AllowedUserNameCharacters = + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+/"; + }); + services.AddIdentityCore(opt => { opt.Password.RequireNonAlphanumeric = false; diff --git a/API/Helpers/AutoMapperProfiles.cs b/API/Helpers/AutoMapperProfiles.cs index 1c2426ae4..3765b7e47 100644 --- a/API/Helpers/AutoMapperProfiles.cs +++ b/API/Helpers/AutoMapperProfiles.cs @@ -7,6 +7,7 @@ using API.DTOs.Reader; using API.DTOs.ReadingLists; using API.DTOs.Search; using API.DTOs.Settings; +using API.DTOs.Theme; using API.Entities; using API.Entities.Enums; using API.Entities.Metadata; @@ -20,45 +21,16 @@ namespace API.Helpers public AutoMapperProfiles() { CreateMap(); - CreateMap(); - CreateMap(); - - CreateMap() - .ForMember(dest => dest.Writers, - opt => - opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.Writer))) - .ForMember(dest => dest.CoverArtist, - opt => - opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.CoverArtist))) - .ForMember(dest => dest.Colorist, - opt => - opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.Colorist))) - .ForMember(dest => dest.Inker, - opt => - opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.Inker))) - .ForMember(dest => dest.Letterer, - opt => - opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.Letterer))) - .ForMember(dest => dest.Penciller, - opt => - opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.Penciller))) - .ForMember(dest => dest.Publisher, - opt => - opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.Publisher))) - .ForMember(dest => dest.Editor, - opt => - opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.Editor))) - .ForMember(dest => dest.Translators, - opt => - opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.Translator))); - + CreateMap(); CreateMap(); CreateMap(); CreateMap(); CreateMap(); CreateMap(); + CreateMap(); + CreateMap(); CreateMap() .ForMember(dest => dest.Writers, @@ -92,37 +64,47 @@ namespace API.Helpers opt => opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.Editor))); - CreateMap() + CreateMap() .ForMember(dest => dest.Writers, opt => opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.Writer))) - .ForMember(dest => dest.CoverArtist, + .ForMember(dest => dest.CoverArtists, opt => opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.CoverArtist))) - .ForMember(dest => dest.Colorist, + .ForMember(dest => dest.Colorists, opt => opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.Colorist))) - .ForMember(dest => dest.Inker, + .ForMember(dest => dest.Inkers, opt => opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.Inker))) - .ForMember(dest => dest.Letterer, + .ForMember(dest => dest.Letterers, opt => opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.Letterer))) - .ForMember(dest => dest.Penciller, + .ForMember(dest => dest.Pencillers, opt => opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.Penciller))) - .ForMember(dest => dest.Publisher, + .ForMember(dest => dest.Publishers, opt => opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.Publisher))) - .ForMember(dest => dest.Editor, + .ForMember(dest => dest.Translators, + opt => + opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.Translator))) + .ForMember(dest => dest.Characters, + opt => + opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.Character))) + .ForMember(dest => dest.Editors, opt => opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.Editor))); + CreateMap(); + CreateMap(); + CreateMap() + .ForMember(dest => dest.Theme, + opt => + opt.MapFrom(src => src.Theme)); - CreateMap(); - CreateMap(); CreateMap(); @@ -146,6 +128,7 @@ namespace API.Helpers CreateMap(); + CreateMap, ServerSettingDto>() .ConvertUsing(); diff --git a/API/Helpers/Converters/ServerSettingConverter.cs b/API/Helpers/Converters/ServerSettingConverter.cs index 31ea46d4b..3678ef7e5 100644 --- a/API/Helpers/Converters/ServerSettingConverter.cs +++ b/API/Helpers/Converters/ServerSettingConverter.cs @@ -45,6 +45,9 @@ namespace API.Helpers.Converters case ServerSettingKey.EmailServiceUrl: destination.EmailServiceUrl = row.Value; break; + case ServerSettingKey.InstallVersion: + destination.InstallVersion = row.Value; + break; } } diff --git a/API/Parser/Parser.cs b/API/Parser/Parser.cs index 45a1e7757..cc237eae7 100644 --- a/API/Parser/Parser.cs +++ b/API/Parser/Parser.cs @@ -57,7 +57,7 @@ namespace API.Parser private static readonly Regex CoverImageRegex = new Regex(@"(?.*)( - )(?:v|vo|c)\d", + @"(?.*)( - )(?:v|vo|c|chapters)\d", MatchOptions, RegexTimeout), // Kedouin Makoto - Corpse Party Musume, Chapter 19 [Dametrans].zip new Regex( @@ -153,16 +153,7 @@ namespace API.Parser MatchOptions, RegexTimeout), // Historys Strongest Disciple Kenichi_v11_c90-98.zip, Killing Bites Vol. 0001 Ch. 0001 - Galactica Scanlations (gb) new Regex( - @"(?.*) (\b|_|-)(v|ch\.?|c)\d+", - MatchOptions, RegexTimeout), - //Ichinensei_ni_Nacchattara_v01_ch01_[Taruby]_v1.1.zip must be before [Suihei Kiki]_Kasumi_Otoko_no_Ko_[Taruby]_v1.1.zip - // due to duplicate version identifiers in file. - new Regex( - @"(?.*)(v|s)\d+(-\d+)?(_|\s)", - MatchOptions, RegexTimeout), - //[Suihei Kiki]_Kasumi_Otoko_no_Ko_[Taruby]_v1.1.zip - new Regex( - @"(?.*)(v|s)\d+(-\d+)?", + @"(?.*) (\b|_|-)(v|ch\.?|c|s)\d+", MatchOptions, RegexTimeout), // Hinowa ga CRUSH! 018 (2019) (Digital) (LuCaZ).cbz new Regex( @@ -170,7 +161,7 @@ namespace API.Parser MatchOptions, RegexTimeout), // Goblin Slayer - Brand New Day 006.5 (2019) (Digital) (danke-Empire) new Regex( - @"(?.*) (?\d+(?:.\d+|-\d+)?) \(\d{4}\)", + @"(?.*) (-)?(?\d+(?:.\d+|-\d+)?) \(\d{4}\)", MatchOptions, RegexTimeout), // Noblesse - Episode 429 (74 Pages).7z new Regex( @@ -184,6 +175,23 @@ namespace API.Parser new Regex( @"(?.*)(\s|_)\((c\s|ch\s|chapter\s)", MatchOptions, RegexTimeout), + // Fullmetal Alchemist chapters 101-108 + new Regex( + @"(?.+?)(\s|_|\-)+?chapters(\s|_|\-)+?\d+(\s|_|\-)+?", + MatchOptions, RegexTimeout), + // It's Witching Time! 001 (Digital) (Anonymous1234) + new Regex( + @"(?.+?)(\s|_|\-)+?\d+(\s|_|\-)\(", + MatchOptions, RegexTimeout), + //Ichinensei_ni_Nacchattara_v01_ch01_[Taruby]_v1.1.zip must be before [Suihei Kiki]_Kasumi_Otoko_no_Ko_[Taruby]_v1.1.zip + // due to duplicate version identifiers in file. + new Regex( + @"(?.*)(v|s)\d+(-\d+)?(_|\s)", + MatchOptions, RegexTimeout), + //[Suihei Kiki]_Kasumi_Otoko_no_Ko_[Taruby]_v1.1.zip + new Regex( + @"(?.*)(v|s)\d+(-\d+)?", + MatchOptions, RegexTimeout), // Black Bullet (This is very loose, keep towards bottom) new Regex( @"(?.*)(_)(v|vo|c|volume)( |_)\d+", @@ -958,8 +966,26 @@ namespace API.Parser public static string Normalize(string name) { - var normalized = NormalizeRegex.Replace(name, string.Empty).ToLower(); - return string.IsNullOrEmpty(normalized) ? name : normalized; + return NormalizeRegex.Replace(name, string.Empty).ToLower(); + } + + /// + /// Responsible for preparing special title for rendering to the UI. Replaces _ with ' ' and strips out SP\d+ + /// + /// + /// + public static string CleanSpecialTitle(string name) + { + // TODO: Optimize this code & Test + if (string.IsNullOrEmpty(name)) return name; + var cleaned = new Regex(@"SP\d+").Replace(name.Replace('_', ' '), string.Empty).Trim(); + var lastIndex = cleaned.LastIndexOf('.'); + if (lastIndex > 0) + { + cleaned = cleaned.Substring(0, cleaned.LastIndexOf('.')).Trim(); + } + + return string.IsNullOrEmpty(cleaned) ? name : cleaned; } @@ -976,18 +1002,18 @@ namespace API.Parser public static bool HasBlacklistedFolderInPath(string path) { - return path.Contains("__MACOSX") || path.StartsWith("@Recently-Snapshot") || path.StartsWith("._"); + return path.Contains("__MACOSX") || path.StartsWith("@Recently-Snapshot") || path.StartsWith("@recycle") || path.StartsWith("._"); } public static bool IsEpub(string filePath) { - return Path.GetExtension(filePath).ToLower() == ".epub"; + return Path.GetExtension(filePath).Equals(".epub", StringComparison.InvariantCultureIgnoreCase); } public static bool IsPdf(string filePath) { - return Path.GetExtension(filePath).ToLower() == ".pdf"; + return Path.GetExtension(filePath).Equals(".pdf", StringComparison.InvariantCultureIgnoreCase); } /// @@ -998,8 +1024,7 @@ namespace API.Parser /// public static string CleanAuthor(string author) { - if (string.IsNullOrEmpty(author)) return string.Empty; - return author.Trim(); + return string.IsNullOrEmpty(author) ? string.Empty : author.Trim(); } /// diff --git a/API/Parser/ParserInfo.cs b/API/Parser/ParserInfo.cs index cb55bd18e..07679ea25 100644 --- a/API/Parser/ParserInfo.cs +++ b/API/Parser/ParserInfo.cs @@ -80,6 +80,7 @@ namespace API.Parser /// /// Merges non empty/null properties from info2 into this entity. /// + /// This does not merge ComicInfo as they should always be the same /// public void Merge(ParserInfo info2) { diff --git a/API/Program.cs b/API/Program.cs index 3a0d9ab25..3bd895353 100644 --- a/API/Program.cs +++ b/API/Program.cs @@ -36,7 +36,6 @@ namespace API var directoryService = new DirectoryService(null, new FileSystem()); - //MigrateConfigFiles.Migrate(isDocker, directoryService); // Before anything, check if JWT has been generated properly or if user still has default if (!Configuration.CheckIfJwtTokenSet() && @@ -73,10 +72,10 @@ namespace API } await context.Database.MigrateAsync(); - var roleManager = services.GetRequiredService>(); - await Seed.SeedRoles(roleManager); + await Seed.SeedRoles(services.GetRequiredService>()); await Seed.SeedSettings(context, directoryService); + await Seed.SeedThemes(context); await Seed.SeedUserApiKeys(context); @@ -110,7 +109,7 @@ namespace API (await context.ServerSetting.SingleOrDefaultAsync(s => s.Key == ServerSettingKey.InstallVersion))?.Value; } - catch + catch (Exception) { // ignored } diff --git a/API/Services/ArchiveService.cs b/API/Services/ArchiveService.cs index db098aa0f..fd29ea07d 100644 --- a/API/Services/ArchiveService.cs +++ b/API/Services/ArchiveService.cs @@ -27,7 +27,6 @@ namespace API.Services ArchiveLibrary CanOpen(string archivePath); bool ArchiveNeedsFlattening(ZipArchive archive); Task> CreateZipForDownload(IEnumerable files, string tempFolder); - string FindCoverImageFilename(string archivePath, IList entryNames); } /// @@ -127,8 +126,8 @@ namespace API.Services public static string FindFolderEntry(IEnumerable entryFullNames) { var result = entryFullNames - .OrderByNatural(Path.GetFileNameWithoutExtension) .Where(path => !(Path.EndsInDirectorySeparator(path) || Parser.Parser.HasBlacklistedFolderInPath(path) || path.StartsWith(Parser.Parser.MacOsMetadataFileStartsWith))) + .OrderByNatural(Path.GetFileNameWithoutExtension) .FirstOrDefault(Parser.Parser.IsCoverImage); return string.IsNullOrEmpty(result) ? null : result; @@ -144,8 +143,8 @@ namespace API.Services // First check if there are any files that are not in a nested folder before just comparing by filename. This is needed // because NaturalSortComparer does not work with paths and doesn't seem 001.jpg as before chapter 1/001.jpg. var fullNames = entryFullNames - .OrderByNatural(c => c.GetFullPathWithoutExtension()) .Where(path => !(Path.EndsInDirectorySeparator(path) || Parser.Parser.HasBlacklistedFolderInPath(path) || path.StartsWith(Parser.Parser.MacOsMetadataFileStartsWith)) && Parser.Parser.IsImage(path)) + .OrderByNatural(c => c.GetFullPathWithoutExtension()) .ToList(); if (fullNames.Count == 0) return null; @@ -201,9 +200,8 @@ namespace API.Services case ArchiveLibrary.Default: { using var archive = ZipFile.OpenRead(archivePath); - var entryNames = archive.Entries.Select(e => e.FullName).ToList(); - var entryName = FindCoverImageFilename(archivePath, entryNames); + var entryName = FindCoverImageFilename(archivePath, archive.Entries.Select(e => e.FullName)); var entry = archive.Entries.Single(e => e.FullName == entryName); using var stream = entry.Open(); @@ -242,7 +240,7 @@ namespace API.Services /// /// /// - public string FindCoverImageFilename(string archivePath, IList entryNames) + public static string FindCoverImageFilename(string archivePath, IEnumerable entryNames) { var entryName = FindFolderEntry(entryNames) ?? FirstFileEntry(entryNames, Path.GetFileName(archivePath)); return entryName; diff --git a/API/Services/BookService.cs b/API/Services/BookService.cs index 9531aa785..9e9aa0ac2 100644 --- a/API/Services/BookService.cs +++ b/API/Services/BookService.cs @@ -150,7 +150,7 @@ namespace API.Services { // @Import statements will be handled by browser, so we must inline the css into the original file that request it, so they can be // Scoped - var prepend = filename.Length > 0 ? filename.Replace(Path.GetFileName(filename), "") : string.Empty; + var prepend = filename.Length > 0 ? filename.Replace(Path.GetFileName(filename), string.Empty) : string.Empty; var importBuilder = new StringBuilder(); foreach (Match match in Parser.Parser.CssImportUrlRegex.Matches(stylesheetHtml)) { @@ -343,7 +343,7 @@ namespace API.Services { foreach (var styleLinks in styleNodes) { - var key = BookService.CleanContentKeys(styleLinks.Attributes["href"].Value); + var key = CleanContentKeys(styleLinks.Attributes["href"].Value); // Some epubs are malformed the key in content.opf might be: content/resources/filelist_0_0.xml but the actual html links to resources/filelist_0_0.xml // In this case, we will do a search for the key that ends with if (!book.Content.Css.ContainsKey(key)) @@ -358,11 +358,20 @@ namespace API.Services key = correctedKey; } - var styleContent = await ScopeStyles(await book.Content.Css[key].ReadContentAsync(), apiBase, - book.Content.Css[key].FileName, book); - if (styleContent != null) + try { - body.PrependChild(HtmlNode.CreateNode($"")); + var cssFile = book.Content.Css[key]; + + var styleContent = await ScopeStyles(await cssFile.ReadContentAsync(), apiBase, + cssFile.FileName, book); + if (styleContent != null) + { + body.PrependChild(HtmlNode.CreateNode($"")); + } + } + catch (Exception ex) + { + _logger.LogError(ex, "There was an error reading css file for inlining likely due to a key mismatch in metadata"); } } } @@ -460,7 +469,7 @@ namespace API.Services } /// - /// Removes the leading ../ + /// Removes all leading ../ /// /// /// diff --git a/API/Services/BookmarkService.cs b/API/Services/BookmarkService.cs index 7acea6ad8..2f4cd8cdc 100644 --- a/API/Services/BookmarkService.cs +++ b/API/Services/BookmarkService.cs @@ -7,6 +7,7 @@ using API.Data; using API.DTOs.Reader; using API.Entities; using API.Entities.Enums; +using API.SignalR; using Microsoft.Extensions.Logging; namespace API.Services; @@ -16,6 +17,7 @@ public interface IBookmarkService Task DeleteBookmarkFiles(IEnumerable bookmarks); Task BookmarkPage(AppUser userWithBookmarks, BookmarkDto bookmarkDto, string imageToBookmark); Task RemoveBookmarkPage(AppUser userWithBookmarks, BookmarkDto bookmarkDto); + Task> GetBookmarkFilesById(int userId, IEnumerable bookmarkIds); } public class BookmarkService : IBookmarkService @@ -139,6 +141,17 @@ public class BookmarkService : IBookmarkService return true; } + public async Task> GetBookmarkFilesById(int userId, IEnumerable bookmarkIds) + { + var bookmarkDirectory = + (await _unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.BookmarkDirectory)).Value; + + var bookmarks = await _unitOfWork.UserRepository.GetAllBookmarksByIds(bookmarkIds.ToList()); + return bookmarks + .Select(b => Parser.Parser.NormalizePath(_directoryService.FileSystem.Path.Join(bookmarkDirectory, + b.FileName))); + } + private static string BookmarkStem(int userId, int seriesId, int chapterId) { return Path.Join($"{userId}", $"{seriesId}", $"{chapterId}"); diff --git a/API/Services/CacheService.cs b/API/Services/CacheService.cs index c5396f4ed..ef2d3609a 100644 --- a/API/Services/CacheService.cs +++ b/API/Services/CacheService.cs @@ -142,7 +142,7 @@ namespace API.Services { foreach (var chapter in chapterIds) { - _directoryService.ClearDirectory(GetCachePath(chapter)); + _directoryService.ClearAndDeleteDirectory(GetCachePath(chapter)); } } diff --git a/API/Services/DirectoryService.cs b/API/Services/DirectoryService.cs index 0edf51ffc..fb7675735 100644 --- a/API/Services/DirectoryService.cs +++ b/API/Services/DirectoryService.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Collections.Immutable; using System.IO; @@ -19,6 +19,7 @@ namespace API.Services string LogDirectory { get; } string TempDirectory { get; } string ConfigDirectory { get; } + string SiteThemeDirectory { get; } /// /// Original BookmarkDirectory. Only used for resetting directory. Use for actual path. /// @@ -64,6 +65,7 @@ namespace API.Services public string TempDirectory { get; } public string ConfigDirectory { get; } public string BookmarkDirectory { get; } + public string SiteThemeDirectory { get; } private readonly ILogger _logger; private static readonly Regex ExcludeDirectories = new Regex( @@ -81,6 +83,9 @@ namespace API.Services TempDirectory = FileSystem.Path.Join(FileSystem.Directory.GetCurrentDirectory(), "config", "temp"); ConfigDirectory = FileSystem.Path.Join(FileSystem.Directory.GetCurrentDirectory(), "config"); BookmarkDirectory = FileSystem.Path.Join(FileSystem.Directory.GetCurrentDirectory(), "config", "bookmarks"); + SiteThemeDirectory = FileSystem.Path.Join(FileSystem.Directory.GetCurrentDirectory(), "config", "themes"); + + ExistOrCreate(SiteThemeDirectory); } /// @@ -351,6 +356,7 @@ namespace API.Services /// /// Copies files to a destination directory. If the destination directory doesn't exist, this will create it. /// + /// If a file already exists in dest, this will rename as (2). It does not support multiple iterations of this. Overwriting is not supported. /// /// /// An optional string to prepend to the target file's name @@ -367,7 +373,16 @@ namespace API.Services var fileInfo = FileSystem.FileInfo.FromFileName(file); if (fileInfo.Exists) { - fileInfo.CopyTo(FileSystem.Path.Join(directoryPath, prepend + fileInfo.Name)); + // TODO: I need to handle if file already exists and allow either an overwrite or prepend (2) to it + try + { + fileInfo.CopyTo(FileSystem.Path.Join(directoryPath, prepend + fileInfo.Name)); + } + catch (IOException ex) + { + _logger.LogError(ex, "File copy, dest already exists. Appending (2)"); + fileInfo.CopyTo(FileSystem.Path.Join(directoryPath, prepend + FileSystem.Path.GetFileNameWithoutExtension(fileInfo.Name) + " (2)" + FileSystem.Path.GetExtension(fileInfo.Name))); + } } else { @@ -690,7 +705,7 @@ namespace API.Services } - private void FlattenDirectory(IDirectoryInfo root, IDirectoryInfo directory, ref int directoryIndex) + private static void FlattenDirectory(IFileSystemInfo root, IDirectoryInfo directory, ref int directoryIndex) { if (!root.FullName.Equals(directory.FullName)) { @@ -712,6 +727,9 @@ namespace API.Services foreach (var subDirectory in directory.EnumerateDirectories().OrderByNatural(d => d.FullName)) { + // We need to check if the directory is not a blacklisted (ie __MACOSX) + if (Parser.Parser.HasBlacklistedFolderInPath(subDirectory.FullName)) continue; + FlattenDirectory(root, subDirectory, ref directoryIndex); } } diff --git a/API/Services/DownloadService.cs b/API/Services/DownloadService.cs index 51830f0ab..7fc1418e6 100644 --- a/API/Services/DownloadService.cs +++ b/API/Services/DownloadService.cs @@ -2,7 +2,9 @@ using System.IO; using System.Linq; using System.Threading.Tasks; +using API.Constants; using API.Entities; +using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.StaticFiles; namespace API.Services; @@ -11,15 +13,18 @@ public interface IDownloadService { Task<(byte[], string, string)> GetFirstFileDownload(IEnumerable files); string GetContentTypeFromFile(string filepath); + Task HasDownloadPermission(AppUser user); } public class DownloadService : IDownloadService { private readonly IDirectoryService _directoryService; + private readonly UserManager _userManager; private readonly FileExtensionContentTypeProvider _fileTypeProvider = new FileExtensionContentTypeProvider(); - public DownloadService(IDirectoryService directoryService) + public DownloadService(IDirectoryService directoryService, UserManager userManager) { _directoryService = directoryService; + _userManager = userManager; } /// @@ -53,4 +58,10 @@ public class DownloadService : IDownloadService return contentType; } + + public async Task HasDownloadPermission(AppUser user) + { + var roles = await _userManager.GetRolesAsync(user); + return roles.Contains(PolicyConstants.DownloadRole) || roles.Contains(PolicyConstants.AdminRole); + } } diff --git a/API/Services/EmailService.cs b/API/Services/EmailService.cs index 08d00d29d..c5ba90464 100644 --- a/API/Services/EmailService.cs +++ b/API/Services/EmailService.cs @@ -1,4 +1,6 @@ using System; +using System.Linq; +using System.Net; using System.Threading.Tasks; using API.Data; using API.DTOs.Email; @@ -40,14 +42,22 @@ public class EmailService : IEmailService cli.Settings.HttpClientFactory = new UntrustedCertClientFactory()); } + /// + /// Test if this instance is accessible outside the network + /// + /// This will do some basic filtering to auto return false if the emailUrl is a LAN ip + /// + /// public async Task TestConnectivity(string emailUrl) { - // FlurlHttp.ConfigureClient(emailUrl, cli => - // cli.Settings.HttpClientFactory = new UntrustedCertClientFactory()); - var result = new EmailTestResultDto(); try { + if (IsLocalIpAddress(emailUrl)) + { + result.Successful = false; + result.ErrorMessage = "This is a local IP address"; + } result.Successful = await SendEmailWithGet(emailUrl + "/api/email/test"); } catch (KavitaException ex) @@ -72,6 +82,7 @@ public class EmailService : IEmailService public async Task CheckIfAccessible(string host) { // This is the only exception for using the default because we need an external service to check if the server is accessible for emails + if (IsLocalIpAddress(host)) return false; return await SendEmailWithGet(DefaultApiUrl + "/api/email/reachable?host=" + host); } @@ -87,7 +98,7 @@ public class EmailService : IEmailService return await SendEmailWithPost(emailLink + "/api/email/email-password-reset", data); } - private static async Task SendEmailWithGet(string url) + private static async Task SendEmailWithGet(string url, int timeoutSecs = 30) { try { @@ -97,7 +108,7 @@ public class EmailService : IEmailService .WithHeader("x-api-key", "MsnvA2DfQqxSK5jh") .WithHeader("x-kavita-version", BuildInfo.Version) .WithHeader("Content-Type", "application/json") - .WithTimeout(TimeSpan.FromSeconds(30)) + .WithTimeout(TimeSpan.FromSeconds(timeoutSecs)) .GetStringAsync(); if (!string.IsNullOrEmpty(response) && bool.Parse(response)) @@ -113,7 +124,7 @@ public class EmailService : IEmailService } - private static async Task SendEmailWithPost(string url, object data) + private static async Task SendEmailWithPost(string url, object data, int timeoutSecs = 30) { try { @@ -123,7 +134,7 @@ public class EmailService : IEmailService .WithHeader("x-api-key", "MsnvA2DfQqxSK5jh") .WithHeader("x-kavita-version", BuildInfo.Version) .WithHeader("Content-Type", "application/json") - .WithTimeout(TimeSpan.FromSeconds(30)) + .WithTimeout(TimeSpan.FromSeconds(timeoutSecs)) .PostJsonAsync(data); if (response.StatusCode != StatusCodes.Status200OK) @@ -138,4 +149,34 @@ public class EmailService : IEmailService return true; } + private static bool IsLocalIpAddress(string url) + { + var host = url.Split(':')[0]; + try + { + // get host IP addresses + var hostIPs = Dns.GetHostAddresses(host); + // get local IP addresses + var localIPs = Dns.GetHostAddresses(Dns.GetHostName()); + + // test if any host IP equals to any local IP or to localhost + foreach (var hostIp in hostIPs) + { + // is localhost + if (IPAddress.IsLoopback(hostIp)) return true; + // is local address + if (localIPs.Contains(hostIp)) + { + return true; + } + } + } + catch + { + // ignored + } + + return false; + } + } diff --git a/API/Services/MetadataService.cs b/API/Services/MetadataService.cs index 75513193d..590582eb5 100644 --- a/API/Services/MetadataService.cs +++ b/API/Services/MetadataService.cs @@ -5,8 +5,11 @@ using System.Linq; using System.Threading.Tasks; using API.Comparators; using API.Data; +using API.Data.Metadata; using API.Data.Repositories; +using API.Data.Scanner; using API.Entities; +using API.Entities.Enums; using API.Extensions; using API.Helpers; using API.SignalR; @@ -35,18 +38,18 @@ public class MetadataService : IMetadataService { private readonly IUnitOfWork _unitOfWork; private readonly ILogger _logger; - private readonly IHubContext _messageHub; + private readonly IEventHub _eventHub; private readonly ICacheHelper _cacheHelper; private readonly IReadingItemService _readingItemService; private readonly IDirectoryService _directoryService; private readonly ChapterSortComparerZeroFirst _chapterSortComparerForInChapterSorting = new ChapterSortComparerZeroFirst(); public MetadataService(IUnitOfWork unitOfWork, ILogger logger, - IHubContext messageHub, ICacheHelper cacheHelper, + IEventHub eventHub, ICacheHelper cacheHelper, IReadingItemService readingItemService, IDirectoryService directoryService) { _unitOfWork = unitOfWork; _logger = logger; - _messageHub = messageHub; + _eventHub = eventHub; _cacheHelper = cacheHelper; _readingItemService = readingItemService; _directoryService = directoryService; @@ -68,8 +71,8 @@ public class MetadataService : IMetadataService _logger.LogDebug("[MetadataService] Generating cover image for {File}", firstFile.FilePath); chapter.CoverImage = _readingItemService.GetCoverImage(firstFile.FilePath, ImageService.GetChapterFormat(chapter.Id, chapter.VolumeId), firstFile.Format); - await _messageHub.Clients.All.SendAsync(SignalREvents.CoverUpdate, MessageFactory.CoverUpdateEvent(chapter.Id, "chapter")); - + await _eventHub.SendMessageAsync(MessageFactory.CoverUpdate, + MessageFactory.CoverUpdateEvent(chapter.Id, "chapter"), false); return true; } @@ -98,7 +101,7 @@ public class MetadataService : IMetadataService if (firstChapter == null) return false; volume.CoverImage = firstChapter.CoverImage; - await _messageHub.Clients.All.SendAsync(SignalREvents.CoverUpdate, MessageFactory.CoverUpdateEvent(volume.Id, "volume")); + await _eventHub.SendMessageAsync(MessageFactory.CoverUpdate, MessageFactory.CoverUpdateEvent(volume.Id, "volume"), false); return true; } @@ -135,7 +138,7 @@ public class MetadataService : IMetadataService } } series.CoverImage = firstCover?.CoverImage ?? coverImage; - await _messageHub.Clients.All.SendAsync(SignalREvents.CoverUpdate, MessageFactory.CoverUpdateEvent(series.Id, "series")); + await _eventHub.SendMessageAsync(MessageFactory.CoverUpdate, MessageFactory.CoverUpdateEvent(series.Id, "series"), false); } @@ -200,8 +203,9 @@ public class MetadataService : IMetadataService var stopwatch = Stopwatch.StartNew(); var totalTime = 0L; _logger.LogInformation("[MetadataService] Refreshing Library {LibraryName}. Total Items: {TotalSize}. Total Chunks: {TotalChunks} with {ChunkSize} size", library.Name, chunkInfo.TotalSize, chunkInfo.TotalChunks, chunkInfo.ChunkSize); - await _messageHub.Clients.All.SendAsync(SignalREvents.RefreshMetadataProgress, - MessageFactory.RefreshMetadataProgressEvent(library.Id, 0F)); + + await _eventHub.SendMessageAsync(MessageFactory.NotificationProgress, + MessageFactory.CoverUpdateProgressEvent(library.Id, 0F, ProgressEventType.Started, $"Starting {library.Name}")); for (var chunk = 1; chunk <= chunkInfo.TotalChunks; chunk++) { @@ -223,6 +227,12 @@ public class MetadataService : IMetadataService var seriesIndex = 0; foreach (var series in nonLibrarySeries) { + var index = chunk * seriesIndex; + var progress = Math.Max(0F, Math.Min(1F, index * 1F / chunkInfo.TotalSize)); + + await _eventHub.SendMessageAsync(MessageFactory.NotificationProgress, + MessageFactory.CoverUpdateProgressEvent(library.Id, progress, ProgressEventType.Updated, series.Name)); + try { await ProcessSeriesMetadataUpdate(series, forceUpdate); @@ -231,11 +241,6 @@ public class MetadataService : IMetadataService { _logger.LogError(ex, "[MetadataService] There was an exception during metadata refresh for {SeriesName}", series.Name); } - var index = chunk * seriesIndex; - var progress = Math.Max(0F, Math.Min(1F, index * 1F / chunkInfo.TotalSize)); - - await _messageHub.Clients.All.SendAsync(SignalREvents.RefreshMetadataProgress, - MessageFactory.RefreshMetadataProgressEvent(library.Id, progress)); seriesIndex++; } @@ -246,8 +251,8 @@ public class MetadataService : IMetadataService chunk * chunkInfo.ChunkSize, (chunk * chunkInfo.ChunkSize) + nonLibrarySeries.Count, chunkInfo.TotalSize, stopwatch.ElapsedMilliseconds, library.Name); } - await _messageHub.Clients.All.SendAsync(SignalREvents.RefreshMetadataProgress, - MessageFactory.RefreshMetadataProgressEvent(library.Id, 1F)); + await _eventHub.SendMessageAsync(MessageFactory.NotificationProgress, + MessageFactory.CoverUpdateProgressEvent(library.Id, 1F, ProgressEventType.Ended, $"Complete")); await RemoveAbandonedMetadataKeys(); @@ -277,8 +282,8 @@ public class MetadataService : IMetadataService return; } - await _messageHub.Clients.All.SendAsync(SignalREvents.RefreshMetadataProgress, - MessageFactory.RefreshMetadataProgressEvent(libraryId, 0F)); + await _eventHub.SendMessageAsync(MessageFactory.NotificationProgress, + MessageFactory.CoverUpdateProgressEvent(libraryId, 0F, ProgressEventType.Started, series.Name)); await ProcessSeriesMetadataUpdate(series, forceUpdate); @@ -288,11 +293,16 @@ public class MetadataService : IMetadataService await _unitOfWork.CommitAsync(); } - await _messageHub.Clients.All.SendAsync(SignalREvents.RefreshMetadataProgress, - MessageFactory.RefreshMetadataProgressEvent(libraryId, 1F)); + await _eventHub.SendMessageAsync(MessageFactory.NotificationProgress, + MessageFactory.CoverUpdateProgressEvent(libraryId, 1F, ProgressEventType.Ended, series.Name)); await RemoveAbandonedMetadataKeys(); + if (_unitOfWork.HasChanges() && await _unitOfWork.CommitAsync()) + { + await _eventHub.SendMessageAsync(MessageFactory.CoverUpdate, MessageFactory.CoverUpdateEvent(series.Id, "series"), false); + } + _logger.LogInformation("[MetadataService] Updated metadata for {SeriesName} in {ElapsedMilliseconds} milliseconds", series.Name, sw.ElapsedMilliseconds); } } diff --git a/API/Services/ReaderService.cs b/API/Services/ReaderService.cs index 36a98317b..ab586486d 100644 --- a/API/Services/ReaderService.cs +++ b/API/Services/ReaderService.cs @@ -16,6 +16,8 @@ namespace API.Services; public interface IReaderService { + Task MarkSeriesAsRead(AppUser user, int seriesId); + Task MarkSeriesAsUnread(AppUser user, int seriesId); void MarkChaptersAsRead(AppUser user, int seriesId, IEnumerable chapters); void MarkChaptersAsUnread(AppUser user, int seriesId, IEnumerable chapters); Task SaveReadingProgress(ProgressDto progressDto, int userId); @@ -45,6 +47,40 @@ public class ReaderService : IReaderService return Parser.Parser.NormalizePath(Path.Join(baseDirectory, $"{userId}", $"{seriesId}", $"{chapterId}")); } + /// + /// Does not commit. Marks all entities under the series as read. + /// + /// + /// + public async Task MarkSeriesAsRead(AppUser user, int seriesId) + { + var volumes = await _unitOfWork.VolumeRepository.GetVolumes(seriesId); + user.Progresses ??= new List(); + foreach (var volume in volumes) + { + MarkChaptersAsRead(user, seriesId, volume.Chapters); + } + + _unitOfWork.UserRepository.Update(user); + } + + /// + /// Does not commit. Marks all entities under the series as unread. + /// + /// + /// + public async Task MarkSeriesAsUnread(AppUser user, int seriesId) + { + var volumes = await _unitOfWork.VolumeRepository.GetVolumes(seriesId); + user.Progresses ??= new List(); + foreach (var volume in volumes) + { + MarkChaptersAsUnread(user, seriesId, volume.Chapters); + } + + _unitOfWork.UserRepository.Update(user); + } + /// /// Marks all Chapters as Read by creating or updating UserProgress rows. Does not commit. /// @@ -242,7 +278,7 @@ public class ReaderService : IReaderService { // Handle Chapters within current Volume // In this case, i need 0 first because 0 represents a full volume file. - var chapterId = GetNextChapterId(currentVolume.Chapters.OrderBy(x => double.Parse(x.Number), _chapterSortComparerForInChapterSorting), + var chapterId = GetNextChapterId(currentVolume.Chapters.OrderBy(x => double.Parse(x.Number), _chapterSortComparer), currentChapter.Range, dto => dto.Range); if (chapterId > 0) return chapterId; @@ -255,6 +291,9 @@ public class ReaderService : IReaderService var chapters = volume.Chapters.OrderBy(x => double.Parse(x.Number), _chapterSortComparer).ToList(); if (currentChapter.Number.Equals("0") && chapters.Last().Number.Equals("0")) { + // We need to handle an extra check if the current chapter is the last special, as we should return -1 + if (currentChapter.IsSpecial) return -1; + return chapters.Last().Id; } @@ -302,7 +341,8 @@ public class ReaderService : IReaderService if (currentVolume.Number == 0) { - var chapterId = GetNextChapterId(currentVolume.Chapters.OrderByNatural(x => x.Range).Reverse(), currentChapter.Number, dto => dto.Number); + var chapterId = GetNextChapterId(currentVolume.Chapters.OrderByNatural(x => x.Range).Reverse(), currentChapter.Range, + dto => dto.Range); if (chapterId > 0) return chapterId; } @@ -311,11 +351,12 @@ public class ReaderService : IReaderService if (volume.Number == currentVolume.Number) { var chapterId = GetNextChapterId(currentVolume.Chapters.OrderBy(x => double.Parse(x.Number), _chapterSortComparerForInChapterSorting).Reverse(), - currentChapter.Number, dto => dto.Number); + currentChapter.Range, dto => dto.Range); if (chapterId > 0) return chapterId; } if (volume.Number == currentVolume.Number - 1) { + if (currentVolume.Number - 1 == 0) break; // If we have walked all the way to chapter volume, then we should break so logic outside can work var lastChapter = volume.Chapters .OrderBy(x => double.Parse(x.Number), _chapterSortComparerForInChapterSorting).LastOrDefault(); if (lastChapter == null) return -1; @@ -335,29 +376,66 @@ public class ReaderService : IReaderService return -1; } + /// + /// Finds the chapter to continue reading from. If a chapter has progress and not complete, return that. If not, progress in the + /// ordering (Volumes -> Loose Chapters -> Special) to find next chapter. If all are read, return first in order for series. + /// + /// + /// + /// public async Task GetContinuePoint(int seriesId, int userId) { - // Loop through all chapters that are not in volume 0 + var progress = (await _unitOfWork.AppUserProgressRepository.GetUserProgressForSeriesAsync(seriesId, userId)).ToList(); var volumes = (await _unitOfWork.VolumeRepository.GetVolumesDtoAsync(seriesId, userId)).ToList(); - var nonSpecialChapters = volumes + if (progress.Count == 0) + { + // I think i need a way to sort volumes last + return volumes.OrderBy(v => double.Parse(v.Number + ""), _chapterSortComparer).First().Chapters + .OrderBy(c => float.Parse(c.Number)).First(); + } + + // Loop through all chapters that are not in volume 0 + var volumeChapters = volumes .Where(v => v.Number != 0) .SelectMany(v => v.Chapters) .OrderBy(c => float.Parse(c.Number)) .ToList(); - var currentlyReadingChapter = nonSpecialChapters.FirstOrDefault(chapter => chapter.PagesRead < chapter.Pages); - - + // If there are any volumes that have progress, return those. If not, move on. + var currentlyReadingChapter = volumeChapters.FirstOrDefault(chapter => chapter.PagesRead < chapter.Pages); if (currentlyReadingChapter != null) return currentlyReadingChapter; - // Check if there are any specials - var volume = volumes.SingleOrDefault(v => v.Number == 0); - if (volume == null) return nonSpecialChapters.First(); + // Order with volume 0 last so we prefer the natural order + return FindNextReadingChapter(volumes.OrderBy(v => v.Number, new SortComparerZeroLast()).SelectMany(v => v.Chapters).ToList()); + } - var chapters = volume.Chapters.OrderBy(c => float.Parse(c.Number)).ToList(); + private static ChapterDto FindNextReadingChapter(IList volumeChapters) + { + var chaptersWithProgress = volumeChapters.Where(c => c.PagesRead > 0).ToList(); + if (chaptersWithProgress.Count <= 0) return volumeChapters.First(); - return chapters.FirstOrDefault(chapter => chapter.PagesRead < chapter.Pages) ?? chapters.First(); + + var last = chaptersWithProgress.FindLastIndex(c => c.PagesRead > 0); + if (last + 1 < chaptersWithProgress.Count) + { + return chaptersWithProgress.ElementAt(last + 1); + } + + var lastChapter = chaptersWithProgress.ElementAt(last); + if (lastChapter.PagesRead < lastChapter.Pages) + { + return chaptersWithProgress.ElementAt(last); + } + + // chaptersWithProgress are all read, then we need to get the next chapter that doesn't have progress + var lastIndexWithProgress = volumeChapters.IndexOf(lastChapter); + if (lastIndexWithProgress + 1 < volumeChapters.Count) + { + return volumeChapters.ElementAt(lastIndexWithProgress + 1); + } + + return volumeChapters.First(); } @@ -392,7 +470,7 @@ public class ReaderService : IReaderService { var chapters = volume.Chapters .OrderBy(c => float.Parse(c.Number)) - .Where(c => !c.IsSpecial && Parser.Parser.MaximumNumberFromRange(c.Range) <= chapterNumber && Parser.Parser.MaximumNumberFromRange(c.Range) > 0.0); + .Where(c => !c.IsSpecial && Parser.Parser.MaximumNumberFromRange(c.Range) <= chapterNumber); MarkChaptersAsRead(user, volume.SeriesId, chapters); } } @@ -400,7 +478,7 @@ public class ReaderService : IReaderService public async Task MarkVolumesUntilAsRead(AppUser user, int seriesId, int volumeNumber) { var volumes = await _unitOfWork.VolumeRepository.GetVolumesForSeriesAsync(new List() { seriesId }, true); - foreach (var volume in volumes.OrderBy(v => v.Number).Where(v => v.Number <= volumeNumber)) + foreach (var volume in volumes.OrderBy(v => v.Number).Where(v => v.Number <= volumeNumber && v.Number > 0)) { MarkChaptersAsRead(user, volume.SeriesId, volume.Chapters); } diff --git a/API/Services/SeriesService.cs b/API/Services/SeriesService.cs new file mode 100644 index 000000000..3146ce6dc --- /dev/null +++ b/API/Services/SeriesService.cs @@ -0,0 +1,567 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using API.Comparators; +using API.Data; +using API.DTOs; +using API.DTOs.CollectionTags; +using API.DTOs.Metadata; +using API.Entities; +using API.Entities.Enums; +using API.Helpers; +using API.SignalR; +using Microsoft.Extensions.Logging; + +namespace API.Services; + + +public interface ISeriesService +{ + Task GetSeriesDetail(int seriesId, int userId); + Task UpdateSeriesMetadata(UpdateSeriesMetadataDto updateSeriesMetadataDto); + Task UpdateRating(AppUser user, UpdateSeriesRatingDto updateSeriesRatingDto); + Task DeleteMultipleSeries(IList seriesIds); + +} + +public class SeriesService : ISeriesService +{ + private readonly IUnitOfWork _unitOfWork; + private readonly IEventHub _eventHub; + private readonly ITaskScheduler _taskScheduler; + private readonly ILogger _logger; + + public SeriesService(IUnitOfWork unitOfWork, IEventHub eventHub, ITaskScheduler taskScheduler, ILogger logger) + { + _unitOfWork = unitOfWork; + _eventHub = eventHub; + _taskScheduler = taskScheduler; + _logger = logger; + } + + public async Task UpdateSeriesMetadata(UpdateSeriesMetadataDto updateSeriesMetadataDto) + { + try + { + var seriesId = updateSeriesMetadataDto.SeriesMetadata.SeriesId; + var series = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(seriesId); + var allCollectionTags = (await _unitOfWork.CollectionTagRepository.GetAllTagsAsync()).ToList(); + var allGenres = (await _unitOfWork.GenreRepository.GetAllGenresAsync()).ToList(); + var allPeople = (await _unitOfWork.PersonRepository.GetAllPeople()).ToList(); + var allTags = (await _unitOfWork.TagRepository.GetAllTagsAsync()).ToList(); + + if (series.Metadata == null) + { + series.Metadata = DbFactory.SeriesMetadata(updateSeriesMetadataDto.CollectionTags + .Select(dto => DbFactory.CollectionTag(dto.Id, dto.Title, dto.Summary, dto.Promoted)).ToList()); + } + else + { + if (series.Metadata.AgeRating != updateSeriesMetadataDto.SeriesMetadata.AgeRating) + { + series.Metadata.AgeRating = updateSeriesMetadataDto.SeriesMetadata.AgeRating; + series.Metadata.AgeRatingLocked = true; + } + + if (series.Metadata.PublicationStatus != updateSeriesMetadataDto.SeriesMetadata.PublicationStatus) + { + series.Metadata.PublicationStatus = updateSeriesMetadataDto.SeriesMetadata.PublicationStatus; + series.Metadata.PublicationStatusLocked = true; + } + + if (series.Metadata.Summary != updateSeriesMetadataDto.SeriesMetadata.Summary.Trim()) + { + series.Metadata.Summary = updateSeriesMetadataDto.SeriesMetadata?.Summary.Trim(); + series.Metadata.SummaryLocked = true; + } + + if (series.Metadata.Language != updateSeriesMetadataDto.SeriesMetadata.Language) + { + series.Metadata.Language = updateSeriesMetadataDto.SeriesMetadata?.Language; + series.Metadata.LanguageLocked = true; + } + + + series.Metadata.CollectionTags ??= new List(); + UpdateRelatedList(updateSeriesMetadataDto.CollectionTags, series, allCollectionTags, (tag) => + { + series.Metadata.CollectionTags.Add(tag); + }); + + series.Metadata.Genres ??= new List(); + UpdateGenreList(updateSeriesMetadataDto.SeriesMetadata.Genres, series, allGenres, (genre) => + { + series.Metadata.Genres.Add(genre); + }, () => series.Metadata.GenresLocked = true); + + series.Metadata.Tags ??= new List(); + UpdateTagList(updateSeriesMetadataDto.SeriesMetadata.Tags, series, allTags, (tag) => + { + series.Metadata.Tags.Add(tag); + }, () => series.Metadata.TagsLocked = true); + + void HandleAddPerson(Person person) + { + PersonHelper.AddPersonIfNotExists(series.Metadata.People, person); + allPeople.Add(person); + } + + series.Metadata.People ??= new List(); + UpdatePeopleList(PersonRole.Writer, updateSeriesMetadataDto.SeriesMetadata.Writers, series, allPeople, + HandleAddPerson, () => series.Metadata.WriterLocked = true); + UpdatePeopleList(PersonRole.Character, updateSeriesMetadataDto.SeriesMetadata.Characters, series, allPeople, + HandleAddPerson, () => series.Metadata.CharacterLocked = true); + UpdatePeopleList(PersonRole.Colorist, updateSeriesMetadataDto.SeriesMetadata.Colorists, series, allPeople, + HandleAddPerson, () => series.Metadata.ColoristLocked = true); + UpdatePeopleList(PersonRole.Editor, updateSeriesMetadataDto.SeriesMetadata.Editors, series, allPeople, + HandleAddPerson, () => series.Metadata.EditorLocked = true); + UpdatePeopleList(PersonRole.Inker, updateSeriesMetadataDto.SeriesMetadata.Inkers, series, allPeople, + HandleAddPerson, () => series.Metadata.InkerLocked = true); + UpdatePeopleList(PersonRole.Letterer, updateSeriesMetadataDto.SeriesMetadata.Letterers, series, allPeople, + HandleAddPerson, () => series.Metadata.LettererLocked = true); + UpdatePeopleList(PersonRole.Penciller, updateSeriesMetadataDto.SeriesMetadata.Pencillers, series, allPeople, + HandleAddPerson, () => series.Metadata.PencillerLocked = true); + UpdatePeopleList(PersonRole.Publisher, updateSeriesMetadataDto.SeriesMetadata.Publishers, series, allPeople, + HandleAddPerson, () => series.Metadata.PublisherLocked = true); + UpdatePeopleList(PersonRole.Translator, updateSeriesMetadataDto.SeriesMetadata.Translators, series, allPeople, + HandleAddPerson, () => series.Metadata.TranslatorLocked = true); + UpdatePeopleList(PersonRole.CoverArtist, updateSeriesMetadataDto.SeriesMetadata.CoverArtists, series, allPeople, + HandleAddPerson, () => series.Metadata.CoverArtistLocked = true); + + if (!updateSeriesMetadataDto.SeriesMetadata.AgeRatingLocked) series.Metadata.AgeRatingLocked = false; + if (!updateSeriesMetadataDto.SeriesMetadata.PublicationStatusLocked) series.Metadata.PublicationStatusLocked = false; + if (!updateSeriesMetadataDto.SeriesMetadata.LanguageLocked) series.Metadata.LanguageLocked = false; + if (!updateSeriesMetadataDto.SeriesMetadata.GenresLocked) series.Metadata.GenresLocked = false; + if (!updateSeriesMetadataDto.SeriesMetadata.TagsLocked) series.Metadata.TagsLocked = false; + if (!updateSeriesMetadataDto.SeriesMetadata.CharacterLocked) series.Metadata.CharacterLocked = false; + if (!updateSeriesMetadataDto.SeriesMetadata.ColoristLocked) series.Metadata.ColoristLocked = false; + if (!updateSeriesMetadataDto.SeriesMetadata.EditorLocked) series.Metadata.EditorLocked = false; + if (!updateSeriesMetadataDto.SeriesMetadata.InkerLocked) series.Metadata.InkerLocked = false; + if (!updateSeriesMetadataDto.SeriesMetadata.LettererLocked) series.Metadata.LettererLocked = false; + if (!updateSeriesMetadataDto.SeriesMetadata.PencillerLocked) series.Metadata.PencillerLocked = false; + if (!updateSeriesMetadataDto.SeriesMetadata.PublisherLocked) series.Metadata.PublisherLocked = false; + if (!updateSeriesMetadataDto.SeriesMetadata.TranslatorLocked) series.Metadata.TranslatorLocked = false; + if (!updateSeriesMetadataDto.SeriesMetadata.CoverArtistLocked) series.Metadata.CoverArtistLocked = false; + if (!updateSeriesMetadataDto.SeriesMetadata.WriterLocked) series.Metadata.WriterLocked = false; + if (!updateSeriesMetadataDto.SeriesMetadata.SummaryLocked) series.Metadata.SummaryLocked = false; + + } + + if (!_unitOfWork.HasChanges()) + { + return true; + } + + if (await _unitOfWork.CommitAsync()) + { + foreach (var tag in updateSeriesMetadataDto.CollectionTags) + { + await _eventHub.SendMessageAsync(MessageFactory.SeriesAddedToCollection, + MessageFactory.SeriesAddedToCollectionEvent(tag.Id, + updateSeriesMetadataDto.SeriesMetadata.SeriesId), false); + } + + await _eventHub.SendMessageAsync(MessageFactory.ScanSeries, + MessageFactory.ScanSeriesEvent(series.LibraryId, series.Id, series.Name), false); + + await _unitOfWork.CollectionTagRepository.RemoveTagsWithoutSeries(); + + return true; + } + } + catch (Exception ex) + { + _logger.LogError(ex, "There was an exception when updating metadata"); + await _unitOfWork.RollbackAsync(); + } + + return false; + } + + // TODO: Move this to a helper so we can easily test + private static void UpdateRelatedList(ICollection tags, Series series, IReadOnlyCollection allTags, + Action handleAdd) + { + // I want a union of these 2 lists. Return only elements that are in both lists, but the list types are different + var existingTags = series.Metadata.CollectionTags.ToList(); + foreach (var existing in existingTags) + { + if (tags.SingleOrDefault(t => t.Id == existing.Id) == null) + { + // Remove tag + series.Metadata.CollectionTags.Remove(existing); + } + } + + // At this point, all tags that aren't in dto have been removed. + foreach (var tag in tags) + { + var existingTag = allTags.SingleOrDefault(t => t.Title == tag.Title); + if (existingTag != null) + { + if (series.Metadata.CollectionTags.All(t => t.Title != tag.Title)) + { + handleAdd(existingTag); + } + } + else + { + // Add new tag + handleAdd(DbFactory.CollectionTag(tag.Id, tag.Title, tag.Summary, tag.Promoted)); + } + } + } + + private static void UpdateGenreList(ICollection tags, Series series, IReadOnlyCollection allTags, Action handleAdd, Action onModified) + { + var isModified = false; + // I want a union of these 2 lists. Return only elements that are in both lists, but the list types are different + var existingTags = series.Metadata.Genres.ToList(); + foreach (var existing in existingTags) + { + if (tags.SingleOrDefault(t => t.Id == existing.Id) == null) + { + // Remove tag + series.Metadata.Genres.Remove(existing); + isModified = true; + } + } + + // At this point, all tags that aren't in dto have been removed. + foreach (var tagTitle in tags.Select(t => t.Title)) + { + var existingTag = allTags.SingleOrDefault(t => t.Title == tagTitle); + if (existingTag != null) + { + if (series.Metadata.Genres.All(t => t.Title != tagTitle)) + { + handleAdd(existingTag); + isModified = true; + } + } + else + { + // Add new tag + handleAdd(DbFactory.Genre(tagTitle, false)); + isModified = true; + } + } + + if (isModified) + { + onModified(); + } + } + + private static void UpdateTagList(ICollection tags, Series series, IReadOnlyCollection allTags, Action handleAdd, Action onModified) + { + var isModified = false; + // I want a union of these 2 lists. Return only elements that are in both lists, but the list types are different + var existingTags = series.Metadata.Tags.ToList(); + foreach (var existing in existingTags) + { + if (tags.SingleOrDefault(t => t.Id == existing.Id) == null) + { + // Remove tag + series.Metadata.Tags.Remove(existing); + isModified = true; + } + } + + // At this point, all tags that aren't in dto have been removed. + foreach (var tagTitle in tags.Select(t => t.Title)) + { + var existingTag = allTags.SingleOrDefault(t => t.Title == tagTitle); + if (existingTag != null) + { + if (series.Metadata.Tags.All(t => t.Title != tagTitle)) + { + + handleAdd(existingTag); + isModified = true; + } + } + else + { + // Add new tag + handleAdd(DbFactory.Tag(tagTitle, false)); + isModified = true; + } + } + + if (isModified) + { + onModified(); + } + } + + private static void UpdatePeopleList(PersonRole role, ICollection tags, Series series, IReadOnlyCollection allTags, + Action handleAdd, Action onModified) + { + var isModified = false; + // I want a union of these 2 lists. Return only elements that are in both lists, but the list types are different + var existingTags = series.Metadata.People.Where(p => p.Role == role).ToList(); + foreach (var existing in existingTags) + { + if (tags.SingleOrDefault(t => t.Id == existing.Id) == null) // This needs to check against role + { + // Remove tag + series.Metadata.People.Remove(existing); + isModified = true; + } + } + + // At this point, all tags that aren't in dto have been removed. + foreach (var tag in tags) + { + var existingTag = allTags.SingleOrDefault(t => t.Name == tag.Name && t.Role == tag.Role); + if (existingTag != null) + { + if (series.Metadata.People.All(t => t.Name != tag.Name && t.Role == tag.Role)) + { + handleAdd(existingTag); + isModified = true; + } + } + else + { + // Add new tag + handleAdd(DbFactory.Person(tag.Name, role)); + isModified = true; + } + } + + if (isModified) + { + onModified(); + } + } + + /// + /// + /// + /// User with Ratings includes + /// + /// + public async Task UpdateRating(AppUser user, UpdateSeriesRatingDto updateSeriesRatingDto) + { + if (user == null) + { + _logger.LogError("Cannot update rating of null user"); + return false; + } + + var userRating = + await _unitOfWork.UserRepository.GetUserRatingAsync(updateSeriesRatingDto.SeriesId, user.Id) ?? + new AppUserRating(); + try + { + userRating.Rating = Math.Clamp(updateSeriesRatingDto.UserRating, 0, 5); + userRating.Review = updateSeriesRatingDto.UserReview; + userRating.SeriesId = updateSeriesRatingDto.SeriesId; + + if (userRating.Id == 0) + { + user.Ratings ??= new List(); + user.Ratings.Add(userRating); + } + + _unitOfWork.UserRepository.Update(user); + + if (!_unitOfWork.HasChanges() || await _unitOfWork.CommitAsync()) return true; + } + catch (Exception ex) + { + _logger.LogError(ex, "There was an exception saving rating"); + } + + await _unitOfWork.RollbackAsync(); + user.Ratings?.Remove(userRating); + + return false; + } + + public async Task DeleteMultipleSeries(IList seriesIds) + { + try + { + var chapterMappings = + await _unitOfWork.SeriesRepository.GetChapterIdWithSeriesIdForSeriesAsync(seriesIds.ToArray()); + + var allChapterIds = new List(); + foreach (var mapping in chapterMappings) + { + allChapterIds.AddRange(mapping.Value); + } + + var series = await _unitOfWork.SeriesRepository.GetSeriesByIdsAsync(seriesIds); + _unitOfWork.SeriesRepository.Remove(series); + + if (!_unitOfWork.HasChanges() || !await _unitOfWork.CommitAsync()) return true; + + foreach (var s in series) + { + await _eventHub.SendMessageAsync(MessageFactory.SeriesRemoved, + MessageFactory.SeriesRemovedEvent(s.Id, s.Name, s.LibraryId), false); + } + + await _unitOfWork.AppUserProgressRepository.CleanupAbandonedChapters(); + await _unitOfWork.CollectionTagRepository.RemoveTagsWithoutSeries(); + _taskScheduler.CleanupChapters(allChapterIds.ToArray()); + } + catch (Exception ex) + { + _logger.LogError(ex, "There was an issue when trying to delete multiple series"); + return false; + } + + return true; + } + + /// + /// This generates all the arrays needed by the Series Detail page in the UI. It is a specialized API for the unique layout constraints. + /// + /// + /// + /// + public async Task GetSeriesDetail(int seriesId, int userId) + { + var series = await _unitOfWork.SeriesRepository.GetSeriesDtoByIdAsync(seriesId, userId); + + var libraryType = await _unitOfWork.LibraryRepository.GetLibraryTypeAsync(series.LibraryId); + var volumes = (await _unitOfWork.VolumeRepository.GetVolumesDtoAsync(seriesId, userId)) + .OrderBy(v => float.Parse(v.Name)) + .ToList(); + var chapters = volumes.SelectMany(v => v.Chapters).ToList(); + + // For books, the Name of the Volume is remapped to the actual name of the book, rather than Volume number. + var processedVolumes = new List(); + if (libraryType == LibraryType.Book) + { + foreach (var volume in volumes) + { + var firstChapter = volume.Chapters.First(); + // On Books, skip volumes that are specials, since these will be shown + if (firstChapter.IsSpecial) continue; + RenameVolumeName(firstChapter, volume, libraryType); + processedVolumes.Add(volume); + } + } + else + { + processedVolumes = volumes.Where(v => v.Number > 0).ToList(); + processedVolumes.ForEach(v => v.Name = $"Volume {v.Name}"); + } + + + var specials = new List(); + foreach (var chapter in chapters) + { + chapter.Title = FormatChapterTitle(chapter, libraryType); + if (chapter.IsSpecial) + { + specials.Add(chapter); + } + } + + + // Don't show chapter 0 (aka single volume chapters) in the Chapters tab or books that are just single numbers (they show as volumes) + IEnumerable retChapters; + if (libraryType == LibraryType.Book) + { + retChapters = Array.Empty(); + } else + { + retChapters = chapters + .Where(ShouldIncludeChapter) + .OrderBy(c => float.Parse(c.Number), new ChapterSortComparer()); + } + + + + return new SeriesDetailDto() + { + Specials = specials, + Chapters = retChapters, + Volumes = processedVolumes, + StorylineChapters = volumes + .Where(v => v.Number == 0) + .SelectMany(v => v.Chapters.Where(c => !c.IsSpecial)) + .OrderBy(c => float.Parse(c.Number), new ChapterSortComparer()) + + }; + } + + /// + /// Should we show the given chapter on the UI. We only show non-specials and non-zero chapters. + /// + /// + /// + private static bool ShouldIncludeChapter(ChapterDto c) + { + return !c.IsSpecial && !c.Number.Equals(Parser.Parser.DefaultChapter); + } + + public static void RenameVolumeName(ChapterDto firstChapter, VolumeDto volume, LibraryType libraryType) + { + if (libraryType == LibraryType.Book) + { + if (string.IsNullOrEmpty(firstChapter.TitleName)) + { + if (firstChapter.Range.Equals(Parser.Parser.DefaultVolume)) return; + var title = Path.GetFileNameWithoutExtension(firstChapter.Range); + if (string.IsNullOrEmpty(title)) return; + volume.Name += $" - {title}"; + } + else + { + volume.Name += $" - {firstChapter.TitleName}"; + } + + return; + } + + volume.Name = $"Volume {volume.Name}"; + } + + + private static string FormatChapterTitle(bool isSpecial, LibraryType libraryType, string chapterTitle, bool withHash) + { + if (isSpecial) + { + return Parser.Parser.CleanSpecialTitle(chapterTitle); + } + + var hashSpot = withHash ? "#" : string.Empty; + return libraryType switch + { + LibraryType.Book => $"Book {chapterTitle}", + LibraryType.Comic => $"Issue {hashSpot}{chapterTitle}", + LibraryType.Manga => $"Chapter {chapterTitle}", + _ => "Chapter " + }; + } + + public static string FormatChapterTitle(ChapterDto chapter, LibraryType libraryType, bool withHash = true) + { + return FormatChapterTitle(chapter.IsSpecial, libraryType, chapter.Title, withHash); + } + + public static string FormatChapterTitle(Chapter chapter, LibraryType libraryType, bool withHash = true) + { + return FormatChapterTitle(chapter.IsSpecial, libraryType, chapter.Title, withHash); + } + + public static string FormatChapterName(LibraryType libraryType, bool withHash = false) + { + return libraryType switch + { + LibraryType.Manga => "Chapter", + LibraryType.Comic => withHash ? "Issue #" : "Issue", + LibraryType.Book => "Book", + _ => "Chapter" + }; + } +} diff --git a/API/Services/TaskScheduler.cs b/API/Services/TaskScheduler.cs index 6c1d914cf..d749c20ca 100644 --- a/API/Services/TaskScheduler.cs +++ b/API/Services/TaskScheduler.cs @@ -15,13 +15,14 @@ public interface ITaskScheduler Task ScheduleTasks(); Task ScheduleStatsTasks(); void ScheduleUpdaterTasks(); - void ScanLibrary(int libraryId, bool forceUpdate = false); + void ScanLibrary(int libraryId); void CleanupChapters(int[] chapterIds); void RefreshMetadata(int libraryId, bool forceUpdate = true); void RefreshSeriesMetadata(int libraryId, int seriesId, bool forceUpdate = false); void ScanSeries(int libraryId, int seriesId, bool forceUpdate = false); void CancelStatsTasks(); Task RunStatCollection(); + void ScanSiteThemes(); } public class TaskScheduler : ITaskScheduler { @@ -35,6 +36,7 @@ public class TaskScheduler : ITaskScheduler private readonly IStatsService _statsService; private readonly IVersionUpdaterService _versionUpdaterService; + private readonly ISiteThemeService _siteThemeService; public static BackgroundJobServer Client => new BackgroundJobServer(); private static readonly Random Rnd = new Random(); @@ -42,7 +44,8 @@ public class TaskScheduler : ITaskScheduler public TaskScheduler(ICacheService cacheService, ILogger logger, IScannerService scannerService, IUnitOfWork unitOfWork, IMetadataService metadataService, IBackupService backupService, - ICleanupService cleanupService, IStatsService statsService, IVersionUpdaterService versionUpdaterService) + ICleanupService cleanupService, IStatsService statsService, IVersionUpdaterService versionUpdaterService, + ISiteThemeService siteThemeService) { _cacheService = cacheService; _logger = logger; @@ -53,6 +56,7 @@ public class TaskScheduler : ITaskScheduler _cleanupService = cleanupService; _statsService = statsService; _versionUpdaterService = versionUpdaterService; + _siteThemeService = siteThemeService; } public async Task ScheduleTasks() @@ -124,6 +128,12 @@ public class TaskScheduler : ITaskScheduler BackgroundJob.Enqueue(() => _statsService.Send()); } + public void ScanSiteThemes() + { + _logger.LogInformation("Starting Site Theme scan"); + BackgroundJob.Enqueue(() => _siteThemeService.Scan()); + } + #endregion #region UpdateTasks @@ -136,7 +146,7 @@ public class TaskScheduler : ITaskScheduler } #endregion - public void ScanLibrary(int libraryId, bool forceUpdate = false) + public void ScanLibrary(int libraryId) { _logger.LogInformation("Enqueuing library scan for: {LibraryId}", libraryId); BackgroundJob.Enqueue(() => _scannerService.ScanLibrary(libraryId)); diff --git a/API/Services/Tasks/BackupService.cs b/API/Services/Tasks/BackupService.cs index 12f4f1083..0f1b70f9f 100644 --- a/API/Services/Tasks/BackupService.cs +++ b/API/Services/Tasks/BackupService.cs @@ -31,17 +31,17 @@ public class BackupService : IBackupService private readonly IUnitOfWork _unitOfWork; private readonly ILogger _logger; private readonly IDirectoryService _directoryService; - private readonly IHubContext _messageHub; + private readonly IEventHub _eventHub; private readonly IList _backupFiles; public BackupService(ILogger logger, IUnitOfWork unitOfWork, - IDirectoryService directoryService, IConfiguration config, IHubContext messageHub) + IDirectoryService directoryService, IConfiguration config, IEventHub eventHub) { _unitOfWork = unitOfWork; _logger = logger; _directoryService = directoryService; - _messageHub = messageHub; + _eventHub = eventHub; var maxRollingFiles = config.GetMaxRollingFiles(); var loggingSection = config.GetLoggingFileName(); @@ -91,17 +91,21 @@ public class BackupService : IBackupService if (!_directoryService.ExistOrCreate(backupDirectory)) { _logger.LogCritical("Could not write to {BackupDirectory}; aborting backup", backupDirectory); + await _eventHub.SendMessageAsync(MessageFactory.Error, + MessageFactory.ErrorEvent("Backup Service Error",$"Could not write to {backupDirectory}; aborting backup")); return; } - await SendProgress(0F); + await SendProgress(0F, "Started backup"); var dateString = $"{DateTime.Now.ToShortDateString()}_{DateTime.Now.ToLongTimeString()}".Replace("/", "_").Replace(":", "_"); var zipPath = _directoryService.FileSystem.Path.Join(backupDirectory, $"kavita_backup_{dateString}.zip"); if (File.Exists(zipPath)) { - _logger.LogInformation("{ZipFile} already exists, aborting", zipPath); + _logger.LogCritical("{ZipFile} already exists, aborting", zipPath); + await _eventHub.SendMessageAsync(MessageFactory.Error, + MessageFactory.ErrorEvent("Backup Service Error",$"{zipPath} already exists, aborting")); return; } @@ -112,15 +116,15 @@ public class BackupService : IBackupService _directoryService.CopyFilesToDirectory( _backupFiles.Select(file => _directoryService.FileSystem.Path.Join(_directoryService.ConfigDirectory, file)).ToList(), tempDirectory); - await SendProgress(0.25F); + await SendProgress(0.25F, "Copying core files"); await CopyCoverImagesToBackupDirectory(tempDirectory); - await SendProgress(0.5F); + await SendProgress(0.5F, "Copying cover images"); await CopyBookmarksToBackupDirectory(tempDirectory); - await SendProgress(0.75F); + await SendProgress(0.75F, "Copying bookmarks"); try { @@ -133,7 +137,7 @@ public class BackupService : IBackupService _directoryService.ClearAndDeleteDirectory(tempDirectory); _logger.LogInformation("Database backup completed"); - await SendProgress(1F); + await SendProgress(1F, "Completed backup"); } private async Task CopyCoverImagesToBackupDirectory(string tempDirectory) @@ -189,10 +193,10 @@ public class BackupService : IBackupService } } - private async Task SendProgress(float progress) + private async Task SendProgress(float progress, string subtitle) { - await _messageHub.Clients.All.SendAsync(SignalREvents.BackupDatabaseProgress, - MessageFactory.BackupDatabaseProgressEvent(progress)); + await _eventHub.SendMessageAsync(MessageFactory.NotificationProgress, + MessageFactory.BackupDatabaseProgressEvent(progress, subtitle)); } } diff --git a/API/Services/Tasks/CleanupService.cs b/API/Services/Tasks/CleanupService.cs index fbb87ecd5..ee0af81cb 100644 --- a/API/Services/Tasks/CleanupService.cs +++ b/API/Services/Tasks/CleanupService.cs @@ -28,16 +28,16 @@ namespace API.Services.Tasks { private readonly ILogger _logger; private readonly IUnitOfWork _unitOfWork; - private readonly IHubContext _messageHub; + private readonly IEventHub _eventHub; private readonly IDirectoryService _directoryService; public CleanupService(ILogger logger, - IUnitOfWork unitOfWork, IHubContext messageHub, + IUnitOfWork unitOfWork, IEventHub eventHub, IDirectoryService directoryService) { _logger = logger; _unitOfWork = unitOfWork; - _messageHub = messageHub; + _eventHub = eventHub; _directoryService = directoryService; } @@ -49,25 +49,23 @@ namespace API.Services.Tasks public async Task Cleanup() { _logger.LogInformation("Starting Cleanup"); - await SendProgress(0F); + await SendProgress(0F, "Starting cleanup"); _logger.LogInformation("Cleaning temp directory"); _directoryService.ClearDirectory(_directoryService.TempDirectory); - await SendProgress(0.1F); + await SendProgress(0.1F, "Cleaning temp directory"); CleanupCacheDirectory(); - await SendProgress(0.25F); + await SendProgress(0.25F, "Cleaning old database backups"); _logger.LogInformation("Cleaning old database backups"); await CleanupBackups(); - await SendProgress(0.50F); + await SendProgress(0.50F, "Cleaning deleted cover images"); _logger.LogInformation("Cleaning deleted cover images"); await DeleteSeriesCoverImages(); - await SendProgress(0.6F); + await SendProgress(0.6F, "Cleaning deleted cover images"); await DeleteChapterCoverImages(); - await SendProgress(0.7F); + await SendProgress(0.7F, "Cleaning deleted cover images"); await DeleteTagCoverImages(); - await SendProgress(0.8F); - //_logger.LogInformation("Cleaning old bookmarks"); - //await CleanupBookmarks(); - await SendProgress(1F); + await SendProgress(0.8F, "Cleaning deleted cover images"); + await SendProgress(1F, "Cleanup finished"); _logger.LogInformation("Cleanup finished"); } @@ -82,10 +80,10 @@ namespace API.Services.Tasks await _unitOfWork.CollectionTagRepository.RemoveTagsWithoutSeries(); } - private async Task SendProgress(float progress) + private async Task SendProgress(float progress, string subtitle) { - await _messageHub.Clients.All.SendAsync(SignalREvents.CleanupProgress, - MessageFactory.CleanupProgressEvent(progress)); + await _eventHub.SendMessageAsync(MessageFactory.NotificationProgress, + MessageFactory.CleanupProgressEvent(progress, subtitle)); } /// diff --git a/API/Services/Tasks/Scanner/ParseScannedFiles.cs b/API/Services/Tasks/Scanner/ParseScannedFiles.cs index 50cb98da9..ddefd00e3 100644 --- a/API/Services/Tasks/Scanner/ParseScannedFiles.cs +++ b/API/Services/Tasks/Scanner/ParseScannedFiles.cs @@ -4,10 +4,14 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; +using System.Threading.Tasks; +using API.Data.Metadata; using API.Entities; using API.Entities.Enums; using API.Helpers; using API.Parser; +using API.SignalR; +using Microsoft.AspNetCore.SignalR; using Microsoft.Extensions.Logging; namespace API.Services.Tasks.Scanner @@ -26,6 +30,7 @@ namespace API.Services.Tasks.Scanner private readonly ILogger _logger; private readonly IDirectoryService _directoryService; private readonly IReadingItemService _readingItemService; + private readonly IEventHub _eventHub; private readonly DefaultParser _defaultParser; /// @@ -36,13 +41,14 @@ namespace API.Services.Tasks.Scanner /// Directory Service /// ReadingItemService Service for extracting information on a number of formats public ParseScannedFiles(ILogger logger, IDirectoryService directoryService, - IReadingItemService readingItemService) + IReadingItemService readingItemService, IEventHub eventHub) { _logger = logger; _directoryService = directoryService; _readingItemService = readingItemService; _scannedSeries = new ConcurrentDictionary>(); _defaultParser = new DefaultParser(_directoryService); + _eventHub = eventHub; } /// @@ -74,8 +80,6 @@ namespace API.Services.Tasks.Scanner /// Library type to determine parsing to perform private void ProcessFile(string path, string rootPath, LibraryType type) { - // TODO: Emit event with what is being processed. It can look like Kavita isn't doing anything during file scan - var info = _readingItemService.Parse(path, rootPath, type); if (info == null) { @@ -111,6 +115,17 @@ namespace API.Services.Tasks.Scanner { info.Chapters = info.ComicInfo.Number; } + + // Patch is SeriesSort from ComicInfo + if (!string.IsNullOrEmpty(info.ComicInfo.TitleSort)) + { + info.SeriesSort = info.ComicInfo.TitleSort; + } + + if (!string.IsNullOrEmpty(info.ComicInfo.SeriesSort)) + { + info.SeriesSort = info.ComicInfo.SeriesSort; + } } TrackSeries(info); @@ -138,8 +153,6 @@ namespace API.Services.Tasks.Scanner NormalizedName = Parser.Parser.Normalize(info.Series) }; - - _scannedSeries.AddOrUpdate(existingKey, new List() {info}, (_, oldValue) => { oldValue ??= new List(); @@ -177,29 +190,28 @@ namespace API.Services.Tasks.Scanner /// /// Type of library. Used for selecting the correct file extensions to search for and parsing files /// The folders to scan. By default, this should be library.Folders, however it can be overwritten to restrict folders - /// Total files scanned - /// Time it took to scan and parse files /// - public Dictionary> ScanLibrariesForSeries(LibraryType libraryType, IEnumerable folders, out int totalFiles, - out long scanElapsedTime) + public async Task>> ScanLibrariesForSeries(LibraryType libraryType, IEnumerable folders, string libraryName) { - var sw = Stopwatch.StartNew(); - totalFiles = 0; + await _eventHub.SendMessageAsync(MessageFactory.NotificationProgress, MessageFactory.FileScanProgressEvent("", libraryName, ProgressEventType.Started)); foreach (var folderPath in folders) { try { - totalFiles += _directoryService.TraverseTreeParallelForEach(folderPath, (f) => + async void Action(string f) { try { ProcessFile(f, folderPath, libraryType); + await _eventHub.SendMessageAsync(MessageFactory.NotificationProgress, MessageFactory.FileScanProgressEvent(f, libraryName, ProgressEventType.Updated)); } catch (FileNotFoundException exception) { _logger.LogError(exception, "The file {Filename} could not be found", f); } - }, Parser.Parser.SupportedExtensions, _logger); + } + + _directoryService.TraverseTreeParallelForEach(folderPath, Action, Parser.Parser.SupportedExtensions, _logger); } catch (ArgumentException ex) { @@ -207,9 +219,7 @@ namespace API.Services.Tasks.Scanner } } - scanElapsedTime = sw.ElapsedMilliseconds; - _logger.LogInformation("Scanned {TotalFiles} files in {ElapsedScanTime} milliseconds", totalFiles, - scanElapsedTime); + await _eventHub.SendMessageAsync(MessageFactory.NotificationProgress, MessageFactory.FileScanProgressEvent("", libraryName, ProgressEventType.Ended)); return SeriesWithInfos(); } diff --git a/API/Services/Tasks/ScannerService.cs b/API/Services/Tasks/ScannerService.cs index 86b819819..08c13e338 100644 --- a/API/Services/Tasks/ScannerService.cs +++ b/API/Services/Tasks/ScannerService.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; @@ -17,7 +17,6 @@ using API.Parser; using API.Services.Tasks.Scanner; using API.SignalR; using Hangfire; -using Microsoft.AspNetCore.SignalR; using Microsoft.Extensions.Logging; namespace API.Services.Tasks; @@ -39,14 +38,14 @@ public class ScannerService : IScannerService private readonly ILogger _logger; private readonly IMetadataService _metadataService; private readonly ICacheService _cacheService; - private readonly IHubContext _messageHub; + private readonly IEventHub _eventHub; private readonly IFileService _fileService; private readonly IDirectoryService _directoryService; private readonly IReadingItemService _readingItemService; private readonly ICacheHelper _cacheHelper; public ScannerService(IUnitOfWork unitOfWork, ILogger logger, - IMetadataService metadataService, ICacheService cacheService, IHubContext messageHub, + IMetadataService metadataService, ICacheService cacheService, IEventHub eventHub, IFileService fileService, IDirectoryService directoryService, IReadingItemService readingItemService, ICacheHelper cacheHelper) { @@ -54,7 +53,7 @@ public class ScannerService : IScannerService _logger = logger; _metadataService = metadataService; _cacheService = cacheService; - _messageHub = messageHub; + _eventHub = eventHub; _fileService = fileService; _directoryService = directoryService; _readingItemService = readingItemService; @@ -72,10 +71,10 @@ public class ScannerService : IScannerService var library = await _unitOfWork.LibraryRepository.GetLibraryForIdAsync(libraryId, LibraryIncludes.Folders); var folderPaths = library.Folders.Select(f => f.Path).ToList(); - // Check if any of the folder roots are not available (ie disconnected from network, etc) and fail if any of them are - if (folderPaths.Any(f => !_directoryService.IsDriveMounted(f))) + + if (!await CheckMounts(library.Name, library.Folders.Select(f => f.Path).ToList())) { - _logger.LogError("Some of the root folders for library are not accessible. Please check that drives are connected and rescan. Scan will be aborted"); + _logger.LogCritical("Some of the root folders for library are not accessible. Please check that drives are connected and rescan. Scan will be aborted"); return; } @@ -86,8 +85,9 @@ public class ScannerService : IScannerService var dirs = _directoryService.FindHighestDirectoriesFromFiles(folderPaths, files.Select(f => f.FilePath).ToList()); _logger.LogInformation("Beginning file scan on {SeriesName}", series.Name); - var scanner = new ParseScannedFiles(_logger, _directoryService, _readingItemService); - var parsedSeries = scanner.ScanLibrariesForSeries(library.Type, dirs.Keys, out var totalFiles, out var scanElapsedTime); + var (totalFiles, scanElapsedTime, parsedSeries) = await ScanFiles(library, dirs.Keys); + + // Remove any parsedSeries keys that don't belong to our series. This can occur when users store 2 series in the same folder RemoveParsedInfosNotForSeries(parsedSeries, series); @@ -133,11 +133,11 @@ public class ScannerService : IScannerService } } + var (totalFiles2, scanElapsedTime2, parsedSeries2) = await ScanFiles(library, dirs.Keys); _logger.LogInformation("{SeriesName} has bad naming convention, forcing rescan at a higher directory", series.OriginalName); - scanner = new ParseScannedFiles(_logger, _directoryService, _readingItemService); - parsedSeries = scanner.ScanLibrariesForSeries(library.Type, dirs.Keys, out var totalFiles2, out var scanElapsedTime2); totalFiles += totalFiles2; scanElapsedTime += scanElapsedTime2; + parsedSeries = parsedSeries2; RemoveParsedInfosNotForSeries(parsedSeries, series); } } @@ -148,9 +148,12 @@ public class ScannerService : IScannerService // Merge any series together that might have different ParsedSeries but belong to another group of ParsedSeries try { - UpdateSeries(series, parsedSeries, allPeople, allTags, allGenres, library.Type); + await _eventHub.SendMessageAsync(MessageFactory.NotificationProgress, MessageFactory.LibraryScanProgressEvent(library.Name, ProgressEventType.Started, series.Name)); + await UpdateSeries(series, parsedSeries, allPeople, allTags, allGenres, library); + await _eventHub.SendMessageAsync(MessageFactory.NotificationProgress, MessageFactory.LibraryScanProgressEvent(library.Name, ProgressEventType.Ended, series.Name)); await CommitAndSend(totalFiles, parsedSeries, sw, scanElapsedTime, series); + await RemoveAbandonedMetadataKeys(); } catch (Exception ex) { @@ -158,7 +161,8 @@ public class ScannerService : IScannerService await _unitOfWork.RollbackAsync(); } // Tell UI that this series is done - await _messageHub.Clients.All.SendAsync(SignalREvents.ScanSeries, MessageFactory.ScanSeriesEvent(seriesId, series.Name), token); + await _eventHub.SendMessageAsync(MessageFactory.ScanSeries, + MessageFactory.ScanSeriesEvent(libraryId, seriesId, series.Name)); await CleanupDbEntities(); BackgroundJob.Enqueue(() => _cacheService.CleanupChapters(chapterIds)); BackgroundJob.Enqueue(() => _metadataService.RefreshMetadataForSeries(libraryId, series.Id, false)); @@ -186,6 +190,43 @@ public class ScannerService : IScannerService } } + private async Task CheckMounts(string libraryName, IList folders) + { + // Check if any of the folder roots are not available (ie disconnected from network, etc) and fail if any of them are + if (folders.Any(f => !_directoryService.IsDriveMounted(f))) + { + _logger.LogError("Some of the root folders for library ({LibraryName} are not accessible. Please check that drives are connected and rescan. Scan will be aborted", libraryName); + + await _eventHub.SendMessageAsync(MessageFactory.Error, + MessageFactory.ErrorEvent("Some of the root folders for library are not accessible. Please check that drives are connected and rescan. Scan will be aborted", + string.Join(", ", folders.Where(f => !_directoryService.IsDriveMounted(f))))); + + return false; + } + + + // For Docker instances check if any of the folder roots are not available (ie disconnected volumes, etc) and fail if any of them are + if (folders.Any(f => _directoryService.IsDirectoryEmpty(f))) + { + // NOTE: Food for thought, move this to throw an exception and let a middleware inform the UI to keep the code clean. (We can throw a custom exception which + // will always propagate to the UI) + // That way logging and UI informing is all in one place with full context + _logger.LogError("Some of the root folders for the library are empty. " + + "Either your mount has been disconnected or you are trying to delete all series in the library. " + + "Scan will be aborted. " + + "Check that your mount is connected or change the library's root folder and rescan"); + + await _eventHub.SendMessageAsync(MessageFactory.Error, MessageFactory.ErrorEvent( $"Some of the root folders for the library, {libraryName}, are empty.", + "Either your mount has been disconnected or you are trying to delete all series in the library. " + + "Scan will be aborted. " + + "Check that your mount is connected or change the library's root folder and rescan")); + + return false; + } + + return true; + } + [DisableConcurrentExecution(timeoutInSeconds: 360)] [AutomaticRetry(Attempts = 0, OnAttemptsExceeded = AttemptsExceededAction.Delete)] @@ -223,33 +264,21 @@ public class ScannerService : IScannerService return; } - // Check if any of the folder roots are not available (ie disconnected from network, etc) and fail if any of them are - if (library.Folders.Any(f => !_directoryService.IsDriveMounted(f.Path))) + if (!await CheckMounts(library.Name, library.Folders.Select(f => f.Path).ToList())) { _logger.LogCritical("Some of the root folders for library are not accessible. Please check that drives are connected and rescan. Scan will be aborted"); - await _messageHub.Clients.All.SendAsync(SignalREvents.ScanLibraryProgress, - MessageFactory.ScanLibraryProgressEvent(libraryId, 1F)); return; } - // For Docker instances check if any of the folder roots are not available (ie disconnected volumes, etc) and fail if any of them are - if (library.Folders.Any(f => _directoryService.IsDirectoryEmpty(f.Path))) - { - _logger.LogCritical("Some of the root folders for the library are empty. " + - "Either your mount has been disconnected or you are trying to delete all series in the library. " + - "Scan will be aborted. " + - "Check that your mount is connected or change the library's root folder and rescan"); - await _messageHub.Clients.All.SendAsync(SignalREvents.ScanLibraryProgress, - MessageFactory.ScanLibraryProgressEvent(libraryId, 1F)); - return; - } _logger.LogInformation("[ScannerService] Beginning file scan on {LibraryName}", library.Name); - await _messageHub.Clients.All.SendAsync(SignalREvents.ScanLibraryProgress, - MessageFactory.ScanLibraryProgressEvent(libraryId, 0)); + // await _eventHub.SendMessageAsync(SignalREvents.NotificationProgress, + // MessageFactory.ScanLibraryProgressEvent(libraryId, 0F)); - var scanner = new ParseScannedFiles(_logger, _directoryService, _readingItemService); - var series = scanner.ScanLibrariesForSeries(library.Type, library.Folders.Select(fp => fp.Path), out var totalFiles, out var scanElapsedTime); + + var (totalFiles, scanElapsedTime, series) = await ScanFiles(library, library.Folders.Select(fp => fp.Path)); + // var scanner = new ParseScannedFiles(_logger, _directoryService, _readingItemService); + // var series = scanner.ScanLibrariesForSeries(library.Type, library.Folders.Select(fp => fp.Path), out var totalFiles, out var scanElapsedTime); _logger.LogInformation("[ScannerService] Finished file scan. Updating database"); foreach (var folderPath in library.Folders) @@ -265,7 +294,7 @@ public class ScannerService : IScannerService if (await _unitOfWork.CommitAsync()) { _logger.LogInformation( - "[ScannerService] Processed {TotalFiles} files and {ParsedSeriesCount} series in {ElapsedScanTime} milliseconds for {LibraryName}", + "[ScannerService] Finished scan of {TotalFiles} files and {ParsedSeriesCount} series in {ElapsedScanTime} milliseconds for {LibraryName}", totalFiles, series.Keys.Count, sw.ElapsedMilliseconds + scanElapsedTime, library.Name); } else @@ -276,11 +305,22 @@ public class ScannerService : IScannerService await CleanupDbEntities(); - await _messageHub.Clients.All.SendAsync(SignalREvents.ScanLibraryProgress, - MessageFactory.ScanLibraryProgressEvent(libraryId, 1F)); + // await _eventHub.SendMessageAsync(SignalREvents.NotificationProgress, + // MessageFactory.ScanLibraryProgressEvent(libraryId, 1F)); BackgroundJob.Enqueue(() => _metadataService.RefreshMetadata(libraryId, false)); } + private async Task>>> ScanFiles(Library library, IEnumerable dirs) + { + var scanner = new ParseScannedFiles(_logger, _directoryService, _readingItemService, _eventHub); + var scanWatch = new Stopwatch(); + var parsedSeries = await scanner.ScanLibrariesForSeries(library.Type, dirs, library.Name); + var totalFiles = parsedSeries.Keys.Sum(key => parsedSeries[key].Count); + var scanElapsedTime = scanWatch.ElapsedMilliseconds; + + return new Tuple>>(totalFiles, scanElapsedTime, parsedSeries); + } + /// /// Remove any user progress rows that no longer exist since scan library ran and deleted series/volumes/chapters /// @@ -350,10 +390,12 @@ public class ScannerService : IScannerService // Now, we only have to deal with series that exist on disk. Let's recalculate the volumes for each series var librarySeries = cleanedSeries.ToList(); - Parallel.ForEach(librarySeries, (series) => + + foreach (var series in librarySeries) { - UpdateSeries(series, parsedSeries, allPeople, allTags, allGenres, library.Type); - }); + await _eventHub.SendMessageAsync(MessageFactory.NotificationProgress, MessageFactory.LibraryScanProgressEvent(library.Name, ProgressEventType.Started, series.Name)); + await UpdateSeries(series, parsedSeries, allPeople, allTags, allGenres, library); + } try { @@ -361,13 +403,16 @@ public class ScannerService : IScannerService } catch (Exception ex) { - _logger.LogCritical(ex, "[ScannerService] There was an issue writing to the DB. Chunk {ChunkNumber} did not save to DB. If debug mode, series to check will be printed", chunk); + _logger.LogCritical(ex, "[ScannerService] There was an issue writing to the DB. Chunk {ChunkNumber} did not save to DB", chunk); foreach (var series in nonLibrarySeries) { - _logger.LogDebug("[ScannerService] There may be a constraint issue with {SeriesName}", series.OriginalName); + _logger.LogCritical("[ScannerService] There may be a constraint issue with {SeriesName}", series.OriginalName); } - await _messageHub.Clients.All.SendAsync(SignalREvents.ScanLibraryError, - MessageFactory.ScanLibraryError(library.Id)); + + await _eventHub.SendMessageAsync(MessageFactory.Error, + MessageFactory.ErrorEvent("There was an issue writing to the DB. Chunk {ChunkNumber} did not save to DB", + "The following series had constraint issues: " + string.Join(",", nonLibrarySeries.Select(s => s.OriginalName)))); + continue; } _logger.LogInformation( @@ -377,17 +422,14 @@ public class ScannerService : IScannerService // Emit any series removed foreach (var missing in missingSeries) { - await _messageHub.Clients.All.SendAsync(SignalREvents.SeriesRemoved, MessageFactory.SeriesRemovedEvent(missing.Id, missing.Name, library.Id)); + await _eventHub.SendMessageAsync(MessageFactory.SeriesRemoved, MessageFactory.SeriesRemovedEvent(missing.Id, missing.Name, library.Id)); } foreach (var series in librarySeries) { - await _messageHub.Clients.All.SendAsync(SignalREvents.ScanSeries, MessageFactory.ScanSeriesEvent(series.Id, series.Name)); + // This is something more like, the series has finished updating in the backend. It may or may not have been modified. + await _eventHub.SendMessageAsync(MessageFactory.ScanSeries, MessageFactory.ScanSeriesEvent(library.Id, series.Id, series.Name)); } - - var progress = Math.Max(0, Math.Min(1, ((chunk + 1F) * chunkInfo.ChunkSize) / chunkInfo.TotalSize)); - await _messageHub.Clients.All.SendAsync(SignalREvents.ScanLibraryProgress, - MessageFactory.ScanLibraryProgressEvent(library.Id, progress)); } @@ -397,6 +439,7 @@ public class ScannerService : IScannerService var allSeries = (await _unitOfWork.SeriesRepository.GetSeriesForLibraryIdAsync(library.Id)).ToList(); _logger.LogDebug("[ScannerService] Fetched {AllSeriesCount} series for comparing new series with. There should be {DeltaToParsedSeries} new series", allSeries.Count, parsedSeries.Count - allSeries.Count); + // TODO: Once a parsedSeries is processed, remove the key to free up some memory foreach (var (key, infos) in parsedSeries) { // Key is normalized already @@ -431,11 +474,10 @@ public class ScannerService : IScannerService } - var i = 0; foreach(var series in newSeries) { _logger.LogDebug("[ScannerService] Processing series {SeriesName}", series.OriginalName); - UpdateSeries(series, parsedSeries, allPeople, allTags, allGenres, library.Type); + await UpdateSeries(series, parsedSeries, allPeople, allTags, allGenres, library); _unitOfWork.SeriesRepository.Attach(series); try { @@ -445,31 +487,29 @@ public class ScannerService : IScannerService newSeries.Count, stopwatch.ElapsedMilliseconds, library.Name); // Inform UI of new series added - await _messageHub.Clients.All.SendAsync(SignalREvents.SeriesAdded, MessageFactory.SeriesAddedEvent(series.Id, series.Name, library.Id)); + await _eventHub.SendMessageAsync(MessageFactory.SeriesAdded, MessageFactory.SeriesAddedEvent(series.Id, series.Name, library.Id)); } catch (Exception ex) { _logger.LogCritical(ex, "[ScannerService] There was a critical exception adding new series entry for {SeriesName} with a duplicate index key: {IndexKey} ", series.Name, $"{series.Name}_{series.NormalizedName}_{series.LocalizedName}_{series.LibraryId}_{series.Format}"); } - - var progress = Math.Max(0F, Math.Min(1F, i * 1F / newSeries.Count)); - await _messageHub.Clients.All.SendAsync(SignalREvents.ScanLibraryProgress, - MessageFactory.ScanLibraryProgressEvent(library.Id, progress)); - i++; } + await _eventHub.SendMessageAsync(MessageFactory.NotificationProgress, MessageFactory.LibraryScanProgressEvent(library.Name, ProgressEventType.Ended)); + _logger.LogInformation( "[ScannerService] Added {NewSeries} series in {ElapsedScanTime} milliseconds for {LibraryName}", newSeries.Count, stopwatch.ElapsedMilliseconds, library.Name); } - private void UpdateSeries(Series series, Dictionary> parsedSeries, - ICollection allPeople, ICollection allTags, ICollection allGenres, LibraryType libraryType) + private async Task UpdateSeries(Series series, Dictionary> parsedSeries, + ICollection allPeople, ICollection allTags, ICollection allGenres, Library library) { try { _logger.LogInformation("[ScannerService] Processing series {SeriesName}", series.OriginalName); + await _eventHub.SendMessageAsync(MessageFactory.NotificationProgress, MessageFactory.LibraryScanProgressEvent(library.Name, ProgressEventType.Ended, series.Name)); // Get all associated ParsedInfos to the series. This includes infos that use a different filename that matches Series LocalizedName var parsedInfos = ParseScannedFiles.GetInfosByName(parsedSeries, series); @@ -483,14 +523,18 @@ public class ScannerService : IScannerService series.Format = parsedInfos[0].Format; } series.OriginalName ??= parsedInfos[0].Series; - series.SortName ??= parsedInfos[0].SeriesSort; + if (!series.SortNameLocked) series.SortName = parsedInfos[0].SeriesSort; - UpdateSeriesMetadata(series, allPeople, allGenres, allTags, libraryType); + await _eventHub.SendMessageAsync(MessageFactory.NotificationProgress, MessageFactory.LibraryScanProgressEvent(library.Name, ProgressEventType.Ended, series.Name)); + + UpdateSeriesMetadata(series, allPeople, allGenres, allTags, library.Type); } catch (Exception ex) { _logger.LogError(ex, "[ScannerService] There was an exception updating volumes for {SeriesName}", series.Name); } + + await _eventHub.SendMessageAsync(MessageFactory.NotificationProgress, MessageFactory.LibraryScanProgressEvent(library.Name, ProgressEventType.Ended, series.Name)); } public static IEnumerable FindSeriesNotOnDisk(IEnumerable existingSeries, Dictionary> parsedSeries) @@ -498,6 +542,13 @@ public class ScannerService : IScannerService return existingSeries.Where(es => !ParserInfoHelpers.SeriesHasMatchingParserInfoFormat(es, parsedSeries)); } + private async Task RemoveAbandonedMetadataKeys() + { + await _unitOfWork.TagRepository.RemoveAllTagNoLongerAssociated(); + await _unitOfWork.PersonRepository.RemoveAllPeopleNoLongerAssociated(); + await _unitOfWork.GenreRepository.RemoveAllGenreNoLongerAssociated(); + } + private static void UpdateSeriesMetadata(Series series, ICollection allPeople, ICollection allGenres, ICollection allTags, LibraryType libraryType) { @@ -521,65 +572,116 @@ public class ScannerService : IScannerService } // Set the AgeRating as highest in all the comicInfos - series.Metadata.AgeRating = chapters.Max(chapter => chapter.AgeRating); + if (!series.Metadata.AgeRatingLocked) series.Metadata.AgeRating = chapters.Max(chapter => chapter.AgeRating); series.Metadata.Count = chapters.Max(chapter => chapter.TotalCount); - series.Metadata.PublicationStatus = PublicationStatus.OnGoing; - if (chapters.Max(chapter => chapter.Count) >= series.Metadata.Count && series.Metadata.Count > 0) + if (!series.Metadata.PublicationStatusLocked) { - series.Metadata.PublicationStatus = PublicationStatus.Completed; + series.Metadata.PublicationStatus = PublicationStatus.OnGoing; + if (chapters.Max(chapter => chapter.Count) >= series.Metadata.Count && series.Metadata.Count > 0) + { + series.Metadata.PublicationStatus = PublicationStatus.Completed; + } } - if (!string.IsNullOrEmpty(firstChapter.Summary)) + if (!string.IsNullOrEmpty(firstChapter.Summary) && !series.Metadata.SummaryLocked) { series.Metadata.Summary = firstChapter.Summary; } - if (!string.IsNullOrEmpty(firstChapter.Language)) + if (!string.IsNullOrEmpty(firstChapter.Language) && !series.Metadata.LanguageLocked) { series.Metadata.Language = firstChapter.Language; } + void HandleAddPerson(Person person) + { + PersonHelper.AddPersonIfNotExists(series.Metadata.People, person); + allPeople.Add(person); + } + // Handle People foreach (var chapter in chapters) { - PersonHelper.UpdatePeople(allPeople, chapter.People.Where(p => p.Role == PersonRole.Writer).Select(p => p.Name), PersonRole.Writer, - person => PersonHelper.AddPersonIfNotExists(series.Metadata.People, person)); + if (!series.Metadata.WriterLocked) + { + PersonHelper.UpdatePeople(allPeople, chapter.People.Where(p => p.Role == PersonRole.Writer).Select(p => p.Name), PersonRole.Writer, + HandleAddPerson); + } - PersonHelper.UpdatePeople(allPeople, chapter.People.Where(p => p.Role == PersonRole.CoverArtist).Select(p => p.Name), PersonRole.CoverArtist, - person => PersonHelper.AddPersonIfNotExists(series.Metadata.People, person)); + if (!series.Metadata.CoverArtistLocked) + { + PersonHelper.UpdatePeople(allPeople, chapter.People.Where(p => p.Role == PersonRole.CoverArtist).Select(p => p.Name), PersonRole.CoverArtist, + HandleAddPerson); + } - PersonHelper.UpdatePeople(allPeople, chapter.People.Where(p => p.Role == PersonRole.Publisher).Select(p => p.Name), PersonRole.Publisher, - person => PersonHelper.AddPersonIfNotExists(series.Metadata.People, person)); + if (!series.Metadata.PublisherLocked) + { + PersonHelper.UpdatePeople(allPeople, chapter.People.Where(p => p.Role == PersonRole.Publisher).Select(p => p.Name), PersonRole.Publisher, + HandleAddPerson); + } - PersonHelper.UpdatePeople(allPeople, chapter.People.Where(p => p.Role == PersonRole.Character).Select(p => p.Name), PersonRole.Character, - person => PersonHelper.AddPersonIfNotExists(series.Metadata.People, person)); + if (!series.Metadata.CharacterLocked) + { + PersonHelper.UpdatePeople(allPeople, chapter.People.Where(p => p.Role == PersonRole.Character).Select(p => p.Name), PersonRole.Character, + HandleAddPerson); + } - PersonHelper.UpdatePeople(allPeople, chapter.People.Where(p => p.Role == PersonRole.Colorist).Select(p => p.Name), PersonRole.Colorist, - person => PersonHelper.AddPersonIfNotExists(series.Metadata.People, person)); + if (!series.Metadata.ColoristLocked) + { + PersonHelper.UpdatePeople(allPeople, chapter.People.Where(p => p.Role == PersonRole.Colorist).Select(p => p.Name), PersonRole.Colorist, + HandleAddPerson); + } - PersonHelper.UpdatePeople(allPeople, chapter.People.Where(p => p.Role == PersonRole.Editor).Select(p => p.Name), PersonRole.Editor, - person => PersonHelper.AddPersonIfNotExists(series.Metadata.People, person)); + if (!series.Metadata.EditorLocked) + { + PersonHelper.UpdatePeople(allPeople, chapter.People.Where(p => p.Role == PersonRole.Editor).Select(p => p.Name), PersonRole.Editor, + HandleAddPerson); + } - PersonHelper.UpdatePeople(allPeople, chapter.People.Where(p => p.Role == PersonRole.Inker).Select(p => p.Name), PersonRole.Inker, - person => PersonHelper.AddPersonIfNotExists(series.Metadata.People, person)); + if (!series.Metadata.InkerLocked) + { + PersonHelper.UpdatePeople(allPeople, chapter.People.Where(p => p.Role == PersonRole.Inker).Select(p => p.Name), PersonRole.Inker, + HandleAddPerson); + } - PersonHelper.UpdatePeople(allPeople, chapter.People.Where(p => p.Role == PersonRole.Letterer).Select(p => p.Name), PersonRole.Letterer, - person => PersonHelper.AddPersonIfNotExists(series.Metadata.People, person)); + if (!series.Metadata.LettererLocked) + { + PersonHelper.UpdatePeople(allPeople, chapter.People.Where(p => p.Role == PersonRole.Letterer).Select(p => p.Name), PersonRole.Letterer, + HandleAddPerson); + } - PersonHelper.UpdatePeople(allPeople, chapter.People.Where(p => p.Role == PersonRole.Penciller).Select(p => p.Name), PersonRole.Penciller, - person => PersonHelper.AddPersonIfNotExists(series.Metadata.People, person)); + if (!series.Metadata.PencillerLocked) + { + PersonHelper.UpdatePeople(allPeople, chapter.People.Where(p => p.Role == PersonRole.Penciller).Select(p => p.Name), PersonRole.Penciller, + HandleAddPerson); + } - PersonHelper.UpdatePeople(allPeople, chapter.People.Where(p => p.Role == PersonRole.Translator).Select(p => p.Name), PersonRole.Translator, - person => PersonHelper.AddPersonIfNotExists(series.Metadata.People, person)); + if (!series.Metadata.TranslatorLocked) + { + PersonHelper.UpdatePeople(allPeople, chapter.People.Where(p => p.Role == PersonRole.Translator).Select(p => p.Name), PersonRole.Translator, + HandleAddPerson); + } - TagHelper.UpdateTag(allTags, chapter.Tags.Select(t => t.Title), false, (tag, _) => - TagHelper.AddTagIfNotExists(series.Metadata.Tags, tag)); + if (!series.Metadata.TagsLocked) + { + TagHelper.UpdateTag(allTags, chapter.Tags.Select(t => t.Title), false, (tag, _) => + { + TagHelper.AddTagIfNotExists(series.Metadata.Tags, tag); + allTags.Add(tag); + }); + } - GenreHelper.UpdateGenre(allGenres, chapter.Genres.Select(t => t.Title), false, genre => - GenreHelper.AddGenreIfNotExists(series.Metadata.Genres, genre)); + if (!series.Metadata.GenresLocked) + { + GenreHelper.UpdateGenre(allGenres, chapter.Genres.Select(t => t.Title), false, genre => + { + GenreHelper.AddGenreIfNotExists(series.Metadata.Genres, genre); + allGenres.Add(genre); + }); + } } var people = chapters.SelectMany(c => c.People).ToList(); @@ -782,9 +884,9 @@ public class ScannerService : IScannerService chapter.TotalCount = comicInfo.Count; } - if (!string.IsNullOrEmpty(comicInfo.Number) && int.Parse(comicInfo.Number) > 0) + if (!string.IsNullOrEmpty(comicInfo.Number) && float.Parse(comicInfo.Number) > 0) { - chapter.Count = int.Parse(comicInfo.Number); + chapter.Count = (int) Math.Floor(float.Parse(comicInfo.Number)); } diff --git a/API/Services/Tasks/SiteThemeService.cs b/API/Services/Tasks/SiteThemeService.cs new file mode 100644 index 000000000..e0e1bc2d8 --- /dev/null +++ b/API/Services/Tasks/SiteThemeService.cs @@ -0,0 +1,169 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using API.Data; +using API.Entities; +using API.Entities.Enums.Theme; +using API.SignalR; +using Kavita.Common; +using Microsoft.AspNetCore.SignalR; + +namespace API.Services.Tasks; + +public interface ISiteThemeService +{ + Task GetContent(int themeId); + Task Scan(); + Task UpdateDefault(int themeId); +} + +public class SiteThemeService : ISiteThemeService +{ + private readonly IDirectoryService _directoryService; + private readonly IUnitOfWork _unitOfWork; + private readonly IEventHub _eventHub; + + public SiteThemeService(IDirectoryService directoryService, IUnitOfWork unitOfWork, IEventHub eventHub) + { + _directoryService = directoryService; + _unitOfWork = unitOfWork; + _eventHub = eventHub; + } + + /// + /// Given a themeId, return the content inside that file + /// + /// + /// + /// + public async Task GetContent(int themeId) + { + var theme = await _unitOfWork.SiteThemeRepository.GetThemeDto(themeId); + if (theme == null) throw new KavitaException("Theme file missing or invalid"); + var themeFile = _directoryService.FileSystem.Path.Join(_directoryService.SiteThemeDirectory, theme.FileName); + if (string.IsNullOrEmpty(themeFile) || !_directoryService.FileSystem.File.Exists(themeFile)) + throw new KavitaException("Theme file missing or invalid"); + + return await _directoryService.FileSystem.File.ReadAllTextAsync(themeFile); + } + + /// + /// Scans the site theme directory for custom css files and updates what the system has on store + /// + public async Task Scan() + { + _directoryService.ExistOrCreate(_directoryService.SiteThemeDirectory); + var reservedNames = Seed.DefaultThemes.Select(t => t.NormalizedName).ToList(); + var themeFiles = _directoryService.GetFilesWithExtension(Parser.Parser.NormalizePath(_directoryService.SiteThemeDirectory), @"\.css") + .Where(name => !reservedNames.Contains(Parser.Parser.Normalize(name))).ToList(); + + var allThemes = (await _unitOfWork.SiteThemeRepository.GetThemes()).ToList(); + + // First remove any files from allThemes that are User Defined and not on disk + var userThemes = allThemes.Where(t => t.Provider == ThemeProvider.User).ToList(); + foreach (var userTheme in userThemes) + { + var filepath = Parser.Parser.NormalizePath( + _directoryService.FileSystem.Path.Join(_directoryService.SiteThemeDirectory, userTheme.FileName)); + if (_directoryService.FileSystem.File.Exists(filepath)) continue; + + // I need to do the removal different. I need to update all user preferences to use DefaultTheme + allThemes.Remove(userTheme); + await RemoveTheme(userTheme); + } + + // Add new custom themes + var allThemeNames = allThemes.Select(t => t.NormalizedName).ToList(); + foreach (var themeFile in themeFiles) + { + var themeName = + Parser.Parser.Normalize(_directoryService.FileSystem.Path.GetFileNameWithoutExtension(themeFile)); + if (allThemeNames.Contains(themeName)) continue; + + _unitOfWork.SiteThemeRepository.Add(new SiteTheme() + { + Name = _directoryService.FileSystem.Path.GetFileNameWithoutExtension(themeFile), + NormalizedName = themeName, + FileName = _directoryService.FileSystem.Path.GetFileName(themeFile), + Provider = ThemeProvider.User, + IsDefault = false, + }); + + await _eventHub.SendMessageAsync(MessageFactory.NotificationProgress, + MessageFactory.SiteThemeProgressEvent(_directoryService.FileSystem.Path.GetFileName(themeFile), themeName, ProgressEventType.Updated)); + } + + + if (_unitOfWork.HasChanges()) + { + await _unitOfWork.CommitAsync(); + } + + // if there are no default themes, reselect Dark as default + var postSaveThemes = (await _unitOfWork.SiteThemeRepository.GetThemes()).ToList(); + if (!postSaveThemes.Any(t => t.IsDefault)) + { + var defaultThemeName = Seed.DefaultThemes.Single(t => t.IsDefault).NormalizedName; + var theme = postSaveThemes.SingleOrDefault(t => t.NormalizedName == defaultThemeName); + if (theme != null) + { + theme.IsDefault = true; + _unitOfWork.SiteThemeRepository.Update(theme); + await _unitOfWork.CommitAsync(); + } + + } + + await _eventHub.SendMessageAsync(MessageFactory.NotificationProgress, + MessageFactory.SiteThemeProgressEvent("", "", ProgressEventType.Ended)); + + } + + /// + /// Removes the theme and any references to it from Pref and sets them to the default at the time. + /// This commits to DB. + /// + /// + private async Task RemoveTheme(SiteTheme theme) + { + var prefs = await _unitOfWork.UserRepository.GetAllPreferencesByThemeAsync(theme.Id); + var defaultTheme = await _unitOfWork.SiteThemeRepository.GetDefaultTheme(); + foreach (var pref in prefs) + { + pref.Theme = defaultTheme; + _unitOfWork.UserRepository.Update(pref); + } + _unitOfWork.SiteThemeRepository.Remove(theme); + await _unitOfWork.CommitAsync(); + } + + /// + /// Updates the themeId to the default theme, all others are marked as non-default + /// + /// + /// + /// If theme does not exist + public async Task UpdateDefault(int themeId) + { + try + { + var theme = await _unitOfWork.SiteThemeRepository.GetThemeDto(themeId); + if (theme == null) throw new KavitaException("Theme file missing or invalid"); + + foreach (var siteTheme in await _unitOfWork.SiteThemeRepository.GetThemes()) + { + siteTheme.IsDefault = (siteTheme.Id == themeId); + _unitOfWork.SiteThemeRepository.Update(siteTheme); + } + + if (!_unitOfWork.HasChanges()) return; + await _unitOfWork.CommitAsync(); + } + catch (Exception) + { + await _unitOfWork.RollbackAsync(); + throw; + } + } +} diff --git a/API/Services/Tasks/StatsService.cs b/API/Services/Tasks/StatsService.cs index 298b8f2b7..831e8f3a0 100644 --- a/API/Services/Tasks/StatsService.cs +++ b/API/Services/Tasks/StatsService.cs @@ -5,6 +5,7 @@ using System.Runtime.InteropServices; using System.Threading.Tasks; using API.Data; using API.DTOs.Stats; +using API.DTOs.Theme; using API.Entities.Enums; using Flurl.Http; using Kavita.Common.EnvironmentInfo; @@ -99,18 +100,36 @@ public class StatsService : IStatsService public async Task GetServerInfo() { var installId = await _unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.InstallId); + var installVersion = await _unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.InstallVersion); + var serverInfo = new ServerInfoDto { InstallId = installId.Value, Os = RuntimeInformation.OSDescription, - KavitaVersion = BuildInfo.Version.ToString(), + KavitaVersion = installVersion.Value, DotnetVersion = Environment.Version.ToString(), IsDocker = new OsInfo(Array.Empty()).IsDocker, NumOfCores = Math.Max(Environment.ProcessorCount, 1), HasBookmarks = (await _unitOfWork.UserRepository.GetAllBookmarksAsync()).Any(), - NumberOfLibraries = (await _unitOfWork.LibraryRepository.GetLibrariesAsync()).Count() + NumberOfLibraries = (await _unitOfWork.LibraryRepository.GetLibrariesAsync()).Count(), + NumberOfCollections = (await _unitOfWork.CollectionTagRepository.GetAllTagsAsync()).Count(), + NumberOfReadingLists = await _unitOfWork.ReadingListRepository.Count(), + OPDSEnabled = (await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).EnableOpds, + NumberOfUsers = (await _unitOfWork.UserRepository.GetAllUsers()).Count(), + TotalFiles = await _unitOfWork.LibraryRepository.GetTotalFiles(), }; + var firstAdminUser = (await _unitOfWork.UserRepository.GetAdminUsersAsync()).FirstOrDefault(); + + if (firstAdminUser != null) + { + var firstAdminUserPref = (await _unitOfWork.UserRepository.GetPreferencesAsync(firstAdminUser.UserName)); + var activeTheme = firstAdminUserPref.Theme ?? Seed.DefaultThemes.First(t => t.IsDefault); + + serverInfo.ActiveSiteTheme = activeTheme.Name; + serverInfo.MangaReaderMode = firstAdminUserPref.ReaderMode; + } + return serverInfo; } } diff --git a/API/Services/Tasks/VersionUpdaterService.cs b/API/Services/Tasks/VersionUpdaterService.cs index 255d0b105..d72f487b4 100644 --- a/API/Services/Tasks/VersionUpdaterService.cs +++ b/API/Services/Tasks/VersionUpdaterService.cs @@ -53,7 +53,7 @@ public interface IVersionUpdaterService public class VersionUpdaterService : IVersionUpdaterService { private readonly ILogger _logger; - private readonly IHubContext _messageHub; + private readonly IEventHub _eventHub; private readonly IPresenceTracker _tracker; private readonly Markdown _markdown = new MarkdownDeep.Markdown(); #pragma warning disable S1075 @@ -61,10 +61,10 @@ public class VersionUpdaterService : IVersionUpdaterService private const string GithubAllReleasesUrl = "https://api.github.com/repos/Kareadita/Kavita/releases"; #pragma warning restore S1075 - public VersionUpdaterService(ILogger logger, IHubContext messageHub, IPresenceTracker tracker) + public VersionUpdaterService(ILogger logger, IEventHub eventHub, IPresenceTracker tracker) { _logger = logger; - _messageHub = messageHub; + _eventHub = eventHub; _tracker = tracker; FlurlHttp.ConfigureClient(GithubLatestReleasesUrl, cli => @@ -117,26 +117,22 @@ public class VersionUpdaterService : IVersionUpdaterService { if (update == null) return; - var admins = await _tracker.GetOnlineAdmins(); var updateVersion = new Version(update.CurrentVersion); if (BuildInfo.Version < updateVersion) { _logger.LogInformation("Server is out of date. Current: {CurrentVersion}. Available: {AvailableUpdate}", BuildInfo.Version, updateVersion); - await SendEvent(update, admins); + await _eventHub.SendMessageAsync(MessageFactory.UpdateAvailable, MessageFactory.UpdateVersionEvent(update), + true); } else if (Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == Environments.Development) { _logger.LogInformation("Server is up to date. Current: {CurrentVersion}", BuildInfo.Version); - await SendEvent(update, admins); + await _eventHub.SendMessageAsync(MessageFactory.UpdateAvailable, MessageFactory.UpdateVersionEvent(update), + true); } } - private async Task SendEvent(UpdateNotificationDto update, IReadOnlyList admins) - { - await _messageHub.Clients.Users(admins).SendAsync(SignalREvents.UpdateAvailable, MessageFactory.UpdateVersionEvent(update)); - } - private static async Task GetGithubRelease() { diff --git a/API/SignalR/EventHub.cs b/API/SignalR/EventHub.cs new file mode 100644 index 000000000..fa92d9ec7 --- /dev/null +++ b/API/SignalR/EventHub.cs @@ -0,0 +1,44 @@ +using System.Threading.Tasks; +using API.Data; +using API.SignalR.Presence; +using Microsoft.AspNetCore.SignalR; + +namespace API.SignalR; + +/// +/// Responsible for ushering events to the UI and allowing simple DI hook to send data +/// +public interface IEventHub +{ + Task SendMessageAsync(string method, SignalRMessage message, bool onlyAdmins = true); +} + +public class EventHub : IEventHub +{ + private readonly IHubContext _messageHub; + private readonly IPresenceTracker _presenceTracker; + private readonly IUnitOfWork _unitOfWork; + + public EventHub(IHubContext messageHub, IPresenceTracker presenceTracker, IUnitOfWork unitOfWork) + { + _messageHub = messageHub; + _presenceTracker = presenceTracker; + _unitOfWork = unitOfWork; + + // TODO: When sending a message, queue the message up and on re-connect, reply the queued messages. Queue messages expire on a rolling basis (rolling array) + } + + public async Task SendMessageAsync(string method, SignalRMessage message, bool onlyAdmins = true) + { + // TODO: If libraryId and NOT onlyAdmins, then perform RBS check before sending the event + + var users = _messageHub.Clients.All; + if (onlyAdmins) + { + var admins = await _presenceTracker.GetOnlineAdmins(); + _messageHub.Clients.Users(admins); + } + + await users.SendAsync(method, message); + } +} diff --git a/API/SignalR/MessageFactory.cs b/API/SignalR/MessageFactory.cs index bf7c649bf..485a2fc37 100644 --- a/API/SignalR/MessageFactory.cs +++ b/API/SignalR/MessageFactory.cs @@ -1,17 +1,94 @@ using System; +using System.Diagnostics; +using System.IO; +using System.Threading; using API.DTOs.Update; +using API.Entities; namespace API.SignalR { public static class MessageFactory { - public static SignalRMessage ScanSeriesEvent(int seriesId, string seriesName) + /// + /// An update is available for the Kavita instance + /// + public const string UpdateAvailable = "UpdateAvailable"; + /// + /// Used to tell when a scan series completes. This also informs UI to update series metadata + /// + public const string ScanSeries = "ScanSeries"; + /// + /// Event sent out during Refresh Metadata for progress tracking + /// + private const string CoverUpdateProgress = "CoverUpdateProgress"; + /// + /// Series is added to server + /// + public const string SeriesAdded = "SeriesAdded"; + /// + /// Series is removed from server + /// + public const string SeriesRemoved = "SeriesRemoved"; + /// + /// When a user is connects/disconnects from server + /// + public const string OnlineUsers = "OnlineUsers"; + /// + /// When a series is added to a collection + /// + public const string SeriesAddedToCollection = "SeriesAddedToCollection"; + /// + /// Event sent out during backing up the database + /// + private const string BackupDatabaseProgress = "BackupDatabaseProgress"; + /// + /// Event sent out during cleaning up temp and cache folders + /// + private const string CleanupProgress = "CleanupProgress"; + /// + /// Event sent out during downloading of files + /// + private const string DownloadProgress = "DownloadProgress"; + /// + /// A cover was updated + /// + public const string CoverUpdate = "CoverUpdate"; + /// + /// A custom site theme was removed or added + /// + private const string SiteThemeProgress = "SiteThemeProgress"; + /// + /// A type of event that has progress (determinate or indeterminate). + /// The underlying event will have a name to give details on how to handle. + /// + public const string NotificationProgress = "NotificationProgress"; + /// + /// Event sent out when Scan Loop is parsing a file + /// + private const string FileScanProgress = "FileScanProgress"; + /// + /// A generic error that can occur in background processing + /// + public const string Error = "Error"; + /// + /// When DB updates are occuring during a library/series scan + /// + private const string ScanProgress = "ScanProgress"; + /// + /// When a library is created/deleted in the Server + /// + public const string LibraryModified = "LibraryModified"; + + + public static SignalRMessage ScanSeriesEvent(int libraryId, int seriesId, string seriesName) { return new SignalRMessage() { - Name = SignalREvents.ScanSeries, + Name = ScanSeries, + EventType = ProgressEventType.Single, Body = new { + LibraryId = libraryId, SeriesId = seriesId, SeriesName = seriesName } @@ -22,7 +99,7 @@ namespace API.SignalR { return new SignalRMessage() { - Name = SignalREvents.SeriesAdded, + Name = SeriesAdded, Body = new { SeriesId = seriesId, @@ -36,7 +113,7 @@ namespace API.SignalR { return new SignalRMessage() { - Name = SignalREvents.SeriesRemoved, + Name = SeriesRemoved, Body = new { SeriesId = seriesId, @@ -46,11 +123,15 @@ namespace API.SignalR }; } - public static SignalRMessage ScanLibraryProgressEvent(int libraryId, float progress) + public static SignalRMessage CoverUpdateProgressEvent(int libraryId, float progress, string eventType, string subtitle = "") { return new SignalRMessage() { - Name = SignalREvents.ScanLibraryProgress, + Name = CoverUpdateProgress, + Title = "Refreshing Covers", + SubTitle = subtitle, + EventType = eventType, + Progress = ProgressType.Determinate, Body = new { LibraryId = libraryId, @@ -60,37 +141,40 @@ namespace API.SignalR }; } - public static SignalRMessage RefreshMetadataProgressEvent(int libraryId, float progress) + public static SignalRMessage BackupDatabaseProgressEvent(float progress, string subtitle = "") { return new SignalRMessage() { - Name = SignalREvents.RefreshMetadataProgress, - Body = new + Name = BackupDatabaseProgress, + Title = "Backing up Database", + SubTitle = subtitle, + EventType = progress switch { - LibraryId = libraryId, - Progress = progress, - EventTime = DateTime.Now - } - }; - } - - - public static SignalRMessage BackupDatabaseProgressEvent(float progress) - { - return new SignalRMessage() - { - Name = SignalREvents.BackupDatabaseProgress, + 0f => "started", + 1f => "ended", + _ => "updated" + }, + Progress = ProgressType.Determinate, Body = new { Progress = progress } }; } - public static SignalRMessage CleanupProgressEvent(float progress) + public static SignalRMessage CleanupProgressEvent(float progress, string subtitle = "") { return new SignalRMessage() { - Name = SignalREvents.CleanupProgress, + Name = CleanupProgress, + Title = "Performing Cleanup", + SubTitle = subtitle, + EventType = progress switch + { + 0f => "started", + 1f => "ended", + _ => "updated" + }, + Progress = ProgressType.Determinate, Body = new { Progress = progress @@ -99,21 +183,26 @@ namespace API.SignalR } - public static SignalRMessage UpdateVersionEvent(UpdateNotificationDto update) { return new SignalRMessage { - Name = SignalREvents.UpdateAvailable, + Name = UpdateAvailable, + Title = "Update Available", + SubTitle = update.UpdateTitle, + EventType = ProgressEventType.Single, + Progress = ProgressType.None, Body = update }; } - public static SignalRMessage SeriesAddedToCollection(int tagId, int seriesId) + public static SignalRMessage SeriesAddedToCollectionEvent(int tagId, int seriesId) { return new SignalRMessage { - Name = SignalREvents.UpdateAvailable, + Name = SeriesAddedToCollection, + Progress = ProgressType.None, + EventType = ProgressEventType.Single, Body = new { TagId = tagId, @@ -122,23 +211,51 @@ namespace API.SignalR }; } - public static SignalRMessage ScanLibraryError(int libraryId) + /** + * A generic error that will show on events widget in the UI + */ + public static SignalRMessage ErrorEvent(string title, string subtitle) { return new SignalRMessage { - Name = SignalREvents.ScanLibraryError, + Name = Error, + Title = title, + SubTitle = subtitle, + Progress = ProgressType.None, + EventType = ProgressEventType.Single, Body = new { - LibraryId = libraryId, + Title = title, + SubTitle = subtitle, } }; } - public static SignalRMessage DownloadProgressEvent(string username, string downloadName, float progress) + public static SignalRMessage LibraryModifiedEvent(int libraryId, string action) + { + return new SignalRMessage + { + Name = LibraryModified, + Title = "Library modified", + Progress = ProgressType.None, + EventType = ProgressEventType.Single, + Body = new + { + LibrayId = libraryId, + Action = action, + } + }; + } + + public static SignalRMessage DownloadProgressEvent(string username, string downloadName, float progress, string eventType = "updated") { return new SignalRMessage() { - Name = SignalREvents.DownloadProgress, + Name = DownloadProgress, + Title = $"Downloading {downloadName}", + SubTitle = $"{username} is downloading {downloadName}", + EventType = eventType, + Progress = ProgressType.Determinate, Body = new { UserName = username, @@ -148,11 +265,54 @@ namespace API.SignalR }; } + /// + /// Represents a file being scanned by Kavita for processing and grouping + /// + /// Does not have a progress as it's unknown how many files there are. Instead sends -1 to represent indeterminate + /// + /// + /// + /// + public static SignalRMessage FileScanProgressEvent(string filename, string libraryName, string eventType) + { + return new SignalRMessage() + { + Name = FileScanProgress, + Title = $"Scanning {libraryName}", + SubTitle = Path.GetFileName(filename), + EventType = eventType, + Progress = ProgressType.Indeterminate, + Body = new + { + Title = $"Scanning {libraryName}", + Subtitle = filename, + Filename = filename, + EventTime = DateTime.Now, + } + }; + } + + public static SignalRMessage LibraryScanProgressEvent(string libraryName, string eventType, string seriesName = "") + { + return new SignalRMessage() + { + Name = ScanProgress, + Title = $"Scanning {libraryName}", + SubTitle = seriesName, + EventType = eventType, + Progress = ProgressType.Indeterminate, + Body = null + }; + } + public static SignalRMessage CoverUpdateEvent(int id, string entityType) { return new SignalRMessage() { - Name = SignalREvents.CoverUpdate, + Name = CoverUpdate, + Title = "Updating Cover", + //SubTitle = series.Name, // TODO: Refactor this + Progress = ProgressType.None, Body = new { Id = id, @@ -160,5 +320,21 @@ namespace API.SignalR } }; } + + public static SignalRMessage SiteThemeProgressEvent(string subtitle, string themeName, string eventType) + { + return new SignalRMessage() + { + Name = SiteThemeProgress, + Title = "Scanning Site Theme", + SubTitle = subtitle, + EventType = eventType, + Progress = ProgressType.Indeterminate, + Body = new + { + ThemeName = themeName, + } + }; + } } } diff --git a/API/SignalR/MessageHub.cs b/API/SignalR/MessageHub.cs index 2b3cd96cc..d4508db17 100644 --- a/API/SignalR/MessageHub.cs +++ b/API/SignalR/MessageHub.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; +using API.Data; using API.Extensions; using API.SignalR.Presence; using Microsoft.AspNetCore.Authorization; @@ -36,6 +37,7 @@ namespace API.SignalR public override async Task OnConnectedAsync() { + lock (Connections) { Connections.Add(Context.ConnectionId); @@ -44,7 +46,7 @@ namespace API.SignalR await _tracker.UserConnected(Context.User.GetUsername(), Context.ConnectionId); var currentUsers = await PresenceTracker.GetOnlineUsers(); - await Clients.All.SendAsync(SignalREvents.OnlineUsers, currentUsers); + await Clients.All.SendAsync(MessageFactory.OnlineUsers, currentUsers); await base.OnConnectedAsync(); @@ -60,7 +62,7 @@ namespace API.SignalR await _tracker.UserDisconnected(Context.User.GetUsername(), Context.ConnectionId); var currentUsers = await PresenceTracker.GetOnlineUsers(); - await Clients.All.SendAsync(SignalREvents.OnlineUsers, currentUsers); + await Clients.All.SendAsync(MessageFactory.OnlineUsers, currentUsers); await base.OnDisconnectedAsync(exception); diff --git a/API/SignalR/Presence/PresenceTracker.cs b/API/SignalR/Presence/PresenceTracker.cs index 73d6479ff..2d71b7302 100644 --- a/API/SignalR/Presence/PresenceTracker.cs +++ b/API/SignalR/Presence/PresenceTracker.cs @@ -15,13 +15,20 @@ namespace API.SignalR.Presence } + internal class ConnectionDetail + { + public List ConnectionIds { get; set; } + public bool IsAdmin { get; set; } + } + + // TODO: This can respond to UserRoleUpdate events to handle online users /// /// This is a singleton service for tracking what users have a SignalR connection and their difference connectionIds /// public class PresenceTracker : IPresenceTracker { private readonly IUnitOfWork _unitOfWork; - private static readonly Dictionary> OnlineUsers = new Dictionary>(); + private static readonly Dictionary OnlineUsers = new Dictionary(); public PresenceTracker(IUnitOfWork unitOfWork) { @@ -30,20 +37,25 @@ namespace API.SignalR.Presence public async Task UserConnected(string username, string connectionId) { + var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(username); + var isAdmin = await _unitOfWork.UserRepository.IsUserAdminAsync(user); lock (OnlineUsers) { if (OnlineUsers.ContainsKey(username)) { - OnlineUsers[username].Add(connectionId); + OnlineUsers[username].ConnectionIds.Add(connectionId); } else { - OnlineUsers.Add(username, new List() { connectionId }); + OnlineUsers.Add(username, new ConnectionDetail() + { + ConnectionIds = new List() {connectionId}, + IsAdmin = isAdmin + }); } } // Update the last active for the user - var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(username); user.LastActive = DateTime.Now; await _unitOfWork.CommitAsync(); } @@ -54,9 +66,9 @@ namespace API.SignalR.Presence { if (!OnlineUsers.ContainsKey(username)) return Task.CompletedTask; - OnlineUsers[username].Remove(connectionId); + OnlineUsers[username].ConnectionIds.Remove(connectionId); - if (OnlineUsers[username].Count == 0) + if (OnlineUsers[username].ConnectionIds.Count == 0) { OnlineUsers.Remove(username); } @@ -75,18 +87,16 @@ namespace API.SignalR.Presence return Task.FromResult(onlineUsers); } - public async Task GetOnlineAdmins() + public Task GetOnlineAdmins() { string[] onlineUsers; lock (OnlineUsers) { - onlineUsers = OnlineUsers.OrderBy(k => k.Key).Select(k => k.Key).ToArray(); + onlineUsers = OnlineUsers.Where(pair => pair.Value.IsAdmin).OrderBy(k => k.Key).Select(k => k.Key).ToArray(); } - var admins = await _unitOfWork.UserRepository.GetAdminUsersAsync(); - var result = admins.Select(a => a.UserName).Intersect(onlineUsers).ToArray(); - return result; + return Task.FromResult(onlineUsers); } public Task> GetConnectionsForUser(string username) @@ -94,7 +104,7 @@ namespace API.SignalR.Presence List connectionIds; lock (OnlineUsers) { - connectionIds = OnlineUsers.GetValueOrDefault(username); + connectionIds = OnlineUsers.GetValueOrDefault(username)?.ConnectionIds; } return Task.FromResult(connectionIds); diff --git a/API/SignalR/ProgressEventType.cs b/API/SignalR/ProgressEventType.cs new file mode 100644 index 000000000..89ba758c5 --- /dev/null +++ b/API/SignalR/ProgressEventType.cs @@ -0,0 +1,17 @@ +namespace API.SignalR; + +public static class ProgressEventType +{ + public const string Started = "started"; + + public const string Updated = "updated"; + /// + /// End of the update chain + /// + public const string Ended = "ended"; + /// + /// Represents a single update + /// + public const string Single = "started"; + +} diff --git a/API/SignalR/ProgressType.cs b/API/SignalR/ProgressType.cs new file mode 100644 index 000000000..b0fbe341d --- /dev/null +++ b/API/SignalR/ProgressType.cs @@ -0,0 +1,21 @@ +namespace API.SignalR; + +/// +/// How progress should be represented on the UI +/// +public static class ProgressType +{ + /// + /// Progress scales from 0F -> 1F + /// + public const string Determinate = "determinate"; + /// + /// Progress has no understanding of quantity + /// + public const string Indeterminate = "indeterminate"; + /// + /// No progress component to the event + /// + public const string None = ""; + +} diff --git a/API/SignalR/SignalREvents.cs b/API/SignalR/SignalREvents.cs deleted file mode 100644 index 1da613455..000000000 --- a/API/SignalR/SignalREvents.cs +++ /dev/null @@ -1,58 +0,0 @@ -namespace API.SignalR -{ - public static class SignalREvents - { - /// - /// An update is available for the Kavita instance - /// - public const string UpdateAvailable = "UpdateAvailable"; - /// - /// Used to tell when a scan series completes - /// - public const string ScanSeries = "ScanSeries"; - /// - /// Event sent out during Refresh Metadata for progress tracking - /// - public const string RefreshMetadataProgress = "RefreshMetadataProgress"; - /// - /// Series is added to server - /// - public const string SeriesAdded = "SeriesAdded"; - /// - /// Series is removed from server - /// - public const string SeriesRemoved = "SeriesRemoved"; - /// - /// Progress event for Scan library - /// - public const string ScanLibraryProgress = "ScanLibraryProgress"; - /// - /// When a user is connects/disconnects from server - /// - public const string OnlineUsers = "OnlineUsers"; - /// - /// When a series is added to a collection - /// - public const string SeriesAddedToCollection = "SeriesAddedToCollection"; - /// - /// When an error occurs during a scan library task - /// - public const string ScanLibraryError = "ScanLibraryError"; - /// - /// Event sent out during backing up the database - /// - public const string BackupDatabaseProgress = "BackupDatabaseProgress"; - /// - /// Event sent out during cleaning up temp and cache folders - /// - public const string CleanupProgress = "CleanupProgress"; - /// - /// Event sent out during downloading of files - /// - public const string DownloadProgress = "DownloadProgress"; - /// - /// A cover was updated - /// - public const string CoverUpdate = "CoverUpdate"; - } -} diff --git a/API/SignalR/SignalRMessage.cs b/API/SignalR/SignalRMessage.cs index dfb181105..b71d0b813 100644 --- a/API/SignalR/SignalRMessage.cs +++ b/API/SignalR/SignalRMessage.cs @@ -1,14 +1,39 @@ -namespace API.SignalR +using System; + +namespace API.SignalR { /// /// Payload for SignalR messages to Frontend /// public class SignalRMessage { + /// + /// Body of the event type + /// public object Body { get; set; } public string Name { get; set; } - - //[JsonIgnore] - //public ModelAction Action { get; set; } // This will be for when we add new flows + /// + /// User friendly Title of the Event + /// + /// Scanning Manga + public string Title { get; set; } = string.Empty; + /// + /// User friendly subtitle. Should have extra info + /// + /// C:/manga/Accel World V01.cbz + public string SubTitle { get; set; } = string.Empty; + /// + /// Represents what this represents. started | updated | ended | single + /// + /// + public string EventType { get; set; } = ProgressEventType.Updated; + /// + /// How should progress be represented. If Determinate, the Body MUST have a Progress float on it. + /// + public string Progress { get; set; } = ProgressType.None; + /// + /// When event took place + /// + public DateTime EventTime = DateTime.Now; } } diff --git a/API/Startup.cs b/API/Startup.cs index 2f9ad133b..2f8ac4d1a 100644 --- a/API/Startup.cs +++ b/API/Startup.cs @@ -8,6 +8,7 @@ using System.Threading.Tasks; using API.Constants; using API.Data; using API.Entities; +using API.Entities.Enums; using API.Extensions; using API.Middleware; using API.Services; @@ -18,6 +19,7 @@ using Hangfire; using Hangfire.MemoryStorage; using Kavita.Common; using Kavita.Common.EnvironmentInfo; +using MediatR; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; @@ -118,6 +120,7 @@ namespace API ForwardedHeaders.All; }); + services.AddHangfire(configuration => configuration .UseSimpleAssemblyNameTypeSerializer() .UseRecommendedSerializerSettings() @@ -129,6 +132,8 @@ namespace API // Add IHostedService for startup tasks // Any services that should be bootstrapped go here services.AddHostedService(); + + services.AddMediatR(typeof(Startup)); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. @@ -146,12 +151,18 @@ namespace API var logger = serviceProvider.GetRequiredService>(); var userManager = serviceProvider.GetRequiredService>(); - await MigrateBookmarks.Migrate(directoryService, unitOfWork, logger, cacheService); // Only run this if we are upgrading await MigrateChangePasswordRoles.Migrate(unitOfWork, userManager); + + // Update the version in the DB after all migrations are run + var installVersion = await unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.InstallVersion); + installVersion.Value = BuildInfo.Version.ToString(); + unitOfWork.SettingsRepository.Update(installVersion); + + await unitOfWork.CommitAsync(); }).GetAwaiter() .GetResult(); } @@ -203,21 +214,6 @@ namespace API app.UseDefaultFiles(); - // This is not implemented completely. Commenting out until implemented - // var service = serviceProvider.GetRequiredService(); - // var settings = service.SettingsRepository.GetSettingsDto(); - // if (!string.IsNullOrEmpty(settings.BaseUrl) && !settings.BaseUrl.Equals("/")) - // { - // var path = !settings.BaseUrl.StartsWith("/") - // ? $"/{settings.BaseUrl}" - // : settings.BaseUrl; - // path = !path.EndsWith("/") - // ? $"{path}/" - // : path; - // app.UsePathBase(path); - // Console.WriteLine("Starting with base url as " + path); - // } - app.UseStaticFiles(new StaticFileOptions { ContentTypeProvider = new FileExtensionContentTypeProvider() diff --git a/INSTALL.txt b/INSTALL.txt index 9119da82c..753236e9a 100644 --- a/INSTALL.txt +++ b/INSTALL.txt @@ -4,4 +4,5 @@ 3. Run Kavita executable. 4. Open localhost:5000 and setup your account and libraries in the UI. -If updating, copy everything but the config/ directory over. Restart Kavita. +How to Update +1. Copy everything but the config/ directory over. Restart Kavita. diff --git a/Kavita.Common/Kavita.Common.csproj b/Kavita.Common/Kavita.Common.csproj index 26d770327..9e72ce3ed 100644 --- a/Kavita.Common/Kavita.Common.csproj +++ b/Kavita.Common/Kavita.Common.csproj @@ -4,15 +4,15 @@ net6.0 kavitareader.com Kavita - 0.5.1.1 + 0.5.2.0 en - + - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/README.md b/README.md index 55570e192..abc2ee070 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,8 @@ services: ## Feature Requests Got a great idea? Throw it up on our [Feature Request site](https://feats.kavitareader.com/) or vote on another idea. Please check the [Project Board](https://github.com/Kareadita/Kavita/projects) first for a list of planned features. +## Notice +Kavita is being actively developed and should be considered beta software until the 1.0 release. Kavita may be subject to changes in how the platform functions as it is being built out toward the vision. You may lose data and have to restart. The Kavita team strives to avoid any data loss. ## Contributors diff --git a/UI/Web/angular.json b/UI/Web/angular.json index a78e625b0..56bc8a3e1 100644 --- a/UI/Web/angular.json +++ b/UI/Web/angular.json @@ -28,7 +28,6 @@ "main": "src/main.ts", "polyfills": "src/polyfills.ts", "tsConfig": "tsconfig.app.json", - "aot": true, "assets": [ "src/assets", "src/site.webmanifest" @@ -46,7 +45,12 @@ "node_modules/lazysizes/lazysizes.min.js", "node_modules/lazysizes/plugins/rias/ls.rias.min.js", "node_modules/lazysizes/plugins/attrchange/ls.attrchange.min.js" - ] + ], + "vendorChunk": true, + "extractLicenses": false, + "buildOptimizer": false, + "optimization": false, + "namedChunks": true }, "configurations": { "production": { @@ -60,7 +64,6 @@ "outputHashing": "all", "namedChunks": false, "extractLicenses": true, - "vendorChunk": true, "buildOptimizer": true, "budgets": [ { @@ -75,7 +78,8 @@ } ] } - } + }, + "defaultConfiguration": "" }, "serve": { "builder": "@angular-devkit/build-angular:dev-server", diff --git a/UI/Web/package-lock.json b/UI/Web/package-lock.json index 68c606f64..279f64bf3 100644 --- a/UI/Web/package-lock.json +++ b/UI/Web/package-lock.json @@ -4,248 +4,381 @@ "lockfileVersion": 1, "requires": true, "dependencies": { - "@angular-devkit/architect": { - "version": "0.1100.7", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1100.7.tgz", - "integrity": "sha512-b2zv2yiRbdhJ7hJfZsAvGYcqgh2DVtc7gRIPo1eDPvOAKrenmZ4zo/v0PRYScrTsPzqmoCokNA5nIwufwUEnuA==", + "@ampproject/remapping": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-1.1.1.tgz", + "integrity": "sha512-YVAcA4DKLOj296CF5SrQ8cYiMRiUGc2sqFpLxsDGWE34suHqhGP/5yMsDHKsrh8hs8I5TiRVXNwKPWQpX3iGjw==", "dev": true, "requires": { - "@angular-devkit/core": "11.0.7", - "rxjs": "6.6.3" + "@jridgewell/resolve-uri": "^3.0.3", + "sourcemap-codec": "1.4.8" + } + }, + "@angular-devkit/architect": { + "version": "0.1302.3", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1302.3.tgz", + "integrity": "sha512-0m8jMKrFfIqsYt33zTUwSmyekyfuS67hna08RQ6USjzWQSE3z4S8ulCUARSjM6AzdMblX+whfy56nJUpT17NSA==", + "dev": true, + "requires": { + "@angular-devkit/core": "13.2.3", + "rxjs": "6.6.7" + }, + "dependencies": { + "rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } } }, "@angular-devkit/build-angular": { - "version": "0.1100.7", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-0.1100.7.tgz", - "integrity": "sha512-erc+AtSU46ZIX7A5dmeZ0/G/SQIbqMAGbTKZbf11GePyhT0JAAnfMQtOHMb6AaX85n4yQTg1uMo9f5+8V3lfKA==", + "version": "13.2.3", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-13.2.3.tgz", + "integrity": "sha512-cZ2gRcMRgW3t1WCeP+2D/wmr2M+BR/RICAh0wL9irIdypWAzIFt3Z2+2R/HmgAAxoEkdUMIfB9AnkYmwRVgFeA==", "dev": true, "requires": { - "@angular-devkit/architect": "0.1100.7", - "@angular-devkit/build-optimizer": "0.1100.7", - "@angular-devkit/build-webpack": "0.1100.7", - "@angular-devkit/core": "11.0.7", - "@babel/core": "7.12.3", - "@babel/generator": "7.12.1", - "@babel/plugin-transform-runtime": "7.12.1", - "@babel/preset-env": "7.12.1", - "@babel/runtime": "7.12.1", - "@babel/template": "7.10.4", - "@jsdevtools/coverage-istanbul-loader": "3.0.5", - "@ngtools/webpack": "11.0.7", + "@ampproject/remapping": "1.1.1", + "@angular-devkit/architect": "0.1302.3", + "@angular-devkit/build-webpack": "0.1302.3", + "@angular-devkit/core": "13.2.3", + "@babel/core": "7.16.12", + "@babel/generator": "7.16.8", + "@babel/helper-annotate-as-pure": "7.16.7", + "@babel/plugin-proposal-async-generator-functions": "7.16.8", + "@babel/plugin-transform-async-to-generator": "7.16.8", + "@babel/plugin-transform-runtime": "7.16.10", + "@babel/preset-env": "7.16.11", + "@babel/runtime": "7.16.7", + "@babel/template": "7.16.7", + "@discoveryjs/json-ext": "0.5.6", + "@ngtools/webpack": "13.2.3", "ansi-colors": "4.1.1", - "autoprefixer": "9.8.6", - "babel-loader": "8.1.0", + "babel-loader": "8.2.3", + "babel-plugin-istanbul": "6.1.1", "browserslist": "^4.9.1", - "cacache": "15.0.5", - "caniuse-lite": "^1.0.30001032", - "circular-dependency-plugin": "5.2.0", - "copy-webpack-plugin": "6.2.1", - "core-js": "3.6.5", - "css-loader": "4.3.0", - "cssnano": "4.1.10", - "file-loader": "6.1.1", - "find-cache-dir": "3.3.1", - "glob": "7.1.6", - "inquirer": "7.3.3", - "jest-worker": "26.5.0", + "cacache": "15.3.0", + "circular-dependency-plugin": "5.2.2", + "copy-webpack-plugin": "10.2.1", + "core-js": "3.20.3", + "critters": "0.0.16", + "css-loader": "6.5.1", + "esbuild": "0.14.14", + "esbuild-wasm": "0.14.14", + "glob": "7.2.0", + "https-proxy-agent": "5.0.0", + "inquirer": "8.2.0", + "jsonc-parser": "3.0.0", "karma-source-map-support": "1.4.0", - "less": "3.12.2", - "less-loader": "7.0.2", - "license-webpack-plugin": "2.3.1", - "loader-utils": "2.0.0", - "mini-css-extract-plugin": "1.2.1", + "less": "4.1.2", + "less-loader": "10.2.0", + "license-webpack-plugin": "4.0.1", + "loader-utils": "3.2.0", + "mini-css-extract-plugin": "2.5.3", "minimatch": "3.0.4", - "open": "7.3.0", - "ora": "5.1.0", + "open": "8.4.0", + "ora": "5.4.1", "parse5-html-rewriting-stream": "6.0.1", - "pnp-webpack-plugin": "1.6.4", - "postcss": "7.0.32", - "postcss-import": "12.0.1", - "postcss-loader": "4.0.4", - "raw-loader": "4.0.2", - "regenerator-runtime": "0.13.7", - "resolve-url-loader": "3.1.2", - "rimraf": "3.0.2", - "rollup": "2.32.1", - "rxjs": "6.6.3", - "sass": "1.27.0", - "sass-loader": "10.0.5", - "semver": "7.3.2", - "source-map": "0.7.3", - "source-map-loader": "1.1.2", - "source-map-support": "0.5.19", - "speed-measure-webpack-plugin": "1.3.3", - "style-loader": "2.0.0", - "stylus": "0.54.8", - "stylus-loader": "4.3.1", - "terser": "5.3.7", - "terser-webpack-plugin": "4.2.3", + "piscina": "3.2.0", + "postcss": "8.4.5", + "postcss-import": "14.0.2", + "postcss-loader": "6.2.1", + "postcss-preset-env": "7.2.3", + "regenerator-runtime": "0.13.9", + "resolve-url-loader": "5.0.0", + "rxjs": "6.6.7", + "sass": "1.49.0", + "sass-loader": "12.4.0", + "semver": "7.3.5", + "source-map-loader": "3.0.1", + "source-map-support": "0.5.21", + "stylus": "0.56.0", + "stylus-loader": "6.2.0", + "terser": "5.10.0", "text-table": "0.2.0", "tree-kill": "1.2.2", - "webpack": "4.44.2", - "webpack-dev-middleware": "3.7.2", - "webpack-dev-server": "3.11.0", - "webpack-merge": "5.2.0", - "webpack-sources": "2.0.1", - "webpack-subresource-integrity": "1.5.1", - "worker-plugin": "5.0.0" + "tslib": "2.3.1", + "webpack": "5.67.0", + "webpack-dev-middleware": "5.3.0", + "webpack-dev-server": "4.7.3", + "webpack-merge": "5.8.0", + "webpack-subresource-integrity": "5.1.0" }, "dependencies": { - "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "@babel/code-frame": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", "dev": true, "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" + "@babel/highlight": "^7.16.7" + } + }, + "@babel/core": { + "version": "7.16.12", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.16.12.tgz", + "integrity": "sha512-dK5PtG1uiN2ikk++5OzSYsitZKny4wOCD0nrO4TqnW4BVBTQ2NGS3NgilvT/TEyxTST7LNyWV/T4tXDoD3fOgg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.16.8", + "@babel/helper-compilation-targets": "^7.16.7", + "@babel/helper-module-transforms": "^7.16.7", + "@babel/helpers": "^7.16.7", + "@babel/parser": "^7.16.12", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.16.10", + "@babel/types": "^7.16.8", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.1.2", + "semver": "^6.3.0", + "source-map": "^0.5.0" }, "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true } } }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "@babel/generator": { + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.16.8.tgz", + "integrity": "sha512-1ojZwE9+lOXzcWdWmO6TbUzDfqLD39CmEhN8+2cX9XkDo5yW1OpgfejfliysR2AWLpMamTiOiAp/mtroaymhpw==", "dev": true, "requires": { - "has-flag": "^3.0.0" + "@babel/types": "^7.16.8", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", + "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", + "dev": true + }, + "@babel/highlight": { + "version": "7.16.10", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz", + "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.16.7", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "requires": { + "debug": "4" + } + }, + "esbuild": { + "version": "0.14.14", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.14.tgz", + "integrity": "sha512-aiK4ddv+uui0k52OqSHu4xxu+SzOim7Rlz4i25pMEiC8rlnGU0HJ9r+ZMfdWL5bzifg+nhnn7x4NSWTeehYblg==", + "dev": true, + "optional": true, + "requires": { + "esbuild-android-arm64": "0.14.14", + "esbuild-darwin-64": "0.14.14", + "esbuild-darwin-arm64": "0.14.14", + "esbuild-freebsd-64": "0.14.14", + "esbuild-freebsd-arm64": "0.14.14", + "esbuild-linux-32": "0.14.14", + "esbuild-linux-64": "0.14.14", + "esbuild-linux-arm": "0.14.14", + "esbuild-linux-arm64": "0.14.14", + "esbuild-linux-mips64le": "0.14.14", + "esbuild-linux-ppc64le": "0.14.14", + "esbuild-linux-s390x": "0.14.14", + "esbuild-netbsd-64": "0.14.14", + "esbuild-openbsd-64": "0.14.14", + "esbuild-sunos-64": "0.14.14", + "esbuild-windows-32": "0.14.14", + "esbuild-windows-64": "0.14.14", + "esbuild-windows-arm64": "0.14.14" + } + }, + "glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "https-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "dev": true, + "requires": { + "agent-base": "6", + "debug": "4" + } + }, + "rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" } } } }, - "@angular-devkit/build-optimizer": { - "version": "0.1100.7", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-optimizer/-/build-optimizer-0.1100.7.tgz", - "integrity": "sha512-bHIIub0d1trVAmAX/EaNR6Zo4b7hkscewK394qYYp/w8VKQkLSAPMUbt2YTWN+erR9yyHnJ2y7tBabIui75Wdw==", - "dev": true, - "requires": { - "loader-utils": "2.0.0", - "source-map": "0.7.3", - "tslib": "2.0.3", - "typescript": "4.0.5", - "webpack-sources": "2.0.1" - } - }, "@angular-devkit/build-webpack": { - "version": "0.1100.7", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1100.7.tgz", - "integrity": "sha512-/6Hudd1hs/GMHX4C/Qk7jueIMNg8NKFJWDEbvMPMgDzTqUIa680PTD6SNSCcY5Cz9mEpdpYCZo5N31JB7dlpOg==", + "version": "0.1302.3", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1302.3.tgz", + "integrity": "sha512-+JYH1lWU0UOjaWYxpoR2VLsdcb6nG9Gv+M1gH+kT0r2sAKOFaHnrksbOvca3EhDoaMa2b9LSGEE0OcSHWnN+eQ==", "dev": true, "requires": { - "@angular-devkit/architect": "0.1100.7", - "@angular-devkit/core": "11.0.7", - "rxjs": "6.6.3" + "@angular-devkit/architect": "0.1302.3", + "rxjs": "6.6.7" + }, + "dependencies": { + "rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } } }, "@angular-devkit/core": { - "version": "11.0.7", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-11.0.7.tgz", - "integrity": "sha512-1GKnIT++YSUHpzzRx9QC0+8yOw4wy+ZpiJVDlroPSeK4FGrTCJqJKenkfRjVFRFOSrzTiJds+IU6kI4+bFbw9g==", + "version": "13.2.3", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-13.2.3.tgz", + "integrity": "sha512-/47RA8qmWzeS60xSdaprIn1MiSv0Iw83t0M9/ENH7irFS5vMAq62NCcwiWXH59pZmvvLbF+7xy/RgYUZLr4nHQ==", "dev": true, "requires": { - "ajv": "6.12.6", + "ajv": "8.9.0", + "ajv-formats": "2.1.1", "fast-json-stable-stringify": "2.1.0", "magic-string": "0.25.7", - "rxjs": "6.6.3", + "rxjs": "6.6.7", "source-map": "0.7.3" + }, + "dependencies": { + "ajv": { + "version": "8.9.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.9.0.tgz", + "integrity": "sha512-qOKJyNj/h+OWx7s5DePL6Zu1KeM9jPZhwBqs+7DzP6bGOvqzVCSf0xueYmVuaC/oQ/VtS2zLMLHdQFbkka+XDQ==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "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 + }, + "rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } } }, "@angular-devkit/schematics": { - "version": "11.2.11", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-11.2.11.tgz", - "integrity": "sha512-xkw+5P9V7VdV/X3Eko0/oZmEqelenIT1RdaOlFA3ZLCdT6bz+79HjeChMy++JcLjVNRcLYQSw0ULByq2q/S2Pw==", + "version": "13.2.3", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-13.2.3.tgz", + "integrity": "sha512-+dyC4iKV0huvpjiuz4uyjLNK3FsCIp/Ghv5lXvhG6yok/dCAubsJItJOxi6G16aVCzG/E9zbsDfm9fNMyVOkgQ==", "dev": true, "requires": { - "@angular-devkit/core": "11.2.11", - "ora": "5.3.0", - "rxjs": "6.6.3" + "@angular-devkit/core": "13.2.3", + "jsonc-parser": "3.0.0", + "magic-string": "0.25.7", + "ora": "5.4.1", + "rxjs": "6.6.7" }, "dependencies": { - "@angular-devkit/core": { - "version": "11.2.11", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-11.2.11.tgz", - "integrity": "sha512-6gFrpG0o00Y4kMU7cQeQ5fSlmXRvNlidylM3OfAvpj0qHoRKo1E3q9iVr4fW3oVZxK3fpCSN7RE5Myl5Y7mV0w==", + "rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", "dev": true, "requires": { - "ajv": "6.12.6", - "fast-json-stable-stringify": "2.1.0", - "magic-string": "0.25.7", - "rxjs": "6.6.3", - "source-map": "0.7.3" + "tslib": "^1.9.0" } }, - "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, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "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, - "requires": { - "color-name": "~1.1.4" - } - }, - "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==", + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "dev": true - }, - "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 - }, - "ora": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.3.0.tgz", - "integrity": "sha512-zAKMgGXUim0Jyd6CXK9lraBnD3H5yPGBPPOkC23a2BG6hsm4Zu6OQSjQuEtV0BHDf4aKHcUFvJiGRrFuW3MG8g==", - "dev": true, - "requires": { - "bl": "^4.0.3", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-spinners": "^2.5.0", - "is-interactive": "^1.0.0", - "log-symbols": "^4.0.0", - "strip-ansi": "^6.0.0", - "wcwidth": "^1.0.1" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } } } }, @@ -260,6 +393,14 @@ "tslib": "^1.9.0" }, "dependencies": { + "rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "requires": { + "tslib": "^1.9.0" + } + }, "tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", @@ -268,178 +409,84 @@ } }, "@angular/animations": { - "version": "11.0.9", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-11.0.9.tgz", - "integrity": "sha512-/KsMBUbRTqp29CNLbRIe4/8IxWxhnbUUZWqULaySnRDDW/p2m4miPcFVSp4zjrDZPqdXSibDiCyTiWmQ5PTuKA==", + "version": "13.2.2", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-13.2.2.tgz", + "integrity": "sha512-qX8LAMuCJaueHBVyuwKtqunx96G0Dr26k7y5Z03VTcscYst4Ib4V2d4i5dwn3HS82DehFdO86cm3Hi2PqE/qww==", "requires": { - "tslib": "^2.0.0" + "tslib": "^2.3.0" } }, "@angular/cdk": { - "version": "12.2.3", - "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-12.2.3.tgz", - "integrity": "sha512-ahY3k5X3eoQlsCX/fYiwbe1z7nfmwY15EiLpcJ8YrnUoB+ZshPm8qFIZi6gwY4tsMmUN8OfsIGcUO701bdxFpg==", + "version": "13.2.2", + "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-13.2.2.tgz", + "integrity": "sha512-cT5DIaz+NI9IGb3X61Wh26+L6zdRcOXT1BP37iRbK2Qa2qM8/0VNeK6hrBBIblyoHKR/WUmRlS8XYf6mmArpZw==", "requires": { "parse5": "^5.0.0", - "tslib": "^2.2.0" - }, - "dependencies": { - "parse5": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", - "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==", - "optional": true - }, - "tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" - } + "tslib": "^2.3.0" } }, "@angular/cli": { - "version": "11.2.11", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-11.2.11.tgz", - "integrity": "sha512-KzpRaCaHUwznlm6Iz/DvWqZs1fQx+NpJsiEOtKz7ijKoktJq+qcxAcBr2A4sNAuuAMgs0Xqy70EHvbMPA1yQ9A==", + "version": "13.2.3", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-13.2.3.tgz", + "integrity": "sha512-QsakxpdQuO67u4fQNuOASqabYUO9gJb/5CpUGpWbuBzru0/9CMEF1CtXoF4EoDiwa5sJMirz3SJMKhtzFlv1cQ==", "dev": true, "requires": { - "@angular-devkit/architect": "0.1102.11", - "@angular-devkit/core": "11.2.11", - "@angular-devkit/schematics": "11.2.11", - "@schematics/angular": "11.2.11", - "@schematics/update": "0.1102.11", + "@angular-devkit/architect": "0.1302.3", + "@angular-devkit/core": "13.2.3", + "@angular-devkit/schematics": "13.2.3", + "@schematics/angular": "13.2.3", "@yarnpkg/lockfile": "1.1.0", "ansi-colors": "4.1.1", - "debug": "4.3.1", + "debug": "4.3.3", "ini": "2.0.0", - "inquirer": "7.3.3", + "inquirer": "8.2.0", "jsonc-parser": "3.0.0", - "npm-package-arg": "8.1.0", - "npm-pick-manifest": "6.1.0", - "open": "7.4.0", - "ora": "5.3.0", - "pacote": "11.2.4", - "resolve": "1.19.0", - "rimraf": "3.0.2", - "semver": "7.3.4", - "symbol-observable": "3.0.0", - "universal-analytics": "0.4.23", + "npm-package-arg": "8.1.5", + "npm-pick-manifest": "6.1.1", + "open": "8.4.0", + "ora": "5.4.1", + "pacote": "12.0.3", + "resolve": "1.22.0", + "semver": "7.3.5", + "symbol-observable": "4.0.0", "uuid": "8.3.2" }, "dependencies": { - "@angular-devkit/architect": { - "version": "0.1102.11", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1102.11.tgz", - "integrity": "sha512-1MoUSz7zNJomUUuzbIyBSprzbWa9eF97SRDEbllYHHXY/IWWetHGNK7gkJPyW0zgKhXIc5Sq4TJKIJKWPNh00Q==", - "dev": true, - "requires": { - "@angular-devkit/core": "11.2.11", - "rxjs": "6.6.3" - } - }, - "@angular-devkit/core": { - "version": "11.2.11", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-11.2.11.tgz", - "integrity": "sha512-6gFrpG0o00Y4kMU7cQeQ5fSlmXRvNlidylM3OfAvpj0qHoRKo1E3q9iVr4fW3oVZxK3fpCSN7RE5Myl5Y7mV0w==", - "dev": true, - "requires": { - "ajv": "6.12.6", - "fast-json-stable-stringify": "2.1.0", - "magic-string": "0.25.7", - "rxjs": "6.6.3", - "source-map": "0.7.3" - } - }, - "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, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "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, - "requires": { - "color-name": "~1.1.4" - } - }, - "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 - }, - "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 - }, "ini": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", "dev": true }, - "open": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/open/-/open-7.4.0.tgz", - "integrity": "sha512-PGoBCX/lclIWlpS/R2PQuIR4NJoXh6X5AwVzE7WXnWRGvHg7+4TBCgsujUgiPpm0K1y4qvQeWnCWVTpTKZBtvA==", + "is-core-module": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", + "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", "dev": true, "requires": { - "is-docker": "^2.0.0", - "is-wsl": "^2.1.1" + "has": "^1.0.3" } }, - "ora": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.3.0.tgz", - "integrity": "sha512-zAKMgGXUim0Jyd6CXK9lraBnD3H5yPGBPPOkC23a2BG6hsm4Zu6OQSjQuEtV0BHDf4aKHcUFvJiGRrFuW3MG8g==", + "resolve": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", + "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", "dev": true, "requires": { - "bl": "^4.0.3", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-spinners": "^2.5.0", - "is-interactive": "^1.0.0", - "log-symbols": "^4.0.0", - "strip-ansi": "^6.0.0", - "wcwidth": "^1.0.1" + "is-core-module": "^2.8.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" } }, "semver": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", - "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", "dev": true, "requires": { "lru-cache": "^6.0.0" } }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - }, "uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", @@ -449,214 +496,80 @@ } }, "@angular/common": { - "version": "11.0.4", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-11.0.4.tgz", - "integrity": "sha512-4R2ALj71J6EAHVCKNnHHCKL7wcosMsv3gcMXbMTE+Wpzo3khEhM0Tej+I1qmMbVmGXVlRb//4+rjE4gff6FvQw==", + "version": "13.2.2", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-13.2.2.tgz", + "integrity": "sha512-56C/bheNLKtTCyQUZCiYtKbBIZN9jj6rjFILPtJCGls3cBCxp7t9tIdoLiQG/wVQRmaxdj1ioLT+sCWz7mLtQw==", "requires": { - "tslib": "^2.0.0" + "tslib": "^2.3.0" } }, "@angular/compiler": { - "version": "11.0.4", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-11.0.4.tgz", - "integrity": "sha512-Smf8FKSjkqd522ZCdXjSnVv1lYA0b21AN3WC5L1mwtRwyl/VacqCA/YEklLneDGgI2FdSIC9+bzSQIV+CCVftA==", + "version": "13.2.2", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-13.2.2.tgz", + "integrity": "sha512-XXQtB0/e7pR2LPrHmpEiTU72SX4xxHGy91vYWIj1JCjSn0fYF7vtHzSJPXDvkbnkNow/PXXzJJYaU1ctdMZPcA==", "requires": { - "tslib": "^2.0.0" + "tslib": "^2.3.0" } }, "@angular/compiler-cli": { - "version": "11.0.4", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-11.0.4.tgz", - "integrity": "sha512-FV010O6GAldRe5sr+qegHe7oLinTylES70NX+0PIp44/W4tPx75Zvop+FVT90I4xPcvFvteLemy8nFAnMK+x5g==", + "version": "13.2.2", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-13.2.2.tgz", + "integrity": "sha512-tuOIcEEKVIht+mKrj0rtX3I8gc+ByPjzpCZhFQRggxM6xbKJIToO1zERbEGKrZ+sUJ6BB5KLvscDy+Pddy3b8w==", "dev": true, "requires": { "@babel/core": "^7.8.6", - "@babel/types": "^7.8.6", - "canonical-path": "1.0.0", "chokidar": "^3.0.0", "convert-source-map": "^1.5.1", - "dependency-graph": "^0.7.2", - "fs-extra": "4.0.2", + "dependency-graph": "^0.11.0", "magic-string": "^0.25.0", - "minimist": "^1.2.0", "reflect-metadata": "^0.1.2", - "semver": "^6.3.0", - "source-map": "^0.6.1", + "semver": "^7.0.0", "sourcemap-codec": "^1.4.8", - "tslib": "^2.0.0", - "yargs": "^16.1.1" + "tslib": "^2.3.0", + "yargs": "^17.2.1" }, "dependencies": { - "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, - "requires": { - "color-convert": "^2.0.1" - } - }, - "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, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "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, - "requires": { - "color-name": "~1.1.4" - } - }, - "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 - }, "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - }, - "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 - }, - "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", "dev": true, "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "lru-cache": "^6.0.0" } - }, - "y18n": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.5.tgz", - "integrity": "sha512-hsRUr4FFrvhhRH12wOdfs38Gy7k2FFzB9qgN9v3aLykRq0dRcdcpz5C9FxdS2NuhOrI/628b/KSTJ3rwHysYSg==", - "dev": true - }, - "yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "requires": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - } - }, - "yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", - "dev": true } } }, "@angular/core": { - "version": "11.0.9", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-11.0.9.tgz", - "integrity": "sha512-J0ff3UK2Cw7Z0eNLtUXrpMFvmmkvPPZWLYIwimyc1pZys7qsIVT6cy2ybGEOhbJgC6qt3fo0DoJV3pGXTalb8A==", + "version": "13.2.2", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-13.2.2.tgz", + "integrity": "sha512-zpctw0BxIVOsRFnckchK15SD1L8tzhf5GzwIDaM6+VylDQj1uYkm8mvAjJTQZyUuApomoFet2Rfj7XQPV+cNSQ==", "requires": { - "tslib": "^2.0.0" + "tslib": "^2.3.0" } }, "@angular/forms": { - "version": "11.0.4", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-11.0.4.tgz", - "integrity": "sha512-Fhfc4buwMZk0WumDvl/X7XBnOKFeTRTJrwKdi8LlhY6o1Og8H4e/f69u9iDJCF3YjU4qC6yGtPp9YpSVCPP7Ew==", + "version": "13.2.2", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-13.2.2.tgz", + "integrity": "sha512-T61W4Ay9X9qhxjc6lLqpNFeHrGKwg2mqdsZ3zIm/c7oKo37mgl9TB5kkrtnS+205r3N2hF4ICnGFZ4a/egUP/g==", "requires": { - "tslib": "^2.0.0" + "tslib": "^2.3.0" } }, "@angular/localize": { - "version": "11.0.4", - "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-11.0.4.tgz", - "integrity": "sha512-r0dWvwFvEqQJ/H94rr548S092Hq53RqyMANuFD09CpkWXS6yAWBfArB6mW77PARnicEC0zkbi5qMGACjtSyNtA==", + "version": "13.2.2", + "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-13.2.2.tgz", + "integrity": "sha512-W/deDIxAFlv0euq7hxYPRCvj2DtDTsid5mRqyjEaVr+eYaLPnD8EElZuKuQEDeo7rWkCjljEpBrFsXwC5FZ8cw==", "requires": { - "@babel/core": "7.8.3", - "glob": "7.1.2", - "yargs": "^16.1.1" + "@babel/core": "7.8.6", + "glob": "7.2.0", + "yargs": "^17.2.1" }, "dependencies": { - "@babel/core": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.8.3.tgz", - "integrity": "sha512-4XFkf8AwyrEG7Ziu3L2L0Cv+WyY47Tcsp70JFmpftbAA1K7YL/sgE9jh9HyNj08Y/U50ItUchpN0w6HxAoX1rA==", - "requires": { - "@babel/code-frame": "^7.8.3", - "@babel/generator": "^7.8.3", - "@babel/helpers": "^7.8.3", - "@babel/parser": "^7.8.3", - "@babel/template": "^7.8.3", - "@babel/traverse": "^7.8.3", - "@babel/types": "^7.8.3", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.1", - "json5": "^2.1.0", - "lodash": "^4.17.13", - "resolve": "^1.3.2", - "semver": "^5.4.1", - "source-map": "^0.5.0" - } - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "requires": { - "color-convert": "^2.0.1" - } - }, - "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "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==", - "requires": { - "color-name": "~1.1.4" - } - }, - "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==" - }, "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -665,77 +578,39 @@ "once": "^1.3.0", "path-is-absolute": "^1.0.0" } - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" - }, - "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "y18n": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.5.tgz", - "integrity": "sha512-hsRUr4FFrvhhRH12wOdfs38Gy7k2FFzB9qgN9v3aLykRq0dRcdcpz5C9FxdS2NuhOrI/628b/KSTJ3rwHysYSg==" - }, - "yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "requires": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - } - }, - "yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==" } } }, "@angular/platform-browser": { - "version": "11.0.4", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-11.0.4.tgz", - "integrity": "sha512-+uUCKJgspSghJ3R6Fk0XHA0tolbaRBi8JFS2cY+hi9s27WKB88peGvtsK6RCOPJONY6JdOuhpcZqRN8dKfPi7w==", + "version": "13.2.2", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-13.2.2.tgz", + "integrity": "sha512-M7gWC8fFCPc/CRcHCzqe/j7WzwAUMeKt9vwlK633XnesHBoqZdYgbb3YHHc6WPVU0YI09Nb/Hm5sezEKmjUmPg==", "requires": { - "tslib": "^2.0.0" + "tslib": "^2.3.0" } }, "@angular/platform-browser-dynamic": { - "version": "11.0.4", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-11.0.4.tgz", - "integrity": "sha512-ZOWTZaFfZSHhMy7a0RIxipiZoiobHWrGlq8/YaMrIgzUb9Fv518FeFCCI68BP0/GuyxX74MJmzv4ZgQctKKxXw==", + "version": "13.2.2", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-13.2.2.tgz", + "integrity": "sha512-lj6xwat0StLp+ROFqXU62upwHQhlxaQi0djhrS+DGKUK0Xu9bkBeaSCfBFgS78jPm1SwL8Xztu9/vuDAHLRrqw==", "requires": { - "tslib": "^2.0.0" + "tslib": "^2.3.0" } }, "@angular/router": { - "version": "11.0.4", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-11.0.4.tgz", - "integrity": "sha512-B0sqv8zMM6j88+udEZzO8wKBw61pHgWZmLopnAqA65rRPrAvMsvAHUnYqX6w5pYqhJQxCVLVeKM+0QlQh1+WnA==", + "version": "13.2.2", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-13.2.2.tgz", + "integrity": "sha512-dt2b9/kGJAkmOqUmUD3aKlp4pGpdqLwB0zmhUYF3ktNEcQaPf4ZjWT/4jhy09gFL+TKOHG5OQW9GxBbhWI4bSg==", "requires": { - "tslib": "^2.0.0" + "tslib": "^2.3.0" } }, + "@assemblyscript/loader": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@assemblyscript/loader/-/loader-0.10.1.tgz", + "integrity": "sha512-H71nDOOL8Y7kWRLqf6Sums+01Q5msqBW2KhDUTemh1tvY04eSkSXrK0uj/4mmY0Xr16/3zyZmsrxN7CKuRbNRg==", + "dev": true + }, "@babel/code-frame": { "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", @@ -745,272 +620,279 @@ } }, "@babel/compat-data": { - "version": "7.12.7", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.12.7.tgz", - "integrity": "sha512-YaxPMGs/XIWtYqrdEOZOCPsVWfEoriXopnsz3/i7apYPXQ3698UFhS6dVT1KN5qOsWmVgw/FOrmQgpRaZayGsw==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.0.tgz", + "integrity": "sha512-392byTlpGWXMv4FbyWw3sAZ/FrW/DrwqLGXpy0mbyNe9Taqv1mg9yON5/o0cnr8XYCkFTZbC1eV+c+LAROgrng==", "dev": true }, "@babel/core": { - "version": "7.12.3", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.3.tgz", - "integrity": "sha512-0qXcZYKZp3/6N2jKYVxZv0aNCsxTSVCiK72DTiTYZAu7sjg73W0/aynWjMbiGd87EQL4WyA8reiJVh92AVla9g==", - "dev": true, + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.8.6.tgz", + "integrity": "sha512-Sheg7yEJD51YHAvLEV/7Uvw95AeWqYPL3Vk3zGujJKIhJ+8oLw2ALaf3hbucILhKsgSoADOvtKRJuNVdcJkOrg==", "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.12.1", - "@babel/helper-module-transforms": "^7.12.1", - "@babel/helpers": "^7.12.1", - "@babel/parser": "^7.12.3", - "@babel/template": "^7.10.4", - "@babel/traverse": "^7.12.1", - "@babel/types": "^7.12.1", + "@babel/code-frame": "^7.8.3", + "@babel/generator": "^7.8.6", + "@babel/helpers": "^7.8.4", + "@babel/parser": "^7.8.6", + "@babel/template": "^7.8.6", + "@babel/traverse": "^7.8.6", + "@babel/types": "^7.8.6", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.1", - "json5": "^2.1.2", - "lodash": "^4.17.19", + "json5": "^2.1.0", + "lodash": "^4.17.13", "resolve": "^1.3.2", "semver": "^5.4.1", "source-map": "^0.5.0" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } } }, "@babel/generator": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.1.tgz", - "integrity": "sha512-DB+6rafIdc9o72Yc3/Ph5h+6hUjeOp66pF0naQBgUFFuPqzQwIlPTm3xZR7YNvduIMtkDIj2t21LSQwnbCrXvg==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.0.tgz", + "integrity": "sha512-I3Omiv6FGOC29dtlZhkfXO6pgkmukJSlT26QjVvS1DGZe/NzSVCPG41X0tS21oZkJYlovfj9qDWgKP+Cn4bXxw==", "requires": { - "@babel/types": "^7.12.1", + "@babel/types": "^7.17.0", "jsesc": "^2.5.1", "source-map": "^0.5.0" - }, - "dependencies": { - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" - } } }, "@babel/helper-annotate-as-pure": { - "version": "7.12.10", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.12.10.tgz", - "integrity": "sha512-XplmVbC1n+KY6jL8/fgLVXXUauDIB+lD5+GsQEh6F6GBF1dq1qy4DP4yXWzDKcoqXB3X58t61e85Fitoww4JVQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz", + "integrity": "sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw==", "dev": true, "requires": { - "@babel/types": "^7.12.10" + "@babel/types": "^7.16.7" } }, "@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.10.4.tgz", - "integrity": "sha512-L0zGlFrGWZK4PbT8AszSfLTM5sDU1+Az/En9VrdT8/LmEiJt4zXt+Jve9DCAnQcbqDhCI+29y/L93mrDzddCcg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.7.tgz", + "integrity": "sha512-C6FdbRaxYjwVu/geKW4ZeQ0Q31AftgRcdSnZ5/jsH6BzCJbtvXvhpfkbkThYSuutZA7nCXpPR6AD9zd1dprMkA==", "dev": true, "requires": { - "@babel/helper-explode-assignable-expression": "^7.10.4", - "@babel/types": "^7.10.4" + "@babel/helper-explode-assignable-expression": "^7.16.7", + "@babel/types": "^7.16.7" } }, "@babel/helper-compilation-targets": { - "version": "7.12.5", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.12.5.tgz", - "integrity": "sha512-+qH6NrscMolUlzOYngSBMIOQpKUGPPsc61Bu5W10mg84LxZ7cmvnBHzARKbDoFxVvqqAbj6Tg6N7bSrWSPXMyw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz", + "integrity": "sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA==", "dev": true, "requires": { - "@babel/compat-data": "^7.12.5", - "@babel/helper-validator-option": "^7.12.1", - "browserslist": "^4.14.5", - "semver": "^5.5.0" + "@babel/compat-data": "^7.16.4", + "@babel/helper-validator-option": "^7.16.7", + "browserslist": "^4.17.5", + "semver": "^6.3.0" }, "dependencies": { "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true } } }, "@babel/helper-create-class-features-plugin": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.12.1.tgz", - "integrity": "sha512-hkL++rWeta/OVOBTRJc9a5Azh5mt5WgZUGAKMD8JM141YsE08K//bp1unBBieO6rUKkIPyUE0USQ30jAy3Sk1w==", + "version": "7.17.1", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.1.tgz", + "integrity": "sha512-JBdSr/LtyYIno/pNnJ75lBcqc3Z1XXujzPanHqjvvrhOA+DTceTFuJi8XjmWTZh4r3fsdfqaCMN0iZemdkxZHQ==", "dev": true, "requires": { - "@babel/helper-function-name": "^7.10.4", - "@babel/helper-member-expression-to-functions": "^7.12.1", - "@babel/helper-optimise-call-expression": "^7.10.4", - "@babel/helper-replace-supers": "^7.12.1", - "@babel/helper-split-export-declaration": "^7.10.4" + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-member-expression-to-functions": "^7.16.7", + "@babel/helper-optimise-call-expression": "^7.16.7", + "@babel/helper-replace-supers": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7" } }, "@babel/helper-create-regexp-features-plugin": { - "version": "7.12.7", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.12.7.tgz", - "integrity": "sha512-idnutvQPdpbduutvi3JVfEgcVIHooQnhvhx0Nk9isOINOIGYkZea1Pk2JlJRiUnMefrlvr0vkByATBY/mB4vjQ==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.17.0.tgz", + "integrity": "sha512-awO2So99wG6KnlE+TPs6rn83gCz5WlEePJDTnLEqbchMVrBeAujURVphRdigsk094VhvZehFoNOihSlcBjwsXA==", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "^7.10.4", - "regexpu-core": "^4.7.1" + "@babel/helper-annotate-as-pure": "^7.16.7", + "regexpu-core": "^5.0.1" } }, - "@babel/helper-define-map": { - "version": "7.10.5", - "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.10.5.tgz", - "integrity": "sha512-fMw4kgFB720aQFXSVaXr79pjjcW5puTCM16+rECJ/plGS+zByelE8l9nCpV1GibxTnFVmUuYG9U8wYfQHdzOEQ==", + "@babel/helper-define-polyfill-provider": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.1.tgz", + "integrity": "sha512-J9hGMpJQmtWmj46B3kBHmL38UhJGhYX7eqkcq+2gsstyYt341HmPeWspihX43yVRA0mS+8GGk2Gckc7bY/HCmA==", "dev": true, "requires": { - "@babel/helper-function-name": "^7.10.4", - "@babel/types": "^7.10.5", - "lodash": "^4.17.19" + "@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" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "@babel/helper-environment-visitor": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz", + "integrity": "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==", + "requires": { + "@babel/types": "^7.16.7" } }, "@babel/helper-explode-assignable-expression": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.12.1.tgz", - "integrity": "sha512-dmUwH8XmlrUpVqgtZ737tK88v07l840z9j3OEhCLwKTkjlvKpfqXVIZ0wpK3aeOxspwGrf/5AP5qLx4rO3w5rA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.7.tgz", + "integrity": "sha512-KyUenhWMC8VrxzkGP0Jizjo4/Zx+1nNZhgocs+gLzyZyB8SHidhoq9KK/8Ato4anhwsivfkBLftky7gvzbZMtQ==", "dev": true, "requires": { - "@babel/types": "^7.12.1" + "@babel/types": "^7.16.7" } }, "@babel/helper-function-name": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz", - "integrity": "sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz", + "integrity": "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==", "requires": { - "@babel/helper-get-function-arity": "^7.10.4", - "@babel/template": "^7.10.4", - "@babel/types": "^7.10.4" + "@babel/helper-get-function-arity": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/types": "^7.16.7" } }, "@babel/helper-get-function-arity": { - "version": "7.12.10", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.10.tgz", - "integrity": "sha512-mm0n5BPjR06wh9mPQaDdXWDoll/j5UpCAPl1x8fS71GHm7HA6Ua2V4ylG1Ju8lvcTOietbPNNPaSilKj+pj+Ag==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz", + "integrity": "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==", "requires": { - "@babel/types": "^7.12.10" + "@babel/types": "^7.16.7" } }, "@babel/helper-hoist-variables": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.10.4.tgz", - "integrity": "sha512-wljroF5PgCk2juF69kanHVs6vrLwIPNp6DLD+Lrl3hoQ3PpPPikaDRNFA+0t81NOoMt2DL6WW/mdU8k4k6ZzuA==", - "dev": true, + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz", + "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==", "requires": { - "@babel/types": "^7.10.4" + "@babel/types": "^7.16.7" } }, "@babel/helper-member-expression-to-functions": { - "version": "7.12.7", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.7.tgz", - "integrity": "sha512-DCsuPyeWxeHgh1Dus7APn7iza42i/qXqiFPWyBDdOFtvS581JQePsc1F/nD+fHrcswhLlRc2UpYS1NwERxZhHw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.7.tgz", + "integrity": "sha512-VtJ/65tYiU/6AbMTDwyoXGPKHgTsfRarivm+YbB5uAzKUyuPjgZSgAFeG87FCigc7KNHu2Pegh1XIT3lXjvz3Q==", "dev": true, "requires": { - "@babel/types": "^7.12.7" + "@babel/types": "^7.16.7" } }, "@babel/helper-module-imports": { - "version": "7.12.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.12.5.tgz", - "integrity": "sha512-SR713Ogqg6++uexFRORf/+nPXMmWIn80TALu0uaFb+iQIUoR7bOC7zBWyzBs5b3tBBJXuyD0cRu1F15GyzjOWA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz", + "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==", "dev": true, "requires": { - "@babel/types": "^7.12.5" + "@babel/types": "^7.16.7" } }, "@babel/helper-module-transforms": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.12.1.tgz", - "integrity": "sha512-QQzehgFAZ2bbISiCpmVGfiGux8YVFXQ0abBic2Envhej22DVXV9nCFaS5hIQbkyo1AdGb+gNME2TSh3hYJVV/w==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.16.7.tgz", + "integrity": "sha512-gaqtLDxJEFCeQbYp9aLAefjhkKdjKcdh6DB7jniIGU3Pz52WAmP268zK0VgPz9hUNkMSYeH976K2/Y6yPadpng==", "dev": true, "requires": { - "@babel/helper-module-imports": "^7.12.1", - "@babel/helper-replace-supers": "^7.12.1", - "@babel/helper-simple-access": "^7.12.1", - "@babel/helper-split-export-declaration": "^7.11.0", - "@babel/helper-validator-identifier": "^7.10.4", - "@babel/template": "^7.10.4", - "@babel/traverse": "^7.12.1", - "@babel/types": "^7.12.1", - "lodash": "^4.17.19" + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-module-imports": "^7.16.7", + "@babel/helper-simple-access": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/helper-validator-identifier": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.16.7", + "@babel/types": "^7.16.7" + }, + "dependencies": { + "@babel/helper-validator-identifier": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", + "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", + "dev": true + } } }, "@babel/helper-optimise-call-expression": { - "version": "7.12.10", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.10.tgz", - "integrity": "sha512-4tpbU0SrSTjjt65UMWSrUOPZTsgvPgGG4S8QSTNHacKzpS51IVWGDj0yCwyeZND/i+LSN2g/O63jEXEWm49sYQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz", + "integrity": "sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w==", "dev": true, "requires": { - "@babel/types": "^7.12.10" + "@babel/types": "^7.16.7" } }, "@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==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz", + "integrity": "sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==", "dev": true }, "@babel/helper-remap-async-to-generator": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.12.1.tgz", - "integrity": "sha512-9d0KQCRM8clMPcDwo8SevNs+/9a8yWVVmaE80FGJcEP8N1qToREmWEGnBn8BUlJhYRFz6fqxeRL1sl5Ogsed7A==", + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.8.tgz", + "integrity": "sha512-fm0gH7Flb8H51LqJHy3HJ3wnE1+qtYR2A99K06ahwrawLdOFsCEWjZOrYricXJHoPSudNKxrMBUPEIPxiIIvBw==", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "^7.10.4", - "@babel/helper-wrap-function": "^7.10.4", - "@babel/types": "^7.12.1" + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-wrap-function": "^7.16.8", + "@babel/types": "^7.16.8" } }, "@babel/helper-replace-supers": { - "version": "7.12.5", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.12.5.tgz", - "integrity": "sha512-5YILoed0ZyIpF4gKcpZitEnXEJ9UoDRki1Ey6xz46rxOzfNMAhVIJMoune1hmPVxh40LRv1+oafz7UsWX+vyWA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.16.7.tgz", + "integrity": "sha512-y9vsWilTNaVnVh6xiJfABzsNpgDPKev9HnAgz6Gb1p6UUwf9NepdlsV7VXGCftJM+jqD5f7JIEubcpLjZj5dBw==", "dev": true, "requires": { - "@babel/helper-member-expression-to-functions": "^7.12.1", - "@babel/helper-optimise-call-expression": "^7.10.4", - "@babel/traverse": "^7.12.5", - "@babel/types": "^7.12.5" + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-member-expression-to-functions": "^7.16.7", + "@babel/helper-optimise-call-expression": "^7.16.7", + "@babel/traverse": "^7.16.7", + "@babel/types": "^7.16.7" } }, "@babel/helper-simple-access": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.12.1.tgz", - "integrity": "sha512-OxBp7pMrjVewSSC8fXDFrHrBcJATOOFssZwv16F3/6Xtc138GHybBfPbm9kfiqQHKhYQrlamWILwlDCeyMFEaA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz", + "integrity": "sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g==", "dev": true, "requires": { - "@babel/types": "^7.12.1" + "@babel/types": "^7.16.7" } }, "@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.12.1.tgz", - "integrity": "sha512-Mf5AUuhG1/OCChOJ/HcADmvcHM42WJockombn8ATJG3OnyiSxBK/Mm5x78BQWvmtXZKHgbjdGL2kin/HOLlZGA==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz", + "integrity": "sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw==", "dev": true, "requires": { - "@babel/types": "^7.12.1" + "@babel/types": "^7.16.0" } }, "@babel/helper-split-export-declaration": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz", - "integrity": "sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz", + "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==", "requires": { - "@babel/types": "^7.11.0" + "@babel/types": "^7.16.7" } }, "@babel/helper-validator-identifier": { @@ -1019,31 +901,31 @@ "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==" }, "@babel/helper-validator-option": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.12.1.tgz", - "integrity": "sha512-YpJabsXlJVWP0USHjnC/AQDTLlZERbON577YUVO/wLpqyj6HAtVYnWaQaN0iUN+1/tWn3c+uKKXjRut5115Y2A==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz", + "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==", "dev": true }, "@babel/helper-wrap-function": { - "version": "7.12.3", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.12.3.tgz", - "integrity": "sha512-Cvb8IuJDln3rs6tzjW3Y8UeelAOdnpB8xtQ4sme2MSZ9wOxrbThporC0y/EtE16VAtoyEfLM404Xr1e0OOp+ow==", + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.16.8.tgz", + "integrity": "sha512-8RpyRVIAW1RcDDGTA+GpPAwV22wXCfKOoM9bet6TLkGIFTkRQSkH1nMQ5Yet4MpoXe1ZwHPVtNasc2w0uZMqnw==", "dev": true, "requires": { - "@babel/helper-function-name": "^7.10.4", - "@babel/template": "^7.10.4", - "@babel/traverse": "^7.10.4", - "@babel/types": "^7.10.4" + "@babel/helper-function-name": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.16.8", + "@babel/types": "^7.16.8" } }, "@babel/helpers": { - "version": "7.12.5", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.12.5.tgz", - "integrity": "sha512-lgKGMQlKqA8meJqKsW6rUnc4MdUk35Ln0ATDqdM1a/UpARODdI4j5Y5lVfUScnSNkJcdCRAaWkspykNoFg9sJA==", + "version": "7.17.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.2.tgz", + "integrity": "sha512-0Qu7RLR1dILozr/6M0xgj+DFPmi6Bnulgm9M8BVa9ZCWxDqlSnqt3cf8IDPB5m45sVXUZ0kuQAgUrdSFFH79fQ==", "requires": { - "@babel/template": "^7.10.4", - "@babel/traverse": "^7.12.5", - "@babel/types": "^7.12.5" + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.17.0", + "@babel/types": "^7.17.0" } }, "@babel/highlight": { @@ -1057,141 +939,186 @@ } }, "@babel/parser": { - "version": "7.12.10", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.10.tgz", - "integrity": "sha512-PJdRPwyoOqFAWfLytxrWwGrAxghCgh/yTNCYciOz8QgjflA7aZhECPZAa2VUedKg2+QMWkI0L9lynh2SNmNEgA==" + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.0.tgz", + "integrity": "sha512-VKXSCQx5D8S04ej+Dqsr1CzYvvWgf20jIw2D+YhQCrIlr2UZGaDds23Y0xg75/skOxpLCRpUZvk/1EAVkGoDOw==" }, - "@babel/plugin-proposal-async-generator-functions": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.12.1.tgz", - "integrity": "sha512-d+/o30tJxFxrA1lhzJqiUcEJdI6jKlNregCv5bASeGf2Q4MXmnwH7viDo7nhx1/ohf09oaH8j1GVYG/e3Yqk6A==", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.16.7.tgz", + "integrity": "sha512-anv/DObl7waiGEnC24O9zqL0pSuI9hljihqiDuFHC8d7/bjr/4RLGPWuc8rYOff/QPzbEPSkzG8wGG9aDuhHRg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-remap-async-to-generator": "^7.12.1", - "@babel/plugin-syntax-async-generators": "^7.8.0" + "@babel/helper-plugin-utils": "^7.16.7" + } + }, + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.16.7.tgz", + "integrity": "sha512-di8vUHRdf+4aJ7ltXhaDbPoszdkh59AQtJM5soLsuHpQJdFQZOA4uGj0V2u/CZ8bJ/u8ULDL5yq6FO/bCXnKHw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", + "@babel/plugin-proposal-optional-chaining": "^7.16.7" + } + }, + "@babel/plugin-proposal-async-generator-functions": { + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.8.tgz", + "integrity": "sha512-71YHIvMuiuqWJQkebWJtdhQTfd4Q4mF76q2IX37uZPkG9+olBxsX+rH1vkhFto4UeJZ9dPY2s+mDvhDm1u2BGQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-remap-async-to-generator": "^7.16.8", + "@babel/plugin-syntax-async-generators": "^7.8.4" } }, "@babel/plugin-proposal-class-properties": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.12.1.tgz", - "integrity": "sha512-cKp3dlQsFsEs5CWKnN7BnSHOd0EOW8EKpEjkoz1pO2E5KzIDNV9Ros1b0CnmbVgAGXJubOYVBOGCT1OmJwOI7w==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.7.tgz", + "integrity": "sha512-IobU0Xme31ewjYOShSIqd/ZGM/r/cuOz2z0MDbNrhF5FW+ZVgi0f2lyeoj9KFPDOAqsYxmLWZte1WOwlvY9aww==", "dev": true, "requires": { - "@babel/helper-create-class-features-plugin": "^7.12.1", - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-create-class-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" + } + }, + "@babel/plugin-proposal-class-static-block": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.16.7.tgz", + "integrity": "sha512-dgqJJrcZoG/4CkMopzhPJjGxsIe9A8RlkQLnL/Vhhx8AA9ZuaRwGSlscSh42hazc7WSrya/IK7mTeoF0DP9tEw==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-class-static-block": "^7.14.5" } }, "@babel/plugin-proposal-dynamic-import": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.12.1.tgz", - "integrity": "sha512-a4rhUSZFuq5W8/OO8H7BL5zspjnc1FLd9hlOxIK/f7qG4a0qsqk8uvF/ywgBA8/OmjsapjpvaEOYItfGG1qIvQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.7.tgz", + "integrity": "sha512-I8SW9Ho3/8DRSdmDdH3gORdyUuYnk1m4cMxUAdu5oy4n3OfN8flDEH+d60iG7dUfi0KkYwSvoalHzzdRzpWHTg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-dynamic-import": "^7.8.0" + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" } }, "@babel/plugin-proposal-export-namespace-from": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.12.1.tgz", - "integrity": "sha512-6CThGf0irEkzujYS5LQcjBx8j/4aQGiVv7J9+2f7pGfxqyKh3WnmVJYW3hdrQjyksErMGBPQrCnHfOtna+WLbw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.7.tgz", + "integrity": "sha512-ZxdtqDXLRGBL64ocZcs7ovt71L3jhC1RGSyR996svrCi3PYqHNkb3SwPJCs8RIzD86s+WPpt2S73+EHCGO+NUA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-export-namespace-from": "^7.8.3" } }, "@babel/plugin-proposal-json-strings": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.12.1.tgz", - "integrity": "sha512-GoLDUi6U9ZLzlSda2Df++VSqDJg3CG+dR0+iWsv6XRw1rEq+zwt4DirM9yrxW6XWaTpmai1cWJLMfM8qQJf+yw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.16.7.tgz", + "integrity": "sha512-lNZ3EEggsGY78JavgbHsK9u5P3pQaW7k4axlgFLYkMd7UBsiNahCITShLjNQschPyjtO6dADrL24757IdhBrsQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-json-strings": "^7.8.0" + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-json-strings": "^7.8.3" } }, "@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.12.1.tgz", - "integrity": "sha512-k8ZmVv0JU+4gcUGeCDZOGd0lCIamU/sMtIiX3UWnUc5yzgq6YUGyEolNYD+MLYKfSzgECPcqetVcJP9Afe/aCA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.7.tgz", + "integrity": "sha512-K3XzyZJGQCr00+EtYtrDjmwX7o7PLK6U9bi1nCwkQioRFVUv6dJoxbQjtWVtP+bCPy82bONBKG8NPyQ4+i6yjg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" } }, "@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.12.1.tgz", - "integrity": "sha512-nZY0ESiaQDI1y96+jk6VxMOaL4LPo/QDHBqL+SF3/vl6dHkTwHlOI8L4ZwuRBHgakRBw5zsVylel7QPbbGuYgg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.16.7.tgz", + "integrity": "sha512-aUOrYU3EVtjf62jQrCj63pYZ7k6vns2h/DQvHPWGmsJRYzWXZ6/AsfgpiRy6XiuIDADhJzP2Q9MwSMKauBQ+UQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0" + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" } }, "@babel/plugin-proposal-numeric-separator": { - "version": "7.12.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.12.7.tgz", - "integrity": "sha512-8c+uy0qmnRTeukiGsjLGy6uVs/TFjJchGXUeBqlG4VWYOdJWkhhVPdQ3uHwbmalfJwv2JsV0qffXP4asRfL2SQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.7.tgz", + "integrity": "sha512-vQgPMknOIgiuVqbokToyXbkY/OmmjAzr/0lhSIbG/KmnzXPGwW/AdhdKpi+O4X/VkWiWjnkKOBiqJrTaC98VKw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-numeric-separator": "^7.10.4" } }, "@babel/plugin-proposal-object-rest-spread": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.12.1.tgz", - "integrity": "sha512-s6SowJIjzlhx8o7lsFx5zmY4At6CTtDvgNQDdPzkBQucle58A6b/TTeEBYtyDgmcXjUTM+vE8YOGHZzzbc/ioA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.16.7.tgz", + "integrity": "sha512-3O0Y4+dw94HA86qSg9IHfyPktgR7q3gpNVAeiKQd+8jBKFaU5NQS1Yatgo4wY+UFNuLjvxcSmzcsHqrhgTyBUA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.0", - "@babel/plugin-transform-parameters": "^7.12.1" + "@babel/compat-data": "^7.16.4", + "@babel/helper-compilation-targets": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.16.7" } }, "@babel/plugin-proposal-optional-catch-binding": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.12.1.tgz", - "integrity": "sha512-hFvIjgprh9mMw5v42sJWLI1lzU5L2sznP805zeT6rySVRA0Y18StRhDqhSxlap0oVgItRsB6WSROp4YnJTJz0g==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.7.tgz", + "integrity": "sha512-eMOH/L4OvWSZAE1VkHbr1vckLG1WUcHGJSLqqQwl2GaUqG6QjddvrOaTUMNYiv77H5IKPMZ9U9P7EaHwvAShfA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.0" + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" } }, "@babel/plugin-proposal-optional-chaining": { - "version": "7.12.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.12.7.tgz", - "integrity": "sha512-4ovylXZ0PWmwoOvhU2vhnzVNnm88/Sm9nx7V8BPgMvAzn5zDou3/Awy0EjglyubVHasJj+XCEkr/r1X3P5elCA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.7.tgz", + "integrity": "sha512-eC3xy+ZrUcBtP7x+sq62Q/HYd674pPTb/77XZMb5wbDPGWIdUbSr4Agr052+zaUPSb+gGRnjxXfKFvx5iMJ+DA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-skip-transparent-expression-wrappers": "^7.12.1", - "@babel/plugin-syntax-optional-chaining": "^7.8.0" + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" } }, "@babel/plugin-proposal-private-methods": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.12.1.tgz", - "integrity": "sha512-mwZ1phvH7/NHK6Kf8LP7MYDogGV+DKB1mryFOEwx5EBNQrosvIczzZFTUmWaeujd5xT6G1ELYWUz3CutMhjE1w==", + "version": "7.16.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.11.tgz", + "integrity": "sha512-F/2uAkPlXDr8+BHpZvo19w3hLFKge+k75XUprE6jaqKxjGkSYcK+4c+bup5PdW/7W/Rpjwql7FTVEDW+fRAQsw==", "dev": true, "requires": { - "@babel/helper-create-class-features-plugin": "^7.12.1", - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-create-class-features-plugin": "^7.16.10", + "@babel/helper-plugin-utils": "^7.16.7" + } + }, + "@babel/plugin-proposal-private-property-in-object": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.16.7.tgz", + "integrity": "sha512-rMQkjcOFbm+ufe3bTZLyOfsOUOxyvLXZJCTARhJr+8UMSoZmqTe1K1BgkFcrW37rAchWg57yI69ORxiWvUINuQ==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-create-class-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" } }, "@babel/plugin-proposal-unicode-property-regex": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.12.1.tgz", - "integrity": "sha512-MYq+l+PvHuw/rKUz1at/vb6nCnQ2gmJBNaM62z0OgH7B2W1D9pvkpYtlti9bGtizNIU1K3zm4bZF9F91efVY0w==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.16.7.tgz", + "integrity": "sha512-QRK0YI/40VLhNVGIjRNAAQkEHws0cswSdFFjpFyt943YmJIU1da9uW63Iu6NFV6CxTZW5eTDCrwZUstBWgp/Rg==", "dev": true, "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.12.1", - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-create-regexp-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-syntax-async-generators": { @@ -1213,12 +1140,21 @@ } }, "@babel/plugin-syntax-class-properties": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.1.tgz", - "integrity": "sha512-U40A76x5gTwmESz+qiqssqmeEsKvcSyvtgktrm0uzcARAmM9I1jR221f6Oq+GmHrcD+LvZDag1UTOTe2fL3TeA==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" } }, "@babel/plugin-syntax-dynamic-import": { @@ -1311,434 +1247,471 @@ "@babel/helper-plugin-utils": "^7.8.0" } }, - "@babel/plugin-syntax-top-level-await": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.12.1.tgz", - "integrity": "sha512-i7ooMZFS+a/Om0crxZodrTzNEPJHZrlMVGMTEpFAj6rYY/bKCddB0Dk/YxfPuYXOopuhKk/e1jV6h+WUU9XN3A==", + "@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-typescript": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.7.tgz", + "integrity": "sha512-YhUIJHHGkqPgEcMYkPCKTyGUdoGKWtopIycQyjJH8OjvRgOYsXsaKehLVPScKJWAULPxMa4N1vCe6szREFlZ7A==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-arrow-functions": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.12.1.tgz", - "integrity": "sha512-5QB50qyN44fzzz4/qxDPQMBCTHgxg3n0xRBLJUmBlLoU/sFvxVWGZF/ZUfMVDQuJUKXaBhbupxIzIfZ6Fwk/0A==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.7.tgz", + "integrity": "sha512-9ffkFFMbvzTvv+7dTp/66xvZAWASuPD5Tl9LK3Z9vhOmANo6j94rik+5YMBt4CwHVMWLWpMsriIc2zsa3WW3xQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-async-to-generator": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.12.1.tgz", - "integrity": "sha512-SDtqoEcarK1DFlRJ1hHRY5HvJUj5kX4qmtpMAm2QnhOlyuMC4TMdCRgW6WXpv93rZeYNeLP22y8Aq2dbcDRM1A==", + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.8.tgz", + "integrity": "sha512-MtmUmTJQHCnyJVrScNzNlofQJ3dLFuobYn3mwOTKHnSCMtbNsqvF71GQmJfFjdrXSsAA7iysFmYWw4bXZ20hOg==", "dev": true, "requires": { - "@babel/helper-module-imports": "^7.12.1", - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-remap-async-to-generator": "^7.12.1" + "@babel/helper-module-imports": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-remap-async-to-generator": "^7.16.8" } }, "@babel/plugin-transform-block-scoped-functions": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.12.1.tgz", - "integrity": "sha512-5OpxfuYnSgPalRpo8EWGPzIYf0lHBWORCkj5M0oLBwHdlux9Ri36QqGW3/LR13RSVOAoUUMzoPI/jpE4ABcHoA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.7.tgz", + "integrity": "sha512-JUuzlzmF40Z9cXyytcbZEZKckgrQzChbQJw/5PuEHYeqzCsvebDx0K0jWnIIVcmmDOAVctCgnYs0pMcrYj2zJg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-block-scoping": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.12.1.tgz", - "integrity": "sha512-zJyAC9sZdE60r1nVQHblcfCj29Dh2Y0DOvlMkcqSo0ckqjiCwNiUezUKw+RjOCwGfpLRwnAeQ2XlLpsnGkvv9w==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.7.tgz", + "integrity": "sha512-ObZev2nxVAYA4bhyusELdo9hb3H+A56bxH3FZMbEImZFiEDYVHXQSJ1hQKFlDnlt8G9bBrCZ5ZpURZUrV4G5qQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-classes": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.12.1.tgz", - "integrity": "sha512-/74xkA7bVdzQTBeSUhLLJgYIcxw/dpEpCdRDiHgPJ3Mv6uC11UhjpOhl72CgqbBCmt1qtssCyB2xnJm1+PFjog==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.7.tgz", + "integrity": "sha512-WY7og38SFAGYRe64BrjKf8OrE6ulEHtr5jEYaZMwox9KebgqPi67Zqz8K53EKk1fFEJgm96r32rkKZ3qA2nCWQ==", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "^7.10.4", - "@babel/helper-define-map": "^7.10.4", - "@babel/helper-function-name": "^7.10.4", - "@babel/helper-optimise-call-expression": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-replace-supers": "^7.12.1", - "@babel/helper-split-export-declaration": "^7.10.4", + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-optimise-call-expression": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-replace-supers": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", "globals": "^11.1.0" } }, "@babel/plugin-transform-computed-properties": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.12.1.tgz", - "integrity": "sha512-vVUOYpPWB7BkgUWPo4C44mUQHpTZXakEqFjbv8rQMg7TC6S6ZhGZ3otQcRH6u7+adSlE5i0sp63eMC/XGffrzg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.7.tgz", + "integrity": "sha512-gN72G9bcmenVILj//sv1zLNaPyYcOzUho2lIJBMh/iakJ9ygCo/hEF9cpGb61SCMEDxbbyBoVQxrt+bWKu5KGw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-destructuring": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.12.1.tgz", - "integrity": "sha512-fRMYFKuzi/rSiYb2uRLiUENJOKq4Gnl+6qOv5f8z0TZXg3llUwUhsNNwrwaT/6dUhJTzNpBr+CUvEWBtfNY1cw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.16.7.tgz", + "integrity": "sha512-VqAwhTHBnu5xBVDCvrvqJbtLUa++qZaWC0Fgr2mqokBlulZARGyIvZDoqbPlPaKImQ9dKAcCzbv+ul//uqu70A==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-dotall-regex": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.12.1.tgz", - "integrity": "sha512-B2pXeRKoLszfEW7J4Hg9LoFaWEbr/kzo3teWHmtFCszjRNa/b40f9mfeqZsIDLLt/FjwQ6pz/Gdlwy85xNckBA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.7.tgz", + "integrity": "sha512-Lyttaao2SjZF6Pf4vk1dVKv8YypMpomAbygW+mU5cYP3S5cWTfCJjG8xV6CFdzGFlfWK81IjL9viiTvpb6G7gQ==", "dev": true, "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.12.1", - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-create-regexp-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-duplicate-keys": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.12.1.tgz", - "integrity": "sha512-iRght0T0HztAb/CazveUpUQrZY+aGKKaWXMJ4uf9YJtqxSUe09j3wteztCUDRHs+SRAL7yMuFqUsLoAKKzgXjw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.16.7.tgz", + "integrity": "sha512-03DvpbRfvWIXyK0/6QiR1KMTWeT6OcQ7tbhjrXyFS02kjuX/mu5Bvnh5SDSWHxyawit2g5aWhKwI86EE7GUnTw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-exponentiation-operator": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.12.1.tgz", - "integrity": "sha512-7tqwy2bv48q+c1EHbXK0Zx3KXd2RVQp6OC7PbwFNt/dPTAV3Lu5sWtWuAj8owr5wqtWnqHfl2/mJlUmqkChKug==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.7.tgz", + "integrity": "sha512-8UYLSlyLgRixQvlYH3J2ekXFHDFLQutdy7FfFAMm3CPZ6q9wHCwnUyiXpQCe3gVVnQlHc5nsuiEVziteRNTXEA==", "dev": true, "requires": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-for-of": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.12.1.tgz", - "integrity": "sha512-Zaeq10naAsuHo7heQvyV0ptj4dlZJwZgNAtBYBnu5nNKJoW62m0zKcIEyVECrUKErkUkg6ajMy4ZfnVZciSBhg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.7.tgz", + "integrity": "sha512-/QZm9W92Ptpw7sjI9Nx1mbcsWz33+l8kuMIQnDwgQBG5s3fAfQvkRjQ7NqXhtNcKOnPkdICmUHyCaWW06HCsqg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-function-name": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.12.1.tgz", - "integrity": "sha512-JF3UgJUILoFrFMEnOJLJkRHSk6LUSXLmEFsA23aR2O5CSLUxbeUX1IZ1YQ7Sn0aXb601Ncwjx73a+FVqgcljVw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.7.tgz", + "integrity": "sha512-SU/C68YVwTRxqWj5kgsbKINakGag0KTgq9f2iZEXdStoAbOzLHEBRYzImmA6yFo8YZhJVflvXmIHUO7GWHmxxA==", "dev": true, "requires": { - "@babel/helper-function-name": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-compilation-targets": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-literals": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.12.1.tgz", - "integrity": "sha512-+PxVGA+2Ag6uGgL0A5f+9rklOnnMccwEBzwYFL3EUaKuiyVnUipyXncFcfjSkbimLrODoqki1U9XxZzTvfN7IQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.7.tgz", + "integrity": "sha512-6tH8RTpTWI0s2sV6uq3e/C9wPo4PTqqZps4uF0kzQ9/xPLFQtipynvmT1g/dOfEJ+0EQsHhkQ/zyRId8J2b8zQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-member-expression-literals": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.12.1.tgz", - "integrity": "sha512-1sxePl6z9ad0gFMB9KqmYofk34flq62aqMt9NqliS/7hPEpURUCMbyHXrMPlo282iY7nAvUB1aQd5mg79UD9Jg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.7.tgz", + "integrity": "sha512-mBruRMbktKQwbxaJof32LT9KLy2f3gH+27a5XSuXo6h7R3vqltl0PgZ80C8ZMKw98Bf8bqt6BEVi3svOh2PzMw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-modules-amd": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.12.1.tgz", - "integrity": "sha512-tDW8hMkzad5oDtzsB70HIQQRBiTKrhfgwC/KkJeGsaNFTdWhKNt/BiE8c5yj19XiGyrxpbkOfH87qkNg1YGlOQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.16.7.tgz", + "integrity": "sha512-KaaEtgBL7FKYwjJ/teH63oAmE3lP34N3kshz8mm4VMAw7U3PxjVwwUmxEFksbgsNUaO3wId9R2AVQYSEGRa2+g==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.12.1", - "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-module-transforms": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", "babel-plugin-dynamic-import-node": "^2.3.3" } }, "@babel/plugin-transform-modules-commonjs": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.12.1.tgz", - "integrity": "sha512-dY789wq6l0uLY8py9c1B48V8mVL5gZh/+PQ5ZPrylPYsnAvnEMjqsUXkuoDVPeVK+0VyGar+D08107LzDQ6pag==", + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.8.tgz", + "integrity": "sha512-oflKPvsLT2+uKQopesJt3ApiaIS2HW+hzHFcwRNtyDGieAeC/dIHZX8buJQ2J2X1rxGPy4eRcUijm3qcSPjYcA==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.12.1", - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-simple-access": "^7.12.1", + "@babel/helper-module-transforms": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-simple-access": "^7.16.7", "babel-plugin-dynamic-import-node": "^2.3.3" } }, "@babel/plugin-transform-modules-systemjs": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.12.1.tgz", - "integrity": "sha512-Hn7cVvOavVh8yvW6fLwveFqSnd7rbQN3zJvoPNyNaQSvgfKmDBO9U1YL9+PCXGRlZD9tNdWTy5ACKqMuzyn32Q==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.16.7.tgz", + "integrity": "sha512-DuK5E3k+QQmnOqBR9UkusByy5WZWGRxfzV529s9nPra1GE7olmxfqO2FHobEOYSPIjPBTr4p66YDcjQnt8cBmw==", "dev": true, "requires": { - "@babel/helper-hoist-variables": "^7.10.4", - "@babel/helper-module-transforms": "^7.12.1", - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-validator-identifier": "^7.10.4", + "@babel/helper-hoist-variables": "^7.16.7", + "@babel/helper-module-transforms": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-validator-identifier": "^7.16.7", "babel-plugin-dynamic-import-node": "^2.3.3" + }, + "dependencies": { + "@babel/helper-validator-identifier": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", + "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", + "dev": true + } } }, "@babel/plugin-transform-modules-umd": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.12.1.tgz", - "integrity": "sha512-aEIubCS0KHKM0zUos5fIoQm+AZUMt1ZvMpqz0/H5qAQ7vWylr9+PLYurT+Ic7ID/bKLd4q8hDovaG3Zch2uz5Q==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.16.7.tgz", + "integrity": "sha512-EMh7uolsC8O4xhudF2F6wedbSHm1HHZ0C6aJ7K67zcDNidMzVcxWdGr+htW9n21klm+bOn+Rx4CBsAntZd3rEQ==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.12.1", - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-module-transforms": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.12.1.tgz", - "integrity": "sha512-tB43uQ62RHcoDp9v2Nsf+dSM8sbNodbEicbQNA53zHz8pWUhsgHSJCGpt7daXxRydjb0KnfmB+ChXOv3oADp1Q==", + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.8.tgz", + "integrity": "sha512-j3Jw+n5PvpmhRR+mrgIh04puSANCk/T/UA3m3P1MjJkhlK906+ApHhDIqBQDdOgL/r1UYpz4GNclTXxyZrYGSw==", "dev": true, "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.12.1" + "@babel/helper-create-regexp-features-plugin": "^7.16.7" } }, "@babel/plugin-transform-new-target": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.12.1.tgz", - "integrity": "sha512-+eW/VLcUL5L9IvJH7rT1sT0CzkdUTvPrXC2PXTn/7z7tXLBuKvezYbGdxD5WMRoyvyaujOq2fWoKl869heKjhw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.16.7.tgz", + "integrity": "sha512-xiLDzWNMfKoGOpc6t3U+etCE2yRnn3SM09BXqWPIZOBpL2gvVrBWUKnsJx0K/ADi5F5YC5f8APFfWrz25TdlGg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-object-super": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.12.1.tgz", - "integrity": "sha512-AvypiGJH9hsquNUn+RXVcBdeE3KHPZexWRdimhuV59cSoOt5kFBmqlByorAeUlGG2CJWd0U+4ZtNKga/TB0cAw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.7.tgz", + "integrity": "sha512-14J1feiQVWaGvRxj2WjyMuXS2jsBkgB3MdSN5HuC2G5nRspa5RK9COcs82Pwy5BuGcjb+fYaUj94mYcOj7rCvw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-replace-supers": "^7.12.1" + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-replace-supers": "^7.16.7" } }, "@babel/plugin-transform-parameters": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.12.1.tgz", - "integrity": "sha512-xq9C5EQhdPK23ZeCdMxl8bbRnAgHFrw5EOC3KJUsSylZqdkCaFEXxGSBuTSObOpiiHHNyb82es8M1QYgfQGfNg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.7.tgz", + "integrity": "sha512-AT3MufQ7zZEhU2hwOA11axBnExW0Lszu4RL/tAlUJBuNoRak+wehQW8h6KcXOcgjY42fHtDxswuMhMjFEuv/aw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-property-literals": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.12.1.tgz", - "integrity": "sha512-6MTCR/mZ1MQS+AwZLplX4cEySjCpnIF26ToWo942nqn8hXSm7McaHQNeGx/pt7suI1TWOWMfa/NgBhiqSnX0cQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.7.tgz", + "integrity": "sha512-z4FGr9NMGdoIl1RqavCqGG+ZuYjfZ/hkCIeuH6Do7tXmSm0ls11nYVSJqFEUOSJbDab5wC6lRE/w6YjVcr6Hqw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-regenerator": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.12.1.tgz", - "integrity": "sha512-gYrHqs5itw6i4PflFX3OdBPMQdPbF4bj2REIUxlMRUFk0/ZOAIpDFuViuxPjUL7YC8UPnf+XG7/utJvqXdPKng==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.7.tgz", + "integrity": "sha512-mF7jOgGYCkSJagJ6XCujSQg+6xC1M77/03K2oBmVJWoFGNUtnVJO4WHKJk3dnPC8HCcj4xBQP1Egm8DWh3Pb3Q==", "dev": true, "requires": { "regenerator-transform": "^0.14.2" } }, "@babel/plugin-transform-reserved-words": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.12.1.tgz", - "integrity": "sha512-pOnUfhyPKvZpVyBHhSBoX8vfA09b7r00Pmm1sH+29ae2hMTKVmSp4Ztsr8KBKjLjx17H0eJqaRC3bR2iThM54A==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.16.7.tgz", + "integrity": "sha512-KQzzDnZ9hWQBjwi5lpY5v9shmm6IVG0U9pB18zvMu2i4H90xpT4gmqwPYsn8rObiadYe2M0gmgsiOIF5A/2rtg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-runtime": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.12.1.tgz", - "integrity": "sha512-Ac/H6G9FEIkS2tXsZjL4RAdS3L3WHxci0usAnz7laPWUmFiGtj7tIASChqKZMHTSQTQY6xDbOq+V1/vIq3QrWg==", + "version": "7.16.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.16.10.tgz", + "integrity": "sha512-9nwTiqETv2G7xI4RvXHNfpGdr8pAA+Q/YtN3yLK7OoK7n9OibVm/xymJ838a9A6E/IciOLPj82lZk0fW6O4O7w==", "dev": true, "requires": { - "@babel/helper-module-imports": "^7.12.1", - "@babel/helper-plugin-utils": "^7.10.4", - "resolve": "^1.8.1", - "semver": "^5.5.1" + "@babel/helper-module-imports": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "babel-plugin-polyfill-corejs2": "^0.3.0", + "babel-plugin-polyfill-corejs3": "^0.5.0", + "babel-plugin-polyfill-regenerator": "^0.3.0", + "semver": "^6.3.0" }, "dependencies": { "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true } } }, "@babel/plugin-transform-shorthand-properties": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.12.1.tgz", - "integrity": "sha512-GFZS3c/MhX1OusqB1MZ1ct2xRzX5ppQh2JU1h2Pnfk88HtFTM+TWQqJNfwkmxtPQtb/s1tk87oENfXJlx7rSDw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.7.tgz", + "integrity": "sha512-hah2+FEnoRoATdIb05IOXf+4GzXYTq75TVhIn1PewihbpyrNWUt2JbudKQOETWw6QpLe+AIUpJ5MVLYTQbeeUg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-spread": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.12.1.tgz", - "integrity": "sha512-vuLp8CP0BE18zVYjsEBZ5xoCecMK6LBMMxYzJnh01rxQRvhNhH1csMMmBfNo5tGpGO+NhdSNW2mzIvBu3K1fng==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.7.tgz", + "integrity": "sha512-+pjJpgAngb53L0iaA5gU/1MLXJIfXcYepLgXB3esVRf4fqmj8f2cxM3/FKaHsZms08hFQJkFccEWuIpm429TXg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-skip-transparent-expression-wrappers": "^7.12.1" + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0" } }, "@babel/plugin-transform-sticky-regex": { - "version": "7.12.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.12.7.tgz", - "integrity": "sha512-VEiqZL5N/QvDbdjfYQBhruN0HYjSPjC4XkeqW4ny/jNtH9gcbgaqBIXYEZCNnESMAGs0/K/R7oFGMhOyu/eIxg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.7.tgz", + "integrity": "sha512-NJa0Bd/87QV5NZZzTuZG5BPJjLYadeSZ9fO6oOUoL4iQx+9EEuw/eEM92SrsT19Yc2jgB1u1hsjqDtH02c3Drw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-template-literals": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.12.1.tgz", - "integrity": "sha512-b4Zx3KHi+taXB1dVRBhVJtEPi9h1THCeKmae2qP0YdUHIFhVjtpqqNfxeVAa1xeHVhAy4SbHxEwx5cltAu5apw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.7.tgz", + "integrity": "sha512-VwbkDDUeenlIjmfNeDX/V0aWrQH2QiVyJtwymVQSzItFDTpxfyJh3EVaQiS0rIN/CqbLGr0VcGmuwyTdZtdIsA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-typeof-symbol": { - "version": "7.12.10", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.12.10.tgz", - "integrity": "sha512-JQ6H8Rnsogh//ijxspCjc21YPd3VLVoYtAwv3zQmqAt8YGYUtdo5usNhdl4b9/Vir2kPFZl6n1h0PfUz4hJhaA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.7.tgz", + "integrity": "sha512-p2rOixCKRJzpg9JB4gjnG4gjWkWa89ZoYUnl9snJ1cWIcTH/hvxZqfO+WjG6T8DRBpctEol5jw1O5rA8gkCokQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-unicode-escapes": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.12.1.tgz", - "integrity": "sha512-I8gNHJLIc7GdApm7wkVnStWssPNbSRMPtgHdmH3sRM1zopz09UWPS4x5V4n1yz/MIWTVnJ9sp6IkuXdWM4w+2Q==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.7.tgz", + "integrity": "sha512-TAV5IGahIz3yZ9/Hfv35TV2xEm+kaBDaZQCn2S/hG9/CZ0DktxJv9eKfPc7yYCvOYR4JGx1h8C+jcSOvgaaI/Q==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-unicode-regex": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.12.1.tgz", - "integrity": "sha512-SqH4ClNngh/zGwHZOOQMTD+e8FGWexILV+ePMyiDJttAWRh5dhDL8rcl5lSgU3Huiq6Zn6pWTMvdPAb21Dwdyg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.7.tgz", + "integrity": "sha512-oC5tYYKw56HO75KZVLQ+R/Nl3Hro9kf8iG0hXoaHP7tjAyCpvqBiSNe6vGrZni1Z6MggmUOC6A7VP7AVmw225Q==", "dev": true, "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.12.1", - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-create-regexp-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/preset-env": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.12.1.tgz", - "integrity": "sha512-H8kxXmtPaAGT7TyBvSSkoSTUK6RHh61So05SyEbpmr0MCZrsNYn7mGMzzeYoOUCdHzww61k8XBft2TaES+xPLg==", + "version": "7.16.11", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.16.11.tgz", + "integrity": "sha512-qcmWG8R7ZW6WBRPZK//y+E3Cli151B20W1Rv7ln27vuPaXU/8TKms6jFdiJtF7UDTxcrb7mZd88tAeK9LjdT8g==", "dev": true, "requires": { - "@babel/compat-data": "^7.12.1", - "@babel/helper-compilation-targets": "^7.12.1", - "@babel/helper-module-imports": "^7.12.1", - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-validator-option": "^7.12.1", - "@babel/plugin-proposal-async-generator-functions": "^7.12.1", - "@babel/plugin-proposal-class-properties": "^7.12.1", - "@babel/plugin-proposal-dynamic-import": "^7.12.1", - "@babel/plugin-proposal-export-namespace-from": "^7.12.1", - "@babel/plugin-proposal-json-strings": "^7.12.1", - "@babel/plugin-proposal-logical-assignment-operators": "^7.12.1", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.12.1", - "@babel/plugin-proposal-numeric-separator": "^7.12.1", - "@babel/plugin-proposal-object-rest-spread": "^7.12.1", - "@babel/plugin-proposal-optional-catch-binding": "^7.12.1", - "@babel/plugin-proposal-optional-chaining": "^7.12.1", - "@babel/plugin-proposal-private-methods": "^7.12.1", - "@babel/plugin-proposal-unicode-property-regex": "^7.12.1", - "@babel/plugin-syntax-async-generators": "^7.8.0", - "@babel/plugin-syntax-class-properties": "^7.12.1", - "@babel/plugin-syntax-dynamic-import": "^7.8.0", + "@babel/compat-data": "^7.16.8", + "@babel/helper-compilation-targets": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-validator-option": "^7.16.7", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.16.7", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.16.7", + "@babel/plugin-proposal-async-generator-functions": "^7.16.8", + "@babel/plugin-proposal-class-properties": "^7.16.7", + "@babel/plugin-proposal-class-static-block": "^7.16.7", + "@babel/plugin-proposal-dynamic-import": "^7.16.7", + "@babel/plugin-proposal-export-namespace-from": "^7.16.7", + "@babel/plugin-proposal-json-strings": "^7.16.7", + "@babel/plugin-proposal-logical-assignment-operators": "^7.16.7", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.7", + "@babel/plugin-proposal-numeric-separator": "^7.16.7", + "@babel/plugin-proposal-object-rest-spread": "^7.16.7", + "@babel/plugin-proposal-optional-catch-binding": "^7.16.7", + "@babel/plugin-proposal-optional-chaining": "^7.16.7", + "@babel/plugin-proposal-private-methods": "^7.16.11", + "@babel/plugin-proposal-private-property-in-object": "^7.16.7", + "@babel/plugin-proposal-unicode-property-regex": "^7.16.7", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.0", + "@babel/plugin-syntax-json-strings": "^7.8.3", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.0", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.0", - "@babel/plugin-syntax-optional-chaining": "^7.8.0", - "@babel/plugin-syntax-top-level-await": "^7.12.1", - "@babel/plugin-transform-arrow-functions": "^7.12.1", - "@babel/plugin-transform-async-to-generator": "^7.12.1", - "@babel/plugin-transform-block-scoped-functions": "^7.12.1", - "@babel/plugin-transform-block-scoping": "^7.12.1", - "@babel/plugin-transform-classes": "^7.12.1", - "@babel/plugin-transform-computed-properties": "^7.12.1", - "@babel/plugin-transform-destructuring": "^7.12.1", - "@babel/plugin-transform-dotall-regex": "^7.12.1", - "@babel/plugin-transform-duplicate-keys": "^7.12.1", - "@babel/plugin-transform-exponentiation-operator": "^7.12.1", - "@babel/plugin-transform-for-of": "^7.12.1", - "@babel/plugin-transform-function-name": "^7.12.1", - "@babel/plugin-transform-literals": "^7.12.1", - "@babel/plugin-transform-member-expression-literals": "^7.12.1", - "@babel/plugin-transform-modules-amd": "^7.12.1", - "@babel/plugin-transform-modules-commonjs": "^7.12.1", - "@babel/plugin-transform-modules-systemjs": "^7.12.1", - "@babel/plugin-transform-modules-umd": "^7.12.1", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.12.1", - "@babel/plugin-transform-new-target": "^7.12.1", - "@babel/plugin-transform-object-super": "^7.12.1", - "@babel/plugin-transform-parameters": "^7.12.1", - "@babel/plugin-transform-property-literals": "^7.12.1", - "@babel/plugin-transform-regenerator": "^7.12.1", - "@babel/plugin-transform-reserved-words": "^7.12.1", - "@babel/plugin-transform-shorthand-properties": "^7.12.1", - "@babel/plugin-transform-spread": "^7.12.1", - "@babel/plugin-transform-sticky-regex": "^7.12.1", - "@babel/plugin-transform-template-literals": "^7.12.1", - "@babel/plugin-transform-typeof-symbol": "^7.12.1", - "@babel/plugin-transform-unicode-escapes": "^7.12.1", - "@babel/plugin-transform-unicode-regex": "^7.12.1", - "@babel/preset-modules": "^0.1.3", - "@babel/types": "^7.12.1", - "core-js-compat": "^3.6.2", - "semver": "^5.5.0" + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-transform-arrow-functions": "^7.16.7", + "@babel/plugin-transform-async-to-generator": "^7.16.8", + "@babel/plugin-transform-block-scoped-functions": "^7.16.7", + "@babel/plugin-transform-block-scoping": "^7.16.7", + "@babel/plugin-transform-classes": "^7.16.7", + "@babel/plugin-transform-computed-properties": "^7.16.7", + "@babel/plugin-transform-destructuring": "^7.16.7", + "@babel/plugin-transform-dotall-regex": "^7.16.7", + "@babel/plugin-transform-duplicate-keys": "^7.16.7", + "@babel/plugin-transform-exponentiation-operator": "^7.16.7", + "@babel/plugin-transform-for-of": "^7.16.7", + "@babel/plugin-transform-function-name": "^7.16.7", + "@babel/plugin-transform-literals": "^7.16.7", + "@babel/plugin-transform-member-expression-literals": "^7.16.7", + "@babel/plugin-transform-modules-amd": "^7.16.7", + "@babel/plugin-transform-modules-commonjs": "^7.16.8", + "@babel/plugin-transform-modules-systemjs": "^7.16.7", + "@babel/plugin-transform-modules-umd": "^7.16.7", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.16.8", + "@babel/plugin-transform-new-target": "^7.16.7", + "@babel/plugin-transform-object-super": "^7.16.7", + "@babel/plugin-transform-parameters": "^7.16.7", + "@babel/plugin-transform-property-literals": "^7.16.7", + "@babel/plugin-transform-regenerator": "^7.16.7", + "@babel/plugin-transform-reserved-words": "^7.16.7", + "@babel/plugin-transform-shorthand-properties": "^7.16.7", + "@babel/plugin-transform-spread": "^7.16.7", + "@babel/plugin-transform-sticky-regex": "^7.16.7", + "@babel/plugin-transform-template-literals": "^7.16.7", + "@babel/plugin-transform-typeof-symbol": "^7.16.7", + "@babel/plugin-transform-unicode-escapes": "^7.16.7", + "@babel/plugin-transform-unicode-regex": "^7.16.7", + "@babel/preset-modules": "^0.1.5", + "@babel/types": "^7.16.8", + "babel-plugin-polyfill-corejs2": "^0.3.0", + "babel-plugin-polyfill-corejs3": "^0.5.0", + "babel-plugin-polyfill-regenerator": "^0.3.0", + "core-js-compat": "^3.20.2", + "semver": "^6.3.0" }, "dependencies": { "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true } } }, "@babel/preset-modules": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.4.tgz", - "integrity": "sha512-J36NhwnfdzpmH41M1DrnkkgAqhZaqr/NBdPfQ677mLzlaXo+oDiv1deyCDtgAhz8p328otdob0Du7+xgHGZbKg==", + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", + "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.0.0", @@ -1749,65 +1722,105 @@ } }, "@babel/runtime": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.12.1.tgz", - "integrity": "sha512-J5AIf3vPj3UwXaAzb5j1xM4WAQDX3EMgemF8rjCP3SoW09LfRKAXQKt6CoVYl230P6iWdRcBbnLDDdnqWxZSCA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.7.tgz", + "integrity": "sha512-9E9FJowqAsytyOY6LG+1KuueckRL+aQW+mKvXRXnuFGyRAyepJPmEo9vgMfXUA6O9u3IeEdv9MAkppFcaQwogQ==", "dev": true, "requires": { "regenerator-runtime": "^0.13.4" } }, "@babel/template": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.4.tgz", - "integrity": "sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", + "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/parser": "^7.10.4", - "@babel/types": "^7.10.4" + "@babel/code-frame": "^7.16.7", + "@babel/parser": "^7.16.7", + "@babel/types": "^7.16.7" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", + "requires": { + "@babel/highlight": "^7.16.7" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", + "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==" + }, + "@babel/highlight": { + "version": "7.16.10", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz", + "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==", + "requires": { + "@babel/helper-validator-identifier": "^7.16.7", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + } } }, "@babel/traverse": { - "version": "7.12.10", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.10.tgz", - "integrity": "sha512-6aEtf0IeRgbYWzta29lePeYSk+YAFIC3kyqESeft8o5CkFlYIMX+EQDDWEiAQ9LHOA3d0oHdgrSsID/CKqXJlg==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.0.tgz", + "integrity": "sha512-fpFIXvqD6kC7c7PUNnZ0Z8cQXlarCLtCUpt2S1Dx7PjoRtCFffvOkHHSom+m5HIxMZn5bIBVb71lhabcmjEsqg==", "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.12.10", - "@babel/helper-function-name": "^7.10.4", - "@babel/helper-split-export-declaration": "^7.11.0", - "@babel/parser": "^7.12.10", - "@babel/types": "^7.12.10", + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.17.0", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-hoist-variables": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/parser": "^7.17.0", + "@babel/types": "^7.17.0", "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.19" + "globals": "^11.1.0" }, "dependencies": { - "@babel/generator": { - "version": "7.12.10", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.10.tgz", - "integrity": "sha512-6mCdfhWgmqLdtTkhXjnIz0LcdVCd26wS2JXRtj2XY0u5klDsXBREA/pG5NVOuVnF2LUrBGNFtQkIqqTbblg0ww==", + "@babel/code-frame": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", "requires": { - "@babel/types": "^7.12.10", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" + "@babel/highlight": "^7.16.7" } }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + "@babel/helper-validator-identifier": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", + "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==" + }, + "@babel/highlight": { + "version": "7.16.10", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz", + "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==", + "requires": { + "@babel/helper-validator-identifier": "^7.16.7", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } } } }, "@babel/types": { - "version": "7.12.10", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.10.tgz", - "integrity": "sha512-sf6wboJV5mGyip2hIpDSKsr80RszPinEFjsHTalMxZAZkoQ2/2yQzxlcFN52SJqsyPfLtPmenL4g2KB3KJXPDw==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz", + "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==", "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "lodash": "^4.17.19", + "@babel/helper-validator-identifier": "^7.16.7", "to-fast-properties": "^2.0.0" + }, + "dependencies": { + "@babel/helper-validator-identifier": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", + "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==" + } } }, "@bcoe/v8-coverage": { @@ -1816,20 +1829,37 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, - "@cnakazawa/watch": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.4.tgz", - "integrity": "sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ==", + "@cspotcode/source-map-consumer": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz", + "integrity": "sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==", + "dev": true + }, + "@cspotcode/source-map-support": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz", + "integrity": "sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA==", "dev": true, "requires": { - "exec-sh": "^0.3.2", - "minimist": "^1.2.0" + "@cspotcode/source-map-consumer": "0.8.0" } }, + "@discoveryjs/json-ext": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.6.tgz", + "integrity": "sha512-ws57AidsDvREKrZKYffXddNkyaF14iHNHm8VQnZH6t99E8gczjNN0GpvcGny0imC80yQ0tHz1xVUKk/KFQSUyA==", + "dev": true + }, "@fortawesome/fontawesome-free": { - "version": "5.15.1", - "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-5.15.1.tgz", - "integrity": "sha512-OEdH7SyC1suTdhBGW91/zBfR6qaIhThbcN8PUXtXilY4GYnSBbVqOntdHbC1vXwsDnX0Qix2m2+DSU1J51ybOQ==" + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-6.0.0.tgz", + "integrity": "sha512-6LB4PYBST1Rx40klypw1SmSDArjFOcfBf2LeX9Zg5EKJT2eXiyiJq+CyBYKeXyK0sXS2FsCJWSPr/luyhuvh0Q==" + }, + "@gar/promisify": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.2.tgz", + "integrity": "sha512-82cpyJyKRoQoRi+14ibCeGPu0CwypgtBAdBhq1WfvagpCZNKqwXbKwXllYSMG91DhmG4jt9gN8eP6lGOtozuaw==", + "dev": true }, "@istanbuljs/load-nyc-config": { "version": "1.1.0", @@ -1842,73 +1872,25 @@ "get-package-type": "^0.1.0", "js-yaml": "^3.13.1", "resolve-from": "^5.0.0" - }, - "dependencies": { - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, - "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, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "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, - "requires": { - "p-locate": "^4.1.0" - } - }, - "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, - "requires": { - "p-limit": "^2.2.0" - } - }, - "path-exists": { - "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 - }, - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - } } }, "@istanbuljs/schema": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.2.tgz", - "integrity": "sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==", + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", "dev": true }, "@jest/console": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-26.6.2.tgz", - "integrity": "sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.5.1.tgz", + "integrity": "sha512-kZ/tNpS3NXn0mlXXXPNuDZnb4c0oZ20r4K5eemM2k30ZC3G0T02nXUvyhf5YdbXWHPEJLc9qGLxEZ216MdL+Zg==", "dev": true, "requires": { - "@jest/types": "^26.6.2", + "@jest/types": "^27.5.1", "@types/node": "*", "chalk": "^4.0.0", - "jest-message-util": "^26.6.2", - "jest-util": "^26.6.2", + "jest-message-util": "^27.5.1", + "jest-util": "^27.5.1", "slash": "^3.0.0" }, "dependencies": { @@ -1922,9 +1904,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -1952,6 +1934,12 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -1964,36 +1952,36 @@ } }, "@jest/core": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-26.6.3.tgz", - "integrity": "sha512-xvV1kKbhfUqFVuZ8Cyo+JPpipAHHAV3kcDBftiduK8EICXmTFddryy3P7NfZt8Pv37rA9nEJBKCCkglCPt/Xjw==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.5.1.tgz", + "integrity": "sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ==", "dev": true, "requires": { - "@jest/console": "^26.6.2", - "@jest/reporters": "^26.6.2", - "@jest/test-result": "^26.6.2", - "@jest/transform": "^26.6.2", - "@jest/types": "^26.6.2", + "@jest/console": "^27.5.1", + "@jest/reporters": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", + "emittery": "^0.8.1", "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "jest-changed-files": "^26.6.2", - "jest-config": "^26.6.3", - "jest-haste-map": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-regex-util": "^26.0.0", - "jest-resolve": "^26.6.2", - "jest-resolve-dependencies": "^26.6.3", - "jest-runner": "^26.6.3", - "jest-runtime": "^26.6.3", - "jest-snapshot": "^26.6.2", - "jest-util": "^26.6.2", - "jest-validate": "^26.6.2", - "jest-watcher": "^26.6.2", - "micromatch": "^4.0.2", - "p-each-series": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^27.5.1", + "jest-config": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-resolve-dependencies": "^27.5.1", + "jest-runner": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "jest-watcher": "^27.5.1", + "micromatch": "^4.0.4", "rimraf": "^3.0.0", "slash": "^3.0.0", "strip-ansi": "^6.0.0" @@ -2009,9 +1997,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -2039,6 +2027,12 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -2051,73 +2045,73 @@ } }, "@jest/environment": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-26.6.2.tgz", - "integrity": "sha512-nFy+fHl28zUrRsCeMB61VDThV1pVTtlEokBRgqPrcT1JNq4yRNIyTHfyht6PqtUvY9IsuLGTrbG8kPXjSZIZwA==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.5.1.tgz", + "integrity": "sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA==", "dev": true, "requires": { - "@jest/fake-timers": "^26.6.2", - "@jest/types": "^26.6.2", + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", "@types/node": "*", - "jest-mock": "^26.6.2" + "jest-mock": "^27.5.1" } }, "@jest/fake-timers": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-26.6.2.tgz", - "integrity": "sha512-14Uleatt7jdzefLPYM3KLcnUl1ZNikaKq34enpb5XG9i81JpppDb5muZvonvKyrl7ftEHkKS5L5/eB/kxJ+bvA==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.5.1.tgz", + "integrity": "sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ==", "dev": true, "requires": { - "@jest/types": "^26.6.2", - "@sinonjs/fake-timers": "^6.0.1", + "@jest/types": "^27.5.1", + "@sinonjs/fake-timers": "^8.0.1", "@types/node": "*", - "jest-message-util": "^26.6.2", - "jest-mock": "^26.6.2", - "jest-util": "^26.6.2" + "jest-message-util": "^27.5.1", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1" } }, "@jest/globals": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-26.6.2.tgz", - "integrity": "sha512-85Ltnm7HlB/KesBUuALwQ68YTU72w9H2xW9FjZ1eL1U3lhtefjjl5c2MiUbpXt/i6LaPRvoOFJ22yCBSfQ0JIA==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.5.1.tgz", + "integrity": "sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q==", "dev": true, "requires": { - "@jest/environment": "^26.6.2", - "@jest/types": "^26.6.2", - "expect": "^26.6.2" + "@jest/environment": "^27.5.1", + "@jest/types": "^27.5.1", + "expect": "^27.5.1" } }, "@jest/reporters": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-26.6.2.tgz", - "integrity": "sha512-h2bW53APG4HvkOnVMo8q3QXa6pcaNt1HkwVsOPMBV6LD/q9oSpxNSYZQYkAnjdMjrJ86UuYeLo+aEZClV6opnw==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.5.1.tgz", + "integrity": "sha512-cPXh9hWIlVJMQkVk84aIvXuBB4uQQmFqZiacloFuGiP3ah1sbCxCosidXFDfqG8+6fO1oR2dTJTlsOy4VFmUfw==", "dev": true, "requires": { "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^26.6.2", - "@jest/test-result": "^26.6.2", - "@jest/transform": "^26.6.2", - "@jest/types": "^26.6.2", + "@jest/console": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", "chalk": "^4.0.0", "collect-v8-coverage": "^1.0.0", "exit": "^0.1.2", "glob": "^7.1.2", - "graceful-fs": "^4.2.4", + "graceful-fs": "^4.2.9", "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^4.0.3", + "istanbul-lib-instrument": "^5.1.0", "istanbul-lib-report": "^3.0.0", "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.0.2", - "jest-haste-map": "^26.6.2", - "jest-resolve": "^26.6.2", - "jest-util": "^26.6.2", - "jest-worker": "^26.6.2", - "node-notifier": "^8.0.0", + "istanbul-reports": "^3.1.3", + "jest-haste-map": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", "slash": "^3.0.0", "source-map": "^0.6.0", "string-length": "^4.0.1", "terminal-link": "^2.0.0", - "v8-to-istanbul": "^7.0.0" + "v8-to-istanbul": "^8.1.0" }, "dependencies": { "ansi-styles": { @@ -2130,9 +2124,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -2160,16 +2154,11 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "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, - "requires": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^7.0.0" - } + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true }, "source-map": { "version": "0.6.1", @@ -2189,22 +2178,16 @@ } }, "@jest/source-map": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-26.6.2.tgz", - "integrity": "sha512-YwYcCwAnNmOVsZ8mr3GfnzdXDAl4LaenZP5z+G0c8bzC9/dugL8zRmxZzdoTl4IaS3CryS1uWnROLPFmb6lVvA==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.5.1.tgz", + "integrity": "sha512-y9NIHUYF3PJRlHk98NdC/N1gl88BL08aQQgu4k4ZopQkCw9t9cV8mtl3TV8b/YCB8XaVTFrmUTAJvjsntDireg==", "dev": true, "requires": { "callsites": "^3.0.0", - "graceful-fs": "^4.2.4", + "graceful-fs": "^4.2.9", "source-map": "^0.6.0" }, "dependencies": { - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -2214,48 +2197,47 @@ } }, "@jest/test-result": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-26.6.2.tgz", - "integrity": "sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.5.1.tgz", + "integrity": "sha512-EW35l2RYFUcUQxFJz5Cv5MTOxlJIQs4I7gxzi2zVU7PJhOwfYq1MdC5nhSmYjX1gmMmLPvB3sIaC+BkcHRBfag==", "dev": true, "requires": { - "@jest/console": "^26.6.2", - "@jest/types": "^26.6.2", + "@jest/console": "^27.5.1", + "@jest/types": "^27.5.1", "@types/istanbul-lib-coverage": "^2.0.0", "collect-v8-coverage": "^1.0.0" } }, "@jest/test-sequencer": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-26.6.3.tgz", - "integrity": "sha512-YHlVIjP5nfEyjlrSr8t/YdNfU/1XEt7c5b4OxcXCjyRhjzLYu/rO69/WHPuYcbCWkz8kAeZVZp2N2+IOLLEPGw==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.5.1.tgz", + "integrity": "sha512-LCheJF7WB2+9JuCS7VB/EmGIdQuhtqjRNI9A43idHv3E4KltCTsPsLxvdaubFHSYwY/fNjMWjl6vNRhDiN7vpQ==", "dev": true, "requires": { - "@jest/test-result": "^26.6.2", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^26.6.2", - "jest-runner": "^26.6.3", - "jest-runtime": "^26.6.3" + "@jest/test-result": "^27.5.1", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-runtime": "^27.5.1" } }, "@jest/transform": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-26.6.2.tgz", - "integrity": "sha512-E9JjhUgNzvuQ+vVAL21vlyfy12gP0GhazGgJC4h6qUt1jSdUXGWJ1wfu/X7Sd8etSgxV4ovT1pb9v5D6QW4XgA==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.5.1.tgz", + "integrity": "sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw==", "dev": true, "requires": { "@babel/core": "^7.1.0", - "@jest/types": "^26.6.2", - "babel-plugin-istanbul": "^6.0.0", + "@jest/types": "^27.5.1", + "babel-plugin-istanbul": "^6.1.1", "chalk": "^4.0.0", "convert-source-map": "^1.4.0", "fast-json-stable-stringify": "^2.0.0", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^26.6.2", - "jest-regex-util": "^26.0.0", - "jest-util": "^26.6.2", - "micromatch": "^4.0.2", - "pirates": "^4.0.1", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-util": "^27.5.1", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", "slash": "^3.0.0", "source-map": "^0.6.1", "write-file-atomic": "^3.0.0" @@ -2271,9 +2253,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -2301,6 +2283,12 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -2319,15 +2307,15 @@ } }, "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", "dev": true, "requires": { "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^3.0.0", "@types/node": "*", - "@types/yargs": "^15.0.0", + "@types/yargs": "^16.0.0", "chalk": "^4.0.0" }, "dependencies": { @@ -2341,9 +2329,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -2382,109 +2370,121 @@ } } }, - "@jsdevtools/coverage-istanbul-loader": { + "@jridgewell/resolve-uri": { "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@jsdevtools/coverage-istanbul-loader/-/coverage-istanbul-loader-3.0.5.tgz", - "integrity": "sha512-EUCPEkaRPvmHjWAAZkWMT7JDzpw7FKB00WTISaiXsbNOd5hCHg77XLA8sLYLFDo1zepYLo2w7GstN8YBqRXZfA==", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz", + "integrity": "sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew==", + "dev": true + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.11", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz", + "integrity": "sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg==", + "dev": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.4.tgz", + "integrity": "sha512-vFv9ttIedivx0ux3QSjhgtCVjPZd5l46ZOMDSCwnH1yUO2e964gO8LZGyv2QkqcgR6TnBU1v+1IFqmeoG+0UJQ==", "dev": true, "requires": { - "convert-source-map": "^1.7.0", - "istanbul-lib-instrument": "^4.0.3", - "loader-utils": "^2.0.0", - "merge-source-map": "^1.1.0", - "schema-utils": "^2.7.0" + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" } }, "@microsoft/signalr": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/@microsoft/signalr/-/signalr-5.0.8.tgz", - "integrity": "sha512-g5U7zGa1CeoPztA1VGLiB418sZ6gt8ZEOsX8krpegyMquzH2Qinny1zQjNsg3mgjGlJI+FXD5bO4gVsHGUp2hA==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@microsoft/signalr/-/signalr-6.0.2.tgz", + "integrity": "sha512-OYSRqvOyJWMA9cRvbOIKG0f5wE9xRiayQvkDTQ8gru3WT3WevHk8KGsBUV3x2NmizTSq7gSShQr/l9GkdT/e8g==", "requires": { "abort-controller": "^3.0.0", "eventsource": "^1.0.7", - "fetch-cookie": "^0.7.3", - "node-fetch": "^2.6.0", - "ws": "^6.0.0" + "fetch-cookie": "^0.11.0", + "node-fetch": "^2.6.1", + "ws": "^7.4.5" } }, "@ng-bootstrap/ng-bootstrap": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/@ng-bootstrap/ng-bootstrap/-/ng-bootstrap-9.1.0.tgz", - "integrity": "sha512-5cTxOew6EsENIa/PiIlIlF3MSGanLGD2fyGPyQJc0hU5j9uK+alz2eJXWpeAX3IHLDIaOBfRdCGOrpXkeIUhzQ==", + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@ng-bootstrap/ng-bootstrap/-/ng-bootstrap-12.0.0.tgz", + "integrity": "sha512-XWf/CsP1gH0aev7Mtsldtj0DPPFdTrJpSiyjzLFS29gU1ZuDlJz6OKthgUDxZoua6uNPAzaGMc0A20T+reMfRw==", "requires": { - "tslib": "^2.0.0" + "tslib": "^2.3.0" } }, "@ngtools/webpack": { - "version": "11.0.7", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-11.0.7.tgz", - "integrity": "sha512-OWGiiDc7s4T53BBCY8tLkLUjgw44HrixW8Wh8e4thFH1eIUM0NHe087s/B5hDNu72W/GqK4IoBbhNQ2wiCR7qQ==", - "dev": true, - "requires": { - "@angular-devkit/core": "11.0.7", - "enhanced-resolve": "5.3.1", - "webpack-sources": "2.0.1" - } + "version": "13.2.3", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-13.2.3.tgz", + "integrity": "sha512-wooUZiV92QyoeFxkhqIwH/cfiAAAn+l8fEEuaaEIfJtpjpbShvvlboEVsqb28soeGiFJfLcmsZM3mUFgsG4QBQ==", + "dev": true }, "@ngx-lite/nav-drawer": { - "version": "0.4.6", - "resolved": "https://registry.npmjs.org/@ngx-lite/nav-drawer/-/nav-drawer-0.4.6.tgz", - "integrity": "sha512-b90i/t/m35pMKk2zymhv3zvjnfl/x6qOFVPAqXL6uw1b1mc+FcZkzxtEXRp/x9Ym20GLo3tgf/Es/Wc/LSkW0Q==", + "version": "0.4.7", + "resolved": "https://registry.npmjs.org/@ngx-lite/nav-drawer/-/nav-drawer-0.4.7.tgz", + "integrity": "sha512-OqXJhzE88RR5Vtgr0tcuvkKVkzsKZjeXxhjpWOJ9UiC2iCQPDL2rtvag5K/vPKN362Jx0htvr3cmFDjHg/kjdA==", "requires": { "tslib": "^2.0.0" } }, "@ngx-lite/util": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/@ngx-lite/util/-/util-0.0.0.tgz", - "integrity": "sha512-n1Y85KCpld5wIKp/izAfmLWuwwZT2F540xkjanq8f9mLy36Ol1MgQYruU8XrBrxKoAa04h43FJmMsoahoZq+/A==", + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/@ngx-lite/util/-/util-0.0.1.tgz", + "integrity": "sha512-j7pBcF+5OEHExEUBNdlQT5x4sVvHIPwZeMvhlO1TAcAAz9frDsvYgJ1c3eXJYJKJq57o1rH1RESKSJ9YRNpAiw==", "requires": { - "tslib": "^1.9.0" - }, - "dependencies": { - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - } + "tslib": "^2.1.0" } }, "@nodelib/fs.scandir": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz", - "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==", + "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, "requires": { - "@nodelib/fs.stat": "2.0.3", + "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "@nodelib/fs.stat": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz", - "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true }, "@nodelib/fs.walk": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz", - "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, "requires": { - "@nodelib/fs.scandir": "2.1.3", + "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, - "@npmcli/ci-detect": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@npmcli/ci-detect/-/ci-detect-1.3.0.tgz", - "integrity": "sha512-oN3y7FAROHhrAt7Rr7PnTSwrHrZVRTS2ZbyxeQwSSYD0ifwM3YNgQqbaRmjcWoPyq77MjchusjJDspbzMmip1Q==", - "dev": true + "@npmcli/fs": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz", + "integrity": "sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==", + "dev": true, + "requires": { + "@gar/promisify": "^1.0.1", + "semver": "^7.3.5" + }, + "dependencies": { + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } }, "@npmcli/git": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-2.0.8.tgz", - "integrity": "sha512-LPnzyBZ+1p7+JzHVwwKycMF8M3lr1ze3wxGRnxn/QxJtk++Y3prSJQrdBDGCxJyRpFsup6J3lrRBVYBhJVrM8Q==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-2.1.0.tgz", + "integrity": "sha512-/hBFX/QG1b+N7PZBFs0bi+evgRZcK9nWBxQKZkGoXUT5hJSwl5c4d7y8/hm+NQZRPhQ67RzFaj5UM9YeyKoryw==", "dev": true, "requires": { "@npmcli/promise-spawn": "^1.3.2", @@ -2497,54 +2497,12 @@ "which": "^2.0.2" }, "dependencies": { - "hosted-git-info": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.0.2.tgz", - "integrity": "sha512-c9OGXbZ3guC/xOlCg1Ci/VgWlwsqDv1yMQL1CWqXDL0hDjXuNcq0zuR4xqPSuasI3kqFDhqSyTjREz5gzq0fXg==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, "mkdirp": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "dev": true }, - "npm-package-arg": { - "version": "8.1.2", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-8.1.2.tgz", - "integrity": "sha512-6Eem455JsSMJY6Kpd3EyWE+n5hC+g9bSyHr9K9U2zqZb7+02+hObQ2c0+8iDk/mNF+8r1MhY44WypKJAkySIYA==", - "dev": true, - "requires": { - "hosted-git-info": "^4.0.1", - "semver": "^7.3.4", - "validate-npm-package-name": "^3.0.0" - } - }, - "npm-pick-manifest": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-6.1.1.tgz", - "integrity": "sha512-dBsdBtORT84S8V8UTad1WlUyKIY9iMsAmqxHbLdeEeBNMLQDlDWWra3wYUx9EBEIiG/YwAy0XyNHDd2goAsfuA==", - "dev": true, - "requires": { - "npm-install-checks": "^4.0.0", - "npm-normalize-package-bin": "^1.0.1", - "npm-package-arg": "^8.1.2", - "semver": "^7.3.4" - } - }, - "promise-retry": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", - "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", - "dev": true, - "requires": { - "err-code": "^2.0.2", - "retry": "^0.12.0" - } - }, "semver": { "version": "7.3.5", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", @@ -2553,15 +2511,6 @@ "requires": { "lru-cache": "^6.0.0" } - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } } } }, @@ -2576,12 +2525,13 @@ } }, "@npmcli/move-file": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.0.1.tgz", - "integrity": "sha512-Uv6h1sT+0DrblvIrolFtbvM1FgWm+/sy4B3pvLp67Zys+thcukzS5ekn7HsZFGpWP4Q3fYJCljbWQE/XivMRLw==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz", + "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", "dev": true, "requires": { - "mkdirp": "^1.0.4" + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" }, "dependencies": { "mkdirp": { @@ -2593,9 +2543,9 @@ } }, "@npmcli/node-gyp": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-1.0.2.tgz", - "integrity": "sha512-yrJUe6reVMpktcvagumoqD9r08fH1iRo01gn1u0zoCApa9lnZGEigVKUd2hzsCId4gdtkZZIVscLhNxMECKgRg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-1.0.3.tgz", + "integrity": "sha512-fnkhw+fmX65kiLqk6E3BFLXNC26rUhK90zVwe2yncPliVT/Qos3xjhTLE59Df8KnPlcwIERXKVlU1bXoUQ+liA==", "dev": true }, "@npmcli/promise-spawn": { @@ -2608,120 +2558,51 @@ } }, "@npmcli/run-script": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-1.8.5.tgz", - "integrity": "sha512-NQspusBCpTjNwNRFMtz2C5MxoxyzlbuJ4YEhxAKrIonTiirKDtatsZictx9RgamQIx6+QuHMNmPl0wQdoESs9A==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-2.0.0.tgz", + "integrity": "sha512-fSan/Pu11xS/TdaTpTB0MRn9guwGU8dye+x56mEVgBEd/QsybBbYcAL0phPXi8SGWFEChkQd6M9qL4y6VOpFig==", "dev": true, "requires": { "@npmcli/node-gyp": "^1.0.2", "@npmcli/promise-spawn": "^1.3.2", - "infer-owner": "^1.0.4", - "node-gyp": "^7.1.0", + "node-gyp": "^8.2.0", "read-package-json-fast": "^2.0.1" - }, - "dependencies": { - "read-package-json-fast": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-2.0.2.tgz", - "integrity": "sha512-5fyFUyO9B799foVk4n6ylcoAktG/FbE3jwRKxvwaeSrIunaoMc0u81dzXxjeAFKOce7O5KncdfwpGvvs6r5PsQ==", - "dev": true, - "requires": { - "json-parse-even-better-errors": "^2.3.0", - "npm-normalize-package-bin": "^1.0.1" - } - } } }, "@polka/url": { - "version": "1.0.0-next.20", - "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.20.tgz", - "integrity": "sha512-88p7+M0QGxKpmnkfXjS4V26AnoC/eiqZutE8GLdaI5X12NY75bXSdTY9NkmYb2Xyk1O+MmkuO6Frmsj84V6I8Q==" + "version": "1.0.0-next.21", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.21.tgz", + "integrity": "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==" + }, + "@popperjs/core": { + "version": "2.11.2", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.2.tgz", + "integrity": "sha512-92FRmppjjqz29VMJ2dn+xdyXZBrMlE42AV6Kq6BwjWV7CNUW1hs2FtxSNLQE+gJhaZ6AAmYuO9y8dshhcBl7vA==" }, "@schematics/angular": { - "version": "11.2.11", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-11.2.11.tgz", - "integrity": "sha512-Ii7KabU79Jg2zoU7qR9wFd81TOAePQ6jog7OhoTyE2aKpKyBZlHXA4qq1dJfV3GAE5H1JKVm0lRgGEFJLQitGg==", + "version": "13.2.3", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-13.2.3.tgz", + "integrity": "sha512-jloooGC7eco9AKxlIMMqFRptJYzZ0jNRBStWOp2dCISg6rmOKqpxbsHLtYFQIT1PnlomSxtKDAgYGQMDi9zhXw==", "dev": true, "requires": { - "@angular-devkit/core": "11.2.11", - "@angular-devkit/schematics": "11.2.11", + "@angular-devkit/core": "13.2.3", + "@angular-devkit/schematics": "13.2.3", "jsonc-parser": "3.0.0" - }, - "dependencies": { - "@angular-devkit/core": { - "version": "11.2.11", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-11.2.11.tgz", - "integrity": "sha512-6gFrpG0o00Y4kMU7cQeQ5fSlmXRvNlidylM3OfAvpj0qHoRKo1E3q9iVr4fW3oVZxK3fpCSN7RE5Myl5Y7mV0w==", - "dev": true, - "requires": { - "ajv": "6.12.6", - "fast-json-stable-stringify": "2.1.0", - "magic-string": "0.25.7", - "rxjs": "6.6.3", - "source-map": "0.7.3" - } - } - } - }, - "@schematics/update": { - "version": "0.1102.11", - "resolved": "https://registry.npmjs.org/@schematics/update/-/update-0.1102.11.tgz", - "integrity": "sha512-SdQ/Zao+huxSFnKXFbf93EEExzyLy5y+BBs14n9uLwnhaFbd5jlH0xO8/Ui1H6oDuOycSRQdnl7gt3sUr8EbaQ==", - "dev": true, - "requires": { - "@angular-devkit/core": "11.2.11", - "@angular-devkit/schematics": "11.2.11", - "@yarnpkg/lockfile": "1.1.0", - "ini": "2.0.0", - "npm-package-arg": "^8.0.0", - "pacote": "11.2.4", - "semver": "7.3.4", - "semver-intersect": "1.4.0" - }, - "dependencies": { - "@angular-devkit/core": { - "version": "11.2.11", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-11.2.11.tgz", - "integrity": "sha512-6gFrpG0o00Y4kMU7cQeQ5fSlmXRvNlidylM3OfAvpj0qHoRKo1E3q9iVr4fW3oVZxK3fpCSN7RE5Myl5Y7mV0w==", - "dev": true, - "requires": { - "ajv": "6.12.6", - "fast-json-stable-stringify": "2.1.0", - "magic-string": "0.25.7", - "rxjs": "6.6.3", - "source-map": "0.7.3" - } - }, - "ini": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", - "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", - "dev": true - }, - "semver": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", - "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } } }, "@sinonjs/commons": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.2.tgz", - "integrity": "sha512-sruwd86RJHdsVf/AtBoijDmUqJp3B6hF/DGC23C+JaegnDHaZyewCjoVGTdg3J0uz3Zs7NnIT05OBOmML72lQw==", + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", + "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", "dev": true, "requires": { "type-detect": "4.0.8" } }, "@sinonjs/fake-timers": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz", - "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz", + "integrity": "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==", "dev": true, "requires": { "@sinonjs/commons": "^1.7.0" @@ -2733,10 +2614,34 @@ "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", "dev": true }, + "@tsconfig/node10": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz", + "integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==", + "dev": true + }, + "@tsconfig/node12": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz", + "integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==", + "dev": true + }, + "@tsconfig/node14": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz", + "integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==", + "dev": true + }, + "@tsconfig/node16": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz", + "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", + "dev": true + }, "@types/babel__core": { - "version": "7.1.12", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.12.tgz", - "integrity": "sha512-wMTHiiTiBAAPebqaPiPDLFA4LYPKr6Ph0Xq/6rq1Ur3v66HXyG+clfR9CNETkD7MQS8ZHvpQOtA53DLws5WAEQ==", + "version": "7.1.18", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.18.tgz", + "integrity": "sha512-S7unDjm/C7z2A2R9NzfKCK1I+BAALDtxEmsJBwlB3EzNfb929ykjL++1CK9LO++EIp2fQrC8O+BwjKvz6UeDyQ==", "dev": true, "requires": { "@babel/parser": "^7.1.0", @@ -2747,18 +2652,18 @@ } }, "@types/babel__generator": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.2.tgz", - "integrity": "sha512-MdSJnBjl+bdwkLskZ3NGFp9YcXGx5ggLpQQPqtgakVhsWK0hTtNYhjpZLlWQTviGTvF8at+Bvli3jV7faPdgeQ==", + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", + "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", "dev": true, "requires": { "@babel/types": "^7.0.0" } }, "@types/babel__template": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.0.tgz", - "integrity": "sha512-NTPErx4/FiPCGScH7foPyr+/1Dkzkni+rHiYHHoTjvwou7AQzJkNeD60A9CXRy+ZEN2B1bggmkTMCDb+Mv5k+A==", + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", + "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", "dev": true, "requires": { "@babel/parser": "^7.1.0", @@ -2766,29 +2671,106 @@ } }, "@types/babel__traverse": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.11.0.tgz", - "integrity": "sha512-kSjgDMZONiIfSH1Nxcr5JIRMwUetDki63FSQfpTCz8ogF3Ulqm8+mr5f78dUYs6vMiB6gBusQqfQmBvHZj/lwg==", + "version": "7.14.2", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.14.2.tgz", + "integrity": "sha512-K2waXdXBi2302XUdcHcR1jCeU0LL4TD9HRs/gk0N2Xvrht+G/BfJa4QObBQZfhMdxiCpV3COl5Nfq4uKTeTnJA==", "dev": true, "requires": { "@babel/types": "^7.3.0" } }, - "@types/file-saver": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/file-saver/-/file-saver-2.0.1.tgz", - "integrity": "sha512-g1QUuhYVVAamfCifK7oB7G3aIl4BbOyzDOqVyUfEr4tfBKrXfeH+M+Tg7HKCXSrbzxYdhyCP7z9WbKo0R2hBCw==" - }, - "@types/glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==", + "@types/body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", "dev": true, "requires": { - "@types/minimatch": "*", + "@types/connect": "*", "@types/node": "*" } }, + "@types/bonjour": { + "version": "3.5.10", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.10.tgz", + "integrity": "sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/connect": { + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/connect-history-api-fallback": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.3.5.tgz", + "integrity": "sha512-h8QJa8xSb1WD4fpKBDcATDNGXghFj6/3GRWG6dhmRcu0RX1Ubasur2Uvx5aeEwlf0MwblEC2bMzzMQntxnw/Cw==", + "dev": true, + "requires": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "@types/eslint": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.1.tgz", + "integrity": "sha512-GE44+DNEyxxh2Kc6ro/VkIj+9ma0pO0bwv9+uHSyBrikYOHr8zYcdPvnBOp1aw8s+CjRvuSx7CyWqRrNFQ59mA==", + "dev": true, + "requires": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "@types/eslint-scope": { + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.3.tgz", + "integrity": "sha512-PB3ldyrcnAicT35TWPs5IcwKD8S333HMaa2VVv4+wdvebJkjWuW/xESoB8IwRcog8HYVYamb1g/R31Qv5Bx03g==", + "dev": true, + "requires": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "@types/estree": { + "version": "0.0.50", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.50.tgz", + "integrity": "sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw==", + "dev": true + }, + "@types/express": { + "version": "4.17.13", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", + "integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==", + "dev": true, + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.18", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "@types/express-serve-static-core": { + "version": "4.17.28", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz", + "integrity": "sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, + "@types/file-saver": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/file-saver/-/file-saver-2.0.5.tgz", + "integrity": "sha512-zv9kNf3keYegP5oThGLaPk8E081DFDuwfqjtiTzm6PoxChdJ1raSuADf2YGCVIyrSynLrgc8JWv296s7Q7pQSQ==" + }, "@types/graceful-fs": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", @@ -2798,10 +2780,19 @@ "@types/node": "*" } }, + "@types/http-proxy": { + "version": "1.17.8", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.8.tgz", + "integrity": "sha512-5kPLG5BKpWYkw/LVOGWpiq3nEVqxiN32rTgI53Sk12/xHFQ2rG3ehI9IO+O3W2QoKeyB92dJkoka8SUm6BX1pA==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/istanbul-lib-coverage": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", - "integrity": "sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", "dev": true }, "@types/istanbul-lib-report": { @@ -2814,46 +2805,40 @@ } }, "@types/istanbul-reports": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz", - "integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", "dev": true, "requires": { "@types/istanbul-lib-report": "*" } }, "@types/jest": { - "version": "26.0.20", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.20.tgz", - "integrity": "sha512-9zi2Y+5USJRxd0FsahERhBwlcvFh6D2GLQnY2FH2BzK8J9s9omvNHIbvABwIluXa0fD8XVKMLTO0aOEuUfACAA==", + "version": "27.4.0", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.4.0.tgz", + "integrity": "sha512-gHl8XuC1RZ8H2j5sHv/JqsaxXkDDM9iDOgu0Wp8sjs4u/snb2PVehyWXJPr+ORA0RPpgw231mnutWI1+0hgjIQ==", "dev": true, "requires": { - "jest-diff": "^26.0.0", - "pretty-format": "^26.0.0" + "jest-diff": "^27.0.0", + "pretty-format": "^27.0.0" } }, "@types/json-schema": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz", - "integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==", + "version": "7.0.9", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", + "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", "dev": true }, - "@types/minimatch": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", - "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", + "@types/mime": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", + "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==", "dev": true }, "@types/node": { - "version": "12.19.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.19.9.tgz", - "integrity": "sha512-yj0DOaQeUrk3nJ0bd3Y5PeDRJ6W0r+kilosLA+dzF3dola/o9hxhMSg2sFvVcA2UHS5JSOsZp4S0c1OEXc4m1Q==", - "dev": true - }, - "@types/normalize-package-data": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==", + "version": "17.0.17", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.17.tgz", + "integrity": "sha512-e8PUNQy1HgJGV3iU/Bp2+D/DXh3PYeyli8LgIwsQcs1Ar1LoaWHSIT6Rw+H2rNJmiq6SNWiDytfx8+gYj7wDHw==", "dev": true }, "@types/parse-json": { @@ -2863,15 +2848,27 @@ "dev": true }, "@types/prettier": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.2.1.tgz", - "integrity": "sha512-DxZZbyMAM9GWEzXL+BMZROWz9oo6A9EilwwOMET2UVu2uZTqMWS5S69KVtuVKaRjCUpcrOXRalet86/OpG4kqw==", + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.4.4.tgz", + "integrity": "sha512-ReVR2rLTV1kvtlWFyuot+d1pkpG2Fw/XKE3PDAdj57rbM97ttSp9JZ2UsP+2EHTylra9cUf6JA7tGwW1INzUrA==", "dev": true }, - "@types/q": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.4.tgz", - "integrity": "sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug==", + "@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", + "dev": true + }, + "@types/range-parser": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", + "dev": true + }, + "@types/retry": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.1.tgz", + "integrity": "sha512-xoDlM2S4ortawSWORYqsdU+2rxdh4LRW9ytc3zmT37RIKQh6IHyKwwtKhKis9ah8ol07DCkZxPt8BBvPjC6v4g==", "dev": true }, "@types/selenium-webdriver": { @@ -2880,224 +2877,207 @@ "integrity": "sha512-tGomyEuzSC1H28y2zlW6XPCaDaXFaD6soTdb4GNdmte2qfHtrKqhy0ZFs4r/1hpazCfEZqeTSRLvSasmEx89uw==", "dev": true }, - "@types/source-list-map": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz", - "integrity": "sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA==", - "dev": true - }, - "@types/stack-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.0.tgz", - "integrity": "sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw==", - "dev": true - }, - "@types/webpack-sources": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/@types/webpack-sources/-/webpack-sources-0.1.8.tgz", - "integrity": "sha512-JHB2/xZlXOjzjBB6fMOpH1eQAfsrpqVVIbneE0Rok16WXwFaznaI5vfg75U5WgGJm7V9W1c4xeRQDjX/zwvghA==", + "@types/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-d/Hs3nWDxNL2xAczmOVZNj92YZCS6RGxfBPjKzuu/XirCgXdpKEb88dYNbrYGint6IVWLNP+yonwVAuRC0T2Dg==", "dev": true, "requires": { - "@types/node": "*", - "@types/source-list-map": "*", - "source-map": "^0.6.1" - }, - "dependencies": { - "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 - } + "@types/express": "*" + } + }, + "@types/serve-static": { + "version": "1.13.10", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz", + "integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==", + "dev": true, + "requires": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "@types/sockjs": { + "version": "0.3.33", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.33.tgz", + "integrity": "sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/stack-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", + "dev": true + }, + "@types/ws": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.2.2.tgz", + "integrity": "sha512-NOn5eIcgWLOo6qW8AcuLZ7G8PycXu0xTxxkS6Q18VWFxgPUSOwV0pBj2a/4viNZVu25i7RIB7GttdkAIUUXOOg==", + "dev": true, + "requires": { + "@types/node": "*" } }, "@types/yargs": { - "version": "15.0.13", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.13.tgz", - "integrity": "sha512-kQ5JNTrbDv3Rp5X2n/iUu37IJBDU2gsZ5R/g1/KHOOEc5IKfUFjXT6DENPGduh08I/pamwtEq4oul7gUqKTQDQ==", + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", "dev": true, "requires": { "@types/yargs-parser": "*" } }, "@types/yargs-parser": { - "version": "20.2.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.0.tgz", - "integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA==", + "version": "20.2.1", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.1.tgz", + "integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==", "dev": true }, "@webassemblyjs/ast": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.0.tgz", - "integrity": "sha512-C6wW5L+b7ogSDVqymbkkvuW9kruN//YisMED04xzeBBqjHa2FYnmvOlS6Xj68xWQRgWvI9cIglsjFowH/RJyEA==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", + "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", "dev": true, "requires": { - "@webassemblyjs/helper-module-context": "1.9.0", - "@webassemblyjs/helper-wasm-bytecode": "1.9.0", - "@webassemblyjs/wast-parser": "1.9.0" + "@webassemblyjs/helper-numbers": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1" } }, "@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==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", + "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", "dev": true }, "@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==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", + "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", "dev": true }, "@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==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", + "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", "dev": true }, - "@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==", + "@webassemblyjs/helper-numbers": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", + "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", "dev": true, "requires": { - "@webassemblyjs/wast-printer": "1.9.0" - } - }, - "@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 - }, - "@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, - "requires": { - "@webassemblyjs/ast": "1.9.0" + "@webassemblyjs/floating-point-hex-parser": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@xtuc/long": "4.2.2" } }, "@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==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", + "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", "dev": true }, "@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==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", + "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/helper-buffer": "1.9.0", - "@webassemblyjs/helper-wasm-bytecode": "1.9.0", - "@webassemblyjs/wasm-gen": "1.9.0" + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1" } }, "@webassemblyjs/ieee754": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.9.0.tgz", - "integrity": "sha512-dcX8JuYU/gvymzIHc9DgxTzUUTLexWwt8uCTWP3otys596io0L5aW02Gb1RjYpx2+0Jus1h4ZFqjla7umFniTg==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", + "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", "dev": true, "requires": { "@xtuc/ieee754": "^1.2.0" } }, "@webassemblyjs/leb128": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.9.0.tgz", - "integrity": "sha512-ENVzM5VwV1ojs9jam6vPys97B/S65YQtv/aanqnU7D8aSoHFX8GyhGg0CMfyKNIHBuAVjy3tlzd5QMMINa7wpw==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", + "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", "dev": true, "requires": { "@xtuc/long": "4.2.2" } }, "@webassemblyjs/utf8": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.9.0.tgz", - "integrity": "sha512-GZbQlWtopBTP0u7cHrEx+73yZKrQoBMpwkGEIqlacljhXCkVM1kMQge/Mf+csMJAjEdSwhOyLAS0AoR3AG5P8w==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", + "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", "dev": true }, "@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==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", + "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", "dev": true, "requires": { - "@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" + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/helper-wasm-section": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-opt": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "@webassemblyjs/wast-printer": "1.11.1" } }, "@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==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", + "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", "dev": true, "requires": { - "@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" + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" } }, "@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==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", + "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/helper-buffer": "1.9.0", - "@webassemblyjs/wasm-gen": "1.9.0", - "@webassemblyjs/wasm-parser": "1.9.0" + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1" } }, "@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==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", + "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", "dev": true, "requires": { - "@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" - } - }, - "@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, - "requires": { - "@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" + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" } }, "@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==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", + "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/wast-parser": "1.9.0", + "@webassemblyjs/ast": "1.11.1", "@xtuc/long": "4.2.2" } }, @@ -3140,20 +3120,36 @@ } }, "accepts": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", - "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "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, "requires": { - "mime-types": "~2.1.24", - "negotiator": "0.6.2" + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "dependencies": { + "mime-db": { + "version": "1.51.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", + "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==", + "dev": true + }, + "mime-types": { + "version": "2.1.34", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", + "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", + "dev": true, + "requires": { + "mime-db": "1.51.0" + } + } } }, "acorn": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", - "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", - "dev": true + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", + "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==" }, "acorn-globals": { "version": "6.0.0", @@ -3170,23 +3166,47 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", "dev": true + }, + "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 } } }, - "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==", + "acorn-import-assertions": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", + "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", "dev": true }, + "acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==" + }, "adjust-sourcemap-loader": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-3.0.0.tgz", - "integrity": "sha512-YBrGyT2/uVQ/c6Rr+t6ZJXniY03YtHGMJQYal368burRGYKqhx9qGTWqcBU5s1CwYY9E/ri63RYyG1IacMZtqw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz", + "integrity": "sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A==", "dev": true, "requires": { "loader-utils": "^2.0.0", "regex-parser": "^2.2.11" + }, + "dependencies": { + "loader-utils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz", + "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + } } }, "adm-zip": { @@ -3205,9 +3225,9 @@ } }, "agentkeepalive": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.1.4.tgz", - "integrity": "sha512-+V/rGa3EuU74H6wR04plBb7Ks10FbtUQgRj/FQOG7uUIEuaINI+AiqJR1k6t3SVNs7o7ZjIdus6706qqzVq8jQ==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.2.0.tgz", + "integrity": "sha512-0PhAp58jZNw13UJv7NVdTGb0ZcghHUb3DrZ046JiiJY/BOaTTpbwdHq2VObPCBV8M2GPh7sgrJ3AQ8Ey468LJw==", "dev": true, "requires": { "debug": "^4.1.0", @@ -3237,11 +3257,34 @@ "uri-js": "^4.2.2" } }, - "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 + "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, + "requires": { + "ajv": "^8.0.0" + }, + "dependencies": { + "ajv": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.10.0.tgz", + "integrity": "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "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 + } + } }, "ajv-keywords": { "version": "3.5.2", @@ -3249,12 +3292,6 @@ "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", "dev": true }, - "alphanum-sort": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz", - "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=", - "dev": true - }, "ansi-colors": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", @@ -3262,18 +3299,18 @@ "dev": true }, "ansi-escapes": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", - "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", "dev": true, "requires": { - "type-fest": "^0.11.0" + "type-fest": "^0.21.3" } }, - "ansi-html": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz", - "integrity": "sha1-gTWEAhliqenm/QOflA0S9WynhZ4=", + "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 }, "ansi-regex": { @@ -3290,9 +3327,9 @@ } }, "anymatch": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", - "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", "dev": true, "requires": { "normalize-path": "^3.0.0", @@ -3306,19 +3343,32 @@ "dev": true }, "aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "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 }, "are-we-there-yet": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", - "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.0.tgz", + "integrity": "sha512-0GWpv50YSOcLXaN6/FAKY3vfRbllXWV2xvfA/oKJF8pzFhWXPV+yjhJXDBbjscDYowv7Yw1A3uigpzn5iEGTyw==", "dev": true, "requires": { "delegates": "^1.0.0", - "readable-stream": "^2.0.6" + "readable-stream": "^3.6.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } } }, "arg": { @@ -3346,30 +3396,6 @@ "commander": "^2.11.0" } }, - "arity-n": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/arity-n/-/arity-n-1.0.4.tgz", - "integrity": "sha1-2edrEXM+CFacCEeuezmyhgswt0U=", - "dev": true - }, - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true - }, - "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 - }, - "arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", - "dev": true - }, "array-flatten": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", @@ -3377,9 +3403,9 @@ "dev": true }, "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==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-3.0.1.tgz", + "integrity": "sha512-1OvF9IbWwaeiM9VhzYXVQacMibxpXOMYVNIvMtKRyX9SImBXpKcFr8XvFDeEslCyuH/t6KRt7HEO94AlP8Iatw==", "dev": true }, "array-uniq": { @@ -3388,12 +3414,6 @@ "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", "dev": true }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true - }, "arrify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", @@ -3409,65 +3429,12 @@ "safer-buffer": "~2.1.0" } }, - "asn1.js": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", - "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", - "dev": true, - "requires": { - "bn.js": "^4.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "safer-buffer": "^2.1.0" - }, - "dependencies": { - "bn.js": { - "version": "4.11.9", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", - "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", - "dev": true - } - } - }, - "assert": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", - "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", - "dev": true, - "requires": { - "object-assign": "^4.1.1", - "util": "0.10.3" - }, - "dependencies": { - "inherits": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", - "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", - "dev": true - }, - "util": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", - "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", - "dev": true, - "requires": { - "inherits": "2.0.1" - } - } - } - }, "assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", "dev": true }, - "assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", - "dev": true - }, "ast-types-flow": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", @@ -3483,17 +3450,6 @@ "lodash": "^4.17.14" } }, - "async-each": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", - "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", - "dev": true - }, - "async-limiter": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", - "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" - }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -3507,18 +3463,17 @@ "dev": true }, "autoprefixer": { - "version": "9.8.6", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.8.6.tgz", - "integrity": "sha512-XrvP4VVHdRBCdX1S3WXVD8+RyG9qeb1D5Sn1DeLiG2xfSpzellk5k54xbUERJ3M5DggQxes39UGOTP8CFrEGbg==", + "version": "10.4.2", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.2.tgz", + "integrity": "sha512-9fOPpHKuDW1w/0EKfRmVnxTDt8166MAnLI3mgZ1JCnhNtYWxcJ6Ud5CO/AVOZi/AvFa8DY9RTy3h3+tFBlrrdQ==", "dev": true, "requires": { - "browserslist": "^4.12.0", - "caniuse-lite": "^1.0.30001109", - "colorette": "^1.2.1", + "browserslist": "^4.19.1", + "caniuse-lite": "^1.0.30001297", + "fraction.js": "^4.1.2", "normalize-range": "^0.1.2", - "num2fraction": "^1.2.2", - "postcss": "^7.0.32", - "postcss-value-parser": "^4.1.0" + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" } }, "aws-sign2": { @@ -3543,18 +3498,18 @@ } }, "babel-jest": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-26.6.3.tgz", - "integrity": "sha512-pl4Q+GAVOHwvjrck6jKjvmGhnO3jHX/xuB9d27f+EJZ/6k+6nMuPjorrYp7s++bKKdANwzElBWnLWaObvTnaZA==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.5.1.tgz", + "integrity": "sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg==", "dev": true, "requires": { - "@jest/transform": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/babel__core": "^7.1.7", - "babel-plugin-istanbul": "^6.0.0", - "babel-preset-jest": "^26.6.2", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^27.5.1", "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", + "graceful-fs": "^4.2.9", "slash": "^3.0.0" }, "dependencies": { @@ -3568,9 +3523,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -3598,6 +3553,12 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -3610,29 +3571,17 @@ } }, "babel-loader": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.1.0.tgz", - "integrity": "sha512-7q7nC1tYOrqvUrN3LQK4GwSk/TQorZSOlO9C+RZDZpODgyN4ZlCqE5q9cDsyWOliN+aU9B4JX01xK9eJXowJLw==", + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.3.tgz", + "integrity": "sha512-n4Zeta8NC3QAsuyiizu0GkmRcQ6clkV9WFUnUf1iXP//IeSKbWjofW3UHyZVwlOB4y039YQKefawyTn64Zwbuw==", "dev": true, "requires": { - "find-cache-dir": "^2.1.0", + "find-cache-dir": "^3.3.1", "loader-utils": "^1.4.0", - "mkdirp": "^0.5.3", - "pify": "^4.0.1", + "make-dir": "^3.1.0", "schema-utils": "^2.6.5" }, "dependencies": { - "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, - "requires": { - "commondir": "^1.0.1", - "make-dir": "^2.0.0", - "pkg-dir": "^3.0.0" - } - }, "json5": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", @@ -3665,22 +3614,22 @@ } }, "babel-plugin-istanbul": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz", - "integrity": "sha512-AF55rZXpe7trmEylbaE1Gv54wn6rwU03aptvRoVIGP8YykoSxqdVLV1TfwflBCE/QtHmqtP8SWlTENqbK8GCSQ==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.0.0", "@istanbuljs/load-nyc-config": "^1.0.0", "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^4.0.0", + "istanbul-lib-instrument": "^5.0.4", "test-exclude": "^6.0.0" } }, "babel-plugin-jest-hoist": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.6.2.tgz", - "integrity": "sha512-PO9t0697lNTmcEHH69mdtYiOIkkOlj9fySqfO3K1eCcdISevLAE0xY59VLLUj0SoiPiTX/JU2CYFpILydUa5Lw==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.5.1.tgz", + "integrity": "sha512-50wCwD5EMNW4aRpOwtqzyZHIewTYNxLA4nhB+09d8BIssfNfzBRhkBIHiaPv1Si226TQSvp8gxAJm2iY2qs2hQ==", "dev": true, "requires": { "@babel/template": "^7.3.3", @@ -3689,6 +3638,44 @@ "@types/babel__traverse": "^7.0.6" } }, + "babel-plugin-polyfill-corejs2": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.1.tgz", + "integrity": "sha512-v7/T6EQcNfVLfcN2X8Lulb7DjprieyLWJK/zOWH5DUYcAgex9sP3h25Q+DLsX9TloXe3y1O8l2q2Jv9q8UVB9w==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.13.11", + "@babel/helper-define-polyfill-provider": "^0.3.1", + "semver": "^6.1.1" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "babel-plugin-polyfill-corejs3": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.2.tgz", + "integrity": "sha512-G3uJih0XWiID451fpeFaYGVuxHEjzKTHtc9uGFEjR6hHrvNzeS/PX+LLLcetJcytsB5m4j+K3o/EpXJNb/5IEQ==", + "dev": true, + "requires": { + "@babel/helper-define-polyfill-provider": "^0.3.1", + "core-js-compat": "^3.21.0" + } + }, + "babel-plugin-polyfill-regenerator": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz", + "integrity": "sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A==", + "dev": true, + "requires": { + "@babel/helper-define-polyfill-provider": "^0.3.1" + } + }, "babel-preset-current-node-syntax": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", @@ -3710,12 +3697,12 @@ } }, "babel-preset-jest": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-26.6.2.tgz", - "integrity": "sha512-YvdtlVm9t3k777c5NPQIv6cxFFFapys25HiUmuSgHwIZhfifweR5c5Sf5nwE3MAbfu327CYSvps8Yx6ANLyleQ==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.5.1.tgz", + "integrity": "sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag==", "dev": true, "requires": { - "babel-plugin-jest-hoist": "^26.6.2", + "babel-plugin-jest-hoist": "^27.5.1", "babel-preset-current-node-syntax": "^1.0.0" } }, @@ -3724,61 +3711,6 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, - "base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", - "dev": true, - "requires": { - "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" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, "base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -3807,21 +3739,11 @@ "dev": true }, "binary-extensions": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", - "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", "dev": true }, - "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, - "optional": true, - "requires": { - "file-uri-to-path": "1.0.0" - } - }, "bl": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", @@ -3833,16 +3755,6 @@ "readable-stream": "^3.4.0" }, "dependencies": { - "buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, "readable-stream": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", @@ -3865,40 +3777,28 @@ "minimist": "^1.2.0" } }, - "bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", - "dev": true - }, - "bn.js": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.1.3.tgz", - "integrity": "sha512-GkTiFpjFtUzU9CbMeJ5iazkCzGL3jrhzerzZIuqLABjbwRaFt33I9tUdSNryIptM+RxDet6OKm2WnLXzW51KsQ==", - "dev": true - }, "body-parser": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", - "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.1.tgz", + "integrity": "sha512-8ljfQi5eBk8EJfECMrgqNGWPEY5jWP+1IzkzkGdFFEwFQZZyaZ21UqdaHktgiMlH0xLHqIFtE/u2OYE5dOtViA==", "dev": true, "requires": { - "bytes": "3.1.0", + "bytes": "3.1.1", "content-type": "~1.0.4", "debug": "2.6.9", "depd": "~1.1.2", - "http-errors": "1.7.2", + "http-errors": "1.8.1", "iconv-lite": "0.4.24", "on-finished": "~2.3.0", - "qs": "6.7.0", - "raw-body": "2.4.0", - "type-is": "~1.6.17" + "qs": "6.9.6", + "raw-body": "2.4.2", + "type-is": "~1.6.18" }, "dependencies": { "bytes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.1.tgz", + "integrity": "sha512-dWe4nWO/ruEOY7HkUJ5gFt1DCFV9zPRoJr8pV0/ASQermOZjtq8jMjOprC0Kd10GLN+l7xaUPvxzJFWtxGu8Fg==", "dev": true }, "debug": { @@ -3939,9 +3839,9 @@ "dev": true }, "bootstrap": { - "version": "4.5.3", - "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.5.3.tgz", - "integrity": "sha512-o9ppKQioXGqhw8Z7mah6KdTYpNQY//tipnkxppWhPbiSWdD+1raYsnhwEZjkTHYbGee4cVQ0Rx65EhOY/HNLcQ==" + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.1.3.tgz", + "integrity": "sha512-fcQztozJ8jToQWXxVuEyXWW+dSo8AiXWKwiSSrKWsRB/Qt+Ewwza+JWoLKiTuQLaEPhdNAJ7+Dosc9DOIqNy7Q==" }, "bowser": { "version": "2.11.0", @@ -3966,121 +3866,23 @@ "fill-range": "^7.0.1" } }, - "brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", - "dev": true - }, "browser-process-hrtime": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", "dev": true }, - "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, - "requires": { - "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" - } - }, - "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, - "requires": { - "browserify-aes": "^1.0.4", - "browserify-des": "^1.0.0", - "evp_bytestokey": "^1.0.0" - } - }, - "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, - "requires": { - "cipher-base": "^1.0.1", - "des.js": "^1.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "browserify-rsa": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz", - "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==", - "dev": true, - "requires": { - "bn.js": "^5.0.0", - "randombytes": "^2.0.1" - } - }, - "browserify-sign": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz", - "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==", - "dev": true, - "requires": { - "bn.js": "^5.1.1", - "browserify-rsa": "^4.0.1", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "elliptic": "^6.5.3", - "inherits": "^2.0.4", - "parse-asn1": "^5.1.5", - "readable-stream": "^3.6.0", - "safe-buffer": "^5.2.0" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true - } - } - }, - "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, - "requires": { - "pako": "~1.0.5" - } - }, "browserslist": { - "version": "4.16.6", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.6.tgz", - "integrity": "sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ==", + "version": "4.19.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.19.1.tgz", + "integrity": "sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A==", "dev": true, "requires": { - "caniuse-lite": "^1.0.30001219", - "colorette": "^1.2.2", - "electron-to-chromium": "^1.3.723", + "caniuse-lite": "^1.0.30001286", + "electron-to-chromium": "^1.4.17", "escalade": "^3.1.1", - "node-releases": "^1.1.71" + "node-releases": "^2.0.1", + "picocolors": "^1.0.0" } }, "browserstack": { @@ -4111,20 +3913,19 @@ } }, "buffer": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", - "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", "dev": true, "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" } }, "buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "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 }, "buffer-indexof": { @@ -4133,24 +3934,12 @@ "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==", "dev": true }, - "buffer-xor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", - "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", - "dev": true - }, "builtin-modules": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", "dev": true }, - "builtin-status-codes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", - "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=", - "dev": true - }, "builtins": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz", @@ -4164,11 +3953,12 @@ "dev": true }, "cacache": { - "version": "15.0.5", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.0.5.tgz", - "integrity": "sha512-lloiL22n7sOjEEXdL8NAjTgv9a1u43xICE9/203qonkZUCj5X1UEWIdf2/Y0d6QcCtMzbKQyhrcDbdvlZTs/+A==", + "version": "15.3.0", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz", + "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", "dev": true, "requires": { + "@npmcli/fs": "^1.0.0", "@npmcli/move-file": "^1.0.1", "chownr": "^2.0.0", "fs-minipass": "^2.0.0", @@ -4183,7 +3973,7 @@ "p-map": "^4.0.0", "promise-inflight": "^1.0.1", "rimraf": "^3.0.2", - "ssri": "^8.0.0", + "ssri": "^8.0.1", "tar": "^6.0.2", "unique-filename": "^1.1.1" }, @@ -4196,23 +3986,6 @@ } } }, - "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, - "requires": { - "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" - } - }, "call-bind": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", @@ -4223,69 +3996,24 @@ "get-intrinsic": "^1.0.2" } }, - "caller-callsite": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", - "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", - "dev": true, - "requires": { - "callsites": "^2.0.0" - } - }, - "caller-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", - "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", - "dev": true, - "requires": { - "caller-callsite": "^2.0.0" - } - }, "callsites": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", - "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true }, "camelcase": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", - "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true }, - "caniuse-api": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", - "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", - "dev": true, - "requires": { - "browserslist": "^4.0.0", - "caniuse-lite": "^1.0.0", - "lodash.memoize": "^4.1.2", - "lodash.uniq": "^4.5.0" - } - }, "caniuse-lite": { - "version": "1.0.30001230", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001230.tgz", - "integrity": "sha512-5yBd5nWCBS+jWKTcHOzXwo5xzcj4ePE/yjtkZyUV1BTUmrBaA9MRGC+e7mxnqXSA90CmCA8L3eKLaSUkt099IQ==", + "version": "1.0.30001311", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001311.tgz", + "integrity": "sha512-mleTFtFKfykEeW34EyfhGIFjGCqzhh38Y0LhdQ9aWF+HorZTtdgKV/1hEE0NlFkG2ubvisPV6l400tlbPys98A==", "dev": true }, - "canonical-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/canonical-path/-/canonical-path-1.0.0.tgz", - "integrity": "sha512-feylzsbDxi1gPZ1IjystzIQZagYYLvfKrSuygUCgf7z6x790VEzze5QEkdSV1U58RA7Hi0+v6fv4K54atOzATg==", - "dev": true - }, - "capture-exit": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz", - "integrity": "sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==", - "dev": true, - "requires": { - "rsvp": "^4.8.4" - } - }, "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", @@ -4315,19 +4043,30 @@ "dev": true }, "chokidar": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.3.tgz", - "integrity": "sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", "dev": true, "requires": { - "anymatch": "~3.1.1", + "anymatch": "~3.1.2", "braces": "~3.0.2", - "fsevents": "~2.1.2", - "glob-parent": "~5.1.0", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", - "readdirp": "~3.5.0" + "readdirp": "~3.6.0" + }, + "dependencies": { + "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, + "requires": { + "is-glob": "^4.0.1" + } + } } }, "chownr": { @@ -4337,73 +4076,29 @@ "dev": true }, "chrome-trace-event": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz", - "integrity": "sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ==", - "dev": true, - "requires": { - "tslib": "^1.9.0" - }, - "dependencies": { - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - } - } - }, - "ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", "dev": true }, - "cipher-base": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", - "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } + "ci-info": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz", + "integrity": "sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw==", + "dev": true }, "circular-dependency-plugin": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/circular-dependency-plugin/-/circular-dependency-plugin-5.2.0.tgz", - "integrity": "sha512-7p4Kn/gffhQaavNfyDFg7LS5S/UT1JAjyGd4UqR2+jzoYF02eDkj0Ec3+48TsIa4zghjLY87nQHIh/ecK9qLdw==", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/circular-dependency-plugin/-/circular-dependency-plugin-5.2.2.tgz", + "integrity": "sha512-g38K9Cm5WRwlaH6g03B9OEz/0qRizI+2I7n+Gz+L5DxXJAPAiWQvwlYNm1V1jkdpUv95bOe/ASm2vfi/G560jQ==", "dev": true }, "cjs-module-lexer": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-0.6.0.tgz", - "integrity": "sha512-uc2Vix1frTfnuzxxu1Hp4ktSvM3QaI4oXl4ZUqL1wjTu/BGki9TrCWoqLTg/drR1KwAEarXuRFCG2Svr1GxPFw==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", + "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", "dev": true }, - "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, - "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, "clean-stack": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", @@ -4420,9 +4115,9 @@ } }, "cli-spinners": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.5.0.tgz", - "integrity": "sha512-PC+AmIuK04E6aeSs/pUccSujsTzBhu4HzC2dL+CfJB/Jcc2qTRbEwZQDfIUpt2Xl8BodYBEq8w4fc0kU2I9DjQ==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.1.tgz", + "integrity": "sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==", "dev": true }, "cli-width": { @@ -4432,54 +4127,13 @@ "dev": true }, "cliui": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", - "dev": true, + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", "requires": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" } }, "clone": { @@ -4505,27 +4159,10 @@ "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", "dev": true }, - "coa": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz", - "integrity": "sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==", - "dev": true, - "requires": { - "@types/q": "^1.5.1", - "chalk": "^2.4.1", - "q": "^1.1.2" - } - }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true - }, "codelyzer": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/codelyzer/-/codelyzer-6.0.1.tgz", - "integrity": "sha512-cOyGQgMdhnRYtW2xrJUNrNYDjEgwQ+BrE2y93Bwz3h4DJ6vJRLfupemU5N3pbYsUlBHJf0u1j1UGk+NLW4d97g==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/codelyzer/-/codelyzer-6.0.2.tgz", + "integrity": "sha512-v3+E0Ucu2xWJMOJ2fA/q9pDT/hlxHftHGPUay1/1cTgyPV5JTHFdO9hqo837Sx2s9vKBMTt5gO+lhF95PO6J+g==", "dev": true, "requires": { "@angular/compiler": "9.0.0", @@ -4556,11 +4193,14 @@ "integrity": "sha512-6Pxgsrf0qF9iFFqmIcWmjJGkkCaCm6V5QNnxMy2KloO3SDq6QuMVRbN9RtC8Urmo25LP+eZ6ZgYqFYpdD8Hd9w==", "dev": true }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true + "rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } }, "sprintf-js": { "version": "1.1.2", @@ -4573,6 +4213,12 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "dev": true + }, + "zone.js": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.10.3.tgz", + "integrity": "sha512-LXVLVEq0NNOqK/fLJo3d0kfzd4sxwn2/h67/02pjCjfKDxgx1i9QqpvtHD8CrBnSSwMw5+dy11O7FRX5mkO7Cg==", + "dev": true } } }, @@ -4582,26 +4228,6 @@ "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", "dev": true }, - "collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", - "dev": true, - "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" - } - }, - "color": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/color/-/color-3.1.3.tgz", - "integrity": "sha512-xgXAcTHa2HeFCGLE9Xs/R82hujGtu9Jd9x4NW3T34+OMs7VoPsjwzRczKHvTAHeJwWFwX5j15+MgAppE8ztObQ==", - "dev": true, - "requires": { - "color-convert": "^1.9.1", - "color-string": "^1.5.4" - } - }, "color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -4615,20 +4241,16 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" }, - "color-string": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.6.0.tgz", - "integrity": "sha512-c/hGS+kRWJutUBEngKKmk4iH3sD59MBkoxVapS/0wgpCz2u7XsNloxknyvBhzwEs1IbV36D9PwqLPJ2DTu3vMA==", - "dev": true, - "requires": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" - } + "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 }, "colorette": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", - "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==", + "version": "2.0.16", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz", + "integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==", "dev": true }, "combined-stream": { @@ -4652,21 +4274,6 @@ "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", "dev": true }, - "component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", - "dev": true - }, - "compose-function": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/compose-function/-/compose-function-3.0.3.tgz", - "integrity": "sha1-ntZ18TzFRQHTCVCkhv9qe6OrGF8=", - "dev": true, - "requires": { - "arity-n": "^1.0.4" - } - }, "compressible": { "version": "2.0.18", "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", @@ -4713,49 +4320,33 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, - "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, - "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, "connect-history-api-fallback": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==", "dev": true }, - "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 - }, "console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", "dev": true }, - "constants-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", - "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=", - "dev": true - }, "content-disposition": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", - "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "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, "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "5.2.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + } } }, "content-type": { @@ -4765,17 +4356,17 @@ "dev": true }, "convert-source-map": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", - "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", "requires": { "safe-buffer": "~5.1.1" } }, "cookie": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", - "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==", "dev": true }, "cookie-signature": { @@ -4784,107 +4375,83 @@ "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", "dev": true }, - "copy-concurrently": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", - "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", + "copy-anything": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz", + "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==", "dev": true, "requires": { - "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" - }, - "dependencies": { - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - } + "is-what": "^3.14.1" } }, - "copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", - "dev": true - }, "copy-webpack-plugin": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-6.2.1.tgz", - "integrity": "sha512-VH2ZTMIBsx4p++Lmpg77adZ0KUyM5gFR/9cuTrbneNnJlcQXUFvsNariPqq2dq2kV3F2skHiDGPQCyKWy1+U0Q==", + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-10.2.1.tgz", + "integrity": "sha512-nr81NhCAIpAWXGCK5thrKmfCQ6GDY0L5RN0U+BnIn/7Us55+UCex5ANNsNKmIVtDRnk0Ecf+/kzp9SUVrrBMLg==", "dev": true, "requires": { - "cacache": "^15.0.5", - "fast-glob": "^3.2.4", - "find-cache-dir": "^3.3.1", - "glob-parent": "^5.1.1", - "globby": "^11.0.1", - "loader-utils": "^2.0.0", + "fast-glob": "^3.2.7", + "glob-parent": "^6.0.1", + "globby": "^12.0.2", "normalize-path": "^3.0.0", - "p-limit": "^3.0.2", - "schema-utils": "^3.0.0", - "serialize-javascript": "^5.0.1", - "webpack-sources": "^1.4.3" + "schema-utils": "^4.0.0", + "serialize-javascript": "^6.0.0" }, "dependencies": { - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "ajv": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.10.0.tgz", + "integrity": "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==", "dev": true, "requires": { - "yocto-queue": "^0.1.0" + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" } }, - "schema-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", - "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==", + "ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", "dev": true, "requires": { - "@types/json-schema": "^7.0.6", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" + "fast-deep-equal": "^3.1.3" } }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "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 }, - "webpack-sources": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", - "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", + "schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", "dev": true, "requires": { - "source-list-map": "^2.0.0", - "source-map": "~0.6.1" + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" } } } }, "core-js": { - "version": "3.6.5", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.6.5.tgz", - "integrity": "sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA==", + "version": "3.20.3", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.20.3.tgz", + "integrity": "sha512-vVl8j8ph6tRS3B8qir40H7yw7voy17xL0piAjlbBUsH7WIfzoedL/ZOr1OV9FyZQLWXsayOJyV4tnRyXR85/ag==", "dev": true }, "core-js-compat": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.8.1.tgz", - "integrity": "sha512-a16TLmy9NVD1rkjUGbwuyWkiDoN0FDpAwrfLONvHFQx0D9k7J9y0srwMT8QP/Z6HE3MIFaVynEeYwZwPX1o5RQ==", + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.21.0.tgz", + "integrity": "sha512-OSXseNPSK2OPJa6GdtkMz/XxeXx8/CJvfhQWTqd6neuUraujcL4jVsjkLQz1OWnax8xVQJnRPe0V2jqNWORA+A==", "dev": true, "requires": { - "browserslist": "^4.15.0", + "browserslist": "^4.19.1", "semver": "7.0.0" }, "dependencies": { @@ -4903,112 +4470,115 @@ "dev": true }, "cosmiconfig": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", - "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", + "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", "dev": true, "requires": { - "import-fresh": "^2.0.0", - "is-directory": "^0.3.1", - "js-yaml": "^3.13.1", - "parse-json": "^4.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" } }, - "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==", + "create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "critters": { + "version": "0.0.16", + "resolved": "https://registry.npmjs.org/critters/-/critters-0.0.16.tgz", + "integrity": "sha512-JwjgmO6i3y6RWtLYmXwO5jMd+maZt8Tnfu7VVISmEWyQqfLpB8soBswf8/2bu6SBXxtKA68Al3c+qIG1ApT68A==", "dev": true, "requires": { - "bn.js": "^4.1.0", - "elliptic": "^6.5.3" + "chalk": "^4.1.0", + "css-select": "^4.2.0", + "parse5": "^6.0.1", + "parse5-htmlparser2-tree-adapter": "^6.0.1", + "postcss": "^8.3.7", + "pretty-bytes": "^5.3.0" }, "dependencies": { - "bn.js": { - "version": "4.11.9", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", - "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "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, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "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, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 + }, + "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 + }, + "parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } } } }, - "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, - "requires": { - "cipher-base": "^1.0.1", - "inherits": "^2.0.1", - "md5.js": "^1.3.4", - "ripemd160": "^2.0.1", - "sha.js": "^2.4.0" - } - }, - "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, - "requires": { - "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" - } - }, "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "dev": true, "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, - "crypto-browserify": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", - "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", - "dev": true, - "requires": { - "browserify-cipher": "^1.0.0", - "browserify-sign": "^4.0.0", - "create-ecdh": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.0", - "diffie-hellman": "^5.0.0", - "inherits": "^2.0.1", - "pbkdf2": "^3.0.3", - "public-encrypt": "^4.0.0", - "randombytes": "^2.0.0", - "randomfill": "^1.0.3" + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" } }, "css": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/css/-/css-2.2.4.tgz", - "integrity": "sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/css/-/css-3.0.0.tgz", + "integrity": "sha512-DG9pFfwOrzc+hawpmqX/dHYHJG+Bsdb0klhyi1sDneOgGOXy9wQIC8hzyVp1e4NRYDBdxcylvywPkkXCHAzTyQ==", "dev": true, "requires": { - "inherits": "^2.0.3", + "inherits": "^2.0.4", "source-map": "^0.6.1", - "source-map-resolve": "^0.5.2", - "urix": "^0.1.0" + "source-map-resolve": "^0.6.0" }, "dependencies": { "source-map": { @@ -5019,69 +4589,70 @@ } } }, - "css-color-names": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz", - "integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=", - "dev": true - }, - "css-declaration-sorter": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-4.0.1.tgz", - "integrity": "sha512-BcxQSKTSEEQUftYpBVnsH4SF05NTuBokb19/sBt6asXGKZ/6VP7PLG1CBCkFDYOnhXhPh0jMhO6xZ71oYHXHBA==", + "css-blank-pseudo": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/css-blank-pseudo/-/css-blank-pseudo-3.0.3.tgz", + "integrity": "sha512-VS90XWtsHGqoM0t4KpH053c4ehxZ2E6HtGI7x68YFV0pTo/QmkV/YFA+NnlvK8guxZVNWGQhVNJGC39Q8XF4OQ==", "dev": true, "requires": { - "postcss": "^7.0.1", - "timsort": "^0.3.0" + "postcss-selector-parser": "^6.0.9" + } + }, + "css-has-pseudo": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/css-has-pseudo/-/css-has-pseudo-3.0.4.tgz", + "integrity": "sha512-Vse0xpR1K9MNlp2j5w1pgWIJtm1a8qS0JwS9goFYcImjlHEmywP9VUF05aGBXzGpDJF86QXk4L0ypBmwPhGArw==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.9" } }, "css-loader": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-4.3.0.tgz", - "integrity": "sha512-rdezjCjScIrsL8BSYszgT4s476IcNKt6yX69t0pHjJVnPUTDpn4WfIpDQTN3wCJvUvfsz/mFjuGOekf3PY3NUg==", + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.5.1.tgz", + "integrity": "sha512-gEy2w9AnJNnD9Kuo4XAP9VflW/ujKoS9c/syO+uWMlm5igc7LysKzPXaDoR2vroROkSwsTS2tGr1yGGEbZOYZQ==", "dev": true, "requires": { - "camelcase": "^6.0.0", - "cssesc": "^3.0.0", - "icss-utils": "^4.1.1", - "loader-utils": "^2.0.0", - "postcss": "^7.0.32", - "postcss-modules-extract-imports": "^2.0.0", - "postcss-modules-local-by-default": "^3.0.3", - "postcss-modules-scope": "^2.2.0", - "postcss-modules-values": "^3.0.0", + "icss-utils": "^5.1.0", + "postcss": "^8.2.15", + "postcss-modules-extract-imports": "^3.0.0", + "postcss-modules-local-by-default": "^4.0.0", + "postcss-modules-scope": "^3.0.0", + "postcss-modules-values": "^4.0.0", "postcss-value-parser": "^4.1.0", - "schema-utils": "^2.7.1", - "semver": "^7.3.2" + "semver": "^7.3.5" + }, + "dependencies": { + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } } }, - "css-parse": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/css-parse/-/css-parse-2.0.0.tgz", - "integrity": "sha1-pGjuZnwW2BzPBcWMONKpfHgNv9Q=", - "dev": true, - "requires": { - "css": "^2.0.0" - } + "css-prefers-color-scheme": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-6.0.3.tgz", + "integrity": "sha512-4BqMbZksRkJQx2zAjrokiGMd07RqOa2IxIrrN10lyBe9xhn9DEvjUK79J6jkeiv9D9hQFXKb6g1jwU62jziJZA==", + "dev": true }, "css-select": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz", - "integrity": "sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.2.1.tgz", + "integrity": "sha512-/aUslKhzkTNCQUB2qTX84lVmfia9NyjP3WpDGtj/WxhwBzWBYUV3DgUpurHTme8UTPcPlAD1DJ+b0nN/t50zDQ==", "dev": true, "requires": { "boolbase": "^1.0.0", - "css-what": "^3.2.1", - "domutils": "^1.7.0", - "nth-check": "^1.0.2" + "css-what": "^5.1.0", + "domhandler": "^4.3.0", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" } }, - "css-select-base-adapter": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz", - "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==", - "dev": true - }, "css-selector-tokenizer": { "version": "0.7.3", "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.3.tgz", @@ -5092,28 +4663,10 @@ "fastparse": "^1.1.2" } }, - "css-tree": { - "version": "1.0.0-alpha.37", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz", - "integrity": "sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg==", - "dev": true, - "requires": { - "mdn-data": "2.0.4", - "source-map": "^0.6.1" - }, - "dependencies": { - "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 - } - } - }, "css-what": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz", - "integrity": "sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.1.0.tgz", + "integrity": "sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw==", "dev": true }, "cssauron": { @@ -5125,122 +4678,18 @@ "through": "X.X.X" } }, + "cssdb": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-5.1.0.tgz", + "integrity": "sha512-/vqjXhv1x9eGkE/zO6o8ZOI7dgdZbLVLUGyVRbPgk6YipXbW87YzUCcO+Jrmi5bwJlAH6oD+MNeZyRgXea1GZw==", + "dev": true + }, "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 }, - "cssnano": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-4.1.10.tgz", - "integrity": "sha512-5wny+F6H4/8RgNlaqab4ktc3e0/blKutmq8yNlBFXA//nSFFAqAngjNVRzUvCgYROULmZZUoosL/KSoZo5aUaQ==", - "dev": true, - "requires": { - "cosmiconfig": "^5.0.0", - "cssnano-preset-default": "^4.0.7", - "is-resolvable": "^1.0.0", - "postcss": "^7.0.0" - } - }, - "cssnano-preset-default": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-4.0.8.tgz", - "integrity": "sha512-LdAyHuq+VRyeVREFmuxUZR1TXjQm8QQU/ktoo/x7bz+SdOge1YKc5eMN6pRW7YWBmyq59CqYba1dJ5cUukEjLQ==", - "dev": true, - "requires": { - "css-declaration-sorter": "^4.0.1", - "cssnano-util-raw-cache": "^4.0.1", - "postcss": "^7.0.0", - "postcss-calc": "^7.0.1", - "postcss-colormin": "^4.0.3", - "postcss-convert-values": "^4.0.1", - "postcss-discard-comments": "^4.0.2", - "postcss-discard-duplicates": "^4.0.2", - "postcss-discard-empty": "^4.0.1", - "postcss-discard-overridden": "^4.0.1", - "postcss-merge-longhand": "^4.0.11", - "postcss-merge-rules": "^4.0.3", - "postcss-minify-font-values": "^4.0.2", - "postcss-minify-gradients": "^4.0.2", - "postcss-minify-params": "^4.0.2", - "postcss-minify-selectors": "^4.0.2", - "postcss-normalize-charset": "^4.0.1", - "postcss-normalize-display-values": "^4.0.2", - "postcss-normalize-positions": "^4.0.2", - "postcss-normalize-repeat-style": "^4.0.2", - "postcss-normalize-string": "^4.0.2", - "postcss-normalize-timing-functions": "^4.0.2", - "postcss-normalize-unicode": "^4.0.1", - "postcss-normalize-url": "^4.0.1", - "postcss-normalize-whitespace": "^4.0.2", - "postcss-ordered-values": "^4.1.2", - "postcss-reduce-initial": "^4.0.3", - "postcss-reduce-transforms": "^4.0.2", - "postcss-svgo": "^4.0.3", - "postcss-unique-selectors": "^4.0.1" - } - }, - "cssnano-util-get-arguments": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cssnano-util-get-arguments/-/cssnano-util-get-arguments-4.0.0.tgz", - "integrity": "sha1-7ToIKZ8h11dBsg87gfGU7UnMFQ8=", - "dev": true - }, - "cssnano-util-get-match": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cssnano-util-get-match/-/cssnano-util-get-match-4.0.0.tgz", - "integrity": "sha1-wOTKB/U4a7F+xeUiULT1lhNlFW0=", - "dev": true - }, - "cssnano-util-raw-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/cssnano-util-raw-cache/-/cssnano-util-raw-cache-4.0.1.tgz", - "integrity": "sha512-qLuYtWK2b2Dy55I8ZX3ky1Z16WYsx544Q0UWViebptpwn/xDBmog2TLg4f+DBMg1rJ6JDWtn96WHbOKDWt1WQA==", - "dev": true, - "requires": { - "postcss": "^7.0.0" - } - }, - "cssnano-util-same-parent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/cssnano-util-same-parent/-/cssnano-util-same-parent-4.0.1.tgz", - "integrity": "sha512-WcKx5OY+KoSIAxBW6UBBRay1U6vkYheCdjyVNDm85zt5K9mHoGOfsOsqIszfAqrQQFIIKgjh2+FDgIj/zsl21Q==", - "dev": true - }, - "csso": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", - "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", - "dev": true, - "requires": { - "css-tree": "^1.1.2" - }, - "dependencies": { - "css-tree": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", - "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", - "dev": true, - "requires": { - "mdn-data": "2.0.14", - "source-map": "^0.6.1" - } - }, - "mdn-data": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", - "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", - "dev": true - }, - "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 - } - } - }, "cssom": { "version": "0.4.4", "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", @@ -5264,26 +4713,10 @@ } } }, - "cyclist": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz", - "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=", - "dev": true - }, - "d": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", - "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", - "dev": true, - "requires": { - "es5-ext": "^0.10.50", - "type": "^1.0.1" - } - }, "damerau-levenshtein": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.6.tgz", - "integrity": "sha512-JVrozIeElnj3QzfUIt8tB8YMluBJom4Vw9qTPpjGYQ9fYlB3D/rb6OordUxf3xeFB35LKWs0xqcO5U6ySvBtug==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", "dev": true }, "dashdash": { @@ -5304,12 +4737,40 @@ "abab": "^2.0.3", "whatwg-mimetype": "^2.3.0", "whatwg-url": "^8.0.0" + }, + "dependencies": { + "tr46": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", + "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", + "dev": true, + "requires": { + "punycode": "^2.1.1" + } + }, + "webidl-conversions": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", + "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", + "dev": true + }, + "whatwg-url": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", + "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", + "dev": true, + "requires": { + "lodash": "^4.7.0", + "tr46": "^2.1.0", + "webidl-conversions": "^6.1.0" + } + } } }, "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", "requires": { "ms": "2.1.2" } @@ -5332,6 +4793,12 @@ "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", "dev": true }, + "dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", + "dev": true + }, "deep-equal": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", @@ -5359,13 +4826,12 @@ "dev": true }, "default-gateway": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-4.2.0.tgz", - "integrity": "sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", "dev": true, "requires": { - "execa": "^1.0.0", - "ip-regex": "^2.1.0" + "execa": "^5.0.0" } }, "defaults": { @@ -5377,6 +4843,12 @@ "clone": "^1.0.2" } }, + "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 + }, "define-properties": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", @@ -5386,106 +4858,47 @@ "object-keys": "^1.0.12" } }, - "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, - "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "dependencies": { - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, "del": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/del/-/del-4.1.1.tgz", - "integrity": "sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/del/-/del-6.0.0.tgz", + "integrity": "sha512-1shh9DQ23L16oXSZKB2JxpL7iMy2E0S9d517ptA1P8iw0alkPtQcrKH7ru31rYtKwF499HkTu+DRzq3TCKDFRQ==", "dev": true, "requires": { - "@types/glob": "^7.1.1", - "globby": "^6.1.0", - "is-path-cwd": "^2.0.0", - "is-path-in-cwd": "^2.0.0", - "p-map": "^2.0.0", - "pify": "^4.0.1", - "rimraf": "^2.6.3" + "globby": "^11.0.1", + "graceful-fs": "^4.2.4", + "is-glob": "^4.0.1", + "is-path-cwd": "^2.2.0", + "is-path-inside": "^3.0.2", + "p-map": "^4.0.0", + "rimraf": "^3.0.2", + "slash": "^3.0.0" }, "dependencies": { "array-union": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", - "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", - "dev": true, - "requires": { - "array-uniq": "^1.0.1" - } - }, - "globby": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", - "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", - "dev": true, - "requires": { - "array-union": "^1.0.1", - "glob": "^7.0.3", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - }, - "dependencies": { - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - } - } - }, - "p-map": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", - "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true }, - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, "requires": { - "glob": "^7.1.3" + "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" } + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true } } }, @@ -5508,21 +4921,11 @@ "dev": true }, "dependency-graph": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.7.2.tgz", - "integrity": "sha512-KqtH4/EZdtdfWX0p6MGP9jljvxSY6msy/pRUD4jgNwVpv3v1QmNLlsB3LDSSUg79BRVSn7jI1QPRtArGABovAQ==", + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.11.0.tgz", + "integrity": "sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg==", "dev": true }, - "des.js": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", - "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, "destroy": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", @@ -5536,9 +4939,9 @@ "dev": true }, "detect-node": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.4.tgz", - "integrity": "sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", "dev": true }, "detect-passive-events": { @@ -5553,30 +4956,11 @@ "dev": true }, "diff-sequences": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz", - "integrity": "sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", + "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", "dev": true }, - "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, - "requires": { - "bn.js": "^4.1.0", - "miller-rabin": "^4.0.0", - "randombytes": "^2.0.0" - }, - "dependencies": { - "bn.js": { - "version": "4.11.9", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", - "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", - "dev": true - } - } - }, "dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -5612,41 +4996,28 @@ } }, "dom-serializer": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", - "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", + "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", "dev": true, "requires": { "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", "entities": "^2.0.0" - }, - "dependencies": { - "domelementtype": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", - "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", - "dev": true - } } }, "dom7": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/dom7/-/dom7-3.0.0.tgz", - "integrity": "sha512-oNlcUdHsC4zb7Msx7JN3K0Nro1dzJ48knvBOnDPKJ2GV9wl1i5vydJZUSyOfrkKFDZEud/jBsTk92S/VGSAe/g==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/dom7/-/dom7-4.0.4.tgz", + "integrity": "sha512-DSSgBzQ4rJWQp1u6o+3FVwMNnT5bzQbMb+o31TjYYeRi05uAcpF8koxdfzeoe5ElzPmua7W7N28YJhF7iEKqIw==", "requires": { - "ssr-window": "^3.0.0-alpha.1" + "ssr-window": "^4.0.0" } }, - "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 - }, "domelementtype": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", - "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", + "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", "dev": true }, "domexception": { @@ -5666,23 +5037,24 @@ } } }, - "domutils": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", - "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", + "domhandler": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.0.tgz", + "integrity": "sha512-fC0aXNQXqKSFTr2wDNZDhsEYjCiYsDWl3D01kwt25hm1YIPyDGHvvi3rw+PLqHAl/m71MaiF7d5zvBr0p5UB2g==", "dev": true, "requires": { - "dom-serializer": "0", - "domelementtype": "1" + "domelementtype": "^2.2.0" } }, - "dot-prop": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", - "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", "dev": true, "requires": { - "is-obj": "^2.0.0" + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" } }, "duplexer": { @@ -5690,18 +5062,6 @@ "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==" }, - "duplexify": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", - "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", - "dev": true, - "requires": { - "end-of-stream": "^1.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.0.0", - "stream-shift": "^1.0.0" - } - }, "ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", @@ -5719,38 +5079,15 @@ "dev": true }, "electron-to-chromium": { - "version": "1.3.741", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.741.tgz", - "integrity": "sha512-4i3T0cwnHo1O4Mnp9JniEco8bZiXoqbm3PhW5hv7uu8YLg35iajYrRnNyKFaN8/8SSTskU2hYqVTeYVPceSpUA==", + "version": "1.4.68", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.68.tgz", + "integrity": "sha512-cId+QwWrV8R1UawO6b9BR1hnkJ4EJPCPAr4h315vliHUtVUJDk39Sg1PMNnaWKfj5x+93ssjeJ9LKL6r8LaMiA==", "dev": true }, - "elliptic": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", - "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", - "dev": true, - "requires": { - "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" - }, - "dependencies": { - "bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true - } - } - }, "emittery": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.7.2.tgz", - "integrity": "sha512-A8OG5SR/ij3SsJdWDJdkkSYUjQdCUx6APQXem0SaEePBSRg4eymGYwBkKo1Y6DU+af/Jn2dBQqDBvjnr9Vi8nQ==", + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", + "integrity": "sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==", "dev": true }, "emoji-regex": { @@ -5781,9 +5118,9 @@ }, "dependencies": { "iconv-lite": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz", - "integrity": "sha512-2y91h5OpQlolefMPmUlivelittSWy0rP+oYVpn6A7GwVHNE8AWzoYOBNmlwks3LobaJxgHCYZAnyNo2GgpNRNQ==", + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "dev": true, "optional": true, "requires": { @@ -5792,23 +5129,14 @@ } } }, - "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, - "requires": { - "once": "^1.4.0" - } - }, "enhanced-resolve": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.3.1.tgz", - "integrity": "sha512-G1XD3MRGrGfNcf6Hg0LVZG7GIKcYkbfHa5QMxt1HDUTdYoXH0JR1xXyg+MaKLF73E9A27uWNVxvFivNRYeUB6w==", + "version": "5.9.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.9.0.tgz", + "integrity": "sha512-weDYmzbBygL7HzGGS26M3hGQx68vehdEg6VUmqSOaFzXExFqlnKuSvsEJCVGQHScS8CQMbrAqftT+AzzHNt/YA==", "dev": true, "requires": { "graceful-fs": "^4.2.4", - "tapable": "^2.0.0" + "tapable": "^2.2.0" } }, "entities": { @@ -5830,10 +5158,11 @@ "dev": true }, "errno": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", - "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", "dev": true, + "optional": true, "requires": { "prr": "~1.0.1" } @@ -5847,67 +5176,11 @@ "is-arrayish": "^0.2.1" } }, - "es-abstract": { - "version": "1.18.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.3.tgz", - "integrity": "sha512-nQIr12dxV7SSxE6r6f1l3DtAeEYdsGpps13dR0TwJg1S8gyp4ZPgy3FZcHBgbiQqnoqSTb+oC+kO4UQ0C/J8vw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.2", - "is-callable": "^1.2.3", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.3", - "is-string": "^1.0.6", - "object-inspect": "^1.10.3", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "es5-ext": { - "version": "0.10.53", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", - "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", - "dev": true, - "requires": { - "es6-iterator": "~2.0.3", - "es6-symbol": "~3.1.3", - "next-tick": "~1.0.0" - } - }, - "es6-denodeify": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/es6-denodeify/-/es6-denodeify-0.1.5.tgz", - "integrity": "sha1-MdTV/pxVA+ElRgQ5MQ4WoqPznB8=" - }, - "es6-iterator": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", - "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", - "dev": true, - "requires": { - "d": "1", - "es5-ext": "^0.10.35", - "es6-symbol": "^3.1.1" - } + "es-module-lexer": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", + "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", + "dev": true }, "es6-promise": { "version": "4.2.8", @@ -5924,15 +5197,137 @@ "es6-promise": "^4.0.3" } }, - "es6-symbol": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", - "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "esbuild-android-arm64": { + "version": "0.14.14", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.14.tgz", + "integrity": "sha512-be/Uw6DdpQiPfula1J4bdmA+wtZ6T3BRCZsDMFB5X+k0Gp8TIh9UvmAcqvKNnbRAafSaXG3jPCeXxDKqnc8hFQ==", "dev": true, - "requires": { - "d": "^1.0.1", - "ext": "^1.1.2" - } + "optional": true + }, + "esbuild-darwin-64": { + "version": "0.14.14", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.14.tgz", + "integrity": "sha512-BEexYmjWafcISK8cT6O98E3TfcLuZL8DKuubry6G54n2+bD4GkoRD6HYUOnCkfl2p7jodA+s4369IjSFSWjtHg==", + "dev": true, + "optional": true + }, + "esbuild-darwin-arm64": { + "version": "0.14.14", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.14.tgz", + "integrity": "sha512-tnBKm41pDOB1GtZ8q/w26gZlLLRzVmP8fdsduYjvM+yFD7E2DLG4KbPAqFMWm4Md9B+DitBglP57FY7AznxbTg==", + "dev": true, + "optional": true + }, + "esbuild-freebsd-64": { + "version": "0.14.14", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.14.tgz", + "integrity": "sha512-Q9Rx6sgArOHalQtNwAaIzJ6dnQ8A+I7f/RsQsdkS3JrdzmnlFo8JEVofTmwVQLoIop7OKUqIVOGP4PoQcwfVMA==", + "dev": true, + "optional": true + }, + "esbuild-freebsd-arm64": { + "version": "0.14.14", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.14.tgz", + "integrity": "sha512-TJvq0OpLM7BkTczlyPIphcvnwrQwQDG1HqxzoYePWn26SMUAlt6wrLnEvxdbXAvNvDLVzG83kA+JimjK7aRNBA==", + "dev": true, + "optional": true + }, + "esbuild-linux-32": { + "version": "0.14.14", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.14.tgz", + "integrity": "sha512-h/CrK9Baimt5VRbu8gqibWV7e1P9l+mkanQgyOgv0Ng3jHT1NVFC9e6rb1zbDdaJVmuhWX5xVliUA5bDDCcJeg==", + "dev": true, + "optional": true + }, + "esbuild-linux-64": { + "version": "0.14.14", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.14.tgz", + "integrity": "sha512-IC+wAiIg/egp5OhQp4W44D9PcBOH1b621iRn1OXmlLzij9a/6BGr9NMIL4CRwz4j2kp3WNZu5sT473tYdynOuQ==", + "dev": true, + "optional": true + }, + "esbuild-linux-arm": { + "version": "0.14.14", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.14.tgz", + "integrity": "sha512-gxpOaHOPwp7zSmcKYsHrtxabScMqaTzfSQioAMUaB047YiMuDBzqVcKBG8OuESrYkGrL9DDljXr/mQNg7pbdaQ==", + "dev": true, + "optional": true + }, + "esbuild-linux-arm64": { + "version": "0.14.14", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.14.tgz", + "integrity": "sha512-6QVul3RI4M5/VxVIRF/I5F+7BaxzR3DfNGoqEVSCZqUbgzHExPn+LXr5ly1C7af2Kw4AHpo+wDqx8A4ziP9avw==", + "dev": true, + "optional": true + }, + "esbuild-linux-mips64le": { + "version": "0.14.14", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.14.tgz", + "integrity": "sha512-4Jl5/+xoINKbA4cesH3f4R+q0vltAztZ6Jm8YycS8lNhN1pgZJBDxWfI6HUMIAdkKlIpR1PIkA9aXQgZ8sxFAg==", + "dev": true, + "optional": true + }, + "esbuild-linux-ppc64le": { + "version": "0.14.14", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.14.tgz", + "integrity": "sha512-BitW37GxeebKxqYNl4SVuSdnIJAzH830Lr6Mkq3pBHXtzQay0vK+IeOR/Ele1GtNVJ+/f8wYM53tcThkv5SC5w==", + "dev": true, + "optional": true + }, + "esbuild-linux-s390x": { + "version": "0.14.14", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.14.tgz", + "integrity": "sha512-vLj6p76HOZG3wfuTr5MyO3qW5iu8YdhUNxuY+tx846rPo7GcKtYSPMusQjeVEfZlJpSYoR+yrNBBxq+qVF9zrw==", + "dev": true, + "optional": true + }, + "esbuild-netbsd-64": { + "version": "0.14.14", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.14.tgz", + "integrity": "sha512-fn8looXPQhpVqUyCBWUuPjesH+yGIyfbIQrLKG05rr1Kgm3rZD/gaYrd3Wpmf5syVZx70pKZPvdHp8OTA+y7cQ==", + "dev": true, + "optional": true + }, + "esbuild-openbsd-64": { + "version": "0.14.14", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.14.tgz", + "integrity": "sha512-HdAnJ399pPff3SKbd8g+P4o5znseni5u5n5rJ6Z7ouqOdgbOwHe2ofZbMow17WMdNtz1IyOZk2Wo9Ve6/lZ4Rg==", + "dev": true, + "optional": true + }, + "esbuild-sunos-64": { + "version": "0.14.14", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.14.tgz", + "integrity": "sha512-bmDHa99ulsGnYlh/xjBEfxoGuC8CEG5OWvlgD+pF7bKKiVTbtxqVCvOGEZeoDXB+ja6AvHIbPxrEE32J+m5nqQ==", + "dev": true, + "optional": true + }, + "esbuild-wasm": { + "version": "0.14.14", + "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.14.14.tgz", + "integrity": "sha512-qTjK4MWnYtQHCMGg2qDUqeFYXfVvYq5qJkQTIsOV4VZCknoYePVaDTG9ygEB9Ct0kc0DWs7IrS6Ja+GjY62Kzw==", + "dev": true + }, + "esbuild-windows-32": { + "version": "0.14.14", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.14.tgz", + "integrity": "sha512-6tVooQcxJCNenPp5GHZBs/RLu31q4B+BuF4MEoRxswT+Eq2JGF0ZWDRQwNKB8QVIo3t6Svc5wNGez+CwKNQjBg==", + "dev": true, + "optional": true + }, + "esbuild-windows-64": { + "version": "0.14.14", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.14.tgz", + "integrity": "sha512-kl3BdPXh0/RD/dad41dtzj2itMUR4C6nQbXQCyYHHo4zoUoeIXhpCrSl7BAW1nv5EFL8stT1V+TQVXGZca5A2A==", + "dev": true, + "optional": true + }, + "esbuild-windows-arm64": { + "version": "0.14.14", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.14.tgz", + "integrity": "sha512-dCm1wTOm6HIisLanmybvRKvaXZZo4yEVrHh1dY0v582GThXJOzuXGja1HIQgV09RpSHYRL3m4KoUBL00l6SWEg==", + "dev": true, + "optional": true }, "escalade": { "version": "3.1.1", @@ -5979,12 +5374,12 @@ } }, "eslint-scope": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", - "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "dev": true, "requires": { - "esrecurse": "^4.1.0", + "esrecurse": "^4.3.0", "estraverse": "^4.1.1" } }, @@ -6004,9 +5399,9 @@ }, "dependencies": { "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true } } @@ -6034,6 +5429,12 @@ "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" }, + "eventemitter-asyncresource": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/eventemitter-asyncresource/-/eventemitter-asyncresource-1.0.0.tgz", + "integrity": "sha512-39F7TBIV0G7gTelxwbEqnwhp90eqCPON1k0NwNfwhgKn4Co4ybUbj2pECcXT0B3ztRKZ7Pw1JujUUgmQJHcVAQ==", + "dev": true + }, "eventemitter3": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", @@ -6041,48 +5442,34 @@ "dev": true }, "events": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.2.0.tgz", - "integrity": "sha512-/46HWwbfCX2xTawVfkKLGxMifJYQBWMwY1mjywRtb4c9x8l5NP3KoJtnIOiL1hfdRkIuYhETxQlo62IF8tcnlg==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", "dev": true }, "eventsource": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.0.7.tgz", - "integrity": "sha512-4Ln17+vVT0k8aWq+t/bF5arcS3EpT9gYtW66EPacdj/mAFevznsnyoHLPy2BA8gbIQeIHoPsvwmfBftfcG//BQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.1.0.tgz", + "integrity": "sha512-VSJjT5oCNrFvCS6igjzPAt5hBzQ2qPBFIbJ03zLI9SE0mxwZpMw6BfJrbFHm1a141AavMEB8JHmBhWAd66PfCg==", "requires": { "original": "^1.0.0" } }, - "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, - "requires": { - "md5.js": "^1.3.4", - "safe-buffer": "^5.1.1" - } - }, - "exec-sh": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.4.tgz", - "integrity": "sha512-sEFIkc61v75sWeOe72qyrqg2Qg0OuLESziUDk/O/z2qgS15y2gWVFrI6f2Qn/qw/0/NCfCEsmNA4zOjkwEZT1A==", - "dev": true - }, "execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "dev": true, "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.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" } }, "exit": { @@ -6091,108 +5478,30 @@ "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", "dev": true }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "requires": { - "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" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, "expect": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/expect/-/expect-26.6.2.tgz", - "integrity": "sha512-9/hlOBkQl2l/PLHJx6JjoDF6xPKcJEsUlWKb23rKE7KzeDqUZKXKNMW27KIue5JMdBV9HgmoJPcc8HtO85t9IA==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz", + "integrity": "sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==", "dev": true, "requires": { - "@jest/types": "^26.6.2", - "ansi-styles": "^4.0.0", - "jest-get-type": "^26.3.0", - "jest-matcher-utils": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-regex-util": "^26.0.0" - }, - "dependencies": { - "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, - "requires": { - "color-convert": "^2.0.1" - } - }, - "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, - "requires": { - "color-name": "~1.1.4" - } - }, - "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 - } + "@jest/types": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1" } }, "express": { - "version": "4.17.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", - "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.2.tgz", + "integrity": "sha512-oxlxJxcQlYwqPWKVJJtvQiwHgosH/LrLSPA+H4UxpyvSS6jC5aH+5MoHFM+KABgTOt0APue4w66Ha8jCUo9QGg==", "dev": true, "requires": { "accepts": "~1.3.7", "array-flatten": "1.1.1", - "body-parser": "1.19.0", - "content-disposition": "0.5.3", + "body-parser": "1.19.1", + "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.4.0", + "cookie": "0.4.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "~1.1.2", @@ -6206,13 +5515,13 @@ "on-finished": "~2.3.0", "parseurl": "~1.3.3", "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.5", - "qs": "6.7.0", + "proxy-addr": "~2.0.7", + "qs": "6.9.6", "range-parser": "~1.2.1", - "safe-buffer": "5.1.2", - "send": "0.17.1", - "serve-static": "1.14.1", - "setprototypeof": "1.1.1", + "safe-buffer": "5.2.1", + "send": "0.17.2", + "serve-static": "1.14.2", + "setprototypeof": "1.2.0", "statuses": "~1.5.0", "type-is": "~1.6.18", "utils-merge": "1.0.1", @@ -6239,22 +5548,11 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true - } - } - }, - "ext": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz", - "integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==", - "dev": true, - "requires": { - "type": "^2.0.0" - }, - "dependencies": { - "type": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/type/-/type-2.1.0.tgz", - "integrity": "sha512-G9absDWvhAWCV2gmF1zKud3OyC61nZDwWvBL2DApaVFogI07CprggiQAOOjvp2NRjYWFzPyu7vwtDrQFq8jeSA==", + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "dev": true } } @@ -6265,27 +5563,6 @@ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", "dev": true }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "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, - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, "external-editor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", @@ -6297,71 +5574,6 @@ "tmp": "^0.0.33" } }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, - "requires": { - "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" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, "extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", @@ -6375,17 +5587,27 @@ "dev": true }, "fast-glob": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.4.tgz", - "integrity": "sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ==", + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", + "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", "dev": true, "requires": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.0", + "glob-parent": "^5.1.2", "merge2": "^1.3.0", - "micromatch": "^4.0.2", - "picomatch": "^2.2.1" + "micromatch": "^4.0.4" + }, + "dependencies": { + "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, + "requires": { + "is-glob": "^4.0.1" + } + } } }, "fast-json-stable-stringify": { @@ -6407,18 +5629,18 @@ "dev": true }, "fastq": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.9.0.tgz", - "integrity": "sha512-i7FVWL8HhVY+CTkwFxkN2mk3h+787ixS5S63eb78diVRc1MCssarHq3W5cj0av7YDSwmaV928RNag+U1etRQ7w==", + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", "dev": true, "requires": { "reusify": "^1.0.4" } }, "faye-websocket": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz", - "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=", + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", "dev": true, "requires": { "websocket-driver": ">=0.5.1" @@ -6434,20 +5656,13 @@ } }, "fetch-cookie": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/fetch-cookie/-/fetch-cookie-0.7.3.tgz", - "integrity": "sha512-rZPkLnI8x5V+zYAiz8QonAHsTb4BY+iFowFBI1RFn0zrO343AVp9X7/yUj/9wL6Ef/8fLls8b/vGtzUvmyAUGA==", + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/fetch-cookie/-/fetch-cookie-0.11.0.tgz", + "integrity": "sha512-BQm7iZLFhMWFy5CZ/162sAGjBfdNWb7a8LEqqnzsHFhxT/X/SVj/z2t2nu3aJvjlbQkrAlTUApplPRjWyH4mhA==", "requires": { - "es6-denodeify": "^0.1.1", - "tough-cookie": "^2.3.3" + "tough-cookie": "^2.3.3 || ^3.0.1 || ^4.0.0" } }, - "figgy-pudding": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz", - "integrity": "sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==", - "dev": true - }, "figures": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", @@ -6457,41 +5672,11 @@ "escape-string-regexp": "^1.0.5" } }, - "file-loader": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.1.1.tgz", - "integrity": "sha512-Klt8C4BjWSXYQAfhpYYkG4qHNTna4toMHEbWrI5IuVoxbU6uiDKeKAP99R8mmbJi3lvewn/jQBOgU4+NS3tDQw==", - "dev": true, - "requires": { - "loader-utils": "^2.0.0", - "schema-utils": "^3.0.0" - }, - "dependencies": { - "schema-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", - "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.6", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - } - } - } - }, "file-saver": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.5.tgz", "integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==" }, - "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, - "optional": true - }, "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -6534,105 +5719,30 @@ } }, "find-cache-dir": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz", - "integrity": "sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==", + "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, "requires": { "commondir": "^1.0.1", "make-dir": "^3.0.2", "pkg-dir": "^4.1.0" - }, - "dependencies": { - "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, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "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, - "requires": { - "p-locate": "^4.1.0" - } - }, - "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, - "requires": { - "semver": "^6.0.0" - } - }, - "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, - "requires": { - "p-limit": "^2.2.0" - } - }, - "path-exists": { - "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 - }, - "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, - "requires": { - "find-up": "^4.0.0" - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } } }, "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, "requires": { - "locate-path": "^3.0.0" - } - }, - "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, - "requires": { - "inherits": "^2.0.3", - "readable-stream": "^2.3.6" + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" } }, "follow-redirects": { - "version": "1.14.7", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.7.tgz", - "integrity": "sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ==", - "dev": true - }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "version": "1.14.8", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz", + "integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==", "dev": true }, "forever-agent": { @@ -6653,19 +5763,16 @@ } }, "forwarded": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", - "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", "dev": true }, - "fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", - "dev": true, - "requires": { - "map-cache": "^0.2.2" - } + "fraction.js": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.1.3.tgz", + "integrity": "sha512-pUHWWt6vHzZZiQJcM6S/0PXfS+g6FM4BF5rj9wZyreivhQPdsh5PpE25VtSNxq80wHS5RfY51Ii+8Z0Zl/pmzg==", + "dev": true }, "fresh": { "version": "0.5.2", @@ -6673,27 +5780,6 @@ "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", "dev": true }, - "from2": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", - "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.0" - } - }, - "fs-extra": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.2.tgz", - "integrity": "sha1-+RcExT0bRh+JNFKwwwfZmXZHq2s=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - }, "fs-minipass": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", @@ -6703,17 +5789,11 @@ "minipass": "^3.0.0" } }, - "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": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "iferr": "^0.1.5", - "imurmurhash": "^0.1.4", - "readable-stream": "1 || 2" - } + "fs-monkey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.3.tgz", + "integrity": "sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q==", + "dev": true }, "fs.realpath": { "version": "1.0.0", @@ -6721,9 +5801,9 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, "fsevents": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", - "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", "dev": true, "optional": true }, @@ -6733,54 +5813,40 @@ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, "gauge": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", - "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.0.tgz", + "integrity": "sha512-F8sU45yQpjQjxKkm1UOAhf0U/O0aFt//Fl7hsrNVto+patMHjs7dPI9mFOGUKbhrgKm0S3EjW3scMFuQmWSROw==", "dev": true, "requires": { - "aproba": "^1.0.3", + "ansi-regex": "^5.0.1", + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", + "has-unicode": "^2.0.1", "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" }, "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" } }, "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "requires": { - "ansi-regex": "^2.0.0" + "ansi-regex": "^5.0.1" } } } @@ -6813,18 +5879,9 @@ "dev": true }, "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "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 }, "getpass": { @@ -6851,46 +5908,45 @@ } }, "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "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, "requires": { - "is-glob": "^4.0.1" + "is-glob": "^4.0.3" } }, + "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 + }, "globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" }, "globby": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.1.tgz", - "integrity": "sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ==", + "version": "12.2.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-12.2.0.tgz", + "integrity": "sha512-wiSuFQLZ+urS9x2gGPl1H5drc5twabmm4m2gTR27XDFyjUHJUNsS8o/2aKyIF6IoBaR630atdher0XJ5g6OMmA==", "dev": true, "requires": { - "array-union": "^2.1.0", + "array-union": "^3.0.1", "dir-glob": "^3.0.1", - "fast-glob": "^3.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", - "slash": "^3.0.0" + "fast-glob": "^3.2.7", + "ignore": "^5.1.9", + "merge2": "^1.4.1", + "slash": "^4.0.0" } }, "graceful-fs": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", - "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "version": "4.2.9", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", + "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==", "dev": true }, - "growly": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", - "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", - "dev": true, - "optional": true - }, "gzip-size": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", @@ -6946,12 +6002,6 @@ } } }, - "has-bigints": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", - "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", - "dev": true - }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -6963,125 +6013,42 @@ "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", "dev": true }, + "has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, "has-unicode": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", "dev": true }, - "has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "hdr-histogram-js": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hdr-histogram-js/-/hdr-histogram-js-2.0.3.tgz", + "integrity": "sha512-Hkn78wwzWHNCp2uarhzQ2SGFLU3JY8SBDDd3TAABK4fc30wm+MuPOrg5QVFVfkKOQd6Bfz3ukJEI+q9sXEkK1g==", "dev": true, "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" + "@assemblyscript/loader": "^0.10.1", + "base64-js": "^1.2.0", + "pako": "^1.0.3" } }, - "has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "dependencies": { - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "hash-base": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", - "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", - "dev": true, - "requires": { - "inherits": "^2.0.4", - "readable-stream": "^3.6.0", - "safe-buffer": "^5.2.0" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true - } - } - }, - "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, - "requires": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } - }, - "hex-color-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz", - "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==", + "hdr-histogram-percentiles-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hdr-histogram-percentiles-obj/-/hdr-histogram-percentiles-obj-3.0.0.tgz", + "integrity": "sha512-7kIufnBqdsBGcSZLPJwqHT3yhk1QTsSlFsVD3kx5ixH/AlgBs9yM1q6DPhXZ8f8gtdqgh7N7/5btRLpQsS2gHw==", "dev": true }, - "hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", - "dev": true, - "requires": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, "hosted-git-info": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-3.0.8.tgz", - "integrity": "sha512-aXpmwoOhRBrw6X3j0h5RloK4x1OzsxMPyxqIHyNfSe2pypkVTZFpEiRoSipPEPlMrh0HW/XsjkJ5WgnCirpNUw==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -7099,18 +6066,6 @@ "wbuf": "^1.1.0" } }, - "hsl-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/hsl-regex/-/hsl-regex-1.0.0.tgz", - "integrity": "sha1-1JMwx4ntgZ4nakwNJy3/owsY/m4=", - "dev": true - }, - "hsla-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/hsla-regex/-/hsla-regex-1.0.0.tgz", - "integrity": "sha1-wc56MWjIxmFAM6S194d/OyJfnDg=", - "dev": true - }, "html-encoding-sniffer": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", @@ -7121,9 +6076,9 @@ } }, "html-entities": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.3.1.tgz", - "integrity": "sha512-rhE/4Z3hIhzHAUKbW8jVcCyuT5oJCXXqhN/6mXXVCpzTmvJnoH2HL/bt3EZ6p55jbFJBeAe1ZNpL5BugLujxNA==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.2.tgz", + "integrity": "sha512-c3Ab/url5ksaT0WyleslpBEthOzWhrjQbg75y7XUsfSzi3Dgzt0l8w5e7DylRn15MTlMMD58dTfzddNS2kcAjQ==", "dev": true }, "html-escaper": { @@ -7145,26 +6100,24 @@ "dev": true }, "http-errors": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", - "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", + "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", "dev": true, "requires": { "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.1", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" - }, - "dependencies": { - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - } + "toidentifier": "1.0.1" } }, + "http-parser-js": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.5.tgz", + "integrity": "sha512-x+JVEkO2PoM8qqpbPbOL3cqHPwerep7OwzK7Ay+sMQjKzaKCqWvjoXm5tqMP9tXWWTnTzAjIhXg+J99XYuPhPA==", + "dev": true + }, "http-proxy": { "version": "1.18.1", "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", @@ -7199,120 +6152,16 @@ } }, "http-proxy-middleware": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz", - "integrity": "sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.3.tgz", + "integrity": "sha512-1bloEwnrHMnCoO/Gcwbz7eSVvW50KPES01PecpagI+YLNLci4AcuKJrujW4Mc3sBLpFxMSlsLNHS5Nl/lvrTPA==", "dev": true, "requires": { - "http-proxy": "^1.17.0", - "is-glob": "^4.0.0", - "lodash": "^4.17.11", - "micromatch": "^3.1.10" - }, - "dependencies": { - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "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" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "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" - } - }, - "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - } - } + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" } }, "http-signature": { @@ -7326,12 +6175,6 @@ "sshpk": "^1.7.0" } }, - "https-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", - "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", - "dev": true - }, "https-proxy-agent": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", @@ -7354,9 +6197,9 @@ } }, "human-signals": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", - "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", + "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 }, "humanize-ms": { @@ -7378,13 +6221,10 @@ } }, "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, - "requires": { - "postcss": "^7.0.14" - } + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "dev": true }, "ieee754": { "version": "1.2.1", @@ -7392,22 +6232,16 @@ "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", "dev": true }, - "iferr": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", - "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=", - "dev": true - }, "ignore": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", "dev": true }, "ignore-walk": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz", - "integrity": "sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-4.0.1.tgz", + "integrity": "sha512-rzDQLaW4jQbh2YrOFlJdCtX8qgJTehFRYiUB2r1osqTeDzV/3+Jh8fz1oAPzUThf3iku8Ds4IDqawI5d8mUiQw==", "dev": true, "requires": { "minimatch": "^3.0.4" @@ -7426,24 +6260,38 @@ "integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=", "dev": true }, + "immutable": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.0.0.tgz", + "integrity": "sha512-zIE9hX70qew5qTUjSS7wi1iwj/l7+m54KWU247nhM3v806UdGj1yDndXj+IOYxxtW9zyLI+xqFNZjTuDaLUqFw==", + "dev": true + }, "import-fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", - "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "dev": true, "requires": { - "caller-path": "^2.0.0", - "resolve-from": "^3.0.0" + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "dependencies": { + "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==", + "dev": true + } } }, "import-local": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", - "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", "dev": true, "requires": { - "pkg-dir": "^3.0.0", - "resolve-cwd": "^2.0.0" + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" } }, "imurmurhash": { @@ -7458,12 +6306,6 @@ "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", "dev": true }, - "indexes-of": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz", - "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=", - "dev": true - }, "infer-owner": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", @@ -7491,21 +6333,22 @@ "dev": true }, "inquirer": { - "version": "7.3.3", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz", - "integrity": "sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.0.tgz", + "integrity": "sha512-0crLweprevJ02tTuA6ThpoAERAGyVILC4sS74uib58Xf/zSr1/ZWtmm7D5CI+bSQEaA04f0K7idaHpQbSWgiVQ==", "dev": true, "requires": { "ansi-escapes": "^4.2.1", - "chalk": "^4.1.0", + "chalk": "^4.1.1", "cli-cursor": "^3.1.0", "cli-width": "^3.0.0", "external-editor": "^3.0.3", "figures": "^3.0.0", - "lodash": "^4.17.19", + "lodash": "^4.17.21", "mute-stream": "0.0.8", + "ora": "^5.4.1", "run-async": "^2.4.0", - "rxjs": "^6.6.0", + "rxjs": "^7.2.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0", "through": "^2.3.6" @@ -7521,9 +6364,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -7562,67 +6405,26 @@ } } }, - "internal-ip": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-4.3.0.tgz", - "integrity": "sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg==", - "dev": true, - "requires": { - "default-gateway": "^4.2.0", - "ipaddr.js": "^1.9.0" - } - }, "ip": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", "dev": true }, - "ip-regex": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", - "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", - "dev": true - }, "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==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.0.1.tgz", + "integrity": "sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng==", "dev": true }, - "is-absolute-url": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz", - "integrity": "sha1-UFMN+4T8yap9vnhS6Do3uTufKqY=", - "dev": true - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, "is-arguments": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.0.tgz", - "integrity": "sha512-1Ij4lOMPl/xB5kBDn7I+b2ttPMKa8szhEIrXDuXQD/oe3HJLTLhqhgGspwgyGd6MOywBUqVvYicF72lkgDnIHg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", "dev": true, "requires": { - "call-bind": "^1.0.0" + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" } }, "is-arrayish": { @@ -7631,12 +6433,6 @@ "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", "dev": true }, - "is-bigint": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.2.tgz", - "integrity": "sha512-0JV5+SOCQkIdzjBK9buARcV804Ddu7A0Qet6sHi3FimE9ne6m4BGQZfRn+NZiXbBk4F4XmHfDZIipLj9pX8dSA==", - "dev": true - }, "is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -7646,50 +6442,6 @@ "binary-extensions": "^2.0.0" } }, - "is-boolean-object": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.1.tgz", - "integrity": "sha512-bXdQWkECBUIAcCkeH1unwJLIpZYaa5VvuygSyS/c2lf719mTKZDU5UdDRlpd01UjADgmW8RfqaP+mRaVPdr/Ng==", - "dev": true, - "requires": { - "call-bind": "^1.0.2" - } - }, - "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 - }, - "is-callable": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", - "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==", - "dev": true - }, - "is-ci": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", - "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", - "dev": true, - "requires": { - "ci-info": "^2.0.0" - } - }, - "is-color-stop": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-color-stop/-/is-color-stop-1.1.0.tgz", - "integrity": "sha1-z/9HGu5N1cnhWFmPvhKWe1za00U=", - "dev": true, - "requires": { - "css-color-names": "^0.0.4", - "hex-color-regex": "^1.1.0", - "hsl-regex": "^1.0.0", - "hsla-regex": "^1.0.0", - "rgb-regex": "^1.0.1", - "rgba-regex": "^1.0.0" - } - }, "is-core-module": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz", @@ -7698,67 +6450,19 @@ "has": "^1.0.3" } }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, "is-date-object": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", - "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", - "dev": true - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", "dev": true, "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } + "has-tostringtag": "^1.0.0" } }, - "is-directory": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", - "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", - "dev": true - }, "is-docker": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.1.1.tgz", - "integrity": "sha512-ZOoqiXfEwtGknTiuDEy8pN2CfE3TxMHprvNer1mXiqwkOT77Rw3YVrUQ52EqAOU3QAWDQ+bQdx7HJzrv7LS2Hw==", - "dev": true - }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", "dev": true }, "is-extglob": { @@ -7779,9 +6483,9 @@ "dev": true }, "is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, "requires": { "is-extglob": "^2.1.1" @@ -7799,53 +6503,29 @@ "integrity": "sha1-PZh3iZ5qU+/AFgUEzeFfgubwYdU=", "dev": true }, - "is-negative-zero": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", - "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", - "dev": true - }, "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 }, - "is-number-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.5.tgz", - "integrity": "sha512-RU0lI/n95pMoUKu9v1BZP5MBcZuNSVJkMkAG2dJqC4z2GlkGUNeH68SuHuBKBD/XFe+LHZ+f9BKkLET60Niedw==", - "dev": true - }, - "is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", - "dev": true - }, "is-path-cwd": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", "dev": true }, - "is-path-in-cwd": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz", - "integrity": "sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ==", - "dev": true, - "requires": { - "is-path-inside": "^2.1.0" - } - }, "is-path-inside": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-2.1.0.tgz", - "integrity": "sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==", - "dev": true, - "requires": { - "path-is-inside": "^1.0.2" - } + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true + }, + "is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "dev": true }, "is-plain-object": { "version": "2.0.4", @@ -7863,52 +6543,37 @@ "dev": true }, "is-regex": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.3.tgz", - "integrity": "sha512-qSVXFz28HM7y+IWX6vLCsexdlvzT1PJNFSBuaQLQ5o0IEw8UDYW6/2+eCMVyIsbM8CNLX2a/QWmSpyxYEHY7CQ==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", "dev": true, "requires": { "call-bind": "^1.0.2", - "has-symbols": "^1.0.2" + "has-tostringtag": "^1.0.0" } }, - "is-resolvable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", - "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", - "dev": true - }, "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true }, - "is-string": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.6.tgz", - "integrity": "sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w==", - "dev": true - }, - "is-symbol": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", - "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", - "dev": true, - "requires": { - "has-symbols": "^1.0.1" - } - }, "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", "dev": true }, - "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==", + "is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true + }, + "is-what": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", + "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==", "dev": true }, "is-wsl": { @@ -7945,23 +6610,82 @@ "dev": true }, "istanbul-lib-coverage": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", - "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", "dev": true }, "istanbul-lib-instrument": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", - "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.1.0.tgz", + "integrity": "sha512-czwUz525rkOFDJxfKK6mYfIs9zBKILyrZQxjz3ABhjQXhbhFsSbo1HW/BFcsDnfJYJWA6thRR5/TUY2qs5W99Q==", "dev": true, "requires": { - "@babel/core": "^7.7.5", + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-coverage": "^3.2.0", "semver": "^6.3.0" }, "dependencies": { + "@ampproject/remapping": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.1.1.tgz", + "integrity": "sha512-Aolwjd7HSC2PyY0fDj/wA/EimQT4HfEnFYNp5s9CQlrdhyvWTtvZ5YzrUPu6R6/1jKiUlxu8bUhkdSnKHNAHMA==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "^0.3.0" + } + }, + "@babel/code-frame": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", + "dev": true, + "requires": { + "@babel/highlight": "^7.16.7" + } + }, + "@babel/core": { + "version": "7.17.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.2.tgz", + "integrity": "sha512-R3VH5G42VSDolRHyUO4V2cfag8WHcZyxdq5Z/m8Xyb92lW/Erm/6kM+XtRFGf3Mulre3mveni2NHfEUws8wSvw==", + "dev": true, + "requires": { + "@ampproject/remapping": "^2.0.0", + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.17.0", + "@babel/helper-compilation-targets": "^7.16.7", + "@babel/helper-module-transforms": "^7.16.7", + "@babel/helpers": "^7.17.2", + "@babel/parser": "^7.17.0", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.17.0", + "@babel/types": "^7.17.0", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.1.2", + "semver": "^6.3.0" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", + "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", + "dev": true + }, + "@babel/highlight": { + "version": "7.16.10", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz", + "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.16.7", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", @@ -7987,21 +6711,6 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "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, - "requires": { - "semver": "^6.0.0" - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -8014,9 +6723,9 @@ } }, "istanbul-lib-source-maps": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz", - "integrity": "sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", "dev": true, "requires": { "debug": "^4.1.1", @@ -8033,9 +6742,9 @@ } }, "istanbul-reports": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.2.tgz", - "integrity": "sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==", + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.4.tgz", + "integrity": "sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw==", "dev": true, "requires": { "html-escaper": "^2.0.0", @@ -8068,14 +6777,14 @@ "dev": true }, "jest": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest/-/jest-26.6.3.tgz", - "integrity": "sha512-lGS5PXGAzR4RF7V5+XObhqz2KZIDUA1yD0DG6pBVmy10eh0ZIXQImRuzocsI/N2XZ1GrLFwTS27In2i2jlpq1Q==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz", + "integrity": "sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==", "dev": true, "requires": { - "@jest/core": "^26.6.3", + "@jest/core": "^27.5.1", "import-local": "^3.0.2", - "jest-cli": "^26.6.3" + "jest-cli": "^27.5.1" }, "dependencies": { "ansi-styles": { @@ -8087,33 +6796,16 @@ "color-convert": "^2.0.1" } }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, - "cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -8129,101 +6821,32 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "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, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, "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 }, - "import-local": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.2.tgz", - "integrity": "sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA==", - "dev": true, - "requires": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - } - }, "jest-cli": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-26.6.3.tgz", - "integrity": "sha512-GF9noBSa9t08pSyl3CY4frMrqp+aQXFGFkf5hEPbh/pIUFYWMK6ZLTfbmadxJVcJrdRoChlWQsA2VkJcDFK8hg==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.5.1.tgz", + "integrity": "sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw==", "dev": true, "requires": { - "@jest/core": "^26.6.3", - "@jest/test-result": "^26.6.2", - "@jest/types": "^26.6.2", + "@jest/core": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", "chalk": "^4.0.0", "exit": "^0.1.2", - "graceful-fs": "^4.2.4", + "graceful-fs": "^4.2.9", "import-local": "^3.0.2", - "is-ci": "^2.0.0", - "jest-config": "^26.6.3", - "jest-util": "^26.6.2", - "jest-validate": "^26.6.2", + "jest-config": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", "prompts": "^2.0.1", - "yargs": "^15.4.1" + "yargs": "^16.2.0" } }, - "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, - "requires": { - "p-locate": "^4.1.0" - } - }, - "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, - "requires": { - "p-limit": "^2.2.0" - } - }, - "path-exists": { - "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 - }, - "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, - "requires": { - "find-up": "^4.0.0" - } - }, - "resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "requires": { - "resolve-from": "^5.0.0" - } - }, - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -8233,167 +6856,71 @@ "has-flag": "^4.0.0" } }, - "wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true }, "yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", "dev": true, "requires": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" } }, "yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true } } }, "jest-changed-files": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-26.6.2.tgz", - "integrity": "sha512-fDS7szLcY9sCtIip8Fjry9oGf3I2ht/QT21bAHm5Dmf0mD4X3ReNUf17y+bO6fR8WgbIZTlbyG1ak/53cbRzKQ==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.5.1.tgz", + "integrity": "sha512-buBLMiByfWGCoMsLLzGUUSpAmIAGnbR2KJoMN10ziLhOLvP4e0SlypHnAel8iqQXTrcbmfEY9sSqae5sgUsTvw==", "dev": true, "requires": { - "@jest/types": "^26.6.2", - "execa": "^4.0.0", - "throat": "^5.0.0" - }, - "dependencies": { - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "execa": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", - "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.0", - "get-stream": "^5.0.0", - "human-signals": "^1.1.1", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.0", - "onetime": "^5.1.0", - "signal-exit": "^3.0.2", - "strip-final-newline": "^2.0.0" - } - }, - "get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "is-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", - "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", - "dev": true - }, - "npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "requires": { - "path-key": "^3.0.0" - } - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - } + "@jest/types": "^27.5.1", + "execa": "^5.0.0", + "throat": "^6.0.1" } }, - "jest-config": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-26.6.3.tgz", - "integrity": "sha512-t5qdIj/bCj2j7NFVHb2nFB4aUdfucDn3JRKgrZnplb8nieAirAzRSHP8uDEd+qV6ygzg9Pz4YG7UTJf94LPSyg==", + "jest-circus": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.5.1.tgz", + "integrity": "sha512-D95R7x5UtlMA5iBYsOHFFbMD/GVA4R/Kdq15f7xYWUfWHBto9NYRsOvnSauTgdF+ogCpJ4tyKOXhUifxS65gdw==", "dev": true, "requires": { - "@babel/core": "^7.1.0", - "@jest/test-sequencer": "^26.6.3", - "@jest/types": "^26.6.2", - "babel-jest": "^26.6.3", + "@jest/environment": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", "chalk": "^4.0.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.1", - "graceful-fs": "^4.2.4", - "jest-environment-jsdom": "^26.6.2", - "jest-environment-node": "^26.6.2", - "jest-get-type": "^26.3.0", - "jest-jasmine2": "^26.6.3", - "jest-regex-util": "^26.0.0", - "jest-resolve": "^26.6.2", - "jest-util": "^26.6.2", - "jest-validate": "^26.6.2", - "micromatch": "^4.0.2", - "pretty-format": "^26.6.2" + "co": "^4.6.0", + "dedent": "^0.7.0", + "expect": "^27.5.1", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3", + "throat": "^6.0.1" }, "dependencies": { "ansi-styles": { @@ -8406,9 +6933,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -8436,6 +6963,101 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-config": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.5.1.tgz", + "integrity": "sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA==", + "dev": true, + "requires": { + "@babel/core": "^7.8.0", + "@jest/test-sequencer": "^27.5.1", + "@jest/types": "^27.5.1", + "babel-jest": "^27.5.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.1", + "graceful-fs": "^4.2.9", + "jest-circus": "^27.5.1", + "jest-environment-jsdom": "^27.5.1", + "jest-environment-node": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-jasmine2": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-runner": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "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, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "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, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 + }, + "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 + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -8448,15 +7070,15 @@ } }, "jest-diff": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-26.6.2.tgz", - "integrity": "sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", + "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", "dev": true, "requires": { "chalk": "^4.0.0", - "diff-sequences": "^26.6.2", - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" + "diff-sequences": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" }, "dependencies": { "ansi-styles": { @@ -8469,9 +7091,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -8511,25 +7133,25 @@ } }, "jest-docblock": { - "version": "26.0.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-26.0.0.tgz", - "integrity": "sha512-RDZ4Iz3QbtRWycd8bUEPxQsTlYazfYn/h5R65Fc6gOfwozFhoImx+affzky/FFBuqISPTqjXomoIGJVKBWoo0w==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.5.1.tgz", + "integrity": "sha512-rl7hlABeTsRYxKiUfpHrQrG4e2obOiTQWfMEH3PxPjOtdsfLQO4ReWSZaQ7DETm4xu07rl4q/h4zcKXyU0/OzQ==", "dev": true, "requires": { "detect-newline": "^3.0.0" } }, "jest-each": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-26.6.2.tgz", - "integrity": "sha512-Mer/f0KaATbjl8MCJ+0GEpNdqmnVmDYqCTJYTvoo7rqmRiDllmp2AYN+06F93nXcY3ur9ShIjS+CO/uD+BbH4A==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.5.1.tgz", + "integrity": "sha512-1Ff6p+FbhT/bXQnEouYy00bkNSY7OUpfIcmdl8vZ31A1UUaurOLPA8a8BbJOF2RDUElwJhmeaV7LnagI+5UwNQ==", "dev": true, "requires": { - "@jest/types": "^26.6.2", + "@jest/types": "^27.5.1", "chalk": "^4.0.0", - "jest-get-type": "^26.3.0", - "jest-util": "^26.6.2", - "pretty-format": "^26.6.2" + "jest-get-type": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1" }, "dependencies": { "ansi-styles": { @@ -8542,9 +7164,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -8584,114 +7206,84 @@ } }, "jest-environment-jsdom": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-26.6.2.tgz", - "integrity": "sha512-jgPqCruTlt3Kwqg5/WVFyHIOJHsiAvhcp2qiR2QQstuG9yWox5+iHpU3ZrcBxW14T4fe5Z68jAfLRh7joCSP2Q==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.5.1.tgz", + "integrity": "sha512-TFBvkTC1Hnnnrka/fUb56atfDtJ9VMZ94JkjTbggl1PEpwrYtUBKMezB3inLmWqQsXYLcMwNoDQwoBTAvFfsfw==", "dev": true, "requires": { - "@jest/environment": "^26.6.2", - "@jest/fake-timers": "^26.6.2", - "@jest/types": "^26.6.2", + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", "@types/node": "*", - "jest-mock": "^26.6.2", - "jest-util": "^26.6.2", - "jsdom": "^16.4.0" + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1", + "jsdom": "^16.6.0" } }, "jest-environment-node": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-26.6.2.tgz", - "integrity": "sha512-zhtMio3Exty18dy8ee8eJ9kjnRyZC1N4C1Nt/VShN1apyXc8rWGtJ9lI7vqiWcyyXS4BVSEn9lxAM2D+07/Tag==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.5.1.tgz", + "integrity": "sha512-Jt4ZUnxdOsTGwSRAfKEnE6BcwsSPNOijjwifq5sDFSA2kesnXTvNqKHYgM0hDq3549Uf/KzdXNYn4wMZJPlFLw==", "dev": true, "requires": { - "@jest/environment": "^26.6.2", - "@jest/fake-timers": "^26.6.2", - "@jest/types": "^26.6.2", + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", "@types/node": "*", - "jest-mock": "^26.6.2", - "jest-util": "^26.6.2" + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1" } }, "jest-get-type": { - "version": "26.3.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz", - "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", "dev": true }, "jest-haste-map": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-26.6.2.tgz", - "integrity": "sha512-easWIJXIw71B2RdR8kgqpjQrbMRWQBgiBwXYEhtGUTaX+doCjBheluShdDMeR8IMfJiTqH4+zfhtg29apJf/8w==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.5.1.tgz", + "integrity": "sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==", "dev": true, "requires": { - "@jest/types": "^26.6.2", + "@jest/types": "^27.5.1", "@types/graceful-fs": "^4.1.2", "@types/node": "*", "anymatch": "^3.0.3", "fb-watchman": "^2.0.0", - "fsevents": "^2.1.2", - "graceful-fs": "^4.2.4", - "jest-regex-util": "^26.0.0", - "jest-serializer": "^26.6.2", - "jest-util": "^26.6.2", - "jest-worker": "^26.6.2", - "micromatch": "^4.0.2", - "sane": "^4.0.3", + "fsevents": "^2.3.2", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^27.5.1", + "jest-serializer": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "micromatch": "^4.0.4", "walker": "^1.0.7" - }, - "dependencies": { - "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 - }, - "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, - "requires": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^7.0.0" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } } }, "jest-jasmine2": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-26.6.3.tgz", - "integrity": "sha512-kPKUrQtc8aYwBV7CqBg5pu+tmYXlvFlSFYn18ev4gPFtrRzB15N2gW/Roew3187q2w2eHuu0MU9TJz6w0/nPEg==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.5.1.tgz", + "integrity": "sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ==", "dev": true, "requires": { - "@babel/traverse": "^7.1.0", - "@jest/environment": "^26.6.2", - "@jest/source-map": "^26.6.2", - "@jest/test-result": "^26.6.2", - "@jest/types": "^26.6.2", + "@jest/environment": "^27.5.1", + "@jest/source-map": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", "@types/node": "*", "chalk": "^4.0.0", "co": "^4.6.0", - "expect": "^26.6.2", + "expect": "^27.5.1", "is-generator-fn": "^2.0.0", - "jest-each": "^26.6.2", - "jest-matcher-utils": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-runtime": "^26.6.3", - "jest-snapshot": "^26.6.2", - "jest-util": "^26.6.2", - "pretty-format": "^26.6.2", - "throat": "^5.0.0" + "jest-each": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1", + "throat": "^6.0.1" }, "dependencies": { "ansi-styles": { @@ -8704,9 +7296,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -8746,25 +7338,25 @@ } }, "jest-leak-detector": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-26.6.2.tgz", - "integrity": "sha512-i4xlXpsVSMeKvg2cEKdfhh0H39qlJlP5Ex1yQxwF9ubahboQYMgTtz5oML35AVA3B4Eu+YsmwaiKVev9KCvLxg==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.5.1.tgz", + "integrity": "sha512-POXfWAMvfU6WMUXftV4HolnJfnPOGEu10fscNCA76KBpRRhcMN2c8d3iT2pxQS3HLbA+5X4sOUPzYO2NUyIlHQ==", "dev": true, "requires": { - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" } }, "jest-matcher-utils": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz", - "integrity": "sha512-llnc8vQgYcNqDrqRDXWwMr9i7rS5XFiCwvh6DTP7Jqa2mqpcCBBlpCbn+trkG0KNhPu/h8rzyBkriOtBstvWhw==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz", + "integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==", "dev": true, "requires": { "chalk": "^4.0.0", - "jest-diff": "^26.6.2", - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" }, "dependencies": { "ansi-styles": { @@ -8777,9 +7369,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -8819,39 +7411,89 @@ } }, "jest-message-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.6.2.tgz", - "integrity": "sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", + "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", "dev": true, "requires": { - "@babel/code-frame": "^7.0.0", - "@jest/types": "^26.6.2", + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.5.1", "@types/stack-utils": "^2.0.0", "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "micromatch": "^4.0.2", - "pretty-format": "^26.6.2", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^27.5.1", "slash": "^3.0.0", - "stack-utils": "^2.0.2" + "stack-utils": "^2.0.3" }, "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "@babel/code-frame": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", "dev": true, "requires": { - "color-convert": "^2.0.1" + "@babel/highlight": "^7.16.7" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", + "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", + "dev": true + }, + "@babel/highlight": { + "version": "7.16.10", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz", + "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.16.7", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "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, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + } } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" + }, + "dependencies": { + "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, + "requires": { + "color-convert": "^2.0.1" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "color-convert": { @@ -8875,24 +7517,21 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true } } }, "jest-mock": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-26.6.2.tgz", - "integrity": "sha512-YyFjePHHp1LzpzYcmgqkJ0nm0gg/lJx2aZFzFy1S6eUqNjXsOqTK10zNRff2dNfssgokjkG65OlWNcIlgd3zew==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", + "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", "dev": true, "requires": { - "@jest/types": "^26.6.2", + "@jest/types": "^27.5.1", "@types/node": "*" } }, @@ -8903,34 +7542,193 @@ "dev": true }, "jest-preset-angular": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/jest-preset-angular/-/jest-preset-angular-8.3.2.tgz", - "integrity": "sha512-mdETK9E5tkCJPnPzB7NLXDB7CULbUEwcrA7eKU7WdR0u7ZIJqP0pvQxK5Cc70KBsOEaiwJK6LSGJm7aeqjSYYA==", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/jest-preset-angular/-/jest-preset-angular-11.1.0.tgz", + "integrity": "sha512-R4ePMBiQub95ESJlN7TozIpRIyMU7buvIdjm8KXqxZK/w8MYwLOSszVStsoZycDmWq5ifZI1eRvhOCUFktFotw==", "dev": true, "requires": { - "pretty-format": "26.x", - "ts-jest": "26.x" + "bs-logger": "^0.2.6", + "esbuild": "0.14.2", + "esbuild-wasm": "0.14.2", + "jest-environment-jsdom": "^27.0.0", + "pretty-format": "^27.0.0", + "ts-jest": "^27.0.0" + }, + "dependencies": { + "esbuild": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.2.tgz", + "integrity": "sha512-l076A6o/PIgcyM24s0dWmDI/b8RQf41uWoJu9I0M71CtW/YSw5T5NUeXxs5lo2tFQD+O4CW4nBHJXx3OY5NpXg==", + "dev": true, + "optional": true, + "requires": { + "esbuild-android-arm64": "0.14.2", + "esbuild-darwin-64": "0.14.2", + "esbuild-darwin-arm64": "0.14.2", + "esbuild-freebsd-64": "0.14.2", + "esbuild-freebsd-arm64": "0.14.2", + "esbuild-linux-32": "0.14.2", + "esbuild-linux-64": "0.14.2", + "esbuild-linux-arm": "0.14.2", + "esbuild-linux-arm64": "0.14.2", + "esbuild-linux-mips64le": "0.14.2", + "esbuild-linux-ppc64le": "0.14.2", + "esbuild-netbsd-64": "0.14.2", + "esbuild-openbsd-64": "0.14.2", + "esbuild-sunos-64": "0.14.2", + "esbuild-windows-32": "0.14.2", + "esbuild-windows-64": "0.14.2", + "esbuild-windows-arm64": "0.14.2" + } + }, + "esbuild-android-arm64": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.2.tgz", + "integrity": "sha512-hEixaKMN3XXCkoe+0WcexO4CcBVU5DCSUT+7P8JZiWZCbAjSkc9b6Yz2X5DSfQmRCtI/cQRU6TfMYrMQ5NBfdw==", + "dev": true, + "optional": true + }, + "esbuild-darwin-64": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.2.tgz", + "integrity": "sha512-Uq8t0cbJQkxkQdbUfOl2wZqZ/AtLZjvJulR1HHnc96UgyzG9YlCLSDMiqjM+NANEy7/zzvwKJsy3iNC9wwqLJA==", + "dev": true, + "optional": true + }, + "esbuild-darwin-arm64": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.2.tgz", + "integrity": "sha512-619MSa17sr7YCIrUj88KzQu2ESA4jKYtIYfLU/smX6qNgxQt3Y/gzM4s6sgJ4fPQzirvmXgcHv1ZNQAs/Xh48A==", + "dev": true, + "optional": true + }, + "esbuild-freebsd-64": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.2.tgz", + "integrity": "sha512-aP6FE/ZsChZpUV6F3HE3x1Pz0paoYXycJ7oLt06g0G9dhJKknPawXCqQg/WMyD+ldCEZfo7F1kavenPdIT/SGQ==", + "dev": true, + "optional": true + }, + "esbuild-freebsd-arm64": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.2.tgz", + "integrity": "sha512-LSm98WTb1QIhyS83+Po0KTpZNdd2XpVpI9ua5rLWqKWbKeNRFwOsjeiuwBaRNc+O32s9oC2ZMefETxHBV6VNkQ==", + "dev": true, + "optional": true + }, + "esbuild-linux-32": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.2.tgz", + "integrity": "sha512-8VxnNEyeUbiGflTKcuVc5JEPTqXfsx2O6ABwUbfS1Hp26lYPRPC7pKQK5Dxa0MBejGc50jy7YZae3EGQUQ8EkQ==", + "dev": true, + "optional": true + }, + "esbuild-linux-64": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.2.tgz", + "integrity": "sha512-4bzMS2dNxOJoFIiHId4w+tqQzdnsch71JJV1qZnbnErSFWcR9lRgpSqWnTTFtv6XM+MvltRzSXC5wQ7AEBY6Hg==", + "dev": true, + "optional": true + }, + "esbuild-linux-arm": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.2.tgz", + "integrity": "sha512-PaylahvMHhH8YMfJPMKEqi64qA0Su+d4FNfHKvlKes/2dUe4QxgbwXT9oLVgy8iJdcFMrO7By4R8fS8S0p8aVQ==", + "dev": true, + "optional": true + }, + "esbuild-linux-arm64": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.2.tgz", + "integrity": "sha512-RlIVp0RwJrdtasDF1vTFueLYZ8WuFzxoQ1OoRFZOTyJHCGCNgh7xJIC34gd7B7+RT0CzLBB4LcM5n0LS+hIoww==", + "dev": true, + "optional": true + }, + "esbuild-linux-mips64le": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.2.tgz", + "integrity": "sha512-Fdwrq2roFnO5oetIiUQQueZ3+5soCxBSJswg3MvYaXDomj47BN6oAWMZgLrFh1oVrtWrxSDLCJBenYdbm2s+qQ==", + "dev": true, + "optional": true + }, + "esbuild-linux-ppc64le": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.2.tgz", + "integrity": "sha512-vxptskw8JfCDD9QqpRO0XnsM1osuWeRjPaXX1TwdveLogYsbdFtcuiuK/4FxGiNMUr1ojtnCS2rMPbY8puc5NA==", + "dev": true, + "optional": true + }, + "esbuild-netbsd-64": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.2.tgz", + "integrity": "sha512-I8+LzYK5iSNpspS9eCV9sW67Rj8FgMHimGri4mKiGAmN0pNfx+hFX146rYtzGtewuxKtTsPywWteHx+hPRLDsw==", + "dev": true, + "optional": true + }, + "esbuild-openbsd-64": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.2.tgz", + "integrity": "sha512-120HgMe9elidWUvM2E6mMf0csrGwx8sYDqUIJugyMy1oHm+/nT08bTAVXuwYG/rkMIqsEO9AlMxuYnwR6En/3Q==", + "dev": true, + "optional": true + }, + "esbuild-sunos-64": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.2.tgz", + "integrity": "sha512-Q3xcf9Uyfra9UuCFxoLixVvdigo0daZaKJ97TL2KNA4bxRUPK18wwGUk3AxvgDQZpRmg82w9PnkaNYo7a+24ow==", + "dev": true, + "optional": true + }, + "esbuild-wasm": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.14.2.tgz", + "integrity": "sha512-Rs8NjWoo1UdsVjhxT2o6kLCX9Sh65pyd3/h4XeJ3jjQNM6NgL+/CSowuJgvOIjDAXMLXpc6fdGnyZQDil9IUJA==", + "dev": true + }, + "esbuild-windows-32": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.2.tgz", + "integrity": "sha512-TW7O49tPsrq+N1sW8mb3m24j/iDGa4xzAZH4wHWwoIzgtZAYPKC0hpIhufRRG/LA30bdMChO9pjJZ5mtcybtBQ==", + "dev": true, + "optional": true + }, + "esbuild-windows-64": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.2.tgz", + "integrity": "sha512-Rym6ViMNmi1E2QuQMWy0AFAfdY0wGwZD73BnzlsQBX5hZBuy/L+Speh7ucUZ16gwsrMM9v86icZUDrSN/lNBKg==", + "dev": true, + "optional": true + }, + "esbuild-windows-arm64": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.2.tgz", + "integrity": "sha512-ZrLbhr0vX5Em/P1faMnHucjVVWPS+m3tktAtz93WkMZLmbRJevhiW1y4CbulBd2z0MEdXZ6emDa1zFHq5O5bSA==", + "dev": true, + "optional": true + } } }, "jest-regex-util": { - "version": "26.0.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-26.0.0.tgz", - "integrity": "sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", + "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==", "dev": true }, "jest-resolve": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.6.2.tgz", - "integrity": "sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.5.1.tgz", + "integrity": "sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw==", "dev": true, "requires": { - "@jest/types": "^26.6.2", + "@jest/types": "^27.5.1", "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", "jest-pnp-resolver": "^1.2.2", - "jest-util": "^26.6.2", - "read-pkg-up": "^7.0.1", - "resolve": "^1.18.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "resolve": "^1.20.0", + "resolve.exports": "^1.1.0", "slash": "^3.0.0" }, "dependencies": { @@ -8944,9 +7742,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -8974,6 +7772,32 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, + "is-core-module": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", + "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "resolve": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", + "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", + "dev": true, + "requires": { + "is-core-module": "^2.8.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -8986,42 +7810,43 @@ } }, "jest-resolve-dependencies": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-26.6.3.tgz", - "integrity": "sha512-pVwUjJkxbhe4RY8QEWzN3vns2kqyuldKpxlxJlzEYfKSvY6/bMvxoFrYYzUO1Gx28yKWN37qyV7rIoIp2h8fTg==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.5.1.tgz", + "integrity": "sha512-QQOOdY4PE39iawDn5rzbIePNigfe5B9Z91GDD1ae/xNDlu9kaat8QQ5EKnNmVWPV54hUdxCVwwj6YMgR2O7IOg==", "dev": true, "requires": { - "@jest/types": "^26.6.2", - "jest-regex-util": "^26.0.0", - "jest-snapshot": "^26.6.2" + "@jest/types": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-snapshot": "^27.5.1" } }, "jest-runner": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-26.6.3.tgz", - "integrity": "sha512-atgKpRHnaA2OvByG/HpGA4g6CSPS/1LK0jK3gATJAoptC1ojltpmVlYC3TYgdmGp+GLuhzpH30Gvs36szSL2JQ==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.5.1.tgz", + "integrity": "sha512-g4NPsM4mFCOwFKXO4p/H/kWGdJp9V8kURY2lX8Me2drgXqG7rrZAx5kv+5H7wtt/cdFIjhqYx1HrlqWHaOvDaQ==", "dev": true, "requires": { - "@jest/console": "^26.6.2", - "@jest/environment": "^26.6.2", - "@jest/test-result": "^26.6.2", - "@jest/types": "^26.6.2", + "@jest/console": "^27.5.1", + "@jest/environment": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", "@types/node": "*", "chalk": "^4.0.0", - "emittery": "^0.7.1", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "jest-config": "^26.6.3", - "jest-docblock": "^26.0.0", - "jest-haste-map": "^26.6.2", - "jest-leak-detector": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-resolve": "^26.6.2", - "jest-runtime": "^26.6.3", - "jest-util": "^26.6.2", - "jest-worker": "^26.6.2", + "emittery": "^0.8.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^27.5.1", + "jest-environment-jsdom": "^27.5.1", + "jest-environment-node": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-leak-detector": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", "source-map-support": "^0.5.6", - "throat": "^5.0.0" + "throat": "^6.0.1" }, "dependencies": { "ansi-styles": { @@ -9034,9 +7859,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -9064,17 +7889,6 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "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, - "requires": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^7.0.0" - } - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -9087,38 +7901,33 @@ } }, "jest-runtime": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-26.6.3.tgz", - "integrity": "sha512-lrzyR3N8sacTAMeonbqpnSka1dHNux2uk0qqDXVkMv2c/A3wYnvQ4EXuI013Y6+gSKSCxdaczvf4HF0mVXHRdw==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.5.1.tgz", + "integrity": "sha512-o7gxw3Gf+H2IGt8fv0RiyE1+r83FJBRruoA+FXrlHw6xEyBsU8ugA6IPfTdVyA0w8HClpbK+DGJxH59UrNMx8A==", "dev": true, "requires": { - "@jest/console": "^26.6.2", - "@jest/environment": "^26.6.2", - "@jest/fake-timers": "^26.6.2", - "@jest/globals": "^26.6.2", - "@jest/source-map": "^26.6.2", - "@jest/test-result": "^26.6.2", - "@jest/transform": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/yargs": "^15.0.0", + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/globals": "^27.5.1", + "@jest/source-map": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", "chalk": "^4.0.0", - "cjs-module-lexer": "^0.6.0", + "cjs-module-lexer": "^1.0.0", "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", + "execa": "^5.0.0", "glob": "^7.1.3", - "graceful-fs": "^4.2.4", - "jest-config": "^26.6.3", - "jest-haste-map": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-mock": "^26.6.2", - "jest-regex-util": "^26.0.0", - "jest-resolve": "^26.6.2", - "jest-snapshot": "^26.6.2", - "jest-util": "^26.6.2", - "jest-validate": "^26.6.2", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-mock": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", "slash": "^3.0.0", - "strip-bom": "^4.0.0", - "yargs": "^15.4.1" + "strip-bom": "^4.0.0" }, "dependencies": { "ansi-styles": { @@ -9130,33 +7939,16 @@ "color-convert": "^2.0.1" } }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, - "cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -9172,44 +7964,16 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "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, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, "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 }, - "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, - "requires": { - "p-locate": "^4.1.0" - } - }, - "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, - "requires": { - "p-limit": "^2.2.0" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true }, "supports-color": { @@ -9220,80 +7984,46 @@ "requires": { "has-flag": "^4.0.0" } - }, - "wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", - "dev": true, - "requires": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" - } - }, - "yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } } } }, "jest-serializer": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-26.6.2.tgz", - "integrity": "sha512-S5wqyz0DXnNJPd/xfIzZ5Xnp1HrJWBczg8mMfMpN78OJ5eDxXyf+Ygld9wX1DnUWbIbhM1YDY95NjR4CBXkb2g==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.5.1.tgz", + "integrity": "sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w==", "dev": true, "requires": { "@types/node": "*", - "graceful-fs": "^4.2.4" + "graceful-fs": "^4.2.9" } }, "jest-snapshot": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-26.6.2.tgz", - "integrity": "sha512-OLhxz05EzUtsAmOMzuupt1lHYXCNib0ECyuZ/PZOx9TrZcC8vL0x+DUG3TL+GLX3yHG45e6YGjIm0XwDc3q3og==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.5.1.tgz", + "integrity": "sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA==", "dev": true, "requires": { + "@babel/core": "^7.7.2", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/traverse": "^7.7.2", "@babel/types": "^7.0.0", - "@jest/types": "^26.6.2", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", "@types/babel__traverse": "^7.0.4", - "@types/prettier": "^2.0.0", + "@types/prettier": "^2.1.5", + "babel-preset-current-node-syntax": "^1.0.0", "chalk": "^4.0.0", - "expect": "^26.6.2", - "graceful-fs": "^4.2.4", - "jest-diff": "^26.6.2", - "jest-get-type": "^26.3.0", - "jest-haste-map": "^26.6.2", - "jest-matcher-utils": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-resolve": "^26.6.2", + "expect": "^27.5.1", + "graceful-fs": "^4.2.9", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-util": "^27.5.1", "natural-compare": "^1.4.0", - "pretty-format": "^26.6.2", + "pretty-format": "^27.5.1", "semver": "^7.3.2" }, "dependencies": { @@ -9307,9 +8037,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -9337,6 +8067,15 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -9349,17 +8088,17 @@ } }, "jest-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", "dev": true, "requires": { - "@jest/types": "^26.6.2", + "@jest/types": "^27.5.1", "@types/node": "*", "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" }, "dependencies": { "ansi-styles": { @@ -9372,9 +8111,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -9414,17 +8153,17 @@ } }, "jest-validate": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-26.6.2.tgz", - "integrity": "sha512-NEYZ9Aeyj0i5rQqbq+tpIOom0YS1u2MVu6+euBsvpgIme+FOfRmoC4R5p0JiAUpaFvFy24xgrpMknarR/93XjQ==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.5.1.tgz", + "integrity": "sha512-thkNli0LYTmOI1tDB3FI1S1RTp/Bqyd9pTarJwL87OIBFuqEb5Apv5EaApEudYg4g86e3CT6kM0RowkhtEnCBQ==", "dev": true, "requires": { - "@jest/types": "^26.6.2", - "camelcase": "^6.0.0", + "@jest/types": "^27.5.1", + "camelcase": "^6.2.0", "chalk": "^4.0.0", - "jest-get-type": "^26.3.0", + "jest-get-type": "^27.5.1", "leven": "^3.1.0", - "pretty-format": "^26.6.2" + "pretty-format": "^27.5.1" }, "dependencies": { "ansi-styles": { @@ -9436,10 +8175,16 @@ "color-convert": "^2.0.1" } }, + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true + }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -9479,17 +8224,17 @@ } }, "jest-watcher": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-26.6.2.tgz", - "integrity": "sha512-WKJob0P/Em2csiVthsI68p6aGKTIcsfjH9Gsx1f0A3Italz43e3ho0geSAVsmj09RWOELP1AZ/DXyJgOgDKxXQ==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.5.1.tgz", + "integrity": "sha512-z676SuD6Z8o8qbmEGhoEUFOM1+jfEiL3DXHK/xgEiG2EyNYfFG60jluWcupY6dATjfEsKQuibReS1djInQnoVw==", "dev": true, "requires": { - "@jest/test-result": "^26.6.2", - "@jest/types": "^26.6.2", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", - "jest-util": "^26.6.2", + "jest-util": "^27.5.1", "string-length": "^4.0.1" }, "dependencies": { @@ -9503,9 +8248,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -9545,14 +8290,14 @@ } }, "jest-worker": { - "version": "26.5.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.5.0.tgz", - "integrity": "sha512-kTw66Dn4ZX7WpjZ7T/SUDgRhapFRKWmisVAF0Rv4Fu8SLFD7eLbqpLvbxVqYhSgaWa7I+bW7pHnbyfNsH6stug==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", "dev": true, "requires": { "@types/node": "*", "merge-stream": "^2.0.0", - "supports-color": "^7.0.0" + "supports-color": "^8.0.0" }, "dependencies": { "has-flag": { @@ -9562,9 +8307,9 @@ "dev": true }, "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, "requires": { "has-flag": "^4.0.0" @@ -9628,12 +8373,6 @@ "xml-name-validator": "^3.0.0" }, "dependencies": { - "acorn": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.6.0.tgz", - "integrity": "sha512-U1riIR+lBSNi3IbxtaHOIKdH8sLFv3NYfNv8sg7ZsNhcfl4HF2++BfqqrNAxoCLQW1iiylOj76ecnaUxz+z9yw==", - "dev": true - }, "agent-base": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", @@ -9664,6 +8403,12 @@ "debug": "4" } }, + "parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true + }, "tough-cookie": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", @@ -9675,11 +8420,31 @@ "universalify": "^0.1.2" } }, - "ws": { - "version": "7.5.6", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.6.tgz", - "integrity": "sha512-6GLgCqo2cy2A2rjCNFlxQS6ZljG/coZfZXclldI8FB/1G3CCI36Zd8xy2HrFVACi8tfk5XrgLQEk+P0Tnz9UcA==", + "tr46": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", + "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", + "dev": true, + "requires": { + "punycode": "^2.1.1" + } + }, + "webidl-conversions": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", + "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", "dev": true + }, + "whatwg-url": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", + "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", + "dev": true, + "requires": { + "lodash": "^4.7.0", + "tr46": "^2.1.0", + "webidl-conversions": "^6.1.0" + } } } }, @@ -9718,16 +8483,10 @@ "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", "dev": true }, - "json3": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.3.tgz", - "integrity": "sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA==", - "dev": true - }, "json5": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", - "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", + "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", "requires": { "minimist": "^1.2.5" } @@ -9738,15 +8497,6 @@ "integrity": "sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA==", "dev": true }, - "jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.6" - } - }, "jsonparse": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", @@ -9778,16 +8528,16 @@ } }, "karma-coverage": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/karma-coverage/-/karma-coverage-2.0.3.tgz", - "integrity": "sha512-atDvLQqvPcLxhED0cmXYdsPMCQuh6Asa9FMZW1bhNqlVEhJoB9qyZ2BY1gu7D/rr5GLGb5QzYO4siQskxaWP/g==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/karma-coverage/-/karma-coverage-2.2.0.tgz", + "integrity": "sha512-gPVdoZBNDZ08UCzdMHHhEImKrw1+PAOQOIiffv1YsvxFhBjqvo/SVXNk4tqn1SYqX0BJZT6S/59zgxiBe+9OuA==", "dev": true, "requires": { - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^4.0.1", + "istanbul-lib-coverage": "^3.2.0", + "istanbul-lib-instrument": "^5.1.0", "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.1", + "istanbul-reports": "^3.0.5", "minimatch": "^3.0.4" } }, @@ -9800,12 +8550,6 @@ "source-map-support": "^0.5.5" } }, - "killable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz", - "integrity": "sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg==", - "dev": true - }, "kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -9819,9 +8563,9 @@ "dev": true }, "klona": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.4.tgz", - "integrity": "sha512-ZRbnvdg/NxqzC7L9Uyqzf4psi1OM4Cuc+sJAkQPjO6XkQIJTNbfK2Rsmbw8fx1p2mkZdp2FZYo2+LwXYY/uwIA==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.5.tgz", + "integrity": "sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ==", "dev": true }, "lazysizes": { @@ -9830,58 +8574,50 @@ "integrity": "sha512-22UzWP+Vedi/sMeOr8O7FWimRVtiNJV2HCa+V8+peZOw6QbswN9k58VUhd7i6iK5bw5QkYrF01LJbeJe0PV8jg==" }, "less": { - "version": "3.12.2", - "resolved": "https://registry.npmjs.org/less/-/less-3.12.2.tgz", - "integrity": "sha512-+1V2PCMFkL+OIj2/HrtrvZw0BC0sYLMICJfbQjuj/K8CEnlrFX6R5cKKgzzttsZDHyxQNL1jqMREjKN3ja/E3Q==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/less/-/less-4.1.2.tgz", + "integrity": "sha512-EoQp/Et7OSOVu0aJknJOtlXZsnr8XE8KwuzTHOLeVSEx8pVWUICc8Q0VYRHgzyjX78nMEyC/oztWFbgyhtNfDA==", "dev": true, "requires": { + "copy-anything": "^2.0.1", "errno": "^0.1.1", "graceful-fs": "^4.1.2", "image-size": "~0.5.0", "make-dir": "^2.1.0", "mime": "^1.4.1", - "native-request": "^1.0.5", + "needle": "^2.5.2", + "parse-node-version": "^1.0.1", "source-map": "~0.6.0", - "tslib": "^1.10.0" + "tslib": "^2.3.0" }, "dependencies": { + "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, + "optional": true, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + } + }, "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, "optional": true - }, - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true } } }, "less-loader": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-7.0.2.tgz", - "integrity": "sha512-7MKlgjnkCf63E3Lv6w2FvAEgLMx3d/tNBExITcanAq7ys5U8VPWT3F6xcRjYmdNfkoQ9udoVFb1r2azSiTnD6w==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-10.2.0.tgz", + "integrity": "sha512-AV5KHWvCezW27GT90WATaDnfXBv99llDbtaj4bshq6DvAihMdNjaPDcUMa6EXKLRF+P2opFenJp89BXg91XLYg==", "dev": true, "requires": { - "klona": "^2.0.4", - "loader-utils": "^2.0.0", - "schema-utils": "^3.0.0" - }, - "dependencies": { - "schema-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", - "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.6", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - } - } + "klona": "^2.0.4" } }, "leven": { @@ -9901,31 +8637,12 @@ } }, "license-webpack-plugin": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-2.3.1.tgz", - "integrity": "sha512-yhqTmlYIEpZWA122lf6E0G8+rkn0AzoQ1OpzUKKs/lXUqG1plmGnwmkuuPlfggzJR5y6DLOdot/Tv00CC51CeQ==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-4.0.1.tgz", + "integrity": "sha512-SQum9mg3BgnY5BK+2KYl4W7pk9b26Q8tW2lTsO6tidD0/Ds9ksdXvp3ip2s9LqDjj5gtBMyWRfOPZptWj4PfCg==", "dev": true, "requires": { - "@types/webpack-sources": "^0.1.5", - "webpack-sources": "^1.2.0" - }, - "dependencies": { - "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 - }, - "webpack-sources": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", - "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", - "dev": true, - "requires": { - "source-list-map": "^2.0.0", - "source-map": "~0.6.1" - } - } + "webpack-sources": "^3.0.0" } }, "lie": { @@ -9938,36 +8655,30 @@ } }, "lines-and-columns": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", - "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", "dev": true }, "loader-runner": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz", - "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz", + "integrity": "sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw==", "dev": true }, "loader-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", - "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", - "dev": true, - "requires": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - } + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.0.tgz", + "integrity": "sha512-HVl9ZqccQihZ7JM85dco1MvO9G+ONvxoGa9rkhzFsneGLKSUg1gJf9bWzhRhcvm2qChhWpebQhP44qxjKIUCaQ==", + "dev": true }, "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" + "p-locate": "^4.1.0" } }, "lodash": { @@ -9975,25 +8686,26 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, + "lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", + "dev": true + }, "lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", "dev": true }, - "lodash.uniq": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", - "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=", - "dev": true - }, "log-symbols": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz", - "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", "dev": true, "requires": { - "chalk": "^4.0.0" + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" }, "dependencies": { "ansi-styles": { @@ -10006,9 +8718,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -10047,12 +8759,6 @@ } } }, - "loglevel": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.7.1.tgz", - "integrity": "sha512-Hesni4s5UkWkwCGJMQGAh71PaLUmKFM60dHvq0zi/vDhhrzuk+4GgNbTXJ12YYQJn6ZKBDNIjYcuQGKudvqrIw==", - "dev": true - }, "lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -10072,19 +8778,18 @@ } }, "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==", + "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, "requires": { - "pify": "^4.0.1", - "semver": "^5.6.0" + "semver": "^6.0.0" }, "dependencies": { "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true } } @@ -10096,13 +8801,13 @@ "dev": true }, "make-fetch-happen": { - "version": "8.0.14", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-8.0.14.tgz", - "integrity": "sha512-EsS89h6l4vbfJEtBZnENTOFk8mCRpY5ru36Xe5bcX1KYIli2mkSHqoFsp5O1wMDvTJJzxe/4THpCTtygjeeGWQ==", + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", + "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==", "dev": true, "requires": { "agentkeepalive": "^4.1.3", - "cacache": "^15.0.5", + "cacache": "^15.2.0", "http-cache-semantics": "^4.1.0", "http-proxy-agent": "^4.0.1", "https-proxy-agent": "^5.0.0", @@ -10113,8 +8818,9 @@ "minipass-fetch": "^1.3.2", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.2", "promise-retry": "^2.0.1", - "socks-proxy-agent": "^5.0.0", + "socks-proxy-agent": "^6.0.0", "ssri": "^8.0.0" }, "dependencies": { @@ -10136,74 +8842,31 @@ "agent-base": "6", "debug": "4" } - }, - "promise-retry": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", - "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", - "dev": true, - "requires": { - "err-code": "^2.0.2", - "retry": "^0.12.0" - } } } }, "makeerror": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", - "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=", + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", "dev": true, "requires": { - "tmpl": "1.0.x" + "tmpl": "1.0.5" } }, - "map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", - "dev": true - }, - "map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", - "dev": true, - "requires": { - "object-visit": "^1.0.0" - } - }, - "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, - "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "mdn-data": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", - "integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==", - "dev": true - }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", "dev": true }, - "memory-fs": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", - "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", + "memfs": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.1.tgz", + "integrity": "sha512-1c9VPVvW5P7I85c35zAdEr1TD5+F11IToIHIlrVIcflfnzPkJa0ZoYEoEdYDP8KgPFoSZ/opDrUsAoZWym3mtw==", "dev": true, "requires": { - "errno": "^0.1.3", - "readable-stream": "^2.0.1" + "fs-monkey": "1.0.3" } }, "merge-descriptors": { @@ -10212,23 +8875,6 @@ "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", "dev": true }, - "merge-source-map": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz", - "integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==", - "dev": true, - "requires": { - "source-map": "^0.6.1" - }, - "dependencies": { - "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 - } - } - }, "merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -10248,31 +8894,13 @@ "dev": true }, "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", "dev": true, "requires": { "braces": "^3.0.1", - "picomatch": "^2.0.5" - } - }, - "miller-rabin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", - "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", - "dev": true, - "requires": { - "bn.js": "^4.0.0", - "brorand": "^1.0.1" - }, - "dependencies": { - "bn.js": { - "version": "4.11.9", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", - "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", - "dev": true - } + "picomatch": "^2.2.3" } }, "mime": { @@ -10303,41 +8931,51 @@ "dev": true }, "mini-css-extract-plugin": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-1.2.1.tgz", - "integrity": "sha512-G3yw7/TQaPfkuiR73MDcyiqhyP8SnbmLhUbpC76H+wtQxA6wfKhMCQOCb6wnPK0dQbjORAeOILQqEesg4/wF7A==", + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.5.3.tgz", + "integrity": "sha512-YseMB8cs8U/KCaAGQoqYmfUuhhGW0a9p9XvWXrxVOkE3/IiISTLw4ALNt7JR5B2eYauFM+PQGSbXMDmVbR7Tfw==", "dev": true, "requires": { - "loader-utils": "^2.0.0", - "schema-utils": "^3.0.0", - "webpack-sources": "^1.1.0" + "schema-utils": "^4.0.0" }, "dependencies": { - "schema-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", - "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==", + "ajv": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.10.0.tgz", + "integrity": "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==", "dev": true, "requires": { - "@types/json-schema": "^7.0.6", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" } }, - "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 - }, - "webpack-sources": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", - "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", + "ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", "dev": true, "requires": { - "source-list-map": "^2.0.0", - "source-map": "~0.6.1" + "fast-deep-equal": "^3.1.3" + } + }, + "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 + }, + "schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" } } } @@ -10348,12 +8986,6 @@ "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", "dev": true }, - "minimalistic-crypto-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", - "dev": true - }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", @@ -10363,14 +8995,14 @@ } }, "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" }, "minipass": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz", - "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==", + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.6.tgz", + "integrity": "sha512-rty5kpw9/z8SX9dmxblFA6edItUmwJgMeYDZRrwlIVN27i8gysGbznJwUggw2V/FVqFSDdWy040ZPS811DYAqQ==", "dev": true, "requires": { "yallist": "^4.0.0" @@ -10386,9 +9018,9 @@ } }, "minipass-fetch": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.3.3.tgz", - "integrity": "sha512-akCrLDWfbdAWkMLBxJEeWTdNsjML+dt5YgOI4gJ53vuO0vrmYQkUPxa6j6V65s9CcePIr2SSWqjT2EcrNseryQ==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz", + "integrity": "sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==", "dev": true, "requires": { "encoding": "^0.1.12", @@ -10444,45 +9076,6 @@ "yallist": "^4.0.0" } }, - "mississippi": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", - "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", - "dev": true, - "requires": { - "concat-stream": "^1.5.0", - "duplexify": "^3.4.2", - "end-of-stream": "^1.1.0", - "flush-write-stream": "^1.0.0", - "from2": "^2.1.0", - "parallel-transform": "^1.1.0", - "pump": "^3.0.0", - "pumpify": "^1.3.3", - "stream-each": "^1.1.0", - "through2": "^2.0.0" - } - }, - "mixin-deep": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", - "dev": true, - "requires": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "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, - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, "mkdirp": { "version": "0.5.5", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", @@ -10492,30 +9085,10 @@ "minimist": "^1.2.5" } }, - "move-concurrently": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", - "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", - "dev": true, - "requires": { - "aproba": "^1.1.1", - "copy-concurrently": "^1.0.0", - "fs-write-stream-atomic": "^1.0.8", - "mkdirp": "^0.5.1", - "rimraf": "^2.5.4", - "run-queue": "^1.0.3" - }, - "dependencies": { - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - } - } + "mrmime": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.0.tgz", + "integrity": "sha512-a70zx7zFfVO7XpnQ2IX1Myh9yY4UYvfld/dikWRnsXxbyvMcfz+u6UfgNAtH+k2QqtJuzVpv6eLTx1G2+WKZbQ==" }, "ms": { "version": "2.1.2", @@ -10544,38 +9117,11 @@ "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", "dev": true }, - "nan": { - "version": "2.14.2", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz", - "integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==", - "dev": true, - "optional": true - }, - "nanomatch": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - } - }, - "native-request": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/native-request/-/native-request-1.0.8.tgz", - "integrity": "sha512-vU2JojJVelUGp6jRcLwToPoWGxSx23z/0iX+I77J3Ht17rf2INGjrhOoQnjVo60nQd8wVsgzKkPfRXBiVdD2ag==", - "dev": true, - "optional": true + "nanoid": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.2.0.tgz", + "integrity": "sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==", + "dev": true }, "natural-compare": { "version": "1.4.0", @@ -10583,10 +9129,34 @@ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, + "needle": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/needle/-/needle-2.9.1.tgz", + "integrity": "sha512-6R9fqJ5Zcmf+uYaFgdIHmLwNldn5HbK8L5ybn7Uz+ylX/rnOsSp1AHcvQSrCaFN+qNM1wpymHqD7mVasEOlHGQ==", + "dev": true, + "optional": true, + "requires": { + "debug": "^3.2.6", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "optional": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, "negotiator": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", "dev": true }, "neo-async": { @@ -10595,12 +9165,6 @@ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "dev": true }, - "next-tick": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", - "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", - "dev": true - }, "ng-circle-progress": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/ng-circle-progress/-/ng-circle-progress-1.6.0.tgz", @@ -10609,35 +9173,47 @@ "tslib": "^2.0.0" } }, - "ng-lazyload-image": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/ng-lazyload-image/-/ng-lazyload-image-9.1.0.tgz", - "integrity": "sha512-ZdfCXMTaehfzxcSRRThpz9YZbEA+8LPA086Od6JiylrGj0yNM7Aq830A1x6NE/M8o2VuVq93emH9m8T6SFBHlA==", + "ngx-color-picker": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/ngx-color-picker/-/ngx-color-picker-12.0.0.tgz", + "integrity": "sha512-SY5KoZka/uq2MNhUAKfJXQjjS2TFvKDJHbsCxfnjKjS/VHx8VVeTJpnt5wuuewzRzLxfOm5y2Fw8/HTPEPtRkA==", "requires": { - "tslib": "^2.0.0" + "tslib": "^2.3.0" } }, "ngx-file-drop": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/ngx-file-drop/-/ngx-file-drop-11.1.0.tgz", - "integrity": "sha512-jRqnI58jh9xVYmbYY315TIaSfpzOXRwj8JQOjNALwi/r1a9SVkxp3C069tXo5Kkxi/elsMePN0Be4EmgLf4EVw==", + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/ngx-file-drop/-/ngx-file-drop-13.0.0.tgz", + "integrity": "sha512-1OF9ln2ZesfNxWEBXMpkkFpUuggejpZtNlGFuyaVAmXyYO4NlCHsOWrgfWB7d8SliHgePD/7s0e60IQs/zqr9g==", "requires": { "tslib": "^2.0.0" } }, "ngx-toastr": { - "version": "13.2.1", - "resolved": "https://registry.npmjs.org/ngx-toastr/-/ngx-toastr-13.2.1.tgz", - "integrity": "sha512-UAzp7/xWK9IXA2LsOmhpaaIGCqscvJokoQpBNpAMrjEkDeSlFf8PWQAuQY795KW0mJb3qF9UG/s23nsXfMYKmg==", + "version": "14.2.1", + "resolved": "https://registry.npmjs.org/ngx-toastr/-/ngx-toastr-14.2.1.tgz", + "integrity": "sha512-1Kq//y8tTgglUYKHIziZwpo4R7fe4/neidcxfbAXzXtcViSjT4Z21Vgqn/inoBlwoc7E9qXQDuZoJr2lanCgGA==", "requires": { - "tslib": "^2.0.0" + "tslib": "^2.3.0" } }, - "nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true + "nice-napi": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz", + "integrity": "sha512-px/KnJAJZf5RuBGcfD+Sp2pAKq0ytz8j+1NehvgIGFkvtvFrDM3T8E4x/JJODXK9WZow8RRGrbA9QQ3hs+pDhA==", + "dev": true, + "optional": true, + "requires": { + "node-addon-api": "^3.0.0", + "node-gyp-build": "^4.2.2" + } + }, + "node-addon-api": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", + "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", + "dev": true, + "optional": true }, "node-fetch": { "version": "2.6.7", @@ -10645,153 +9221,60 @@ "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", "requires": { "whatwg-url": "^5.0.0" - }, - "dependencies": { - "tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" - }, - "webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" - }, - "whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", - "requires": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - } } }, "node-forge": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", - "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.0.tgz", + "integrity": "sha512-08ARB91bUi6zNKzVmaj3QO7cr397uiDT2nJ63cHjyNtCTWIgvS47j3eT0WfzUwS9+6Z5YshRaoasFkXCKrIYbA==", "dev": true }, "node-gyp": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-7.1.2.tgz", - "integrity": "sha512-CbpcIo7C3eMu3dL1c3d0xw449fHIGALIJsRP4DDPHpyiW8vcriNY7ubh9TE4zEKfSxscY7PjeFnshE7h75ynjQ==", + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz", + "integrity": "sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==", "dev": true, "requires": { "env-paths": "^2.2.0", "glob": "^7.1.4", - "graceful-fs": "^4.2.3", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^9.1.0", "nopt": "^5.0.0", - "npmlog": "^4.1.2", - "request": "^2.88.2", + "npmlog": "^6.0.0", "rimraf": "^3.0.2", - "semver": "^7.3.2", - "tar": "^6.0.2", + "semver": "^7.3.5", + "tar": "^6.1.2", "which": "^2.0.2" }, "dependencies": { - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", "dev": true, "requires": { - "isexe": "^2.0.0" + "lru-cache": "^6.0.0" } } } }, + "node-gyp-build": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.3.0.tgz", + "integrity": "sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q==", + "dev": true, + "optional": true + }, "node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", "dev": true }, - "node-libs-browser": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz", - "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==", - "dev": true, - "requires": { - "assert": "^1.1.1", - "browserify-zlib": "^0.2.0", - "buffer": "^4.3.0", - "console-browserify": "^1.1.0", - "constants-browserify": "^1.0.0", - "crypto-browserify": "^3.11.0", - "domain-browser": "^1.1.1", - "events": "^3.0.0", - "https-browserify": "^1.0.0", - "os-browserify": "^0.3.0", - "path-browserify": "0.0.1", - "process": "^0.11.10", - "punycode": "^1.2.4", - "querystring-es3": "^0.2.0", - "readable-stream": "^2.3.3", - "stream-browserify": "^2.0.1", - "stream-http": "^2.7.2", - "string_decoder": "^1.0.0", - "timers-browserify": "^2.0.4", - "tty-browserify": "0.0.0", - "url": "^0.11.0", - "util": "^0.11.0", - "vm-browserify": "^1.0.1" - }, - "dependencies": { - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", - "dev": true - } - } - }, - "node-modules-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", - "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=", - "dev": true - }, - "node-notifier": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-8.0.1.tgz", - "integrity": "sha512-BvEXF+UmsnAfYfoapKM9nGxnP+Wn7P91YfXmrKnfcYCx6VBeoN5Ez5Ogck6I8Bi5k4RlpqRYaw75pAwzX9OphA==", - "dev": true, - "optional": true, - "requires": { - "growly": "^1.3.0", - "is-wsl": "^2.2.0", - "semver": "^7.3.2", - "shellwords": "^0.1.1", - "uuid": "^8.3.0", - "which": "^2.0.2" - }, - "dependencies": { - "uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true, - "optional": true - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "optional": true, - "requires": { - "isexe": "^2.0.0" - } - } - } - }, "node-releases": { - "version": "1.1.72", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.72.tgz", - "integrity": "sha512-LLUo+PpH3dU6XizX3iVoubUNheF/owjXCZZ5yACDxNnPtgFuludV1ZL3ayK1kVep42Rmm0+R9/Y60NQbZ2bifw==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.2.tgz", + "integrity": "sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg==", "dev": true }, "nopt": { @@ -10803,32 +9286,6 @@ "abbrev": "1" } }, - "normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "requires": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - }, - "dependencies": { - "hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, "normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -10841,12 +9298,6 @@ "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=", "dev": true }, - "normalize-url": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz", - "integrity": "sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==", - "dev": true - }, "npm-bundled": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.2.tgz", @@ -10863,6 +9314,17 @@ "dev": true, "requires": { "semver": "^7.1.1" + }, + "dependencies": { + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } } }, "npm-normalize-package-bin": { @@ -10872,97 +9334,174 @@ "dev": true }, "npm-package-arg": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-8.1.0.tgz", - "integrity": "sha512-/ep6QDxBkm9HvOhOg0heitSd7JHA1U7y1qhhlRlteYYAi9Pdb/ZV7FW5aHpkrpM8+P+4p/jjR8zCyKPBMBjSig==", + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-8.1.5.tgz", + "integrity": "sha512-LhgZrg0n0VgvzVdSm1oiZworPbTxYHUJCgtsJW8mGvlDpxTM1vSJc3m5QZeUkhAHIzbz3VCHd/R4osi1L1Tg/Q==", "dev": true, "requires": { - "hosted-git-info": "^3.0.6", - "semver": "^7.0.0", + "hosted-git-info": "^4.0.1", + "semver": "^7.3.4", "validate-npm-package-name": "^3.0.0" + }, + "dependencies": { + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } } }, "npm-packlist": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-2.1.5.tgz", - "integrity": "sha512-KCfK3Vi2F+PH1klYauoQzg81GQ8/GGjQRKYY6tRnpQUPKTs/1gBZSRWtTEd7jGdSn1LZL7gpAmJT+BcS55k2XQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-3.0.0.tgz", + "integrity": "sha512-L/cbzmutAwII5glUcf2DBRNY/d0TFd4e/FnaZigJV6JD85RHZXJFGwCndjMWiiViiWSsWt3tiOLpI3ByTnIdFQ==", "dev": true, "requires": { "glob": "^7.1.6", - "ignore-walk": "^3.0.3", + "ignore-walk": "^4.0.1", "npm-bundled": "^1.1.1", "npm-normalize-package-bin": "^1.0.1" } }, "npm-pick-manifest": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-6.1.0.tgz", - "integrity": "sha512-ygs4k6f54ZxJXrzT0x34NybRlLeZ4+6nECAIbr2i0foTnijtS1TJiyzpqtuUAJOps/hO0tNDr8fRV5g+BtRlTw==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-6.1.1.tgz", + "integrity": "sha512-dBsdBtORT84S8V8UTad1WlUyKIY9iMsAmqxHbLdeEeBNMLQDlDWWra3wYUx9EBEIiG/YwAy0XyNHDd2goAsfuA==", "dev": true, "requires": { "npm-install-checks": "^4.0.0", - "npm-package-arg": "^8.0.0", - "semver": "^7.0.0" + "npm-normalize-package-bin": "^1.0.1", + "npm-package-arg": "^8.1.2", + "semver": "^7.3.4" + }, + "dependencies": { + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } } }, "npm-registry-fetch": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-9.0.0.tgz", - "integrity": "sha512-PuFYYtnQ8IyVl6ib9d3PepeehcUeHN9IO5N/iCRhyg9tStQcqGQBRVHmfmMWPDERU3KwZoHFvbJ4FPXPspvzbA==", + "version": "12.0.2", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-12.0.2.tgz", + "integrity": "sha512-Df5QT3RaJnXYuOwtXBXS9BWs+tHH2olvkCLh6jcR/b/u3DvPMlp3J0TvvYwplPKxHMOwfg287PYih9QqaVFoKA==", "dev": true, "requires": { - "@npmcli/ci-detect": "^1.0.0", - "lru-cache": "^6.0.0", - "make-fetch-happen": "^8.0.9", - "minipass": "^3.1.3", - "minipass-fetch": "^1.3.0", + "make-fetch-happen": "^10.0.1", + "minipass": "^3.1.6", + "minipass-fetch": "^1.4.1", "minipass-json-stream": "^1.0.1", - "minizlib": "^2.0.0", - "npm-package-arg": "^8.0.0" + "minizlib": "^2.1.2", + "npm-package-arg": "^8.1.5" + }, + "dependencies": { + "@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "dev": true + }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "requires": { + "debug": "4" + } + }, + "http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dev": true, + "requires": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + } + }, + "https-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "dev": true, + "requires": { + "agent-base": "6", + "debug": "4" + } + }, + "lru-cache": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.3.1.tgz", + "integrity": "sha512-nX1x4qUrKqwbIAhv4s9et4FIUVzNOpeY07bsjGUy8gwJrXH/wScImSQqXErmo/b2jZY2r0mohbLA9zVj7u1cNw==", + "dev": true + }, + "make-fetch-happen": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.0.2.tgz", + "integrity": "sha512-JSFLK53NJP22FL/eAGOyKsWbc2G3v+toPMD7Dq9PJKQCvK0i3t8hGkKxe+3YZzwYa+c0kxRHu7uxH3fvO+rsaA==", + "dev": true, + "requires": { + "agentkeepalive": "^4.2.0", + "cacache": "^15.3.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.3.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^1.4.1", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^6.1.1", + "ssri": "^8.0.1" + } + } } }, "npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "dev": true, "requires": { - "path-key": "^2.0.0" + "path-key": "^3.0.0" } }, "npmlog": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.1.tgz", + "integrity": "sha512-BTHDvY6nrRHuRfyjt1MAufLxYdVXZfd099H4+i1f0lPywNQyI4foeNXJRObB/uy+TYqUW0vAD9gbdSOXPst7Eg==", "dev": true, "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" + "are-we-there-yet": "^3.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^4.0.0", + "set-blocking": "^2.0.0" } }, "nth-check": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", - "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz", + "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==", "dev": true, "requires": { - "boolbase": "~1.0.0" + "boolbase": "^1.0.0" } }, - "num2fraction": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", - "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=", - "dev": true - }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true - }, "nwsapi": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", @@ -10981,50 +9520,13 @@ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "dev": true }, - "object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", - "dev": true, - "requires": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "object-inspect": { - "version": "1.10.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.3.tgz", - "integrity": "sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw==", - "dev": true - }, "object-is": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.4.tgz", - "integrity": "sha512-1ZvAZ4wlF7IyPVOcE1Omikt7UpaFlOQq0HlSti+ZvDH3UiD2brwGMwDbyV43jao2bKJ+4+WdPJHSd7kgzKYVqg==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", + "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", "dev": true, "requires": { - "call-bind": "^1.0.0", + "call-bind": "^1.0.2", "define-properties": "^1.1.3" } }, @@ -11034,15 +9536,6 @@ "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", "dev": true }, - "object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", - "dev": true, - "requires": { - "isobject": "^3.0.0" - } - }, "object.assign": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", @@ -11055,37 +9548,6 @@ "object-keys": "^1.1.1" } }, - "object.getownpropertydescriptors": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.2.tgz", - "integrity": "sha512-WtxeKSzfBjlzL+F9b7M7hewDzMwy+C8NRssHd1YrNlzHzIDrXcXiNOMrezdAEM4UXixgV+vvnyBeN7Rygl2ttQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.2" - } - }, - "object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, - "object.values": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.4.tgz", - "integrity": "sha512-TnGo7j4XSnKQoK3MfvkzqKCi0nVe/D9I9IjwTNYdb/fxYHpjrluHVOgw0AF6jrRFGMPHdfuidR09tIDiIvnaSg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.2" - } - }, "obuf": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", @@ -11125,13 +9587,14 @@ } }, "open": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/open/-/open-7.3.0.tgz", - "integrity": "sha512-mgLwQIx2F/ye9SmbrUkurZCnkoXyXyu9EbHtJZrICjVAJfyMArdHp3KkixGdZx1ZHFPNIwl0DDM1dFFqXbTLZw==", + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz", + "integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==", "dev": true, "requires": { - "is-docker": "^2.0.0", - "is-wsl": "^2.1.1" + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" } }, "opener": { @@ -11139,23 +9602,6 @@ "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==" }, - "opn": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz", - "integrity": "sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==", - "dev": true, - "requires": { - "is-wsl": "^1.1.0" - }, - "dependencies": { - "is-wsl": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", - "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", - "dev": true - } - } - }, "optionator": { "version": "0.8.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", @@ -11171,17 +9617,18 @@ } }, "ora": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.1.0.tgz", - "integrity": "sha512-9tXIMPvjZ7hPTbk8DFq1f7Kow/HU/pQYB60JbNq+QnGwcyhWVZaQ4hM9zQDEsPxw/muLpgiHSaumUZxCAmod/w==", + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", "dev": true, "requires": { + "bl": "^4.1.0", "chalk": "^4.1.0", "cli-cursor": "^3.1.0", - "cli-spinners": "^2.4.0", + "cli-spinners": "^2.5.0", "is-interactive": "^1.0.0", - "log-symbols": "^4.0.0", - "mute-stream": "0.0.8", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", "strip-ansi": "^6.0.0", "wcwidth": "^1.0.1" }, @@ -11196,9 +9643,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -11245,30 +9692,12 @@ "url-parse": "^1.4.3" } }, - "os-browserify": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", - "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", - "dev": true - }, "os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true }, - "p-each-series": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-2.2.0.tgz", - "integrity": "sha512-ycIL2+1V32th+8scbpTvyHNaHe02z0sjgh91XXjAk+ZeXoPN4Z46DVUnzdso0aX4KckKw0FNNFHdjZ2UsZvxiA==", - "dev": true - }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true - }, "p-limit": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", @@ -11279,12 +9708,12 @@ } }, "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==", + "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, "requires": { - "p-limit": "^2.0.0" + "p-limit": "^2.2.0" } }, "p-map": { @@ -11297,12 +9726,13 @@ } }, "p-retry": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-3.0.1.tgz", - "integrity": "sha512-XE6G4+YTTkT2a0UWb2kjZe8xNwf8bIbnqpc/IS/idOBVhyves0mK5OJgeocjx7q5pvX/6m23xuzVPYT1uGM73w==", + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.1.tgz", + "integrity": "sha512-e2xXGNhZOZ0lfgR9kL34iGlU8N/KO0xZnQxVEwdeOvpqNDQfdnxIYizvWtK8RglUa3bGqI8g0R/BdfzLMxRkiA==", "dev": true, "requires": { - "retry": "^0.12.0" + "@types/retry": "^0.12.0", + "retry": "^0.13.1" } }, "p-try": { @@ -11312,15 +9742,15 @@ "dev": true }, "pacote": { - "version": "11.2.4", - "resolved": "https://registry.npmjs.org/pacote/-/pacote-11.2.4.tgz", - "integrity": "sha512-GfTeVQGJ6WyBQbQD4t3ocHbyOmTQLmWjkCKSZPmKiGFKYKNUaM5U2gbLzUW8WG1XmS9yQFnsTFA0k3o1+q4klQ==", + "version": "12.0.3", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-12.0.3.tgz", + "integrity": "sha512-CdYEl03JDrRO3x18uHjBYA9TyoW8gy+ThVcypcDkxPtKlw76e4ejhYB6i9lJ+/cebbjpqPW/CijjqxwDTts8Ow==", "dev": true, "requires": { - "@npmcli/git": "^2.0.1", - "@npmcli/installed-package-contents": "^1.0.5", + "@npmcli/git": "^2.1.0", + "@npmcli/installed-package-contents": "^1.0.6", "@npmcli/promise-spawn": "^1.2.0", - "@npmcli/run-script": "^1.3.0", + "@npmcli/run-script": "^2.0.0", "cacache": "^15.0.5", "chownr": "^2.0.0", "fs-minipass": "^2.1.0", @@ -11328,13 +9758,13 @@ "minipass": "^3.1.3", "mkdirp": "^1.0.3", "npm-package-arg": "^8.0.1", - "npm-packlist": "^2.1.4", + "npm-packlist": "^3.0.0", "npm-pick-manifest": "^6.0.0", - "npm-registry-fetch": "^9.0.0", - "promise-retry": "^1.1.1", - "read-package-json-fast": "^1.1.3", + "npm-registry-fetch": "^12.0.0", + "promise-retry": "^2.0.1", + "read-package-json-fast": "^2.0.1", "rimraf": "^3.0.2", - "ssri": "^8.0.0", + "ssri": "^8.0.1", "tar": "^6.1.0" }, "dependencies": { @@ -11352,17 +9782,6 @@ "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", "dev": true }, - "parallel-transform": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz", - "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==", - "dev": true, - "requires": { - "cyclist": "^1.0.1", - "inherits": "^2.0.3", - "readable-stream": "^2.1.5" - } - }, "parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -11370,45 +9789,32 @@ "dev": true, "requires": { "callsites": "^3.0.0" - }, - "dependencies": { - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - } - } - }, - "parse-asn1": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", - "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", - "dev": true, - "requires": { - "asn1.js": "^5.2.0", - "browserify-aes": "^1.0.0", - "evp_bytestokey": "^1.0.0", - "pbkdf2": "^3.0.3", - "safe-buffer": "^5.1.1" } }, "parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, "requires": { + "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" } }, - "parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "parse-node-version": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", + "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", "dev": true }, + "parse5": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", + "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==", + "optional": true + }, "parse5-html-rewriting-stream": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/parse5-html-rewriting-stream/-/parse5-html-rewriting-stream-6.0.1.tgz", @@ -11417,6 +9823,31 @@ "requires": { "parse5": "^6.0.1", "parse5-sax-parser": "^6.0.1" + }, + "dependencies": { + "parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true + } + } + }, + "parse5-htmlparser2-tree-adapter": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", + "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", + "dev": true, + "requires": { + "parse5": "^6.0.1" + }, + "dependencies": { + "parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true + } } }, "parse5-sax-parser": { @@ -11426,6 +9857,14 @@ "dev": true, "requires": { "parse5": "^6.0.1" + }, + "dependencies": { + "parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true + } } }, "parseurl": { @@ -11434,28 +9873,10 @@ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", "dev": true }, - "pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", - "dev": true - }, - "path-browserify": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", - "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==", - "dev": true - }, - "path-dirname": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", - "dev": true - }, "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "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 }, "path-is-absolute": { @@ -11470,9 +9891,9 @@ "dev": true }, "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true }, "path-parse": { @@ -11492,19 +9913,6 @@ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true }, - "pbkdf2": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.1.tgz", - "integrity": "sha512-4Ejy1OPxi9f2tt1rRV7Go7zmfDQ+ZectEQz3VGUQhgq62HtIRPDyG/JtnwIxs6x3uNMwo2V7q1fMvKjb+Tnpqg==", - "dev": true, - "requires": { - "create-hash": "^1.1.2", - "create-hmac": "^1.1.4", - "ripemd160": "^2.0.1", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", @@ -11512,22 +9920,23 @@ "dev": true }, "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", "dev": true }, "picomatch": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", - "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true }, "pify": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true + "dev": true, + "optional": true }, "pinkie": { "version": "2.0.4", @@ -11545,30 +9954,30 @@ } }, "pirates": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz", - "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", + "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", + "dev": true + }, + "piscina": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/piscina/-/piscina-3.2.0.tgz", + "integrity": "sha512-yn/jMdHRw+q2ZJhFhyqsmANcbF6V2QwmD84c6xRau+QpQOmtrBCoRGdvTfeuFDYXB5W2m6MfLkjkvQa9lUSmIA==", "dev": true, "requires": { - "node-modules-regexp": "^1.0.0" + "eventemitter-asyncresource": "^1.0.0", + "hdr-histogram-js": "^2.0.1", + "hdr-histogram-percentiles-obj": "^3.0.0", + "nice-napi": "^1.0.2" } }, "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==", + "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, "requires": { - "find-up": "^3.0.0" - } - }, - "pnp-webpack-plugin": { - "version": "1.6.4", - "resolved": "https://registry.npmjs.org/pnp-webpack-plugin/-/pnp-webpack-plugin-1.6.4.tgz", - "integrity": "sha512-7Wjy+9E3WwLOEL30D+m8TSTF7qJJUJLONBnwQp0518siuMxUQUbgZwssaFX+QKlZkjHZcw/IpZCt/H0srrntSg==", - "dev": true, - "requires": { - "ts-pnp": "^1.1.6" + "find-up": "^4.0.0" } }, "portfinder": { @@ -11593,636 +10002,347 @@ } } }, - "posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "postcss": { + "version": "8.4.5", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.5.tgz", + "integrity": "sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg==", + "dev": true, + "requires": { + "nanoid": "^3.1.30", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.1" + } + }, + "postcss-attribute-case-insensitive": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-5.0.0.tgz", + "integrity": "sha512-b4g9eagFGq9T5SWX4+USfVyjIb3liPnjhHHRMP7FMB2kFVpYyfEscV0wP3eaXhKlcHKUut8lt5BGoeylWA/dBQ==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.2" + } + }, + "postcss-color-functional-notation": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/postcss-color-functional-notation/-/postcss-color-functional-notation-4.2.2.tgz", + "integrity": "sha512-DXVtwUhIk4f49KK5EGuEdgx4Gnyj6+t2jBSEmxvpIK9QI40tWrpS2Pua8Q7iIZWBrki2QOaeUdEaLPPa91K0RQ==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-color-hex-alpha": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/postcss-color-hex-alpha/-/postcss-color-hex-alpha-8.0.3.tgz", + "integrity": "sha512-fESawWJCrBV035DcbKRPAVmy21LpoyiXdPTuHUfWJ14ZRjY7Y7PA6P4g8z6LQGYhU1WAxkTxjIjurXzoe68Glw==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-color-rebeccapurple": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-7.0.2.tgz", + "integrity": "sha512-SFc3MaocHaQ6k3oZaFwH8io6MdypkUtEy/eXzXEB1vEQlO3S3oDc/FSZA8AsS04Z25RirQhlDlHLh3dn7XewWw==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-custom-media": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-8.0.0.tgz", + "integrity": "sha512-FvO2GzMUaTN0t1fBULDeIvxr5IvbDXcIatt6pnJghc736nqNgsGao5NT+5+WVLAQiTt6Cb3YUms0jiPaXhL//g==", "dev": true }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", + "postcss-custom-properties": { + "version": "12.1.4", + "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-12.1.4.tgz", + "integrity": "sha512-i6AytuTCoDLJkWN/MtAIGriJz3j7UX6bV7Z5t+KgFz+dwZS15/mlTJY1S0kRizlk6ba0V8u8hN50Fz5Nm7tdZw==", "dev": true, "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "dependencies": { - "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 - } + "postcss-value-parser": "^4.2.0" } }, - "postcss-calc": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-7.0.5.tgz", - "integrity": "sha512-1tKHutbGtLtEZF6PT4JSihCHfIVldU72mZ8SdZHIYriIZ9fh9k9aWSppaT8rHsyI3dX+KSR+W+Ix9BMY3AODrg==", + "postcss-custom-selectors": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-custom-selectors/-/postcss-custom-selectors-6.0.0.tgz", + "integrity": "sha512-/1iyBhz/W8jUepjGyu7V1OPcGbc636snN1yXEQCinb6Bwt7KxsiU7/bLQlp8GwAXzCh7cobBU5odNn/2zQWR8Q==", "dev": true, "requires": { - "postcss": "^7.0.27", - "postcss-selector-parser": "^6.0.2", - "postcss-value-parser": "^4.0.2" + "postcss-selector-parser": "^6.0.4" } }, - "postcss-colormin": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-4.0.3.tgz", - "integrity": "sha512-WyQFAdDZpExQh32j0U0feWisZ0dmOtPl44qYmJKkq9xFWY3p+4qnRzCHeNrkeRhwPHz9bQ3mo0/yVkaply0MNw==", + "postcss-dir-pseudo-class": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-6.0.4.tgz", + "integrity": "sha512-I8epwGy5ftdzNWEYok9VjW9whC4xnelAtbajGv4adql4FIF09rnrxnA9Y8xSHN47y7gqFIv10C5+ImsLeJpKBw==", "dev": true, "requires": { - "browserslist": "^4.0.0", - "color": "^3.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - } + "postcss-selector-parser": "^6.0.9" } }, - "postcss-convert-values": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-4.0.1.tgz", - "integrity": "sha512-Kisdo1y77KUC0Jmn0OXU/COOJbzM8cImvw1ZFsBgBgMgb1iL23Zs/LXRe3r+EZqM3vGYKdQ2YJVQ5VkJI+zEJQ==", + "postcss-double-position-gradients": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/postcss-double-position-gradients/-/postcss-double-position-gradients-3.0.5.tgz", + "integrity": "sha512-XiZzvdxLOWZwtt/1GgHJYGoD9scog/DD/yI5dcvPrXNdNDEv7T53/6tL7ikl+EM3jcerII5/XIQzd1UHOdTi2w==", "dev": true, "requires": { - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - } + "postcss-value-parser": "^4.2.0" } }, - "postcss-discard-comments": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-4.0.2.tgz", - "integrity": "sha512-RJutN259iuRf3IW7GZyLM5Sw4GLTOH8FmsXBnv8Ab/Tc2k4SR4qbV4DNbyyY4+Sjo362SyDmW2DQ7lBSChrpkg==", + "postcss-env-function": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/postcss-env-function/-/postcss-env-function-4.0.5.tgz", + "integrity": "sha512-gPUJc71ji9XKyl0WSzAalBeEA/89kU+XpffpPxSaaaZ1c48OL36r1Ep5R6+9XAPkIiDlSvVAwP4io12q/vTcvA==", "dev": true, "requires": { - "postcss": "^7.0.0" + "postcss-value-parser": "^4.2.0" } }, - "postcss-discard-duplicates": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-4.0.2.tgz", - "integrity": "sha512-ZNQfR1gPNAiXZhgENFfEglF93pciw0WxMkJeVmw8eF+JZBbMD7jp6C67GqJAXVZP2BWbOztKfbsdmMp/k8c6oQ==", + "postcss-focus-visible": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/postcss-focus-visible/-/postcss-focus-visible-6.0.4.tgz", + "integrity": "sha512-QcKuUU/dgNsstIK6HELFRT5Y3lbrMLEOwG+A4s5cA+fx3A3y/JTq3X9LaOj3OC3ALH0XqyrgQIgey/MIZ8Wczw==", "dev": true, "requires": { - "postcss": "^7.0.0" + "postcss-selector-parser": "^6.0.9" } }, - "postcss-discard-empty": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-4.0.1.tgz", - "integrity": "sha512-B9miTzbznhDjTfjvipfHoqbWKwd0Mj+/fL5s1QOz06wufguil+Xheo4XpOnc4NqKYBCNqqEzgPv2aPBIJLox0w==", + "postcss-focus-within": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/postcss-focus-within/-/postcss-focus-within-5.0.4.tgz", + "integrity": "sha512-vvjDN++C0mu8jz4af5d52CB184ogg/sSxAFS+oUJQq2SuCe7T5U2iIsVJtsCp2d6R4j0jr5+q3rPkBVZkXD9fQ==", "dev": true, "requires": { - "postcss": "^7.0.0" + "postcss-selector-parser": "^6.0.9" } }, - "postcss-discard-overridden": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-4.0.1.tgz", - "integrity": "sha512-IYY2bEDD7g1XM1IDEsUT4//iEYCxAmP5oDSFMVU/JVvT7gh+l4fmjciLqGgwjdWpQIdb0Che2VX00QObS5+cTg==", + "postcss-font-variant": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-font-variant/-/postcss-font-variant-5.0.0.tgz", + "integrity": "sha512-1fmkBaCALD72CK2a9i468mA/+tr9/1cBxRRMXOUaZqO43oWPR5imcyPjXwuv7PXbCid4ndlP5zWhidQVVa3hmA==", + "dev": true + }, + "postcss-gap-properties": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/postcss-gap-properties/-/postcss-gap-properties-3.0.3.tgz", + "integrity": "sha512-rPPZRLPmEKgLk/KlXMqRaNkYTUpE7YC+bOIQFN5xcu1Vp11Y4faIXv6/Jpft6FMnl6YRxZqDZG0qQOW80stzxQ==", + "dev": true + }, + "postcss-image-set-function": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/postcss-image-set-function/-/postcss-image-set-function-4.0.6.tgz", + "integrity": "sha512-KfdC6vg53GC+vPd2+HYzsZ6obmPqOk6HY09kttU19+Gj1nC3S3XBVEXDHxkhxTohgZqzbUb94bKXvKDnYWBm/A==", "dev": true, "requires": { - "postcss": "^7.0.0" + "postcss-value-parser": "^4.2.0" } }, "postcss-import": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-12.0.1.tgz", - "integrity": "sha512-3Gti33dmCjyKBgimqGxL3vcV8w9+bsHwO5UrBawp796+jdardbcFl4RP5w/76BwNL7aGzpKstIfF9I+kdE8pTw==", + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-14.0.2.tgz", + "integrity": "sha512-BJ2pVK4KhUyMcqjuKs9RijV5tatNzNa73e/32aBVE/ejYPe37iH+6vAu9WvqUkB5OAYgLHzbSvzHnorybJCm9g==", "dev": true, "requires": { - "postcss": "^7.0.1", - "postcss-value-parser": "^3.2.3", + "postcss-value-parser": "^4.0.0", "read-cache": "^1.0.0", "resolve": "^1.1.7" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - } + } + }, + "postcss-initial": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-initial/-/postcss-initial-4.0.1.tgz", + "integrity": "sha512-0ueD7rPqX8Pn1xJIjay0AZeIuDoF+V+VvMt/uOnn+4ezUKhZM/NokDeP6DwMNyIoYByuN/94IQnt5FEkaN59xQ==", + "dev": true + }, + "postcss-lab-function": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-4.0.4.tgz", + "integrity": "sha512-TAEW8X/ahMYV33mvLFQARtBPAy1VVJsiR9VVx3Pcbu+zlqQj0EIyJ/Ie1/EwxwIt530CWtEDzzTXBDzfdb+qIQ==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" } }, "postcss-loader": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-4.0.4.tgz", - "integrity": "sha512-pntA9zIR14drQo84yGTjQJg1m7T0DkXR4vXYHBngiRZdJtEeCrojL6lOpqUanMzG375lIJbT4Yug85zC/AJWGw==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-6.2.1.tgz", + "integrity": "sha512-WbbYpmAaKcux/P66bZ40bpWsBucjx/TTgVVzRZ9yUO8yQfVBlameJ0ZGVaPfH64hNSBh63a+ICP5nqOpBA0w+Q==", "dev": true, "requires": { "cosmiconfig": "^7.0.0", - "klona": "^2.0.4", - "loader-utils": "^2.0.0", - "schema-utils": "^3.0.0", - "semver": "^7.3.2" + "klona": "^2.0.5", + "semver": "^7.3.5" }, "dependencies": { - "cosmiconfig": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.0.tgz", - "integrity": "sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA==", + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", "dev": true, "requires": { - "@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" - } - }, - "import-fresh": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.2.tgz", - "integrity": "sha512-cTPNrlvJT6twpYy+YmKUKrTSjWFs3bjYjAhCwm+z4EOCubZxAuO+hHpRN64TqjEaYSHs7tJAE0w1CKMGmsG/lw==", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "parse-json": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.1.0.tgz", - "integrity": "sha512-+mi/lmVVNKFNVyLXV31ERiy2CY5E1/F6QtJFEzoChPRwwngMNXRDQ9GJ5WdE2Z2P4AujsOi0/+2qHID68KwfIQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - } - }, - "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==", - "dev": true - }, - "schema-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", - "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.6", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" + "lru-cache": "^6.0.0" } } } }, - "postcss-merge-longhand": { - "version": "4.0.11", - "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-4.0.11.tgz", - "integrity": "sha512-alx/zmoeXvJjp7L4mxEMjh8lxVlDFX1gqWHzaaQewwMZiVhLo42TEClKaeHbRf6J7j82ZOdTJ808RtN0ZOZwvw==", - "dev": true, - "requires": { - "css-color-names": "0.0.4", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0", - "stylehacks": "^4.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - } - } + "postcss-logical": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-5.0.4.tgz", + "integrity": "sha512-RHXxplCeLh9VjinvMrZONq7im4wjWGlRJAqmAVLXyZaXwfDWP73/oq4NdIp+OZwhQUMj0zjqDfM5Fj7qby+B4g==", + "dev": true }, - "postcss-merge-rules": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-4.0.3.tgz", - "integrity": "sha512-U7e3r1SbvYzO0Jr3UT/zKBVgYYyhAz0aitvGIYOYK5CPmkNih+WDSsS5tvPrJ8YMQYlEMvsZIiqmn7HdFUaeEQ==", - "dev": true, - "requires": { - "browserslist": "^4.0.0", - "caniuse-api": "^3.0.0", - "cssnano-util-same-parent": "^4.0.0", - "postcss": "^7.0.0", - "postcss-selector-parser": "^3.0.0", - "vendors": "^1.0.0" - }, - "dependencies": { - "postcss-selector-parser": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", - "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", - "dev": true, - "requires": { - "dot-prop": "^5.2.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - } - } - } - }, - "postcss-minify-font-values": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-4.0.2.tgz", - "integrity": "sha512-j85oO6OnRU9zPf04+PZv1LYIYOprWm6IA6zkXkrJXyRveDEuQggG6tvoy8ir8ZwjLxLuGfNkCZEQG7zan+Hbtg==", - "dev": true, - "requires": { - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - } - } - }, - "postcss-minify-gradients": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-4.0.2.tgz", - "integrity": "sha512-qKPfwlONdcf/AndP1U8SJ/uzIJtowHlMaSioKzebAXSG4iJthlWC9iSWznQcX4f66gIWX44RSA841HTHj3wK+Q==", - "dev": true, - "requires": { - "cssnano-util-get-arguments": "^4.0.0", - "is-color-stop": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - } - } - }, - "postcss-minify-params": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-4.0.2.tgz", - "integrity": "sha512-G7eWyzEx0xL4/wiBBJxJOz48zAKV2WG3iZOqVhPet/9geefm/Px5uo1fzlHu+DOjT+m0Mmiz3jkQzVHe6wxAWg==", - "dev": true, - "requires": { - "alphanum-sort": "^1.0.0", - "browserslist": "^4.0.0", - "cssnano-util-get-arguments": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0", - "uniqs": "^2.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - } - } - }, - "postcss-minify-selectors": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-4.0.2.tgz", - "integrity": "sha512-D5S1iViljXBj9kflQo4YutWnJmwm8VvIsU1GeXJGiG9j8CIg9zs4voPMdQDUmIxetUOh60VilsNzCiAFTOqu3g==", - "dev": true, - "requires": { - "alphanum-sort": "^1.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-selector-parser": "^3.0.0" - }, - "dependencies": { - "postcss-selector-parser": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", - "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", - "dev": true, - "requires": { - "dot-prop": "^5.2.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - } - } - } + "postcss-media-minmax": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-media-minmax/-/postcss-media-minmax-5.0.0.tgz", + "integrity": "sha512-yDUvFf9QdFZTuCUg0g0uNSHVlJ5X1lSzDZjPSFaiCWvjgsvu8vEVxtahPrLMinIDEEGnx6cBe6iqdx5YWz08wQ==", + "dev": true }, "postcss-modules-extract-imports": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz", - "integrity": "sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ==", - "dev": true, - "requires": { - "postcss": "^7.0.5" - } + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", + "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", + "dev": true }, "postcss-modules-local-by-default": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-3.0.3.tgz", - "integrity": "sha512-e3xDq+LotiGesympRlKNgaJ0PCzoUIdpH0dj47iWAui/kyTgh3CiAr1qP54uodmJhl6p9rN6BoNcdEDVJx9RDw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz", + "integrity": "sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==", "dev": true, "requires": { - "icss-utils": "^4.1.1", - "postcss": "^7.0.32", + "icss-utils": "^5.0.0", "postcss-selector-parser": "^6.0.2", "postcss-value-parser": "^4.1.0" } }, "postcss-modules-scope": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-2.2.0.tgz", - "integrity": "sha512-YyEgsTMRpNd+HmyC7H/mh3y+MeFWevy7V1evVhJWewmMbjDHIbZbOXICC2y+m1xI1UVfIT1HMW/O04Hxyu9oXQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", + "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", "dev": true, "requires": { - "postcss": "^7.0.6", - "postcss-selector-parser": "^6.0.0" + "postcss-selector-parser": "^6.0.4" } }, "postcss-modules-values": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-3.0.0.tgz", - "integrity": "sha512-1//E5jCBrZ9DmRX+zCtmQtRSV6PV42Ix7Bzj9GbwJceduuf7IqP8MgeTXuRDHOWj2m0VzZD5+roFWDuU8RQjcg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", "dev": true, "requires": { - "icss-utils": "^4.0.0", - "postcss": "^7.0.6" + "icss-utils": "^5.0.0" } }, - "postcss-normalize-charset": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-4.0.1.tgz", - "integrity": "sha512-gMXCrrlWh6G27U0hF3vNvR3w8I1s2wOBILvA87iNXaPvSNo5uZAMYsZG7XjCUf1eVxuPfyL4TJ7++SGZLc9A3g==", + "postcss-nesting": { + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-10.1.2.tgz", + "integrity": "sha512-dJGmgmsvpzKoVMtDMQQG/T6FSqs6kDtUDirIfl4KnjMCiY9/ETX8jdKyCd20swSRAbUYkaBKV20pxkzxoOXLqQ==", "dev": true, "requires": { - "postcss": "^7.0.0" + "postcss-selector-parser": "^6.0.8" } }, - "postcss-normalize-display-values": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.2.tgz", - "integrity": "sha512-3F2jcsaMW7+VtRMAqf/3m4cPFhPD3EFRgNs18u+k3lTJJlVe7d0YPO+bnwqo2xg8YiRpDXJI2u8A0wqJxMsQuQ==", + "postcss-overflow-shorthand": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/postcss-overflow-shorthand/-/postcss-overflow-shorthand-3.0.3.tgz", + "integrity": "sha512-CxZwoWup9KXzQeeIxtgOciQ00tDtnylYIlJBBODqkgS/PU2jISuWOL/mYLHmZb9ZhZiCaNKsCRiLp22dZUtNsg==", + "dev": true + }, + "postcss-page-break": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/postcss-page-break/-/postcss-page-break-3.0.4.tgz", + "integrity": "sha512-1JGu8oCjVXLa9q9rFTo4MbeeA5FMe00/9C7lN4va606Rdb+HkxXtXsmEDrIraQ11fGz/WvKWa8gMuCKkrXpTsQ==", + "dev": true + }, + "postcss-place": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/postcss-place/-/postcss-place-7.0.4.tgz", + "integrity": "sha512-MrgKeiiu5OC/TETQO45kV3npRjOFxEHthsqGtkh3I1rPbZSbXGD/lZVi9j13cYh+NA8PIAPyk6sGjT9QbRyvSg==", "dev": true, "requires": { - "cssnano-util-get-match": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - } + "postcss-value-parser": "^4.2.0" } }, - "postcss-normalize-positions": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-4.0.2.tgz", - "integrity": "sha512-Dlf3/9AxpxE+NF1fJxYDeggi5WwV35MXGFnnoccP/9qDtFrTArZ0D0R+iKcg5WsUd8nUYMIl8yXDCtcrT8JrdA==", + "postcss-preset-env": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-7.2.3.tgz", + "integrity": "sha512-Ok0DhLfwrcNGrBn8sNdy1uZqWRk/9FId0GiQ39W4ILop5GHtjJs8bu1MY9isPwHInpVEPWjb4CEcEaSbBLpfwA==", "dev": true, "requires": { - "cssnano-util-get-arguments": "^4.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - } + "autoprefixer": "^10.4.2", + "browserslist": "^4.19.1", + "caniuse-lite": "^1.0.30001299", + "css-blank-pseudo": "^3.0.2", + "css-has-pseudo": "^3.0.3", + "css-prefers-color-scheme": "^6.0.2", + "cssdb": "^5.0.0", + "postcss-attribute-case-insensitive": "^5.0.0", + "postcss-color-functional-notation": "^4.2.1", + "postcss-color-hex-alpha": "^8.0.2", + "postcss-color-rebeccapurple": "^7.0.2", + "postcss-custom-media": "^8.0.0", + "postcss-custom-properties": "^12.1.2", + "postcss-custom-selectors": "^6.0.0", + "postcss-dir-pseudo-class": "^6.0.3", + "postcss-double-position-gradients": "^3.0.4", + "postcss-env-function": "^4.0.4", + "postcss-focus-visible": "^6.0.3", + "postcss-focus-within": "^5.0.3", + "postcss-font-variant": "^5.0.0", + "postcss-gap-properties": "^3.0.2", + "postcss-image-set-function": "^4.0.4", + "postcss-initial": "^4.0.1", + "postcss-lab-function": "^4.0.3", + "postcss-logical": "^5.0.3", + "postcss-media-minmax": "^5.0.0", + "postcss-nesting": "^10.1.2", + "postcss-overflow-shorthand": "^3.0.2", + "postcss-page-break": "^3.0.4", + "postcss-place": "^7.0.3", + "postcss-pseudo-class-any-link": "^7.0.2", + "postcss-replace-overflow-wrap": "^4.0.0", + "postcss-selector-not": "^5.0.0" } }, - "postcss-normalize-repeat-style": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-4.0.2.tgz", - "integrity": "sha512-qvigdYYMpSuoFs3Is/f5nHdRLJN/ITA7huIoCyqqENJe9PvPmLhNLMu7QTjPdtnVf6OcYYO5SHonx4+fbJE1+Q==", + "postcss-pseudo-class-any-link": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-7.1.1.tgz", + "integrity": "sha512-JRoLFvPEX/1YTPxRxp1JO4WxBVXJYrSY7NHeak5LImwJ+VobFMwYDQHvfTXEpcn+7fYIeGkC29zYFhFWIZD8fg==", "dev": true, "requires": { - "cssnano-util-get-arguments": "^4.0.0", - "cssnano-util-get-match": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - } + "postcss-selector-parser": "^6.0.9" } }, - "postcss-normalize-string": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-4.0.2.tgz", - "integrity": "sha512-RrERod97Dnwqq49WNz8qo66ps0swYZDSb6rM57kN2J+aoyEAJfZ6bMx0sx/F9TIEX0xthPGCmeyiam/jXif0eA==", - "dev": true, - "requires": { - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - } - } + "postcss-replace-overflow-wrap": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-4.0.0.tgz", + "integrity": "sha512-KmF7SBPphT4gPPcKZc7aDkweHiKEEO8cla/GjcBK+ckKxiZslIu3C4GCRW3DNfL0o7yW7kMQu9xlZ1kXRXLXtw==", + "dev": true }, - "postcss-normalize-timing-functions": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-4.0.2.tgz", - "integrity": "sha512-acwJY95edP762e++00Ehq9L4sZCEcOPyaHwoaFOhIwWCDfik6YvqsYNxckee65JHLKzuNSSmAdxwD2Cud1Z54A==", + "postcss-selector-not": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-not/-/postcss-selector-not-5.0.0.tgz", + "integrity": "sha512-/2K3A4TCP9orP4TNS7u3tGdRFVKqz/E6pX3aGnriPG0jU78of8wsUcqE4QAhWEU0d+WnMSF93Ah3F//vUtK+iQ==", "dev": true, "requires": { - "cssnano-util-get-match": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - } - } - }, - "postcss-normalize-unicode": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-4.0.1.tgz", - "integrity": "sha512-od18Uq2wCYn+vZ/qCOeutvHjB5jm57ToxRaMeNuf0nWVHaP9Hua56QyMF6fs/4FSUnVIw0CBPsU0K4LnBPwYwg==", - "dev": true, - "requires": { - "browserslist": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - } - } - }, - "postcss-normalize-url": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-4.0.1.tgz", - "integrity": "sha512-p5oVaF4+IHwu7VpMan/SSpmpYxcJMtkGppYf0VbdH5B6hN8YNmVyJLuY9FmLQTzY3fag5ESUUHDqM+heid0UVA==", - "dev": true, - "requires": { - "is-absolute-url": "^2.0.0", - "normalize-url": "^3.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - } - } - }, - "postcss-normalize-whitespace": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-4.0.2.tgz", - "integrity": "sha512-tO8QIgrsI3p95r8fyqKV+ufKlSHh9hMJqACqbv2XknufqEDhDvbguXGBBqxw9nsQoXWf0qOqppziKJKHMD4GtA==", - "dev": true, - "requires": { - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - } - } - }, - "postcss-ordered-values": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-4.1.2.tgz", - "integrity": "sha512-2fCObh5UanxvSxeXrtLtlwVThBvHn6MQcu4ksNT2tsaV2Fg76R2CV98W7wNSlX+5/pFwEyaDwKLLoEV7uRybAw==", - "dev": true, - "requires": { - "cssnano-util-get-arguments": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - } - } - }, - "postcss-reduce-initial": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-4.0.3.tgz", - "integrity": "sha512-gKWmR5aUulSjbzOfD9AlJiHCGH6AEVLaM0AV+aSioxUDd16qXP1PCh8d1/BGVvpdWn8k/HiK7n6TjeoXN1F7DA==", - "dev": true, - "requires": { - "browserslist": "^4.0.0", - "caniuse-api": "^3.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0" - } - }, - "postcss-reduce-transforms": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-4.0.2.tgz", - "integrity": "sha512-EEVig1Q2QJ4ELpJXMZR8Vt5DQx8/mo+dGWSR7vWXqcob2gQLyQGsionYcGKATXvQzMPn6DSN1vTN7yFximdIAg==", - "dev": true, - "requires": { - "cssnano-util-get-match": "^4.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - } + "balanced-match": "^1.0.0" } }, "postcss-selector-parser": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.4.tgz", - "integrity": "sha512-gjMeXBempyInaBqpp8gODmwZ52WaYsVOsfr4L4lDQ7n3ncD6mEyySiDtgzCT+NYC0mmeOLvtsF8iaEf0YT6dBw==", + "version": "6.0.9", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.9.tgz", + "integrity": "sha512-UO3SgnZOVTwu4kyLR22UQ1xZh086RyNZppb7lLAKBFK8a32ttG5i87Y/P3+2bRSjZNyJ1B7hfFNo273tKe9YxQ==", "dev": true, "requires": { "cssesc": "^3.0.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1", "util-deprecate": "^1.0.2" } }, - "postcss-svgo": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-4.0.3.tgz", - "integrity": "sha512-NoRbrcMWTtUghzuKSoIm6XV+sJdvZ7GZSc3wdBN0W19FTtp2ko8NqLsgoh/m9CzNhU3KLPvQmjIwtaNFkaFTvw==", - "dev": true, - "requires": { - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0", - "svgo": "^1.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - } - } - }, - "postcss-unique-selectors": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-4.0.1.tgz", - "integrity": "sha512-+JanVaryLo9QwZjKrmJgkI4Fn8SBgRO6WXQBJi7KiAVPlmxikB5Jzc4EvXMT2H0/m0RjrVVm9rGNhZddm/8Spg==", - "dev": true, - "requires": { - "alphanum-sort": "^1.0.0", - "postcss": "^7.0.0", - "uniqs": "^2.0.0" - } - }, "postcss-value-parser": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", - "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==", + "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 }, "prelude-ls": { @@ -12231,50 +10351,31 @@ "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", "dev": true }, + "pretty-bytes": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", + "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", + "dev": true + }, "pretty-format": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", - "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", "dev": true, "requires": { - "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", "react-is": "^17.0.1" }, "dependencies": { "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, - "requires": { - "color-convert": "^2.0.1" - } - }, - "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, - "requires": { - "color-name": "~1.1.4" - } - }, - "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==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true } } }, - "process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", - "dev": true - }, "process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -12288,33 +10389,27 @@ "dev": true }, "promise-retry": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-1.1.1.tgz", - "integrity": "sha1-ZznpaOMFHaIM5kl/srUPaRHfPW0=", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", "dev": true, "requires": { - "err-code": "^1.0.0", - "retry": "^0.10.0" + "err-code": "^2.0.2", + "retry": "^0.12.0" }, "dependencies": { - "err-code": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/err-code/-/err-code-1.1.2.tgz", - "integrity": "sha1-BuARbTAo9q70gGhJ6w6mp0iuaWA=", - "dev": true - }, "retry": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.10.1.tgz", - "integrity": "sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q=", + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=", "dev": true } } }, "prompts": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.0.tgz", - "integrity": "sha512-awZAKrk3vN6CroQukBL+R9051a4R3zCZBlJm/HBfrSZ8iTpYix3VX1vU4mveiLpiwmOJT4wokTF9m6HUk4KqWQ==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", "dev": true, "requires": { "kleur": "^3.0.3", @@ -12665,108 +10760,44 @@ } }, "proxy-addr": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", - "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==", + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", "dev": true, "requires": { - "forwarded": "~0.1.2", + "forwarded": "0.2.0", "ipaddr.js": "1.9.1" + }, + "dependencies": { + "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 + } } }, "prr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", - "dev": true + "dev": true, + "optional": true }, "psl": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" }, - "public-encrypt": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", - "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", - "dev": true, - "requires": { - "bn.js": "^4.1.0", - "browserify-rsa": "^4.0.0", - "create-hash": "^1.1.0", - "parse-asn1": "^5.0.0", - "randombytes": "^2.0.1", - "safe-buffer": "^5.1.2" - }, - "dependencies": { - "bn.js": { - "version": "4.11.9", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", - "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", - "dev": true - } - } - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "pumpify": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", - "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", - "dev": true, - "requires": { - "duplexify": "^3.6.0", - "inherits": "^2.0.3", - "pump": "^2.0.0" - }, - "dependencies": { - "pump": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", - "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - } - } - }, "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" }, - "q": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", - "dev": true - }, "qs": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", - "dev": true - }, - "querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", - "dev": true - }, - "querystring-es3": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", - "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", + "version": "6.9.6", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.6.tgz", + "integrity": "sha512-TIRk4aqYLNoJUbd+g2lEdz5kLWIuTMRagAXxl78Q0RiVjAOugHmeKNGdd3cwo/ktpf9aL9epCfFqWDEKysUlLQ==", "dev": true }, "querystringify": { @@ -12774,6 +10805,12 @@ "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true + }, "randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -12783,16 +10820,6 @@ "safe-buffer": "^5.1.0" } }, - "randomfill": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", - "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", - "dev": true, - "requires": { - "randombytes": "^2.0.5", - "safe-buffer": "^5.1.0" - } - }, "range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -12800,52 +10827,29 @@ "dev": true }, "raw-body": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", - "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.2.tgz", + "integrity": "sha512-RPMAFUJP19WIet/99ngh6Iv8fzAbqum4Li7AD6DtGaW2RpMB/11xDoalPiJMTbu6I3hkbMVkATvZrqb9EEqeeQ==", "dev": true, "requires": { - "bytes": "3.1.0", - "http-errors": "1.7.2", + "bytes": "3.1.1", + "http-errors": "1.8.1", "iconv-lite": "0.4.24", "unpipe": "1.0.0" }, "dependencies": { "bytes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.1.tgz", + "integrity": "sha512-dWe4nWO/ruEOY7HkUJ5gFt1DCFV9zPRoJr8pV0/ASQermOZjtq8jMjOprC0Kd10GLN+l7xaUPvxzJFWtxGu8Fg==", "dev": true } } }, - "raw-loader": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/raw-loader/-/raw-loader-4.0.2.tgz", - "integrity": "sha512-ZnScIV3ag9A4wPX/ZayxL/jZH+euYb6FcUinPcgiQW0+UBtEv0O6Q3lGd3cqJ+GHH+rksEv3Pj99oxJ3u3VIKA==", - "dev": true, - "requires": { - "loader-utils": "^2.0.0", - "schema-utils": "^3.0.0" - }, - "dependencies": { - "schema-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", - "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.6", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - } - } - } - }, "react-is": { - "version": "17.0.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.1.tgz", - "integrity": "sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA==", + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "dev": true }, "read-cache": { @@ -12866,100 +10870,15 @@ } }, "read-package-json-fast": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-1.2.2.tgz", - "integrity": "sha512-39DbPJjkltEzfXJXB6D8/Ir3GFOU2YbSKa2HaB/Y3nKrc/zY+0XrALpID6/13ezWyzqvOHrBbR4t4cjQuTdBVQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-2.0.3.tgz", + "integrity": "sha512-W/BKtbL+dUjTuRL2vziuYhp76s5HZ9qQhd/dKfWIZveD0O40453QNyZhC0e63lqZrAQ4jiOapVoeJ7JrszenQQ==", "dev": true, "requires": { "json-parse-even-better-errors": "^2.3.0", "npm-normalize-package-bin": "^1.0.1" } }, - "read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", - "dev": true, - "requires": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" - }, - "dependencies": { - "parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - } - }, - "type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "dev": true - } - } - }, - "read-pkg-up": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", - "dev": true, - "requires": { - "find-up": "^4.1.0", - "read-pkg": "^5.2.0", - "type-fest": "^0.8.1" - }, - "dependencies": { - "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, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "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, - "requires": { - "p-locate": "^4.1.0" - } - }, - "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, - "requires": { - "p-limit": "^2.2.0" - } - }, - "path-exists": { - "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 - }, - "type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true - } - } - }, "readable-stream": { "version": "2.3.7", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", @@ -12976,9 +10895,9 @@ } }, "readdirp": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", - "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "dev": true, "requires": { "picomatch": "^2.2.1" @@ -12997,18 +10916,18 @@ "dev": true }, "regenerate-unicode-properties": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz", - "integrity": "sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.0.1.tgz", + "integrity": "sha512-vn5DU6yg6h8hP/2OkQo3K7uVILvY4iu0oI4t3HFa81UPkhGJwkRwM10JEc3upjdhHjs/k8GJY1sRBhk5sr69Bw==", "dev": true, "requires": { - "regenerate": "^1.4.0" + "regenerate": "^1.4.2" } }, "regenerator-runtime": { - "version": "0.13.7", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==", + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", "dev": true }, "regenerator-transform": { @@ -13020,16 +10939,6 @@ "@babel/runtime": "^7.8.4" } }, - "regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", - "dev": true, - "requires": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - } - }, "regex-parser": { "version": "2.2.11", "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.2.11.tgz", @@ -13037,39 +10946,39 @@ "dev": true }, "regexp.prototype.flags": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz", - "integrity": "sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.1.tgz", + "integrity": "sha512-pMR7hBVUUGI7PMA37m2ofIdQCsomVnas+Jn5UPGAHQ+/LlwKm/aTLJHdasmHRzlfeZwHiAOaRSo2rbBDm3nNUQ==", "dev": true, "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.1" + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" } }, "regexpu-core": { - "version": "4.7.1", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.7.1.tgz", - "integrity": "sha512-ywH2VUraA44DZQuRKzARmw6S66mr48pQVva4LBeRhcOltJ6hExvWly5ZjFLYo67xbIxb6W1q4bAGtgfEl20zfQ==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.0.1.tgz", + "integrity": "sha512-CriEZlrKK9VJw/xQGJpQM5rY88BtuL8DM+AEwvcThHilbxiTAy8vq4iJnd2tqq8wLmjbGZzP7ZcKFjbGkmEFrw==", "dev": true, "requires": { - "regenerate": "^1.4.0", - "regenerate-unicode-properties": "^8.2.0", - "regjsgen": "^0.5.1", - "regjsparser": "^0.6.4", - "unicode-match-property-ecmascript": "^1.0.4", - "unicode-match-property-value-ecmascript": "^1.2.0" + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.0.1", + "regjsgen": "^0.6.0", + "regjsparser": "^0.8.2", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.0.0" } }, "regjsgen": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz", - "integrity": "sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.6.0.tgz", + "integrity": "sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA==", "dev": true }, "regjsparser": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.4.tgz", - "integrity": "sha512-64O87/dPDgfk8/RQqC4gkZoGyyWFIEUTTh80CU6CWuK5vkCGyekIx+oKcEIYtP/RAxSQltCZHCNu/mdd7fqlJw==", + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.8.4.tgz", + "integrity": "sha512-J3LABycON/VNEu3abOviqGHuB/LOtOQj8SKmfP9anY5GfAVw/SPjwzSjxGjbZXIxbGfqTHtJw58C2Li/WkStmA==", "dev": true, "requires": { "jsesc": "~0.5.0" @@ -13083,24 +10992,6 @@ } } }, - "remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", - "dev": true - }, - "repeat-element": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", - "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", - "dev": true - }, - "repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "dev": true - }, "request": { "version": "2.88.2", "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", @@ -13142,6 +11033,12 @@ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true + }, "require-main-filename": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", @@ -13163,85 +11060,42 @@ } }, "resolve-cwd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", - "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", "dev": true, "requires": { - "resolve-from": "^3.0.0" + "resolve-from": "^5.0.0" } }, "resolve-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", - "dev": true - }, - "resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true }, "resolve-url-loader": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-3.1.2.tgz", - "integrity": "sha512-QEb4A76c8Mi7I3xNKXlRKQSlLBwjUV/ULFMP+G7n3/7tJZ8MG5wsZ3ucxP1Jz8Vevn6fnJsxDx9cIls+utGzPQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-5.0.0.tgz", + "integrity": "sha512-uZtduh8/8srhBoMx//5bwqjQ+rfYOUq8zC9NrMUGtjBiGTtFJM42s58/36+hTqeqINcnYe08Nj3LkK9lW4N8Xg==", "dev": true, "requires": { - "adjust-sourcemap-loader": "3.0.0", - "camelcase": "5.3.1", - "compose-function": "3.0.3", - "convert-source-map": "1.7.0", - "es6-iterator": "2.0.3", - "loader-utils": "1.2.3", - "postcss": "7.0.21", - "rework": "1.0.1", - "rework-visit": "1.0.0", + "adjust-sourcemap-loader": "^4.0.0", + "convert-source-map": "^1.7.0", + "loader-utils": "^2.0.0", + "postcss": "^8.2.14", "source-map": "0.6.1" }, "dependencies": { - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, - "emojis-list": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", - "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", - "dev": true - }, - "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", - "dev": true, - "requires": { - "minimist": "^1.2.0" - } - }, "loader-utils": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz", - "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz", + "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", "dev": true, "requires": { "big.js": "^5.2.2", - "emojis-list": "^2.0.0", - "json5": "^1.0.1" - } - }, - "postcss": { - "version": "7.0.21", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.21.tgz", - "integrity": "sha512-uIFtJElxJo29QC753JzhidoAhvp/e/Exezkdhfmt8AymWT6/5B7W1WmponYWkHk2eg6sONyTch0A3nkMPun3SQ==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" + "emojis-list": "^3.0.0", + "json5": "^2.1.2" } }, "source-map": { @@ -13249,18 +11103,15 @@ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } } } }, + "resolve.exports": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", + "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==", + "dev": true + }, "restore-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", @@ -13271,16 +11122,10 @@ "signal-exit": "^3.0.2" } }, - "ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", - "dev": true - }, "retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=", + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", "dev": true }, "reusify": { @@ -13289,42 +11134,6 @@ "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", "dev": true }, - "rework": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/rework/-/rework-1.0.1.tgz", - "integrity": "sha1-MIBqhBNCtUUQqkEQhQzUhTQUSqc=", - "dev": true, - "requires": { - "convert-source-map": "^0.3.3", - "css": "^2.0.0" - }, - "dependencies": { - "convert-source-map": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-0.3.5.tgz", - "integrity": "sha1-8dgClQr33SYxof6+BZZVDIarMZA=", - "dev": true - } - } - }, - "rework-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/rework-visit/-/rework-visit-1.0.0.tgz", - "integrity": "sha1-mUWygD8hni96ygCtuLyfZA+ELJo=", - "dev": true - }, - "rgb-regex": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/rgb-regex/-/rgb-regex-1.0.1.tgz", - "integrity": "sha1-wODWiC3w4jviVKR16O3UGRX+rrE=", - "dev": true - }, - "rgba-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/rgba-regex/-/rgba-regex-1.0.0.tgz", - "integrity": "sha1-QzdOLiyglosO8VI0YLfXMP8i7rM=", - "dev": true - }, "rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -13334,31 +11143,6 @@ "glob": "^7.1.3" } }, - "ripemd160": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", - "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", - "dev": true, - "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" - } - }, - "rollup": { - "version": "2.32.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.32.1.tgz", - "integrity": "sha512-Op2vWTpvK7t6/Qnm1TTh7VjEZZkN8RWgf0DHbkKzQBwNf748YhXbozHVefqpPp/Fuyk/PQPAnYsBxAEtlMvpUw==", - "dev": true, - "requires": { - "fsevents": "~2.1.2" - } - }, - "rsvp": { - "version": "4.8.5", - "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz", - "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==", - "dev": true - }, "run-async": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", @@ -13366,33 +11150,20 @@ "dev": true }, "run-parallel": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.10.tgz", - "integrity": "sha512-zb/1OuZ6flOlH6tQyMPUrE3x3Ulxjlo9WIVXR4yVYi4H9UXQaeIsPbLn2R3O3vQCnDKkAl2qHiuocKKX4Tz/Sw==", - "dev": true - }, - "run-queue": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", - "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", "dev": true, "requires": { - "aproba": "^1.1.1" + "queue-microtask": "^1.2.2" } }, "rxjs": { - "version": "6.6.3", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.3.tgz", - "integrity": "sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.4.tgz", + "integrity": "sha512-h5M3Hk78r6wAheJF0a5YahB1yRQKCsZ4MsGdZ5O9ETbVtjPcScGfrMmoOq7EBsCRzd4BDkvDJ7ogP8Sz5tTFiQ==", "requires": { - "tslib": "^1.9.0" - }, - "dependencies": { - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - } + "tslib": "^2.1.0" } }, "rxjs-compat": { @@ -13405,195 +11176,31 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, - "safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", - "dev": true, - "requires": { - "ret": "~0.1.10" - } - }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, - "sane": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/sane/-/sane-4.1.0.tgz", - "integrity": "sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA==", - "dev": true, - "requires": { - "@cnakazawa/watch": "^1.0.3", - "anymatch": "^2.0.0", - "capture-exit": "^2.0.0", - "exec-sh": "^0.3.2", - "execa": "^1.0.0", - "fb-watchman": "^2.0.0", - "micromatch": "^3.1.4", - "minimist": "^1.1.1", - "walker": "~1.0.5" - }, - "dependencies": { - "anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", - "dev": true, - "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - } - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "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" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "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" - } - }, - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "requires": { - "remove-trailing-separator": "^1.0.1" - } - }, - "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - } - } - } - }, "sass": { - "version": "1.27.0", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.27.0.tgz", - "integrity": "sha512-0gcrER56OkzotK/GGwgg4fPrKuiFlPNitO7eUJ18Bs+/NBlofJfMxmxqpqJxjae9vu0Wq8TZzrSyxZal00WDig==", + "version": "1.49.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.49.0.tgz", + "integrity": "sha512-TVwVdNDj6p6b4QymJtNtRS2YtLJ/CqZriGg0eIAbAKMlN8Xy6kbv33FsEZSF7FufFFM705SQviHjjThfaQ4VNw==", "dev": true, "requires": { - "chokidar": ">=2.0.0 <4.0.0" + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" } }, "sass-loader": { - "version": "10.0.5", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-10.0.5.tgz", - "integrity": "sha512-2LqoNPtKkZq/XbXNQ4C64GFEleSEHKv6NPSI+bMC/l+jpEXGJhiRYkAQToO24MR7NU4JRY2RpLpJ/gjo2Uf13w==", + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-12.4.0.tgz", + "integrity": "sha512-7xN+8khDIzym1oL9XyS6zP6Ges+Bo2B2xbPrjdMHEYyV3AQYhd/wXeru++3ODHF0zMjYmVadblSKrPrjEkL8mg==", "dev": true, "requires": { "klona": "^2.0.4", - "loader-utils": "^2.0.0", - "neo-async": "^2.6.2", - "schema-utils": "^3.0.0", - "semver": "^7.3.2" - }, - "dependencies": { - "schema-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", - "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.6", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - } - } + "neo-async": "^2.6.2" } }, "saucelabs": { @@ -13670,19 +11277,18 @@ } }, "selfsigned": { - "version": "1.10.8", - "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.8.tgz", - "integrity": "sha512-2P4PtieJeEwVgTU9QEcwIRDQ/mXJLX8/+I3ur+Pg16nS8oNbrGxEso9NyYWy8NAmXiNl4dlAp5MwoNeCWzON4w==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.0.0.tgz", + "integrity": "sha512-cUdFiCbKoa1mZ6osuJs2uDHrs0k0oprsKveFiiaBKCNq3SYyb5gs2HxhQyDNLCmL51ZZThqi4YNDpCK6GOP1iQ==", "dev": true, "requires": { - "node-forge": "^0.10.0" + "node-forge": "^1.2.0" } }, "semver": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", - "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", - "dev": true + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" }, "semver-dsl": { "version": "1.0.1", @@ -13691,37 +11297,12 @@ "dev": true, "requires": { "semver": "^5.3.0" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, - "semver-intersect": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/semver-intersect/-/semver-intersect-1.4.0.tgz", - "integrity": "sha512-d8fvGg5ycKAq0+I6nfWeCx6ffaWJCsBYU0H2Rq56+/zFePYfT8mXkB3tWBSjR5BerkHNZ5eTPIk1/LBYas35xQ==", - "dev": true, - "requires": { - "semver": "^5.0.0" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } } }, "send": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", - "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "version": "0.17.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz", + "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==", "dev": true, "requires": { "debug": "2.6.9", @@ -13731,9 +11312,9 @@ "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "0.5.2", - "http-errors": "~1.7.2", + "http-errors": "1.8.1", "mime": "1.6.0", - "ms": "2.1.1", + "ms": "2.1.3", "on-finished": "~2.3.0", "range-parser": "~1.2.1", "statuses": "~1.5.0" @@ -13757,17 +11338,17 @@ } }, "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true } } }, "serialize-javascript": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz", - "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", "dev": true, "requires": { "randombytes": "^2.1.0" @@ -13830,15 +11411,15 @@ } }, "serve-static": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", - "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz", + "integrity": "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==", "dev": true, "requires": { "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.17.1" + "send": "0.17.2" } }, "set-blocking": { @@ -13853,51 +11434,12 @@ "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=", "dev": true }, - "set-value": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", - "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", - "dev": true - }, "setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", "dev": true }, - "sha.js": { - "version": "2.4.11", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", - "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, "shallow-clone": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", @@ -13908,65 +11450,34 @@ } }, "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, "requires": { - "shebang-regex": "^1.0.0" + "shebang-regex": "^3.0.0" } }, "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, - "shellwords": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", - "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", - "dev": true, - "optional": true - }, "signal-exit": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", - "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true }, - "simple-swizzle": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", - "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", - "dev": true, - "requires": { - "is-arrayish": "^0.3.1" - }, - "dependencies": { - "is-arrayish": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", - "dev": true - } - } - }, "sirv": { - "version": "1.0.17", - "resolved": "https://registry.npmjs.org/sirv/-/sirv-1.0.17.tgz", - "integrity": "sha512-qx9go5yraB7ekT7bCMqUHJ5jEaOC/GXBxUWv+jeWnb7WzHUFdcQPGWk7YmAwFBaQBrogpuSqd/azbC2lZRqqmw==", + "version": "1.0.19", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-1.0.19.tgz", + "integrity": "sha512-JuLThK3TnZG1TAKDwNIqNq6QA2afLOCcm+iE8D1Kj3GA40pSPsxQjjJl0J8X3tsR7T+CP1GavpzLwYkgVLWrZQ==", "requires": { "@polka/url": "^1.0.0-next.20", - "mime": "^2.3.1", + "mrmime": "^1.0.0", "totalist": "^1.0.0" - }, - "dependencies": { - "mime": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz", - "integrity": "sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==" - } } }, "sisteransi": { @@ -13976,209 +11487,55 @@ "dev": true }, "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", "dev": true }, "smart-buffer": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.1.0.tgz", - "integrity": "sha512-iVICrxOzCynf/SNaBQCw34eM9jROU/s5rzIhpOvzhzuYHfJR/DhZfDkXiZSgKXfgv26HT3Yni3AV/DGw0cGnnw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", "dev": true }, - "snapdragon": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", - "dev": true, - "requires": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", - "dev": true, - "requires": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", - "dev": true, - "requires": { - "kind-of": "^3.2.0" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, "sockjs": { - "version": "0.3.20", - "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.20.tgz", - "integrity": "sha512-SpmVOVpdq0DJc0qArhF3E5xsxvaiqGNb73XfgBpK1y3UD5gs8DSo8aCTsuT5pX8rssdc2NDIzANwP9eCAiSdTA==", + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", "dev": true, "requires": { - "faye-websocket": "^0.10.0", - "uuid": "^3.4.0", - "websocket-driver": "0.6.5" - } - }, - "sockjs-client": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.4.0.tgz", - "integrity": "sha512-5zaLyO8/nri5cua0VtOrFXBPK1jbL4+1cebT/mmKA1E1ZXOvJrII75bPu0l0k843G/+iAbhEqzyKr0w/eCCj7g==", - "dev": true, - "requires": { - "debug": "^3.2.5", - "eventsource": "^1.0.7", - "faye-websocket": "~0.11.1", - "inherits": "^2.0.3", - "json3": "^3.3.2", - "url-parse": "^1.4.3" + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" }, "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "faye-websocket": { - "version": "0.11.3", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.3.tgz", - "integrity": "sha512-D2y4bovYpzziGgbHYtGCMjlJM36vAl/y+xUyn1C+FVx8szd1E+86KwVw6XvYSzOP8iMpm1X0I4xJD+QtUb36OA==", - "dev": true, - "requires": { - "websocket-driver": ">=0.5.1" - } + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true } } }, "socks": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.6.1.tgz", - "integrity": "sha512-kLQ9N5ucj8uIcxrDwjm0Jsqk06xdpBjGNQtpXy4Q8/QY2k+fY7nZH8CARy+hkbG+SGAovmzzuauCpBlb8FrnBA==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.6.2.tgz", + "integrity": "sha512-zDZhHhZRY9PxRruRMR7kMhnf3I8hDs4S3f9RecfnGxvcBHQcKcIH/oUcEWffsfl1XxdYlA7nnlGbbTvPz9D8gA==", "dev": true, "requires": { "ip": "^1.1.5", - "smart-buffer": "^4.1.0" + "smart-buffer": "^4.2.0" } }, "socks-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-5.0.0.tgz", - "integrity": "sha512-lEpa1zsWCChxiynk+lCycKuC502RxDWLKJZoIhnxrWNjLSDGYRFflHA1/228VkRcnv9TIb8w98derGbpKxJRgA==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.1.1.tgz", + "integrity": "sha512-t8J0kG3csjA4g6FTbsMOWws+7R7vuRC8aQ/wy3/1OWmsgwA68zs/+cExQ0koSitUDXqhufF/YJr9wtNMZHw5Ew==", "dev": true, "requires": { - "agent-base": "6", - "debug": "4", - "socks": "^2.3.3" + "agent-base": "^6.0.2", + "debug": "^4.3.1", + "socks": "^2.6.1" }, "dependencies": { "agent-base": { @@ -14192,77 +11549,53 @@ } } }, - "source-list-map": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", - "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", - "dev": true - }, "source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + }, + "source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", "dev": true }, "source-map-loader": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-1.1.2.tgz", - "integrity": "sha512-bjf6eSENOYBX4JZDfl9vVLNsGAQ6Uz90fLmOazcmMcyDYOBFsGxPNn83jXezWLY9bJsVAo1ObztxPcV8HAbjVA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-3.0.1.tgz", + "integrity": "sha512-Vp1UsfyPvgujKQzi4pyDiTOnE3E4H+yHvkVRN3c/9PJmQS4CQJExvcDvaX/D+RV+xQben9HJ56jMJS3CgUeWyA==", "dev": true, "requires": { "abab": "^2.0.5", - "iconv-lite": "^0.6.2", - "loader-utils": "^2.0.0", - "schema-utils": "^3.0.0", - "source-map": "^0.6.1", - "whatwg-mimetype": "^2.3.0" + "iconv-lite": "^0.6.3", + "source-map-js": "^1.0.1" }, "dependencies": { "iconv-lite": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz", - "integrity": "sha512-2y91h5OpQlolefMPmUlivelittSWy0rP+oYVpn6A7GwVHNE8AWzoYOBNmlwks3LobaJxgHCYZAnyNo2GgpNRNQ==", + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "dev": true, "requires": { "safer-buffer": ">= 2.1.2 < 3.0.0" } - }, - "schema-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", - "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.6", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - } - }, - "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 } } }, "source-map-resolve": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", - "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.6.0.tgz", + "integrity": "sha512-KXBr9d/fO/bWo97NXsPIAW1bFSBOuCnjbNTBMO7N59hsv5i9yzRDfcYwwt0l04+VqnKC+EwzvJZIP/qkuMgR/w==", "dev": true, "requires": { "atob": "^2.1.2", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" + "decode-uri-component": "^0.2.0" } }, "source-map-support": { - "version": "0.5.19", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", - "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "dev": true, "requires": { "buffer-from": "^1.0.0", @@ -14277,50 +11610,12 @@ } } }, - "source-map-url": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", - "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", - "dev": true - }, "sourcemap-codec": { "version": "1.4.8", "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", "dev": true }, - "spdx-correct": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", - "dev": true, - "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true - }, - "spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, - "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.7.tgz", - "integrity": "sha512-U+MTEOO0AiDzxwFvoa4JVnMV6mZlJKk2sBLt90s7G0Gd0Mlknc7kxEn3nuDPNZRta7O2uy8oLcZLVT+4sqNZHQ==", - "dev": true - }, "spdy": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", @@ -14361,24 +11656,6 @@ } } }, - "speed-measure-webpack-plugin": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/speed-measure-webpack-plugin/-/speed-measure-webpack-plugin-1.3.3.tgz", - "integrity": "sha512-2ljD4Ch/rz2zG3HsLsnPfp23osuPBS0qPuz9sGpkNXTN1Ic4M+W9xB8l8rS8ob2cO4b1L+WTJw/0AJwWYVgcxQ==", - "dev": true, - "requires": { - "chalk": "^2.0.1" - } - }, - "split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", - "dev": true, - "requires": { - "extend-shallow": "^3.0.0" - } - }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -14403,9 +11680,9 @@ } }, "ssr-window": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ssr-window/-/ssr-window-3.0.0.tgz", - "integrity": "sha512-q+8UfWDg9Itrg0yWK7oe5p/XRCJpJF9OBtXfOPgSJl+u3Xd5KI328RUEvUqSMVM9CiQUEf1QdBzJMkYGErj9QA==" + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/ssr-window/-/ssr-window-4.0.2.tgz", + "integrity": "sha512-ISv/Ch+ig7SOtw7G2+qkwfVASzazUnvlDTwypdLoPoySv+6MqlOV10VwPSE6EWkGjhW50lUmghPmpYZXMu/+AQ==" }, "ssri": { "version": "8.0.1", @@ -14416,16 +11693,10 @@ "minipass": "^3.1.1" } }, - "stable": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", - "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", - "dev": true - }, "stack-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-gL//fkxfWUsIlFL2Tl42Cl6+HFALEaB1FU76I/Fy+oZjRreP7OPMXFlGbxM7NQsI0ZpUfw76sHnv0WNYuTb7Iw==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", + "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", "dev": true, "requires": { "escape-string-regexp": "^2.0.0" @@ -14439,76 +11710,16 @@ } } }, - "static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", - "dev": true, - "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, "statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", "dev": true }, - "stream-browserify": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", - "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", - "dev": true, - "requires": { - "inherits": "~2.0.1", - "readable-stream": "^2.0.2" - } - }, - "stream-each": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz", - "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "stream-shift": "^1.0.0" - } - }, - "stream-http": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", - "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", - "dev": true, - "requires": { - "builtin-status-codes": "^3.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.3.6", - "to-arraybuffer": "^1.0.0", - "xtend": "^4.0.0" - } - }, - "stream-shift": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", - "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", - "dev": true - }, "string-length": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.1.tgz", - "integrity": "sha512-PKyXUd0LK0ePjSOnWn34V2uD6acUWev9uy0Ft05k0E8xRW+SKcA0F7eMr7h5xlzfn+4O3N+55rduYyet3Jk+jw==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", "dev": true, "requires": { "char-regex": "^1.0.2", @@ -14525,26 +11736,6 @@ "strip-ansi": "^6.0.0" } }, - "string.prototype.trimend": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", - "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "string.prototype.trimstart": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", - "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -14568,134 +11759,49 @@ "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", "dev": true }, - "strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", - "dev": true - }, "strip-final-newline": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", "dev": true }, - "style-loader": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-2.0.0.tgz", - "integrity": "sha512-Z0gYUJmzZ6ZdRUqpg1r8GsaFKypE+3xAzuFeMuoHgjc9KZv3wMyCRjQIWEbhoFSq7+7yoHXySDJyyWQaPajeiQ==", - "dev": true, - "requires": { - "loader-utils": "^2.0.0", - "schema-utils": "^3.0.0" - }, - "dependencies": { - "schema-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", - "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.6", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - } - } - } - }, - "stylehacks": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-4.0.3.tgz", - "integrity": "sha512-7GlLk9JwlElY4Y6a/rmbH2MhVlTyVmiJd1PfTCqFaIBEGMYNsrO/v3SeGTdhBThLg4Z+NbOk/qFMwCa+J+3p/g==", - "dev": true, - "requires": { - "browserslist": "^4.0.0", - "postcss": "^7.0.0", - "postcss-selector-parser": "^3.0.0" - }, - "dependencies": { - "postcss-selector-parser": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", - "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", - "dev": true, - "requires": { - "dot-prop": "^5.2.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - } - } - } + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true }, "stylus": { - "version": "0.54.8", - "resolved": "https://registry.npmjs.org/stylus/-/stylus-0.54.8.tgz", - "integrity": "sha512-vr54Or4BZ7pJafo2mpf0ZcwA74rpuYCZbxrHBsH8kbcXOwSfvBFwsRfpGO5OD5fhG5HDCFW737PKaawI7OqEAg==", + "version": "0.56.0", + "resolved": "https://registry.npmjs.org/stylus/-/stylus-0.56.0.tgz", + "integrity": "sha512-Ev3fOb4bUElwWu4F9P9WjnnaSpc8XB9OFHSFZSKMFL1CE1oM+oFXWEgAqPmmZIyhBihuqIQlFsVTypiiS9RxeA==", "dev": true, "requires": { - "css-parse": "~2.0.0", - "debug": "~3.1.0", + "css": "^3.0.0", + "debug": "^4.3.2", "glob": "^7.1.6", - "mkdirp": "~1.0.4", "safer-buffer": "^2.1.2", "sax": "~1.2.4", - "semver": "^6.3.0", "source-map": "^0.7.3" }, "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", "dev": true } } }, "stylus-loader": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/stylus-loader/-/stylus-loader-4.3.1.tgz", - "integrity": "sha512-apDYJEM5ZpOAWbWInWcsbtI8gHNr/XYVcSY/tWqOUPt7M5tqhtwXVsAkgyiVjhuvw2Yrjq474a9H+g4d047Ebw==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/stylus-loader/-/stylus-loader-6.2.0.tgz", + "integrity": "sha512-5dsDc7qVQGRoc6pvCL20eYgRUxepZ9FpeK28XhdXaIPP6kXr6nI1zAAKFQgP5OBkOfKaURp4WUpJzspg1f01Gg==", "dev": true, "requires": { - "fast-glob": "^3.2.4", + "fast-glob": "^3.2.7", "klona": "^2.0.4", - "loader-utils": "^2.0.0", - "normalize-path": "^3.0.0", - "schema-utils": "^3.0.0" - }, - "dependencies": { - "schema-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", - "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.6", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - } - } + "normalize-path": "^3.0.0" } }, "supports-color": { @@ -14707,9 +11813,9 @@ } }, "supports-hyperlinks": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.1.0.tgz", - "integrity": "sha512-zoE5/e+dnEijk6ASB6/qrK+oYdm2do1hjoLWrqUC/8WEIW1gbxFcKuBof7sW8ArN6e+AYvsE8HBGiVRWL/F5CA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", + "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", "dev": true, "requires": { "has-flag": "^4.0.0", @@ -14733,40 +11839,25 @@ } } }, - "svgo": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz", - "integrity": "sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw==", - "dev": true, - "requires": { - "chalk": "^2.4.1", - "coa": "^2.0.2", - "css-select": "^2.0.0", - "css-select-base-adapter": "^0.1.1", - "css-tree": "1.0.0-alpha.37", - "csso": "^4.0.2", - "js-yaml": "^3.13.1", - "mkdirp": "~0.5.1", - "object.values": "^1.1.0", - "sax": "~1.2.4", - "stable": "^0.1.8", - "unquote": "~1.1.1", - "util.promisify": "~1.0.0" - } + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true }, "swiper": { - "version": "6.5.8", - "resolved": "https://registry.npmjs.org/swiper/-/swiper-6.5.8.tgz", - "integrity": "sha512-SW8bNkJf8jCB4VdZsA1EZ3c87xshHS4f83YZVqT9ppkDKgspOfk9/I6dTtKGJFlsZpuE1S5X0LUAa7+QEaC0fQ==", + "version": "8.0.6", + "resolved": "https://registry.npmjs.org/swiper/-/swiper-8.0.6.tgz", + "integrity": "sha512-Ssyu1+FeNATF/G8e84QG+ZUNtUOAZ5vngdgxzczh0oWZPhGUVgkdv+BoePUuaCXLAFXnwVpNjgLIcGnxMdmWPA==", "requires": { - "dom7": "^3.0.0", - "ssr-window": "^3.0.0" + "dom7": "^4.0.4", + "ssr-window": "^4.0.2" } }, "symbol-observable": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-3.0.0.tgz", - "integrity": "sha512-6tDOXSHiVjuCaasQSWTmHUWn4PuG7qa3+1WT031yTc/swT7+rLiw3GOrFxaH1E3lLP09dH3bVuVDf2gK5rxG3Q==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz", + "integrity": "sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==", "dev": true }, "symbol-tree": { @@ -14776,9 +11867,9 @@ "dev": true }, "tapable": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.0.tgz", - "integrity": "sha512-FBk4IesMV1rBxX2tfiK8RAmogtWn53puLOQlvO8XuwlgxcYbP4mVPS9Ph4aeamSyyVjOl24aYWAuc8U5kCVwMw==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", "dev": true }, "tar": { @@ -14814,49 +11905,44 @@ } }, "terser": { - "version": "5.3.7", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.3.7.tgz", - "integrity": "sha512-lJbKdfxWvjpV330U4PBZStCT9h3N9A4zZVA5Y4k9sCWXknrpdyxi1oMsRKLmQ/YDMDxSBKIh88v0SkdhdqX06w==", + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.10.0.tgz", + "integrity": "sha512-AMmF99DMfEDiRJfxfY5jj5wNH/bYO09cniSqhfoyxc8sFoYIgkJy86G04UoZU5VjlpnplVu0K6Tx6E9b5+DlHA==", "dev": true, "requires": { "commander": "^2.20.0", "source-map": "~0.7.2", - "source-map-support": "~0.5.19" + "source-map-support": "~0.5.20" + }, + "dependencies": { + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true + } } }, "terser-webpack-plugin": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-4.2.3.tgz", - "integrity": "sha512-jTgXh40RnvOrLQNgIkwEKnQ8rmHjHK4u+6UBEi+W+FPmvb+uo+chJXntKe7/3lW5mNysgSWD60KyesnhW8D6MQ==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.1.tgz", + "integrity": "sha512-GvlZdT6wPQKbDNW/GDQzZFg/j4vKU96yl2q6mcUkzKOgW4gwf1Z8cZToUCrz31XHlPWH8MVb1r2tFtdDtTGJ7g==", "dev": true, "requires": { - "cacache": "^15.0.5", - "find-cache-dir": "^3.3.1", - "jest-worker": "^26.5.0", - "p-limit": "^3.0.2", - "schema-utils": "^3.0.0", - "serialize-javascript": "^5.0.1", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.0", "source-map": "^0.6.1", - "terser": "^5.3.4", - "webpack-sources": "^1.4.3" + "terser": "^5.7.2" }, "dependencies": { - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "requires": { - "yocto-queue": "^0.1.0" - } - }, "schema-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", - "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", "dev": true, "requires": { - "@types/json-schema": "^7.0.6", + "@types/json-schema": "^7.0.8", "ajv": "^6.12.5", "ajv-keywords": "^3.5.2" } @@ -14866,16 +11952,6 @@ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true - }, - "webpack-sources": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", - "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", - "dev": true, - "requires": { - "source-list-map": "^2.0.0", - "source-map": "~0.6.1" - } } } }, @@ -14897,9 +11973,9 @@ "dev": true }, "throat": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz", - "integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.1.tgz", + "integrity": "sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w==", "dev": true }, "through": { @@ -14908,37 +11984,12 @@ "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", "dev": true }, - "through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "requires": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, "thunky": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", "dev": true }, - "timers-browserify": { - "version": "2.0.12", - "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz", - "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==", - "dev": true, - "requires": { - "setimmediate": "^1.0.4" - } - }, - "timsort": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", - "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=", - "dev": true - }, "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", @@ -14954,49 +12005,11 @@ "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", "dev": true }, - "to-arraybuffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", - "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=", - "dev": true - }, "to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=" }, - "to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", - "dev": true, - "requires": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" - } - }, "to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -15007,9 +12020,9 @@ } }, "toidentifier": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", - "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "dev": true }, "totalist": { @@ -15027,13 +12040,9 @@ } }, "tr46": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", - "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", - "dev": true, - "requires": { - "punycode": "^2.1.1" - } + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" }, "tree-kill": { "version": "1.2.2", @@ -15042,61 +12051,63 @@ "dev": true }, "ts-jest": { - "version": "26.5.1", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-26.5.1.tgz", - "integrity": "sha512-G7Rmo3OJMvlqE79amJX8VJKDiRcd7/r61wh9fnvvG8cAjhA9edklGw/dCxRSQmfZ/z8NDums5srSVgwZos1qfg==", + "version": "27.1.3", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-27.1.3.tgz", + "integrity": "sha512-6Nlura7s6uM9BVUAoqLH7JHyMXjz8gluryjpPXxr3IxZdAXnU6FhjvVLHFtfd1vsE1p8zD1OJfskkc0jhTSnkA==", "dev": true, "requires": { - "@types/jest": "26.x", "bs-logger": "0.x", - "buffer-from": "1.x", "fast-json-stable-stringify": "2.x", - "jest-util": "^26.1.0", + "jest-util": "^27.0.0", "json5": "2.x", - "lodash": "4.x", + "lodash.memoize": "4.x", "make-error": "1.x", - "mkdirp": "1.x", "semver": "7.x", "yargs-parser": "20.x" }, "dependencies": { - "mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } }, "yargs-parser": { - "version": "20.2.5", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.5.tgz", - "integrity": "sha512-jYRGS3zWy20NtDtK2kBgo/TlAoy5YUuhD9/LZ7z7W4j1Fdw2cqD0xEEclf8fxc8xjD6X5Qr+qQQwCEsP8iRiYg==", + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", "dev": true } } }, "ts-node": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.3.0.tgz", - "integrity": "sha512-dyNS/RqyVTDcmNM4NIBAeDMpsAdaQ+ojdf0GOLqE6nwJOgzEkdRNzJywhDfwnuvB10oa6NLVG1rUJQCpRN7qoQ==", + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.5.0.tgz", + "integrity": "sha512-6kEJKwVxAJ35W4akuiysfKwKmjkbYxwQMTBaAxo9KKAx/Yd26mPUyhGz3ji+EsJoAgrLqVsYHNuuYwQe22lbtw==", "dev": true, "requires": { + "@cspotcode/source-map-support": "0.7.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", "arg": "^4.1.0", + "create-require": "^1.1.0", "diff": "^4.0.1", "make-error": "^1.1.1", - "source-map-support": "^0.5.6", - "yn": "^3.0.0" + "v8-compile-cache-lib": "^3.0.0", + "yn": "3.1.1" } }, - "ts-pnp": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/ts-pnp/-/ts-pnp-1.2.0.tgz", - "integrity": "sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw==", - "dev": true - }, "tslib": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz", - "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ==" + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", + "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" }, "tslint": { "version": "6.1.3", @@ -15150,12 +12161,6 @@ } } }, - "tty-browserify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", - "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", - "dev": true - }, "tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -15171,12 +12176,6 @@ "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", "dev": true }, - "type": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", - "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==", - "dev": true - }, "type-check": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", @@ -15193,9 +12192,9 @@ "dev": true }, "type-fest": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz", - "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==", + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", "dev": true }, "type-is": { @@ -15208,10 +12207,10 @@ "mime-types": "~2.1.24" } }, - "typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "typed-assert": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/typed-assert/-/typed-assert-1.0.8.tgz", + "integrity": "sha512-5NkbXZUlmCE73Fs7gvkp1XXJWHYetPkg60QnQ2NXQmBYNFxbBr2zA8GCtaH4K2s2WhOmSlgiSTmrjrcm5tnM5g==", "dev": true }, "typedarray-to-buffer": { @@ -15224,73 +12223,37 @@ } }, "typescript": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.0.5.tgz", - "integrity": "sha512-ywmr/VrTVCmNTJ6iV2LwIrfG1P+lv6luD8sUJs+2eI9NLGigaN+nUQc13iHqisq7bra9lnmUSYqbJvegraBOPQ==", + "version": "4.5.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz", + "integrity": "sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==", "dev": true }, - "unbox-primitive": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", - "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "has-bigints": "^1.0.1", - "has-symbols": "^1.0.2", - "which-boxed-primitive": "^1.0.2" - } - }, "unicode-canonical-property-names-ecmascript": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", - "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", "dev": true }, "unicode-match-property-ecmascript": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz", - "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", "dev": true, "requires": { - "unicode-canonical-property-names-ecmascript": "^1.0.4", - "unicode-property-aliases-ecmascript": "^1.0.4" + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" } }, "unicode-match-property-value-ecmascript": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz", - "integrity": "sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz", + "integrity": "sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==", "dev": true }, "unicode-property-aliases-ecmascript": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz", - "integrity": "sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg==", - "dev": true - }, - "union-value": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", - "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^2.0.1" - } - }, - "uniq": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", - "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=", - "dev": true - }, - "uniqs": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/uniqs/-/uniqs-2.0.0.tgz", - "integrity": "sha1-/+3ks2slKQaW5uFl1KWe25mOawI=", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz", + "integrity": "sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ==", "dev": true }, "unique-filename": { @@ -15311,17 +12274,6 @@ "imurmurhash": "^0.1.4" } }, - "universal-analytics": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/universal-analytics/-/universal-analytics-0.4.23.tgz", - "integrity": "sha512-lgMIH7XBI6OgYn1woDEmxhGdj8yDefMKg7GkWdeATAlQZFrMrNyxSkpDzY57iY0/6fdlzTbBV03OawvvzG+q7A==", - "dev": true, - "requires": { - "debug": "^4.1.1", - "request": "^2.88.2", - "uuid": "^3.0.0" - } - }, "universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", @@ -15334,58 +12286,6 @@ "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", "dev": true }, - "unquote": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz", - "integrity": "sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ=", - "dev": true - }, - "unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", - "dev": true, - "requires": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "dependencies": { - "has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "dev": true, - "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "dependencies": { - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "requires": { - "isarray": "1.0.0" - } - } - } - }, - "has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", - "dev": true - } - } - }, - "upath": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", - "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", - "dev": true - }, "uri-js": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz", @@ -15395,80 +12295,21 @@ "punycode": "^2.1.0" } }, - "urix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", - "dev": true - }, - "url": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", - "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", - "dev": true, - "requires": { - "punycode": "1.3.2", - "querystring": "0.2.0" - }, - "dependencies": { - "punycode": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", - "dev": true - } - } - }, "url-parse": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.3.tgz", - "integrity": "sha512-IIORyIQD9rvj0A4CLWsHkBBJuNqWpFQe224b6j9t/ABmquIS0qDU2pY6kl6AuOrL5OkCXHMCFNe1jBcuAggjvQ==", + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", "requires": { "querystringify": "^2.1.1", "requires-port": "^1.0.0" } }, - "use": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", - "dev": true - }, - "util": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", - "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", - "dev": true, - "requires": { - "inherits": "2.0.3" - }, - "dependencies": { - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - } - } - }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true }, - "util.promisify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.1.tgz", - "integrity": "sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.2", - "has-symbols": "^1.0.1", - "object.getownpropertydescriptors": "^2.1.0" - } - }, "utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -15481,25 +12322,29 @@ "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", "dev": true }, + "v8-compile-cache-lib": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.0.tgz", + "integrity": "sha512-mpSYqfsFvASnSn5qMiwrr4VKfumbPyONLCOPmsR3A6pTY/r0+tSaVbgPWSAIuzbk3lCTa+FForeTiO+wBQGkjA==", + "dev": true + }, "v8-to-istanbul": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-7.1.0.tgz", - "integrity": "sha512-uXUVqNUCLa0AH1vuVxzi+MI4RfxEOKt9pBgKwHbgH7st8Kv2P1m+jvWNnektzBh5QShF3ODgKmUFCf38LnVz1g==", + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz", + "integrity": "sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w==", "dev": true, "requires": { "@types/istanbul-lib-coverage": "^2.0.1", "convert-source-map": "^1.6.0", "source-map": "^0.7.3" - } - }, - "validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" + }, + "dependencies": { + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true + } } }, "validate-npm-package-name": { @@ -15517,12 +12362,6 @@ "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", "dev": true }, - "vendors": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.4.tgz", - "integrity": "sha512-/juG65kTL4Cy2su4P8HjtkTxk6VmJDiOPBufWniqQ6wknac6jNiXS9vU+hO3wgusiyqWlzTbVHi0dyJqRONg3w==", - "dev": true - }, "verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", @@ -15534,12 +12373,6 @@ "extsprintf": "^1.2.0" } }, - "vm-browserify": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", - "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==", - "dev": true - }, "w3c-hr-time": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", @@ -15559,254 +12392,22 @@ } }, "walker": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz", - "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", "dev": true, "requires": { - "makeerror": "1.0.x" + "makeerror": "1.0.12" } }, "watchpack": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz", - "integrity": "sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.3.1.tgz", + "integrity": "sha512-x0t0JuydIo8qCNctdDrn1OzH/qDzk2+rdCOC3YzumZ42fiMqmQ7T3xQurykYMhYfHaPHTp4ZxAx2NfUo1K6QaA==", "dev": true, "requires": { - "chokidar": "^3.4.1", - "graceful-fs": "^4.1.2", - "neo-async": "^2.5.0", - "watchpack-chokidar2": "^2.0.1" - } - }, - "watchpack-chokidar2": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz", - "integrity": "sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww==", - "dev": true, - "optional": true, - "requires": { - "chokidar": "^2.1.8" - }, - "dependencies": { - "anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", - "dev": true, - "optional": true, - "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - }, - "dependencies": { - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "optional": true, - "requires": { - "remove-trailing-separator": "^1.0.1" - } - } - } - }, - "binary-extensions": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", - "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", - "dev": true, - "optional": true - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "optional": true, - "requires": { - "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" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "optional": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "chokidar": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", - "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", - "dev": true, - "optional": true, - "requires": { - "anymatch": "^2.0.0", - "async-each": "^1.0.1", - "braces": "^2.3.2", - "fsevents": "^1.2.7", - "glob-parent": "^3.1.0", - "inherits": "^2.0.3", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "normalize-path": "^3.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.2.1", - "upath": "^1.1.1" - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "optional": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "optional": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "fsevents": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", - "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", - "dev": true, - "optional": true, - "requires": { - "bindings": "^1.5.0", - "nan": "^2.12.1" - } - }, - "glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", - "dev": true, - "optional": true, - "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "optional": true, - "requires": { - "is-extglob": "^2.1.0" - } - } - } - }, - "is-binary-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", - "dev": true, - "optional": true, - "requires": { - "binary-extensions": "^1.0.0" - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "optional": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "optional": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "optional": true, - "requires": { - "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" - } - }, - "readdirp": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", - "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", - "dev": true, - "optional": true, - "requires": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" - } - }, - "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "dev": true, - "optional": true, - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - } - } + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" } }, "wbuf": { @@ -15838,348 +12439,64 @@ } }, "webidl-conversions": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", - "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", - "dev": true + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" }, "webpack": { - "version": "4.44.2", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.44.2.tgz", - "integrity": "sha512-6KJVGlCxYdISyurpQ0IPTklv+DULv05rs2hseIXer6D7KrUicRDLFb4IUM1S6LUAKypPM/nSiVSuv8jHu1m3/Q==", + "version": "5.67.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.67.0.tgz", + "integrity": "sha512-LjFbfMh89xBDpUMgA1W9Ur6Rn/gnr2Cq1jjHFPo4v6a79/ypznSYbAyPgGhwsxBtMIaEmDD1oJoA7BEYw/Fbrw==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/helper-module-context": "1.9.0", - "@webassemblyjs/wasm-edit": "1.9.0", - "@webassemblyjs/wasm-parser": "1.9.0", - "acorn": "^6.4.1", - "ajv": "^6.10.2", - "ajv-keywords": "^3.4.1", + "@types/eslint-scope": "^3.7.0", + "@types/estree": "^0.0.50", + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/wasm-edit": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "acorn": "^8.4.1", + "acorn-import-assertions": "^1.7.6", + "browserslist": "^4.14.5", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^4.3.0", - "eslint-scope": "^4.0.3", + "enhanced-resolve": "^5.8.3", + "es-module-lexer": "^0.9.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", "json-parse-better-errors": "^1.0.2", - "loader-runner": "^2.4.0", - "loader-utils": "^1.2.3", - "memory-fs": "^0.4.1", - "micromatch": "^3.1.10", - "mkdirp": "^0.5.3", - "neo-async": "^2.6.1", - "node-libs-browser": "^2.2.1", - "schema-utils": "^1.0.0", - "tapable": "^1.1.3", - "terser-webpack-plugin": "^1.4.3", - "watchpack": "^1.7.4", - "webpack-sources": "^1.4.1" + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.1.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.1.3", + "watchpack": "^2.3.1", + "webpack-sources": "^3.2.3" }, "dependencies": { - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "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" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "cacache": { - "version": "12.0.4", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz", - "integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==", - "dev": true, - "requires": { - "bluebird": "^3.5.5", - "chownr": "^1.1.1", - "figgy-pudding": "^3.5.1", - "glob": "^7.1.4", - "graceful-fs": "^4.1.15", - "infer-owner": "^1.0.3", - "lru-cache": "^5.1.1", - "mississippi": "^3.0.0", - "mkdirp": "^0.5.1", - "move-concurrently": "^1.0.1", - "promise-inflight": "^1.0.1", - "rimraf": "^2.6.3", - "ssri": "^6.0.1", - "unique-filename": "^1.1.1", - "y18n": "^4.0.0" - } - }, - "chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "dev": true - }, - "enhanced-resolve": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.3.0.tgz", - "integrity": "sha512-3e87LvavsdxyoCfGusJnrZ5G8SLPOFeHSNpZI/ATL9a5leXo2k0w6MKnbqhdBad9qTobSfB20Ld7UmgoNbAZkQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "memory-fs": "^0.5.0", - "tapable": "^1.0.0" - }, - "dependencies": { - "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, - "requires": { - "errno": "^0.1.3", - "readable-stream": "^2.0.1" - } - } - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "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, - "requires": { - "commondir": "^1.0.1", - "make-dir": "^2.0.0", - "pkg-dir": "^3.0.0" - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-wsl": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", - "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", - "dev": true - }, - "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", - "dev": true, - "requires": { - "minimist": "^1.2.0" - } - }, - "loader-utils": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", - "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", - "dev": true, - "requires": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^1.0.1" - } - }, - "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, - "requires": { - "yallist": "^3.0.2" - } - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "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" - } - }, - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, "schema-utils": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", - "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", - "dev": true, - "requires": { - "ajv": "^6.1.0", - "ajv-errors": "^1.0.0", - "ajv-keywords": "^3.1.0" - } - }, - "serialize-javascript": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", - "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", - "dev": true, - "requires": { - "randombytes": "^2.1.0" - } - }, - "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 - }, - "ssri": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.2.tgz", - "integrity": "sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q==", - "dev": true, - "requires": { - "figgy-pudding": "^3.5.1" - } - }, - "tapable": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", - "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", - "dev": true - }, - "terser": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz", - "integrity": "sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==", - "dev": true, - "requires": { - "commander": "^2.20.0", - "source-map": "~0.6.1", - "source-map-support": "~0.5.12" - } - }, - "terser-webpack-plugin": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz", - "integrity": "sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw==", - "dev": true, - "requires": { - "cacache": "^12.0.2", - "find-cache-dir": "^2.1.0", - "is-wsl": "^1.1.0", - "schema-utils": "^1.0.0", - "serialize-javascript": "^4.0.0", - "source-map": "^0.6.1", - "terser": "^4.1.2", - "webpack-sources": "^1.4.0", - "worker-farm": "^1.7.0" - } - }, - "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - } - }, - "webpack-sources": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", - "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", - "dev": true, - "requires": { - "source-list-map": "^2.0.0", - "source-map": "~0.6.1" - } - }, - "yallist": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } } } }, "webpack-bundle-analyzer": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.4.2.tgz", - "integrity": "sha512-PIagMYhlEzFfhMYOzs5gFT55DkUdkyrJi/SxJp8EF3YMWhS+T9vvs2EoTetpk5qb6VsCq02eXTlRDOydRhDFAQ==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.5.0.tgz", + "integrity": "sha512-GUMZlM3SKwS8Z+CKeIFx7CVoHn3dXFcUAjT/dcZQQmfSZGvitPfMob2ipjai7ovFFqPvTqkEZ/leL4O0YOdAYQ==", "requires": { "acorn": "^8.0.4", "acorn-walk": "^8.0.0", "chalk": "^4.1.0", - "commander": "^6.2.0", + "commander": "^7.2.0", "gzip-size": "^6.0.0", "lodash": "^4.17.20", "opener": "^1.5.2", @@ -16187,16 +12504,6 @@ "ws": "^7.3.1" }, "dependencies": { - "acorn": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.5.0.tgz", - "integrity": "sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==" - }, - "acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==" - }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -16228,9 +12535,9 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "commander": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", - "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==" + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==" }, "has-flag": { "version": "4.0.0", @@ -16244,349 +12551,181 @@ "requires": { "has-flag": "^4.0.0" } - }, - "ws": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.5.tgz", - "integrity": "sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w==" } } }, "webpack-dev-middleware": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.7.2.tgz", - "integrity": "sha512-1xC42LxbYoqLNAhV6YzTYacicgMZQTqRd27Sim9wn5hJrX3I5nxYy1SxSd4+gjUFsz1dQFj+yEe6zEVmSkeJjw==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.0.tgz", + "integrity": "sha512-MouJz+rXAm9B1OTOYaJnn6rtD/lWZPy2ufQCH3BPs8Rloh/Du6Jze4p7AeLYHkVi0giJnYLaSGDC7S+GM9arhg==", "dev": true, "requires": { - "memory-fs": "^0.4.1", - "mime": "^2.4.4", - "mkdirp": "^0.5.1", + "colorette": "^2.0.10", + "memfs": "^3.2.2", + "mime-types": "^2.1.31", "range-parser": "^1.2.1", - "webpack-log": "^2.0.0" + "schema-utils": "^4.0.0" }, "dependencies": { - "mime": { - "version": "2.4.6", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.6.tgz", - "integrity": "sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==", + "ajv": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.10.0.tgz", + "integrity": "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3" + } + }, + "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 + }, + "mime-db": { + "version": "1.51.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", + "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==", + "dev": true + }, + "mime-types": { + "version": "2.1.34", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", + "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", + "dev": true, + "requires": { + "mime-db": "1.51.0" + } + }, + "schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + } } } }, "webpack-dev-server": { - "version": "3.11.0", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.11.0.tgz", - "integrity": "sha512-PUxZ+oSTxogFQgkTtFndEtJIPNmml7ExwufBZ9L2/Xyyd5PnOL5UreWe5ZT7IU25DSdykL9p1MLQzmLh2ljSeg==", + "version": "4.7.3", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.7.3.tgz", + "integrity": "sha512-mlxq2AsIw2ag016nixkzUkdyOE8ST2GTy34uKSABp1c4nhjZvH90D5ZRR+UOLSsG4Z3TFahAi72a3ymRtfRm+Q==", "dev": true, "requires": { - "ansi-html": "0.0.7", + "@types/bonjour": "^3.5.9", + "@types/connect-history-api-fallback": "^1.3.5", + "@types/serve-index": "^1.9.1", + "@types/sockjs": "^0.3.33", + "@types/ws": "^8.2.2", + "ansi-html-community": "^0.0.8", "bonjour": "^3.5.0", - "chokidar": "^2.1.8", + "chokidar": "^3.5.2", + "colorette": "^2.0.10", "compression": "^1.7.4", "connect-history-api-fallback": "^1.6.0", - "debug": "^4.1.1", - "del": "^4.1.1", + "default-gateway": "^6.0.3", + "del": "^6.0.0", "express": "^4.17.1", - "html-entities": "^1.3.1", - "http-proxy-middleware": "0.19.1", - "import-local": "^2.0.0", - "internal-ip": "^4.3.0", - "ip": "^1.1.5", - "is-absolute-url": "^3.0.3", - "killable": "^1.0.1", - "loglevel": "^1.6.8", - "opn": "^5.5.0", - "p-retry": "^3.0.1", - "portfinder": "^1.0.26", - "schema-utils": "^1.0.0", - "selfsigned": "^1.10.7", - "semver": "^6.3.0", + "graceful-fs": "^4.2.6", + "html-entities": "^2.3.2", + "http-proxy-middleware": "^2.0.0", + "ipaddr.js": "^2.0.1", + "open": "^8.0.9", + "p-retry": "^4.5.0", + "portfinder": "^1.0.28", + "schema-utils": "^4.0.0", + "selfsigned": "^2.0.0", "serve-index": "^1.9.1", - "sockjs": "0.3.20", - "sockjs-client": "1.4.0", + "sockjs": "^0.3.21", "spdy": "^4.0.2", - "strip-ansi": "^3.0.1", - "supports-color": "^6.1.0", - "url": "^0.11.0", - "webpack-dev-middleware": "^3.7.2", - "webpack-log": "^2.0.0", - "ws": "^6.2.1", - "yargs": "^13.3.2" + "strip-ansi": "^7.0.0", + "webpack-dev-middleware": "^5.3.0", + "ws": "^8.1.0" }, "dependencies": { + "ajv": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.10.0.tgz", + "integrity": "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3" + } + }, "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", "dev": true }, - "anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", - "dev": true, - "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - }, - "dependencies": { - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "requires": { - "remove-trailing-separator": "^1.0.1" - } - } - } - }, - "binary-extensions": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", - "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "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 }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "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" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "chokidar": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", - "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", - "dev": true, - "requires": { - "anymatch": "^2.0.0", - "async-each": "^1.0.1", - "braces": "^2.3.2", - "fsevents": "^1.2.7", - "glob-parent": "^3.1.0", - "inherits": "^2.0.3", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "normalize-path": "^3.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.2.1", - "upath": "^1.1.1" - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "fsevents": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", - "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", - "dev": true, - "optional": true, - "requires": { - "bindings": "^1.5.0", - "nan": "^2.12.1" - } - }, - "glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", - "dev": true, - "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "requires": { - "is-extglob": "^2.1.0" - } - } - } - }, - "is-absolute-url": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-3.0.3.tgz", - "integrity": "sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q==", - "dev": true - }, - "is-binary-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", - "dev": true, - "requires": { - "binary-extensions": "^1.0.0" - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "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" - } - }, - "readdirp": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", - "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" - } - }, "schema-utils": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", - "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", "dev": true, "requires": { - "ajv": "^6.1.0", - "ajv-errors": "^1.0.0", - "ajv-keywords": "^3.1.0" + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" } }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - }, "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", + "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", "dev": true, "requires": { - "ansi-regex": "^2.0.0" + "ansi-regex": "^6.0.1" } }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - }, - "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - } - } - } - }, - "webpack-log": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/webpack-log/-/webpack-log-2.0.0.tgz", - "integrity": "sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg==", - "dev": true, - "requires": { - "ansi-colors": "^3.0.0", - "uuid": "^3.3.2" - }, - "dependencies": { - "ansi-colors": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", - "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==", + "ws": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz", + "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==", "dev": true } } }, "webpack-merge": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.2.0.tgz", - "integrity": "sha512-QBglJBg5+lItm3/Lopv8KDDK01+hjdg2azEwi/4vKJ8ZmGPdtJsTpjtNNOW3a4WiqzXdCATtTudOZJngE7RKkA==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", + "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==", "dev": true, "requires": { "clone-deep": "^4.0.1", @@ -16594,56 +12733,28 @@ } }, "webpack-sources": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-2.0.1.tgz", - "integrity": "sha512-A9oYz7ANQBK5EN19rUXbvNgfdfZf5U2gP0769OXsj9CvYkCR6OHOsd6OKyEy4H38GGxpsQPKIL83NC64QY6Xmw==", - "dev": true, - "requires": { - "source-list-map": "^2.0.1", - "source-map": "^0.6.1" - }, - "dependencies": { - "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 - } - } + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true }, "webpack-subresource-integrity": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/webpack-subresource-integrity/-/webpack-subresource-integrity-1.5.1.tgz", - "integrity": "sha512-uekbQ93PZ9e7BFB8Hl9cFIVYQyQqiXp2ExKk9Zv+qZfH/zHXHrCFAfw1VW0+NqWbTWrs/HnuDrto3+tiPXh//Q==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/webpack-subresource-integrity/-/webpack-subresource-integrity-5.1.0.tgz", + "integrity": "sha512-sacXoX+xd8r4WKsy9MvH/q/vBtEHr86cpImXwyg74pFIpERKt6FmB8cXpeuh0ZLgclOlHI4Wcll7+R5L02xk9Q==", "dev": true, "requires": { - "webpack-sources": "^1.3.0" - }, - "dependencies": { - "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 - }, - "webpack-sources": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", - "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", - "dev": true, - "requires": { - "source-list-map": "^2.0.0", - "source-map": "~0.6.1" - } - } + "typed-assert": "^1.0.8" } }, "websocket-driver": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.6.5.tgz", - "integrity": "sha1-XLJVbOuF9Dc8bYI4qmkchFThOjY=", + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", "dev": true, "requires": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", "websocket-extensions": ">=0.1.1" } }, @@ -16669,38 +12780,23 @@ "dev": true }, "whatwg-url": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", - "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", - "dev": true, + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", "requires": { - "lodash": "^4.7.0", - "tr46": "^2.1.0", - "webidl-conversions": "^6.1.0" + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" } }, "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, "requires": { "isexe": "^2.0.0" } }, - "which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, - "requires": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - } - }, "which-module": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", @@ -16728,94 +12824,36 @@ "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", "dev": true }, - "worker-farm": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz", - "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==", - "dev": true, - "requires": { - "errno": "~0.1.7" - } - }, - "worker-plugin": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/worker-plugin/-/worker-plugin-5.0.0.tgz", - "integrity": "sha512-AXMUstURCxDD6yGam2r4E34aJg6kW85IiaeX72hi+I1cxyaMUtrvVY6sbfpGKAj5e7f68Acl62BjQF5aOOx2IQ==", - "dev": true, - "requires": { - "loader-utils": "^1.1.0" - }, - "dependencies": { - "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", - "dev": true, - "requires": { - "minimist": "^1.2.0" - } - }, - "loader-utils": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", - "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", - "dev": true, - "requires": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^1.0.1" - } - } - } - }, "wrap-ansi": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", - "dev": true, + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "requires": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" }, "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" + "color-convert": "^2.0.1" } }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, + "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==", "requires": { - "ansi-regex": "^4.1.0" + "color-name": "~1.1.4" } + }, + "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==" } } }, @@ -16837,12 +12875,9 @@ } }, "ws": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.2.tgz", - "integrity": "sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==", - "requires": { - "async-limiter": "~1.0.0" - } + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", + "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==" }, "xml-name-validator": { "version": "3.0.0", @@ -16872,12 +12907,6 @@ "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", "dev": true }, - "xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "dev": true - }, "y18n": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz", @@ -16891,86 +12920,54 @@ "dev": true }, "yaml": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.0.tgz", - "integrity": "sha512-yr2icI4glYaNG+KWONODapy2/jDdMSDnrONSjblABjD9B4Z5LgiircSt8m8sRZFNi08kG9Sm0uSHtEmP3zaEGg==", + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", "dev": true }, "yargs": { - "version": "13.3.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", - "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", - "dev": true, + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.3.1.tgz", + "integrity": "sha512-WUANQeVgjLbNsEmGk20f+nlHgOqzRFpiGWVaBrYGYIGANIIu3lWjoyi0fNlFmJkvfhCZ6BXINe7/W2O2bV4iaA==", "requires": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.2" + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.0.0" }, "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" } }, "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "requires": { - "ansi-regex": "^4.1.0" + "ansi-regex": "^5.0.1" } + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" } } }, "yargs-parser": { - "version": "13.1.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", - "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - }, - "dependencies": { - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - } - } + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-z9kApYUOCwoeZ78rfRYYWdiU/iNL6mwwYlkkZfJoyMR1xps+NEBX5X7XmRpxkZHhXJ6+Ey00IwKxBBSW9FIjyA==" }, "yn": { "version": "3.1.1", @@ -16978,16 +12975,13 @@ "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", "dev": true }, - "yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true - }, "zone.js": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.10.3.tgz", - "integrity": "sha512-LXVLVEq0NNOqK/fLJo3d0kfzd4sxwn2/h67/02pjCjfKDxgx1i9QqpvtHD8CrBnSSwMw5+dy11O7FRX5mkO7Cg==" + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.11.4.tgz", + "integrity": "sha512-DDh2Ab+A/B+9mJyajPjHFPWfYU1H+pdun4wnnk0OcQTNjem1XQSZ2CDW+rfZEUDjv5M19SBqAkjZi0x5wuB5Qw==", + "requires": { + "tslib": "^2.0.0" + } } } } diff --git a/UI/Web/package.json b/UI/Web/package.json index 26fb10c7f..2dbba8f3f 100644 --- a/UI/Web/package.json +++ b/UI/Web/package.json @@ -5,7 +5,7 @@ "ng": "ng", "start": "ng serve", "build": "ng build", - "prod": "ng build --prod", + "prod": "ng build --configuration production", "explore": "ng build --stats-json && webpack-bundle-analyzer dist/stats.json", "test": "jest", "test:watch": "jest --watch", @@ -16,50 +16,51 @@ "private": true, "dependencies": { "@angular-slider/ngx-slider": "^2.0.3", - "@angular/animations": "~11.0.0", - "@angular/cdk": "^12.2.3", - "@angular/common": "~11.0.0", - "@angular/compiler": "~11.0.0", - "@angular/core": "~11.0.0", - "@angular/forms": "~11.0.0", - "@angular/localize": "~11.0.0", - "@angular/platform-browser": "~11.0.0", - "@angular/platform-browser-dynamic": "~11.0.0", - "@angular/router": "~11.0.0", - "@fortawesome/fontawesome-free": "^5.15.1", - "@microsoft/signalr": "^5.0.8", - "@ng-bootstrap/ng-bootstrap": "^9.1.0", - "@ngx-lite/nav-drawer": "^0.4.6", - "@ngx-lite/util": "0.0.0", - "@types/file-saver": "^2.0.1", - "bootstrap": "^4.5.0", + "@angular/animations": "~13.2.2", + "@angular/cdk": "^13.2.2", + "@angular/common": "~13.2.2", + "@angular/compiler": "~13.2.2", + "@angular/core": "~13.2.2", + "@angular/forms": "~13.2.2", + "@angular/localize": "~13.2.2", + "@angular/platform-browser": "~13.2.2", + "@angular/platform-browser-dynamic": "~13.2.2", + "@angular/router": "~13.2.2", + "@fortawesome/fontawesome-free": "^6.0.0", + "@microsoft/signalr": "^6.0.2", + "@ng-bootstrap/ng-bootstrap": "^12.0.0", + "@ngx-lite/nav-drawer": "^0.4.7", + "@ngx-lite/util": "0.0.1", + "@popperjs/core": "^2.11.2", + "@types/file-saver": "^2.0.5", + "bootstrap": "^5.1.2", "bowser": "^2.11.0", "file-saver": "^2.0.5", "lazysizes": "^5.3.2", "ng-circle-progress": "^1.6.0", - "ng-lazyload-image": "^9.1.0", - "ngx-file-drop": "^11.1.0", - "ngx-toastr": "^13.2.1", - "rxjs": "~6.6.0", - "swiper": "^6.5.8", - "tslib": "^2.0.0", - "webpack-bundle-analyzer": "^4.4.2", - "zone.js": "~0.10.2" + "ngx-color-picker": "^12.0.0", + "ngx-file-drop": "^13.0.0", + "ngx-toastr": "^14.2.1", + "rxjs": "~7.5.4", + "swiper": "^8.0.6", + "tslib": "^2.3.1", + "webpack-bundle-analyzer": "^4.5.0", + "zone.js": "~0.11.4" }, "devDependencies": { - "@angular-devkit/build-angular": "~0.1100.0", - "@angular/cli": "^11.2.11", - "@angular/compiler-cli": "~11.0.0", - "@types/jest": "^26.0.20", - "@types/node": "^12.11.1", - "codelyzer": "^6.0.0", - "jest": "^26.6.3", - "jest-preset-angular": "^8.3.2", - "karma-coverage": "~2.0.3", + "@angular-devkit/build-angular": "~13.2.3", + "@angular/cli": "^13.2.3", + "@angular/compiler-cli": "~13.2.2", + "@types/jest": "^27.4.0", + "@types/node": "^17.0.17", + "codelyzer": "^6.0.2", + "jest": "^27.5.1", + "jest-preset-angular": "^11.1.0", + "karma-coverage": "~2.2.0", "protractor": "~7.0.0", - "ts-node": "~8.3.0", + "ts-node": "~10.5.0", "tslint": "^6.1.3", - "typescript": "~4.0.2" + "typescript": "~4.5.5" }, "jest": { "preset": "jest-preset-angular", diff --git a/UI/Web/src/app/_guards/admin.guard.ts b/UI/Web/src/app/_guards/admin.guard.ts index b88c8d51c..29ca3795e 100644 --- a/UI/Web/src/app/_guards/admin.guard.ts +++ b/UI/Web/src/app/_guards/admin.guard.ts @@ -3,7 +3,6 @@ import { CanActivate } from '@angular/router'; import { ToastrService } from 'ngx-toastr'; import { Observable } from 'rxjs'; import { map, take } from 'rxjs/operators'; -import { User } from '../_models/user'; import { AccountService } from '../_services/account.service'; @Injectable({ @@ -15,8 +14,8 @@ export class AdminGuard implements CanActivate { canActivate(): Observable { // this automaticallys subs due to being router guard return this.accountService.currentUser$.pipe(take(1), - map((user: User) => { - if (this.accountService.hasAdminRole(user)) { + map((user) => { + if (user && this.accountService.hasAdminRole(user)) { return true; } diff --git a/UI/Web/src/app/_guards/auth.guard.ts b/UI/Web/src/app/_guards/auth.guard.ts index 924f03bf2..2ed39c00d 100644 --- a/UI/Web/src/app/_guards/auth.guard.ts +++ b/UI/Web/src/app/_guards/auth.guard.ts @@ -3,7 +3,6 @@ import { CanActivate, Router } from '@angular/router'; import { ToastrService } from 'ngx-toastr'; import { Observable } from 'rxjs'; import { map, take } from 'rxjs/operators'; -import { User } from '../_models/user'; import { AccountService } from '../_services/account.service'; @Injectable({ @@ -15,7 +14,7 @@ export class AuthGuard implements CanActivate { canActivate(): Observable { return this.accountService.currentUser$.pipe(take(1), - map((user: User) => { + map((user) => { if (user) { return true; } diff --git a/UI/Web/src/app/_guards/library-access.guard.ts b/UI/Web/src/app/_guards/library-access.guard.ts index 611eb556d..8d10699f7 100644 --- a/UI/Web/src/app/_guards/library-access.guard.ts +++ b/UI/Web/src/app/_guards/library-access.guard.ts @@ -1,6 +1,6 @@ import { Injectable } from '@angular/core'; import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; -import { Observable } from 'rxjs'; +import { Observable, of } from 'rxjs'; import { MemberService } from '../_services/member.service'; @Injectable({ @@ -12,6 +12,7 @@ export class LibraryAccessGuard implements CanActivate { canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable { const libraryId = parseInt(state.url.split('library/')[1], 10); + if (isNaN(libraryId)) return of(false); return this.memberService.hasLibraryAccess(libraryId); } } diff --git a/UI/Web/src/app/_interceptors/error.interceptor.ts b/UI/Web/src/app/_interceptors/error.interceptor.ts index 2e4b50acd..a0b792045 100644 --- a/UI/Web/src/app/_interceptors/error.interceptor.ts +++ b/UI/Web/src/app/_interceptors/error.interceptor.ts @@ -1,4 +1,4 @@ -import { Injectable, OnDestroy } from '@angular/core'; +import { Injectable } from '@angular/core'; import { HttpRequest, HttpHandler, @@ -8,14 +8,12 @@ import { import { Observable, throwError } from 'rxjs'; import { Router } from '@angular/router'; import { ToastrService } from 'ngx-toastr'; -import { catchError, take } from 'rxjs/operators'; +import { catchError } from 'rxjs/operators'; import { AccountService } from '../_services/account.service'; -import { environment } from 'src/environments/environment'; @Injectable() export class ErrorInterceptor implements HttpInterceptor { - public urlKey: string = 'kavita--no-connection-url'; constructor(private router: Router, private toastr: ToastrService, private accountService: AccountService) {} @@ -44,12 +42,6 @@ export class ErrorInterceptor implements HttpInterceptor { if (this.toastr.previousToastMessage !== 'Something unexpected went wrong.') { this.toastr.error('Something unexpected went wrong.'); } - - // If we are not on no-connection, redirect there and save current url so when we refersh, we redirect back there - // if (this.router.url !== '/no-connection') { - // localStorage.setItem(this.urlKey, this.router.url); - // this.router.navigateByUrl('/no-connection'); - // } break; } return throwError(error); @@ -126,8 +118,7 @@ export class ErrorInterceptor implements HttpInterceptor { private handleAuthError(error: any) { // NOTE: Signin has error.error or error.statusText available. // if statement is due to http/2 spec issue: https://github.com/angular/angular/issues/23334 - this.accountService.currentUser$.pipe(take(1)).subscribe(user => { - this.accountService.logout(); - }); + this.accountService.logout(); + this.router.navigateByUrl('/login'); } } diff --git a/UI/Web/src/app/_interceptors/jwt.interceptor.ts b/UI/Web/src/app/_interceptors/jwt.interceptor.ts index 014a7ca41..738057425 100644 --- a/UI/Web/src/app/_interceptors/jwt.interceptor.ts +++ b/UI/Web/src/app/_interceptors/jwt.interceptor.ts @@ -7,7 +7,6 @@ import { } from '@angular/common/http'; import { Observable } from 'rxjs'; import { AccountService } from '../_services/account.service'; -import { User } from '../_models/user'; import { take } from 'rxjs/operators'; @Injectable() @@ -16,16 +15,13 @@ export class JwtInterceptor implements HttpInterceptor { constructor(private accountService: AccountService) {} intercept(request: HttpRequest, next: HttpHandler): Observable> { - let currentUser: User; // Take 1 means we don't have to unsubscribe because we take 1 then complete this.accountService.currentUser$.pipe(take(1)).subscribe(user => { - currentUser = user; - - if (currentUser) { + if (user) { request = request.clone({ setHeaders: { - Authorization: `Bearer ${currentUser.token}` + Authorization: `Bearer ${user.token}` } }); } diff --git a/UI/Web/src/app/_modals/review-series-modal/review-series-modal.component.html b/UI/Web/src/app/_modals/review-series-modal/review-series-modal.component.html index b6fbedd6c..f64ef951f 100644 --- a/UI/Web/src/app/_modals/review-series-modal/review-series-modal.component.html +++ b/UI/Web/src/app/_modals/review-series-modal/review-series-modal.component.html @@ -2,29 +2,29 @@

    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 baAr_T1qJ{B000;O7yx()006P*0{{R3d&Vg- diff --git a/API.Tests/Services/Test Data/BookService/EPUB/content.opf b/API.Tests/Services/Test Data/BookService/EPUB/content.opf new file mode 100644 index 000000000..74e62677a --- /dev/null +++ b/API.Tests/Services/Test Data/BookService/EPUB/content.opf @@ -0,0 +1,81 @@ + + + + + Public domain in the USA. + http://www.gutenberg.org/64999 + Roger Starbuck + The Golden Harpoon / Lost Among the Floes + en + 2021-04-05 + 2021-04-05T23:00:07.039989+00:00 + https://www.gutenberg.org/files/64999/64999-h/64999-h.htm + Book Description + Genre1, Genre2 + Junya Inoue + Inoue, Junya + aut + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/API.Tests/generate_test_data.py b/API.Tests/generate_test_data.py deleted file mode 100644 index 69652969a..000000000 --- a/API.Tests/generate_test_data.py +++ /dev/null @@ -1,80 +0,0 @@ -""" This script should be run on a directory which will generate a test case file - that can be loaded into the renametest.py""" -import os -from pathlib import Path -import shutil - -verbose = False - -def print_log(val): - if verbose: - print(val) - - -def create_test_base(file, root_dir): - """ Creates and returns a new base directory for data creation for a given testcase.""" - base_dir = os.path.split(file.split('-testcase.txt')[0])[-1] - print_log('base_dir: {0}'.format(base_dir)) - new_dir = os.path.join(root_dir, base_dir) - print_log('new dir: {0}'.format(new_dir)) - p = Path(new_dir) - if not p.exists(): - os.mkdir(new_dir) - - return new_dir - - - -def generate_data(file, root_dir): - ''' Generates directories and fake files for testing against ''' - - base_dir = '' - if file.endswith('-testcase.txt'): - base_dir = create_test_base(file, root_dir) - - files_to_create = [] - with open(file, 'r') as in_file: - files_to_create = in_file.read().splitlines() - - for filepath in files_to_create: - for part in os.path.split(filepath): - part_path = os.path.join(base_dir, part) - print_log('Checking if {0} exists '.format(part_path)) - p = Path(part_path) - - if not p.exists(): - print_log('Creating: {0}'.format(part)) - - if p.suffix != '': - with open(os.path.join(root_dir, base_dir + '/' + filepath), 'w+') as f: - f.write('') - else: - os.mkdir(part_path) - -def clean_up_generated_data(root_dir): - for root, dirs, files in os.walk(root_dir): - for dir in dirs: - shutil.rmtree(os.path.join(root, dir)) - for file in files: - if not file.endswith('-testcase.txt'): - print_log('Removing {0}'.format(os.path.join(root, file))) - os.remove(os.path.join(root, file)) - - -def generate_test_file(): - root_dir = os.path.abspath('.') - current_folder = os.path.split(root_dir)[-1] - out_files = [] - for root, _, files in os.walk(root_dir): - for file in files: - if not file.endswith('-testcase.txt'): - filename = os.path.join(root.replace(root_dir, ''), file) # root_dir or root_dir + '//'? - out_files.append(filename) - - with open(os.path.join(root_dir, current_folder + '-testcase.txt'), 'w+') as f: - for filename in out_files: - f.write(filename + '\n') - -if __name__ == '__main__': - verbose = True - generate_test_file() \ No newline at end of file diff --git a/API/API.csproj b/API/API.csproj index d6f059830..fbf15067e 100644 --- a/API/API.csproj +++ b/API/API.csproj @@ -2,7 +2,7 @@ Default - net5.0 + net6.0 true Linux @@ -36,39 +36,41 @@ - - + + - - + + - + - - - + + + - + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - + + + + + - - + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - + + + + diff --git a/API/API.csproj.DotSettings b/API/API.csproj.DotSettings index 80aad93c5..c7410bba2 100644 --- a/API/API.csproj.DotSettings +++ b/API/API.csproj.DotSettings @@ -1,2 +1,3 @@  - True \ No newline at end of file + True + True \ No newline at end of file diff --git a/API/Comparators/ChapterSortComparer.cs b/API/Comparators/ChapterSortComparer.cs index 3791e05ff..189919a33 100644 --- a/API/Comparators/ChapterSortComparer.cs +++ b/API/Comparators/ChapterSortComparer.cs @@ -8,7 +8,7 @@ namespace API.Comparators public class ChapterSortComparer : IComparer { ///