From 744540dda949aa13ce6f5eb758205574a89df004 Mon Sep 17 00:00:00 2001 From: "Anthony D. Mays" Date: Fri, 2 May 2025 05:43:57 +0000 Subject: [PATCH 1/4] feat: adds lesson_26 homework and lesson_27 pre-work Signed-off-by: Anthony D. Mays --- lesson_26/README.md | 47 +- lesson_26/api/java/.gitattributes | 9 + lesson_26/api/java/.gitignore | 5 + lesson_26/api/java/api_app/build.gradle.kts | 79 + lesson_26/api/java/api_app/lombok.config | 2 + .../codedifferently/lesson26/Lesson26.java | 38 + .../lesson26/cli/LibraryApp.java | 190 + .../lesson26/cli/LibraryCommand.java | 28 + .../lesson26/cli/LibrarySearchCommand.java | 28 + .../factory/LibraryCsvDataLoader.java | 126 + .../lesson26/factory/LibraryDataLoader.java | 15 + .../lesson26/factory/LibraryDbDataLoader.java | 26 + .../lesson26/factory/LibraryFactory.java | 103 + .../factory/LibraryJsonDataLoader.java | 28 + .../lesson26/library/Book.java | 77 + .../codedifferently/lesson26/library/Dvd.java | 20 + .../lesson26/library/Librarian.java | 13 + .../lesson26/library/Library.java | 300 + .../library/LibraryConfiguration.java | 16 + .../lesson26/library/LibraryGuest.java | 45 + .../lesson26/library/LibraryGuestBase.java | 75 + .../lesson26/library/LibraryInfo.java | 20 + .../lesson26/library/Magazine.java | 25 + .../lesson26/library/MediaItem.java | 53 + .../lesson26/library/MediaItemBase.java | 93 + .../lesson26/library/MediaType.java | 28 + .../lesson26/library/Newspaper.java | 25 + .../lesson26/library/Patron.java | 20 + .../exceptions/LibraryNotSetException.java | 7 + .../MediaItemCheckedOutException.java | 7 + .../exceptions/WrongLibraryException.java | 7 + .../library/search/CatalogSearcher.java | 31 + .../library/search/SearchCriteria.java | 24 + .../lesson26/library/search/Searchable.java | 11 + .../lesson26/models/AuthorsConverter.java | 18 + .../lesson26/models/CheckoutModel.java | 15 + .../lesson26/models/LibraryDataModel.java | 61 + .../lesson26/models/LibraryGuestModel.java | 19 + .../lesson26/models/MediaItemModel.java | 29 + .../repository/LibraryGuestRepository.java | 10 + .../repository/MediaItemRepository.java | 11 + .../lesson26/web/CreateMediaItemRequest.java | 17 + .../lesson26/web/CreateMediaItemResponse.java | 10 + .../lesson26/web/GetMediaItemsResponse.java | 12 + .../lesson26/web/GlobalExceptionHandler.java | 33 + .../lesson26/web/MediaItemRequest.java | 52 + .../lesson26/web/MediaItemResponse.java | 40 + .../lesson26/web/MediaItemsController.java | 34 + .../lesson26/web/WebConfiguration.java | 11 + .../src/main/resources/application.yml | 9 + .../main/resources/csv/checked_out_items.csv | 5 + .../api_app/src/main/resources/csv/guests.csv | 6 + .../src/main/resources/csv/media_items.csv | 32 + .../api_app/src/main/resources/json/data.json | 268 + .../main/resources/queries/anthonydmays.sql | 1 + .../api_app/src/main/resources/sqlite/data.db | Bin 0 -> 16384 bytes .../lesson26/Lesson26Test.java | 13 + .../factory/LibraryCsvDataLoaderTest.java | 84 + .../factory/LibraryJsonDataLoaderTest.java | 76 + .../lesson26/library/BookTest.java | 94 + .../lesson26/library/LibraryTest.java | 353 + .../lesson26/library/MediaItemBaseTest.java | 94 + .../lesson26/library/PatronTest.java | 93 + .../web/MediaItemsControllerTest.java | 125 + .../java/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 43583 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 + lesson_26/api/java/gradlew | 252 + lesson_26/api/java/gradlew.bat | 94 + lesson_26/api/java/settings.gradle.kts | 13 + .../api/javascript/api_app/.editorconfig | 9 + lesson_26/api/javascript/api_app/.eslintrc.js | 30 + lesson_26/api/javascript/api_app/.gitignore | 56 + lesson_26/api/javascript/api_app/.prettierrc | 4 + lesson_26/api/javascript/api_app/README.md | 99 + .../api/javascript/api_app/nest-cli.json | 8 + .../api/javascript/api_app/package-lock.json | 9201 +++++++++++++++++ lesson_26/api/javascript/api_app/package.json | 72 + .../javascript/api_app/resources/data.json | 254 + .../api_app/src/app.controller.spec.ts | 22 + .../javascript/api_app/src/app.controller.ts | 12 + .../api/javascript/api_app/src/app.module.ts | 11 + .../api/javascript/api_app/src/app.service.ts | 8 + .../api_app/src/data/data.module.ts | 14 + .../api/javascript/api_app/src/data/index.ts | 5 + .../api_app/src/data/library_data_loader.ts | 14 + .../src/data/library_json_data_loader.ts | 12 + .../javascript/api_app/src/library/book.ts | 53 + .../api/javascript/api_app/src/library/dvd.ts | 16 + .../javascript/api_app/src/library/index.ts | 11 + .../api_app/src/library/librarian.ts | 12 + .../api_app/src/library/library.module.ts | 23 + .../api_app/src/library/library.service.ts | 155 + .../javascript/api_app/src/library/library.ts | 43 + .../api_app/src/library/library_factory.ts | 109 + .../api_app/src/library/library_guest.ts | 41 + .../api_app/src/library/library_guest_base.ts | 48 + .../api_app/src/library/magazine.ts | 20 + .../api_app/src/library/media_item.ts | 50 + .../api_app/src/library/media_item_base.ts | 69 + .../api_app/src/library/media_type.ts | 7 + .../api_app/src/library/newspaper.ts | 20 + .../javascript/api_app/src/library/patron.ts | 12 + .../src/library/search/catalog_searcher.ts | 14 + .../api_app/src/library/search/index.ts | 2 + .../src/library/search/search_criteria.ts | 13 + .../api_app/src/library/search/searchable.ts | 11 + lesson_26/api/javascript/api_app/src/main.ts | 23 + .../javascript/api_app/src/models/index.ts | 5 + .../api_app/src/models/library_data_model.ts | 86 + .../src/web/create_media_item_request.ts | 5 + .../src/web/create_media_item_response.ts | 6 + .../src/web/get_media_items_response.ts | 5 + .../api_app/src/web/media_item_request.ts | 42 + .../api_app/src/web/media_item_response.ts | 31 + .../api_app/src/web/media_items.controller.ts | 77 + .../javascript/api_app/src/web/web.module.ts | 9 + .../javascript/api_app/test/app.e2e-spec.ts | 24 + .../api/javascript/api_app/test/jest-e2e.json | 9 + .../api_app/test/web/media_items.e2e-spec.ts | 100 + .../javascript/api_app/tsconfig.build.json | 4 + .../api/javascript/api_app/tsconfig.json | 22 + lesson_26/debug.png | Bin 0 -> 147441 bytes lesson_27/README.md | 16 + 123 files changed, 14635 insertions(+), 1 deletion(-) create mode 100644 lesson_26/api/java/.gitattributes create mode 100644 lesson_26/api/java/.gitignore create mode 100644 lesson_26/api/java/api_app/build.gradle.kts create mode 100644 lesson_26/api/java/api_app/lombok.config create mode 100644 lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/Lesson26.java create mode 100644 lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/cli/LibraryApp.java create mode 100644 lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/cli/LibraryCommand.java create mode 100644 lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/cli/LibrarySearchCommand.java create mode 100644 lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/factory/LibraryCsvDataLoader.java create mode 100644 lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/factory/LibraryDataLoader.java create mode 100644 lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/factory/LibraryDbDataLoader.java create mode 100644 lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/factory/LibraryFactory.java create mode 100644 lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/factory/LibraryJsonDataLoader.java create mode 100644 lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/Book.java create mode 100644 lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/Dvd.java create mode 100644 lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/Librarian.java create mode 100644 lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/Library.java create mode 100644 lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/LibraryConfiguration.java create mode 100644 lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/LibraryGuest.java create mode 100644 lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/LibraryGuestBase.java create mode 100644 lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/LibraryInfo.java create mode 100644 lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/Magazine.java create mode 100644 lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/MediaItem.java create mode 100644 lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/MediaItemBase.java create mode 100644 lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/MediaType.java create mode 100644 lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/Newspaper.java create mode 100644 lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/Patron.java create mode 100644 lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/exceptions/LibraryNotSetException.java create mode 100644 lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/exceptions/MediaItemCheckedOutException.java create mode 100644 lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/exceptions/WrongLibraryException.java create mode 100644 lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/search/CatalogSearcher.java create mode 100644 lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/search/SearchCriteria.java create mode 100644 lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/search/Searchable.java create mode 100644 lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/models/AuthorsConverter.java create mode 100644 lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/models/CheckoutModel.java create mode 100644 lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/models/LibraryDataModel.java create mode 100644 lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/models/LibraryGuestModel.java create mode 100644 lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/models/MediaItemModel.java create mode 100644 lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/repository/LibraryGuestRepository.java create mode 100644 lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/repository/MediaItemRepository.java create mode 100644 lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/web/CreateMediaItemRequest.java create mode 100644 lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/web/CreateMediaItemResponse.java create mode 100644 lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/web/GetMediaItemsResponse.java create mode 100644 lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/web/GlobalExceptionHandler.java create mode 100644 lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/web/MediaItemRequest.java create mode 100644 lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/web/MediaItemResponse.java create mode 100644 lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/web/MediaItemsController.java create mode 100644 lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/web/WebConfiguration.java create mode 100644 lesson_26/api/java/api_app/src/main/resources/application.yml create mode 100644 lesson_26/api/java/api_app/src/main/resources/csv/checked_out_items.csv create mode 100644 lesson_26/api/java/api_app/src/main/resources/csv/guests.csv create mode 100644 lesson_26/api/java/api_app/src/main/resources/csv/media_items.csv create mode 100644 lesson_26/api/java/api_app/src/main/resources/json/data.json create mode 100644 lesson_26/api/java/api_app/src/main/resources/queries/anthonydmays.sql create mode 100644 lesson_26/api/java/api_app/src/main/resources/sqlite/data.db create mode 100644 lesson_26/api/java/api_app/src/test/java/com/codedifferently/lesson26/Lesson26Test.java create mode 100644 lesson_26/api/java/api_app/src/test/java/com/codedifferently/lesson26/factory/LibraryCsvDataLoaderTest.java create mode 100644 lesson_26/api/java/api_app/src/test/java/com/codedifferently/lesson26/factory/LibraryJsonDataLoaderTest.java create mode 100644 lesson_26/api/java/api_app/src/test/java/com/codedifferently/lesson26/library/BookTest.java create mode 100644 lesson_26/api/java/api_app/src/test/java/com/codedifferently/lesson26/library/LibraryTest.java create mode 100644 lesson_26/api/java/api_app/src/test/java/com/codedifferently/lesson26/library/MediaItemBaseTest.java create mode 100644 lesson_26/api/java/api_app/src/test/java/com/codedifferently/lesson26/library/PatronTest.java create mode 100644 lesson_26/api/java/api_app/src/test/java/com/codedifferently/lesson26/web/MediaItemsControllerTest.java create mode 100644 lesson_26/api/java/gradle/wrapper/gradle-wrapper.jar create mode 100644 lesson_26/api/java/gradle/wrapper/gradle-wrapper.properties create mode 100755 lesson_26/api/java/gradlew create mode 100644 lesson_26/api/java/gradlew.bat create mode 100644 lesson_26/api/java/settings.gradle.kts create mode 100644 lesson_26/api/javascript/api_app/.editorconfig create mode 100644 lesson_26/api/javascript/api_app/.eslintrc.js create mode 100644 lesson_26/api/javascript/api_app/.gitignore create mode 100644 lesson_26/api/javascript/api_app/.prettierrc create mode 100644 lesson_26/api/javascript/api_app/README.md create mode 100644 lesson_26/api/javascript/api_app/nest-cli.json create mode 100644 lesson_26/api/javascript/api_app/package-lock.json create mode 100644 lesson_26/api/javascript/api_app/package.json create mode 100644 lesson_26/api/javascript/api_app/resources/data.json create mode 100644 lesson_26/api/javascript/api_app/src/app.controller.spec.ts create mode 100644 lesson_26/api/javascript/api_app/src/app.controller.ts create mode 100644 lesson_26/api/javascript/api_app/src/app.module.ts create mode 100644 lesson_26/api/javascript/api_app/src/app.service.ts create mode 100644 lesson_26/api/javascript/api_app/src/data/data.module.ts create mode 100644 lesson_26/api/javascript/api_app/src/data/index.ts create mode 100644 lesson_26/api/javascript/api_app/src/data/library_data_loader.ts create mode 100644 lesson_26/api/javascript/api_app/src/data/library_json_data_loader.ts create mode 100644 lesson_26/api/javascript/api_app/src/library/book.ts create mode 100644 lesson_26/api/javascript/api_app/src/library/dvd.ts create mode 100644 lesson_26/api/javascript/api_app/src/library/index.ts create mode 100644 lesson_26/api/javascript/api_app/src/library/librarian.ts create mode 100644 lesson_26/api/javascript/api_app/src/library/library.module.ts create mode 100644 lesson_26/api/javascript/api_app/src/library/library.service.ts create mode 100644 lesson_26/api/javascript/api_app/src/library/library.ts create mode 100644 lesson_26/api/javascript/api_app/src/library/library_factory.ts create mode 100644 lesson_26/api/javascript/api_app/src/library/library_guest.ts create mode 100644 lesson_26/api/javascript/api_app/src/library/library_guest_base.ts create mode 100644 lesson_26/api/javascript/api_app/src/library/magazine.ts create mode 100644 lesson_26/api/javascript/api_app/src/library/media_item.ts create mode 100644 lesson_26/api/javascript/api_app/src/library/media_item_base.ts create mode 100644 lesson_26/api/javascript/api_app/src/library/media_type.ts create mode 100644 lesson_26/api/javascript/api_app/src/library/newspaper.ts create mode 100644 lesson_26/api/javascript/api_app/src/library/patron.ts create mode 100644 lesson_26/api/javascript/api_app/src/library/search/catalog_searcher.ts create mode 100644 lesson_26/api/javascript/api_app/src/library/search/index.ts create mode 100644 lesson_26/api/javascript/api_app/src/library/search/search_criteria.ts create mode 100644 lesson_26/api/javascript/api_app/src/library/search/searchable.ts create mode 100644 lesson_26/api/javascript/api_app/src/main.ts create mode 100644 lesson_26/api/javascript/api_app/src/models/index.ts create mode 100644 lesson_26/api/javascript/api_app/src/models/library_data_model.ts create mode 100644 lesson_26/api/javascript/api_app/src/web/create_media_item_request.ts create mode 100644 lesson_26/api/javascript/api_app/src/web/create_media_item_response.ts create mode 100644 lesson_26/api/javascript/api_app/src/web/get_media_items_response.ts create mode 100644 lesson_26/api/javascript/api_app/src/web/media_item_request.ts create mode 100644 lesson_26/api/javascript/api_app/src/web/media_item_response.ts create mode 100644 lesson_26/api/javascript/api_app/src/web/media_items.controller.ts create mode 100644 lesson_26/api/javascript/api_app/src/web/web.module.ts create mode 100644 lesson_26/api/javascript/api_app/test/app.e2e-spec.ts create mode 100644 lesson_26/api/javascript/api_app/test/jest-e2e.json create mode 100644 lesson_26/api/javascript/api_app/test/web/media_items.e2e-spec.ts create mode 100644 lesson_26/api/javascript/api_app/tsconfig.build.json create mode 100644 lesson_26/api/javascript/api_app/tsconfig.json create mode 100644 lesson_26/debug.png create mode 100644 lesson_27/README.md diff --git a/lesson_26/README.md b/lesson_26/README.md index 18ad558a9..c515729cf 100644 --- a/lesson_26/README.md +++ b/lesson_26/README.md @@ -19,4 +19,49 @@ Please review the following resources before lecture: ## Homework -- TODO(anthonydmays): Add details here. \ No newline at end of file +- [ ] Complete the [Creating a Library API](#creating-a-library-api) assignment. +- [ ] Do pre-work for [lesson 27](/lesson_27/). + +### Creating a Library API + +We are continuing to build atop the foundation of our library app. For this assignment, you will help implement the API that will be used by a yet-to-come front-end app. + +* You will implement the [MediaItemsController][controller-file] to enable the following API: + * `GET /items` - Retrieves a list of media items + * `POST /items` - Creates a new media item + * `GET /items/:id` - Retrieves a single media item with the given ID. + * `DELETE /items/:id` - Deletes a single media item with the given ID. +* Study the tests in [MediaItemsControllerTest][controller-test-file] to understand what you should accept and return in the API. +* You should not need to make any code changes outside of the `com.codedifferently.lesson26.web` package. + +#### Running the API + +You can run the server using the usual `./gradlew run` command from the `api/java` directory. If you want to test that the server is running correctly, you can use `curl` like so: + +```bash +curl http://localhost:3001/items | json_pp +``` + +The project also includes an OpenAPI user interface (Swagger) for navigating the API. Just visit http://localhost:3001/swagger-ui.html to access it. + +Alternatively, you can also test the API using the tool [Postman][postman-link]. I recommend installing this tool to make it easier to test things. + +#### Debugging the API + +Remember that you can debug the API by visiting the main function in [Lesson26.java][main-file] and clicking `Debug main`. You'll be able to set breakpoints in your code to see what's happening and fix issues. + +![Debugging the API](./debug.png) + + +#### TypeScript API + +This project also includes a fully functioning TypeScript version of the Java project. You can visit `api/javascript/api_app` to execute it using `npm start` and view the OpenAPI documentation at http://localhost:3000/api (note that it runs on port 3000). + +## Additional resources + +* [gRPC vs REST: Comparing API Styles in Practice (Article)](https://dev.to/anthonydmays/grpc-vs-rest-comparing-api-styles-in-practice-4bl): This article explains why the stuff most people call REST isn't actually. + +[controller-file]: ./api/java/api_app/src/main/java/com/codedifferently/lesson26/web/MediaItemsController.java +[controller-test-file]: ./api/java/api_app/src/test/java/com/codedifferently/lesson26/web/MediaItemsControllerTest.java +[postman-link]: https://www.postman.com/downloads/ +[main-file]: ./api/java/api_app/src/main/java/com/codedifferently/lesson26/Lesson26.java \ No newline at end of file diff --git a/lesson_26/api/java/.gitattributes b/lesson_26/api/java/.gitattributes new file mode 100644 index 000000000..097f9f98d --- /dev/null +++ b/lesson_26/api/java/.gitattributes @@ -0,0 +1,9 @@ +# +# https://help.github.com/articles/dealing-with-line-endings/ +# +# Linux start script should use lf +/gradlew text eol=lf + +# These are Windows script files and should use crlf +*.bat text eol=crlf + diff --git a/lesson_26/api/java/.gitignore b/lesson_26/api/java/.gitignore new file mode 100644 index 000000000..1b6985c00 --- /dev/null +++ b/lesson_26/api/java/.gitignore @@ -0,0 +1,5 @@ +# Ignore Gradle project-specific cache directory +.gradle + +# Ignore Gradle build output directory +build diff --git a/lesson_26/api/java/api_app/build.gradle.kts b/lesson_26/api/java/api_app/build.gradle.kts new file mode 100644 index 000000000..ac0c0e680 --- /dev/null +++ b/lesson_26/api/java/api_app/build.gradle.kts @@ -0,0 +1,79 @@ +plugins { + // Apply the application plugin to add support for building a CLI application in Java. + application + eclipse + id("com.diffplug.spotless") version "6.25.0" + id("org.springframework.boot") version "3.4.0" + id("com.adarshr.test-logger") version "4.0.0" + id("io.freefair.lombok") version "8.6" +} + +apply(plugin = "io.spring.dependency-management") + +repositories { + // Use Maven Central for resolving dependencies. + mavenCentral() +} + +dependencies { + // Use JUnit Jupiter for testing. + testImplementation("com.codedifferently.instructional:instructional-lib") + testImplementation("org.junit.jupiter:junit-jupiter:5.11.3") + testImplementation("org.springframework.boot:spring-boot-starter-test") + testImplementation("org.assertj:assertj-core:3.26.3") + testImplementation("at.favre.lib:bcrypt:0.10.2") + testImplementation("org.springframework.boot:spring-boot-starter-test") + + // This dependency is used by the application. + implementation("com.codedifferently.instructional:instructional-lib") + implementation("com.google.guava:guava:33.3.1-jre") + implementation("com.google.code.gson:gson:2.11.0") + implementation("commons-cli:commons-cli:1.6.0") + implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:2.6.0") + implementation("org.springframework.boot:spring-boot-starter") + implementation("org.springframework.boot:spring-boot-starter-data-jpa") + implementation("org.springframework.boot:spring-boot-starter-validation") + implementation("org.springframework.boot:spring-boot-starter-web") + compileOnly("org.springframework.boot:spring-boot-devtools") + implementation("com.opencsv:opencsv:5.9") + implementation("org.apache.commons:commons-csv:1.10.0") + implementation("org.xerial:sqlite-jdbc:3.36.0") + implementation("org.hibernate.orm:hibernate-community-dialects:6.2.7.Final") +} + +application { + // Define the main class for the application. + mainClass.set("com.codedifferently.lesson26.Lesson26") +} + +tasks.named("run") { + standardInput = System.`in` +} + +tasks.named("test") { + // Use JUnit Platform for unit tests. + useJUnitPlatform() +} + + +configure { + + format("misc", { + // define the files to apply `misc` to + target("*.gradle", ".gitattributes", ".gitignore") + + // define the steps to apply to those files + trimTrailingWhitespace() + indentWithTabs() // or spaces. Takes an integer argument if you don't like 4 + endWithNewline() + }) + + java { + // don't need to set target, it is inferred from java + + // apply a specific flavor of google-java-format + googleJavaFormat() + // fix formatting of type annotations + formatAnnotations() + } +} \ No newline at end of file diff --git a/lesson_26/api/java/api_app/lombok.config b/lesson_26/api/java/api_app/lombok.config new file mode 100644 index 000000000..6aa51d71e --- /dev/null +++ b/lesson_26/api/java/api_app/lombok.config @@ -0,0 +1,2 @@ +# This file is generated by the 'io.freefair.lombok' Gradle plugin +config.stopBubbling = true diff --git a/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/Lesson26.java b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/Lesson26.java new file mode 100644 index 000000000..7a283bf69 --- /dev/null +++ b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/Lesson26.java @@ -0,0 +1,38 @@ +package com.codedifferently.lesson26; + +import com.codedifferently.lesson26.cli.LibraryApp; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Configuration; + +@Configuration +@SpringBootApplication(scanBasePackages = "com.codedifferently") +public class Lesson26 implements CommandLineRunner { + @Autowired private LibraryApp libraryApp; + + public static void main(String[] args) { + var application = new SpringApplication(Lesson26.class); + application.run(args); + } + + @Override + public void run(String... args) throws Exception { + // Don't run as an app if we're running as a JUnit test. + if (isJUnitTest()) { + return; + } + + libraryApp.run(args); + } + + private static boolean isJUnitTest() { + for (StackTraceElement element : Thread.currentThread().getStackTrace()) { + if (element.getClassName().startsWith("org.junit.")) { + return true; + } + } + return false; + } +} diff --git a/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/cli/LibraryApp.java b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/cli/LibraryApp.java new file mode 100644 index 000000000..f96a08191 --- /dev/null +++ b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/cli/LibraryApp.java @@ -0,0 +1,190 @@ +package com.codedifferently.lesson26.cli; + +import com.codedifferently.lesson26.factory.LibraryDataLoader; +import com.codedifferently.lesson26.library.Book; +import com.codedifferently.lesson26.library.Library; +import com.codedifferently.lesson26.library.LibraryInfo; +import com.codedifferently.lesson26.library.MediaItem; +import com.codedifferently.lesson26.library.search.SearchCriteria; +import java.util.Map; +import java.util.Scanner; +import java.util.Set; +import java.util.UUID; +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.DefaultParser; +import org.apache.commons.cli.HelpFormatter; +import org.apache.commons.cli.Option; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public final class LibraryApp { + @Autowired private Library library; + + public void run(String[] args) throws Exception { + // Show stats about the loaded library to the user. + printLibraryInfo(library); + + try (var scanner = new Scanner(System.in)) { + LibraryCommand command; + // Main application loop. + while ((command = promptForCommand(scanner)) != LibraryCommand.EXIT) { + switch (command) { + case SEARCH -> doSearch(scanner, library); + default -> System.out.println("\nNot ready yet, coming soon!"); + } + } + } + } + + private void printLibraryInfo(Library library) { + LibraryInfo info = library.getInfo(); + Map> checkedOutItemsByGuest = info.getCheckedOutItemsByGuest(); + int numCheckedOutItems = checkedOutItemsByGuest.values().stream().mapToInt(Set::size).sum(); + System.out.println(); + System.out.println("========================================"); + System.out.println("Library id: " + library.getId()); + System.out.println("Number of items: " + info.getItems().size()); + System.out.println("Number of guests: " + info.getGuests().size()); + System.out.println("Number of checked out items: " + numCheckedOutItems); + System.out.println("========================================"); + System.out.println(); + } + + private static LibraryDataLoader getLoaderOrDefault( + String[] args, LibraryDataLoader defaultLoader) throws Exception { + String loaderType = getLoaderFromCommandLine(args); + return loaderType == null + ? defaultLoader + : Class.forName(loaderType) + .asSubclass(LibraryDataLoader.class) + .getDeclaredConstructor() + .newInstance(); + } + + private static String getLoaderFromCommandLine(String[] args) throws IllegalArgumentException { + Options options = new Options(); + Option input = new Option("l", "loader", true, "data loader type"); + input.setRequired(false); + options.addOption(input); + CommandLineParser parser = new DefaultParser(); + HelpFormatter formatter = new HelpFormatter(); + try { + CommandLine cmd = parser.parse(options, args); + return cmd.getOptionValue("loader"); + } catch (ParseException e) { + System.out.println(); + System.out.println(e.getMessage()); + formatter.printHelp("utility-name", options); + + System.exit(1); + } + return null; + } + + private static LibraryCommand promptForCommand(Scanner scanner) { + var command = LibraryCommand.UNKNOWN; + while (command == LibraryCommand.UNKNOWN) { + printMenu(); + var input = scanner.nextLine(); + try { + command = LibraryCommand.fromValue(Integer.parseInt(input.trim())); + } catch (IllegalArgumentException e) { + System.out.println("Invalid command: " + input); + } + } + return command; + } + + private static void printMenu() { + System.out.println("\nEnter the number of the desired command:"); + System.out.println("1) << EXIT"); + System.out.println("2) SEARCH"); + System.out.println("3) CHECKOUT"); + System.out.println("4) RETURN"); + System.out.print("command> "); + } + + private void doSearch(Scanner scanner, Library library) { + LibrarySearchCommand command = promptForSearchCommand(scanner); + if (command == LibrarySearchCommand.RETURN) { + return; + } + SearchCriteria criteria = getSearchCriteria(scanner, command); + Set results = library.search(criteria); + printSearchResults(results); + } + + private LibrarySearchCommand promptForSearchCommand(Scanner scanner) { + var command = LibrarySearchCommand.UNKNOWN; + while (command == LibrarySearchCommand.UNKNOWN) { + printSearchMenu(); + var input = scanner.nextLine(); + try { + command = LibrarySearchCommand.fromValue(Integer.parseInt(input.trim())); + } catch (IllegalArgumentException e) { + System.out.println("Invalid command: " + input); + } + } + return command; + } + + private void printSearchMenu() { + System.out.println("\nEnter the number of the desired search criteria:"); + System.out.println("1) << RETURN"); + System.out.println("2) TITLE"); + System.out.println("3) AUTHOR"); + System.out.println("4) TYPE"); + System.out.print("search> "); + } + + private SearchCriteria getSearchCriteria(Scanner scanner, LibrarySearchCommand command) { + System.out.println(); + switch (command) { + case TITLE -> { + System.out.println("Enter the title to search for: "); + System.out.print("title> "); + var title = scanner.nextLine(); + return SearchCriteria.builder().title(title).build(); + } + case AUTHOR -> { + System.out.println("Enter the author to search for: "); + System.out.print("author> "); + var author = scanner.nextLine(); + return SearchCriteria.builder().author(author).build(); + } + case TYPE -> { + System.out.println("Enter the type to search for: "); + System.out.print("type> "); + var type = scanner.nextLine(); + return SearchCriteria.builder().type(type).build(); + } + default -> System.out.println("Invalid search command: " + command); + } + return null; + } + + private void printSearchResults(Set results) { + System.out.println(); + + if (results.isEmpty()) { + System.out.println("No results found."); + return; + } + + System.out.println("Search results:\n"); + for (MediaItem item : results) { + System.out.println("ID: " + item.getId()); + System.out.println("TITLE: " + item.getTitle()); + if (item instanceof Book book) { + System.out.println("AUTHOR(S): " + String.join(", ", book.getAuthors())); + } + System.out.println("TYPE: " + item.getType().toString().toUpperCase()); + System.out.println(); + } + System.out.println("Found " + results.size() + " result(s).\n"); + } +} diff --git a/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/cli/LibraryCommand.java b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/cli/LibraryCommand.java new file mode 100644 index 000000000..7ce3db373 --- /dev/null +++ b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/cli/LibraryCommand.java @@ -0,0 +1,28 @@ +package com.codedifferently.lesson26.cli; + +public enum LibraryCommand { + UNKNOWN(0), + EXIT(1), + SEARCH(2), + CHECKOUT(3), + RETURN(4); + + private final int value; + + LibraryCommand(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + + public static LibraryCommand fromValue(int value) { + for (LibraryCommand command : LibraryCommand.values()) { + if (command.getValue() == value) { + return command; + } + } + return UNKNOWN; + } +} diff --git a/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/cli/LibrarySearchCommand.java b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/cli/LibrarySearchCommand.java new file mode 100644 index 000000000..d438fd7dd --- /dev/null +++ b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/cli/LibrarySearchCommand.java @@ -0,0 +1,28 @@ +package com.codedifferently.lesson26.cli; + +public enum LibrarySearchCommand { + UNKNOWN(0), + RETURN(1), + TITLE(2), + AUTHOR(3), + TYPE(4); + + private final int value; + + LibrarySearchCommand(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + + public static LibrarySearchCommand fromValue(int value) { + for (LibrarySearchCommand criteria : LibrarySearchCommand.values()) { + if (criteria.getValue() == value) { + return criteria; + } + } + return UNKNOWN; + } +} diff --git a/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/factory/LibraryCsvDataLoader.java b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/factory/LibraryCsvDataLoader.java new file mode 100644 index 000000000..42fa3530c --- /dev/null +++ b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/factory/LibraryCsvDataLoader.java @@ -0,0 +1,126 @@ +package com.codedifferently.lesson26.factory; + +import com.codedifferently.lesson26.library.MediaType; +import com.codedifferently.lesson26.models.CheckoutModel; +import com.codedifferently.lesson26.models.LibraryDataModel; +import com.codedifferently.lesson26.models.LibraryGuestModel; +import com.codedifferently.lesson26.models.MediaItemModel; +import java.io.FileReader; +import java.io.IOException; +import java.time.Instant; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import org.apache.commons.csv.CSVFormat; +import org.apache.commons.csv.CSVRecord; +import org.springframework.core.io.ClassPathResource; +import org.springframework.stereotype.Service; + +/** An object that loads data from a CSV and returns a LibraryDataModel object. */ +@Service +public final class LibraryCsvDataLoader implements LibraryDataLoader { + private static final String MEDIA_ITEMS_CSV_PATH = "csv/media_items.csv"; + private static final String GUESTS_CSV_PATH = "csv/guests.csv"; + private static final String CHECKED_OUT_ITEMS_CSV_PATH = "csv/checked_out_items.csv"; + + @Override + public LibraryDataModel loadData() throws IOException { + var model = new LibraryDataModel(); + model.mediaItems = loadMediaItemsFromCsv(MEDIA_ITEMS_CSV_PATH); + model.guests = loadGuestsFromCsv(GUESTS_CSV_PATH, CHECKED_OUT_ITEMS_CSV_PATH); + return model; + } + + private List loadMediaItemsFromCsv(String filePath) throws IOException { + List mediaItems = new ArrayList<>(); + + try (var reader = new FileReader(new ClassPathResource(filePath).getFile()); + var csvParser = CSVFormat.DEFAULT.withFirstRecordAsHeader().parse(reader)) { + for (CSVRecord csvRecord : csvParser) { + var item = new MediaItemModel(); + + item.type = MediaType.fromString(csvRecord.get("type")); + item.id = UUID.fromString(csvRecord.get("id")); + item.title = csvRecord.get("title"); + item.isbn = csvRecord.get("isbn"); + item.authors = List.of(csvRecord.get("authors").split(", ")); + item.pages = parseIntOrDefault(csvRecord.get("pages"), 0); + item.runtime = parseIntOrDefault(csvRecord.get("runtime"), 0); + item.edition = csvRecord.get("edition"); + + mediaItems.add(item); + } + + } catch (IOException e) { + return new ArrayList<>(); + } + + return mediaItems; + } + + private int parseIntOrDefault(String value, int defaultVal) { + try { + return Integer.parseInt(value); + } catch (NumberFormatException e) { + return defaultVal; + } + } + + private List loadGuestsFromCsv( + String guestsCsvPath, String checkedOutCsvPath) { + List guests = loadGuestRecordsFromCsv(guestsCsvPath); + Map> checkedOutItems = loadCheckoutsFromCsv(checkedOutCsvPath); + for (LibraryGuestModel guest : guests) { + if (checkedOutItems.containsKey(guest.email)) { + guest.checkedOutItems = checkedOutItems.get(guest.email); + } else { + guest.checkedOutItems = new ArrayList<>(); + } + } + return guests; + } + + private List loadGuestRecordsFromCsv(String guestsCsvPath) { + List guests = new ArrayList<>(); + + try (var reader = new FileReader(new ClassPathResource(guestsCsvPath).getFile()); + var csvParser = CSVFormat.DEFAULT.withFirstRecordAsHeader().parse(reader)) { + for (CSVRecord csvRecord : csvParser) { + var guest = new LibraryGuestModel(); + + guest.type = csvRecord.get("type"); + guest.name = csvRecord.get("name"); + guest.email = csvRecord.get("email"); + + guests.add(guest); + } + } catch (IOException e) { + return new ArrayList<>(); + } + + return guests; + } + + private Map> loadCheckoutsFromCsv(String checkedOutCsvPath) { + Map> checkoutsByGuestEmail = new HashMap<>(); + + try (var reader = new FileReader(new ClassPathResource(checkedOutCsvPath).getFile()); + var csvParser = CSVFormat.DEFAULT.withFirstRecordAsHeader().parse(reader)) { + for (CSVRecord csvRecord : csvParser) { + var checkout = new CheckoutModel(); + + checkout.itemId = UUID.fromString(csvRecord.get("item_id")); + checkout.dueDate = Instant.parse(csvRecord.get("due_date")); + + String guestEmail = csvRecord.get("email"); + checkoutsByGuestEmail.computeIfAbsent(guestEmail, e -> new ArrayList<>()).add(checkout); + } + } catch (IOException e) { + return new HashMap<>(); + } + + return checkoutsByGuestEmail; + } +} diff --git a/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/factory/LibraryDataLoader.java b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/factory/LibraryDataLoader.java new file mode 100644 index 000000000..fc80694c3 --- /dev/null +++ b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/factory/LibraryDataLoader.java @@ -0,0 +1,15 @@ +package com.codedifferently.lesson26.factory; + +import com.codedifferently.lesson26.models.LibraryDataModel; +import java.io.IOException; + +/** An object that loads data from a source and returns a LibraryDataModel object. */ +public interface LibraryDataLoader { + /** + * Load data from a source and return a LibraryDataModel object. + * + * @return A LibraryDataModel object. + * @throws IOException if an I/O error occurs. + */ + public LibraryDataModel loadData() throws IOException; +} diff --git a/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/factory/LibraryDbDataLoader.java b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/factory/LibraryDbDataLoader.java new file mode 100644 index 000000000..d5ce2dd50 --- /dev/null +++ b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/factory/LibraryDbDataLoader.java @@ -0,0 +1,26 @@ +package com.codedifferently.lesson26.factory; + +import com.codedifferently.lesson26.models.LibraryDataModel; +import com.codedifferently.lesson26.repository.LibraryGuestRepository; +import com.codedifferently.lesson26.repository.MediaItemRepository; +import java.io.IOException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** A data loader that loads library data from a database. */ +@Service +public final class LibraryDbDataLoader implements LibraryDataLoader { + + @Autowired private MediaItemRepository mediaItemsRepository; + @Autowired private LibraryGuestRepository libraryGuestRepository; + + @Override + public LibraryDataModel loadData() throws IOException { + var model = new LibraryDataModel(); + + model.mediaItems = mediaItemsRepository.findAll(); + model.guests = libraryGuestRepository.findAll(); + + return model; + } +} diff --git a/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/factory/LibraryFactory.java b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/factory/LibraryFactory.java new file mode 100644 index 000000000..a925c2b2b --- /dev/null +++ b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/factory/LibraryFactory.java @@ -0,0 +1,103 @@ +package com.codedifferently.lesson26.factory; + +import com.codedifferently.lesson26.library.Librarian; +import com.codedifferently.lesson26.library.Library; +import com.codedifferently.lesson26.library.LibraryGuest; +import com.codedifferently.lesson26.library.MediaItem; +import com.codedifferently.lesson26.models.CheckoutModel; +import com.codedifferently.lesson26.models.LibraryDataModel; +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +/** A factory class that creates a Library object with a LibraryDataLoader object. */ +public final class LibraryFactory { + + /** + * Create a Library object with a LibraryDataLoader object. + * + * @param loader A LibraryDataLoader object. + * @return A Library object. + * @throws IOException + */ + public static Library createWithLoader(LibraryDataLoader loader) throws IOException { + Library library = new Library("main-library"); + + // Load library data. + LibraryDataModel data = loader.loadData(); + + // Add guests to the library. + List guests = data.getGuests(); + addLibraryGuests(library, guests); + + // Add library items using the first librarian. + Librarian firstLibrarian = findFirstLibrarian(guests); + List mediaItems = data.getMediaItems(); + addLibraryItems(library, mediaItems, firstLibrarian); + + // Check out items from the library. + Map> checkoutsByEmail = data.getCheckoutsByEmail(); + Map mediaItemById = getMediaItemsById(mediaItems); + Map guestsByEmail = getGuestsByEmail(guests); + checkOutItems(library, checkoutsByEmail, guestsByEmail, mediaItemById); + + return library; + } + + private static Map getMediaItemsById(List mediaItems) { + Map mediaItemById = new HashMap<>(); + for (MediaItem mediaItem : mediaItems) { + mediaItemById.put(mediaItem.getId(), mediaItem); + } + return mediaItemById; + } + + private static Librarian findFirstLibrarian(List guests) { + Librarian firstLibrarian = null; + for (LibraryGuest guest : guests) { + if (guest instanceof Librarian librarian) { + firstLibrarian = librarian; + } + } + return firstLibrarian; + } + + private static void addLibraryGuests(Library library, List guests) { + for (LibraryGuest guest : guests) { + library.addLibraryGuest(guest); + } + } + + private static void addLibraryItems( + Library library, List mediaItems, Librarian firstLibrarian) { + for (MediaItem mediaItem : mediaItems) { + library.addMediaItem(mediaItem, firstLibrarian); + } + } + + private static Map getGuestsByEmail(List guests) { + Map guestByEmail = new HashMap<>(); + for (LibraryGuest guest : guests) { + guestByEmail.put(guest.getEmail(), guest); + } + return guestByEmail; + } + + private static void checkOutItems( + Library library, + Map> checkoutsByEmail, + Map guestByEmail, + Map mediaItemById) { + for (var entry : checkoutsByEmail.entrySet()) { + String email = entry.getKey(); + List checkouts = entry.getValue(); + LibraryGuest guest = guestByEmail.get(email); + for (CheckoutModel checkout : checkouts) { + MediaItem mediaItem = mediaItemById.get(checkout.itemId); + library.checkOutMediaItem(mediaItem, guest); + } + } + } +} diff --git a/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/factory/LibraryJsonDataLoader.java b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/factory/LibraryJsonDataLoader.java new file mode 100644 index 000000000..6d6e56484 --- /dev/null +++ b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/factory/LibraryJsonDataLoader.java @@ -0,0 +1,28 @@ +package com.codedifferently.lesson26.factory; + +import com.codedifferently.lesson26.models.LibraryDataModel; +import com.fasterxml.jackson.databind.MapperFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.json.JsonMapper; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import java.io.File; +import java.io.IOException; +import org.springframework.core.io.ClassPathResource; +import org.springframework.stereotype.Service; + +/** Loads data from a JSON file and returns a LibraryDataModel object. */ +@Service +public final class LibraryJsonDataLoader implements LibraryDataLoader { + @Override + public LibraryDataModel loadData() throws IOException { + ObjectMapper objectMapper = + JsonMapper.builder() + .addModule(new JavaTimeModule()) + .enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS) + .build(); + + // Load data from data.json file + File file = new ClassPathResource("json/data.json").getFile(); + return objectMapper.readValue(file, LibraryDataModel.class); + } +} diff --git a/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/Book.java b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/Book.java new file mode 100644 index 000000000..18cef66a8 --- /dev/null +++ b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/Book.java @@ -0,0 +1,77 @@ +package com.codedifferently.lesson26.library; + +import java.util.List; +import java.util.UUID; + +/** Represents a book. */ +public class Book extends MediaItemBase { + private final String isbn; + private final List authors; + private final int numberOfPages; + + /** + * Create a new book with the given title, ISBN, authors, and number of pages. + * + * @param id The ID of the book. + * @param title The title of the book. + * @param isbn The ISBN of the book. + * @param authors The authors of the book. + * @param numberOfPages The number of pages in the book. + */ + public Book(UUID id, String title, String isbn, List authors, int numberOfPages) { + super(id, title); + this.isbn = isbn; + this.authors = authors; + this.numberOfPages = numberOfPages; + } + + @Override + public MediaType getType() { + return MediaType.BOOK; + } + + /** + * Get the ISBN of the book. + * + * @return The ISBN of the book. + */ + public String getIsbn() { + return this.isbn; + } + + /** + * Get the authors of the book. + * + * @return The authors of the book. + */ + public List getAuthors() { + return this.authors; + } + + /** + * Get the number of pages in the book. + * + * @return The number of pages in the book. + */ + public int getNumberOfPages() { + return this.numberOfPages; + } + + @Override + protected boolean matchesAuthor(String authorQuery) { + if (authorQuery == null) { + return true; + } + for (String author : this.getAuthors()) { + if (author.toLowerCase().contains(authorQuery.toLowerCase())) { + return true; + } + } + return false; + } + + @Override + public String toString() { + return "Book{" + "id='" + getId() + '\'' + ", title='" + getTitle() + '\'' + '}'; + } +} diff --git a/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/Dvd.java b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/Dvd.java new file mode 100644 index 000000000..06ae9a86b --- /dev/null +++ b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/Dvd.java @@ -0,0 +1,20 @@ +package com.codedifferently.lesson26.library; + +import java.util.UUID; + +/** Represents a DVD. */ +public class Dvd extends MediaItemBase { + public Dvd(UUID id, String title) { + super(id, title); + } + + @Override + public MediaType getType() { + return MediaType.DVD; + } + + @Override + public String toString() { + return "Dvd{" + "id='" + getId() + '\'' + ", title='" + getTitle() + '\'' + '}'; + } +} diff --git a/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/Librarian.java b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/Librarian.java new file mode 100644 index 000000000..edb8aea92 --- /dev/null +++ b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/Librarian.java @@ -0,0 +1,13 @@ +package com.codedifferently.lesson26.library; + +/** Represents a librarian of a library. */ +public class Librarian extends LibraryGuestBase { + public Librarian(String name, String email) { + super(name, email); + } + + @Override + public String toString() { + return "Librarian{" + "id='" + getEmail() + '\'' + ", name='" + getName() + '\'' + '}'; + } +} diff --git a/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/Library.java b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/Library.java new file mode 100644 index 000000000..2071a60f3 --- /dev/null +++ b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/Library.java @@ -0,0 +1,300 @@ +package com.codedifferently.lesson26.library; + +import com.codedifferently.lesson26.library.exceptions.MediaItemCheckedOutException; +import com.codedifferently.lesson26.library.search.CatalogSearcher; +import com.codedifferently.lesson26.library.search.SearchCriteria; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.stream.Collectors; + +/** Represents a library. */ +public class Library { + private final Map itemsById = new HashMap<>(); + private final Set checkedOutItemIds = new HashSet<>(); + private final Map> checkedOutItemsByGuest = new HashMap<>(); + private final Map guestsById = new HashMap<>(); + private final String id; + private final CatalogSearcher searcher; + + /** + * Create a new library with the given id. + * + * @param id The id of the library. + */ + public Library(String id) { + this.id = id; + this.searcher = new CatalogSearcher(this.itemsById.values()); + } + + /** + * Get the id of the library. + * + * @return The id of the library. + */ + public String getId() { + return this.id; + } + + /** + * Add a item to the library. + * + * @param item The item to add. + * @param librarian The librarian adding the item. + */ + public void addMediaItem(MediaItem item, Librarian librarian) { + this.itemsById.put(item.getId(), item); + item.setLibrary(this); + } + + /** + * Remove a item from the library. + * + * @param item The item to remove. + * @param librarian The librarian removing the item. + */ + public void removeMediaItem(MediaItem item, Librarian librarian) + throws MediaItemCheckedOutException { + if (this.isCheckedOut(item)) { + throw new MediaItemCheckedOutException("Cannot remove checked out item."); + } + this.itemsById.remove(item.getId()); + item.setLibrary(null); + } + + /** + * Remove a item from the library. + * + * @param id The ID of the item to remove. + * @param librarian The librarian removing the item. + */ + public void removeMediaItem(UUID id, Librarian librarian) throws MediaItemCheckedOutException { + MediaItem item = this.itemsById.get(id); + this.removeMediaItem(item, librarian); + } + + /** + * Search the library for items matching the given query. + * + * @param query The query to search for. + * @return The items matching the query. + */ + public Set search(SearchCriteria query) { + return new HashSet<>(this.searcher.search(query)); + } + + /** + * Add a guest to the library. + * + * @param guest The guest to add. + */ + public void addLibraryGuest(LibraryGuest guest) { + this.guestsById.put(guest.getId(), guest); + this.checkedOutItemsByGuest.put(guest.getId(), new HashSet<>()); + guest.setLibrary(this); + } + + /** + * Remove a guest from the library. + * + * @param id The ID of the guest to remove. + */ + public void removeLibraryGuest(UUID id) throws MediaItemCheckedOutException { + LibraryGuest guest = this.guestsById.get(id); + if (guest == null) { + return; + } + if (!this.checkedOutItemsByGuest.get(guest.getId()).isEmpty()) { + throw new MediaItemCheckedOutException("Cannot remove guest with checked out items."); + } + this.guestsById.remove(guest.getId()); + this.checkedOutItemsByGuest.remove(guest.getId()); + guest.setLibrary(null); + } + + /** + * Remove a guest from the library. + * + * @param guest The guest to remove. + */ + public void removeLibraryGuest(LibraryGuest guest) throws MediaItemCheckedOutException { + this.removeLibraryGuest(guest.getId()); + } + + /** + * Returns all librarians registered for this library. + * + * @return A unique set of librarians. + */ + public Set getLibrarians() { + return this.guestsById.values().stream() + .filter(g -> g instanceof Librarian) + .map(g -> (Librarian) g) + .collect(Collectors.toSet()); + } + + /** + * Returns all registered library patrons. + * + * @return A unique set of all Library patrons. + */ + public Set getPatrons() { + return this.guestsById.values().stream().collect(Collectors.toSet()); + } + + /** + * Check out a item to a guest. + * + * @param item The item to check out. + * @param guest The guest to check out the item to. + * @return True if the item was checked out, false otherwise. + */ + public boolean checkOutMediaItem(MediaItem item, LibraryGuest guest) { + if (!this.canCheckOutMediaItem(item, guest)) { + return false; + } + this.checkedOutItemIds.add(item.getId()); + this.checkedOutItemsByGuest.get(guest.getId()).add(item); + return true; + } + + private boolean canCheckOutMediaItem(MediaItem item, LibraryGuest guest) { + if (!item.canCheckOut()) { + return false; + } + if (!this.hasMediaItem(item)) { + return false; + } + if (this.isCheckedOut(item)) { + return false; + } + return this.hasLibraryGuest(guest); + } + + /** + * Check if the library has the given item. + * + * @param item The item to check for. + * @return True if the library has the item, false otherwise. + */ + public boolean hasMediaItem(MediaItem item) { + return this.hasMediaItem(item.getId()); + } + + /** + * Check if the library has the given item. + * + * @param id The ID of the item to check for. + * @return True if the library has the item, false otherwise. + */ + public boolean hasMediaItem(UUID id) { + return this.itemsById.containsKey(id); + } + + /** + * Check if the given item is checked out. + * + * @param item The item to check. + * @return True if the item is checked out, false otherwise. + */ + public boolean isCheckedOut(MediaItem item) { + return this.checkedOutItemIds.contains(item.getId()); + } + + /** + * Check if the library has the given guest. + * + * @param guest The guest to check for. + * @return True if the library has the guest, false otherwise. + */ + public boolean hasLibraryGuest(LibraryGuest guest) { + return this.hasLibraryGuest(guest.getId()); + } + + /** + * Check if the library has the given guest. + * + * @param id The ID to check for. + * @return True if the library has the guest, false otherwise. + */ + public boolean hasLibraryGuest(UUID id) { + return this.guestsById.containsKey(id); + } + + /** + * Check if the library has the given guest. + * + * @param emailAddress The email address to check for. + * @return True if the library has the guest, false otherwise. + */ + public boolean hasLibraryGuest(String emailAddress) { + return this.guestsById.values().stream() + .anyMatch(g -> g.getEmail().equalsIgnoreCase(emailAddress)); + } + + /** + * Return a item to the library. + * + * @param item The item to return. + * @param guest The guest returning the item. + * @return True if the item was returned, false otherwise. + */ + public boolean checkInMediaItem(MediaItem item, LibraryGuest guest) { + if (!this.hasMediaItem(item)) { + return false; + } + this.checkedOutItemIds.remove(item.getId()); + this.checkedOutItemsByGuest.get(guest.getId()).remove(item); + return true; + } + + /** + * Get the items checked out by a guest. + * + * @param guest The guest to get the items for. + * @return The items checked out by the guest. + */ + public Set getCheckedOutByGuest(LibraryGuest guest) { + return this.checkedOutItemsByGuest.get(guest.getId()); + } + + /** + * Get a snapshot of the library info. + * + * @return The library info. + */ + public LibraryInfo getInfo() { + Map> itemsByGuest = + this.checkedOutItemsByGuest.entrySet().stream() + .collect( + HashMap::new, + (map, entry) -> + map.put( + entry.getKey(), + Collections.unmodifiableSet(new HashSet<>(entry.getValue()))), + HashMap::putAll); + return LibraryInfo.builder() + .id(this.id) + .items(Collections.unmodifiableSet(new HashSet<>(this.itemsById.values()))) + .guests(Collections.unmodifiableSet(new HashSet<>(this.guestsById.values()))) + .checkedOutItemsByGuest(Collections.unmodifiableMap(itemsByGuest)) + .build(); + } + + @Override + public String toString() { + return "Library{" + + "itemsById=" + + itemsById + + ", checkedOutItemIds=" + + checkedOutItemIds + + ", checkedOutMediaItemsByLibraryGuest=" + + checkedOutItemsByGuest + + ", guestIds=" + + guestsById + + '}'; + } +} diff --git a/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/LibraryConfiguration.java b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/LibraryConfiguration.java new file mode 100644 index 000000000..768c9cca7 --- /dev/null +++ b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/LibraryConfiguration.java @@ -0,0 +1,16 @@ +package com.codedifferently.lesson26.library; + +import com.codedifferently.lesson26.factory.LibraryDbDataLoader; +import com.codedifferently.lesson26.factory.LibraryFactory; +import java.io.IOException; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class LibraryConfiguration { + + @Bean + public Library getDefaultLibrary(LibraryDbDataLoader loader) throws IOException { + return LibraryFactory.createWithLoader(loader); + } +} diff --git a/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/LibraryGuest.java b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/LibraryGuest.java new file mode 100644 index 000000000..f13cc178a --- /dev/null +++ b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/LibraryGuest.java @@ -0,0 +1,45 @@ +package com.codedifferently.lesson26.library; + +import com.codedifferently.lesson26.library.exceptions.LibraryNotSetException; +import com.codedifferently.lesson26.library.exceptions.WrongLibraryException; +import java.util.Set; +import java.util.UUID; + +public interface LibraryGuest { + /** + * Get the library that the guest is in. + * + * @param library The library that the guest is in. + * @throws WrongLibraryException If the guest is not in the library. + */ + public void setLibrary(Library library) throws WrongLibraryException; + + /** + * Get the name of the guest. + * + * @return The name of the guest. + */ + public String getName(); + + /** + * Get the email of the guest. + * + * @return The email of the guest. + */ + public String getEmail(); + + /** + * Get the id of the guest. + * + * @return The id of the guest. + */ + public UUID getId(); + + /** + * Gets the items currently checked out to the guest. + * + * @return The items currently checked out to the guest. + * @throws LibraryNotSetException If the library is not set for the guest. + */ + public Set getCheckedOutMediaItems() throws LibraryNotSetException; +} diff --git a/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/LibraryGuestBase.java b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/LibraryGuestBase.java new file mode 100644 index 000000000..14448ca12 --- /dev/null +++ b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/LibraryGuestBase.java @@ -0,0 +1,75 @@ +package com.codedifferently.lesson26.library; + +import com.codedifferently.lesson26.library.exceptions.LibraryNotSetException; +import com.codedifferently.lesson26.library.exceptions.WrongLibraryException; +import java.util.Objects; +import java.util.Set; +import java.util.UUID; + +/** Base implementation of a library guest. */ +public class LibraryGuestBase implements LibraryGuest { + + private Library library; + private final UUID id = UUID.randomUUID(); + private final String name; + private final String email; + + public LibraryGuestBase(String name, String email) { + this.name = name; + this.email = email; + } + + @Override + public void setLibrary(Library library) throws WrongLibraryException { + if (library != null && !library.hasLibraryGuest(this)) { + throw new WrongLibraryException( + "Patron " + this.getEmail() + " is not in library " + library.getId()); + } + this.library = library; + } + + @Override + public String getName() { + return this.name; + } + + @Override + public String getEmail() { + return this.email; + } + + @Override + public UUID getId() { + return this.id; + } + + @Override + public Set getCheckedOutMediaItems() throws LibraryNotSetException { + if (this.library == null) { + throw new LibraryNotSetException("Library not set for patron " + this.getEmail()); + } + return this.library.getCheckedOutByGuest(this); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof LibraryGuestBase)) { + return false; + } + LibraryGuestBase guest = (LibraryGuestBase) o; + return Objects.equals(getEmail(), guest.getEmail()); + } + + @Override + public int hashCode() { + return Objects.hash(getId()); + } + + @Override + public String toString() { + return "LibraryGuestBase{" + "id='" + getEmail() + '\'' + ", name='" + getName() + '\'' + '}'; + } +} diff --git a/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/LibraryInfo.java b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/LibraryInfo.java new file mode 100644 index 000000000..a8c4deb76 --- /dev/null +++ b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/LibraryInfo.java @@ -0,0 +1,20 @@ +package com.codedifferently.lesson26.library; + +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class LibraryInfo { + public String id; + public Set items; + public Set guests; + public Map> checkedOutItemsByGuest; +} diff --git a/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/Magazine.java b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/Magazine.java new file mode 100644 index 000000000..8fda2be1c --- /dev/null +++ b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/Magazine.java @@ -0,0 +1,25 @@ +package com.codedifferently.lesson26.library; + +import java.util.UUID; + +/** Represents a magazine. */ +public class Magazine extends MediaItemBase { + public Magazine(UUID id, String title) { + super(id, title); + } + + @Override + public MediaType getType() { + return MediaType.MAGAZINE; + } + + @Override + public boolean canCheckOut() { + return false; + } + + @Override + public String toString() { + return "Magazine{" + "id='" + getId() + '\'' + ", title='" + getTitle() + '\'' + '}'; + } +} diff --git a/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/MediaItem.java b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/MediaItem.java new file mode 100644 index 000000000..f1f4805e1 --- /dev/null +++ b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/MediaItem.java @@ -0,0 +1,53 @@ +package com.codedifferently.lesson26.library; + +import com.codedifferently.lesson26.library.exceptions.LibraryNotSetException; +import com.codedifferently.lesson26.library.exceptions.WrongLibraryException; +import com.codedifferently.lesson26.library.search.Searchable; +import java.util.UUID; + +/** Represents a media item. */ +public interface MediaItem extends Searchable { + /** + * Get the type of the media item. + * + * @return The type of the media item. + */ + public MediaType getType(); + + /** + * Get the id of the media item. + * + * @return The id of the media item. + */ + public UUID getId(); + + /** + * Set the library that the media item is in. + * + * @param library + * @throws WrongLibraryException + */ + public void setLibrary(Library library) throws WrongLibraryException; + + /** + * Get the title of the media item. + * + * @return The title of the media item. + */ + public String getTitle(); + + /** + * Check if the media item is checked out. + * + * @return True if the media item is checked out, false otherwise. + * @throws LibraryNotSetException + */ + public boolean isCheckedOut() throws LibraryNotSetException; + + /** + * Check if the media item can be checked out. + * + * @return True if the media item can be checked out, false otherwise. + */ + public boolean canCheckOut(); +} diff --git a/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/MediaItemBase.java b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/MediaItemBase.java new file mode 100644 index 000000000..2e1ece8fa --- /dev/null +++ b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/MediaItemBase.java @@ -0,0 +1,93 @@ +package com.codedifferently.lesson26.library; + +import com.codedifferently.lesson26.library.exceptions.LibraryNotSetException; +import com.codedifferently.lesson26.library.exceptions.WrongLibraryException; +import com.codedifferently.lesson26.library.search.SearchCriteria; +import java.util.Objects; +import java.util.UUID; + +/** Base implementation of a media item. */ +public abstract class MediaItemBase implements MediaItem { + private Library library; + private final UUID id; + private final String title; + + public MediaItemBase(UUID id, String title) { + this.id = id; + this.title = title; + } + + @Override + public UUID getId() { + return id; + } + + @Override + public String getTitle() { + return title; + } + + @Override + public void setLibrary(Library library) throws WrongLibraryException { + if (library != null && !library.hasMediaItem(this)) { + throw new WrongLibraryException( + "Media item " + this.getId() + " is not in library " + library.getId()); + } + this.library = library; + } + + @Override + public boolean isCheckedOut() throws LibraryNotSetException { + if (this.library == null) { + throw new LibraryNotSetException("Library not set for item " + this.getId()); + } + return library.isCheckedOut(this); + } + + @Override + public boolean canCheckOut() { + return true; + } + + /** + * Check if the media item matches the given author. + * + * @param author The author to check. + * @return True if the media item matches the author, false otherwise. + */ + protected boolean matchesAuthor(String author) { + return false; + } + + @Override + public boolean matches(SearchCriteria query) { + if (query.id != null && !this.getId().toString().equalsIgnoreCase(query.id)) { + return false; + } + if (query.title != null && !this.getTitle().toLowerCase().contains(query.title.toLowerCase())) { + return false; + } + if (query.type != null && !this.getType().toString().equalsIgnoreCase(query.type)) { + return false; + } + return query.author == null || this.matchesAuthor(query.author); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof MediaItem)) return false; + MediaItem item = (MediaItem) o; + return Objects.equals(getId(), item.getId()); + } + + @Override + public int hashCode() { + return Objects.hash(getId()); + } + + @Override + public String toString() { + return "MediaItem{" + "id='" + getId() + '\'' + ", title='" + getTitle() + '\'' + '}'; + } +} diff --git a/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/MediaType.java b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/MediaType.java new file mode 100644 index 000000000..bfce8dca5 --- /dev/null +++ b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/MediaType.java @@ -0,0 +1,28 @@ +package com.codedifferently.lesson26.library; + +public enum MediaType { + UNKNOWN("unknown"), + BOOK("book"), + DVD("dvd"), + MAGAZINE("magazine"), + NEWSPAPER("newspaper"); + + private final String type; + + MediaType(String type) { + this.type = type; + } + + public String getType() { + return type; + } + + public static MediaType fromString(String type) { + for (MediaType mediaItemType : MediaType.values()) { + if (mediaItemType.type.equalsIgnoreCase(type)) { + return mediaItemType; + } + } + throw new IllegalArgumentException("Invalid media item type: " + type); + } +} diff --git a/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/Newspaper.java b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/Newspaper.java new file mode 100644 index 000000000..e99bcc441 --- /dev/null +++ b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/Newspaper.java @@ -0,0 +1,25 @@ +package com.codedifferently.lesson26.library; + +import java.util.UUID; + +/** Represents a newspaper. */ +public class Newspaper extends MediaItemBase { + public Newspaper(UUID id, String title) { + super(id, title); + } + + @Override + public MediaType getType() { + return MediaType.NEWSPAPER; + } + + @Override + public boolean canCheckOut() { + return false; + } + + @Override + public String toString() { + return "Newspaper{" + "id='" + getId() + '\'' + ", title='" + getTitle() + '\'' + '}'; + } +} diff --git a/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/Patron.java b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/Patron.java new file mode 100644 index 000000000..93b332308 --- /dev/null +++ b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/Patron.java @@ -0,0 +1,20 @@ +package com.codedifferently.lesson26.library; + +/** Represents a patron of a library. */ +public class Patron extends LibraryGuestBase { + + /** + * Create a new patron with the given name and email. + * + * @param name The name of the patron. + * @param email The email of the patron. + */ + public Patron(String name, String email) { + super(name, email); + } + + @Override + public String toString() { + return "Patron{" + "id='" + getEmail() + '\'' + ", name='" + getName() + '\'' + '}'; + } +} diff --git a/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/exceptions/LibraryNotSetException.java b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/exceptions/LibraryNotSetException.java new file mode 100644 index 000000000..230f2f9f1 --- /dev/null +++ b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/exceptions/LibraryNotSetException.java @@ -0,0 +1,7 @@ +package com.codedifferently.lesson26.library.exceptions; + +public class LibraryNotSetException extends RuntimeException { + public LibraryNotSetException(String message) { + super(message); + } +} diff --git a/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/exceptions/MediaItemCheckedOutException.java b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/exceptions/MediaItemCheckedOutException.java new file mode 100644 index 000000000..059dd0305 --- /dev/null +++ b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/exceptions/MediaItemCheckedOutException.java @@ -0,0 +1,7 @@ +package com.codedifferently.lesson26.library.exceptions; + +public class MediaItemCheckedOutException extends RuntimeException { + public MediaItemCheckedOutException(String message) { + super(message); + } +} diff --git a/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/exceptions/WrongLibraryException.java b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/exceptions/WrongLibraryException.java new file mode 100644 index 000000000..9fe9ad138 --- /dev/null +++ b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/exceptions/WrongLibraryException.java @@ -0,0 +1,7 @@ +package com.codedifferently.lesson26.library.exceptions; + +public class WrongLibraryException extends RuntimeException { + public WrongLibraryException(String message) { + super(message); + } +} diff --git a/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/search/CatalogSearcher.java b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/search/CatalogSearcher.java new file mode 100644 index 000000000..a1b6ed3d2 --- /dev/null +++ b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/search/CatalogSearcher.java @@ -0,0 +1,31 @@ +package com.codedifferently.lesson26.library.search; + +import java.util.Collection; + +/** + * Searches a catalog for items that match a query. + * + * @param + */ +public class CatalogSearcher { + private final Collection catalog; + + /** + * Constructor for CatalogSearcher + * + * @param catalog + */ + public CatalogSearcher(Collection catalog) { + this.catalog = catalog; + } + + /** + * Searches the catalog for items that match the given query. + * + * @param query The query to search for. + * @return The items that match the query. + */ + public Collection search(SearchCriteria query) { + return catalog.stream().filter(item -> item.matches(query)).toList(); + } +} diff --git a/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/search/SearchCriteria.java b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/search/SearchCriteria.java new file mode 100644 index 000000000..d7e2e0a8b --- /dev/null +++ b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/search/SearchCriteria.java @@ -0,0 +1,24 @@ +package com.codedifferently.lesson26.library.search; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class SearchCriteria { + /** The ID to search for (exact match). */ + public String id; + + /** The title to search for. */ + public String title; + + /** The author to search for. */ + public String author; + + /** The type to search for (exact match). */ + public String type; +} diff --git a/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/search/Searchable.java b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/search/Searchable.java new file mode 100644 index 000000000..1d4c3f282 --- /dev/null +++ b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/library/search/Searchable.java @@ -0,0 +1,11 @@ +package com.codedifferently.lesson26.library.search; + +public interface Searchable { + /** + * Indicates whether an item matches the search criteria. + * + * @param query The query to search for. + * @return The items that match the query. + */ + boolean matches(SearchCriteria query); +} diff --git a/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/models/AuthorsConverter.java b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/models/AuthorsConverter.java new file mode 100644 index 000000000..2d3750592 --- /dev/null +++ b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/models/AuthorsConverter.java @@ -0,0 +1,18 @@ +package com.codedifferently.lesson26.models; + +import jakarta.persistence.AttributeConverter; +import jakarta.persistence.Converter; +import java.util.List; + +@Converter +public class AuthorsConverter implements AttributeConverter, String> { + @Override + public String convertToDatabaseColumn(List authors) { + return String.join(", ", authors); + } + + @Override + public List convertToEntityAttribute(String authors) { + return authors != null ? List.of(authors.split(", ")) : List.of(); + } +} diff --git a/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/models/CheckoutModel.java b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/models/CheckoutModel.java new file mode 100644 index 000000000..aa280e4db --- /dev/null +++ b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/models/CheckoutModel.java @@ -0,0 +1,15 @@ +package com.codedifferently.lesson26.models; + +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import java.time.Instant; +import java.util.UUID; + +@Entity +@Table(name = "checked_out_items") +public class CheckoutModel { + @Id public UUID itemId; + public String email; + public Instant dueDate; +} diff --git a/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/models/LibraryDataModel.java b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/models/LibraryDataModel.java new file mode 100644 index 000000000..29c6e6151 --- /dev/null +++ b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/models/LibraryDataModel.java @@ -0,0 +1,61 @@ +package com.codedifferently.lesson26.models; + +import com.codedifferently.lesson26.library.Book; +import com.codedifferently.lesson26.library.Dvd; +import com.codedifferently.lesson26.library.Librarian; +import com.codedifferently.lesson26.library.LibraryGuest; +import com.codedifferently.lesson26.library.Magazine; +import com.codedifferently.lesson26.library.MediaItem; +import com.codedifferently.lesson26.library.Newspaper; +import com.codedifferently.lesson26.library.Patron; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class LibraryDataModel { + public List mediaItems; + public List guests; + + public List getMediaItems() { + List results = new ArrayList<>(); + for (MediaItemModel mediaItemModel : mediaItems) { + switch (mediaItemModel.type) { + case BOOK -> + results.add( + new Book( + mediaItemModel.id, + mediaItemModel.title, + mediaItemModel.isbn, + mediaItemModel.authors, + mediaItemModel.pages)); + case DVD -> results.add(new Dvd(mediaItemModel.id, mediaItemModel.title)); + case MAGAZINE -> results.add(new Magazine(mediaItemModel.id, mediaItemModel.title)); + case NEWSPAPER -> results.add(new Newspaper(mediaItemModel.id, mediaItemModel.title)); + default -> + throw new IllegalArgumentException("Unknown media item type: " + mediaItemModel.type); + } + } + return results; + } + + public List getGuests() { + List results = new ArrayList<>(); + for (LibraryGuestModel guestModel : this.guests) { + switch (guestModel.type) { + case "librarian" -> results.add(new Librarian(guestModel.name, guestModel.email)); + case "patron" -> results.add(new Patron(guestModel.name, guestModel.email)); + default -> throw new AssertionError(); + } + } + return results; + } + + public Map> getCheckoutsByEmail() { + Map> results = new HashMap<>(); + for (LibraryGuestModel guest : this.guests) { + results.put(guest.email, guest.checkedOutItems); + } + return results; + } +} diff --git a/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/models/LibraryGuestModel.java b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/models/LibraryGuestModel.java new file mode 100644 index 000000000..310433689 --- /dev/null +++ b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/models/LibraryGuestModel.java @@ -0,0 +1,19 @@ +package com.codedifferently.lesson26.models; + +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.Id; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; +import java.util.List; + +@Entity +@Table(name = "guests") +public class LibraryGuestModel { + public String type; + public String name; + @Id public String email; + + @OneToMany(mappedBy = "email", fetch = FetchType.EAGER) + public List checkedOutItems; +} diff --git a/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/models/MediaItemModel.java b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/models/MediaItemModel.java new file mode 100644 index 000000000..a4bd64a89 --- /dev/null +++ b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/models/MediaItemModel.java @@ -0,0 +1,29 @@ +package com.codedifferently.lesson26.models; + +import com.codedifferently.lesson26.library.MediaType; +import jakarta.persistence.Convert; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import java.util.List; +import java.util.UUID; + +@Entity +@Table(name = "media_items") +public class MediaItemModel { + @Enumerated(EnumType.STRING) + public MediaType type; + + @Id public UUID id; + public String isbn; + public String title; + + @Convert(converter = AuthorsConverter.class) + public List authors; + + public String edition; + public Integer pages = 0; + public Integer runtime = 0; +} diff --git a/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/repository/LibraryGuestRepository.java b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/repository/LibraryGuestRepository.java new file mode 100644 index 000000000..c0b242e8d --- /dev/null +++ b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/repository/LibraryGuestRepository.java @@ -0,0 +1,10 @@ +package com.codedifferently.lesson26.repository; + +import com.codedifferently.lesson26.models.LibraryGuestModel; +import java.util.List; +import org.springframework.data.repository.CrudRepository; + +public interface LibraryGuestRepository extends CrudRepository { + @Override + List findAll(); +} diff --git a/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/repository/MediaItemRepository.java b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/repository/MediaItemRepository.java new file mode 100644 index 000000000..3022c51f6 --- /dev/null +++ b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/repository/MediaItemRepository.java @@ -0,0 +1,11 @@ +package com.codedifferently.lesson26.repository; + +import com.codedifferently.lesson26.models.MediaItemModel; +import java.util.List; +import java.util.UUID; +import org.springframework.data.repository.CrudRepository; + +public interface MediaItemRepository extends CrudRepository { + @Override + List findAll(); +} diff --git a/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/web/CreateMediaItemRequest.java b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/web/CreateMediaItemRequest.java new file mode 100644 index 000000000..26f7e1a4a --- /dev/null +++ b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/web/CreateMediaItemRequest.java @@ -0,0 +1,17 @@ +package com.codedifferently.lesson26.web; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class CreateMediaItemRequest { + @NotNull(message = "item is required") @Valid + private MediaItemRequest item; +} diff --git a/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/web/CreateMediaItemResponse.java b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/web/CreateMediaItemResponse.java new file mode 100644 index 000000000..01da025e9 --- /dev/null +++ b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/web/CreateMediaItemResponse.java @@ -0,0 +1,10 @@ +package com.codedifferently.lesson26.web; + +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +public class CreateMediaItemResponse { + private MediaItemResponse item; +} diff --git a/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/web/GetMediaItemsResponse.java b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/web/GetMediaItemsResponse.java new file mode 100644 index 000000000..0d167cdba --- /dev/null +++ b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/web/GetMediaItemsResponse.java @@ -0,0 +1,12 @@ +package com.codedifferently.lesson26.web; + +import java.util.List; +import lombok.Builder; +import lombok.Data; +import lombok.Singular; + +@Data +@Builder +public class GetMediaItemsResponse { + @Singular private List items; +} diff --git a/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/web/GlobalExceptionHandler.java b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/web/GlobalExceptionHandler.java new file mode 100644 index 000000000..1c8eea724 --- /dev/null +++ b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/web/GlobalExceptionHandler.java @@ -0,0 +1,33 @@ +package com.codedifferently.lesson26.web; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.FieldError; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +@RestControllerAdvice +public class GlobalExceptionHandler { + + @ExceptionHandler(MethodArgumentNotValidException.class) + public ResponseEntity>> handleValidationErrors( + MethodArgumentNotValidException ex) { + List errors = + ex.getBindingResult().getFieldErrors().stream() + .map(FieldError::getDefaultMessage) + .collect(Collectors.toList()); + return new ResponseEntity<>(getErrorsMap(errors), new HttpHeaders(), HttpStatus.BAD_REQUEST); + } + + private Map> getErrorsMap(List errors) { + Map> errorResponse = new HashMap<>(); + errorResponse.put("errors", errors); + return errorResponse; + } +} diff --git a/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/web/MediaItemRequest.java b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/web/MediaItemRequest.java new file mode 100644 index 000000000..74552dbeb --- /dev/null +++ b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/web/MediaItemRequest.java @@ -0,0 +1,52 @@ +package com.codedifferently.lesson26.web; + +import com.codedifferently.lesson26.library.Book; +import com.codedifferently.lesson26.library.Dvd; +import com.codedifferently.lesson26.library.Magazine; +import com.codedifferently.lesson26.library.MediaItem; +import com.codedifferently.lesson26.library.Newspaper; +import jakarta.validation.constraints.NotBlank; +import java.util.List; +import java.util.UUID; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class MediaItemRequest { + + private UUID id; + private String type; + private String isbn; + + @NotBlank(message = "Title is required") + private String title; + + private String[] authors; + private String edition; + private int pages; + private int runtime; + + public static MediaItem asMediaItem(MediaItemRequest request) { + var id = request.id != null ? request.id : UUID.randomUUID(); + switch (request.type.toLowerCase()) { + case "book" -> { + return new Book(id, request.title, request.isbn, List.of(request.authors), request.pages); + } + case "dvd" -> { + return new Dvd(id, request.title); + } + case "magazine" -> { + return new Magazine(id, request.title); + } + case "newspaper" -> { + return new Newspaper(id, request.title); + } + default -> throw new IllegalArgumentException("Unknown media item type: " + request.type); + } + } +} diff --git a/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/web/MediaItemResponse.java b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/web/MediaItemResponse.java new file mode 100644 index 000000000..69a29dc98 --- /dev/null +++ b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/web/MediaItemResponse.java @@ -0,0 +1,40 @@ +package com.codedifferently.lesson26.web; + +import com.codedifferently.lesson26.library.Book; +import com.codedifferently.lesson26.library.MediaItem; +import java.util.List; +import java.util.UUID; +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +public class MediaItemResponse { + + private String type; + private UUID id; + private String isbn; + private String title; + public List authors; + public String edition; + public int pages; + public int runtime; + + public static MediaItemResponse from(MediaItem item) { + var result = + MediaItemResponse.builder() + .id(item.getId()) + .title(item.getTitle()) + .type(item.getType().name().toLowerCase()); + + switch (item.getType()) { + case BOOK -> { + var book = (Book) item; + result = + result.isbn(book.getIsbn()).authors(book.getAuthors()).pages(book.getNumberOfPages()); + } + } + + return result.build(); + } +} diff --git a/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/web/MediaItemsController.java b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/web/MediaItemsController.java new file mode 100644 index 000000000..bbbc45e41 --- /dev/null +++ b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/web/MediaItemsController.java @@ -0,0 +1,34 @@ +package com.codedifferently.lesson26.web; + +import com.codedifferently.lesson26.library.Librarian; +import com.codedifferently.lesson26.library.Library; +import com.codedifferently.lesson26.library.MediaItem; +import com.codedifferently.lesson26.library.search.SearchCriteria; +import java.io.IOException; +import java.util.List; +import java.util.Set; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.CrossOrigin; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@CrossOrigin +public class MediaItemsController { + + private final Library library; + private final Librarian librarian; + + public MediaItemsController(Library library) throws IOException { + this.library = library; + this.librarian = library.getLibrarians().stream().findFirst().orElseThrow(); + } + + @GetMapping("/items") + public ResponseEntity getItems() { + Set items = library.search(SearchCriteria.builder().build()); + List responseItems = items.stream().map(MediaItemResponse::from).toList(); + var response = GetMediaItemsResponse.builder().items(responseItems).build(); + return ResponseEntity.ok(response); + } +} diff --git a/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/web/WebConfiguration.java b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/web/WebConfiguration.java new file mode 100644 index 000000000..309e68356 --- /dev/null +++ b/lesson_26/api/java/api_app/src/main/java/com/codedifferently/lesson26/web/WebConfiguration.java @@ -0,0 +1,11 @@ +package com.codedifferently.lesson26.web; + +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@EnableWebMvc +@Configuration +@ComponentScan(basePackages = "com.codedifferently") +public class WebConfiguration implements WebMvcConfigurer {} diff --git a/lesson_26/api/java/api_app/src/main/resources/application.yml b/lesson_26/api/java/api_app/src/main/resources/application.yml new file mode 100644 index 000000000..bc26497dc --- /dev/null +++ b/lesson_26/api/java/api_app/src/main/resources/application.yml @@ -0,0 +1,9 @@ +server: + port: 3001 +spring: + jpa: + database-platform: org.hibernate.community.dialect.SQLiteDialect + generate-ddl: true + datasource: + url: jdbc:sqlite::resource:sqlite/data.db + driver-class-name: org.sqlite.JDBC \ No newline at end of file diff --git a/lesson_26/api/java/api_app/src/main/resources/csv/checked_out_items.csv b/lesson_26/api/java/api_app/src/main/resources/csv/checked_out_items.csv new file mode 100644 index 000000000..1c2fffa70 --- /dev/null +++ b/lesson_26/api/java/api_app/src/main/resources/csv/checked_out_items.csv @@ -0,0 +1,5 @@ +email,item_id,due_date +jane.smith@example.com,e27a4e0d-9664-420d-955e-c0e295d0ce02,2024-04-05T00:00:00Z +jane.smith@example.com,295ea581-cd61-4319-8b0c-e5c0c03286c5,2024-04-07T00:00:00Z +alice.johnson@example.com,17dd5d20-98f5-4a26-be09-449fea88a3c3,2024-04-03T00:00:00Z +alice.johnson@example.com,28e5c91f-0e4b-4be5-abb1-8da01fd5587e,2024-04-06T00:00:00Z \ No newline at end of file diff --git a/lesson_26/api/java/api_app/src/main/resources/csv/guests.csv b/lesson_26/api/java/api_app/src/main/resources/csv/guests.csv new file mode 100644 index 000000000..bcc02b051 --- /dev/null +++ b/lesson_26/api/java/api_app/src/main/resources/csv/guests.csv @@ -0,0 +1,6 @@ +type,name,email +librarian,John Doe,john.doe@fakelibrary.org +patron,Jane Smith,jane.smith@example.com +patron,Alice Johnson,alice.johnson@example.com +librarian,Bob Williams,bob.williams@fakelibrary.org +patron,Emily Brown,emily.brown@example.com \ No newline at end of file diff --git a/lesson_26/api/java/api_app/src/main/resources/csv/media_items.csv b/lesson_26/api/java/api_app/src/main/resources/csv/media_items.csv new file mode 100644 index 000000000..c3f8161d5 --- /dev/null +++ b/lesson_26/api/java/api_app/src/main/resources/csv/media_items.csv @@ -0,0 +1,32 @@ +type,id,title,isbn,authors,pages,runtime,edition +book,e27a4e0d-9664-420d-955e-c0e295d0ce02,To Kill a Mockingbird,978-0061120084,"Harper Lee",336,, +book,17dd5d20-98f5-4a26-be09-449fea88a3c3,1984,978-0451524935,"George Orwell",328,, +dvd,28e5c91f-0e4b-4be5-abb1-8da01fd5587e,The Shawshank Redemption,,,,142, +dvd,295ea581-cd61-4319-8b0c-e5c0c03286c5,Inception,,,,148, +magazine,222111dd-c561-462a-8854-853ada4d3421,National Geographic,,,,,March 2024 +magazine,0afd425b-973f-4af9-a6aa-8febe943a8f6,Time,,,,,"March 15, 2024" +newspaper,91b74a71-97ad-4fea-b17c-a640c98d355f,The New York Times,,,,,"Morning Edition, March 22, 2024" +newspaper,45cab344-b792-484c-9156-d929237dde67,The Guardian,,,,,"March 22, 2024" +book,218b55fa-a3cd-4803-805e-7cd1ef3115ac,The Great Gatsby,978-0743273565,"F. Scott Fitzgerald",180,, +book,b4249c17-f77b-46da-aa82-7aa227eca5e2,Harry Potter and the Sorcerer's Stone,978-0590353427,"J.K. Rowling",309,, +dvd,a3cc5ccb-e2fd-4cd0-a6f8-dc1f2f07589b,The Godfather,,,,175, +dvd,6386364c-8505-4dbe-8731-ff8fa0d6e381,The Dark Knight,,,,152, +magazine,e5060cc1-33f0-431c-a1b3-d1979e38b6f2,Scientific American,,,,,April 2024 +magazine,7048bd13-49ee-4693-8900-e396bbdf3f98,Vogue,,,,,Spring 2024 +newspaper,6f80a5ce-5958-48f3-a029-ff3d76f2c3fe,The Washington Post,,,,,"Evening Edition, March 22, 2024" +newspaper,f5f1196c-7935-417e-bc52-7144f63da3cb,The Times,,,,,"March 23, 2024" +book,faf5a804-e02c-4bbc-8505-4ba90a526e28,Pride and Prejudice,978-0141439518,"Jane Austen",279,, +book,1aab8182-4345-4ead-98e8-0db53682311b,The Catcher in the Rye,978-0316769488,"J.D. Salinger",277,, +dvd,2b92ef3d-b224-4589-9a59-cdaba758affd,The Matrix,,,,136, +dvd,e5d75a1d-f3b4-430f-ba63-b6e4603228eb,Pulp Fiction,,,,154, +magazine,75fb71ad-ea84-45b8-8396-b790c833573e,Wired,,,,,"May 2024" +magazine,e30a6739-cdc9-4b2e-ac67-7278fcfb9a59,Forbes,,,,,"April 2024" +newspaper,3e228c29-6163-477a-8b70-e873a3788758,Los Angeles Times,,,,,"Morning Edition, March 23, 2024" +newspaper,8e3946e2-d5a6-4cb4-ac92-17cc44935d2d,Chicago Tribune,,,,,"March 23, 2024" +book,b08c9da7-5c01-494c-84ec-af3fef9dc480,The Lord of the Rings,978-0544003415,"J.R.R. Tolkien",1178,, +dvd,af1ae237-d29a-49d8-a18a-d6193c07a033,The Silence of the Lambs,,,,118, +dvd,215af9ba-e881-48fb-8284-a3dc6a1c096d,The Departed,,,,151, +magazine,8efcbbb2-5c1e-486c-924d-63c3503f498c,The Economist,,,,,"March 23, 2024" +magazine,d39f5cf3-9574-4fdc-b81b-99d31b26ee92,The New Yorker,,,,,"March 25, 2024" +newspaper,8b369c0f-6c68-4a84-8e15-8b85a2dd1949,USA Today,,,,,"Morning Edition, March 23, 2024" +newspaper,eaf356a3-ae28-4cc5-92a2-9b0264165b5d,The Wall Street Journal,,,,,"March 23, 2024" \ No newline at end of file diff --git a/lesson_26/api/java/api_app/src/main/resources/json/data.json b/lesson_26/api/java/api_app/src/main/resources/json/data.json new file mode 100644 index 000000000..d419365ff --- /dev/null +++ b/lesson_26/api/java/api_app/src/main/resources/json/data.json @@ -0,0 +1,268 @@ +{ + "mediaItems": [ + { + "type": "book", + "id": "e27a4e0d-9664-420d-955e-c0e295d0ce02", + "title": "To Kill a Mockingbird", + "isbn": "978-0061120084", + "authors": [ + "Harper Lee" + ], + "pages": 336 + }, + { + "type": "book", + "id": "17dd5d20-98f5-4a26-be09-449fea88a3c3", + "title": "1984", + "isbn": "978-0451524935", + "authors": [ + "George Orwell" + ], + "pages": 328 + }, + { + "type": "dvd", + "id": "28e5c91f-0e4b-4be5-abb1-8da01fd5587e", + "title": "The Shawshank Redemption", + "runtime": 142 + }, + { + "type": "dvd", + "id": "295ea581-cd61-4319-8b0c-e5c0c03286c5", + "title": "Inception", + "runtime": 148 + }, + { + "type": "magazine", + "id": "222111dd-c561-462a-8854-853ada4d3421", + "title": "National Geographic", + "edition": "March 2024" + }, + { + "type": "magazine", + "id": "0afd425b-973f-4af9-a6aa-8febe943a8f6", + "title": "Time", + "edition": "March 15, 2024" + }, + { + "type": "newspaper", + "id": "91b74a71-97ad-4fea-b17c-a640c98d355f", + "title": "The New York Times", + "edition": "Morning Edition, March 22, 2024" + }, + { + "type": "newspaper", + "id": "45cab344-b792-484c-9156-d929237dde67", + "title": "The Guardian", + "edition": "March 22, 2024" + }, + { + "type": "book", + "id": "218b55fa-a3cd-4803-805e-7cd1ef3115ac", + "title": "The Great Gatsby", + "isbn": "978-0743273565", + "authors": [ + "F. Scott Fitzgerald" + ], + "pages": 180 + }, + { + "type": "book", + "id": "b4249c17-f77b-46da-aa82-7aa227eca5e2", + "title": "Harry Potter and the Sorcerer's Stone", + "isbn": "978-0590353427", + "authors": [ + "J.K. Rowling" + ], + "pages": 309 + }, + { + "type": "dvd", + "id": "a3cc5ccb-e2fd-4cd0-a6f8-dc1f2f07589b", + "title": "The Godfather", + "runtime": 175 + }, + { + "type": "dvd", + "id": "6386364c-8505-4dbe-8731-ff8fa0d6e381", + "title": "The Dark Knight", + "runtime": 152 + }, + { + "type": "magazine", + "id": "e5060cc1-33f0-431c-a1b3-d1979e38b6f2", + "title": "Scientific American", + "edition": "April 2024" + }, + { + "type": "magazine", + "id": "7048bd13-49ee-4693-8900-e396bbdf3f98", + "title": "Vogue", + "edition": "Spring 2024" + }, + { + "type": "newspaper", + "id": "6f80a5ce-5958-48f3-a029-ff3d76f2c3fe", + "title": "The Washington Post", + "edition": "Evening Edition, March 22, 2024" + }, + { + "type": "newspaper", + "id": "f5f1196c-7935-417e-bc52-7144f63da3cb", + "title": "The Times", + "edition": "March 23, 2024" + }, + { + "type": "book", + "id": "faf5a804-e02c-4bbc-8505-4ba90a526e28", + "title": "Pride and Prejudice", + "isbn": "978-0141439518", + "authors": [ + "Jane Austen" + ], + "pages": 279 + }, + { + "type": "book", + "id": "1aab8182-4345-4ead-98e8-0db53682311b", + "title": "The Catcher in the Rye", + "isbn": "978-0316769488", + "authors": [ + "J.D. Salinger" + ], + "pages": 277 + }, + { + "type": "dvd", + "id": "2b92ef3d-b224-4589-9a59-cdaba758affd", + "title": "The Matrix", + "runtime": 136 + }, + { + "type": "dvd", + "id": "e5d75a1d-f3b4-430f-ba63-b6e4603228eb", + "title": "Pulp Fiction", + "runtime": 154 + }, + { + "type": "magazine", + "id": "75fb71ad-ea84-45b8-8396-b790c833573e", + "title": "Wired", + "edition": "May 2024" + }, + { + "type": "magazine", + "id": "e30a6739-cdc9-4b2e-ac67-7278fcfb9a59", + "title": "Forbes", + "edition": "April 2024" + }, + { + "type": "newspaper", + "id": "3e228c29-6163-477a-8b70-e873a3788758", + "title": "Los Angeles Times", + "edition": "Morning Edition, March 23, 2024" + }, + { + "type": "newspaper", + "id": "8e3946e2-d5a6-4cb4-ac92-17cc44935d2d", + "title": "Chicago Tribune", + "edition": "March 23, 2024" + }, + { + "type": "book", + "id": "b08c9da7-5c01-494c-84ec-af3fef9dc480", + "title": "The Lord of the Rings", + "isbn": "978-0544003415", + "authors": [ + "J.R.R. Tolkien" + ], + "pages": 1178 + }, + { + "type": "dvd", + "id": "af1ae237-d29a-49d8-a18a-d6193c07a033", + "title": "The Silence of the Lambs", + "runtime": 118 + }, + { + "type": "dvd", + "id": "215af9ba-e881-48fb-8284-a3dc6a1c096d", + "title": "The Departed", + "runtime": 151 + }, + { + "type": "magazine", + "id": "8efcbbb2-5c1e-486c-924d-63c3503f498c", + "title": "The Economist", + "edition": "March 23, 2024" + }, + { + "type": "magazine", + "id": "d39f5cf3-9574-4fdc-b81b-99d31b26ee92", + "title": "The New Yorker", + "edition": "March 25, 2024" + }, + { + "type": "newspaper", + "id": "8b369c0f-6c68-4a84-8e15-8b85a2dd1949", + "title": "USA Today", + "edition": "Morning Edition, March 23, 2024" + }, + { + "type": "newspaper", + "id": "eaf356a3-ae28-4cc5-92a2-9b0264165b5d", + "title": "The Wall Street Journal", + "edition": "March 23, 2024" + } + ], + "guests": [ + { + "type": "librarian", + "name": "John Doe", + "email": "john.doe@fakelibrary.org", + "checkedOutItems": [] + }, + { + "type": "patron", + "name": "Jane Smith", + "email": "jane.smith@example.com", + "checkedOutItems": [ + { + "itemId": "e27a4e0d-9664-420d-955e-c0e295d0ce02", + "dueDate": "2024-04-05T00:00:00Z" + }, + { + "itemId": "295ea581-cd61-4319-8b0c-e5c0c03286c5", + "dueDate": "2024-04-07T00:00:00Z" + } + ] + }, + { + "type": "patron", + "name": "Alice Johnson", + "email": "alice.johnson@example.com", + "checkedOutItems": [ + { + "itemId": "17dd5d20-98f5-4a26-be09-449fea88a3c3", + "dueDate": "2024-04-03T00:00:00Z" + }, + { + "itemId": "28e5c91f-0e4b-4be5-abb1-8da01fd5587e", + "dueDate": "2024-04-06T00:00:00Z" + } + ] + }, + { + "type": "librarian", + "name": "Bob Williams", + "email": "bob.williams@fakelibrary.org", + "checkedOutItems": [] + }, + { + "type": "patron", + "name": "Emily Brown", + "email": "emily.brown@example.com", + "checkedOutItems": [] + } + ] +} \ No newline at end of file diff --git a/lesson_26/api/java/api_app/src/main/resources/queries/anthonydmays.sql b/lesson_26/api/java/api_app/src/main/resources/queries/anthonydmays.sql new file mode 100644 index 000000000..027b7d63f --- /dev/null +++ b/lesson_26/api/java/api_app/src/main/resources/queries/anthonydmays.sql @@ -0,0 +1 @@ +SELECT 1; \ No newline at end of file diff --git a/lesson_26/api/java/api_app/src/main/resources/sqlite/data.db b/lesson_26/api/java/api_app/src/main/resources/sqlite/data.db new file mode 100644 index 0000000000000000000000000000000000000000..16f3563b10820e8dd268b0c729ae36b29a164dbf GIT binary patch literal 16384 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 literal 0 HcmV?d00001 diff --git a/lesson_26/api/java/api_app/src/test/java/com/codedifferently/lesson26/Lesson26Test.java b/lesson_26/api/java/api_app/src/test/java/com/codedifferently/lesson26/Lesson26Test.java new file mode 100644 index 000000000..de228a594 --- /dev/null +++ b/lesson_26/api/java/api_app/src/test/java/com/codedifferently/lesson26/Lesson26Test.java @@ -0,0 +1,13 @@ +package com.codedifferently.lesson26; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; + +class Lesson26Test { + + @Test + void testInstantiate() { + assertThat(new Lesson26()).isNotNull(); + } +} diff --git a/lesson_26/api/java/api_app/src/test/java/com/codedifferently/lesson26/factory/LibraryCsvDataLoaderTest.java b/lesson_26/api/java/api_app/src/test/java/com/codedifferently/lesson26/factory/LibraryCsvDataLoaderTest.java new file mode 100644 index 000000000..46f77f692 --- /dev/null +++ b/lesson_26/api/java/api_app/src/test/java/com/codedifferently/lesson26/factory/LibraryCsvDataLoaderTest.java @@ -0,0 +1,84 @@ +package com.codedifferently.lesson26.factory; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.codedifferently.lesson26.Lesson26; +import com.codedifferently.lesson26.library.LibraryGuest; +import com.codedifferently.lesson26.library.MediaItem; +import com.codedifferently.lesson26.library.MediaType; +import com.codedifferently.lesson26.models.CheckoutModel; +import com.codedifferently.lesson26.models.LibraryDataModel; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ContextConfiguration; + +@SpringBootTest +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +@ContextConfiguration(classes = Lesson26.class) +class LibraryCsvDataLoaderTest { + private LibraryDataModel libraryDataModel; + + @BeforeAll + void beforeAll() throws Exception { + libraryDataModel = new LibraryCsvDataLoader().loadData(); + } + + @Test + void testDataLoader_loadsCheckedOutItems() { + Map> checkedOutItemsByGuest = + libraryDataModel.getCheckoutsByEmail(); + var numCheckedOutItems = checkedOutItemsByGuest.values().stream().mapToInt(List::size).sum(); + assertThat(numCheckedOutItems) + .describedAs("LibraryCsvDataLoader should load checked out items") + .isEqualTo(4); + } + + @Test + void testDataLoader_loadsCorrectItemTypes() { + List items = libraryDataModel.getMediaItems(); + Map countByMediaType = + items.stream() + .reduce( + new HashMap<>(), + (hashMap, e) -> { + hashMap.merge(e.getType(), 1, Integer::sum); + return hashMap; + }, + (m, m2) -> { + m.putAll(m2); + return m; + }); + assertThat(countByMediaType.get(MediaType.BOOK)).isEqualTo(7); + assertThat(countByMediaType.get(MediaType.MAGAZINE)).isEqualTo(8); + assertThat(countByMediaType.get(MediaType.NEWSPAPER)).isEqualTo(8); + assertThat(countByMediaType.get(MediaType.DVD)).isEqualTo(8); + assertThat(items.stream().map(MediaItem::getId).distinct().count()).isEqualTo(31); + assertThat(items.stream().map(MediaItem::getTitle).distinct().count()).isEqualTo(31); + } + + @Test + void testDataLoader_loadsCorrectGuestTypes() { + List guests = libraryDataModel.getGuests(); + Map countByGuestType = + guests.stream() + .reduce( + new HashMap<>(), + (hashMap, e) -> { + hashMap.merge(e.getClass().getSimpleName(), 1, Integer::sum); + return hashMap; + }, + (m, m2) -> { + m.putAll(m2); + return m; + }); + assertThat(countByGuestType.get("Librarian")).isEqualTo(2); + assertThat(countByGuestType.get("Patron")).isEqualTo(3); + assertThat(guests.stream().map(LibraryGuest::getEmail).distinct().count()).isEqualTo(5); + assertThat(guests.stream().map(LibraryGuest::getName).distinct().count()).isEqualTo(5); + } +} diff --git a/lesson_26/api/java/api_app/src/test/java/com/codedifferently/lesson26/factory/LibraryJsonDataLoaderTest.java b/lesson_26/api/java/api_app/src/test/java/com/codedifferently/lesson26/factory/LibraryJsonDataLoaderTest.java new file mode 100644 index 000000000..83d3d9b01 --- /dev/null +++ b/lesson_26/api/java/api_app/src/test/java/com/codedifferently/lesson26/factory/LibraryJsonDataLoaderTest.java @@ -0,0 +1,76 @@ +package com.codedifferently.lesson26.factory; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.codedifferently.lesson26.library.LibraryGuest; +import com.codedifferently.lesson26.library.MediaItem; +import com.codedifferently.lesson26.library.MediaType; +import com.codedifferently.lesson26.models.CheckoutModel; +import com.codedifferently.lesson26.models.LibraryDataModel; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +class LibraryJsonDataLoaderTest { + private static LibraryDataModel libraryDataModel; + + @BeforeAll + static void beforeAll() throws Exception { + var libraryJsonDataLoader = new LibraryJsonDataLoader(); + libraryDataModel = libraryJsonDataLoader.loadData(); + } + + @Test + void testDataLoader_loadsCheckedOutItems() { + Map> checkedOutItemsByGuest = + libraryDataModel.getCheckoutsByEmail(); + var numCheckedOutItems = checkedOutItemsByGuest.values().stream().mapToInt(List::size).sum(); + assertThat(numCheckedOutItems).isEqualTo(4); + } + + @Test + void testDataLoader_loadsCorrectItemTypes() { + List items = libraryDataModel.getMediaItems(); + Map countByMediaType = + items.stream() + .reduce( + new HashMap<>(), + (hashMap, e) -> { + hashMap.merge(e.getType(), 1, Integer::sum); + return hashMap; + }, + (m, m2) -> { + m.putAll(m2); + return m; + }); + assertThat(countByMediaType.get(MediaType.BOOK)).isEqualTo(7); + assertThat(countByMediaType.get(MediaType.MAGAZINE)).isEqualTo(8); + assertThat(countByMediaType.get(MediaType.NEWSPAPER)).isEqualTo(8); + assertThat(countByMediaType.get(MediaType.DVD)).isEqualTo(8); + assertThat(items.stream().map(MediaItem::getId).distinct().count()).isEqualTo(31); + assertThat(items.stream().map(MediaItem::getTitle).distinct().count()).isEqualTo(31); + } + + @Test + void testDataLoader_loadsCorrectGuestTypes() { + List guests = libraryDataModel.getGuests(); + Map countByGuestType = + guests.stream() + .reduce( + new HashMap<>(), + (hashMap, e) -> { + hashMap.merge(e.getClass().getSimpleName(), 1, Integer::sum); + return hashMap; + }, + (m, m2) -> { + m.putAll(m2); + return m; + }); + assertThat(countByGuestType.get("Librarian")).isEqualTo(2); + assertThat(countByGuestType.get("Patron")).isEqualTo(3); + assertThat(guests.stream().map(LibraryGuest::getEmail).distinct().count()).isEqualTo(5); + assertThat(guests.stream().map(LibraryGuest::getName).distinct().count()).isEqualTo(5); + } +} diff --git a/lesson_26/api/java/api_app/src/test/java/com/codedifferently/lesson26/library/BookTest.java b/lesson_26/api/java/api_app/src/test/java/com/codedifferently/lesson26/library/BookTest.java new file mode 100644 index 000000000..18dd7513d --- /dev/null +++ b/lesson_26/api/java/api_app/src/test/java/com/codedifferently/lesson26/library/BookTest.java @@ -0,0 +1,94 @@ +package com.codedifferently.lesson26.library; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import com.codedifferently.lesson26.library.exceptions.LibraryNotSetException; +import com.codedifferently.lesson26.library.exceptions.WrongLibraryException; +import java.util.List; +import java.util.UUID; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class BookTest { + + private Book classUnderTest; + private Library library; + + @BeforeEach + void setUp() { + classUnderTest = + new Book( + UUID.fromString("2b7591dd-f418-4115-974e-45115b3bf39a"), + "To Kill a Mockingbird", + "978-0061120084", + List.of("Harper Lee"), + 281); + library = mock(Library.class); + when(library.getId()).thenReturn("Library 1"); + when(library.hasMediaItem(classUnderTest)).thenReturn(true); + classUnderTest.setLibrary(library); + } + + @Test + void testPatron_created() { + // Assert + assertThat(classUnderTest.getTitle()).isEqualTo("To Kill a Mockingbird"); + assertThat(classUnderTest.getIsbn()).isEqualTo("978-0061120084"); + assertThat(classUnderTest.getAuthors()).isEqualTo(List.of("Harper Lee")); + assertThat(classUnderTest.getNumberOfPages()).isEqualTo(281); + } + + @Test + void testSetLibrary_WrongLibrary() { + // Arrange + Library otherLibrary = mock(Library.class); + when(otherLibrary.hasMediaItem(classUnderTest)).thenReturn(false); + when(otherLibrary.getId()).thenReturn("Library 2"); + + // Act & Assert + assertThatThrownBy(() -> classUnderTest.setLibrary(otherLibrary)) + .isInstanceOf(WrongLibraryException.class) + .hasMessageContaining( + "Media item 2b7591dd-f418-4115-974e-45115b3bf39a is not in library Library 2"); + } + + @Test + void testIsCheckedOut_LibraryNotSet() { + // Arrange + classUnderTest.setLibrary(null); + + // Act & Assert + assertThatThrownBy(() -> classUnderTest.isCheckedOut()) + .isInstanceOf(LibraryNotSetException.class) + .hasMessageContaining("Library not set for item 2b7591dd-f418-4115-974e-45115b3bf39a"); + } + + @Test + void testIsCheckedOut() { + // Arrange + when(library.isCheckedOut(classUnderTest)).thenReturn(true); + + // Act & Assert + assertThat(classUnderTest.isCheckedOut()).isTrue(); + } + + @Test + void testIsCheckedOut_whenNotCheckedOut() { + // Arrange + when(library.isCheckedOut(classUnderTest)).thenReturn(false); + + // Act & Assert + assertThat(classUnderTest.isCheckedOut()).isFalse(); + } + + @Test + void testToString() { + // Act & Assert + assertThat(classUnderTest.toString()) + .isEqualTo( + "Book{id='2b7591dd-f418-4115-974e-45115b3bf39a', title='To Kill a Mockingbird'}"); + } +} diff --git a/lesson_26/api/java/api_app/src/test/java/com/codedifferently/lesson26/library/LibraryTest.java b/lesson_26/api/java/api_app/src/test/java/com/codedifferently/lesson26/library/LibraryTest.java new file mode 100644 index 000000000..e589f4d27 --- /dev/null +++ b/lesson_26/api/java/api_app/src/test/java/com/codedifferently/lesson26/library/LibraryTest.java @@ -0,0 +1,353 @@ +package com.codedifferently.lesson26.library; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import com.codedifferently.lesson26.library.exceptions.MediaItemCheckedOutException; +import java.util.List; +import java.util.Set; +import java.util.UUID; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class LibraryTest { + private Library classUnderTest; + + @BeforeEach + void setUp() { + classUnderTest = new Library("compton-library"); + } + + @Test + void testLibrary_canAddItems() { + // Arrange + Book book1 = + new Book( + UUID.randomUUID(), + "The Great Gatsby", + "978-0743273565", + List.of("F. Scott Fitzgerald"), + 180); + Book book2 = + new Book( + UUID.randomUUID(), + "To Kill a Mockingbird", + "978-0061120084", + List.of("Harper Lee"), + 281); + Librarian librarian = new Librarian("Anthony Mays", "anthony@example.com"); + // Act + classUnderTest.addMediaItem(book1, librarian); + classUnderTest.addMediaItem(book2, librarian); + // Assert + assertThat(classUnderTest.hasMediaItem(book1)).isTrue(); + assertThat(classUnderTest.hasMediaItem(book2)).isTrue(); + } + + @Test + void testLibrary_canRemoveItems() { + // Arrange + Book book1 = + new Book( + UUID.randomUUID(), + "The Great Gatsby", + "978-0743273565", + List.of("F. Scott Fitzgerald"), + 180); + Book book2 = + new Book( + UUID.randomUUID(), + "To Kill a Mockingbird", + "978-0061120084", + List.of("Harper Lee"), + 281); + Librarian librarian = new Librarian("Anthony Mays", "anthony@example.com"); + classUnderTest.addMediaItem(book1, librarian); + classUnderTest.addMediaItem(book2, librarian); + // Act + classUnderTest.removeMediaItem(book1, librarian); + classUnderTest.removeMediaItem(book2, librarian); + // Assert + assertThat(classUnderTest.hasMediaItem(book1)).isFalse(); + assertThat(classUnderTest.hasMediaItem(book2)).isFalse(); + } + + @Test + void testLibrary_canAddPatrons() { + // Arrange + Patron patron1 = new Patron("John Doe", "john@example.com"); + Patron patron2 = new Patron("Jane Doe", "jane@example.com"); + // Act + classUnderTest.addLibraryGuest(patron1); + classUnderTest.addLibraryGuest(patron2); + // Assert + assertThat(classUnderTest.hasLibraryGuest(patron1)).isTrue(); + assertThat(classUnderTest.hasLibraryGuest(patron2)).isTrue(); + } + + @Test + void testLibrary_canRemovePatrons() { + // Arrange + Patron patron1 = new Patron("John Doe", "john@example.com"); + Patron patron2 = new Patron("Jane Doe", "jane@example.com"); + classUnderTest.addLibraryGuest(patron1); + classUnderTest.addLibraryGuest(patron2); + // Act + classUnderTest.removeLibraryGuest(patron1); + classUnderTest.removeLibraryGuest(patron2); + // Assert + assertThat(classUnderTest.hasLibraryGuest(patron1)).isFalse(); + assertThat(classUnderTest.hasLibraryGuest(patron2)).isFalse(); + } + + @Test + void testLibrary_allowsPatronToCheckoutBook() { + // Arrange + Book book = + new Book( + UUID.randomUUID(), + "The Great Gatsby", + "978-0743273565", + List.of("F. Scott Fitzgerald"), + 180); + Patron patron = new Patron("John Doe", "john@example.com"); + Librarian librarian = new Librarian("Anthony Mays", "anthony@example.com"); + classUnderTest.addMediaItem(book, librarian); + classUnderTest.addLibraryGuest(patron); + // Act + boolean wasCheckedOut = classUnderTest.checkOutMediaItem(book, patron); + // Assert + assertThat(wasCheckedOut).isTrue(); + assertThat(classUnderTest.isCheckedOut(book)).isTrue(); + assertThat(patron.getCheckedOutMediaItems().contains(book)).isTrue(); + } + + @Test + void testLibrary_allowPatronToCheckInBook() { + // Arrange + Book book = + new Book( + UUID.randomUUID(), + "The Great Gatsby", + "978-0743273565", + List.of("F. Scott Fitzgerald"), + 180); + Patron patron = new Patron("John Doe", "john@example.com"); + Librarian librarian = new Librarian("Anthony Mays", "anthony@example.com"); + classUnderTest.addMediaItem(book, librarian); + classUnderTest.addLibraryGuest(patron); + classUnderTest.checkOutMediaItem(book, patron); + // Act + boolean wasReturned = classUnderTest.checkInMediaItem(book, patron); + // Assert + assertThat(wasReturned).isTrue(); + assertThat(classUnderTest.isCheckedOut(book)).isFalse(); + assertThat(patron.getCheckedOutMediaItems().contains(book)).isFalse(); + } + + @Test + void testLibrary_allowLibrarianToCheckOutBook() { + // Arrange + Librarian librarian = new Librarian("Anthony Mays", "anthony@example.com"); + Book book = + new Book( + UUID.randomUUID(), + "The Great Gatsby", + "978-0743273565", + List.of("F. Scott Fitzgerald"), + 180); + classUnderTest.addMediaItem(book, librarian); + classUnderTest.addLibraryGuest(librarian); + // Act + boolean wasCheckedOut = classUnderTest.checkOutMediaItem(book, librarian); + // Assert + assertThat(wasCheckedOut).isTrue(); + assertThat(librarian.getCheckedOutMediaItems().contains(book)).isTrue(); + } + + @Test + void testLibrary_allowLibrarianToCheckInBook() { + // Arrange + Book book = + new Book( + UUID.randomUUID(), + "The Great Gatsby", + "978-0743273565", + List.of("F. Scott Fitzgerald"), + 180); + Librarian librarian = new Librarian("John Doe", "john@example.com"); + classUnderTest.addMediaItem(book, librarian); + classUnderTest.addLibraryGuest(librarian); + classUnderTest.checkOutMediaItem(book, librarian); + // Act + boolean wasReturned = classUnderTest.checkInMediaItem(book, librarian); + // Assert + assertThat(wasReturned).isTrue(); + assertThat(classUnderTest.isCheckedOut(book)).isFalse(); + assertThat(librarian.getCheckedOutMediaItems().contains(book)).isFalse(); + } + + @Test + void testLibrary_preventsMultipleCheckouts() { + // Arrange + Book book = + new Book( + UUID.randomUUID(), + "The Great Gatsby", + "978-0743273565", + List.of("F. Scott Fitzgerald"), + 180); + Patron patron = new Patron("John Doe", "john@example.com"); + Librarian librarian = new Librarian("Anthony Mays", "anthony@example.com"); + classUnderTest.addMediaItem(book, librarian); + classUnderTest.addLibraryGuest(patron); + classUnderTest.checkOutMediaItem(book, patron); + // Act + boolean wasCheckedOut = classUnderTest.checkOutMediaItem(book, patron); + // Assert + assertThat(wasCheckedOut).isFalse(); + assertThat(classUnderTest.isCheckedOut(book)).isTrue(); + } + + @Test + void testLibrary_preventsRemovingPatronWithCheckedOutItems() { + // Arrange + Book book = + new Book( + UUID.randomUUID(), + "The Great Gatsby", + "978-0743273565", + List.of("F. Scott Fitzgerald"), + 180); + Patron patron = new Patron("John Doe", "john@example.com"); + Librarian librarian = new Librarian("Anthony Mays", "anthony@example.com"); + classUnderTest.addMediaItem(book, librarian); + classUnderTest.addLibraryGuest(patron); + classUnderTest.checkOutMediaItem(book, patron); + // Act + assertThatThrownBy(() -> classUnderTest.removeLibraryGuest(patron)) + .isInstanceOf(MediaItemCheckedOutException.class) + .hasMessage("Cannot remove guest with checked out items."); + } + + @Test + void testLibrary_preventsRemovingCheckedOutItems() { + // Arrange + Book book = + new Book( + UUID.randomUUID(), + "The Great Gatsby", + "978-0743273565", + List.of("F. Scott Fitzgerald"), + 180); + Patron patron = new Patron("Jane Doe", "jane@example.com"); + Librarian librarian = new Librarian("Anthony Mays", "anthony@example.com"); + classUnderTest.addMediaItem(book, librarian); + classUnderTest.addLibraryGuest(patron); + classUnderTest.checkOutMediaItem(book, patron); + // Act + assertThatThrownBy(() -> classUnderTest.removeMediaItem(book, librarian)) + .isInstanceOf(MediaItemCheckedOutException.class) + .hasMessage("Cannot remove checked out item."); + } + + @Test + void testLibrary_canAddDvd() { + // Arrange + Dvd dvd = new Dvd(UUID.randomUUID(), "The Great Gatsby"); + Librarian librarian = new Librarian("Anthony Mays", "anthony@example.com"); + // Act + classUnderTest.addMediaItem(dvd, librarian); + // Assert + assertThat(classUnderTest.hasMediaItem(dvd)).isTrue(); + } + + @Test + void testLibrary_canRemoveDvd() { + // Arrange + Dvd dvd = new Dvd(UUID.randomUUID(), "The Great Gatsby"); + Librarian librarian = new Librarian("Anthony Mays", "anthony@example.com"); + // Act + classUnderTest.removeMediaItem(dvd, librarian); + // Assert + assertThat(classUnderTest.hasMediaItem(dvd)).isFalse(); + } + + @Test + void testLibrary_allowLibrarianToCheckOutDvd() { + // Arrange + Librarian librarian = new Librarian("Anthony Mays", "anthony@example.com"); + Dvd dvd = new Dvd(UUID.randomUUID(), "The Great Gatsby"); + classUnderTest.addMediaItem(dvd, librarian); + classUnderTest.addLibraryGuest(librarian); + // Act + boolean wasCheckedOut = classUnderTest.checkOutMediaItem(dvd, librarian); + // Assert + assertThat(wasCheckedOut).isTrue(); + assertThat(librarian.getCheckedOutMediaItems().contains(dvd)).isTrue(); + } + + @Test + void testLibrary_allowPatronToCheckInDvd() { + // Arrange + Dvd dvd = new Dvd(UUID.randomUUID(), "The Great Gatsby"); + Patron patron = new Patron("John Doe", "john@example.com"); + Librarian librarian = new Librarian("Anthony Mays", "anthony@example.com"); + classUnderTest.addMediaItem(dvd, librarian); + classUnderTest.addLibraryGuest(patron); + classUnderTest.checkOutMediaItem(dvd, patron); + // Act + boolean wasReturned = classUnderTest.checkInMediaItem(dvd, patron); + // Assert + assertThat(wasReturned).isTrue(); + assertThat(classUnderTest.isCheckedOut(dvd)).isFalse(); + assertThat(patron.getCheckedOutMediaItems().contains(dvd)).isFalse(); + } + + @Test + void testLibrary_preventsGuestFromCheckingOutMagazine() { + // Arrange + Patron patron = new Patron("John Doe", "john@example.com"); + Librarian librarian = new Librarian("Anthony Mays", "anthony@example.com"); + Magazine magazine = new Magazine(UUID.randomUUID(), "The Great Gatsby"); + classUnderTest.addMediaItem(magazine, librarian); + classUnderTest.addLibraryGuest(librarian); + classUnderTest.addLibraryGuest(patron); + // Act + boolean wasCheckedOut = classUnderTest.checkOutMediaItem(magazine, librarian); + // Assert + assertThat(wasCheckedOut).isFalse(); + assertThat(patron.getCheckedOutMediaItems().contains(magazine)).isFalse(); + } + + @Test + void testLibrary_preventsGuestFromCheckingOutNewspaper() { + // Arrange + Patron patron = new Patron("John Doe", "john@example.com"); + Librarian librarian = new Librarian("Anthony Mays", "anthony@example.com"); + Newspaper newspaper = new Newspaper(UUID.randomUUID(), "LA Times"); + classUnderTest.addMediaItem(newspaper, librarian); + classUnderTest.addLibraryGuest(librarian); + classUnderTest.addLibraryGuest(patron); + // Act + boolean wasCheckedOut = classUnderTest.checkOutMediaItem(newspaper, librarian); + // Assert + assertThat(wasCheckedOut).isFalse(); + assertThat(patron.getCheckedOutMediaItems().contains(newspaper)).isFalse(); + } + + @Test + void testLibrary_retrievesAllPatrons() { + // Arrange + Patron patron1 = new Patron("John Doe", "john@example.com"); + Patron patron2 = new Patron("Jane Doe", "jane@example.com"); + classUnderTest.addLibraryGuest(patron1); + classUnderTest.addLibraryGuest(patron2); + + // Act + Set guests = classUnderTest.getPatrons(); + + // Assert + assertThat(classUnderTest.getPatrons().size()).isEqualTo(2); + } +} diff --git a/lesson_26/api/java/api_app/src/test/java/com/codedifferently/lesson26/library/MediaItemBaseTest.java b/lesson_26/api/java/api_app/src/test/java/com/codedifferently/lesson26/library/MediaItemBaseTest.java new file mode 100644 index 000000000..c0d63f3e5 --- /dev/null +++ b/lesson_26/api/java/api_app/src/test/java/com/codedifferently/lesson26/library/MediaItemBaseTest.java @@ -0,0 +1,94 @@ +package com.codedifferently.lesson26.library; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import com.codedifferently.lesson26.library.exceptions.LibraryNotSetException; +import com.codedifferently.lesson26.library.exceptions.WrongLibraryException; +import java.util.UUID; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class MediaItemBaseTest { + private MediaItemBase mediaItem; + private static final UUID ITEM_ID = UUID.fromString("af71ac38-7628-415f-a2cd-bcaf7e001b97"); + + class MockMediaItem extends MediaItemBase { + public MockMediaItem(UUID id, String title) { + super(id, title); + } + + @Override + public MediaType getType() { + return MediaType.MAGAZINE; + } + } + + @BeforeEach + void setUp() { + mediaItem = new MockMediaItem(ITEM_ID, "Sample Title"); + } + + @Test + void getId() { + assertEquals(ITEM_ID, mediaItem.getId()); + } + + @Test + void getTitle() { + assertEquals("Sample Title", mediaItem.getTitle()); + } + + @Test + void setLibrary_withWrongLibraryException() { + Library library = mock(Library.class); + when(library.getId()).thenReturn("compton-library"); + when(library.hasMediaItem(mediaItem)).thenReturn(false); + assertThatThrownBy(() -> mediaItem.setLibrary(library)) + .isInstanceOf(WrongLibraryException.class) + .hasMessage( + "Media item af71ac38-7628-415f-a2cd-bcaf7e001b97 is not in library compton-library"); + } + + @Test + void isCheckedOut() throws LibraryNotSetException { + Library library = mock(Library.class); + when(library.hasMediaItem(mediaItem)).thenReturn(true); + when(library.isCheckedOut(mediaItem)).thenReturn(true); + mediaItem.setLibrary(library); + assertTrue(mediaItem.isCheckedOut()); + } + + @Test + void isCheckedOut_withLibraryNotSetException() { + assertThatThrownBy(() -> mediaItem.isCheckedOut()) + .isInstanceOf(LibraryNotSetException.class) + .hasMessage("Library not set for item af71ac38-7628-415f-a2cd-bcaf7e001b97"); + } + + @Test + void canCheckOut() { + assertTrue(mediaItem.canCheckOut()); + } + + @Test + void equals() { + MediaItemBase mediaItem2 = new MockMediaItem(ITEM_ID, "Sample Title"); + assertEquals(mediaItem, mediaItem2); + } + + @Test + void hashCodeTest() { + MediaItemBase mediaItem2 = new MockMediaItem(ITEM_ID, "Sample Title"); + assertEquals(mediaItem.hashCode(), mediaItem2.hashCode()); + } + + @Test + void toStringTest() { + String expected = "MediaItem{id='af71ac38-7628-415f-a2cd-bcaf7e001b97', title='Sample Title'}"; + assertEquals(expected, mediaItem.toString()); + } +} diff --git a/lesson_26/api/java/api_app/src/test/java/com/codedifferently/lesson26/library/PatronTest.java b/lesson_26/api/java/api_app/src/test/java/com/codedifferently/lesson26/library/PatronTest.java new file mode 100644 index 000000000..4c4cf5437 --- /dev/null +++ b/lesson_26/api/java/api_app/src/test/java/com/codedifferently/lesson26/library/PatronTest.java @@ -0,0 +1,93 @@ +package com.codedifferently.lesson26.library; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import com.codedifferently.lesson26.library.exceptions.LibraryNotSetException; +import com.codedifferently.lesson26.library.exceptions.WrongLibraryException; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.UUID; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class PatronTest { + + private Patron classUnderTest; + private Library library; + + @BeforeEach + void setUp() { + classUnderTest = new Patron("John Doe", "johndoe@example.com"); + library = new Library("Library 1"); + library.addLibraryGuest(classUnderTest); + } + + @Test + void testPatron_created() { + // Assert + assertThat(classUnderTest.getName()).isEqualTo("John Doe"); + assertThat(classUnderTest.getEmail()).isEqualTo("johndoe@example.com"); + } + + @Test + void testSetLibrary_WrongLibrary() { + // Arrange + Library otherLibrary = new Library("Library 2"); + + // Act & Assert + assertThatThrownBy(() -> classUnderTest.setLibrary(otherLibrary)) + .isInstanceOf(WrongLibraryException.class) + .hasMessageContaining("Patron johndoe@example.com is not in library Library 2"); + } + + @Test + void testGetCheckedOutBooks_LibraryNotSet() { + // Arrange + classUnderTest.setLibrary(null); + + // Act & Assert + assertThatThrownBy(() -> classUnderTest.getCheckedOutMediaItems()) + .isInstanceOf(LibraryNotSetException.class) + .hasMessageContaining("Library not set for patron johndoe@example.com"); + } + + @Test + void testGetCheckedOutBooks() { + // Arrange + Book book1 = + new Book( + UUID.randomUUID(), + "The Great Gatsby", + "978-0743273565", + List.of("F. Scott Fitzgerald"), + 180); + Book book2 = + new Book( + UUID.randomUUID(), + "To Kill a Mockingbird", + "978-0061120084", + List.of("Harper Lee"), + 281); + Librarian librarian = new Librarian("Anthony Mays", "anthony@example.com"); + Set expectedBooks = new HashSet<>(); + expectedBooks.add(book1); + expectedBooks.add(book2); + + library.addMediaItem(book1, librarian); + library.addMediaItem(book2, librarian); + library.checkOutMediaItem(book1, classUnderTest); + library.checkOutMediaItem(book2, classUnderTest); + + // Act & Assert + assertThat(classUnderTest.getCheckedOutMediaItems()).isEqualTo(expectedBooks); + } + + @Test + void testToString() { + // Act & Assert + assertThat(classUnderTest.toString()) + .isEqualTo("Patron{id='johndoe@example.com', name='John Doe'}"); + } +} diff --git a/lesson_26/api/java/api_app/src/test/java/com/codedifferently/lesson26/web/MediaItemsControllerTest.java b/lesson_26/api/java/api_app/src/test/java/com/codedifferently/lesson26/web/MediaItemsControllerTest.java new file mode 100644 index 000000000..1b7757b58 --- /dev/null +++ b/lesson_26/api/java/api_app/src/test/java/com/codedifferently/lesson26/web/MediaItemsControllerTest.java @@ -0,0 +1,125 @@ +package com.codedifferently.lesson26.web; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import com.codedifferently.lesson26.Lesson26; +import com.codedifferently.lesson26.library.Book; +import com.codedifferently.lesson26.library.Library; +import com.codedifferently.lesson26.library.MediaItem; +import com.codedifferently.lesson26.library.search.SearchCriteria; +import java.util.Set; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; + +@SpringBootTest +@ContextConfiguration(classes = Lesson26.class) +class MediaItemsControllerTest { + private static MockMvc mockMvc; + @Autowired private Library library; + + @BeforeAll + static void setUp(WebApplicationContext wac) { + mockMvc = MockMvcBuilders.webAppContextSetup(wac).build(); + } + + @Test + void testController_getsAllItems() throws Exception { + mockMvc + .perform(get("/items").contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.items").isArray()) + .andExpect(jsonPath("$.items.length()").value(31)); + } + + @Test + void testController_getsAnItem() throws Exception { + mockMvc + .perform( + get("/items/31616162-3831-3832-2d34-3334352d3465") + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()); + } + + @Test + void testController_returnsNotFoundOnGetItem() throws Exception { + mockMvc + .perform( + get("/items/00000000-0000-0000-0000-000000000000") + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isNotFound()); + } + + @Test + void testController_reportsBadRequestOnAddItem() throws Exception { + String json = "{}"; + + mockMvc + .perform(post("/items").contentType(MediaType.APPLICATION_JSON).content(json)) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.errors").isArray()) + .andExpect(jsonPath("$.errors.length()").value(1)); + } + + @Test + void testController_addsItem() throws Exception { + String json = + """ + { + "item": { + "id": "e27a4e0d-9664-420d-955e-c0e295d0ce02", + "type": "BOOK", + "title": "Becoming", + "isbn": "9781524763138", + "authors": ["Michelle Obama"], + "pages": 448 + } + } + """; + + mockMvc + .perform(post("/items").contentType(MediaType.APPLICATION_JSON).content(json)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.item.id").value("e27a4e0d-9664-420d-955e-c0e295d0ce02")); + + Set items = + library.search(SearchCriteria.builder().id("e27a4e0d-9664-420d-955e-c0e295d0ce02").build()); + assertThat(items).hasSize(1); + var item = items.iterator().next(); + assertThat(item).isInstanceOf(Book.class); + assertThat(item.getTitle()).isEqualTo("Becoming"); + } + + @Test + void testController_returnsNotFoundOnDeleteItem() throws Exception { + mockMvc + .perform( + delete("/items/00000000-0000-0000-0000-000000000000") + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isNotFound()); + } + + @Test + void testController_deletesItem() throws Exception { + mockMvc + .perform( + delete("/items/32623932-6566-3364-2d62-3232342d3435") + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isNoContent()); + + Set items = + library.search(SearchCriteria.builder().id("32623932-6566-3364-2d62-3232342d3435").build()); + assertThat(items).hasSize(0); + } +} diff --git a/lesson_26/api/java/gradle/wrapper/gradle-wrapper.jar b/lesson_26/api/java/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..a4b76b9530d66f5e68d973ea569d8e19de379189 GIT binary patch literal 43583 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 yu?e%!_ptzGB|8GrCfu%p?(_ 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 GZ~q4|mN%#X literal 0 HcmV?d00001 diff --git a/lesson_26/api/java/gradle/wrapper/gradle-wrapper.properties b/lesson_26/api/java/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..e2847c820 --- /dev/null +++ b/lesson_26/api/java/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/lesson_26/api/java/gradlew b/lesson_26/api/java/gradlew new file mode 100755 index 000000000..f5feea6d6 --- /dev/null +++ b/lesson_26/api/java/gradlew @@ -0,0 +1,252 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s +' "$PWD" ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/lesson_26/api/java/gradlew.bat b/lesson_26/api/java/gradlew.bat new file mode 100644 index 000000000..9d21a2183 --- /dev/null +++ b/lesson_26/api/java/gradlew.bat @@ -0,0 +1,94 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/lesson_26/api/java/settings.gradle.kts b/lesson_26/api/java/settings.gradle.kts new file mode 100644 index 000000000..fadeb1bcd --- /dev/null +++ b/lesson_26/api/java/settings.gradle.kts @@ -0,0 +1,13 @@ +/* + * This file was generated by the Gradle 'init' task. + * + * The settings file is used to specify which projects to include in your build. + * + * Detailed information about configuring a multi-project build in Gradle can be found + * in the user manual at https://docs.gradle.org/8.0.2/userguide/multi_project_builds.html + */ + +includeBuild("../../../lib/java/codedifferently-instructional") + +rootProject.name = "lesson_26" +include("api_app") diff --git a/lesson_26/api/javascript/api_app/.editorconfig b/lesson_26/api/javascript/api_app/.editorconfig new file mode 100644 index 000000000..696df3e4c --- /dev/null +++ b/lesson_26/api/javascript/api_app/.editorconfig @@ -0,0 +1,9 @@ +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +insert_final_newline = true +quote_type = single diff --git a/lesson_26/api/javascript/api_app/.eslintrc.js b/lesson_26/api/javascript/api_app/.eslintrc.js new file mode 100644 index 000000000..01fb0fdb0 --- /dev/null +++ b/lesson_26/api/javascript/api_app/.eslintrc.js @@ -0,0 +1,30 @@ +module.exports = { + parser: '@typescript-eslint/parser', + parserOptions: { + project: 'tsconfig.json', + tsconfigRootDir: __dirname, + sourceType: 'module', + }, + plugins: ['@typescript-eslint/eslint-plugin', '@stylistic/eslint-plugin'], + extends: [ + 'plugin:@typescript-eslint/recommended', + 'plugin:prettier/recommended', + ], + root: true, + env: { + node: true, + jest: true, + }, + ignorePatterns: ['.eslintrc.js'], + rules: { + '@typescript-eslint/interface-name-prefix': 'off', + '@typescript-eslint/explicit-function-return-type': 'off', + '@typescript-eslint/no-explicit-any': 'error', + '@typescript-eslint/no-extraneous-class': 'off', + '@stylistic/quotes': [ + 'error', + 'single', + { avoidEscape: true, allowTemplateLiterals: false }, + ], + }, +}; diff --git a/lesson_26/api/javascript/api_app/.gitignore b/lesson_26/api/javascript/api_app/.gitignore new file mode 100644 index 000000000..4b56acfbe --- /dev/null +++ b/lesson_26/api/javascript/api_app/.gitignore @@ -0,0 +1,56 @@ +# compiled output +/dist +/node_modules +/build + +# Logs +logs +*.log +npm-debug.log* +pnpm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# OS +.DS_Store + +# Tests +/coverage +/.nyc_output + +# IDEs and editors +/.idea +.project +.classpath +.c9/ +*.launch +.settings/ +*.sublime-workspace + +# IDE - VSCode +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json + +# dotenv environment variable files +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# temp directory +.temp +.tmp + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json diff --git a/lesson_26/api/javascript/api_app/.prettierrc b/lesson_26/api/javascript/api_app/.prettierrc new file mode 100644 index 000000000..a20502b7f --- /dev/null +++ b/lesson_26/api/javascript/api_app/.prettierrc @@ -0,0 +1,4 @@ +{ + "singleQuote": true, + "trailingComma": "all" +} diff --git a/lesson_26/api/javascript/api_app/README.md b/lesson_26/api/javascript/api_app/README.md new file mode 100644 index 000000000..c17103c31 --- /dev/null +++ b/lesson_26/api/javascript/api_app/README.md @@ -0,0 +1,99 @@ +

+ Nest Logo +

+ +[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456 +[circleci-url]: https://circleci.com/gh/nestjs/nest + +

A progressive Node.js framework for building efficient and scalable server-side applications.

+

+NPM Version +Package License +NPM Downloads +CircleCI +Coverage +Discord +Backers on Open Collective +Sponsors on Open Collective + Donate us + Support us + Follow us on Twitter +

+ + +## Description + +[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository. + +## Project setup + +```bash +$ npm install +``` + +## Compile and run the project + +```bash +# development +$ npm run start + +# watch mode +$ npm run start:dev + +# production mode +$ npm run start:prod +``` + +## Run tests + +```bash +# unit tests +$ npm run test + +# e2e tests +$ npm run test:e2e + +# test coverage +$ npm run test:cov +``` + +## Deployment + +When you're ready to deploy your NestJS application to production, there are some key steps you can take to ensure it runs as efficiently as possible. Check out the [deployment documentation](https://docs.nestjs.com/deployment) for more information. + +If you are looking for a cloud-based platform to deploy your NestJS application, check out [Mau](https://mau.nestjs.com), our official platform for deploying NestJS applications on AWS. Mau makes deployment straightforward and fast, requiring just a few simple steps: + +```bash +$ npm install -g mau +$ mau deploy +``` + +With Mau, you can deploy your application in just a few clicks, allowing you to focus on building features rather than managing infrastructure. + +## Resources + +Check out a few resources that may come in handy when working with NestJS: + +- Visit the [NestJS Documentation](https://docs.nestjs.com) to learn more about the framework. +- For questions and support, please visit our [Discord channel](https://discord.gg/G7Qnnhy). +- To dive deeper and get more hands-on experience, check out our official video [courses](https://courses.nestjs.com/). +- Deploy your application to AWS with the help of [NestJS Mau](https://mau.nestjs.com) in just a few clicks. +- Visualize your application graph and interact with the NestJS application in real-time using [NestJS Devtools](https://devtools.nestjs.com). +- Need help with your project (part-time to full-time)? Check out our official [enterprise support](https://enterprise.nestjs.com). +- To stay in the loop and get updates, follow us on [X](https://x.com/nestframework) and [LinkedIn](https://linkedin.com/company/nestjs). +- Looking for a job, or have a job to offer? Check out our official [Jobs board](https://jobs.nestjs.com). + +## Support + +Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support). + +## Stay in touch + +- Author - [Kamil Myśliwiec](https://twitter.com/kammysliwiec) +- Website - [https://nestjs.com](https://nestjs.com/) +- Twitter - [@nestframework](https://twitter.com/nestframework) + +## License + +Nest is [MIT licensed](https://github.com/nestjs/nest/blob/master/LICENSE). diff --git a/lesson_26/api/javascript/api_app/nest-cli.json b/lesson_26/api/javascript/api_app/nest-cli.json new file mode 100644 index 000000000..f9aa683b1 --- /dev/null +++ b/lesson_26/api/javascript/api_app/nest-cli.json @@ -0,0 +1,8 @@ +{ + "$schema": "https://json.schemastore.org/nest-cli", + "collection": "@nestjs/schematics", + "sourceRoot": "src", + "compilerOptions": { + "deleteOutDir": true + } +} diff --git a/lesson_26/api/javascript/api_app/package-lock.json b/lesson_26/api/javascript/api_app/package-lock.json new file mode 100644 index 000000000..aeda27228 --- /dev/null +++ b/lesson_26/api/javascript/api_app/package-lock.json @@ -0,0 +1,9201 @@ +{ + "name": "api_app", + "version": "0.0.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "api_app", + "version": "0.0.1", + "license": "UNLICENSED", + "dependencies": { + "@nestjs/common": "^10.4.15", + "@nestjs/core": "^10.4.15", + "@nestjs/platform-express": "^10.4.15", + "@nestjs/swagger": "^8.1.0", + "reflect-metadata": "^0.2.2", + "rxjs": "^7.8.1" + }, + "devDependencies": { + "@nestjs/cli": "^10.4.9", + "@nestjs/schematics": "^10.2.3", + "@nestjs/testing": "^10.4.15", + "@stylistic/eslint-plugin": "^2.12.1", + "@types/express": "^5.0.0", + "@types/jest": "^29.5.14", + "@types/node": "^22.10.2", + "@types/supertest": "^6.0.2", + "@typescript-eslint/eslint-plugin": "^8.18.0", + "@typescript-eslint/parser": "^8.18.0", + "eslint": "^9.17.0", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-prettier": "^5.2.1", + "jest": "^29.7.0", + "prettier": "^3.4.2", + "source-map-support": "^0.5.21", + "supertest": "^7.0.0", + "ts-jest": "^29.2.5", + "ts-loader": "^9.5.1", + "ts-node": "^10.9.2", + "tsconfig-paths": "^4.2.0", + "typescript": "^5.7.2" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@angular-devkit/core": { + "version": "17.3.11", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-17.3.11.tgz", + "integrity": "sha512-vTNDYNsLIWpYk2I969LMQFH29GTsLzxNk/0cLw5q56ARF0v5sIWfHYwGTS88jdDqIpuuettcSczbxeA7EuAmqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "8.12.0", + "ajv-formats": "2.1.1", + "jsonc-parser": "3.2.1", + "picomatch": "4.0.1", + "rxjs": "7.8.1", + "source-map": "0.7.4" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "chokidar": "^3.5.2" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/schematics": { + "version": "17.3.11", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-17.3.11.tgz", + "integrity": "sha512-I5wviiIqiFwar9Pdk30Lujk8FczEEc18i22A5c6Z9lbmhPQdTroDnEQdsfXjy404wPe8H62s0I15o4pmMGfTYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-devkit/core": "17.3.11", + "jsonc-parser": "3.2.1", + "magic-string": "0.30.8", + "ora": "5.4.1", + "rxjs": "7.8.1" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular-devkit/schematics-cli": { + "version": "17.3.11", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics-cli/-/schematics-cli-17.3.11.tgz", + "integrity": "sha512-kcOMqp+PHAKkqRad7Zd7PbpqJ0LqLaNZdY1+k66lLWmkEBozgq8v4ASn/puPWf9Bo0HpCiK+EzLf0VHE8Z/y6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-devkit/core": "17.3.11", + "@angular-devkit/schematics": "17.3.11", + "ansi-colors": "4.1.3", + "inquirer": "9.2.15", + "symbol-observable": "4.0.0", + "yargs-parser": "21.1.1" + }, + "bin": { + "schematics": "bin/schematics.js" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular-devkit/schematics-cli/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@angular-devkit/schematics-cli/node_modules/cli-width": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 12" + } + }, + "node_modules/@angular-devkit/schematics-cli/node_modules/inquirer": { + "version": "9.2.15", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-9.2.15.tgz", + "integrity": "sha512-vI2w4zl/mDluHt9YEQ/543VTCwPKWiHzKtm9dM2V0NdFcqEexDAjUHzO1oA60HRNaVifGXXM1tRRNluLVHa0Kg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ljharb/through": "^2.3.12", + "ansi-escapes": "^4.3.2", + "chalk": "^5.3.0", + "cli-cursor": "^3.1.0", + "cli-width": "^4.1.0", + "external-editor": "^3.1.0", + "figures": "^3.2.0", + "lodash": "^4.17.21", + "mute-stream": "1.0.0", + "ora": "^5.4.1", + "run-async": "^3.0.0", + "rxjs": "^7.8.1", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^6.2.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@angular-devkit/schematics-cli/node_modules/mute-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz", + "integrity": "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@angular-devkit/schematics-cli/node_modules/run-async": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-3.0.0.tgz", + "integrity": "sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", + "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.25.9", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.2.tgz", + "integrity": "sha512-Z0WgzSEa+aUcdiJuCIqgujCshpMWgUpgOxXotrYPSA53hA3qopNaqcJpyr0hVb1FeWdnqFA35/fUtXgBK8srQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.0.tgz", + "integrity": "sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.26.0", + "@babel/generator": "^7.26.0", + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-module-transforms": "^7.26.0", + "@babel/helpers": "^7.26.0", + "@babel/parser": "^7.26.0", + "@babel/template": "^7.25.9", + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.26.0", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.2.tgz", + "integrity": "sha512-zevQbhbau95nkoxSq3f/DC/SC+EEOUZd3DYqfSkMhY2/wfSeaHV1Ew4vk8e+x8lja31IbyuUa2uQ3JONqKbysw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.26.2", + "@babel/types": "^7.26.0", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.9.tgz", + "integrity": "sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.25.9", + "@babel/helper-validator-option": "^7.25.9", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", + "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", + "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.9.tgz", + "integrity": "sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", + "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", + "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", + "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.0.tgz", + "integrity": "sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.25.9", + "@babel/types": "^7.26.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.2.tgz", + "integrity": "sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.26.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "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, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@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, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.26.0.tgz", + "integrity": "sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz", + "integrity": "sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@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, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@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, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.9.tgz", + "integrity": "sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz", + "integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.25.9", + "@babel/parser": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.9.tgz", + "integrity": "sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.25.9", + "@babel/generator": "^7.25.9", + "@babel/parser": "^7.25.9", + "@babel/template": "^7.25.9", + "@babel/types": "^7.25.9", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/types": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.0.tgz", + "integrity": "sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", + "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.1.tgz", + "integrity": "sha512-fo6Mtm5mWyKjA/Chy1BYTdn5mGJoDNjC7C64ug20ADsRDGrA85bN3uK3MaKbeRkRuuIEAR5N33Jr1pbm411/PA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.5", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-array/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/core": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.9.1.tgz", + "integrity": "sha512-GuUdqkyyzQI5RMIWkHhvTWLCyLo1jNK3vzkSyaExH5kHPDHcuL2VOpHjmMY+y3+NC69qAKToBqldTBgYeLSr9Q==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.2.0.tgz", + "integrity": "sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/js": { + "version": "9.17.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.17.0.tgz", + "integrity": "sha512-Sxc4hqcs1kTu0iID3kcZDW3JHq2a77HO9P8CP6YEA/FpH3Ll8UXE2r/86Rz9YJLKme39S9vU5OWNjC6Xl0Cr3w==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.5.tgz", + "integrity": "sha512-o0bhxnL89h5Bae5T318nFoFzGy+YE5i/gGkoPAgkmTVdRKTiv3p8JHevPiPaMwoloKfEiiaHlawCqaZMqRm+XQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.4.tgz", + "integrity": "sha512-zSkKow6H5Kdm0ZUQUB2kV5JIXqoG0+uH5YADhaEHswm664N9Db8dXSi0nMJpacpMf+MyyglF1vnZohpEg5yUtg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.1.tgz", + "integrity": "sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", + "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", + "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/reporters": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^29.7.0", + "jest-config": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-resolve-dependencies": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "jest-watcher": "^29.7.0", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/environment": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", + "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "^29.7.0", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", + "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", + "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/types": "^29.6.3", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", + "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^6.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/reporters/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@jest/reporters/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@jest/reporters/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", + "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.18", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", + "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", + "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@ljharb/through": { + "version": "2.3.13", + "resolved": "https://registry.npmjs.org/@ljharb/through/-/through-2.3.13.tgz", + "integrity": "sha512-/gKJun8NNiWGZJkGzI/Ragc53cOdcLNdzjLaIa+GEjguQs0ulsurx8WN0jijdK9yPqDvziX995sMRLyLt1uZMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/@lukeed/csprng": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@lukeed/csprng/-/csprng-1.1.0.tgz", + "integrity": "sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@microsoft/tsdoc": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.15.0.tgz", + "integrity": "sha512-HZpPoABogPvjeJOdzCOSJsXeL/SMCBgBZMVC3X3d7YYp2gf31MfxhUoYUNwf1ERPJOnQc0wkFn9trqI6ZEdZuA==", + "license": "MIT" + }, + "node_modules/@nestjs/cli": { + "version": "10.4.9", + "resolved": "https://registry.npmjs.org/@nestjs/cli/-/cli-10.4.9.tgz", + "integrity": "sha512-s8qYd97bggqeK7Op3iD49X2MpFtW4LVNLAwXFkfbRxKME6IYT7X0muNTJ2+QfI8hpbNx9isWkrLWIp+g5FOhiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-devkit/core": "17.3.11", + "@angular-devkit/schematics": "17.3.11", + "@angular-devkit/schematics-cli": "17.3.11", + "@nestjs/schematics": "^10.0.1", + "chalk": "4.1.2", + "chokidar": "3.6.0", + "cli-table3": "0.6.5", + "commander": "4.1.1", + "fork-ts-checker-webpack-plugin": "9.0.2", + "glob": "10.4.5", + "inquirer": "8.2.6", + "node-emoji": "1.11.0", + "ora": "5.4.1", + "tree-kill": "1.2.2", + "tsconfig-paths": "4.2.0", + "tsconfig-paths-webpack-plugin": "4.2.0", + "typescript": "5.7.2", + "webpack": "5.97.1", + "webpack-node-externals": "3.0.0" + }, + "bin": { + "nest": "bin/nest.js" + }, + "engines": { + "node": ">= 16.14" + }, + "peerDependencies": { + "@swc/cli": "^0.1.62 || ^0.3.0 || ^0.4.0 || ^0.5.0", + "@swc/core": "^1.3.62" + }, + "peerDependenciesMeta": { + "@swc/cli": { + "optional": true + }, + "@swc/core": { + "optional": true + } + } + }, + "node_modules/@nestjs/common": { + "version": "10.4.15", + "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-10.4.15.tgz", + "integrity": "sha512-vaLg1ZgwhG29BuLDxPA9OAcIlgqzp9/N8iG0wGapyUNTf4IY4O6zAHgN6QalwLhFxq7nOI021vdRojR1oF3bqg==", + "license": "MIT", + "dependencies": { + "iterare": "1.2.1", + "tslib": "2.8.1", + "uid": "2.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nest" + }, + "peerDependencies": { + "class-transformer": "*", + "class-validator": "*", + "reflect-metadata": "^0.1.12 || ^0.2.0", + "rxjs": "^7.1.0" + }, + "peerDependenciesMeta": { + "class-transformer": { + "optional": true + }, + "class-validator": { + "optional": true + } + } + }, + "node_modules/@nestjs/core": { + "version": "10.4.15", + "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-10.4.15.tgz", + "integrity": "sha512-UBejmdiYwaH6fTsz2QFBlC1cJHM+3UDeLZN+CiP9I1fRv2KlBZsmozGLbV5eS1JAVWJB4T5N5yQ0gjN8ZvcS2w==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "@nuxtjs/opencollective": "0.3.2", + "fast-safe-stringify": "2.1.1", + "iterare": "1.2.1", + "path-to-regexp": "3.3.0", + "tslib": "2.8.1", + "uid": "2.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nest" + }, + "peerDependencies": { + "@nestjs/common": "^10.0.0", + "@nestjs/microservices": "^10.0.0", + "@nestjs/platform-express": "^10.0.0", + "@nestjs/websockets": "^10.0.0", + "reflect-metadata": "^0.1.12 || ^0.2.0", + "rxjs": "^7.1.0" + }, + "peerDependenciesMeta": { + "@nestjs/microservices": { + "optional": true + }, + "@nestjs/platform-express": { + "optional": true + }, + "@nestjs/websockets": { + "optional": true + } + } + }, + "node_modules/@nestjs/mapped-types": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@nestjs/mapped-types/-/mapped-types-2.0.6.tgz", + "integrity": "sha512-84ze+CPfp1OWdpRi1/lOu59hOhTz38eVzJvRKrg9ykRFwDz+XleKfMsG0gUqNZYFa6v53XYzeD+xItt8uDW7NQ==", + "license": "MIT", + "peerDependencies": { + "@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0", + "class-transformer": "^0.4.0 || ^0.5.0", + "class-validator": "^0.13.0 || ^0.14.0", + "reflect-metadata": "^0.1.12 || ^0.2.0" + }, + "peerDependenciesMeta": { + "class-transformer": { + "optional": true + }, + "class-validator": { + "optional": true + } + } + }, + "node_modules/@nestjs/platform-express": { + "version": "10.4.15", + "resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-10.4.15.tgz", + "integrity": "sha512-63ZZPkXHjoDyO7ahGOVcybZCRa7/Scp6mObQKjcX/fTEq1YJeU75ELvMsuQgc8U2opMGOBD7GVuc4DV0oeDHoA==", + "license": "MIT", + "dependencies": { + "body-parser": "1.20.3", + "cors": "2.8.5", + "express": "4.21.2", + "multer": "1.4.4-lts.1", + "tslib": "2.8.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nest" + }, + "peerDependencies": { + "@nestjs/common": "^10.0.0", + "@nestjs/core": "^10.0.0" + } + }, + "node_modules/@nestjs/schematics": { + "version": "10.2.3", + "resolved": "https://registry.npmjs.org/@nestjs/schematics/-/schematics-10.2.3.tgz", + "integrity": "sha512-4e8gxaCk7DhBxVUly2PjYL4xC2ifDFexCqq1/u4TtivLGXotVk0wHdYuPYe1tHTHuR1lsOkRbfOCpkdTnigLVg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-devkit/core": "17.3.11", + "@angular-devkit/schematics": "17.3.11", + "comment-json": "4.2.5", + "jsonc-parser": "3.3.1", + "pluralize": "8.0.0" + }, + "peerDependencies": { + "typescript": ">=4.8.2" + } + }, + "node_modules/@nestjs/schematics/node_modules/jsonc-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", + "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@nestjs/swagger": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@nestjs/swagger/-/swagger-8.1.0.tgz", + "integrity": "sha512-8hzH+r/31XshzXHC9vww4T0xjDAxMzvOaT1xAOvvY1LtXTWyNRCUP2iQsCYJOnnMrR+vydWjvRZiuB3hdvaHxA==", + "license": "MIT", + "dependencies": { + "@microsoft/tsdoc": "^0.15.0", + "@nestjs/mapped-types": "2.0.6", + "js-yaml": "4.1.0", + "lodash": "4.17.21", + "path-to-regexp": "3.3.0", + "swagger-ui-dist": "5.18.2" + }, + "peerDependencies": { + "@fastify/static": "^6.0.0 || ^7.0.0", + "@nestjs/common": "^9.0.0 || ^10.0.0", + "@nestjs/core": "^9.0.0 || ^10.0.0", + "class-transformer": "*", + "class-validator": "*", + "reflect-metadata": "^0.1.12 || ^0.2.0" + }, + "peerDependenciesMeta": { + "@fastify/static": { + "optional": true + }, + "class-transformer": { + "optional": true + }, + "class-validator": { + "optional": true + } + } + }, + "node_modules/@nestjs/testing": { + "version": "10.4.15", + "resolved": "https://registry.npmjs.org/@nestjs/testing/-/testing-10.4.15.tgz", + "integrity": "sha512-eGlWESkACMKti+iZk1hs6FUY/UqObmMaa8HAN9JLnaYkoLf1Jeh+EuHlGnfqo/Rq77oznNLIyaA3PFjrFDlNUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "2.8.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nest" + }, + "peerDependencies": { + "@nestjs/common": "^10.0.0", + "@nestjs/core": "^10.0.0", + "@nestjs/microservices": "^10.0.0", + "@nestjs/platform-express": "^10.0.0" + }, + "peerDependenciesMeta": { + "@nestjs/microservices": { + "optional": true + }, + "@nestjs/platform-express": { + "optional": true + } + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "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, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "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, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nuxtjs/opencollective": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@nuxtjs/opencollective/-/opencollective-0.3.2.tgz", + "integrity": "sha512-um0xL3fO7Mf4fDxcqx9KryrB7zgRM5JSlvGN5AGkP6JLM5XEKyjeAiPbNxdXVXQ16isuAhYpvP88NgL2BGd6aA==", + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "consola": "^2.15.0", + "node-fetch": "^2.6.1" + }, + "bin": { + "opencollective": "bin/opencollective.js" + }, + "engines": { + "node": ">=8.0.0", + "npm": ">=5.0.0" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@pkgr/core": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", + "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/@scarf/scarf": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@scarf/scarf/-/scarf-1.4.0.tgz", + "integrity": "sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ==", + "hasInstallScript": true, + "license": "Apache-2.0" + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/@stylistic/eslint-plugin": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-2.12.1.tgz", + "integrity": "sha512-fubZKIHSPuo07FgRTn6S4Nl0uXPRPYVNpyZzIDGfp7Fny6JjNus6kReLD7NI380JXi4HtUTSOZ34LBuNPO1XLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/utils": "^8.13.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", + "estraverse": "^5.3.0", + "picomatch": "^4.0.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "peerDependencies": { + "eslint": ">=8.40.0" + } + }, + "node_modules/@stylistic/eslint-plugin/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@stylistic/eslint-plugin/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.8", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", + "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.6", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz", + "integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.20.7" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/cookiejar": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.5.tgz", + "integrity": "sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/eslint": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", + "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/express": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.0.tgz", + "integrity": "sha512-DvZriSMehGHL1ZNLzi6MidnsDhUZM/x2pRdDIKdwbUNqqwHxMlRdkxtn6/EPKyqKpHqTl/4nRZsRNLpZxZRpPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^5.0.0", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.1.tgz", + "integrity": "sha512-CRICJIl0N5cXDONAdlTv5ShATZ4HEwk6kDDIW2/w9qOWKg+NU/5F8wYRWCrONad0/UKkloNSmmyN/wX4rtpbVA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", + "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest": { + "version": "29.5.14", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.14.tgz", + "integrity": "sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "^29.0.0", + "pretty-format": "^29.0.0" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/methods": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@types/methods/-/methods-1.1.4.tgz", + "integrity": "sha512-ymXWVrDiCxTBE3+RIrrP533E70eA+9qu7zdWoHuOmGujkYtzf4HQF96b8nwHLqhuf4ykX61IGRIB38CC6/sImQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.10.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.2.tgz", + "integrity": "sha512-Xxr6BBRCAOQixvonOye19wnzyDiUtTeqldOOmj3CkeblonbccA12PFwlufvRdrpjXxqnmUaeiU5EOA+7s5diUQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.20.0" + } + }, + "node_modules/@types/qs": { + "version": "6.9.17", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.17.tgz", + "integrity": "sha512-rX4/bPcfmvxHDv0XjfJELTTr+iB+tn032nPILqHm5wbthUUUuVtNGGqzhya9XUxjTP8Fpr0qYgSZZKxGY++svQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/send": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.7", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", + "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "*" + } + }, + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/superagent": { + "version": "8.1.9", + "resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-8.1.9.tgz", + "integrity": "sha512-pTVjI73witn+9ILmoJdajHGW2jkSaOzhiFYF1Rd3EQ94kymLqB9PjD9ISg7WaALC7+dCHT0FGe9T2LktLq/3GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/cookiejar": "^2.1.5", + "@types/methods": "^1.1.4", + "@types/node": "*", + "form-data": "^4.0.0" + } + }, + "node_modules/@types/supertest": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@types/supertest/-/supertest-6.0.2.tgz", + "integrity": "sha512-137ypx2lk/wTQbW6An6safu9hXmajAifU/s7szAHLN/FeIm5w7yR0Wkl9fdJMRSHwOn4HLAI0DaB2TOORuhPDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/methods": "^1.1.4", + "@types/superagent": "^8.1.0" + } + }, + "node_modules/@types/yargs": { + "version": "17.0.33", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", + "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.18.0.tgz", + "integrity": "sha512-NR2yS7qUqCL7AIxdJUQf2MKKNDVNaig/dEB0GBLU7D+ZdHgK1NoH/3wsgO3OnPVipn51tG3MAwaODEGil70WEw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.18.0", + "@typescript-eslint/type-utils": "8.18.0", + "@typescript-eslint/utils": "8.18.0", + "@typescript-eslint/visitor-keys": "8.18.0", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.18.0.tgz", + "integrity": "sha512-hgUZ3kTEpVzKaK3uNibExUYm6SKKOmTU2BOxBSvOYwtJEPdVQ70kZJpPjstlnhCHcuc2WGfSbpKlb/69ttyN5Q==", + "dev": true, + "license": "MITClause", + "dependencies": { + "@typescript-eslint/scope-manager": "8.18.0", + "@typescript-eslint/types": "8.18.0", + "@typescript-eslint/typescript-estree": "8.18.0", + "@typescript-eslint/visitor-keys": "8.18.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.18.0.tgz", + "integrity": "sha512-PNGcHop0jkK2WVYGotk/hxj+UFLhXtGPiGtiaWgVBVP1jhMoMCHlTyJA+hEj4rszoSdLTK3fN4oOatrL0Cp+Xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.18.0", + "@typescript-eslint/visitor-keys": "8.18.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.18.0.tgz", + "integrity": "sha512-er224jRepVAVLnMF2Q7MZJCq5CsdH2oqjP4dT7K6ij09Kyd+R21r7UVJrF0buMVdZS5QRhDzpvzAxHxabQadow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/typescript-estree": "8.18.0", + "@typescript-eslint/utils": "8.18.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.18.0.tgz", + "integrity": "sha512-FNYxgyTCAnFwTrzpBGq+zrnoTO4x0c1CKYY5MuUTzpScqmY5fmsh2o3+57lqdI3NZucBDCzDgdEbIaNfAjAHQA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.18.0.tgz", + "integrity": "sha512-rqQgFRu6yPkauz+ms3nQpohwejS8bvgbPyIDq13cgEDbkXt4LH4OkDMT0/fN1RUtzG8e8AKJyDBoocuQh8qNeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.18.0", + "@typescript-eslint/visitor-keys": "8.18.0", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.8.0" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.18.0.tgz", + "integrity": "sha512-p6GLdY383i7h5b0Qrfbix3Vc3+J2k6QWw6UMUeY5JGfm3C5LbZ4QIZzJNoNOfgyRe0uuYKjvVOsO/jD4SJO+xg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.18.0", + "@typescript-eslint/types": "8.18.0", + "@typescript-eslint/typescript-estree": "8.18.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.18.0.tgz", + "integrity": "sha512-pCh/qEA8Lb1wVIqNvBke8UaRjJ6wrAWkJO5yyIbs8Yx6TNGYyfNjOo61tLv+WwLvoLPp4BQ8B7AHKijl8NGUfw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.18.0", + "eslint-visitor-keys": "^4.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", + "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/helper-numbers": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", + "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", + "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", + "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", + "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.13.2", + "@webassemblyjs/helper-api-error": "1.13.2", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", + "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", + "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/wasm-gen": "1.14.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", + "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", + "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", + "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", + "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/helper-wasm-section": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-opt": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1", + "@webassemblyjs/wast-printer": "1.14.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", + "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", + "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", + "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-api-error": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", + "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-escapes": { + "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, + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "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, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/append-field": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", + "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==", + "license": "MIT" + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true, + "license": "MIT" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "license": "MIT" + }, + "node_modules/array-timsort": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-timsort/-/array-timsort-1.0.3.tgz", + "integrity": "sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "dev": true, + "license": "MIT" + }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "dev": true, + "license": "MIT" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/babel-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", + "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/transform": "^29.7.0", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.6.3", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-plugin-istanbul": { + "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, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", + "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.1.0.tgz", + "integrity": "sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@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.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@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" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/babel-preset-jest": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", + "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", + "dev": true, + "license": "MIT", + "dependencies": { + "babel-plugin-jest-hoist": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bl/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/body-parser": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.13.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.24.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz", + "integrity": "sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001669", + "electron-to-chromium": "^1.5.41", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.1" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-json-stable-stringify": "2.x" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "license": "MIT" + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001683", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001683.tgz", + "integrity": "sha512-iqmNnThZ0n70mNwvxpEC2nBJ037ZHZUoBI5Gorh1Mw6IlEAZujEoU1tXA628iZfzm7R9FvFzxbfdgml82a3k8Q==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true, + "license": "MIT" + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", + "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0" + } + }, + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cjs-module-lexer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.1.tgz", + "integrity": "sha512-cuSVIHi9/9E/+821Qjdvngor+xpnlwnuwIyZOaLmHBVdXL+gP+I6QQB9VkO7RI77YIcTV+S1W9AreJ5eN63JBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-table3": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.5.tgz", + "integrity": "sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "string-width": "^4.2.0" + }, + "engines": { + "node": "10.* || >= 12.*" + }, + "optionalDependencies": { + "@colors/colors": "1.5.0" + } + }, + "node_modules/cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 10" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", + "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/comment-json": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/comment-json/-/comment-json-4.2.5.tgz", + "integrity": "sha512-bKw/r35jR3HGt5PEPm1ljsQQGyCrR8sFGNiN5L+ykDHdpO8Smxkrkla9Yi6NkQyUrb8V54PGhfMs6NrIwtxtdw==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-timsort": "^1.0.3", + "core-util-is": "^1.0.3", + "esprima": "^4.0.1", + "has-own-prop": "^2.0.0", + "repeat-string": "^1.6.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/component-emitter": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", + "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "engines": [ + "node >= 0.8" + ], + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/consola": { + "version": "2.15.3", + "resolved": "https://registry.npmjs.org/consola/-/consola-2.15.3.tgz", + "integrity": "sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==", + "license": "MIT" + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cookie": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "license": "MIT" + }, + "node_modules/cookiejar": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz", + "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==", + "dev": true, + "license": "MIT" + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "license": "MIT" + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/cosmiconfig": { + "version": "8.3.6", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", + "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/create-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", + "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "prompts": "^2.0.1" + }, + "bin": { + "create-jest": "bin/create-jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/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, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/dedent": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz", + "integrity": "sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/dezalgo": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", + "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", + "dev": true, + "license": "ISC", + "dependencies": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/ejs": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", + "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "jake": "^10.8.5" + }, + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.64", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.64.tgz", + "integrity": "sha512-IXEuxU+5ClW2IGEYFC2T7szbyVgehupCWQe5GNh+H065CD6U6IFN0s4KeAMFGNmQolRU4IV7zGBWSYMmZ8uuqQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.17.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", + "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", + "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==", + "dev": true, + "license": "MIT" + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.17.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.17.0.tgz", + "integrity": "sha512-evtlNcpJg+cZLcnVKwsai8fExnqjGPicK7gnUtlNuzu+Fv9bI0aLpND5T44VLQtoMEnI57LoXO9XAkIXwohKrA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.19.0", + "@eslint/core": "^0.9.0", + "@eslint/eslintrc": "^3.2.0", + "@eslint/js": "9.17.0", + "@eslint/plugin-kit": "^0.2.3", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.1", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.2.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-config-prettier": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", + "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", + "dev": true, + "license": "MIT", + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.1.tgz", + "integrity": "sha512-gH3iR3g4JfF+yYPaJYkN7jEl9QbweL/YfkoRlNnuIEHEz1vHVlCmWOS+eGGiRuzHQXdJFCOTxRgvju9b8VUmrw==", + "dev": true, + "license": "MIT", + "dependencies": { + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.9.1" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-plugin-prettier" + }, + "peerDependencies": { + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "eslint-config-prettier": "*", + "prettier": ">=3.0.0" + }, + "peerDependenciesMeta": { + "@types/eslint": { + "optional": true + }, + "eslint-config-prettier": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz", + "integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/eslint/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/espree": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", + "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.14.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/execa/node_modules/signal-exit": { + "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, + "license": "ISC" + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/express": { + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.3", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.7.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.3.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.12", + "proxy-addr": "~2.0.7", + "qs": "6.13.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.19.0", + "serve-static": "1.16.2", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/express/node_modules/path-to-regexp": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", + "license": "MIT" + }, + "node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "license": "MIT", + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/figures/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/filelist": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", + "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "minimatch": "^5.0.1" + } + }, + "node_modules/filelist/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.2.tgz", + "integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==", + "dev": true, + "license": "ISC" + }, + "node_modules/foreground-child": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/fork-ts-checker-webpack-plugin": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-9.0.2.tgz", + "integrity": "sha512-Uochze2R8peoN1XqlSi/rGUkDQpRogtLFocP9+PGu68zk1BDAKXfdeCdyVZpgTk8V8WFVQXdEz426VKjXLO1Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.16.7", + "chalk": "^4.1.2", + "chokidar": "^3.5.3", + "cosmiconfig": "^8.2.0", + "deepmerge": "^4.2.2", + "fs-extra": "^10.0.0", + "memfs": "^3.4.1", + "minimatch": "^3.0.4", + "node-abort-controller": "^3.0.1", + "schema-utils": "^3.1.1", + "semver": "^7.3.5", + "tapable": "^2.2.1" + }, + "engines": { + "node": ">=12.13.0", + "yarn": ">=1.0.0" + }, + "peerDependencies": { + "typescript": ">3.6.0", + "webpack": "^5.11.0" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/form-data": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", + "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/formidable": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-3.5.2.tgz", + "integrity": "sha512-Jqc1btCy3QzRbJaICGwKcBfGWuLADRerLzDqi2NwSt/UkXLsHJw2TVResiaoBufHVHy9aSgClOHCeJsSsFLTbg==", + "dev": true, + "license": "MIT", + "dependencies": { + "dezalgo": "^1.0.4", + "hexoid": "^2.0.0", + "once": "^1.4.0" + }, + "funding": { + "url": "https://ko-fi.com/tunnckoCore/commissions" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/fs-monkey": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.6.tgz", + "integrity": "sha512-b1FMfwetIKymC0eioW7mTywihSQE4oLzQn1dB6rZB5fx/3NpNEdAWeCSMB+60/AeT0TCXsxzAlcYVEFCTAksWg==", + "dev": true, + "license": "Unlicense" + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-own-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-own-prop/-/has-own-prop-2.0.0.tgz", + "integrity": "sha512-Pq0h+hvsVm6dDEa8x82GnLSYHOzNDt7f0ddFa3FqcQlgzEiptPqL+XrOJNavjOzSYiYWIrgeVYYgGlLmnxwilQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hexoid": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hexoid/-/hexoid-2.0.0.tgz", + "integrity": "sha512-qlspKUK7IlSQv2o+5I7yhUd7TxlOG2Vr5LTa3ve2XSNVKAL/n/u/7KLvKmFNimomDIKvZFXWHv0T12mv7rT8Aw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-local": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/inquirer": { + "version": "8.2.6", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz", + "integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^4.2.1", + "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.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^6.0.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", + "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/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, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps": { + "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, + "license": "BSD-3-Clause", + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/istanbul-reports": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", + "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/iterare": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/iterare/-/iterare-1.2.1.tgz", + "integrity": "sha512-RKYVTCjAnRthyJes037NX/IiqeidgN1xc3j1RjFfECFp28A1GVwK9nA+i0rJPaHqSZwygLzRnFlzUuHFoWWy+Q==", + "license": "ISC", + "engines": { + "node": ">=6" + } + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jake": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.2.tgz", + "integrity": "sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "async": "^3.2.3", + "chalk": "^4.0.2", + "filelist": "^1.0.4", + "minimatch": "^3.1.2" + }, + "bin": { + "jake": "bin/cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jake/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/jake/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", + "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/types": "^29.6.3", + "import-local": "^3.0.2", + "jest-cli": "^29.7.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", + "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "execa": "^5.0.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", + "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^1.0.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.7.0", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0", + "pretty-format": "^29.7.0", + "pure-rand": "^6.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-cli": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", + "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "create-jest": "^29.7.0", + "exit": "^0.1.2", + "import-local": "^3.0.2", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "yargs": "^17.3.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-config": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", + "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-jest": "^29.7.0", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-config/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/jest-config/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/jest-config/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-docblock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", + "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", + "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "jest-util": "^29.7.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-environment-node": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", + "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", + "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-leak-detector": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", + "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", + "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "resolve": "^1.20.0", + "resolve.exports": "^2.0.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", + "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-regex-util": "^29.6.3", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", + "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/environment": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-leak-detector": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-resolve": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-util": "^29.7.0", + "jest-watcher": "^29.7.0", + "jest-worker": "^29.7.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jest-runner/node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/jest-runtime": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", + "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/globals": "^29.7.0", + "@jest/source-map": "^29.6.3", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/jest-runtime/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/jest-runtime/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/jest-snapshot": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", + "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "natural-compare": "^1.4.0", + "pretty-format": "^29.7.0", + "semver": "^7.5.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-util/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/jest-validate": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watcher": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", + "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "jest-util": "^29.7.0", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonc-parser": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", + "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "license": "MIT" + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/log-symbols": { + "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, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/magic-string": { + "version": "0.30.8", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.8.tgz", + "integrity": "sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "license": "ISC" + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "dev": true, + "license": "Unlicense", + "dependencies": { + "fs-monkey": "^1.0.4" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "license": "MIT", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/multer": { + "version": "1.4.4-lts.1", + "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.4-lts.1.tgz", + "integrity": "sha512-WeSGziVj6+Z2/MwQo3GvqzgR+9Uc+qt8SwHKh3gvNPiISKfsMfG4SvCOFYlxxgkXt7yIV2i1yczehm0EOKIxIg==", + "license": "MIT", + "dependencies": { + "append-field": "^1.0.0", + "busboy": "^1.0.0", + "concat-stream": "^1.5.2", + "mkdirp": "^0.5.4", + "object-assign": "^4.1.1", + "type-is": "^1.6.4", + "xtend": "^4.0.0" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true, + "license": "ISC" + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-abort-controller": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz", + "integrity": "sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-emoji": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.11.0.tgz", + "integrity": "sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash": "^4.17.21" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", + "dev": true, + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/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, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz", + "integrity": "sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/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, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/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, + "license": "MIT", + "dependencies": { + "@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" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/path-to-regexp": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-3.3.0.tgz", + "integrity": "sha512-qyCH421YQPS2WFDxDjftfc1ZR5WKQzVzqsp4n9M2kQhVOo/ByahFoUNJfl58kOcEGfQ//7weFTDhm+ss8Ecxgw==", + "license": "MIT" + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.1.tgz", + "integrity": "sha512-xUXwsxNjwTQ8K3GnT4pCJm+xq3RUPQbmkYJTP5aFIfNIvbcc/4MUxgBaaRSZJ6yGJZiGSyYlM6MzwTsRk8SYCg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.2.tgz", + "integrity": "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "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, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "license": "MIT" + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/proxy-addr": { + "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==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pure-rand": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT" + }, + "node_modules/qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/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, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/readdirp/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/reflect-metadata": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", + "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==", + "license": "Apache-2.0" + }, + "node_modules/repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/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, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/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, + "license": "MIT", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-cwd/node_modules/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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve.exports": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", + "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/restore-cursor/node_modules/signal-exit": { + "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, + "license": "ISC" + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/run-parallel": { + "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, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/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==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/schema-utils/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/schema-utils/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/schema-utils/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-static": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.19.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/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, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 8" + } + }, + "node_modules/source-map-support": { + "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, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-width": { + "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, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "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, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/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, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/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, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/superagent": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-9.0.2.tgz", + "integrity": "sha512-xuW7dzkUpcJq7QnhOsnNUgtYp3xRwpt2F7abdRYIpCsAt0hhUqia0EdxyXZQQpNmGtsCzYHryaKSV3q3GJnq7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "component-emitter": "^1.3.0", + "cookiejar": "^2.1.4", + "debug": "^4.3.4", + "fast-safe-stringify": "^2.1.1", + "form-data": "^4.0.0", + "formidable": "^3.5.1", + "methods": "^1.1.2", + "mime": "2.6.0", + "qs": "^6.11.0" + }, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/superagent/node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true, + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/supertest": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/supertest/-/supertest-7.0.0.tgz", + "integrity": "sha512-qlsr7fIC0lSddmA3tzojvzubYxvlGtzumcdHgPwbFWMISQwL22MhM2Y3LNt+6w9Yyx7559VW5ab70dgphm8qQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "methods": "^1.1.2", + "superagent": "^9.0.1" + }, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/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==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/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, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/swagger-ui-dist": { + "version": "5.18.2", + "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.18.2.tgz", + "integrity": "sha512-J+y4mCw/zXh1FOj5wGJvnAajq6XgHOyywsa9yITmwxIlJbMqITq3gYRZHaeqLVH/eV/HOPphE6NjF+nbSNC5Zw==", + "license": "Apache-2.0", + "dependencies": { + "@scarf/scarf": "=1.4.0" + } + }, + "node_modules/symbol-observable": { + "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, + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/synckit": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.2.tgz", + "integrity": "sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@pkgr/core": "^0.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/terser": { + "version": "5.36.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.36.0.tgz", + "integrity": "sha512-IYV9eNMuFAV4THUspIRXkLakHnV6XO7FEdtKjf/mDyrnqUg9LnlOn6/RwRvM9SZjR4GUq8Nk8zj67FzVARr74w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.10", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", + "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.20", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.26.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser-webpack-plugin/node_modules/jest-worker": { + "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, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/terser-webpack-plugin/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/test-exclude/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/test-exclude/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/test-exclude/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "license": "MIT", + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/ts-api-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.0.tgz", + "integrity": "sha512-032cPxaEKwM+GT3vA5JXNzIaizx388rhsSW79vGRNGXfRRAdEAn2mvk36PvK5HnOchyWZ7afLEXqYCvPCrzuzQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/ts-jest": { + "version": "29.2.5", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.2.5.tgz", + "integrity": "sha512-KD8zB2aAZrcKIdGk4OwpJggeLcH1FgrICqDSROWqlnJXGCXK4Mn6FcdK2B6670Xr73lHMG1kHw8R87A0ecZ+vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "bs-logger": "^0.2.6", + "ejs": "^3.1.10", + "fast-json-stable-stringify": "^2.1.0", + "jest-util": "^29.0.0", + "json5": "^2.2.3", + "lodash.memoize": "^4.1.2", + "make-error": "^1.3.6", + "semver": "^7.6.3", + "yargs-parser": "^21.1.1" + }, + "bin": { + "ts-jest": "cli.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.0.0-beta.0 <8", + "@jest/transform": "^29.0.0", + "@jest/types": "^29.0.0", + "babel-jest": "^29.0.0", + "jest": "^29.0.0", + "typescript": ">=4.3 <6" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@jest/transform": { + "optional": true + }, + "@jest/types": { + "optional": true + }, + "babel-jest": { + "optional": true + }, + "esbuild": { + "optional": true + } + } + }, + "node_modules/ts-loader": { + "version": "9.5.1", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.1.tgz", + "integrity": "sha512-rNH3sK9kGZcH9dYzC7CewQm4NtxJTjSEVRJ2DyBZR7f8/wcta+iV44UPCXc5+nzDzivKtlzV6c9P4e+oFhDLYg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "enhanced-resolve": "^5.0.0", + "micromatch": "^4.0.0", + "semver": "^7.3.4", + "source-map": "^0.7.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "typescript": "*", + "webpack": "^5.0.0" + } + }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.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", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/tsconfig-paths": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", + "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "json5": "^2.2.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tsconfig-paths-webpack-plugin": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths-webpack-plugin/-/tsconfig-paths-webpack-plugin-4.2.0.tgz", + "integrity": "sha512-zbem3rfRS8BgeNK50Zz5SIQgXzLafiHjOwUAvk/38/o1jHn/V5QAgVUcz884or7WYcPaH3N2CIfUc2u0ul7UcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "enhanced-resolve": "^5.7.0", + "tapable": "^2.2.1", + "tsconfig-paths": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/tsconfig-paths/node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "license": "MIT" + }, + "node_modules/typescript": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", + "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/uid": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/uid/-/uid-2.0.2.tgz", + "integrity": "sha512-u3xV3X7uzvi5b1MncmZo3i2Aw222Zk1keqLA1YkHldREkAhAqi65wuPfe7lHx8H/Wzy+8CE7S7uS3jekIM5s8g==", + "license": "MIT", + "dependencies": { + "@lukeed/csprng": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/undici-types": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "dev": true, + "license": "MIT" + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", + "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true, + "license": "MIT" + }, + "node_modules/v8-to-istanbul": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/watchpack": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz", + "integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "license": "MIT", + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/webpack": { + "version": "5.97.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.97.1.tgz", + "integrity": "sha512-EksG6gFY3L1eFMROS/7Wzgrii5mBAFe4rIr3r2BTfo7bcc+DWwFZ4OJ/miOuHJO/A85HwyI4eQ0F6IKXesO7Fg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/eslint-scope": "^3.7.7", + "@types/estree": "^1.0.6", + "@webassemblyjs/ast": "^1.14.1", + "@webassemblyjs/wasm-edit": "^1.14.1", + "@webassemblyjs/wasm-parser": "^1.14.1", + "acorn": "^8.14.0", + "browserslist": "^4.24.0", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.17.1", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.11", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.2.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.10", + "watchpack": "^2.4.1", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-node-externals": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/webpack-node-externals/-/webpack-node-externals-3.0.0.tgz", + "integrity": "sha512-LnL6Z3GGDPht/AigwRh2dvL9PQPFQ8skEpVrWZXLWBYmqcaojHNN0onvHzie6rq7EWKrrBfPYqNEzTJgiwEQDQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/webpack-sources": { + "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, + "license": "MIT", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack/node_modules/eslint-scope": { + "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, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/webpack/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/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, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/write-file-atomic/node_modules/signal-exit": { + "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, + "license": "ISC" + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/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, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/lesson_26/api/javascript/api_app/package.json b/lesson_26/api/javascript/api_app/package.json new file mode 100644 index 000000000..8758fafcd --- /dev/null +++ b/lesson_26/api/javascript/api_app/package.json @@ -0,0 +1,72 @@ +{ + "name": "api_app", + "version": "0.0.1", + "description": "", + "author": "", + "private": true, + "license": "UNLICENSED", + "scripts": { + "build": "nest build", + "fix": "prettier --write .", + "start": "nest start", + "start:dev": "nest start --watch", + "start:debug": "nest start --debug --watch", + "start:prod": "node dist/main", + "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix", + "test": "jest", + "test:watch": "jest --watch", + "test:cov": "jest --coverage", + "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand", + "test:e2e": "jest --config ./test/jest-e2e.json", + "check": "npm run lint && npm run test:e2e" + }, + "dependencies": { + "@nestjs/common": "^10.4.15", + "@nestjs/core": "^10.4.15", + "@nestjs/platform-express": "^10.4.15", + "@nestjs/swagger": "^8.1.0", + "reflect-metadata": "^0.2.2", + "rxjs": "^7.8.1" + }, + "devDependencies": { + "@nestjs/cli": "^10.4.9", + "@nestjs/schematics": "^10.2.3", + "@nestjs/testing": "^10.4.15", + "@stylistic/eslint-plugin": "^2.12.1", + "@types/express": "^5.0.0", + "@types/jest": "^29.5.14", + "@types/node": "^22.10.2", + "@types/supertest": "^6.0.2", + "@typescript-eslint/eslint-plugin": "^8.18.0", + "@typescript-eslint/parser": "^8.18.0", + "eslint": "^9.17.0", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-prettier": "^5.2.1", + "jest": "^29.7.0", + "prettier": "^3.4.2", + "source-map-support": "^0.5.21", + "supertest": "^7.0.0", + "ts-jest": "^29.2.5", + "ts-loader": "^9.5.1", + "ts-node": "^10.9.2", + "tsconfig-paths": "^4.2.0", + "typescript": "^5.7.2" + }, + "jest": { + "moduleFileExtensions": [ + "js", + "json", + "ts" + ], + "rootDir": "src", + "testRegex": ".*\\.spec\\.ts$", + "transform": { + "^.+\\.(t|j)s$": "ts-jest" + }, + "collectCoverageFrom": [ + "**/*.(t|j)s" + ], + "coverageDirectory": "../coverage", + "testEnvironment": "node" + } +} diff --git a/lesson_26/api/javascript/api_app/resources/data.json b/lesson_26/api/javascript/api_app/resources/data.json new file mode 100644 index 000000000..99014104f --- /dev/null +++ b/lesson_26/api/javascript/api_app/resources/data.json @@ -0,0 +1,254 @@ +{ + "mediaItems": [ + { + "type": "book", + "id": "e27a4e0d-9664-420d-955e-c0e295d0ce02", + "title": "To Kill a Mockingbird", + "isbn": "978-0061120084", + "authors": ["Harper Lee"], + "pages": 336 + }, + { + "type": "book", + "id": "17dd5d20-98f5-4a26-be09-449fea88a3c3", + "title": "1984", + "isbn": "978-0451524935", + "authors": ["George Orwell"], + "pages": 328 + }, + { + "type": "dvd", + "id": "28e5c91f-0e4b-4be5-abb1-8da01fd5587e", + "title": "The Shawshank Redemption", + "runtime": 142 + }, + { + "type": "dvd", + "id": "295ea581-cd61-4319-8b0c-e5c0c03286c5", + "title": "Inception", + "runtime": 148 + }, + { + "type": "magazine", + "id": "222111dd-c561-462a-8854-853ada4d3421", + "title": "National Geographic", + "edition": "March 2024" + }, + { + "type": "magazine", + "id": "0afd425b-973f-4af9-a6aa-8febe943a8f6", + "title": "Time", + "edition": "March 15, 2024" + }, + { + "type": "newspaper", + "id": "91b74a71-97ad-4fea-b17c-a640c98d355f", + "title": "The New York Times", + "edition": "Morning Edition, March 22, 2024" + }, + { + "type": "newspaper", + "id": "45cab344-b792-484c-9156-d929237dde67", + "title": "The Guardian", + "edition": "March 22, 2024" + }, + { + "type": "book", + "id": "218b55fa-a3cd-4803-805e-7cd1ef3115ac", + "title": "The Great Gatsby", + "isbn": "978-0743273565", + "authors": ["F. Scott Fitzgerald"], + "pages": 180 + }, + { + "type": "book", + "id": "b4249c17-f77b-46da-aa82-7aa227eca5e2", + "title": "Harry Potter and the Sorcerer's Stone", + "isbn": "978-0590353427", + "authors": ["J.K. Rowling"], + "pages": 309 + }, + { + "type": "dvd", + "id": "a3cc5ccb-e2fd-4cd0-a6f8-dc1f2f07589b", + "title": "The Godfather", + "runtime": 175 + }, + { + "type": "dvd", + "id": "6386364c-8505-4dbe-8731-ff8fa0d6e381", + "title": "The Dark Knight", + "runtime": 152 + }, + { + "type": "magazine", + "id": "e5060cc1-33f0-431c-a1b3-d1979e38b6f2", + "title": "Scientific American", + "edition": "April 2024" + }, + { + "type": "magazine", + "id": "7048bd13-49ee-4693-8900-e396bbdf3f98", + "title": "Vogue", + "edition": "Spring 2024" + }, + { + "type": "newspaper", + "id": "6f80a5ce-5958-48f3-a029-ff3d76f2c3fe", + "title": "The Washington Post", + "edition": "Evening Edition, March 22, 2024" + }, + { + "type": "newspaper", + "id": "f5f1196c-7935-417e-bc52-7144f63da3cb", + "title": "The Times", + "edition": "March 23, 2024" + }, + { + "type": "book", + "id": "faf5a804-e02c-4bbc-8505-4ba90a526e28", + "title": "Pride and Prejudice", + "isbn": "978-0141439518", + "authors": ["Jane Austen"], + "pages": 279 + }, + { + "type": "book", + "id": "1aab8182-4345-4ead-98e8-0db53682311b", + "title": "The Catcher in the Rye", + "isbn": "978-0316769488", + "authors": ["J.D. Salinger"], + "pages": 277 + }, + { + "type": "dvd", + "id": "2b92ef3d-b224-4589-9a59-cdaba758affd", + "title": "The Matrix", + "runtime": 136 + }, + { + "type": "dvd", + "id": "e5d75a1d-f3b4-430f-ba63-b6e4603228eb", + "title": "Pulp Fiction", + "runtime": 154 + }, + { + "type": "magazine", + "id": "75fb71ad-ea84-45b8-8396-b790c833573e", + "title": "Wired", + "edition": "May 2024" + }, + { + "type": "magazine", + "id": "e30a6739-cdc9-4b2e-ac67-7278fcfb9a59", + "title": "Forbes", + "edition": "April 2024" + }, + { + "type": "newspaper", + "id": "3e228c29-6163-477a-8b70-e873a3788758", + "title": "Los Angeles Times", + "edition": "Morning Edition, March 23, 2024" + }, + { + "type": "newspaper", + "id": "8e3946e2-d5a6-4cb4-ac92-17cc44935d2d", + "title": "Chicago Tribune", + "edition": "March 23, 2024" + }, + { + "type": "book", + "id": "b08c9da7-5c01-494c-84ec-af3fef9dc480", + "title": "The Lord of the Rings", + "isbn": "978-0544003415", + "authors": ["J.R.R. Tolkien"], + "pages": 1178 + }, + { + "type": "dvd", + "id": "af1ae237-d29a-49d8-a18a-d6193c07a033", + "title": "The Silence of the Lambs", + "runtime": 118 + }, + { + "type": "dvd", + "id": "215af9ba-e881-48fb-8284-a3dc6a1c096d", + "title": "The Departed", + "runtime": 151 + }, + { + "type": "magazine", + "id": "8efcbbb2-5c1e-486c-924d-63c3503f498c", + "title": "The Economist", + "edition": "March 23, 2024" + }, + { + "type": "magazine", + "id": "d39f5cf3-9574-4fdc-b81b-99d31b26ee92", + "title": "The New Yorker", + "edition": "March 25, 2024" + }, + { + "type": "newspaper", + "id": "8b369c0f-6c68-4a84-8e15-8b85a2dd1949", + "title": "USA Today", + "edition": "Morning Edition, March 23, 2024" + }, + { + "type": "newspaper", + "id": "eaf356a3-ae28-4cc5-92a2-9b0264165b5d", + "title": "The Wall Street Journal", + "edition": "March 23, 2024" + } + ], + "guests": [ + { + "type": "librarian", + "name": "John Doe", + "email": "john.doe@fakelibrary.org", + "checkedOutItems": [] + }, + { + "type": "patron", + "name": "Jane Smith", + "email": "jane.smith@example.com", + "checkedOutItems": [ + { + "itemId": "e27a4e0d-9664-420d-955e-c0e295d0ce02", + "dueDate": "2024-04-05T00:00:00Z" + }, + { + "itemId": "295ea581-cd61-4319-8b0c-e5c0c03286c5", + "dueDate": "2024-04-07T00:00:00Z" + } + ] + }, + { + "type": "patron", + "name": "Alice Johnson", + "email": "alice.johnson@example.com", + "checkedOutItems": [ + { + "itemId": "17dd5d20-98f5-4a26-be09-449fea88a3c3", + "dueDate": "2024-04-03T00:00:00Z" + }, + { + "itemId": "28e5c91f-0e4b-4be5-abb1-8da01fd5587e", + "dueDate": "2024-04-06T00:00:00Z" + } + ] + }, + { + "type": "librarian", + "name": "Bob Williams", + "email": "bob.williams@fakelibrary.org", + "checkedOutItems": [] + }, + { + "type": "patron", + "name": "Emily Brown", + "email": "emily.brown@example.com", + "checkedOutItems": [] + } + ] +} diff --git a/lesson_26/api/javascript/api_app/src/app.controller.spec.ts b/lesson_26/api/javascript/api_app/src/app.controller.spec.ts new file mode 100644 index 000000000..d22f3890a --- /dev/null +++ b/lesson_26/api/javascript/api_app/src/app.controller.spec.ts @@ -0,0 +1,22 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { AppController } from './app.controller'; +import { AppService } from './app.service'; + +describe('AppController', () => { + let appController: AppController; + + beforeEach(async () => { + const app: TestingModule = await Test.createTestingModule({ + controllers: [AppController], + providers: [AppService], + }).compile(); + + appController = app.get(AppController); + }); + + describe('root', () => { + it('should return "Hello World!"', () => { + expect(appController.getHello()).toBe('Hello World!'); + }); + }); +}); diff --git a/lesson_26/api/javascript/api_app/src/app.controller.ts b/lesson_26/api/javascript/api_app/src/app.controller.ts new file mode 100644 index 000000000..cce879ee6 --- /dev/null +++ b/lesson_26/api/javascript/api_app/src/app.controller.ts @@ -0,0 +1,12 @@ +import { Controller, Get } from '@nestjs/common'; +import { AppService } from './app.service'; + +@Controller() +export class AppController { + constructor(private readonly appService: AppService) {} + + @Get() + getHello(): string { + return this.appService.getHello(); + } +} diff --git a/lesson_26/api/javascript/api_app/src/app.module.ts b/lesson_26/api/javascript/api_app/src/app.module.ts new file mode 100644 index 000000000..aecf55c45 --- /dev/null +++ b/lesson_26/api/javascript/api_app/src/app.module.ts @@ -0,0 +1,11 @@ +import { Module } from '@nestjs/common'; +import { AppController } from './app.controller'; +import { AppService } from './app.service'; +import { WebModule } from './web/web.module'; + +@Module({ + imports: [WebModule], + controllers: [AppController], + providers: [AppService], +}) +export class AppModule {} diff --git a/lesson_26/api/javascript/api_app/src/app.service.ts b/lesson_26/api/javascript/api_app/src/app.service.ts new file mode 100644 index 000000000..927d7cca0 --- /dev/null +++ b/lesson_26/api/javascript/api_app/src/app.service.ts @@ -0,0 +1,8 @@ +import { Injectable } from '@nestjs/common'; + +@Injectable() +export class AppService { + getHello(): string { + return 'Hello World!'; + } +} diff --git a/lesson_26/api/javascript/api_app/src/data/data.module.ts b/lesson_26/api/javascript/api_app/src/data/data.module.ts new file mode 100644 index 000000000..3d9cd36d9 --- /dev/null +++ b/lesson_26/api/javascript/api_app/src/data/data.module.ts @@ -0,0 +1,14 @@ +import { Module } from '@nestjs/common'; +import { LIBRARY_DATA_LOADER_PROVIDER } from './library_data_loader'; +import { LibraryJsonDataLoader } from './library_json_data_loader'; + +@Module({ + providers: [ + { + provide: LIBRARY_DATA_LOADER_PROVIDER, + useClass: LibraryJsonDataLoader, + }, + ], + exports: [LIBRARY_DATA_LOADER_PROVIDER], +}) +export class DataModule {} diff --git a/lesson_26/api/javascript/api_app/src/data/index.ts b/lesson_26/api/javascript/api_app/src/data/index.ts new file mode 100644 index 000000000..9d2700073 --- /dev/null +++ b/lesson_26/api/javascript/api_app/src/data/index.ts @@ -0,0 +1,5 @@ +export { DataModule } from './data.module'; +export { + LIBRARY_DATA_LOADER_PROVIDER, + LibraryDataLoader, +} from './library_data_loader'; diff --git a/lesson_26/api/javascript/api_app/src/data/library_data_loader.ts b/lesson_26/api/javascript/api_app/src/data/library_data_loader.ts new file mode 100644 index 000000000..d198157d0 --- /dev/null +++ b/lesson_26/api/javascript/api_app/src/data/library_data_loader.ts @@ -0,0 +1,14 @@ +import { LibraryDataModel } from '../models/library_data_model'; + +export const LIBRARY_DATA_LOADER_PROVIDER = Symbol('LibraryDataLoader'); + +/** An object that loads data from a source and returns a LibraryDataModel object. */ +export interface LibraryDataLoader { + /** + * Load data from a source and return a LibraryDataModel object. + * + * @return A LibraryDataModel object. + * @throws Error if an I/O error occurs. + */ + loadData(): Promise; +} diff --git a/lesson_26/api/javascript/api_app/src/data/library_json_data_loader.ts b/lesson_26/api/javascript/api_app/src/data/library_json_data_loader.ts new file mode 100644 index 000000000..44eff7605 --- /dev/null +++ b/lesson_26/api/javascript/api_app/src/data/library_json_data_loader.ts @@ -0,0 +1,12 @@ +import { Injectable } from '@nestjs/common'; +import * as LibraryJsonData from '../../resources/data.json'; +import { LibraryDataModel } from '../models/library_data_model'; +import { LibraryDataLoader } from './library_data_loader'; + +@Injectable() +export class LibraryJsonDataLoader implements LibraryDataLoader { + async loadData() { + const { mediaItems, guests } = LibraryJsonData; + return new LibraryDataModel(mediaItems, guests); + } +} diff --git a/lesson_26/api/javascript/api_app/src/library/book.ts b/lesson_26/api/javascript/api_app/src/library/book.ts new file mode 100644 index 000000000..4bf61860a --- /dev/null +++ b/lesson_26/api/javascript/api_app/src/library/book.ts @@ -0,0 +1,53 @@ +import { MediaItemBase } from './media_item_base'; +import { MediaType } from './media_type'; + +export class Book extends MediaItemBase { + private readonly isbn: string; + private readonly authors: string[]; + private readonly numberOfPages: number; + + constructor( + id: string, + title: string, + isbn: string, + authors: string[], + numberOfPages: number, + ) { + super(id, title); + this.isbn = isbn; + this.authors = authors; + this.numberOfPages = numberOfPages; + } + + getType(): MediaType { + return MediaType.BOOK; + } + + getIsbn(): string { + return this.isbn; + } + + getAuthors(): string[] { + return this.authors; + } + + getNumberOfPages(): number { + return this.numberOfPages; + } + + protected matchesAuthor(authorQuery: string): boolean { + if (!authorQuery) { + return true; + } + for (const author of this.getAuthors()) { + if (author.toLowerCase().includes(authorQuery.toLowerCase())) { + return true; + } + } + return false; + } + + toString(): string { + return `Book{id='${this.getId()}', title='${this.getTitle()}'}`; + } +} diff --git a/lesson_26/api/javascript/api_app/src/library/dvd.ts b/lesson_26/api/javascript/api_app/src/library/dvd.ts new file mode 100644 index 000000000..ec327b4c9 --- /dev/null +++ b/lesson_26/api/javascript/api_app/src/library/dvd.ts @@ -0,0 +1,16 @@ +import { MediaItemBase } from './media_item_base'; +import { MediaType } from './media_type'; + +export class Dvd extends MediaItemBase { + constructor(id: string, title: string) { + super(id, title); + } + + getType(): MediaType { + return MediaType.DVD; + } + + toString(): string { + return `Dvd{id='${this.getId()}', title='${this.getTitle()}'}`; + } +} diff --git a/lesson_26/api/javascript/api_app/src/library/index.ts b/lesson_26/api/javascript/api_app/src/library/index.ts new file mode 100644 index 000000000..bd30f84a7 --- /dev/null +++ b/lesson_26/api/javascript/api_app/src/library/index.ts @@ -0,0 +1,11 @@ +export { Book } from './book'; +export { Dvd } from './dvd'; +export { Librarian } from './librarian'; +export { LibraryModule } from './library.module'; +export { LibraryService } from './library.service'; +export { LibraryGuest } from './library_guest'; +export { Magazine } from './magazine'; +export { MediaItem } from './media_item'; +export { MediaType } from './media_type'; +export { Newspaper } from './newspaper'; +export { Patron } from './patron'; diff --git a/lesson_26/api/javascript/api_app/src/library/librarian.ts b/lesson_26/api/javascript/api_app/src/library/librarian.ts new file mode 100644 index 000000000..bf8a35e9b --- /dev/null +++ b/lesson_26/api/javascript/api_app/src/library/librarian.ts @@ -0,0 +1,12 @@ +import { LibraryGuestBase } from './library_guest_base'; + +/** Represents a librarian of a library. */ +export class Librarian extends LibraryGuestBase { + constructor(name: string, email: string) { + super(name, email); + } + + toString(): string { + return `Librarian{id='${this.getEmail()}', name='${this.getName()}'}`; + } +} diff --git a/lesson_26/api/javascript/api_app/src/library/library.module.ts b/lesson_26/api/javascript/api_app/src/library/library.module.ts new file mode 100644 index 000000000..920ad64d1 --- /dev/null +++ b/lesson_26/api/javascript/api_app/src/library/library.module.ts @@ -0,0 +1,23 @@ +import { Module } from '@nestjs/common'; +import { + DataModule, + LIBRARY_DATA_LOADER_PROVIDER, + LibraryDataLoader, +} from '../data'; +import { LibraryService } from './library.service'; +import { LibraryFactory } from './library_factory'; + +const libraryServiceProvider = { + provide: LibraryService, + useFactory: (loader: LibraryDataLoader) => { + return LibraryFactory.createWithLoader(loader); + }, + inject: [LIBRARY_DATA_LOADER_PROVIDER], +}; + +@Module({ + imports: [DataModule], + providers: [libraryServiceProvider], + exports: [LibraryService], +}) +export class LibraryModule {} diff --git a/lesson_26/api/javascript/api_app/src/library/library.service.ts b/lesson_26/api/javascript/api_app/src/library/library.service.ts new file mode 100644 index 000000000..2d2b18d8d --- /dev/null +++ b/lesson_26/api/javascript/api_app/src/library/library.service.ts @@ -0,0 +1,155 @@ +import { Injectable, Logger } from '@nestjs/common'; +import { Librarian } from './librarian'; +import { LibraryGuest } from './library_guest'; +import { MediaItem } from './media_item'; +import { CatalogSearcher } from './search/catalog_searcher'; +import { SearchCriteria } from './search/search_criteria'; + +@Injectable() +export class LibraryService { + private readonly itemsById: Map = new Map(); + private readonly checkedOutItemIds: Set = new Set(); + private readonly checkedOutItemsByGuest: Map> = + new Map(); + private readonly guestsById: Map = new Map(); + private readonly id: string; + private readonly searcher: CatalogSearcher; + private readonly logger: Logger = new Logger(LibraryService.name); + + constructor(id: string) { + this.id = id; + this.searcher = new CatalogSearcher(this.itemsById); + } + + getId(): string { + return this.id; + } + + addMediaItem(item: MediaItem, librarian: Librarian): void { + this.itemsById.set(item.getId(), item); + item.setLibrary(this); + } + + removeMediaItem(item: MediaItem, librarian: Librarian): void { + if (this.isCheckedOut(item)) { + throw new Error('Cannot remove checked out item.'); + } + this.itemsById.delete(item.getId()); + item.setLibrary(null); + } + + removeMediaItemById(id: string, librarian: Librarian): void { + const item = this.itemsById.get(id); + if (item) { + this.removeMediaItem(item, librarian); + } + } + + addLibraryGuest(guest: LibraryGuest): void { + this.guestsById.set(guest.getId(), guest); + this.checkedOutItemsByGuest.set(guest.getId(), new Set()); + guest.setLibrary(this); + } + + removeLibraryGuestById(id: string): void { + const guest = this.guestsById.get(id); + if (guest && this.checkedOutItemsByGuest.get(guest.getId())?.size === 0) { + this.guestsById.delete(guest.getId()); + this.checkedOutItemsByGuest.delete(guest.getId()); + guest.setLibrary(null); + } else { + throw new Error('Cannot remove guest with checked out items.'); + } + } + + removeLibraryGuest(guest: LibraryGuest): void { + this.removeLibraryGuestById(guest.getId()); + } + + getLibrarians(): Set { + return new Set( + Array.from(this.guestsById.values()).filter( + (g): g is Librarian => g instanceof Librarian, + ), + ); + } + + getPatrons(): Set { + return new Set(this.guestsById.values()); + } + + checkOutMediaItem(item: MediaItem, guest: LibraryGuest): boolean { + if (!this.canCheckOutMediaItem(item, guest)) { + return false; + } + this.checkedOutItemIds.add(item.getId()); + this.checkedOutItemsByGuest.get(guest.getId())?.add(item); + return true; + } + + private canCheckOutMediaItem(item: MediaItem, guest: LibraryGuest): boolean { + return ( + item.canCheckOut() && + this.hasMediaItem(item) && + !this.isCheckedOut(item) && + this.hasLibraryGuest(guest) + ); + } + + hasMediaItem(item: MediaItem): boolean { + return this.itemsById.has(item.getId()); + } + + hasMediaItemById(id: string): boolean { + return this.itemsById.has(id); + } + + isCheckedOut(item: MediaItem): boolean { + return this.checkedOutItemIds.has(item.getId()); + } + + hasLibraryGuest(guest: LibraryGuest): boolean { + return this.guestsById.has(guest.getId()); + } + + hasLibraryGuestById(id: string): boolean { + return this.guestsById.has(id); + } + + hasLibraryGuestByEmail(emailAddress: string): boolean { + return Array.from(this.guestsById.values()).some( + (g) => g.getEmail().toLowerCase() === emailAddress.toLowerCase(), + ); + } + + checkInMediaItem(item: MediaItem, guest: LibraryGuest): boolean { + if (!this.hasMediaItem(item)) { + return false; + } + this.checkedOutItemIds.delete(item.getId()); + this.checkedOutItemsByGuest.get(guest.getId())?.delete(item); + return true; + } + + getCheckedOutByGuest(guest: LibraryGuest): Set { + return this.checkedOutItemsByGuest.get(guest.getId()) || new Set(); + } + + /** + * Search the library for items matching the given query. + * + * @param query The query to search for. + * @return The items matching the query. + */ + search(query: SearchCriteria): ReadonlySet { + return new Set(this.searcher.search(query)); + } + + toString(): string { + return `Library{itemsById=${Array.from(this.itemsById.entries())}, checkedOutItemIds=${Array.from( + this.checkedOutItemIds, + )}, checkedOutItemsByGuest=${Array.from(this.checkedOutItemsByGuest.entries())}, guestsById=${Array.from( + this.guestsById.entries(), + )}}`; + } +} diff --git a/lesson_26/api/javascript/api_app/src/library/library.ts b/lesson_26/api/javascript/api_app/src/library/library.ts new file mode 100644 index 000000000..99c8aa914 --- /dev/null +++ b/lesson_26/api/javascript/api_app/src/library/library.ts @@ -0,0 +1,43 @@ +import { LibraryGuest } from './library_guest'; +import { MediaItem } from './media_item'; + +export interface Library { + /** + * Get the id of the library. + * + * @return The id of the library. + */ + getId(): string; + + /** + * Check if the library has the given guest. + * + * @param guest The guest to check for. + * @return True if the library has the guest, false otherwise. + */ + hasLibraryGuest(guest: LibraryGuest): boolean; + + /** + * Get the items checked out by a guest. + * + * @param guest The guest to get the items for. + * @return The items checked out by the guest. + */ + getCheckedOutByGuest(guest: LibraryGuest): ReadonlySet; + + /** + * Check if the given item is checked out. + * + * @param item The item to check. + * @return True if the item is checked out, false otherwise. + */ + isCheckedOut(item: MediaItem): boolean; + + /** + * Check if the library has the given item. + * + * @param item The item to check for. + * @return True if the library has the item, false otherwise. + */ + hasMediaItem(item: MediaItem): boolean; +} diff --git a/lesson_26/api/javascript/api_app/src/library/library_factory.ts b/lesson_26/api/javascript/api_app/src/library/library_factory.ts new file mode 100644 index 000000000..8a15af560 --- /dev/null +++ b/lesson_26/api/javascript/api_app/src/library/library_factory.ts @@ -0,0 +1,109 @@ +import { LibraryDataLoader } from '../data/library_data_loader'; +import { CheckoutModel, LibraryDataModel } from '../models'; +import { Librarian } from './librarian'; +import { LibraryService } from './library.service'; +import { LibraryGuest } from './library_guest'; +import { MediaItem } from './media_item'; + +export class LibraryFactory { + /** + * Create a Library object with a LibraryDataLoader object. + * + * @param loader A LibraryDataLoader object. + * @return A Library object. + * @throws IOException + */ + static async createWithLoader( + loader: LibraryDataLoader, + ): Promise { + const library = new LibraryService('main-library'); + + // Load library data. + const data: LibraryDataModel = await loader.loadData(); + + // Add guests to the library. + const guests: LibraryGuest[] = data.getGuests(); + this.addLibraryGuests(library, guests); + + // Add library items using the first librarian. + const firstLibrarian: Librarian = this.findFirstLibrarian(guests); + const mediaItems: MediaItem[] = data.getMediaItems(); + this.addLibraryItems(library, mediaItems, firstLibrarian); + + // Check out items from the library. + const checkoutsByEmail: Map = + data.getCheckoutsByEmail(); + const mediaItemById: Map = + this.getMediaItemsById(mediaItems); + const guestsByEmail: Map = + this.getGuestsByEmail(guests); + this.checkOutItems(library, checkoutsByEmail, guestsByEmail, mediaItemById); + + return library; + } + + private static getMediaItemsById( + mediaItems: MediaItem[], + ): Map { + const mediaItemById = new Map(); + for (const mediaItem of mediaItems) { + mediaItemById.set(mediaItem.getId(), mediaItem); + } + return mediaItemById; + } + + private static findFirstLibrarian(guests: LibraryGuest[]): Librarian { + let firstLibrarian: Librarian = null; + for (const guest of guests) { + if (guest instanceof Librarian) { + firstLibrarian = guest; + break; + } + } + return firstLibrarian; + } + + private static addLibraryGuests( + library: LibraryService, + guests: LibraryGuest[], + ): void { + for (const guest of guests) { + library.addLibraryGuest(guest); + } + } + + private static addLibraryItems( + library: LibraryService, + mediaItems: MediaItem[], + firstLibrarian: Librarian, + ): void { + for (const mediaItem of mediaItems) { + library.addMediaItem(mediaItem, firstLibrarian); + } + } + + private static getGuestsByEmail( + guests: LibraryGuest[], + ): Map { + const guestByEmail = new Map(); + for (const guest of guests) { + guestByEmail.set(guest.getEmail(), guest); + } + return guestByEmail; + } + + private static checkOutItems( + library: LibraryService, + checkoutsByEmail: Map, + guestByEmail: Map, + mediaItemById: Map, + ): void { + for (const [email, checkouts] of checkoutsByEmail.entries()) { + const guest = guestByEmail.get(email); + for (const checkout of checkouts) { + const mediaItem = mediaItemById.get(checkout.itemId); + library.checkOutMediaItem(mediaItem, guest); + } + } + } +} diff --git a/lesson_26/api/javascript/api_app/src/library/library_guest.ts b/lesson_26/api/javascript/api_app/src/library/library_guest.ts new file mode 100644 index 000000000..3ee5ef3e9 --- /dev/null +++ b/lesson_26/api/javascript/api_app/src/library/library_guest.ts @@ -0,0 +1,41 @@ +import { Library } from './library'; +import { MediaItem } from './media_item'; + +export interface LibraryGuest { + /** + * Set the library that the guest is in. + * + * @param library The library that the guest is in. + * @throws WrongLibraryException If the guest is not in the library. + */ + setLibrary(library: Library): void; + + /** + * Get the name of the guest. + * + * @return The name of the guest. + */ + getName(): string; + + /** + * Get the email of the guest. + * + * @return The email of the guest. + */ + getEmail(): string; + + /** + * Get the id of the guest. + * + * @return The id of the guest. + */ + getId(): string; + + /** + * Gets the items currently checked out to the guest. + * + * @return The items currently checked out to the guest. + * @throws LibraryNotSetException If the library is not set for the guest. + */ + getCheckedOutMediaItems(): ReadonlySet; +} diff --git a/lesson_26/api/javascript/api_app/src/library/library_guest_base.ts b/lesson_26/api/javascript/api_app/src/library/library_guest_base.ts new file mode 100644 index 000000000..f6018a217 --- /dev/null +++ b/lesson_26/api/javascript/api_app/src/library/library_guest_base.ts @@ -0,0 +1,48 @@ +import { randomUUID } from 'crypto'; +import { Library } from './library'; +import { LibraryGuest } from './library_guest'; +import { MediaItem } from './media_item'; + +export class LibraryGuestBase implements LibraryGuest { + private library: Library | null = null; + private readonly id: string = randomUUID(); + private readonly name: string; + private readonly email: string; + + constructor(name: string, email: string) { + this.name = name; + this.email = email; + } + + public setLibrary(library: Library): void { + if (library && !library.hasLibraryGuest(this)) { + throw new Error( + `Patron ${this.getEmail()} is not in library ${library.getId()}`, + ); + } + this.library = library; + } + + public getName(): string { + return this.name; + } + + public getEmail(): string { + return this.email; + } + + public getId(): string { + return this.id; + } + + public getCheckedOutMediaItems(): ReadonlySet { + if (!this.library) { + throw new Error(`Library not set for patron ${this.getEmail()}`); + } + return this.library.getCheckedOutByGuest(this); + } + + public toString(): string { + return `LibraryGuestBase{id='${this.getEmail()}', name='${this.getName()}'}`; + } +} diff --git a/lesson_26/api/javascript/api_app/src/library/magazine.ts b/lesson_26/api/javascript/api_app/src/library/magazine.ts new file mode 100644 index 000000000..6178cf9ef --- /dev/null +++ b/lesson_26/api/javascript/api_app/src/library/magazine.ts @@ -0,0 +1,20 @@ +import { MediaItemBase } from './media_item_base'; +import { MediaType } from './media_type'; + +export class Magazine extends MediaItemBase { + constructor(id: string, title: string) { + super(id, title); + } + + getType(): MediaType { + return MediaType.MAGAZINE; + } + + canCheckOut(): boolean { + return false; + } + + toString(): string { + return `Magazine{id='${this.getId()}', title='${this.getTitle()}'}`; + } +} diff --git a/lesson_26/api/javascript/api_app/src/library/media_item.ts b/lesson_26/api/javascript/api_app/src/library/media_item.ts new file mode 100644 index 000000000..358be421c --- /dev/null +++ b/lesson_26/api/javascript/api_app/src/library/media_item.ts @@ -0,0 +1,50 @@ +import { Library } from './library'; +import { MediaType } from './media_type'; +import { Searchable } from './search/searchable'; + +/** Represents a media item. */ +export interface MediaItem extends Searchable { + /** + * Get the type of the media item. + * + * @return The type of the media item. + */ + getType(): MediaType; + + /** + * Get the id of the media item. + * + * @return The id of the media item. + */ + getId(): string; + + /** + * Set the library that the media item is in. + * + * @param library + * @throws WrongLibraryException + */ + setLibrary(library: Library): void; + + /** + * Get the title of the media item. + * + * @return The title of the media item. + */ + getTitle(): string; + + /** + * Check if the media item is checked out. + * + * @return True if the media item is checked out, false otherwise. + * @throws LibraryNotSetException + */ + isCheckedOut(): boolean; + + /** + * Check if the media item can be checked out. + * + * @return True if the media item can be checked out, false otherwise. + */ + canCheckOut(): boolean; +} diff --git a/lesson_26/api/javascript/api_app/src/library/media_item_base.ts b/lesson_26/api/javascript/api_app/src/library/media_item_base.ts new file mode 100644 index 000000000..be7e22f9d --- /dev/null +++ b/lesson_26/api/javascript/api_app/src/library/media_item_base.ts @@ -0,0 +1,69 @@ +import { Library } from './library'; +import { MediaItem } from './media_item'; +import { MediaType } from './media_type'; +import { SearchCriteria } from './search/search_criteria'; + +export abstract class MediaItemBase implements MediaItem { + private library: Library | null = null; + private readonly id: string; + private readonly title: string; + + constructor(id: string, title: string) { + this.id = id; + this.title = title; + } + + getId(): string { + return this.id; + } + + getTitle(): string { + return this.title; + } + + setLibrary(library: Library): void { + if (library && !library.hasMediaItem(this)) { + throw new Error( + `Media item ${this.getId()} is not in library ${library.getId()}`, + ); + } + this.library = library; + } + + isCheckedOut(): boolean { + if (!this.library) { + throw new Error(`Library not set for item ${this.getId()}`); + } + return this.library.isCheckedOut(this); + } + + canCheckOut(): boolean { + return true; + } + + protected matchesAuthor(author: string): boolean { + return false; + } + + matches(query: SearchCriteria): boolean { + if (query.id && this.getId() !== query.id) { + return false; + } + if ( + query.title && + !this.getTitle().toLowerCase().includes(query.title.toLowerCase()) + ) { + return false; + } + if (query.type && !this.getType().includes(query.type.toLowerCase())) { + return false; + } + return !query.author || this.matchesAuthor(query.author); + } + + toString(): string { + return `MediaItem{id='${this.getId()}', title='${this.getTitle()}'}`; + } + + abstract getType(): MediaType; +} diff --git a/lesson_26/api/javascript/api_app/src/library/media_type.ts b/lesson_26/api/javascript/api_app/src/library/media_type.ts new file mode 100644 index 000000000..89441526d --- /dev/null +++ b/lesson_26/api/javascript/api_app/src/library/media_type.ts @@ -0,0 +1,7 @@ +export enum MediaType { + UNKNOWN = 'unknown', + BOOK = 'book', + DVD = 'dvd', + MAGAZINE = 'magazine', + NEWSPAPER = 'newspaper', +} diff --git a/lesson_26/api/javascript/api_app/src/library/newspaper.ts b/lesson_26/api/javascript/api_app/src/library/newspaper.ts new file mode 100644 index 000000000..7655c234e --- /dev/null +++ b/lesson_26/api/javascript/api_app/src/library/newspaper.ts @@ -0,0 +1,20 @@ +import { MediaItemBase } from './media_item_base'; +import { MediaType } from './media_type'; + +export class Newspaper extends MediaItemBase { + constructor(id: string, title: string) { + super(id, title); + } + + getType(): MediaType { + return MediaType.NEWSPAPER; + } + + canCheckOut(): boolean { + return false; + } + + toString(): string { + return `Newspaper{id='${this.getId()}', title='${this.getTitle()}'}`; + } +} diff --git a/lesson_26/api/javascript/api_app/src/library/patron.ts b/lesson_26/api/javascript/api_app/src/library/patron.ts new file mode 100644 index 000000000..f23374b83 --- /dev/null +++ b/lesson_26/api/javascript/api_app/src/library/patron.ts @@ -0,0 +1,12 @@ +import { LibraryGuestBase } from './library_guest_base'; + +/** Represents a patron of a library. */ +export class Patron extends LibraryGuestBase { + constructor(name: string, email: string) { + super(name, email); + } + + toString(): string { + return `Patron{id='${this.getEmail()}', name='${this.getName()}'}`; + } +} diff --git a/lesson_26/api/javascript/api_app/src/library/search/catalog_searcher.ts b/lesson_26/api/javascript/api_app/src/library/search/catalog_searcher.ts new file mode 100644 index 000000000..f562c6ae3 --- /dev/null +++ b/lesson_26/api/javascript/api_app/src/library/search/catalog_searcher.ts @@ -0,0 +1,14 @@ +import { SearchCriteria } from './search_criteria'; +import { Searchable } from './searchable'; + +export class CatalogSearcher { + private catalog: ReadonlyMap; + + constructor(catalog: ReadonlyMap) { + this.catalog = catalog; + } + + search(query: SearchCriteria): T[] { + return [...this.catalog.values()].filter((item) => item.matches(query)); + } +} diff --git a/lesson_26/api/javascript/api_app/src/library/search/index.ts b/lesson_26/api/javascript/api_app/src/library/search/index.ts new file mode 100644 index 000000000..a95cebee1 --- /dev/null +++ b/lesson_26/api/javascript/api_app/src/library/search/index.ts @@ -0,0 +1,2 @@ +export { SearchCriteria } from './search_criteria'; +export { Searchable } from './searchable'; diff --git a/lesson_26/api/javascript/api_app/src/library/search/search_criteria.ts b/lesson_26/api/javascript/api_app/src/library/search/search_criteria.ts new file mode 100644 index 000000000..aafbae933 --- /dev/null +++ b/lesson_26/api/javascript/api_app/src/library/search/search_criteria.ts @@ -0,0 +1,13 @@ +export interface SearchCriteria { + /** The ID to search for (exact match). */ + id?: string; + + /** The title to search for. */ + title?: string; + + /** The author to search for. */ + author?: string; + + /** The type to search for (exact match). */ + type?: string; +} diff --git a/lesson_26/api/javascript/api_app/src/library/search/searchable.ts b/lesson_26/api/javascript/api_app/src/library/search/searchable.ts new file mode 100644 index 000000000..14943d293 --- /dev/null +++ b/lesson_26/api/javascript/api_app/src/library/search/searchable.ts @@ -0,0 +1,11 @@ +import { SearchCriteria } from './search_criteria'; + +export interface Searchable { + /** + * Indicates whether an item matches the search criteria. + * + * @param query The query to search for. + * @return The items that match the query. + */ + matches(query: SearchCriteria): boolean; +} diff --git a/lesson_26/api/javascript/api_app/src/main.ts b/lesson_26/api/javascript/api_app/src/main.ts new file mode 100644 index 000000000..0b439c264 --- /dev/null +++ b/lesson_26/api/javascript/api_app/src/main.ts @@ -0,0 +1,23 @@ +import { NestFactory } from '@nestjs/core'; +import { NestExpressApplication } from '@nestjs/platform-express'; +import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'; +import { AppModule } from './app.module'; + +async function bootstrap() { + const app = await NestFactory.create(AppModule); + app.enableCors(); + app.set('trust proxy', 'loopback'); // Trust requests from the loopback address + + const config = new DocumentBuilder() + .setTitle('Library API') + .setDescription('An API for managing a library of media items') + .setVersion('1.0') + .addTag('library') + .build(); + const documentFactory = () => SwaggerModule.createDocument(app, config); + SwaggerModule.setup('api', app, documentFactory); + + await app.listen(3000); +} + +bootstrap(); diff --git a/lesson_26/api/javascript/api_app/src/models/index.ts b/lesson_26/api/javascript/api_app/src/models/index.ts new file mode 100644 index 000000000..890d5539f --- /dev/null +++ b/lesson_26/api/javascript/api_app/src/models/index.ts @@ -0,0 +1,5 @@ +export { + CheckoutModel, + LibraryDataModel, + MediaItemModel, +} from './library_data_model'; diff --git a/lesson_26/api/javascript/api_app/src/models/library_data_model.ts b/lesson_26/api/javascript/api_app/src/models/library_data_model.ts new file mode 100644 index 000000000..e63f21acb --- /dev/null +++ b/lesson_26/api/javascript/api_app/src/models/library_data_model.ts @@ -0,0 +1,86 @@ +import { + Book, + Dvd, + Librarian, + LibraryGuest, + Magazine, + MediaItem, + MediaType, + Newspaper, + Patron, +} from '../library'; + +export interface MediaItemModel { + id: string; + title: string; + type: string; + isbn?: string; + authors?: string[]; + pages?: number; +} + +export interface LibraryGuestModel { + name: string; + email: string; + type: string; + checkedOutItems: CheckoutModel[]; +} + +export interface CheckoutModel { + itemId: string; + dueDate?: string; +} + +export class LibraryDataModel { + public mediaItems: MediaItemModel[]; + public guests: LibraryGuestModel[]; + + constructor(mediaItems: MediaItemModel[], guests: LibraryGuestModel[]) { + this.mediaItems = mediaItems; + this.guests = guests; + } + + public getMediaItems(): MediaItem[] { + return this.mediaItems.map((mediaItemModel) => { + switch (mediaItemModel.type) { + case MediaType.BOOK: + return new Book( + mediaItemModel.id, + mediaItemModel.title, + mediaItemModel.isbn!, + mediaItemModel.authors!, + mediaItemModel.pages!, + ); + case MediaType.DVD: + return new Dvd(mediaItemModel.id, mediaItemModel.title); + case MediaType.MAGAZINE: + return new Magazine(mediaItemModel.id, mediaItemModel.title); + case MediaType.NEWSPAPER: + return new Newspaper(mediaItemModel.id, mediaItemModel.title); + default: + throw new Error(`Unknown media item type: ${mediaItemModel.type}`); + } + }); + } + + public getGuests(): LibraryGuest[] { + return this.guests.map((guestModel) => { + switch (guestModel.type) { + case 'librarian': + return new Librarian(guestModel.name, guestModel.email); + case 'patron': + return new Patron(guestModel.name, guestModel.email); + default: + throw new Error(`Unknown guest type: ${guestModel.type}`); + } + }); + } + + public getCheckoutsByEmail(): Map { + const results = new Map(); + this.guests.forEach((guest) => { + results.set(guest.email, guest.checkedOutItems); + }); + return results; + } +} diff --git a/lesson_26/api/javascript/api_app/src/web/create_media_item_request.ts b/lesson_26/api/javascript/api_app/src/web/create_media_item_request.ts new file mode 100644 index 000000000..75d41cbbd --- /dev/null +++ b/lesson_26/api/javascript/api_app/src/web/create_media_item_request.ts @@ -0,0 +1,5 @@ +import { MediaItemRequest } from './media_item_request'; + +export interface CreateMediaItemRequest { + item: MediaItemRequest; +} diff --git a/lesson_26/api/javascript/api_app/src/web/create_media_item_response.ts b/lesson_26/api/javascript/api_app/src/web/create_media_item_response.ts new file mode 100644 index 000000000..06cc60ca5 --- /dev/null +++ b/lesson_26/api/javascript/api_app/src/web/create_media_item_response.ts @@ -0,0 +1,6 @@ +import { MediaItemResponse } from './media_item_response'; + +export interface CreateMediaItemResponse { + item?: MediaItemResponse; + errors?: string[]; +} diff --git a/lesson_26/api/javascript/api_app/src/web/get_media_items_response.ts b/lesson_26/api/javascript/api_app/src/web/get_media_items_response.ts new file mode 100644 index 000000000..e7cdbc98d --- /dev/null +++ b/lesson_26/api/javascript/api_app/src/web/get_media_items_response.ts @@ -0,0 +1,5 @@ +import { MediaItemResponse } from './media_item_response'; + +export interface GetMediaItemsResponse { + items: MediaItemResponse[]; +} diff --git a/lesson_26/api/javascript/api_app/src/web/media_item_request.ts b/lesson_26/api/javascript/api_app/src/web/media_item_request.ts new file mode 100644 index 000000000..03fe75a80 --- /dev/null +++ b/lesson_26/api/javascript/api_app/src/web/media_item_request.ts @@ -0,0 +1,42 @@ +import { randomUUID } from 'crypto'; +import { + Book, + Dvd, + Magazine, + MediaItem, + MediaType, + Newspaper, +} from '../library'; + +export interface MediaItemRequest { + id?: string; + type: string; + isbn?: string; + title: string; + authors?: string[]; + edition?: string; + pages?: number; + runtime?: number; +} + +export function fromMediaItemRequest(request: MediaItemRequest): MediaItem { + const id = request.id ? request.id : randomUUID(); + switch (request.type.toLowerCase()) { + case MediaType.BOOK: + return new Book( + id, + request.title, + request.isbn, + request.authors, + request.pages, + ); + case MediaType.DVD: + return new Dvd(id, request.title); + case MediaType.MAGAZINE: + return new Magazine(id, request.title); + case MediaType.NEWSPAPER: + return new Newspaper(id, request.title); + default: + throw new Error(`Unknown media item type: ${request.type}`); + } +} diff --git a/lesson_26/api/javascript/api_app/src/web/media_item_response.ts b/lesson_26/api/javascript/api_app/src/web/media_item_response.ts new file mode 100644 index 000000000..31bedc6df --- /dev/null +++ b/lesson_26/api/javascript/api_app/src/web/media_item_response.ts @@ -0,0 +1,31 @@ +import { Book, MediaItem, MediaType } from '../library'; + +interface MediaItemResponse { + type: MediaType; + id: string; + isbn?: string; + title: string; + authors?: string[]; + edition?: string; + pages?: number; + runtime?: number; +} + +function toMediaItemResponse(item: MediaItem): MediaItemResponse { + const result: MediaItemResponse = { + id: item.getId(), + title: item.getTitle(), + type: item.getType(), + }; + + if (item.getType() === MediaType.BOOK) { + const book = item as Book; + result.isbn = book.getIsbn(); + result.authors = book.getAuthors(); + result.pages = book.getNumberOfPages(); + } + + return result; +} + +export { MediaItemResponse, toMediaItemResponse }; diff --git a/lesson_26/api/javascript/api_app/src/web/media_items.controller.ts b/lesson_26/api/javascript/api_app/src/web/media_items.controller.ts new file mode 100644 index 000000000..dd940f7fa --- /dev/null +++ b/lesson_26/api/javascript/api_app/src/web/media_items.controller.ts @@ -0,0 +1,77 @@ +import { + Body, + Controller, + Delete, + Get, + HttpCode, + HttpStatus, + Param, + Post, + Res, +} from '@nestjs/common'; +import { Response } from 'express'; +import { Librarian, LibraryService, MediaItem } from '../library'; +import { CreateMediaItemRequest } from './create_media_item_request'; +import { CreateMediaItemResponse } from './create_media_item_response'; +import { GetMediaItemsResponse } from './get_media_items_response'; +import { fromMediaItemRequest } from './media_item_request'; +import { MediaItemResponse, toMediaItemResponse } from './media_item_response'; + +@Controller() +export class MediaItemsController { + private readonly librarian: Librarian; + + constructor(private readonly library: LibraryService) { + this.librarian = library.getLibrarians()[0]; + } + + @Get('items') + getItems(): GetMediaItemsResponse { + const items: ReadonlySet = this.library.search({}); + const responseItems: MediaItemResponse[] = [...items].map( + toMediaItemResponse, + ); + const response = { items: responseItems }; + return response; + } + + @Get('items/:id') + getItem( + @Param('id') id: string, + @Res({ passthrough: true }) res: Response, + ): MediaItemResponse { + const items = this.library.search({ id }); + if (items.size === 0) { + res.status(HttpStatus.NOT_FOUND); + } + const item = items.values().next().value; + return item ? toMediaItemResponse(item) : undefined; + } + + @Post('items') + @HttpCode(HttpStatus.OK) + addItem( + @Body() body: CreateMediaItemRequest, + @Res({ passthrough: true }) res: Response, + ): CreateMediaItemResponse { + if (!body.item) { + res.status(HttpStatus.BAD_REQUEST); + return { errors: ['Missing item'] }; + } + const item = fromMediaItemRequest(body.item); + this.library.addMediaItem(item, this.librarian); + return { item: toMediaItemResponse(item) }; + } + + @Delete('items/:id') + @HttpCode(HttpStatus.NO_CONTENT) + deleteItem( + @Param('id') id: string, + @Res({ passthrough: true }) res: Response, + ): void { + if (!this.library.hasMediaItemById(id)) { + res.status(HttpStatus.NOT_FOUND); + } + this.library.removeMediaItemById(id, this.librarian); + } +} diff --git a/lesson_26/api/javascript/api_app/src/web/web.module.ts b/lesson_26/api/javascript/api_app/src/web/web.module.ts new file mode 100644 index 000000000..b1cea0f3b --- /dev/null +++ b/lesson_26/api/javascript/api_app/src/web/web.module.ts @@ -0,0 +1,9 @@ +import { Module } from '@nestjs/common'; +import { LibraryModule } from '../library'; +import { MediaItemsController } from './media_items.controller'; + +@Module({ + imports: [LibraryModule], + controllers: [MediaItemsController], +}) +export class WebModule {} diff --git a/lesson_26/api/javascript/api_app/test/app.e2e-spec.ts b/lesson_26/api/javascript/api_app/test/app.e2e-spec.ts new file mode 100644 index 000000000..c8d2b3642 --- /dev/null +++ b/lesson_26/api/javascript/api_app/test/app.e2e-spec.ts @@ -0,0 +1,24 @@ +import { INestApplication } from '@nestjs/common'; +import { Test, TestingModule } from '@nestjs/testing'; +import * as request from 'supertest'; +import { AppModule } from '../src/app.module'; + +describe('AppController (e2e)', () => { + let app: INestApplication; + + beforeEach(async () => { + const moduleFixture: TestingModule = await Test.createTestingModule({ + imports: [AppModule], + }).compile(); + + app = moduleFixture.createNestApplication(); + await app.init(); + }); + + it('/ (GET)', () => { + return request(app.getHttpServer()) + .get('/') + .expect(200) + .expect('Hello World!'); + }); +}); diff --git a/lesson_26/api/javascript/api_app/test/jest-e2e.json b/lesson_26/api/javascript/api_app/test/jest-e2e.json new file mode 100644 index 000000000..e9d912f3e --- /dev/null +++ b/lesson_26/api/javascript/api_app/test/jest-e2e.json @@ -0,0 +1,9 @@ +{ + "moduleFileExtensions": ["js", "json", "ts"], + "rootDir": ".", + "testEnvironment": "node", + "testRegex": ".e2e-spec.ts$", + "transform": { + "^.+\\.(t|j)s$": "ts-jest" + } +} diff --git a/lesson_26/api/javascript/api_app/test/web/media_items.e2e-spec.ts b/lesson_26/api/javascript/api_app/test/web/media_items.e2e-spec.ts new file mode 100644 index 000000000..f98cc818e --- /dev/null +++ b/lesson_26/api/javascript/api_app/test/web/media_items.e2e-spec.ts @@ -0,0 +1,100 @@ +import { INestApplication } from '@nestjs/common'; +import { Test, TestingModule } from '@nestjs/testing'; +import * as request from 'supertest'; +import { Book, LibraryService } from '../../src/library'; +import { WebModule } from '../../src/web/web.module'; + +describe('MediaItemsController (e2e)', () => { + let app: INestApplication; + let library: LibraryService; + + beforeEach(async () => { + const moduleFixture: TestingModule = await Test.createTestingModule({ + imports: [WebModule], + }).compile(); + + app = moduleFixture.createNestApplication(); + library = app.get(LibraryService); + await app.init(); + }); + + it('/items (GET)', () => { + return request(app.getHttpServer()) + .get('/items') + .expect(200) + .then((res) => { + expect(res.body.items).toHaveLength(31); + }); + }); + + it('/items/:id (GET) - gets an item', () => { + return request(app.getHttpServer()) + .get('/items/8efcbbb2-5c1e-486c-924d-63c3503f498c') + .expect(200); + }); + + it('/items/:id (GET) - returns not found on get item', () => { + return request(app.getHttpServer()) + .get('/items/00000000-0000-0000-0000-000000000000') + .expect(404); + }); + + it('/items (POST) - reports bad request on add item', () => { + const json = {}; + + return request(app.getHttpServer()) + .post('/items') + .send(json) + .expect(400) + .then((res) => { + expect(res.body.errors).toBeInstanceOf(Array); + expect(res.body.errors.length).toBe(1); + }); + }); + + it('/items (POST) - adds an item', async () => { + const json = { + item: { + id: 'e27a4e0d-9664-420d-955e-c0e295d0ce02', + type: 'BOOK', + title: 'Becoming', + isbn: '9781524763138', + authors: ['Michelle Obama'], + pages: 448, + }, + }; + + await request(app.getHttpServer()) + .post('/items') + .send(json) + .expect(200) + .then((res) => { + expect(res.body.item.id).toBe('e27a4e0d-9664-420d-955e-c0e295d0ce02'); + }); + + const items = await library.search({ + id: 'e27a4e0d-9664-420d-955e-c0e295d0ce02', + }); + expect(items.size).toBe(1); + const item = items.values().next().value; + expect(item).toBeInstanceOf(Book); + expect(item.title).toBe('Becoming'); + }); + + it('/items/:id (DELETE) - returns not found on delete item', () => { + return request(app.getHttpServer()) + .delete('/items/00000000-0000-0000-0000-000000000000') + .expect(404); + }); + + it('/items/:id (DELETE) - deletes an item', async () => { + await request(app.getHttpServer()) + .delete('/items/8efcbbb2-5c1e-486c-924d-63c3503f498c') + .expect(204); + + const items = library.search({ + id: '8efcbbb2-5c1e-486c-924d-63c3503f498c', + }); + expect(items.size).toBe(0); + }); +}); diff --git a/lesson_26/api/javascript/api_app/tsconfig.build.json b/lesson_26/api/javascript/api_app/tsconfig.build.json new file mode 100644 index 000000000..64f86c6bd --- /dev/null +++ b/lesson_26/api/javascript/api_app/tsconfig.build.json @@ -0,0 +1,4 @@ +{ + "extends": "./tsconfig.json", + "exclude": ["node_modules", "test", "dist", "**/*spec.ts"] +} diff --git a/lesson_26/api/javascript/api_app/tsconfig.json b/lesson_26/api/javascript/api_app/tsconfig.json new file mode 100644 index 000000000..2b0c0e1f9 --- /dev/null +++ b/lesson_26/api/javascript/api_app/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "module": "commonjs", + "declaration": true, + "removeComments": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "allowSyntheticDefaultImports": true, + "target": "ES2021", + "sourceMap": true, + "outDir": "./dist", + "baseUrl": "./", + "incremental": true, + "skipLibCheck": true, + "strictNullChecks": false, + "noImplicitAny": false, + "strictBindCallApply": false, + "forceConsistentCasingInFileNames": false, + "noFallthroughCasesInSwitch": false, + "resolveJsonModule": true + } +} diff --git a/lesson_26/debug.png b/lesson_26/debug.png new file mode 100644 index 0000000000000000000000000000000000000000..2b883f61373fee52c7dd2efb5adeb43eb5e9aa91 GIT binary patch literal 147441 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%0D(2YjC3o^G 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%0Ai8MC< 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 b$;kRvD~AXvjYwJ67T||HX^x?taEbXh>UwCm literal 0 HcmV?d00001 diff --git a/lesson_27/README.md b/lesson_27/README.md new file mode 100644 index 000000000..3651f7ce6 --- /dev/null +++ b/lesson_27/README.md @@ -0,0 +1,16 @@ +# Lesson 27: Integrating with Backend APIs ([Slides](https://code-differently.github.io/code-differently-25-q1/slides/#/lesson_27)) + +## Pre-work + +Please review the following resources before lecture: + +### Required +* [Learn Fetch API In 6 Minutes (Video)](https://www.youtube.com/watch?v=cuEtnrL9-H0) +* [Using Promises - MDN (Article)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises) + +### Recommended +* [How To Make API Call In React... (Video)](https://www.youtube.com/watch?v=ZRFwuGpiLl4) + +## Homework + +- TODO(anthonydmays): Provide some details here \ No newline at end of file From 538982bf025c6d07910f2640551432283d9ee98f Mon Sep 17 00:00:00 2001 From: "Anthony D. Mays" Date: Fri, 2 May 2025 06:04:57 +0000 Subject: [PATCH 2/4] tests: adds unit tests for media items controller Signed-off-by: Anthony D. Mays --- .../{ => __tests__}/app.controller.spec.ts | 4 +- .../__tests__/media_items.controller.spec.ts | 258 ++++++++++++++++++ 2 files changed, 260 insertions(+), 2 deletions(-) rename lesson_26/api/javascript/api_app/src/{ => __tests__}/app.controller.spec.ts (84%) create mode 100644 lesson_26/api/javascript/api_app/src/web/__tests__/media_items.controller.spec.ts diff --git a/lesson_26/api/javascript/api_app/src/app.controller.spec.ts b/lesson_26/api/javascript/api_app/src/__tests__/app.controller.spec.ts similarity index 84% rename from lesson_26/api/javascript/api_app/src/app.controller.spec.ts rename to lesson_26/api/javascript/api_app/src/__tests__/app.controller.spec.ts index d22f3890a..ef381a2e8 100644 --- a/lesson_26/api/javascript/api_app/src/app.controller.spec.ts +++ b/lesson_26/api/javascript/api_app/src/__tests__/app.controller.spec.ts @@ -1,6 +1,6 @@ import { Test, TestingModule } from '@nestjs/testing'; -import { AppController } from './app.controller'; -import { AppService } from './app.service'; +import { AppController } from '../app.controller'; +import { AppService } from '../app.service'; describe('AppController', () => { let appController: AppController; diff --git a/lesson_26/api/javascript/api_app/src/web/__tests__/media_items.controller.spec.ts b/lesson_26/api/javascript/api_app/src/web/__tests__/media_items.controller.spec.ts new file mode 100644 index 000000000..b59f9387e --- /dev/null +++ b/lesson_26/api/javascript/api_app/src/web/__tests__/media_items.controller.spec.ts @@ -0,0 +1,258 @@ +import { HttpStatus } from '@nestjs/common'; +import { Test, TestingModule } from '@nestjs/testing'; +import { Librarian, LibraryService, MediaItem } from '../../library'; +import { CreateMediaItemRequest } from '../create_media_item_request'; +import { fromMediaItemRequest } from '../media_item_request'; +import { toMediaItemResponse } from '../media_item_response'; +import { MediaItemsController } from '../media_items.controller'; + +// Mock dependencies and utils +jest.mock('../media_item_request', () => ({ + fromMediaItemRequest: jest.fn(), +})); + +jest.mock('../media_item_response', () => ({ + toMediaItemResponse: jest.fn(), +})); + +describe('MediaItemsController', () => { + let controller: MediaItemsController; + let libraryService: LibraryService; + let mockLibrarian: Librarian; + let mockMediaItem1: MediaItem; + let mockMediaItem2: MediaItem; + + beforeEach(async () => { + // Create mock objects + mockLibrarian = new Librarian('Test Librarian', 'test@example.com'); + + mockMediaItem1 = { + getId: jest.fn().mockReturnValue('123'), + getTitle: jest.fn().mockReturnValue('Test Item 1'), + getType: jest.fn().mockReturnValue('movie'), + getReleaseYear: jest.fn().mockReturnValue(2020), + getCredits: jest.fn().mockReturnValue([]), + addCredit: jest.fn(), + } as unknown as MediaItem; + + mockMediaItem2 = { + getId: jest.fn().mockReturnValue('456'), + getTitle: jest.fn().mockReturnValue('Test Item 2'), + getType: jest.fn().mockReturnValue('book'), + getReleaseYear: jest.fn().mockReturnValue(2021), + getCredits: jest.fn().mockReturnValue([]), + addCredit: jest.fn(), + } as unknown as MediaItem; + + // Mock the library service + const mockLibraryService = { + getLibrarians: jest.fn().mockReturnValue([mockLibrarian]), + search: jest.fn(), + hasMediaItemById: jest.fn(), + addMediaItem: jest.fn(), + removeMediaItemById: jest.fn(), + }; + + // Create mock response transformer + const mockMediaItemResponse1 = { + id: '123', + title: 'Test Item 1', + type: 'movie', + releaseYear: 2020, + }; + + const mockMediaItemResponse2 = { + id: '456', + title: 'Test Item 2', + type: 'book', + releaseYear: 2021, + }; + + (toMediaItemResponse as jest.Mock).mockImplementation((item: MediaItem) => { + if (item.getId() === '123') return mockMediaItemResponse1; + if (item.getId() === '456') return mockMediaItemResponse2; + return null; + }); + + (fromMediaItemRequest as jest.Mock).mockImplementation((requestItem) => { + if (requestItem.id === '123') return mockMediaItem1; + if (requestItem.id === '456') return mockMediaItem2; + return mockMediaItem1; // Default to first mock item + }); + + const module: TestingModule = await Test.createTestingModule({ + controllers: [MediaItemsController], + providers: [ + { + provide: LibraryService, + useValue: mockLibraryService, + }, + ], + }).compile(); + + controller = module.get(MediaItemsController); + libraryService = module.get(LibraryService); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + describe('getItems', () => { + it('should return all media items', () => { + // Arrange + const itemsSet = new Set([mockMediaItem1, mockMediaItem2]); + (libraryService.search as jest.Mock).mockReturnValue(itemsSet); + + // Act + const result = controller.getItems(); + + // Assert + expect(libraryService.search).toHaveBeenCalledWith({}); + expect(toMediaItemResponse).toHaveBeenCalledTimes(2); + expect(result.items).toHaveLength(2); + expect(result).toEqual({ + items: [ + { id: '123', title: 'Test Item 1', type: 'movie', releaseYear: 2020 }, + { id: '456', title: 'Test Item 2', type: 'book', releaseYear: 2021 }, + ], + }); + }); + + it('should return empty array when no items', () => { + // Arrange + const emptySet = new Set([]); + (libraryService.search as jest.Mock).mockReturnValue(emptySet); + + // Act + const result = controller.getItems(); + + // Assert + expect(libraryService.search).toHaveBeenCalledWith({}); + expect(toMediaItemResponse).not.toHaveBeenCalled(); + expect(result.items).toHaveLength(0); + expect(result).toEqual({ items: [] }); + }); + }); + + describe('getItem', () => { + it('should return a specific media item when found', () => { + // Arrange + const itemsSet = new Set([mockMediaItem1]); + (libraryService.search as jest.Mock).mockReturnValue(itemsSet); + const mockResponse = { status: jest.fn() }; + + // Act + const result = controller.getItem('123', mockResponse as any); + + // Assert + expect(libraryService.search).toHaveBeenCalledWith({ id: '123' }); + expect(toMediaItemResponse).toHaveBeenCalledWith(mockMediaItem1); + expect(mockResponse.status).not.toHaveBeenCalled(); + expect(result).toEqual({ + id: '123', + title: 'Test Item 1', + type: 'movie', + releaseYear: 2020, + }); + }); + + it('should return 404 when item not found', () => { + // Arrange + const emptySet = new Set([]); + (libraryService.search as jest.Mock).mockReturnValue(emptySet); + const mockResponse = { status: jest.fn() }; + + // Act + const result = controller.getItem('999', mockResponse as any); + + // Assert + expect(libraryService.search).toHaveBeenCalledWith({ id: '999' }); + expect(mockResponse.status).toHaveBeenCalledWith(HttpStatus.NOT_FOUND); + expect(result).toBeUndefined(); + }); + }); + + describe('addItem', () => { + it('should successfully add a media item', () => { + // Arrange + const mockRequest: CreateMediaItemRequest = { + item: { + id: '123', + title: 'Test Item 1', + type: 'movie', + }, + }; + const mockResponse = { status: jest.fn() }; + + // Act + const result = controller.addItem(mockRequest, mockResponse as any); + + // Assert + expect(fromMediaItemRequest).toHaveBeenCalledWith(mockRequest.item); + expect(libraryService.addMediaItem).toHaveBeenCalledWith( + mockMediaItem1, + mockLibrarian, + ); + expect(toMediaItemResponse).toHaveBeenCalledWith(mockMediaItem1); + expect(result).toEqual({ + item: { + id: '123', + title: 'Test Item 1', + type: 'movie', + releaseYear: 2020, + }, + }); + }); + + it('should return errors when item is missing', () => { + // Arrange + const mockRequest = {} as CreateMediaItemRequest; + const mockResponse = { status: jest.fn() }; + + // Act + const result = controller.addItem(mockRequest, mockResponse as any); + + // Assert + expect(mockResponse.status).toHaveBeenCalledWith(HttpStatus.BAD_REQUEST); + expect(libraryService.addMediaItem).not.toHaveBeenCalled(); + expect(result).toEqual({ errors: ['Missing item'] }); + }); + }); + + describe('deleteItem', () => { + it('should successfully delete an existing media item', () => { + // Arrange + (libraryService.hasMediaItemById as jest.Mock).mockReturnValue(true); + const mockResponse = { status: jest.fn() }; + + // Act + controller.deleteItem('123', mockResponse as any); + + // Assert + expect(libraryService.hasMediaItemById).toHaveBeenCalledWith('123'); + expect(libraryService.removeMediaItemById).toHaveBeenCalledWith( + '123', + mockLibrarian, + ); + expect(mockResponse.status).not.toHaveBeenCalled(); + }); + + it('should return 404 when trying to delete non-existent item', () => { + // Arrange + (libraryService.hasMediaItemById as jest.Mock).mockReturnValue(false); + const mockResponse = { status: jest.fn() }; + + // Act + controller.deleteItem('999', mockResponse as any); + + // Assert + expect(libraryService.hasMediaItemById).toHaveBeenCalledWith('999'); + expect(mockResponse.status).toHaveBeenCalledWith(HttpStatus.NOT_FOUND); + expect(libraryService.removeMediaItemById).toHaveBeenCalledWith( + '999', + mockLibrarian, + ); + }); + }); +}); From 392c4f7f4336ed17677e156965dc669da22cdb12 Mon Sep 17 00:00:00 2001 From: "Anthony D. Mays" Date: Fri, 2 May 2025 06:11:15 +0000 Subject: [PATCH 3/4] chore: updating slides Signed-off-by: Anthony D. Mays --- slides/src/Slides/Lessons/Lesson26.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/slides/src/Slides/Lessons/Lesson26.js b/slides/src/Slides/Lessons/Lesson26.js index c03012b85..d01cfb7ba 100644 --- a/slides/src/Slides/Lessons/Lesson26.js +++ b/slides/src/Slides/Lessons/Lesson26.js @@ -155,10 +155,10 @@ ${` `}
-

We can use languages that we’ve learned so far (Java or JavaScript) in order to implement our API

+

We can use languages that we’ve learned so far (Java or TypeScript) in order to implement our API

-

For this lesson, we’ll use Java

+

For this lesson, we’ll use TypeScript

<${DemoSlide} /> <${QuestionsSlide} /> From de7b6315a9eb8a77535387852c6ee0dc8d50f40b Mon Sep 17 00:00:00 2001 From: "Anthony D. Mays" Date: Fri, 2 May 2025 17:12:41 +0000 Subject: [PATCH 4/4] chore: adds build checks Signed-off-by: Anthony D. Mays --- .../workflows/check_lesson_26_java_pr.yaml | 28 +++++++++++++++++++ .github/workflows/check_lesson_26_ts_pr.yaml | 28 +++++++++++++++++++ .github/workflows/check_push.yml | 10 +++++++ 3 files changed, 66 insertions(+) create mode 100644 .github/workflows/check_lesson_26_java_pr.yaml create mode 100644 .github/workflows/check_lesson_26_ts_pr.yaml diff --git a/.github/workflows/check_lesson_26_java_pr.yaml b/.github/workflows/check_lesson_26_java_pr.yaml new file mode 100644 index 000000000..cbb91f0e0 --- /dev/null +++ b/.github/workflows/check_lesson_26_java_pr.yaml @@ -0,0 +1,28 @@ +name: Check Lesson 26 Java Pull Request + +on: + pull_request: + branches: [ "main" ] + paths: + - "lesson_26/api/java/**" + +jobs: + build: + + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: write + + steps: + - uses: actions/checkout@v4 + + - name: Set up JDK + uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: 'temurin' + + - name: Build Lesson 26 with Java + working-directory: ./lesson_26/api/java + run: ./gradlew check \ No newline at end of file diff --git a/.github/workflows/check_lesson_26_ts_pr.yaml b/.github/workflows/check_lesson_26_ts_pr.yaml new file mode 100644 index 000000000..9b2cd15be --- /dev/null +++ b/.github/workflows/check_lesson_26_ts_pr.yaml @@ -0,0 +1,28 @@ +name: Check Lesson 26 TS Pull Request + +on: + pull_request: + branches: [ "main" ] + paths: + - "lesson_26/api/javascript/api_app/**" + +jobs: + build: + + runs-on: ubuntu-latest + permissions: + contents: read + + steps: + - uses: actions/checkout@v4 + + - name: Use Node.js + uses: actions/setup-node@v4 + with: + node-version: '20.x' + + - name: Build Lesson 26 with Node.js + working-directory: ./lesson_26/api/javascript/api_app + run: | + npm ci + npm run check \ No newline at end of file diff --git a/.github/workflows/check_push.yml b/.github/workflows/check_push.yml index 054de1e25..5fa29fd04 100644 --- a/.github/workflows/check_push.yml +++ b/.github/workflows/check_push.yml @@ -164,3 +164,13 @@ jobs: working-directory: ./lesson_17/bank run: ./gradlew check + - name: Build Lesson 26 with Java + working-directory: ./lesson_26/api/java + run: ./gradlew assemble + + - name: Build Lesson 26 with Node.js + working-directory: ./lesson_26/api/javascript/api_app + run: | + npm ci + npm run build +