From a285608af17d05816093a9a3406117d8dd6a3281 Mon Sep 17 00:00:00 2001 From: Jelle Maas Date: Wed, 22 Mar 2023 14:13:26 +0100 Subject: [PATCH] Add initial Web API project including relevant changes (#93) Resolve issues caused by rebasing Fix merge issues Homepage (#74) * Created Page model and Service interface * Created PageHttpService.cs * Added GetPageImages method * Changed GetPageImages so that it replaces the img src with the base64 string of the image. * Added persona to word exporter * Added dispose * Removed redundant code and renamed method * Wrapped HttpRequestMessage in try catch block to ensure that the request gets disposed even when an error is thrown. * Changed HttpClient to protected, renamed HTMLUrl to HtmlUrl to match code convention, modified Httpservices and changed FileService to iEnumerable. * Changed to using * Change on previous commit * fix * Removed generic exception * fix * Added throw exception to suppress testing error. Feat/58 unit testing poc (#73) * Release v1.0.0 (#41) * Change formats type to `string` and split with comma separator * Use root configuration instead of configuration section * Fix exceptions not properly displaying in the console * Add all module item types according to documentation * Update application demo GIF * Create code-analysis.yml * Remove comments and enable additional queries * Removed push from code-analysis.yml workflow * Typo code-analysis.yml * Added support for a Word export option * Added footer Epsilon Credits * Created helper class with reformat functions * Reformat code * Improved helper functions, Found that they can be added to records :-) * Reformat files * string interpolation * Feature/cleanup (#40) * Remove obsolete Epsilon.Http.Abstractions project * Fix invalid serializable implementation * Disable unused method return value hint * Change exception to more appropriate one * Update Grade score description * Prevent null grades from exporting * Reduce cognitive complexity to acceptable level * Move logging call * Reduce nesting * Move project name and repository uri to constants * Fix nullability warnings * Remove unused class * Use ?: operator and move constants to top level of class * Reduce loop complexity * Use project name constant in output name export option * Update README.md application demo gif * Add supported formats to README.md Co-authored-by: Jelle Maas * POC Open XML SDK * Update * Add KPI format and structure * Added module names to document * Testing the build and structure of exel files. * Testing release deployment script. * Delete file * POC for excel export * Code reformat * Abstracted format logic from exporters to main logic * Remove typo * Remove unused variable * Headers added * Code cleanup * Merge * Removal nullability warnings * Removal nullability warnings * Removal tasks/awaits because they dont have nay use atm. * Removal tasks/awaits because they dont have nay use atm. * Add exporters return type * Added memoryStream return type for ConsoleModuleExporter * Remove unused ExportOptions from ConsoleModuleExporter * Clean up old merge files * Update continuous-integration.yml * Add tests for HttpService, Exporter and ExportDataPackager * Update continuous-integration.yml * 'Var' is everything * Update continuous-integration.yml * Created unit test for CanvasModuleCollectionFetcher GetAll method * Renamed unit test * Bugfix * Merged feat/42 into feat/58 * Refactored ExcelModuleExporter tests to WordModuleExporter tests --------- Co-authored-by: Neal Geilen Co-authored-by: Jelle Maas Co-authored-by: Sven Hansen <76601644+1SvenHansen@users.noreply.github.com> Add download Word file endpoint Change classes to records & add poc endpoints Create controllers and endpoints Add decaying average logic to the frontend (#86) * Add multi threading * Restyle KPI Table and cleanup code * Rename to correspond to definitions * Reformat code * Add loading icon * Decrease personal development graph width * Add decaying average to front-end * Rename styling entries to conform with coding conventions and reformat code * Use colors from domain * Small cleanup changes * Eslint enforcements updates * CI testing * CI testing * Bugfixes * Hardcoded preliminary version of the dashboard with functional term buttons. Ready for demo skrr skrr * Fix competence profile being empty and cleanup code * Make personal development height the same as competence graph * Use different order for terms * Remove centering * Show toolbar * changes of commands to pnpm * Set version and package manager * Add a readme * First POC for moving DecayingAverage logic to frontend * Moved the DecayingAverage.ts to the frontend * Removal backed code of decayingAverage * Fronted changes * Merge * Trying * POC decaying average * Cleanup * Add abstraction for competence outcome results * Removal of backend Decaying average calculations * Calculating decaying average in the frontend * Frontend implementation of decaying average * Import change * code cleanup * code cleanup * Graph changes on term selection * Implementation PersonalDevelopmentGraph.vue * Warning fixes * Mastery level indication in PersonalDevelopmentGraph.vue * Fixed the mess * Change AssessedAt to SubmittedAt * Added comments * Cleanup code * MOved functions inside mount function * Changed function names * Changes and removed unused file * Project setting changes --------- Co-authored-by: Jelle Maas Co-authored-by: jan.fojtik Make dashboard frontend improvements (#83) * Add multi threading * Restyle KPI Table and cleanup code * Rename to correspond to definitions * Reformat code * Add loading icon * Decrease personal development graph width * Add decaying average to front-end * Rename styling entries to conform with coding conventions and reformat code * Use colors from domain * Small cleanup changes * Eslint enforcements updates * CI testing * CI testing * Bugfixes * Hardcoded preliminary version of the dashboard with functional term buttons. Ready for demo skrr skrr * Fix competence profile being empty and cleanup code * Make personal development height the same as competence graph * Use different order for terms * Remove centering * Show toolbar * changes of commands to pnpm * Set version and package manager * Add a readme * Selected button highglight * Update README.md * Cleanup project and update PNPM lock file * Add prettier plugin and update code to conform to coding guidelines * Add JavaScript to code analysis action * Perform code analysis on all pull requests * Add null checking on cert and key * Add separate jobs for setup, building and linting * Install PNPM in setup job * Fix unknown cache path * Install PNPM for build and lint jobs * Remove redundant setup step and add install to both lint and build steps --------- Co-authored-by: Jelle Maas Co-authored-by: jan.fojtik Add support for component based documents (EpsilonComponents) (#89) * Initial component architecture for JSON and Word export * Added architecture for single point of component data retrieval and Word convertion * Typo * Cleanup component architecture and modify Word export to return OpenXML * Add coding guidelines enforcement (#85) * Add initial coding guidelines and fix where necessary * Enforce code styling and update code where necessary * Remove duplicate .editorconfig entries * Add code analysis setup to CI * Add missing checkout step * Update incorrect action version tag * Remove incompatible analysis step * Push code style offense to validate CI pipeline * Remove code style violation * Add global.json * Add support for dynamic component converters * Removed Word component merging logic from controller to WordDownloader class * Remve redundant method * Remove accidental document * Remove redundant models and interfaces * Fix persona images not being added as Base64 (#84) * Made some adjustments that the pictures in the persona get converted to Base64 strings versus loading it remotely from Canvas (as the access key is only valid for a limited time period) * Add coding guidelines enforcement (#85) * Add initial coding guidelines and fix where necessary * Enforce code styling and update code where necessary * Remove duplicate .editorconfig entries * Add code analysis setup to CI * Add missing checkout step * Update incorrect action version tag * Remove incompatible analysis step * Push code style offense to validate CI pipeline * Remove code style violation * Add global.json * Made a couple of changes based on recommendations made in the merge request. --------- Co-authored-by: Jelle Maas * Fix exporters no longer working correctly (#88) * Temporarily fix paginator not working correctly * Set format names to uppercase * Fix stream being disposed before usage * Fix homepage returning null when no images are present * Cleanup Word downloader * Change CLI project namespace to allow for additional projects * Add initial Web API project * Create controllers and endpoints * Transform abstract class to interface * Change classes to records & add poc endpoints * Add download Word file endpoint * Typo * Add initial frontend code * Add competence profile data model (#76) * Initial proof of concept for competence profile data model * Refactor competence profile return type * Created endpoint with updated HboIDomain and Mockdata. Also created GraphQL endpoint for student data * Cleanup records to seperate GraphQL folder * Fix GraphQL records --------- Co-authored-by: Jelle Maas Co-authored-by: Sven Hansen <76601644+1SvenHansen@users.noreply.github.com> * Link submission query with competence profile endpoint (#79) * Added Professional development * Rename namespace to correspond with coding guidelines * Separate records into different files * Rename Value to Name to correspond with domain * Rename Value to Level to correspond with domain * Add professional skills to domain * Add short name to architectural layer and professional skills * Rename properties in competence profile random data filler * Rename CompetenceProfileOutcome to ProfessionalTaskOutcome * Add Professional skill outcome to competence profile * Use singular name * Use id references instead of name values * Use type keyword * Add submissions from all courses from student to competence profile transformation * Fix merge issues * Add task and skill outcomes to competence profile return type * Fetch terms from canvas * Remove redundant imports * Change default application url * Prevent browser from launching on every restart * Cleanup code * Add filter enrolment term function * Add terms to competence profile * Remove unused terms function * Added filter on professional outcomes and sorting * Removed unused things * V0.1 * Defining colors for elements * Remove obsolete styling * Update pnpm lock file * Add Vue router * Resolve ESLint warnings * Add authorization view and controller * Use controller templating for route * A lot of stuff * A lot of stuff * Working * Set it all to vue 3 supported format * Fix import path * Add CORS policy * Realtime user data * Add terms to competence profile * Cleanup code and improve competence profile converter * Filter on PostedAt value --------- Co-authored-by: Tara Co-authored-by: Sven Co-authored-by: Neal Geilen * Add performance dashboard frontend interface (#81) * Added Professional development * Rename namespace to correspond with coding guidelines * Separate records into different files * Rename Value to Name to correspond with domain * Rename Value to Level to correspond with domain * Add professional skills to domain * Add short name to architectural layer and professional skills * Rename properties in competence profile random data filler * Rename CompetenceProfileOutcome to ProfessionalTaskOutcome * Add Professional skill outcome to competence profile * Use singular name * Use id references instead of name values * Use type keyword * Add submissions from all courses from student to competence profile transformation * Fix merge issues * Add task and skill outcomes to competence profile return type * Fetch terms from canvas * Remove redundant imports * Change default application url * Prevent browser from launching on every restart * Cleanup code * V0.1 * Defining colors for elements * Remove obsolete styling * Update pnpm lock file * Add Vue router * Resolve ESLint warnings * Add authorization view and controller * Use controller templating for route * A lot of stuff * A lot of stuff * Working * Set it all to vue 3 supported format * Fix import path * Add CORS policy * Realtime user data * Bugfixes * Add filter enrolment term function * Add terms to competence profile * Remove unused terms function * Added filter on professional outcomes and sorting * Removed unused things * Realtime user data * Add terms to competence profile * Cleanup code and improve competence profile converter * Filter on PostedAt value * Added frontend grid & colors --------- Co-authored-by: Tara Co-authored-by: Jelle Maas Co-authored-by: Sven Co-authored-by: Eline * Add decaying average calculations (#80) * initial version of the decaying average functionality * Added Professional development * Rename namespace to correspond with coding guidelines * Separate records into different files * Rename Value to Name to correspond with domain * Rename Value to Level to correspond with domain * Add professional skills to domain * Add short name to architectural layer and professional skills * Rename properties in competence profile random data filler * Rename CompetenceProfileOutcome to ProfessionalTaskOutcome * Add Professional skill outcome to competence profile * Use singular name * Use id references instead of name values * Use type keyword * re-adding decaying average files and logic * Add submissions from all courses from student to competence profile transformation * Fix merge issues * Add task and skill outcomes to competence profile return type * Fetch terms from canvas * Remove redundant imports * Change default application url * Prevent browser from launching on every restart * Cleanup code * Add filter enrolment term function * Add terms to competence profile * Remove unused terms function * Added filter on professional outcomes and sorting * Removed unused things * V0.1 * Defining colors for elements * Remove obsolete styling * Update pnpm lock file * Add Vue router * Resolve ESLint warnings * Add authorization view and controller * Use controller templating for route * A lot of stuff * A lot of stuff * Working * Set it all to vue 3 supported format * Fix import path * Add CORS policy * Realtime user data * Add terms to competence profile * Cleanup code and improve competence profile converter * Filter on PostedAt value * initial version of the decaying average functionality * re-adding decaying average files and logic * Decaying average calculation functionality supporting both ArchitectureLayer and Skill outcomes * Decaying average calculation functional per layer per activity and skills are independent of layers --------- Co-authored-by: jan.fojtik Co-authored-by: Tara Co-authored-by: Jelle Maas Co-authored-by: Sven Co-authored-by: Neal Geilen * Fix to not all learning outcomes getting retrieved (#82) * Attempt to fix not all learning outcomes getting retrieved * Use submission histories instead of rubric assessments directly * Ensure rubric assessments nodes has elements * Add performance dashboard frontend interface (#81) * Added Professional development * Rename namespace to correspond with coding guidelines * Separate records into different files * Rename Value to Name to correspond with domain * Rename Value to Level to correspond with domain * Add professional skills to domain * Add short name to architectural layer and professional skills * Rename properties in competence profile random data filler * Rename CompetenceProfileOutcome to ProfessionalTaskOutcome * Add Professional skill outcome to competence profile * Use singular name * Use id references instead of name values * Use type keyword * Add submissions from all courses from student to competence profile transformation * Fix merge issues * Add task and skill outcomes to competence profile return type * Fetch terms from canvas * Remove redundant imports * Change default application url * Prevent browser from launching on every restart * Cleanup code * V0.1 * Defining colors for elements * Remove obsolete styling * Update pnpm lock file * Add Vue router * Resolve ESLint warnings * Add authorization view and controller * Use controller templating for route * A lot of stuff * A lot of stuff * Working * Set it all to vue 3 supported format * Fix import path * Add CORS policy * Realtime user data * Bugfixes * Add filter enrolment term function * Add terms to competence profile * Remove unused terms function * Added filter on professional outcomes and sorting * Removed unused things * Realtime user data * Add terms to competence profile * Cleanup code and improve competence profile converter * Filter on PostedAt value * Added frontend grid & colors --------- Co-authored-by: Tara Co-authored-by: Jelle Maas Co-authored-by: Sven Co-authored-by: Eline * Add decaying average calculations (#80) * initial version of the decaying average functionality * Added Professional development * Rename namespace to correspond with coding guidelines * Separate records into different files * Rename Value to Name to correspond with domain * Rename Value to Level to correspond with domain * Add professional skills to domain * Add short name to architectural layer and professional skills * Rename properties in competence profile random data filler * Rename CompetenceProfileOutcome to ProfessionalTaskOutcome * Add Professional skill outcome to competence profile * Use singular name * Use id references instead of name values * Use type keyword * re-adding decaying average files and logic * Add submissions from all courses from student to competence profile transformation * Fix merge issues * Add task and skill outcomes to competence profile return type * Fetch terms from canvas * Remove redundant imports * Change default application url * Prevent browser from launching on every restart * Cleanup code * Add filter enrolment term function * Add terms to competence profile * Remove unused terms function * Added filter on professional outcomes and sorting * Removed unused things * V0.1 * Defining colors for elements * Remove obsolete styling * Update pnpm lock file * Add Vue router * Resolve ESLint warnings * Add authorization view and controller * Use controller templating for route * A lot of stuff * A lot of stuff * Working * Set it all to vue 3 supported format * Fix import path * Add CORS policy * Realtime user data * Add terms to competence profile * Cleanup code and improve competence profile converter * Filter on PostedAt value * initial version of the decaying average functionality * re-adding decaying average files and logic * Decaying average calculation functionality supporting both ArchitectureLayer and Skill outcomes * Decaying average calculation functional per layer per activity and skills are independent of layers --------- Co-authored-by: jan.fojtik Co-authored-by: Tara Co-authored-by: Jelle Maas Co-authored-by: Sven Co-authored-by: Neal Geilen * Correct HBO-i domain layer order * Add performance dashboard frontend interface (#81) * Added Professional development * Rename namespace to correspond with coding guidelines * Separate records into different files * Rename Value to Name to correspond with domain * Rename Value to Level to correspond with domain * Add professional skills to domain * Add short name to architectural layer and professional skills * Rename properties in competence profile random data filler * Rename CompetenceProfileOutcome to ProfessionalTaskOutcome * Add Professional skill outcome to competence profile * Use singular name * Use id references instead of name values * Use type keyword * Add submissions from all courses from student to competence profile transformation * Fix merge issues * Add task and skill outcomes to competence profile return type * Fetch terms from canvas * Remove redundant imports * Change default application url * Prevent browser from launching on every restart * Cleanup code * V0.1 * Defining colors for elements * Remove obsolete styling * Update pnpm lock file * Add Vue router * Resolve ESLint warnings * Add authorization view and controller * Use controller templating for route * A lot of stuff * A lot of stuff * Working * Set it all to vue 3 supported format * Fix import path * Add CORS policy * Realtime user data * Bugfixes * Add filter enrolment term function * Add terms to competence profile * Remove unused terms function * Added filter on professional outcomes and sorting * Removed unused things * Realtime user data * Add terms to competence profile * Cleanup code and improve competence profile converter * Filter on PostedAt value * Added frontend grid & colors --------- Co-authored-by: Tara Co-authored-by: Jelle Maas Co-authored-by: Sven Co-authored-by: Eline * Add decaying average calculations (#80) * initial version of the decaying average functionality * Added Professional development * Rename namespace to correspond with coding guidelines * Separate records into different files * Rename Value to Name to correspond with domain * Rename Value to Level to correspond with domain * Add professional skills to domain * Add short name to architectural layer and professional skills * Rename properties in competence profile random data filler * Rename CompetenceProfileOutcome to ProfessionalTaskOutcome * Add Professional skill outcome to competence profile * Use singular name * Use id references instead of name values * Use type keyword * re-adding decaying average files and logic * Add submissions from all courses from student to competence profile transformation * Fix merge issues * Add task and skill outcomes to competence profile return type * Fetch terms from canvas * Remove redundant imports * Change default application url * Prevent browser from launching on every restart * Cleanup code * Add filter enrolment term function * Add terms to competence profile * Remove unused terms function * Added filter on professional outcomes and sorting * Removed unused things * V0.1 * Defining colors for elements * Remove obsolete styling * Update pnpm lock file * Add Vue router * Resolve ESLint warnings * Add authorization view and controller * Use controller templating for route * A lot of stuff * A lot of stuff * Working * Set it all to vue 3 supported format * Fix import path * Add CORS policy * Realtime user data * Add terms to competence profile * Cleanup code and improve competence profile converter * Filter on PostedAt value * initial version of the decaying average functionality * re-adding decaying average files and logic * Decaying average calculation functionality supporting both ArchitectureLayer and Skill outcomes * Decaying average calculation functional per layer per activity and skills are independent of layers --------- Co-authored-by: jan.fojtik Co-authored-by: Tara Co-authored-by: Jelle Maas Co-authored-by: Sven Co-authored-by: Neal Geilen * Attempt to fix not all learning outcomes getting retrieved * Use submission histories instead of rubric assessments directly * Ensure rubric assessments nodes has elements * Correct HBO-i domain layer order --------- Co-authored-by: Jelle Maas Co-authored-by: Tara Co-authored-by: Sven Co-authored-by: Eline Co-authored-by: jendafojtik <83012368+jendafojtik@users.noreply.github.com> Co-authored-by: jan.fojtik * Initial component architecture for JSON and Word export * Added architecture for single point of component data retrieval and Word convertion * Typo * Cleanup component architecture and modify Word export to return OpenXML * Add support for dynamic component converters * Removed Word component merging logic from controller to WordDownloader class * Remve redundant method * Remove accidental document * Remove redundant models and interfaces * Cleanup Word downloader * Fix code analysis issues * Fix incorrect interface reference * Remove CLI projects and its dependencies * Rename Epsilon component classes * Reformat records * Remove obsolete test * Rename TResponse to TComponent * Remove redundant export data * Remove redundant interface * Add service collection extensions for components * Rework component converters to be included in component models * Move domain logic in controller to separate services * Move component name to attribute and rename to competence component * Remove duplicate package reference * Move HttpService class to Canvas project * Remove unused constants * Modify persona page to accommodate new component architecture (#91) * Created PersonaPage component for the new architecture. * fix feedback sven * Cleanup code * Modify architecture to force adding Word components instead of creating them * Add using statement to ensure stream is disposed --------- Co-authored-by: Jelle Maas * Add initial KPI matrix component (#87) * Created KpiMatrix component * Added modules and fixed comments * Fixed an issue where outcomes where duplicate * Created KPIMatrix in word document * Fixed all remaining issues. * Merge conflicts * Fixed MR requests * Changed course to allcourses * File restructure * Revised coding structure. Assignments that are not yest graded are also now included * Merged files in new structure * Colored rows * "Simplified" * Move HttpService class to Canvas project * Added legend and changed "GradeStatus" structure * Remove unused constants * Modify persona page to accommodate new component architecture (#91) * Created PersonaPage component for the new architecture. * fix feedback sven * Cleanup code * Modify architecture to force adding Word components instead of creating them * Add using statement to ensure stream is disposed --------- Co-authored-by: Jelle Maas * Move HttpService class to Canvas project * Remove unused constants * Modify persona page to accommodate new component architecture (#91) * Created PersonaPage component for the new architecture. * fix feedback sven * Cleanup code * Modify architecture to force adding Word components instead of creating them * Add using statement to ensure stream is disposed --------- Co-authored-by: Jelle Maas * Created KpiMatrix component * Added modules and fixed comments * Merge conflicts * File restructure * Revised coding structure. Assignments that are not yest graded are also now included * Created KpiMatrix component * Added modules and fixed comments * Merge conflicts * File restructure * Revised coding structure. Assignments that are not yest graded are also now included * Added legend and changed "GradeStatus" structure * Added extra grade type * Added legend to json result * Working order * startDate & endDate implementation for document generator * POC working * Created KpiMatrix component * Added modules and fixed comments * Fixed an issue where outcomes where duplicate * Created KPIMatrix in word document * Fixed all remaining issues. * Merge conflicts * Fixed MR requests * Changed course to allcourses * File restructure * Revised coding structure. Assignments that are not yest graded are also now included * Merged files in new structure * Colored rows * "Simplified" * Added legend and changed "GradeStatus" structure * Created KpiMatrix component * Added modules and fixed comments * Merge conflicts * File restructure * Revised coding structure. Assignments that are not yest graded are also now included * Created KpiMatrix component * Added modules and fixed comments * Merge conflicts * File restructure * Revised coding structure. Assignments that are not yest graded are also now included * Added legend and changed "GradeStatus" structure * Added extra grade type * Added legend to json result * Working order * startDate & endDate implementation for document generator * POC working * changes * Lint fixes * Lint fixes * Cleanup code and update coding guidelines * Change outcome grade statuses * Cleanup code --------- Co-authored-by: Neal Geilen Co-authored-by: Jelle Maas Co-authored-by: Koen Janssen <6256259+koen253janssen@users.noreply.github.com> --------- Co-authored-by: Sven Co-authored-by: Koen Janssen <6256259+koen253janssen@users.noreply.github.com> Co-authored-by: Sven Hansen <76601644+1SvenHansen@users.noreply.github.com> Co-authored-by: Sven Hansen <76601644+SyntaxSven@users.noreply.github.com> Co-authored-by: Tara Co-authored-by: Neal Geilen Co-authored-by: Eline Co-authored-by: jendafojtik <83012368+jendafojtik@users.noreply.github.com> Co-authored-by: jan.fojtik Co-authored-by: Jasper123pyah <73039915+Jasper123pyah@users.noreply.github.com> Fix to not all learning outcomes getting retrieved (#82) * Attempt to fix not all learning outcomes getting retrieved * Use submission histories instead of rubric assessments directly * Ensure rubric assessments nodes has elements * Add performance dashboard frontend interface (#81) * Added Professional development * Rename namespace to correspond with coding guidelines * Separate records into different files * Rename Value to Name to correspond with domain * Rename Value to Level to correspond with domain * Add professional skills to domain * Add short name to architectural layer and professional skills * Rename properties in competence profile random data filler * Rename CompetenceProfileOutcome to ProfessionalTaskOutcome * Add Professional skill outcome to competence profile * Use singular name * Use id references instead of name values * Use type keyword * Add submissions from all courses from student to competence profile transformation * Fix merge issues * Add task and skill outcomes to competence profile return type * Fetch terms from canvas * Remove redundant imports * Change default application url * Prevent browser from launching on every restart * Cleanup code * V0.1 * Defining colors for elements * Remove obsolete styling * Update pnpm lock file * Add Vue router * Resolve ESLint warnings * Add authorization view and controller * Use controller templating for route * A lot of stuff * A lot of stuff * Working * Set it all to vue 3 supported format * Fix import path * Add CORS policy * Realtime user data * Bugfixes * Add filter enrolment term function * Add terms to competence profile * Remove unused terms function * Added filter on professional outcomes and sorting * Removed unused things * Realtime user data * Add terms to competence profile * Cleanup code and improve competence profile converter * Filter on PostedAt value * Added frontend grid & colors --------- Co-authored-by: Tara Co-authored-by: Jelle Maas Co-authored-by: Sven Co-authored-by: Eline * Add decaying average calculations (#80) * initial version of the decaying average functionality * Added Professional development * Rename namespace to correspond with coding guidelines * Separate records into different files * Rename Value to Name to correspond with domain * Rename Value to Level to correspond with domain * Add professional skills to domain * Add short name to architectural layer and professional skills * Rename properties in competence profile random data filler * Rename CompetenceProfileOutcome to ProfessionalTaskOutcome * Add Professional skill outcome to competence profile * Use singular name * Use id references instead of name values * Use type keyword * re-adding decaying average files and logic * Add submissions from all courses from student to competence profile transformation * Fix merge issues * Add task and skill outcomes to competence profile return type * Fetch terms from canvas * Remove redundant imports * Change default application url * Prevent browser from launching on every restart * Cleanup code * Add filter enrolment term function * Add terms to competence profile * Remove unused terms function * Added filter on professional outcomes and sorting * Removed unused things * V0.1 * Defining colors for elements * Remove obsolete styling * Update pnpm lock file * Add Vue router * Resolve ESLint warnings * Add authorization view and controller * Use controller templating for route * A lot of stuff * A lot of stuff * Working * Set it all to vue 3 supported format * Fix import path * Add CORS policy * Realtime user data * Add terms to competence profile * Cleanup code and improve competence profile converter * Filter on PostedAt value * initial version of the decaying average functionality * re-adding decaying average files and logic * Decaying average calculation functionality supporting both ArchitectureLayer and Skill outcomes * Decaying average calculation functional per layer per activity and skills are independent of layers --------- Co-authored-by: jan.fojtik Co-authored-by: Tara Co-authored-by: Jelle Maas Co-authored-by: Sven Co-authored-by: Neal Geilen * Correct HBO-i domain layer order * Add performance dashboard frontend interface (#81) * Added Professional development * Rename namespace to correspond with coding guidelines * Separate records into different files * Rename Value to Name to correspond with domain * Rename Value to Level to correspond with domain * Add professional skills to domain * Add short name to architectural layer and professional skills * Rename properties in competence profile random data filler * Rename CompetenceProfileOutcome to ProfessionalTaskOutcome * Add Professional skill outcome to competence profile * Use singular name * Use id references instead of name values * Use type keyword * Add submissions from all courses from student to competence profile transformation * Fix merge issues * Add task and skill outcomes to competence profile return type * Fetch terms from canvas * Remove redundant imports * Change default application url * Prevent browser from launching on every restart * Cleanup code * V0.1 * Defining colors for elements * Remove obsolete styling * Update pnpm lock file * Add Vue router * Resolve ESLint warnings * Add authorization view and controller * Use controller templating for route * A lot of stuff * A lot of stuff * Working * Set it all to vue 3 supported format * Fix import path * Add CORS policy * Realtime user data * Bugfixes * Add filter enrolment term function * Add terms to competence profile * Remove unused terms function * Added filter on professional outcomes and sorting * Removed unused things * Realtime user data * Add terms to competence profile * Cleanup code and improve competence profile converter * Filter on PostedAt value * Added frontend grid & colors --------- Co-authored-by: Tara Co-authored-by: Jelle Maas Co-authored-by: Sven Co-authored-by: Eline * Add decaying average calculations (#80) * initial version of the decaying average functionality * Added Professional development * Rename namespace to correspond with coding guidelines * Separate records into different files * Rename Value to Name to correspond with domain * Rename Value to Level to correspond with domain * Add professional skills to domain * Add short name to architectural layer and professional skills * Rename properties in competence profile random data filler * Rename CompetenceProfileOutcome to ProfessionalTaskOutcome * Add Professional skill outcome to competence profile * Use singular name * Use id references instead of name values * Use type keyword * re-adding decaying average files and logic * Add submissions from all courses from student to competence profile transformation * Fix merge issues * Add task and skill outcomes to competence profile return type * Fetch terms from canvas * Remove redundant imports * Change default application url * Prevent browser from launching on every restart * Cleanup code * Add filter enrolment term function * Add terms to competence profile * Remove unused terms function * Added filter on professional outcomes and sorting * Removed unused things * V0.1 * Defining colors for elements * Remove obsolete styling * Update pnpm lock file * Add Vue router * Resolve ESLint warnings * Add authorization view and controller * Use controller templating for route * A lot of stuff * A lot of stuff * Working * Set it all to vue 3 supported format * Fix import path * Add CORS policy * Realtime user data * Add terms to competence profile * Cleanup code and improve competence profile converter * Filter on PostedAt value * initial version of the decaying average functionality * re-adding decaying average files and logic * Decaying average calculation functionality supporting both ArchitectureLayer and Skill outcomes * Decaying average calculation functional per layer per activity and skills are independent of layers --------- Co-authored-by: jan.fojtik Co-authored-by: Tara Co-authored-by: Jelle Maas Co-authored-by: Sven Co-authored-by: Neal Geilen * Attempt to fix not all learning outcomes getting retrieved * Use submission histories instead of rubric assessments directly * Ensure rubric assessments nodes has elements * Correct HBO-i domain layer order --------- Co-authored-by: Jelle Maas Co-authored-by: Tara Co-authored-by: Sven Co-authored-by: Eline Co-authored-by: jendafojtik <83012368+jendafojtik@users.noreply.github.com> Co-authored-by: jan.fojtik Add decaying average calculations (#80) * initial version of the decaying average functionality * Added Professional development * Rename namespace to correspond with coding guidelines * Separate records into different files * Rename Value to Name to correspond with domain * Rename Value to Level to correspond with domain * Add professional skills to domain * Add short name to architectural layer and professional skills * Rename properties in competence profile random data filler * Rename CompetenceProfileOutcome to ProfessionalTaskOutcome * Add Professional skill outcome to competence profile * Use singular name * Use id references instead of name values * Use type keyword * re-adding decaying average files and logic * Add submissions from all courses from student to competence profile transformation * Fix merge issues * Add task and skill outcomes to competence profile return type * Fetch terms from canvas * Remove redundant imports * Change default application url * Prevent browser from launching on every restart * Cleanup code * Add filter enrolment term function * Add terms to competence profile * Remove unused terms function * Added filter on professional outcomes and sorting * Removed unused things * V0.1 * Defining colors for elements * Remove obsolete styling * Update pnpm lock file * Add Vue router * Resolve ESLint warnings * Add authorization view and controller * Use controller templating for route * A lot of stuff * A lot of stuff * Working * Set it all to vue 3 supported format * Fix import path * Add CORS policy * Realtime user data * Add terms to competence profile * Cleanup code and improve competence profile converter * Filter on PostedAt value * initial version of the decaying average functionality * re-adding decaying average files and logic * Decaying average calculation functionality supporting both ArchitectureLayer and Skill outcomes * Decaying average calculation functional per layer per activity and skills are independent of layers --------- Co-authored-by: jan.fojtik Co-authored-by: Tara Co-authored-by: Jelle Maas Co-authored-by: Sven Co-authored-by: Neal Geilen Add performance dashboard frontend interface (#81) * Added Professional development * Rename namespace to correspond with coding guidelines * Separate records into different files * Rename Value to Name to correspond with domain * Rename Value to Level to correspond with domain * Add professional skills to domain * Add short name to architectural layer and professional skills * Rename properties in competence profile random data filler * Rename CompetenceProfileOutcome to ProfessionalTaskOutcome * Add Professional skill outcome to competence profile * Use singular name * Use id references instead of name values * Use type keyword * Add submissions from all courses from student to competence profile transformation * Fix merge issues * Add task and skill outcomes to competence profile return type * Fetch terms from canvas * Remove redundant imports * Change default application url * Prevent browser from launching on every restart * Cleanup code * V0.1 * Defining colors for elements * Remove obsolete styling * Update pnpm lock file * Add Vue router * Resolve ESLint warnings * Add authorization view and controller * Use controller templating for route * A lot of stuff * A lot of stuff * Working * Set it all to vue 3 supported format * Fix import path * Add CORS policy * Realtime user data * Bugfixes * Add filter enrolment term function * Add terms to competence profile * Remove unused terms function * Added filter on professional outcomes and sorting * Removed unused things * Realtime user data * Add terms to competence profile * Cleanup code and improve competence profile converter * Filter on PostedAt value * Added frontend grid & colors --------- Co-authored-by: Tara Co-authored-by: Jelle Maas Co-authored-by: Sven Co-authored-by: Eline Link submission query with competence profile endpoint (#79) * Added Professional development * Rename namespace to correspond with coding guidelines * Separate records into different files * Rename Value to Name to correspond with domain * Rename Value to Level to correspond with domain * Add professional skills to domain * Add short name to architectural layer and professional skills * Rename properties in competence profile random data filler * Rename CompetenceProfileOutcome to ProfessionalTaskOutcome * Add Professional skill outcome to competence profile * Use singular name * Use id references instead of name values * Use type keyword * Add submissions from all courses from student to competence profile transformation * Fix merge issues * Add task and skill outcomes to competence profile return type * Fetch terms from canvas * Remove redundant imports * Change default application url * Prevent browser from launching on every restart * Cleanup code * Add filter enrolment term function * Add terms to competence profile * Remove unused terms function * Added filter on professional outcomes and sorting * Removed unused things * V0.1 * Defining colors for elements * Remove obsolete styling * Update pnpm lock file * Add Vue router * Resolve ESLint warnings * Add authorization view and controller * Use controller templating for route * A lot of stuff * A lot of stuff * Working * Set it all to vue 3 supported format * Fix import path * Add CORS policy * Realtime user data * Add terms to competence profile * Cleanup code and improve competence profile converter * Filter on PostedAt value --------- Co-authored-by: Tara Co-authored-by: Sven Co-authored-by: Neal Geilen Add competence profile data model (#76) * Initial proof of concept for competence profile data model * Refactor competence profile return type * Created endpoint with updated HboIDomain and Mockdata. Also created GraphQL endpoint for student data * Cleanup records to seperate GraphQL folder * Fix GraphQL records --------- Co-authored-by: Jelle Maas Co-authored-by: Sven Hansen <76601644+1SvenHansen@users.noreply.github.com> Add initial frontend code Typo Add download Word file endpoint Change classes to records & add poc endpoints Transform abstract class to interface Create controllers and endpoints Add initial Web API project Change CLI project namespace to allow for additional projects --- .editorconfig | 5 +- .github/workflows/code-analysis.yml | 3 +- .github/workflows/continuous-integration.yml | 60 +- .gitignore | 6 +- .../Component/CompetenceComponentFetcher.cs | 8 + .../CompetenceComponentNameAttribute.cs | 12 + .../Component/CompetenceProfile.cs | 34 + .../Component/ICompetenceComponent.cs | 8 + .../Component/ICompetenceComponentFetcher.cs | 12 + .../Component/ICompetenceWordComponent.cs | 8 + .../Component/KpiMatrixAssignment.cs | 6 + .../Component/KpiMatrixCollection.cs | 196 ++ .../Component/KpiMatrixOutcome.cs | 7 + .../Component/KpiMatrixOutcomeGradeStatus.cs | 6 + Epsilon.Abstractions/Component/PersonaPage.cs | 25 + .../Epsilon.Abstractions.csproj | 5 +- .../Export/ICanvasModuleExporter.cs | 7 - .../Export/IExportDataPackager.cs | 9 - Epsilon.Abstractions/Export/IExporter.cs | 10 - .../Export/IModuleExporterCollection.cs | 8 - Epsilon.Abstractions/Model/Activity.cs | 7 + .../Model/ArchitecturalLayer.cs | 8 + .../Model/CompetenceOutcomeResult.cs | 7 + Epsilon.Abstractions/Model/ExportData.cs | 8 - Epsilon.Abstractions/Model/HboIDomain2018.cs | 60 + Epsilon.Abstractions/Model/IHboIDomain.cs | 9 + Epsilon.Abstractions/Model/MasteryLevel.cs | 3 + .../Model/ProfessionalSkill.cs | 8 + .../Model/ProfessionalSkillLevel.cs | 6 + .../Model/ProfessionalSkillResult.cs | 9 + .../Model/ProfessionalTask.cs | 7 + .../Model/ProfessionalTaskResult.cs | 10 + .../Service/ICompetenceComponentService.cs | 14 + .../Service/ICompetenceDocumentService.cs | 6 + .../ICanvasModuleCollectionFetcher.cs | 8 - .../Model/EnrollmentTerm.cs | 9 + .../Model/EnrollmentTermCollection.cs | 7 + .../Model/GraphQl/AssessmentRating.cs | 11 + .../Model/GraphQl/Assignment.cs | 9 + .../GraphQl/CanvasGraphQlQueryResponse.cs | 7 + .../Model/GraphQl/CanvasGraphQlSchema.cs | 8 + .../Model/GraphQl/Course.cs | 8 + .../Model/GraphQl/Criteria.cs | 7 + .../Model/GraphQl/Criterion.cs | 8 + .../Model/GraphQl/Module.cs | 7 + .../Model/GraphQl/Outcome.cs | 8 + .../Model/GraphQl/Rubric.cs | 7 + .../Model/GraphQl/RubricAssessmentNode.cs | 7 + .../GraphQl/RubricAssessmentsConnection.cs | 7 + .../Model/GraphQl/SubmissionsConnection.cs | 7 + .../GraphQl/SubmissionsConnectionNode.cs | 10 + .../GraphQl/SubmissionsHistoriesConnection.cs | 7 + .../SubmissionsHistoriesConnectionNode.cs | 10 + .../Model/GraphQl/User.cs | 7 + .../Model/OutcomeGradeStatus.cs | 9 + .../Model/OutcomeResultCollection.cs | 3 +- .../Service/IAccountHttpService.cs | 8 + .../Service/IGraphQlHttpService.cs | 6 + .../CanvasModuleCollectionFetcherTests.cs | 121 - .../Epsilon.Canvas.Tests.csproj | 10 +- .../CanvasModuleCollectionFetcher.cs | 62 - .../CanvasServiceCollectionExtensions.cs | 5 +- Epsilon.Canvas/Epsilon.Canvas.csproj | 15 +- .../Http/HttpService.cs | 2 +- Epsilon.Canvas/QueryConstants.cs | 0 Epsilon.Canvas/Service/AccountHttpService.cs | 23 + .../Service/AssignmentHttpService.cs | 2 +- Epsilon.Canvas/Service/FileHttpService.cs | 2 +- Epsilon.Canvas/Service/GraphQlHttpService.cs | 30 + Epsilon.Canvas/Service/ModuleHttpService.cs | 2 +- Epsilon.Canvas/Service/OutcomeHttpService.cs | 2 +- Epsilon.Canvas/Service/PageHttpService.cs | 2 +- .../Service/PaginatorHttpService.cs | 2 +- .../Service/SubmissionHttpService.cs | 2 +- Epsilon.Cli/Epsilon.Cli.csproj | 36 - Epsilon.Cli/Program.cs | 33 - Epsilon.Cli/Startup.cs | 105 - Epsilon.Cli/appsettings.example.json | 24 - Epsilon.Host.Frontend/.eslintrc | 28 + Epsilon.Host.Frontend/.gitignore | 24 + Epsilon.Host.Frontend/.prettierrc | 7 + Epsilon.Host.Frontend/.vscode/extensions.json | 3 + Epsilon.Host.Frontend/Colors layers.md | 26 + Epsilon.Host.Frontend/README.md | 11 + Epsilon.Host.Frontend/aspnetcore-https.js | 33 + Epsilon.Host.Frontend/aspnetcore-vite.js | 54 + Epsilon.Host.Frontend/index.html | 13 + Epsilon.Host.Frontend/package-lock.json | 2810 +++++++++++++++++ Epsilon.Host.Frontend/package.json | 36 + Epsilon.Host.Frontend/pnpm-lock.yaml | 1806 +++++++++++ Epsilon.Host.Frontend/src/App.vue | 3 + Epsilon.Host.Frontend/src/assets/vite.svg | 1 + Epsilon.Host.Frontend/src/assets/vue.svg | 1 + .../src/components/CompetenceGraph.vue | 115 + .../src/components/CompetenceProfile.vue | 104 + .../components/CompetenceProfileLegend.vue | 43 + .../src/components/EnrollmentTermButtons.vue | 55 + .../src/components/KPIMatrix.vue | 69 + .../components/PersonalDevelopmentGraph.vue | 122 + .../src/components/RoundLoader.vue | 39 + Epsilon.Host.Frontend/src/logic/Api.ts | 448 +++ .../src/logic/DecayingAverageLogic.ts | 199 ++ Epsilon.Host.Frontend/src/main.ts | 6 + Epsilon.Host.Frontend/src/router/index.ts | 21 + Epsilon.Host.Frontend/src/shimd-vue.d.ts | 1 + Epsilon.Host.Frontend/src/style.css | 92 + Epsilon.Host.Frontend/src/views/Authorize.vue | 33 + .../src/views/AuthorizeUser.vue | 31 + .../src/views/PerformanceDashboard.vue | 99 + Epsilon.Host.Frontend/tsconfig.json | 34 + Epsilon.Host.Frontend/vite.config.ts | 25 + .../Controllers/AuthController.cs | 28 + .../Controllers/ComponentController.cs | 30 + .../Controllers/DocumentController.cs | 29 + .../Epsilon.Host.WebApi.csproj | 23 + Epsilon.Host.WebApi/Program.cs | 54 + .../Properties/launchSettings.json | 15 + Epsilon.Tests/Epsilon.Tests.csproj | 10 +- Epsilon.Tests/Usings.cs | 1 - Epsilon.sln | 19 +- ...etenceProfileCompetenceComponentFetcher.cs | 148 + .../ComponentServiceCollectionExtensions.cs | 17 + .../Component/KpiMatrixComponentFetcher.cs | 137 + .../Component/PersonaPageComponentFetcher.cs | 66 + Epsilon/Constants.cs | 7 - Epsilon/Epsilon.csproj | 14 +- .../Exceptions/NoExportersFoundException.cs | 31 - Epsilon/Export/ExportDataPackager.cs | 86 - Epsilon/Export/ExportOptions.cs | 14 - .../Export/Exporters/ConsoleModuleExporter.cs | 62 - Epsilon/Export/Exporters/CsvModuleExporter.cs | 97 - .../Export/Exporters/ExcelModuleExporter.cs | 132 - .../Export/Exporters/WordModuleExporter.cs | 167 - Epsilon/Export/ModuleExporterCollection.cs | 37 - .../CoreServiceCollectionExtensions.cs | 34 - Epsilon/FhictConstants.cs | 265 ++ Epsilon/Service/CompetenceComponentService.cs | 57 + Epsilon/Service/CompetenceDocumentService.cs | 41 + package-lock.json | 6 + 139 files changed, 8111 insertions(+), 1170 deletions(-) create mode 100644 Epsilon.Abstractions/Component/CompetenceComponentFetcher.cs create mode 100644 Epsilon.Abstractions/Component/CompetenceComponentNameAttribute.cs create mode 100644 Epsilon.Abstractions/Component/CompetenceProfile.cs create mode 100644 Epsilon.Abstractions/Component/ICompetenceComponent.cs create mode 100644 Epsilon.Abstractions/Component/ICompetenceComponentFetcher.cs create mode 100644 Epsilon.Abstractions/Component/ICompetenceWordComponent.cs create mode 100644 Epsilon.Abstractions/Component/KpiMatrixAssignment.cs create mode 100644 Epsilon.Abstractions/Component/KpiMatrixCollection.cs create mode 100644 Epsilon.Abstractions/Component/KpiMatrixOutcome.cs create mode 100644 Epsilon.Abstractions/Component/KpiMatrixOutcomeGradeStatus.cs create mode 100644 Epsilon.Abstractions/Component/PersonaPage.cs delete mode 100644 Epsilon.Abstractions/Export/ICanvasModuleExporter.cs delete mode 100644 Epsilon.Abstractions/Export/IExportDataPackager.cs delete mode 100644 Epsilon.Abstractions/Export/IExporter.cs delete mode 100644 Epsilon.Abstractions/Export/IModuleExporterCollection.cs create mode 100644 Epsilon.Abstractions/Model/Activity.cs create mode 100644 Epsilon.Abstractions/Model/ArchitecturalLayer.cs create mode 100644 Epsilon.Abstractions/Model/CompetenceOutcomeResult.cs delete mode 100644 Epsilon.Abstractions/Model/ExportData.cs create mode 100644 Epsilon.Abstractions/Model/HboIDomain2018.cs create mode 100644 Epsilon.Abstractions/Model/IHboIDomain.cs create mode 100644 Epsilon.Abstractions/Model/MasteryLevel.cs create mode 100644 Epsilon.Abstractions/Model/ProfessionalSkill.cs create mode 100644 Epsilon.Abstractions/Model/ProfessionalSkillLevel.cs create mode 100644 Epsilon.Abstractions/Model/ProfessionalSkillResult.cs create mode 100644 Epsilon.Abstractions/Model/ProfessionalTask.cs create mode 100644 Epsilon.Abstractions/Model/ProfessionalTaskResult.cs create mode 100644 Epsilon.Abstractions/Service/ICompetenceComponentService.cs create mode 100644 Epsilon.Abstractions/Service/ICompetenceDocumentService.cs delete mode 100644 Epsilon.Canvas.Abstractions/ICanvasModuleCollectionFetcher.cs create mode 100644 Epsilon.Canvas.Abstractions/Model/EnrollmentTerm.cs create mode 100644 Epsilon.Canvas.Abstractions/Model/EnrollmentTermCollection.cs create mode 100644 Epsilon.Canvas.Abstractions/Model/GraphQl/AssessmentRating.cs create mode 100644 Epsilon.Canvas.Abstractions/Model/GraphQl/Assignment.cs create mode 100644 Epsilon.Canvas.Abstractions/Model/GraphQl/CanvasGraphQlQueryResponse.cs create mode 100644 Epsilon.Canvas.Abstractions/Model/GraphQl/CanvasGraphQlSchema.cs create mode 100644 Epsilon.Canvas.Abstractions/Model/GraphQl/Course.cs create mode 100644 Epsilon.Canvas.Abstractions/Model/GraphQl/Criteria.cs create mode 100644 Epsilon.Canvas.Abstractions/Model/GraphQl/Criterion.cs create mode 100644 Epsilon.Canvas.Abstractions/Model/GraphQl/Module.cs create mode 100644 Epsilon.Canvas.Abstractions/Model/GraphQl/Outcome.cs create mode 100644 Epsilon.Canvas.Abstractions/Model/GraphQl/Rubric.cs create mode 100644 Epsilon.Canvas.Abstractions/Model/GraphQl/RubricAssessmentNode.cs create mode 100644 Epsilon.Canvas.Abstractions/Model/GraphQl/RubricAssessmentsConnection.cs create mode 100644 Epsilon.Canvas.Abstractions/Model/GraphQl/SubmissionsConnection.cs create mode 100644 Epsilon.Canvas.Abstractions/Model/GraphQl/SubmissionsConnectionNode.cs create mode 100644 Epsilon.Canvas.Abstractions/Model/GraphQl/SubmissionsHistoriesConnection.cs create mode 100644 Epsilon.Canvas.Abstractions/Model/GraphQl/SubmissionsHistoriesConnectionNode.cs create mode 100644 Epsilon.Canvas.Abstractions/Model/GraphQl/User.cs create mode 100644 Epsilon.Canvas.Abstractions/Model/OutcomeGradeStatus.cs create mode 100644 Epsilon.Canvas.Abstractions/Service/IAccountHttpService.cs create mode 100644 Epsilon.Canvas.Abstractions/Service/IGraphQlHttpService.cs delete mode 100644 Epsilon.Canvas.Tests/CanvasModuleCollectionFetcherTests.cs delete mode 100644 Epsilon.Canvas/CanvasModuleCollectionFetcher.cs rename {Epsilon.Abstractions => Epsilon.Canvas}/Http/HttpService.cs (80%) create mode 100644 Epsilon.Canvas/QueryConstants.cs create mode 100644 Epsilon.Canvas/Service/AccountHttpService.cs create mode 100644 Epsilon.Canvas/Service/GraphQlHttpService.cs delete mode 100644 Epsilon.Cli/Epsilon.Cli.csproj delete mode 100644 Epsilon.Cli/Program.cs delete mode 100644 Epsilon.Cli/Startup.cs delete mode 100644 Epsilon.Cli/appsettings.example.json create mode 100644 Epsilon.Host.Frontend/.eslintrc create mode 100644 Epsilon.Host.Frontend/.gitignore create mode 100644 Epsilon.Host.Frontend/.prettierrc create mode 100644 Epsilon.Host.Frontend/.vscode/extensions.json create mode 100644 Epsilon.Host.Frontend/Colors layers.md create mode 100644 Epsilon.Host.Frontend/README.md create mode 100644 Epsilon.Host.Frontend/aspnetcore-https.js create mode 100644 Epsilon.Host.Frontend/aspnetcore-vite.js create mode 100644 Epsilon.Host.Frontend/index.html create mode 100644 Epsilon.Host.Frontend/package-lock.json create mode 100644 Epsilon.Host.Frontend/package.json create mode 100644 Epsilon.Host.Frontend/pnpm-lock.yaml create mode 100644 Epsilon.Host.Frontend/src/App.vue create mode 100644 Epsilon.Host.Frontend/src/assets/vite.svg create mode 100644 Epsilon.Host.Frontend/src/assets/vue.svg create mode 100644 Epsilon.Host.Frontend/src/components/CompetenceGraph.vue create mode 100644 Epsilon.Host.Frontend/src/components/CompetenceProfile.vue create mode 100644 Epsilon.Host.Frontend/src/components/CompetenceProfileLegend.vue create mode 100644 Epsilon.Host.Frontend/src/components/EnrollmentTermButtons.vue create mode 100644 Epsilon.Host.Frontend/src/components/KPIMatrix.vue create mode 100644 Epsilon.Host.Frontend/src/components/PersonalDevelopmentGraph.vue create mode 100644 Epsilon.Host.Frontend/src/components/RoundLoader.vue create mode 100644 Epsilon.Host.Frontend/src/logic/Api.ts create mode 100644 Epsilon.Host.Frontend/src/logic/DecayingAverageLogic.ts create mode 100644 Epsilon.Host.Frontend/src/main.ts create mode 100644 Epsilon.Host.Frontend/src/router/index.ts create mode 100644 Epsilon.Host.Frontend/src/shimd-vue.d.ts create mode 100644 Epsilon.Host.Frontend/src/style.css create mode 100644 Epsilon.Host.Frontend/src/views/Authorize.vue create mode 100644 Epsilon.Host.Frontend/src/views/AuthorizeUser.vue create mode 100644 Epsilon.Host.Frontend/src/views/PerformanceDashboard.vue create mode 100644 Epsilon.Host.Frontend/tsconfig.json create mode 100644 Epsilon.Host.Frontend/vite.config.ts create mode 100644 Epsilon.Host.WebApi/Controllers/AuthController.cs create mode 100644 Epsilon.Host.WebApi/Controllers/ComponentController.cs create mode 100644 Epsilon.Host.WebApi/Controllers/DocumentController.cs create mode 100644 Epsilon.Host.WebApi/Epsilon.Host.WebApi.csproj create mode 100644 Epsilon.Host.WebApi/Program.cs create mode 100644 Epsilon.Host.WebApi/Properties/launchSettings.json create mode 100644 Epsilon/Component/CompetenceProfileCompetenceComponentFetcher.cs create mode 100644 Epsilon/Component/ComponentServiceCollectionExtensions.cs create mode 100644 Epsilon/Component/KpiMatrixComponentFetcher.cs create mode 100644 Epsilon/Component/PersonaPageComponentFetcher.cs delete mode 100644 Epsilon/Constants.cs delete mode 100644 Epsilon/Export/Exceptions/NoExportersFoundException.cs delete mode 100644 Epsilon/Export/ExportDataPackager.cs delete mode 100644 Epsilon/Export/ExportOptions.cs delete mode 100644 Epsilon/Export/Exporters/ConsoleModuleExporter.cs delete mode 100644 Epsilon/Export/Exporters/CsvModuleExporter.cs delete mode 100644 Epsilon/Export/Exporters/ExcelModuleExporter.cs delete mode 100644 Epsilon/Export/Exporters/WordModuleExporter.cs delete mode 100644 Epsilon/Export/ModuleExporterCollection.cs delete mode 100644 Epsilon/Extensions/CoreServiceCollectionExtensions.cs create mode 100644 Epsilon/FhictConstants.cs create mode 100644 Epsilon/Service/CompetenceComponentService.cs create mode 100644 Epsilon/Service/CompetenceDocumentService.cs create mode 100644 package-lock.json diff --git a/.editorconfig b/.editorconfig index 2b7ad954..2163fed3 100644 --- a/.editorconfig +++ b/.editorconfig @@ -435,6 +435,9 @@ dotnet_diagnostic.ca2007.severity = none # CA1848: Use the LoggerMessage delegates dotnet_diagnostic.ca1848.severity = none +# CA1826: Do not use Enumerable methods on indexable collections. Instead use the collection directly. +dotnet_diagnostic.ca1826.severity = none + # Code style errors dotnet_diagnostic.ide0001.severity = error dotnet_diagnostic.ide0002.severity = error @@ -473,7 +476,7 @@ dotnet_diagnostic.ide0041.severity = error dotnet_diagnostic.ide0042.severity = error dotnet_diagnostic.ide0044.severity = error dotnet_diagnostic.ide0045.severity = error -dotnet_diagnostic.ide0046.severity = error +dotnet_diagnostic.ide0046.severity = none dotnet_diagnostic.ide0047.severity = error dotnet_diagnostic.ide0048.severity = error dotnet_diagnostic.ide0049.severity = error diff --git a/.github/workflows/code-analysis.yml b/.github/workflows/code-analysis.yml index e45bb7b7..dd44f81c 100644 --- a/.github/workflows/code-analysis.yml +++ b/.github/workflows/code-analysis.yml @@ -2,7 +2,6 @@ name: "Code analysis" on: pull_request: - branches: [ "master", "develop" ] schedule: - cron: '22 18 * * 5' @@ -18,7 +17,7 @@ jobs: strategy: fail-fast: false matrix: - language: [ 'csharp' ] + language: [ 'csharp', 'javascript' ] steps: - name: Checkout repository diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 431cfbaa..02c1c7cf 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -2,36 +2,58 @@ on: [ pull_request ] jobs: - setup: - name: Setup + build-backend: + name: Build .NET solution runs-on: ubuntu-20.04 + steps: - uses: actions/checkout@v2 - - - name: Setup .NET - uses: actions/setup-dotnet@v1.7.2 + - uses: actions/setup-dotnet@v1.7.2 with: dotnet-version: '6.0.x' + - name: Restore dependencies + run: dotnet restore + - name: Build + run: dotnet build --no-restore - build: - name: Build - needs: [ setup ] + build-frontend: + name: Build frontend runs-on: ubuntu-20.04 + defaults: + run: + working-directory: Epsilon.Host.Frontend steps: - uses: actions/checkout@v2 - - - name: Restore dependencies - run: dotnet restore - + - uses: pnpm/action-setup@v2 + with: + version: 7 + - uses: actions/setup-node@v3 + with: + node-version: 16 + cache: 'pnpm' + cache-dependency-path: 'Epsilon.Host.Frontend/pnpm-lock.yaml' + - name: Install modules + run: pnpm install - name: Build - run: dotnet build --no-restore + run: pnpm build - test: - name: Test - needs: [ setup, build ] + lint-frontend: + name: Lint frontend runs-on: ubuntu-20.04 + defaults: + run: + working-directory: Epsilon.Host.Frontend steps: - uses: actions/checkout@v2 - - - name: Test - run: dotnet test --no-build --verbosity normal + - uses: pnpm/action-setup@v2 + with: + version: 7 + - uses: actions/setup-node@v3 + with: + node-version: 16 + cache: 'pnpm' + cache-dependency-path: 'Epsilon.Host.Frontend/pnpm-lock.yaml' + - name: Install modules + run: pnpm install + - name: Perform linting + run: pnpm lint diff --git a/.gitignore b/.gitignore index 8dc6e617..c6cb22b7 100644 --- a/.gitignore +++ b/.gitignore @@ -646,4 +646,8 @@ fabric.properties ### VisualStudio Patch ### # Additional files built by Visual Studio -# End of https://www.toptal.com/developers/gitignore/api/csharp,rider,visualstudio,dotnetcore \ No newline at end of file +# End of https://www.toptal.com/developers/gitignore/api/csharp,rider,visualstudio,dotnetcore + +appsettings.json +appsettings.*.json +!appsettings.example.json \ No newline at end of file diff --git a/Epsilon.Abstractions/Component/CompetenceComponentFetcher.cs b/Epsilon.Abstractions/Component/CompetenceComponentFetcher.cs new file mode 100644 index 00000000..0ee2a961 --- /dev/null +++ b/Epsilon.Abstractions/Component/CompetenceComponentFetcher.cs @@ -0,0 +1,8 @@ +namespace Epsilon.Abstractions.Component; + +public abstract class CompetenceComponentFetcher : ICompetenceComponentFetcher where TComponent : ICompetenceComponent +{ + public async Task FetchUnknown(DateTime startDate, DateTime endDate) => await Fetch(startDate, endDate); + + public abstract Task Fetch(DateTime startDate, DateTime endDate); +} \ No newline at end of file diff --git a/Epsilon.Abstractions/Component/CompetenceComponentNameAttribute.cs b/Epsilon.Abstractions/Component/CompetenceComponentNameAttribute.cs new file mode 100644 index 00000000..5169c5cc --- /dev/null +++ b/Epsilon.Abstractions/Component/CompetenceComponentNameAttribute.cs @@ -0,0 +1,12 @@ +namespace Epsilon.Abstractions.Component; + +[AttributeUsage(AttributeTargets.Class)] +public sealed class CompetenceComponentNameAttribute : Attribute +{ + public CompetenceComponentNameAttribute(string name) + { + Name = name; + } + + public string Name { get; } +} \ No newline at end of file diff --git a/Epsilon.Abstractions/Component/CompetenceProfile.cs b/Epsilon.Abstractions/Component/CompetenceProfile.cs new file mode 100644 index 00000000..09631de1 --- /dev/null +++ b/Epsilon.Abstractions/Component/CompetenceProfile.cs @@ -0,0 +1,34 @@ +using DocumentFormat.OpenXml.Packaging; +using DocumentFormat.OpenXml.Wordprocessing; +using Epsilon.Abstractions.Model; +using Epsilon.Canvas.Abstractions.Model; + +namespace Epsilon.Abstractions.Component; + +[CompetenceComponentName("competence_profile")] +public record CompetenceProfile( + IHboIDomain HboIDomain, + IEnumerable ProfessionalTaskOutcomes, + IEnumerable ProfessionalSkillOutcomes, + IEnumerable Terms +) : ICompetenceWordComponent +{ + public void AddToWordDocument(MainDocumentPart mainDocumentPart) + { + // TODO: This is simply an example to show the capability of the component architecture + var body = new Body(); + + foreach (var enrollmentTerm in Terms) + { + body.AppendChild( + new Paragraph( + new Run( + new Text(enrollmentTerm.Name) + ) + ) + ); + } + + mainDocumentPart.Document.AppendChild(body); + } +} \ No newline at end of file diff --git a/Epsilon.Abstractions/Component/ICompetenceComponent.cs b/Epsilon.Abstractions/Component/ICompetenceComponent.cs new file mode 100644 index 00000000..5f3da0eb --- /dev/null +++ b/Epsilon.Abstractions/Component/ICompetenceComponent.cs @@ -0,0 +1,8 @@ +namespace Epsilon.Abstractions.Component; + +#pragma warning disable CA1040 +public interface ICompetenceComponent +#pragma warning restore CA1040 +{ + +} \ No newline at end of file diff --git a/Epsilon.Abstractions/Component/ICompetenceComponentFetcher.cs b/Epsilon.Abstractions/Component/ICompetenceComponentFetcher.cs new file mode 100644 index 00000000..dde1871c --- /dev/null +++ b/Epsilon.Abstractions/Component/ICompetenceComponentFetcher.cs @@ -0,0 +1,12 @@ +namespace Epsilon.Abstractions.Component; + +public interface ICompetenceComponentFetcher +{ + public Task FetchUnknown(DateTime startDate, DateTime endDate); +} + +public interface ICompetenceComponentFetcher : ICompetenceComponentFetcher + where TComponent : ICompetenceComponent +{ + public Task Fetch(DateTime startDate, DateTime endDate); +} \ No newline at end of file diff --git a/Epsilon.Abstractions/Component/ICompetenceWordComponent.cs b/Epsilon.Abstractions/Component/ICompetenceWordComponent.cs new file mode 100644 index 00000000..29cfca03 --- /dev/null +++ b/Epsilon.Abstractions/Component/ICompetenceWordComponent.cs @@ -0,0 +1,8 @@ +using DocumentFormat.OpenXml.Packaging; + +namespace Epsilon.Abstractions.Component; + +public interface ICompetenceWordComponent : ICompetenceComponent +{ + public void AddToWordDocument(MainDocumentPart mainDocumentPart); +} \ No newline at end of file diff --git a/Epsilon.Abstractions/Component/KpiMatrixAssignment.cs b/Epsilon.Abstractions/Component/KpiMatrixAssignment.cs new file mode 100644 index 00000000..625815fa --- /dev/null +++ b/Epsilon.Abstractions/Component/KpiMatrixAssignment.cs @@ -0,0 +1,6 @@ +namespace Epsilon.Abstractions.Component; + +public record KpiMatrixAssignment( + string Name, + IEnumerable Outcomes +); \ No newline at end of file diff --git a/Epsilon.Abstractions/Component/KpiMatrixCollection.cs b/Epsilon.Abstractions/Component/KpiMatrixCollection.cs new file mode 100644 index 00000000..c58cf57a --- /dev/null +++ b/Epsilon.Abstractions/Component/KpiMatrixCollection.cs @@ -0,0 +1,196 @@ +using DocumentFormat.OpenXml; +using DocumentFormat.OpenXml.Packaging; +using DocumentFormat.OpenXml.Wordprocessing; +using Epsilon.Canvas.Abstractions.Model; + +namespace Epsilon.Abstractions.Component; + +[CompetenceComponentName("kpi_matrix")] +public record KpiMatrixCollection( + IEnumerable KpiMatrixAssignments, + IDictionary GradeStatus +) : ICompetenceWordComponent +{ + public static readonly IDictionary DefaultGradeStatus = new Dictionary + { + { + OutcomeGradeStatus.Mastered, new KpiMatrixOutcomeGradeStatus("Mastered", "44F656") + }, + { + OutcomeGradeStatus.NotMastered, new KpiMatrixOutcomeGradeStatus("Insufficient", "FA1818") + }, + { + OutcomeGradeStatus.NotGraded, new KpiMatrixOutcomeGradeStatus("Not applicable", "FAFF00") + }, + { + OutcomeGradeStatus.NotAssessed, new KpiMatrixOutcomeGradeStatus("Needs grade", "9F2B68") + }, + }; + + public void AddToWordDocument(MainDocumentPart mainDocumentPart) + { + var body = new Body(); + // Create a table, with rows for the outcomes and columns for the assignments. + var table = new Table(); + + var assignments = KpiMatrixAssignments.OrderBy(static ass => ass.Name).ToList(); + + // Set table properties for formatting. + table.AppendChild(new TableProperties( + new TableWidth + { + Width = "0", Type = TableWidthUnitValues.Auto, + })); + + // Calculate the header row height based on the longest assignment name. + var headerRowHeight = 0; + if (KpiMatrixAssignments.Any()) + { + headerRowHeight = assignments.Max(static a => a.Name.Length) * 111; + } + + // Create the table header row. + var headerRow = new TableRow(); + headerRow.AppendChild(new TableRowProperties(new TableRowHeight + { + Val = (UInt32Value)(uint)headerRowHeight, + })); + + // Empty top-left cell. + headerRow.AppendChild(CreateTableCellWithBorders("2500", new Paragraph(new Run(new Text(""))))); + + foreach (var assignment in assignments) + { + var cell = CreateTableCellWithBorders("100"); + cell.FirstChild.Append(new TextDirection + { + Val = TextDirectionValues.TopToBottomLeftToRightRotated, + }); + + cell.Append(new Paragraph(new Run(new Text(assignment.Name)))); + cell.FirstChild.Append(new Shading + { + Fill = assignments.IndexOf(assignment) % 2 == 0 + ? "FFFFFF" + : "d3d3d3", + }); + headerRow.AppendChild(cell); + } + + table.AppendChild(headerRow); + + var listOfOutcomes = new Dictionary(); + foreach (var assignment in KpiMatrixAssignments) + { + foreach (var outcome in assignment.Outcomes) + { + listOfOutcomes.TryAdd(outcome.Id, outcome); + } + } + + // Add the outcome rows. + foreach (var outcome in listOfOutcomes.OrderByDescending(static o => o.Value.Title)) + { + var row = new TableRow(); + + // Add the outcome title cell. + row.AppendChild(CreateTableCellWithBorders("2500", new Paragraph(new Run(new Text(outcome.Value.Title))))); + + // Add the assignment cells. + foreach (var assignment in assignments) + { + var outcomeAssignment = assignment.Outcomes.FirstOrDefault(o => o.Id == outcome.Key); + var cell = CreateTableCellWithBorders("100"); + + // Set cell color based on GradeStatus. + var fillColor = outcomeAssignment != null + ? outcomeAssignment.GradeStatus.Color + : assignments.IndexOf(assignment) % 2 == 0 + ? "ffffff" + : "d3d3d3"; + + cell.FirstChild?.Append(new Shading + { + Fill = fillColor, + }); + + // Add an empty text element since we're using color instead of text. + cell.Append(new Paragraph(new Run(new Text("")))); + row.AppendChild(cell); + } + + table.AppendChild(row); + } + + body.AppendChild(GetLegend()); + body.Append(new Paragraph(new Run(new Text("")))); + body.AppendChild(table); + + mainDocumentPart.Document.AppendChild(body); + } + + private OpenXmlElement GetLegend() + { + var table = new Table(); + foreach (var status in GradeStatus) + { + var row = new TableRow(); + var cellName = CreateTableCellWithBorders("200"); + cellName.Append(new Paragraph(new Run(new Text(status.Value.Status)))); + + var cellValue = CreateTableCellWithBorders("200"); + cellValue.Append(new Paragraph(new Run(new Text("")))); + cellValue.FirstChild?.Append(new Shading + { + Fill = status.Value.Color, + }); + row.AppendChild(cellName); + row.AppendChild(cellValue); + table.AppendChild(row); + } + + return table; + } + + + private static TableCell CreateTableCellWithBorders(string? width, params OpenXmlElement[] elements) + { + var cell = new TableCell(); + var cellProperties = new TableCellProperties(); + var borders = new TableCellBorders( + new LeftBorder + { + Val = BorderValues.Single, + }, + new RightBorder + { + Val = BorderValues.Single, + }, + new TopBorder + { + Val = BorderValues.Single, + }, + new BottomBorder + { + Val = BorderValues.Single, + }); + + foreach (var element in elements) + { + cell.Append(element); + } + + if (width != null) + { + cellProperties.Append(new TableCellWidth + { + Type = TableWidthUnitValues.Dxa, Width = width, + }); + } + + cellProperties.Append(borders); + cell.PrependChild(cellProperties); + + return cell; + } +} \ No newline at end of file diff --git a/Epsilon.Abstractions/Component/KpiMatrixOutcome.cs b/Epsilon.Abstractions/Component/KpiMatrixOutcome.cs new file mode 100644 index 00000000..90ed26c4 --- /dev/null +++ b/Epsilon.Abstractions/Component/KpiMatrixOutcome.cs @@ -0,0 +1,7 @@ + +namespace Epsilon.Abstractions.Component; +public record KpiMatrixOutcome( + int Id, + string Title, + KpiMatrixOutcomeGradeStatus GradeStatus +); \ No newline at end of file diff --git a/Epsilon.Abstractions/Component/KpiMatrixOutcomeGradeStatus.cs b/Epsilon.Abstractions/Component/KpiMatrixOutcomeGradeStatus.cs new file mode 100644 index 00000000..f1a47c1d --- /dev/null +++ b/Epsilon.Abstractions/Component/KpiMatrixOutcomeGradeStatus.cs @@ -0,0 +1,6 @@ +namespace Epsilon.Abstractions.Component; + +public record KpiMatrixOutcomeGradeStatus( + string Status, + string Color +); \ No newline at end of file diff --git a/Epsilon.Abstractions/Component/PersonaPage.cs b/Epsilon.Abstractions/Component/PersonaPage.cs new file mode 100644 index 00000000..a936bf6f --- /dev/null +++ b/Epsilon.Abstractions/Component/PersonaPage.cs @@ -0,0 +1,25 @@ +using System.Text; +using DocumentFormat.OpenXml.Packaging; +using DocumentFormat.OpenXml.Wordprocessing; + +namespace Epsilon.Abstractions.Component; + +[CompetenceComponentName("persona")] +public record PersonaPage(string PersonaHtml) : ICompetenceWordComponent +{ + public void AddToWordDocument(MainDocumentPart mainDocumentPart) + { + var personaHtmlBuffer = Encoding.UTF8.GetPreamble().Concat(Encoding.UTF8.GetBytes($"{PersonaHtml}")).ToArray(); + using var personaHtmlStream = new MemoryStream(personaHtmlBuffer); + + var formatImportPart = mainDocumentPart.AddAlternativeFormatImportPart(AlternativeFormatImportPartType.Html); + formatImportPart.FeedData(personaHtmlStream); + + mainDocumentPart.Document.AppendChild(new Body( + new AltChunk + { + Id = mainDocumentPart.GetIdOfPart(formatImportPart), + } + )); + } +} \ No newline at end of file diff --git a/Epsilon.Abstractions/Epsilon.Abstractions.csproj b/Epsilon.Abstractions/Epsilon.Abstractions.csproj index 1d04e691..d034d6a3 100644 --- a/Epsilon.Abstractions/Epsilon.Abstractions.csproj +++ b/Epsilon.Abstractions/Epsilon.Abstractions.csproj @@ -10,7 +10,7 @@ - + @@ -20,4 +20,7 @@ + + + diff --git a/Epsilon.Abstractions/Export/ICanvasModuleExporter.cs b/Epsilon.Abstractions/Export/ICanvasModuleExporter.cs deleted file mode 100644 index 3d619e4d..00000000 --- a/Epsilon.Abstractions/Export/ICanvasModuleExporter.cs +++ /dev/null @@ -1,7 +0,0 @@ -using Epsilon.Abstractions.Model; - -namespace Epsilon.Abstractions.Export; - -public interface ICanvasModuleExporter : IExporter -{ -} \ No newline at end of file diff --git a/Epsilon.Abstractions/Export/IExportDataPackager.cs b/Epsilon.Abstractions/Export/IExportDataPackager.cs deleted file mode 100644 index f4e0aafd..00000000 --- a/Epsilon.Abstractions/Export/IExportDataPackager.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Epsilon.Abstractions.Model; -using Epsilon.Canvas.Abstractions.Model; - -namespace Epsilon.Abstractions.Export; - -public interface IExportDataPackager -{ - public Task GetExportData(IAsyncEnumerable data); -} \ No newline at end of file diff --git a/Epsilon.Abstractions/Export/IExporter.cs b/Epsilon.Abstractions/Export/IExporter.cs deleted file mode 100644 index d36f4aea..00000000 --- a/Epsilon.Abstractions/Export/IExporter.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Epsilon.Abstractions.Export; - -public interface IExporter -{ - public IEnumerable Formats { get; } - - public string FileExtension { get; } - - Task Export(T data, string format); -} \ No newline at end of file diff --git a/Epsilon.Abstractions/Export/IModuleExporterCollection.cs b/Epsilon.Abstractions/Export/IModuleExporterCollection.cs deleted file mode 100644 index abba4749..00000000 --- a/Epsilon.Abstractions/Export/IModuleExporterCollection.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Epsilon.Abstractions.Export; - -public interface IModuleExporterCollection -{ - public IEnumerable Formats(); - - public IDictionary DetermineExporters(IEnumerable formats); -} \ No newline at end of file diff --git a/Epsilon.Abstractions/Model/Activity.cs b/Epsilon.Abstractions/Model/Activity.cs new file mode 100644 index 00000000..4b2150ed --- /dev/null +++ b/Epsilon.Abstractions/Model/Activity.cs @@ -0,0 +1,7 @@ +namespace Epsilon.Abstractions.Model; + +public record Activity( + int Id, + string Name, + string? Color = null +); \ No newline at end of file diff --git a/Epsilon.Abstractions/Model/ArchitecturalLayer.cs b/Epsilon.Abstractions/Model/ArchitecturalLayer.cs new file mode 100644 index 00000000..fec7c817 --- /dev/null +++ b/Epsilon.Abstractions/Model/ArchitecturalLayer.cs @@ -0,0 +1,8 @@ +namespace Epsilon.Abstractions.Model; + +public record ArchitectureLayer( + int Id, + string Name, + string ShortName, + string? Color = null +); \ No newline at end of file diff --git a/Epsilon.Abstractions/Model/CompetenceOutcomeResult.cs b/Epsilon.Abstractions/Model/CompetenceOutcomeResult.cs new file mode 100644 index 00000000..7d6e8cc5 --- /dev/null +++ b/Epsilon.Abstractions/Model/CompetenceOutcomeResult.cs @@ -0,0 +1,7 @@ +namespace Epsilon.Abstractions.Model; + +public record CompetenceOutcomeResult( + int OutcomeId, + double Grade, + DateTime SubmittedAt +); \ No newline at end of file diff --git a/Epsilon.Abstractions/Model/ExportData.cs b/Epsilon.Abstractions/Model/ExportData.cs deleted file mode 100644 index b19b1c83..00000000 --- a/Epsilon.Abstractions/Model/ExportData.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Epsilon.Abstractions.Model; - -public class ExportData -{ - public string PersonaHtml { get; set; } = string.Empty; - - public IEnumerable CourseModules { get; set; } = Enumerable.Empty(); -} \ No newline at end of file diff --git a/Epsilon.Abstractions/Model/HboIDomain2018.cs b/Epsilon.Abstractions/Model/HboIDomain2018.cs new file mode 100644 index 00000000..7f6d6a50 --- /dev/null +++ b/Epsilon.Abstractions/Model/HboIDomain2018.cs @@ -0,0 +1,60 @@ +namespace Epsilon.Abstractions.Model; + +public class HboIDomain2018 : IHboIDomain +{ + public static readonly ArchitectureLayer UserInteraction = new ArchitectureLayer(0, "User Interaction", "U", "#E29C53"); + public static readonly ArchitectureLayer OrganisationalProcesses = new ArchitectureLayer(1, "Organisational Processes", "O", "#D16557"); + public static readonly ArchitectureLayer Software = new ArchitectureLayer(2, "Software", "S", "#96B9C0"); + public static readonly ArchitectureLayer HardwareInterfacing = new ArchitectureLayer(3, "Hardware Interfacing", "H", "#8D9292"); + public static readonly ArchitectureLayer Infrastructure = new ArchitectureLayer(4, "Infrastructure", "I", "#6EA7D4"); + + public static readonly Activity ManageAndControl = new Activity(0, "Manage & Control"); + public static readonly Activity Analysis = new Activity(1, "Analysis"); + public static readonly Activity Advise = new Activity(2, "Advise"); + public static readonly Activity Design = new Activity(3, "Design"); + public static readonly Activity Realisation = new Activity(4, "Realisation"); + + public static readonly MasteryLevel LevelOne = new MasteryLevel(0, 1, "#8EAADB"); + public static readonly MasteryLevel LevelTwo = new MasteryLevel(1, 2, "#A8D08D"); + public static readonly MasteryLevel LevelThree = new MasteryLevel(2, 3, "#FFD965"); + public static readonly MasteryLevel LevelFour = new MasteryLevel(3, 4, "#B15EB2"); + + public static readonly ProfessionalSkill FutureOrientedOrganisation = new ProfessionalSkill(0, "Future-Oriented Organisation", "FOO"); + public static readonly ProfessionalSkill InvestigativeProblemSolving = new ProfessionalSkill(1, "Investigative Problem Solving", "IPS"); + public static readonly ProfessionalSkill PersonalLeadership = new ProfessionalSkill(2, "Personal Leadership", "PL"); + public static readonly ProfessionalSkill TargetedInteraction = new ProfessionalSkill(3, "Targeted Interaction", "TI"); + + public IEnumerable ArchitectureLayers => new[] + { + UserInteraction, + OrganisationalProcesses, + Software, + HardwareInterfacing, + Infrastructure, + }; + + public IEnumerable Activities => new[] + { + ManageAndControl, + Analysis, + Advise, + Design, + Realisation, + }; + + public IEnumerable ProfessionalSkills => new[] + { + FutureOrientedOrganisation, + InvestigativeProblemSolving, + PersonalLeadership, + TargetedInteraction, + }; + + public IEnumerable MasteryLevels => new[] + { + LevelOne, + LevelTwo, + LevelThree, + LevelFour, + }; +} \ No newline at end of file diff --git a/Epsilon.Abstractions/Model/IHboIDomain.cs b/Epsilon.Abstractions/Model/IHboIDomain.cs new file mode 100644 index 00000000..5c53a79a --- /dev/null +++ b/Epsilon.Abstractions/Model/IHboIDomain.cs @@ -0,0 +1,9 @@ +namespace Epsilon.Abstractions.Model; + +public interface IHboIDomain +{ + IEnumerable ArchitectureLayers { get; } + IEnumerable Activities { get; } + IEnumerable ProfessionalSkills { get; } + IEnumerable MasteryLevels { get; } +} \ No newline at end of file diff --git a/Epsilon.Abstractions/Model/MasteryLevel.cs b/Epsilon.Abstractions/Model/MasteryLevel.cs new file mode 100644 index 00000000..3087ec30 --- /dev/null +++ b/Epsilon.Abstractions/Model/MasteryLevel.cs @@ -0,0 +1,3 @@ +namespace Epsilon.Abstractions.Model; + +public record MasteryLevel(int Id, int Level, string? Color = null); \ No newline at end of file diff --git a/Epsilon.Abstractions/Model/ProfessionalSkill.cs b/Epsilon.Abstractions/Model/ProfessionalSkill.cs new file mode 100644 index 00000000..b1b1dded --- /dev/null +++ b/Epsilon.Abstractions/Model/ProfessionalSkill.cs @@ -0,0 +1,8 @@ +namespace Epsilon.Abstractions.Model; + +public record ProfessionalSkill( + int Id, + string Name, + string ShortName, + string? Color = null +); \ No newline at end of file diff --git a/Epsilon.Abstractions/Model/ProfessionalSkillLevel.cs b/Epsilon.Abstractions/Model/ProfessionalSkillLevel.cs new file mode 100644 index 00000000..31acfe2a --- /dev/null +++ b/Epsilon.Abstractions/Model/ProfessionalSkillLevel.cs @@ -0,0 +1,6 @@ +namespace Epsilon.Abstractions.Model; + +public record ProfessionalSkillLevel( + int Skill, + int MasteryLevel +); \ No newline at end of file diff --git a/Epsilon.Abstractions/Model/ProfessionalSkillResult.cs b/Epsilon.Abstractions/Model/ProfessionalSkillResult.cs new file mode 100644 index 00000000..505b4f3b --- /dev/null +++ b/Epsilon.Abstractions/Model/ProfessionalSkillResult.cs @@ -0,0 +1,9 @@ +namespace Epsilon.Abstractions.Model; + +public record ProfessionalSkillResult( + int OutcomeId, + int Skill, + int MasteryLevel, + double Grade, + DateTime AssessedAt +) : CompetenceOutcomeResult(OutcomeId, Grade, AssessedAt); \ No newline at end of file diff --git a/Epsilon.Abstractions/Model/ProfessionalTask.cs b/Epsilon.Abstractions/Model/ProfessionalTask.cs new file mode 100644 index 00000000..2a1cb9d4 --- /dev/null +++ b/Epsilon.Abstractions/Model/ProfessionalTask.cs @@ -0,0 +1,7 @@ +namespace Epsilon.Abstractions.Model; + +public record ProfessionalTask( + int Layer, + int Activity, + int MasteryLevel +); \ No newline at end of file diff --git a/Epsilon.Abstractions/Model/ProfessionalTaskResult.cs b/Epsilon.Abstractions/Model/ProfessionalTaskResult.cs new file mode 100644 index 00000000..a83e9c83 --- /dev/null +++ b/Epsilon.Abstractions/Model/ProfessionalTaskResult.cs @@ -0,0 +1,10 @@ +namespace Epsilon.Abstractions.Model; + +public record ProfessionalTaskResult( + int OutcomeId, + int ArchitectureLayer, + int Activity, + int MasteryLevel, + double Grade, + DateTime AssessedAt +) : CompetenceOutcomeResult(OutcomeId, Grade, AssessedAt); \ No newline at end of file diff --git a/Epsilon.Abstractions/Service/ICompetenceComponentService.cs b/Epsilon.Abstractions/Service/ICompetenceComponentService.cs new file mode 100644 index 00000000..9a8fb590 --- /dev/null +++ b/Epsilon.Abstractions/Service/ICompetenceComponentService.cs @@ -0,0 +1,14 @@ +using Epsilon.Abstractions.Component; + +namespace Epsilon.Abstractions.Service; + +public interface ICompetenceComponentService +{ + IAsyncEnumerable GetComponents(DateTime startDate, DateTime endDate); + + IAsyncEnumerable GetComponents(DateTime startDate, DateTime endDate) where TComponent : ICompetenceComponent; + + Task GetComponent(string name, DateTime startDate, DateTime endDate); + + Task GetComponent(string name, DateTime startDate, DateTime endDate) where TComponent : class, ICompetenceComponent; +} \ No newline at end of file diff --git a/Epsilon.Abstractions/Service/ICompetenceDocumentService.cs b/Epsilon.Abstractions/Service/ICompetenceDocumentService.cs new file mode 100644 index 00000000..d2bee6e3 --- /dev/null +++ b/Epsilon.Abstractions/Service/ICompetenceDocumentService.cs @@ -0,0 +1,6 @@ +namespace Epsilon.Abstractions.Service; + +public interface ICompetenceDocumentService +{ + Task WriteDocument(Stream stream, DateTime startDate, DateTime endDate); +} \ No newline at end of file diff --git a/Epsilon.Canvas.Abstractions/ICanvasModuleCollectionFetcher.cs b/Epsilon.Canvas.Abstractions/ICanvasModuleCollectionFetcher.cs deleted file mode 100644 index f10fa543..00000000 --- a/Epsilon.Canvas.Abstractions/ICanvasModuleCollectionFetcher.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Epsilon.Canvas.Abstractions.Model; - -namespace Epsilon.Canvas.Abstractions; - -public interface ICanvasModuleCollectionFetcher -{ - public IAsyncEnumerable GetAll(int courseId, IEnumerable? allowedModules); -} \ No newline at end of file diff --git a/Epsilon.Canvas.Abstractions/Model/EnrollmentTerm.cs b/Epsilon.Canvas.Abstractions/Model/EnrollmentTerm.cs new file mode 100644 index 00000000..0603f850 --- /dev/null +++ b/Epsilon.Canvas.Abstractions/Model/EnrollmentTerm.cs @@ -0,0 +1,9 @@ +using System.Text.Json.Serialization; + +namespace Epsilon.Canvas.Abstractions.Model; + +public record EnrollmentTerm( + [property: JsonPropertyName("name")] string Name, + [property: JsonPropertyName("start_at")] DateTime? StartAt, + [property: JsonPropertyName("end_at")] DateTime? EndAt +); \ No newline at end of file diff --git a/Epsilon.Canvas.Abstractions/Model/EnrollmentTermCollection.cs b/Epsilon.Canvas.Abstractions/Model/EnrollmentTermCollection.cs new file mode 100644 index 00000000..184a382f --- /dev/null +++ b/Epsilon.Canvas.Abstractions/Model/EnrollmentTermCollection.cs @@ -0,0 +1,7 @@ +using System.Text.Json.Serialization; + +namespace Epsilon.Canvas.Abstractions.Model; + +public record EnrollmentTermCollection( + [property: JsonPropertyName("enrollment_terms")] IEnumerable Terms +); \ No newline at end of file diff --git a/Epsilon.Canvas.Abstractions/Model/GraphQl/AssessmentRating.cs b/Epsilon.Canvas.Abstractions/Model/GraphQl/AssessmentRating.cs new file mode 100644 index 00000000..8d570e6a --- /dev/null +++ b/Epsilon.Canvas.Abstractions/Model/GraphQl/AssessmentRating.cs @@ -0,0 +1,11 @@ +using System.Text.Json.Serialization; + +namespace Epsilon.Canvas.Abstractions.Model.GraphQl; + +public record AssessmentRating( + [property: JsonPropertyName("criterion")] Criterion? Criterion, + [property: JsonPropertyName("points")] double? Points +) +{ + public bool IsMastery => Points >= Criterion?.MasteryPoints; +} \ No newline at end of file diff --git a/Epsilon.Canvas.Abstractions/Model/GraphQl/Assignment.cs b/Epsilon.Canvas.Abstractions/Model/GraphQl/Assignment.cs new file mode 100644 index 00000000..ebc20383 --- /dev/null +++ b/Epsilon.Canvas.Abstractions/Model/GraphQl/Assignment.cs @@ -0,0 +1,9 @@ +using System.Text.Json.Serialization; + +namespace Epsilon.Canvas.Abstractions.Model.GraphQl; + +public record Assignment( + [property: JsonPropertyName("name")] string? Name, + [property: JsonPropertyName("modules")] IEnumerable? Modules , + [property: JsonPropertyName("rubric")] Rubric? Rubric +); \ No newline at end of file diff --git a/Epsilon.Canvas.Abstractions/Model/GraphQl/CanvasGraphQlQueryResponse.cs b/Epsilon.Canvas.Abstractions/Model/GraphQl/CanvasGraphQlQueryResponse.cs new file mode 100644 index 00000000..f0318dac --- /dev/null +++ b/Epsilon.Canvas.Abstractions/Model/GraphQl/CanvasGraphQlQueryResponse.cs @@ -0,0 +1,7 @@ +using System.Text.Json.Serialization; + +namespace Epsilon.Canvas.Abstractions.Model.GraphQl; + +public record CanvasGraphQlQueryResponse( + [property: JsonPropertyName("data")] CanvasGraphQlSchema? Data +); \ No newline at end of file diff --git a/Epsilon.Canvas.Abstractions/Model/GraphQl/CanvasGraphQlSchema.cs b/Epsilon.Canvas.Abstractions/Model/GraphQl/CanvasGraphQlSchema.cs new file mode 100644 index 00000000..02d4e9fc --- /dev/null +++ b/Epsilon.Canvas.Abstractions/Model/GraphQl/CanvasGraphQlSchema.cs @@ -0,0 +1,8 @@ +using System.Text.Json.Serialization; + +namespace Epsilon.Canvas.Abstractions.Model.GraphQl; + +public record CanvasGraphQlSchema( + [property: JsonPropertyName("allCourses")] IEnumerable? Courses, + [property: JsonPropertyName("course")] Course? Course +); \ No newline at end of file diff --git a/Epsilon.Canvas.Abstractions/Model/GraphQl/Course.cs b/Epsilon.Canvas.Abstractions/Model/GraphQl/Course.cs new file mode 100644 index 00000000..ac0c6948 --- /dev/null +++ b/Epsilon.Canvas.Abstractions/Model/GraphQl/Course.cs @@ -0,0 +1,8 @@ +using System.Text.Json.Serialization; + +namespace Epsilon.Canvas.Abstractions.Model.GraphQl; + +public record Course( + [property: JsonPropertyName("name")] string? Name, + [property: JsonPropertyName("submissionsConnection")] SubmissionsConnection? SubmissionsConnection +); \ No newline at end of file diff --git a/Epsilon.Canvas.Abstractions/Model/GraphQl/Criteria.cs b/Epsilon.Canvas.Abstractions/Model/GraphQl/Criteria.cs new file mode 100644 index 00000000..728d7082 --- /dev/null +++ b/Epsilon.Canvas.Abstractions/Model/GraphQl/Criteria.cs @@ -0,0 +1,7 @@ +using System.Text.Json.Serialization; + +namespace Epsilon.Canvas.Abstractions.Model.GraphQl; + +public record Criteria( + [property: JsonPropertyName("outcome")] Outcome? Outcome +); \ No newline at end of file diff --git a/Epsilon.Canvas.Abstractions/Model/GraphQl/Criterion.cs b/Epsilon.Canvas.Abstractions/Model/GraphQl/Criterion.cs new file mode 100644 index 00000000..a8f289a5 --- /dev/null +++ b/Epsilon.Canvas.Abstractions/Model/GraphQl/Criterion.cs @@ -0,0 +1,8 @@ +using System.Text.Json.Serialization; + +namespace Epsilon.Canvas.Abstractions.Model.GraphQl; + +public record Criterion( + [property: JsonPropertyName("masteryPoints")] double? MasteryPoints, + [property: JsonPropertyName("outcome")] Outcome? Outcome +); \ No newline at end of file diff --git a/Epsilon.Canvas.Abstractions/Model/GraphQl/Module.cs b/Epsilon.Canvas.Abstractions/Model/GraphQl/Module.cs new file mode 100644 index 00000000..6964d37b --- /dev/null +++ b/Epsilon.Canvas.Abstractions/Model/GraphQl/Module.cs @@ -0,0 +1,7 @@ +using System.Text.Json.Serialization; + +namespace Epsilon.Canvas.Abstractions.Model.GraphQl; + +public record Module( + [property: JsonPropertyName("name")] string Name +); \ No newline at end of file diff --git a/Epsilon.Canvas.Abstractions/Model/GraphQl/Outcome.cs b/Epsilon.Canvas.Abstractions/Model/GraphQl/Outcome.cs new file mode 100644 index 00000000..6bdbd704 --- /dev/null +++ b/Epsilon.Canvas.Abstractions/Model/GraphQl/Outcome.cs @@ -0,0 +1,8 @@ +using System.Text.Json.Serialization; + +namespace Epsilon.Canvas.Abstractions.Model.GraphQl; + +public record Outcome( + [property: JsonPropertyName("_id")] int Id, + [property: JsonPropertyName("title")] string Title +); \ No newline at end of file diff --git a/Epsilon.Canvas.Abstractions/Model/GraphQl/Rubric.cs b/Epsilon.Canvas.Abstractions/Model/GraphQl/Rubric.cs new file mode 100644 index 00000000..c763d62b --- /dev/null +++ b/Epsilon.Canvas.Abstractions/Model/GraphQl/Rubric.cs @@ -0,0 +1,7 @@ +using System.Text.Json.Serialization; + +namespace Epsilon.Canvas.Abstractions.Model.GraphQl; + +public record Rubric( + [property: JsonPropertyName("criteria")] IEnumerable? Criteria +); \ No newline at end of file diff --git a/Epsilon.Canvas.Abstractions/Model/GraphQl/RubricAssessmentNode.cs b/Epsilon.Canvas.Abstractions/Model/GraphQl/RubricAssessmentNode.cs new file mode 100644 index 00000000..e2f0ef08 --- /dev/null +++ b/Epsilon.Canvas.Abstractions/Model/GraphQl/RubricAssessmentNode.cs @@ -0,0 +1,7 @@ +using System.Text.Json.Serialization; + +namespace Epsilon.Canvas.Abstractions.Model.GraphQl; + +public record RubricAssessmentNode( + [property: JsonPropertyName("assessmentRatings")] IReadOnlyList? AssessmentRatings +); \ No newline at end of file diff --git a/Epsilon.Canvas.Abstractions/Model/GraphQl/RubricAssessmentsConnection.cs b/Epsilon.Canvas.Abstractions/Model/GraphQl/RubricAssessmentsConnection.cs new file mode 100644 index 00000000..0c01078e --- /dev/null +++ b/Epsilon.Canvas.Abstractions/Model/GraphQl/RubricAssessmentsConnection.cs @@ -0,0 +1,7 @@ +using System.Text.Json.Serialization; + +namespace Epsilon.Canvas.Abstractions.Model.GraphQl; + +public record RubricAssessmentsConnection( + [property: JsonPropertyName("nodes")] IEnumerable? Nodes +); \ No newline at end of file diff --git a/Epsilon.Canvas.Abstractions/Model/GraphQl/SubmissionsConnection.cs b/Epsilon.Canvas.Abstractions/Model/GraphQl/SubmissionsConnection.cs new file mode 100644 index 00000000..1c1e5f90 --- /dev/null +++ b/Epsilon.Canvas.Abstractions/Model/GraphQl/SubmissionsConnection.cs @@ -0,0 +1,7 @@ +using System.Text.Json.Serialization; + +namespace Epsilon.Canvas.Abstractions.Model.GraphQl; + +public record SubmissionsConnection( + [property: JsonPropertyName("nodes")] IReadOnlyList? Nodes +); \ No newline at end of file diff --git a/Epsilon.Canvas.Abstractions/Model/GraphQl/SubmissionsConnectionNode.cs b/Epsilon.Canvas.Abstractions/Model/GraphQl/SubmissionsConnectionNode.cs new file mode 100644 index 00000000..013fdbb2 --- /dev/null +++ b/Epsilon.Canvas.Abstractions/Model/GraphQl/SubmissionsConnectionNode.cs @@ -0,0 +1,10 @@ +using System.Text.Json.Serialization; + +namespace Epsilon.Canvas.Abstractions.Model.GraphQl; + +public record SubmissionsConnectionNode( + [property: JsonPropertyName("postedAt")] DateTime? PostedAt, + [property: JsonPropertyName("assignment")] Assignment? Assignment, + [property: JsonPropertyName("submissionHistoriesConnection")] SubmissionsHistoriesConnection SubmissionsHistories, + [property: JsonPropertyName("rubricAssessmentsConnection")] RubricAssessmentsConnection RubricAssessmentsConnection +); \ No newline at end of file diff --git a/Epsilon.Canvas.Abstractions/Model/GraphQl/SubmissionsHistoriesConnection.cs b/Epsilon.Canvas.Abstractions/Model/GraphQl/SubmissionsHistoriesConnection.cs new file mode 100644 index 00000000..524f3f66 --- /dev/null +++ b/Epsilon.Canvas.Abstractions/Model/GraphQl/SubmissionsHistoriesConnection.cs @@ -0,0 +1,7 @@ +using System.Text.Json.Serialization; + +namespace Epsilon.Canvas.Abstractions.Model.GraphQl; + +public record SubmissionsHistoriesConnection( + [property: JsonPropertyName("nodes")] IReadOnlyList Nodes +); \ No newline at end of file diff --git a/Epsilon.Canvas.Abstractions/Model/GraphQl/SubmissionsHistoriesConnectionNode.cs b/Epsilon.Canvas.Abstractions/Model/GraphQl/SubmissionsHistoriesConnectionNode.cs new file mode 100644 index 00000000..bf875031 --- /dev/null +++ b/Epsilon.Canvas.Abstractions/Model/GraphQl/SubmissionsHistoriesConnectionNode.cs @@ -0,0 +1,10 @@ +using System.Text.Json.Serialization; + +namespace Epsilon.Canvas.Abstractions.Model.GraphQl; + +public record SubmissionsHistoriesConnectionNode( + [property: JsonPropertyName("attempt")] int? Attempt, + [property: JsonPropertyName("submittedAt")] DateTime? SubmittedAt, + [property: JsonPropertyName("assignment")] Assignment? Assignment, + [property: JsonPropertyName("rubricAssessmentsConnection")] RubricAssessmentsConnection? RubricAssessments +); \ No newline at end of file diff --git a/Epsilon.Canvas.Abstractions/Model/GraphQl/User.cs b/Epsilon.Canvas.Abstractions/Model/GraphQl/User.cs new file mode 100644 index 00000000..0fb0e1be --- /dev/null +++ b/Epsilon.Canvas.Abstractions/Model/GraphQl/User.cs @@ -0,0 +1,7 @@ +using System.Text.Json.Serialization; + +namespace Epsilon.Canvas.Abstractions.Model.GraphQl; + +public record User( + [property: JsonPropertyName("name")] string? Name +); \ No newline at end of file diff --git a/Epsilon.Canvas.Abstractions/Model/OutcomeGradeStatus.cs b/Epsilon.Canvas.Abstractions/Model/OutcomeGradeStatus.cs new file mode 100644 index 00000000..37c0b7aa --- /dev/null +++ b/Epsilon.Canvas.Abstractions/Model/OutcomeGradeStatus.cs @@ -0,0 +1,9 @@ +namespace Epsilon.Canvas.Abstractions.Model; + +public enum OutcomeGradeStatus +{ + Mastered, + NotMastered, + NotGraded, + NotAssessed, +} \ No newline at end of file diff --git a/Epsilon.Canvas.Abstractions/Model/OutcomeResultCollection.cs b/Epsilon.Canvas.Abstractions/Model/OutcomeResultCollection.cs index 6443f307..9cbf3ac6 100644 --- a/Epsilon.Canvas.Abstractions/Model/OutcomeResultCollection.cs +++ b/Epsilon.Canvas.Abstractions/Model/OutcomeResultCollection.cs @@ -3,6 +3,7 @@ namespace Epsilon.Canvas.Abstractions.Model; public record OutcomeResultCollection( - [property: JsonPropertyName("outcome_results")] IEnumerable OutcomeResults, + [property: JsonPropertyName("outcome_results")] + IEnumerable OutcomeResults, [property: JsonPropertyName("linked")] OutcomeResultCollectionLink? Links ); \ No newline at end of file diff --git a/Epsilon.Canvas.Abstractions/Service/IAccountHttpService.cs b/Epsilon.Canvas.Abstractions/Service/IAccountHttpService.cs new file mode 100644 index 00000000..110c880e --- /dev/null +++ b/Epsilon.Canvas.Abstractions/Service/IAccountHttpService.cs @@ -0,0 +1,8 @@ +using Epsilon.Canvas.Abstractions.Model; + +namespace Epsilon.Canvas.Abstractions.Service; + +public interface IAccountHttpService +{ + public Task?> GetAllTerms(int accountId); +} \ No newline at end of file diff --git a/Epsilon.Canvas.Abstractions/Service/IGraphQlHttpService.cs b/Epsilon.Canvas.Abstractions/Service/IGraphQlHttpService.cs new file mode 100644 index 00000000..bf5ffb95 --- /dev/null +++ b/Epsilon.Canvas.Abstractions/Service/IGraphQlHttpService.cs @@ -0,0 +1,6 @@ +namespace Epsilon.Canvas.Abstractions.Service; + +public interface IGraphQlHttpService +{ + public Task Query(string query); +} \ No newline at end of file diff --git a/Epsilon.Canvas.Tests/CanvasModuleCollectionFetcherTests.cs b/Epsilon.Canvas.Tests/CanvasModuleCollectionFetcherTests.cs deleted file mode 100644 index d569f451..00000000 --- a/Epsilon.Canvas.Tests/CanvasModuleCollectionFetcherTests.cs +++ /dev/null @@ -1,121 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text.Json; -using System.Threading.Tasks; -using Epsilon.Canvas.Abstractions.Model; -using Epsilon.Canvas.Abstractions.Service; -using Moq; -using Xunit; - -namespace Epsilon.Canvas.Tests; - -public class CanvasModuleCollectionFetcherTests -{ - [Fact] - public async Task GivenAllowedModulesAndCourseId_WhenModuleAndOutcomeServiceAreMocked_ThenReturnsExpectedModuleOutcomeResultCollection() - { - // Arrange - const int courseId = 123; - var allowedModules = new[] - { - "Module 1", - "Module 3", - }; - var outcomeServiceMock = new Mock(); - var moduleServiceMock = new Mock(); - - var expectedResults = new List - { - new ModuleOutcomeResultCollection( - new CourseModule(1, "Module 1", 3, new List - { - new ModuleItem(1, "Module 1 Item 1", ModuleItemType.Page, 1), - new ModuleItem(2, "Module 1 Item 2", ModuleItemType.Assignment, 2), - new ModuleItem(3, "Module 1 Item 3", ModuleItemType.Quiz, 3), - }), - new OutcomeResultCollection( - new List(), - new OutcomeResultCollectionLink( - new List - { - new Outcome(1, "Outcome 1", "Outcome 1 EN Short Description NL Long Description"), - new Outcome(2, "Outcome 2", "Outcome 2 EN Short Description NL Long Description"), - }, - new List()) - ) - ), - new ModuleOutcomeResultCollection( - new CourseModule(3, "Module 3", 2, new List - { - new ModuleItem(4, "Module 3 Item 1", ModuleItemType.Assignment, 4), - new ModuleItem(5, "Module 3 Item 2", ModuleItemType.Assignment, 5), - }), - new OutcomeResultCollection( - new List(), - new OutcomeResultCollectionLink( - new List - { - new Outcome(1, "Outcome 1", "Outcome 1 EN Short Description NL Long Description"), - new Outcome(2, "Outcome 2", "Outcome 2 EN Short Description NL Long Description"), - }, - new List()) - ) - ), - }; - - outcomeServiceMock - .Setup(static s => s.GetResults(It.IsAny(), It.IsAny())) - .ReturnsAsync(new OutcomeResultCollection( - new List - { - new OutcomeResult(false, 3, new OutcomeResultLink("user1", "1", "1", "2")), - new OutcomeResult(true, 4.5, new OutcomeResultLink("user2", "2", "2", "3")), - new OutcomeResult(false, null, new OutcomeResultLink("user1", "1", "1", "3")), - }, - new OutcomeResultCollectionLink( - new List - { - new Outcome(1, "Outcome 1", "Outcome 1 EN Short Description NL Long Description"), - new Outcome(2, "Outcome 2", "Outcome 2 EN Short Description NL Long Description"), - }, - new List - { - new Alignment("1", "Alignment 1", new Uri("https://alignment1.com")), - new Alignment("2", "Alignment 2", new Uri("https://alignment2.com")), - new Alignment("3", "Alignment 3", new Uri("https://alignment3.com")), - } - ) - )); - - moduleServiceMock - .Setup(static s => s.GetAll(It.IsAny(), It.IsAny())) - .ReturnsAsync(new List - { - new CourseModule(1, "Module 1", 3, new List - { - new ModuleItem(1, "Module 1 Item 1", ModuleItemType.Page, 1), - new ModuleItem(2, "Module 1 Item 2", ModuleItemType.Assignment, 2), - new ModuleItem(3, "Module 1 Item 3", ModuleItemType.Quiz, 3), - }), - new CourseModule(2, "Module 2", 0, new List()), - new CourseModule(3, "Module 3", 2, new List - { - new ModuleItem(4, "Module 3 Item 1", ModuleItemType.Assignment, 4), - new ModuleItem(5, "Module 3 Item 2", ModuleItemType.Assignment, 5), - }), - }); - - var canvasModuleCollectionFetcher = new CanvasModuleCollectionFetcher(moduleServiceMock.Object, outcomeServiceMock.Object - ); - - // Act - var result = new List(); - await foreach (var item in canvasModuleCollectionFetcher.GetAll(courseId, allowedModules)) - { - result.Add(item); - } - - // Assert - Assert.Equal(JsonSerializer.Serialize(expectedResults), JsonSerializer.Serialize(result)); - } -} \ No newline at end of file diff --git a/Epsilon.Canvas.Tests/Epsilon.Canvas.Tests.csproj b/Epsilon.Canvas.Tests/Epsilon.Canvas.Tests.csproj index d5f67744..8fa4588c 100644 --- a/Epsilon.Canvas.Tests/Epsilon.Canvas.Tests.csproj +++ b/Epsilon.Canvas.Tests/Epsilon.Canvas.Tests.csproj @@ -14,10 +14,10 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - - - - + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -25,7 +25,7 @@ - + diff --git a/Epsilon.Canvas/CanvasModuleCollectionFetcher.cs b/Epsilon.Canvas/CanvasModuleCollectionFetcher.cs deleted file mode 100644 index 045a6497..00000000 --- a/Epsilon.Canvas/CanvasModuleCollectionFetcher.cs +++ /dev/null @@ -1,62 +0,0 @@ -using System.Diagnostics; -using Epsilon.Canvas.Abstractions; -using Epsilon.Canvas.Abstractions.Model; -using Epsilon.Canvas.Abstractions.Service; - -namespace Epsilon.Canvas; - -public class CanvasModuleCollectionFetcher : ICanvasModuleCollectionFetcher -{ - private readonly IModuleHttpService _moduleService; - private readonly IOutcomeHttpService _outcomeService; - - public CanvasModuleCollectionFetcher( - IModuleHttpService moduleService, - IOutcomeHttpService outcomeService - ) - { - _moduleService = moduleService; - _outcomeService = outcomeService; - } - - public async IAsyncEnumerable GetAll( - int courseId, - IEnumerable? allowedModules - ) - { - var response = await _outcomeService.GetResults(courseId, new[] - { - "outcomes", - "alignments", - }); - var modules = await _moduleService.GetAll(courseId, new[] - { - "items", - }); - - Debug.Assert(response != null, nameof(response) + " != null"); - Debug.Assert(modules != null, nameof(modules) + " != null"); - - var allowedModulesArray = allowedModules?.ToArray(); - - foreach (var module in modules.ToArray()) - { - if (allowedModulesArray == null || !allowedModulesArray.Any() || allowedModulesArray.Contains(module.Name)) - { - Debug.Assert(module.Items != null, "module.Items != null"); - - var ids = module.Items.Select(static i => $"assignment_{i.ContentId}"); - - Debug.Assert(response.Links?.Alignments != null, "response.Links?.Alignments != null"); - - yield return new ModuleOutcomeResultCollection(module, new OutcomeResultCollection( - response.OutcomeResults.Where(r => ids.Contains(r.Link.Alignment)), - response.Links with - { - Alignments = response.Links.Alignments.Where(a => ids.Contains(a.Id)), - } - )); - } - } - } -} \ No newline at end of file diff --git a/Epsilon.Canvas/CanvasServiceCollectionExtensions.cs b/Epsilon.Canvas/CanvasServiceCollectionExtensions.cs index 31b6664c..35d7e606 100644 --- a/Epsilon.Canvas/CanvasServiceCollectionExtensions.cs +++ b/Epsilon.Canvas/CanvasServiceCollectionExtensions.cs @@ -1,5 +1,4 @@ using System.Net.Http.Headers; -using Epsilon.Canvas.Abstractions; using Epsilon.Canvas.Abstractions.Converter; using Epsilon.Canvas.Abstractions.Service; using Epsilon.Canvas.Converter; @@ -35,11 +34,11 @@ public static IServiceCollection AddCanvas(this IServiceCollection services, ICo services.AddHttpClient(CanvasHttpClient); services.AddHttpClient(CanvasHttpClient); services.AddHttpClient(CanvasHttpClient); + services.AddHttpClient(CanvasHttpClient); + services.AddHttpClient(CanvasHttpClient); services.AddScoped(); - services.AddScoped(); - return services; } } \ No newline at end of file diff --git a/Epsilon.Canvas/Epsilon.Canvas.csproj b/Epsilon.Canvas/Epsilon.Canvas.csproj index 27dc3807..1914a099 100644 --- a/Epsilon.Canvas/Epsilon.Canvas.csproj +++ b/Epsilon.Canvas/Epsilon.Canvas.csproj @@ -10,21 +10,20 @@ - - + - + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - + + + + + diff --git a/Epsilon.Abstractions/Http/HttpService.cs b/Epsilon.Canvas/Http/HttpService.cs similarity index 80% rename from Epsilon.Abstractions/Http/HttpService.cs rename to Epsilon.Canvas/Http/HttpService.cs index fc445bd1..07ef9665 100644 --- a/Epsilon.Abstractions/Http/HttpService.cs +++ b/Epsilon.Canvas/Http/HttpService.cs @@ -1,4 +1,4 @@ -namespace Epsilon.Abstractions.Http; +namespace Epsilon.Canvas.Http; public abstract class HttpService { diff --git a/Epsilon.Canvas/QueryConstants.cs b/Epsilon.Canvas/QueryConstants.cs new file mode 100644 index 00000000..e69de29b diff --git a/Epsilon.Canvas/Service/AccountHttpService.cs b/Epsilon.Canvas/Service/AccountHttpService.cs new file mode 100644 index 00000000..c568c1bb --- /dev/null +++ b/Epsilon.Canvas/Service/AccountHttpService.cs @@ -0,0 +1,23 @@ +using System.Net.Http.Json; +using Epsilon.Canvas.Abstractions.Model; +using Epsilon.Canvas.Abstractions.Service; +using Epsilon.Canvas.Http; + +namespace Epsilon.Canvas.Service; + +public class AccountHttpService : HttpService, IAccountHttpService +{ + public AccountHttpService(HttpClient client) + : base(client) + { + } + + public async Task?> GetAllTerms(int accountId) + { + using var request = new HttpRequestMessage(HttpMethod.Get, $"v1/accounts/{accountId}/terms?per_page=100"); + var response = await Client.SendAsync(request); + var collection = await response.Content.ReadFromJsonAsync(); + + return collection?.Terms; + } +} \ No newline at end of file diff --git a/Epsilon.Canvas/Service/AssignmentHttpService.cs b/Epsilon.Canvas/Service/AssignmentHttpService.cs index 9edf3843..8468c100 100644 --- a/Epsilon.Canvas/Service/AssignmentHttpService.cs +++ b/Epsilon.Canvas/Service/AssignmentHttpService.cs @@ -1,7 +1,7 @@ using System.Net.Http.Json; -using Epsilon.Abstractions.Http; using Epsilon.Canvas.Abstractions.Model; using Epsilon.Canvas.Abstractions.Service; +using Epsilon.Canvas.Http; namespace Epsilon.Canvas.Service; diff --git a/Epsilon.Canvas/Service/FileHttpService.cs b/Epsilon.Canvas/Service/FileHttpService.cs index 98cfca94..49d3c544 100644 --- a/Epsilon.Canvas/Service/FileHttpService.cs +++ b/Epsilon.Canvas/Service/FileHttpService.cs @@ -1,5 +1,5 @@ -using Epsilon.Abstractions.Http; using Epsilon.Canvas.Abstractions.Service; +using Epsilon.Canvas.Http; namespace Epsilon.Canvas.Service; diff --git a/Epsilon.Canvas/Service/GraphQlHttpService.cs b/Epsilon.Canvas/Service/GraphQlHttpService.cs new file mode 100644 index 00000000..1e791318 --- /dev/null +++ b/Epsilon.Canvas/Service/GraphQlHttpService.cs @@ -0,0 +1,30 @@ +using System.Net.Http.Json; +using Epsilon.Canvas.Abstractions.Service; +using Epsilon.Canvas.Http; + +namespace Epsilon.Canvas.Service; + +public class GraphQlHttpService : HttpService, IGraphQlHttpService +{ + public GraphQlHttpService(HttpClient client) + : base(client) + { + } + + public async Task Query(string query) + { + using var request = new HttpRequestMessage(HttpMethod.Post, "/api/graphql") + { + Content = new FormUrlEncodedContent(new Dictionary + { + { + "query", query + }, + }), + }; + + var response = await Client.SendAsync(request); + + return await response.Content.ReadFromJsonAsync(); + } +} \ No newline at end of file diff --git a/Epsilon.Canvas/Service/ModuleHttpService.cs b/Epsilon.Canvas/Service/ModuleHttpService.cs index 0e39e84e..7253ba77 100644 --- a/Epsilon.Canvas/Service/ModuleHttpService.cs +++ b/Epsilon.Canvas/Service/ModuleHttpService.cs @@ -1,8 +1,8 @@ using System.Net.Http.Json; using System.Text; -using Epsilon.Abstractions.Http; using Epsilon.Canvas.Abstractions.Model; using Epsilon.Canvas.Abstractions.Service; +using Epsilon.Canvas.Http; namespace Epsilon.Canvas.Service; diff --git a/Epsilon.Canvas/Service/OutcomeHttpService.cs b/Epsilon.Canvas/Service/OutcomeHttpService.cs index 6ca33a1a..86eef8e5 100644 --- a/Epsilon.Canvas/Service/OutcomeHttpService.cs +++ b/Epsilon.Canvas/Service/OutcomeHttpService.cs @@ -1,7 +1,7 @@ using System.Net.Http.Json; -using Epsilon.Abstractions.Http; using Epsilon.Canvas.Abstractions.Model; using Epsilon.Canvas.Abstractions.Service; +using Epsilon.Canvas.Http; namespace Epsilon.Canvas.Service; diff --git a/Epsilon.Canvas/Service/PageHttpService.cs b/Epsilon.Canvas/Service/PageHttpService.cs index df99ab98..00e2aebe 100644 --- a/Epsilon.Canvas/Service/PageHttpService.cs +++ b/Epsilon.Canvas/Service/PageHttpService.cs @@ -1,8 +1,8 @@ using System.Net; using System.Net.Http.Json; -using Epsilon.Abstractions.Http; using Epsilon.Canvas.Abstractions.Model; using Epsilon.Canvas.Abstractions.Service; +using Epsilon.Canvas.Http; namespace Epsilon.Canvas.Service; diff --git a/Epsilon.Canvas/Service/PaginatorHttpService.cs b/Epsilon.Canvas/Service/PaginatorHttpService.cs index bda57eb9..85082257 100644 --- a/Epsilon.Canvas/Service/PaginatorHttpService.cs +++ b/Epsilon.Canvas/Service/PaginatorHttpService.cs @@ -1,8 +1,8 @@ using System.Net.Http.Json; using System.Web; -using Epsilon.Abstractions.Http; using Epsilon.Canvas.Abstractions.Converter; using Epsilon.Canvas.Abstractions.Service; +using Epsilon.Canvas.Http; namespace Epsilon.Canvas.Service; diff --git a/Epsilon.Canvas/Service/SubmissionHttpService.cs b/Epsilon.Canvas/Service/SubmissionHttpService.cs index fa35f7c7..39ebf11e 100644 --- a/Epsilon.Canvas/Service/SubmissionHttpService.cs +++ b/Epsilon.Canvas/Service/SubmissionHttpService.cs @@ -1,7 +1,7 @@ using System.Text; -using Epsilon.Abstractions.Http; using Epsilon.Canvas.Abstractions.Model; using Epsilon.Canvas.Abstractions.Service; +using Epsilon.Canvas.Http; namespace Epsilon.Canvas.Service; diff --git a/Epsilon.Cli/Epsilon.Cli.csproj b/Epsilon.Cli/Epsilon.Cli.csproj deleted file mode 100644 index 9f7fc45c..00000000 --- a/Epsilon.Cli/Epsilon.Cli.csproj +++ /dev/null @@ -1,36 +0,0 @@ - - - - Exe - net6.0 - enable - enable - latest-All - true - true - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - - - - - PreserveNewest - - - - - - - - - diff --git a/Epsilon.Cli/Program.cs b/Epsilon.Cli/Program.cs deleted file mode 100644 index 603e2cdb..00000000 --- a/Epsilon.Cli/Program.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Epsilon.Cli; -using Epsilon.Extensions; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Serilog; - -IHostBuilder CreateHostBuilder(string[] args) -{ - return Host.CreateDefaultBuilder(args) - .ConfigureAppConfiguration(config => - { - config.SetBasePath(Directory.GetCurrentDirectory()); - config.AddJsonFile("appsettings.json"); - config.AddCommandLine(args); - }) - .ConfigureServices(static (context, services) => - { - Log.Logger = new LoggerConfiguration() - .ReadFrom.Configuration(context.Configuration) - .CreateLogger(); - - services.AddCore(context.Configuration); - services.AddHostedService(); - }); -} - -Log.Information("Starting up"); - -await CreateHostBuilder(args) - .UseSerilog() - .Build() - .RunAsync(); \ No newline at end of file diff --git a/Epsilon.Cli/Startup.cs b/Epsilon.Cli/Startup.cs deleted file mode 100644 index 891bb0da..00000000 --- a/Epsilon.Cli/Startup.cs +++ /dev/null @@ -1,105 +0,0 @@ -using System.ComponentModel.DataAnnotations; -using System.Diagnostics.CodeAnalysis; -using Epsilon.Abstractions.Export; -using Epsilon.Canvas; -using Epsilon.Canvas.Abstractions; -using Epsilon.Export; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; - -namespace Epsilon.Cli; - -public class Startup : IHostedService -{ - private readonly CanvasSettings _canvasSettings; - private readonly ICanvasModuleCollectionFetcher _collectionFetcher; - private readonly IModuleExporterCollection _exporterCollection; - private readonly IExportDataPackager _exporterDataCollection; - private readonly ExportOptions _exportOptions; - private readonly IHostApplicationLifetime _lifetime; - private readonly ILogger _logger; - - public Startup( - ILogger logger, - IHostApplicationLifetime lifetime, - IOptions canvasSettings, - IOptions exportSettings, - ICanvasModuleCollectionFetcher collectionFetcher, - IModuleExporterCollection exporterCollection, - IExportDataPackager exporterDataCollection - ) - { - _logger = logger; - _canvasSettings = canvasSettings.Value; - _exportOptions = exportSettings.Value; - _lifetime = lifetime; - _collectionFetcher = collectionFetcher; - _exporterCollection = exporterCollection; - _exporterDataCollection = exporterDataCollection; - } - - public Task StartAsync(CancellationToken cancellationToken) - { - _lifetime.ApplicationStarted.Register(() => Task.Run(ExecuteAsync, cancellationToken)); - - return Task.CompletedTask; - } - - public Task StopAsync(CancellationToken cancellationToken) - { - return Task.CompletedTask; - } - - private static IEnumerable Validate(object model) - { - var results = new List(); - var context = new ValidationContext(model); - - Validator.TryValidateObject(model, context, results, true); - - return results; - } - - [SuppressMessage("Performance", "CA1848: Use the LoggerMessage delegates", Justification = "https://github.com/dotnet/roslyn-analyzers/issues/6281")] - private async Task ExecuteAsync() - { - var results = Validate(_canvasSettings).ToArray(); - if (results.Any()) - { - foreach (var validationResult in results) - { - _logger.LogError("Error: {Message}", validationResult.ErrorMessage); - } - - _lifetime.StopApplication(); - return; - } - - var modules = _exportOptions.Modules?.Split(","); - _logger.LogInformation("Targeting Canvas course: {CourseId}, at {Url}", _canvasSettings.CourseId, _canvasSettings.ApiUrl); - _logger.LogInformation("Downloading results, this may take a few seconds..."); - var items = _collectionFetcher.GetAll(_canvasSettings.CourseId, modules); - var formattedItems = await _exporterDataCollection.GetExportData(items); - - var formats = _exportOptions.Formats.Split(","); - var exporters = _exporterCollection.DetermineExporters(formats).ToArray(); - - _logger.LogInformation("Attempting to use following formats: {Formats}", string.Join(", ", formats)); - - foreach (var (format, exporter) in exporters) - { - _logger.LogInformation("Exporting to {Format} using {Exporter}...", format, exporter.GetType().Name); - - var stream = await exporter.Export(formattedItems, format); - - await using var fileStream = - new FileStream($"{_exportOptions.FormattedOutputName}.{exporter.FileExtension}", FileMode.Create, FileAccess.Write); - - stream.Position = 0; // Reset position to zero to prepare for copy - await stream.CopyToAsync(fileStream); - } - - _lifetime.StopApplication(); - } -} \ No newline at end of file diff --git a/Epsilon.Cli/appsettings.example.json b/Epsilon.Cli/appsettings.example.json deleted file mode 100644 index 09bf3f2a..00000000 --- a/Epsilon.Cli/appsettings.example.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "Serilog": { - "Using": [ - "Serilog.Sinks.Console" - ], - "MinimumLevel": { - "Default": "Debug" - }, - "WriteTo": [ - { - "Name": "Console", - "Args": { - "theme": "Serilog.Sinks.SystemConsole.Themes.AnsiConsoleTheme::Sixteen, Serilog.Sinks.Console", - "outputTemplate": "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}" - } - } - ] - }, - "Canvas": { - "ApiUrl": "https://fhict.instructure.com/api/", - "CourseId": 0, - "AccessToken": "" - } -} \ No newline at end of file diff --git a/Epsilon.Host.Frontend/.eslintrc b/Epsilon.Host.Frontend/.eslintrc new file mode 100644 index 00000000..1db173d6 --- /dev/null +++ b/Epsilon.Host.Frontend/.eslintrc @@ -0,0 +1,28 @@ +{ + "root": true, + "env": { + "browser": true, + "es2021": true, + "node": true + }, + "parser": "vue-eslint-parser", + "extends": [ + "plugin:vue/vue3-recommended", + "eslint:recommended", + "@vue/typescript/recommended", + "prettier" + ], + "parserOptions": { + "ecmaVersion": 2021 + }, + "plugins": [ + "@typescript-eslint", + "prettier" + ], + "rules": { + "prettier/prettier": "error", + "@typescript-eslint/no-unused-vars": "error", + "@typescript-eslint/explicit-function-return-type": "error", + "@typescript-eslint/explicit-module-boundary-types": "error" + } +} diff --git a/Epsilon.Host.Frontend/.gitignore b/Epsilon.Host.Frontend/.gitignore new file mode 100644 index 00000000..a547bf36 --- /dev/null +++ b/Epsilon.Host.Frontend/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/Epsilon.Host.Frontend/.prettierrc b/Epsilon.Host.Frontend/.prettierrc new file mode 100644 index 00000000..adaa8871 --- /dev/null +++ b/Epsilon.Host.Frontend/.prettierrc @@ -0,0 +1,7 @@ +{ + "trailingComma": "es5", + "tabWidth": 4, + "semi": false, + "singleQuote": false, + "bracketSameLine": true +} diff --git a/Epsilon.Host.Frontend/.vscode/extensions.json b/Epsilon.Host.Frontend/.vscode/extensions.json new file mode 100644 index 00000000..c0a6e5a4 --- /dev/null +++ b/Epsilon.Host.Frontend/.vscode/extensions.json @@ -0,0 +1,3 @@ +{ + "recommendations": ["Vue.volar", "Vue.vscode-typescript-vue-plugin"] +} diff --git a/Epsilon.Host.Frontend/Colors layers.md b/Epsilon.Host.Frontend/Colors layers.md new file mode 100644 index 00000000..82713869 --- /dev/null +++ b/Epsilon.Host.Frontend/Colors layers.md @@ -0,0 +1,26 @@ +# Architecture Layers + +| Name | Color | +|--------------------------|---------| +| User interaction | #E29C53 | +| Infrastructure | #6EA7D4 | +| Organisational processes | #D16557 | +| Software | #96B9C0 | +| Hardware interfacing | #8D9292 | + +# Activities +| Name | Color | +|------------------|-------| +| Analyse | | +| Advise | | +| Design | | +| Realise | | +| Manage & Control | | + +# Mastery Levels +| Name | Color | +|------|---------| +| 1 | #8EAADB | +| 2 | #A8D08D | +| 3 | #FFD965 | +| 4 | #B15EB2 | diff --git a/Epsilon.Host.Frontend/README.md b/Epsilon.Host.Frontend/README.md new file mode 100644 index 00000000..96fea7ee --- /dev/null +++ b/Epsilon.Host.Frontend/README.md @@ -0,0 +1,11 @@ +# Getting started + +1. Install [PNPM](https://pnpm.io/) +1. Run `pnpm install` in the `\Epsilon.Host.Frontend` directory +2. Run `pnpm prestart`, to install SSL certificates for development +3. Run `pnpm dev`, to start the project + +## Regenerate API structure + +1. Run `pnpm modelGeneration` +2. Make sure the base url is correct for development or production. diff --git a/Epsilon.Host.Frontend/aspnetcore-https.js b/Epsilon.Host.Frontend/aspnetcore-https.js new file mode 100644 index 00000000..3bd01709 --- /dev/null +++ b/Epsilon.Host.Frontend/aspnetcore-https.js @@ -0,0 +1,33 @@ +// This script sets up HTTPS for the application using the ASP.NET Core HTTPS certificate +import fs from "fs"; +import {spawn} from "child_process"; +import path from "path"; + +const baseFolder = + process.env.APPDATA !== undefined && process.env.APPDATA !== '' + ? `${process.env.APPDATA}/ASP.NET/https` + : `${process.env.HOME}/.aspnet/https`; + +const certificateArg = process.argv.map(arg => arg.match(/--name=(?.+)/i)).filter(Boolean)[0]; +const certificateName = certificateArg ? certificateArg.groups.value : process.env.npm_package_name; + +if (!certificateName) { + console.error('Invalid certificate name. Run this script in the context of an npm/yarn script or pass --name=<> explicitly.') + process.exit(-1); +} + +const certFilePath = path.join(baseFolder, `${certificateName}.pem`); +const keyFilePath = path.join(baseFolder, `${certificateName}.key`); + +if (!fs.existsSync(certFilePath) || !fs.existsSync(keyFilePath)) { + spawn('dotnet', [ + 'dev-certs', + 'https', + '--export-path', + certFilePath, + '--format', + 'Pem', + '--no-password', + ], {stdio: 'inherit',}) + .on('exit', (code) => process.exit(code)); +} diff --git a/Epsilon.Host.Frontend/aspnetcore-vite.js b/Epsilon.Host.Frontend/aspnetcore-vite.js new file mode 100644 index 00000000..7ef10db9 --- /dev/null +++ b/Epsilon.Host.Frontend/aspnetcore-vite.js @@ -0,0 +1,54 @@ +// This script configures the .env.development.local file with additional environment variables to configure HTTPS using the ASP.NET Core +// development certificate in the webpack development proxy. +import fs from "fs"; +import path from "path"; + +const baseFolder = + process.env.APPDATA !== undefined && process.env.APPDATA !== '' + ? `${process.env.APPDATA}/ASP.NET/https` + : `${process.env.HOME}/.aspnet/https`; + +const certificateArg = process.argv.map(arg => arg.match(/--name=(?.+)/i)).filter(Boolean)[0]; +const certificateName = certificateArg ? certificateArg.groups.value : process.env.npm_package_name; + +if (!certificateName) { + console.error('Invalid certificate name. Run this script in the context of an npm/yarn script or pass --name=<> explicitly.') + process.exit(-1); +} + +const certFilePath = path.join(baseFolder, `${certificateName}.pem`); +const keyFilePath = path.join(baseFolder, `${certificateName}.key`); + +if (!fs.existsSync('.env.development.local')) { + fs.writeFileSync( + '.env.development.local', + `VITE_SSL_CRT_FILE=${certFilePath} +VITE_SSL_KEY_FILE=${keyFilePath}` + ); +} else { + let lines = fs.readFileSync('.env.development.local') + .toString() + .split('\n'); + + let hasCert, hasCertKey = false; + for (const line of lines) { + if (/VITE_SSL_CRT_FILE=.*/i.test(line)) { + hasCert = true; + } + if (/VITE_SSL_KEY_FILE=.*/i.test(line)) { + hasCertKey = true; + } + } + if (!hasCert) { + fs.appendFileSync( + '.env.development.local', + `\nVITE_SSL_CRT_FILE=${certFilePath}` + ); + } + if (!hasCertKey) { + fs.appendFileSync( + '.env.development.local', + `\nVITE_SSL_KEY_FILE=${keyFilePath}` + ); + } +} diff --git a/Epsilon.Host.Frontend/index.html b/Epsilon.Host.Frontend/index.html new file mode 100644 index 00000000..760fbbe5 --- /dev/null +++ b/Epsilon.Host.Frontend/index.html @@ -0,0 +1,13 @@ + + + + + + + Vite + Vue + + +
+ + + diff --git a/Epsilon.Host.Frontend/package-lock.json b/Epsilon.Host.Frontend/package-lock.json new file mode 100644 index 00000000..5a8b5880 --- /dev/null +++ b/Epsilon.Host.Frontend/package-lock.json @@ -0,0 +1,2810 @@ +{ + "name": "learningtool.webapp", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "learningtool.webapp", + "version": "0.0.0", + "dependencies": { + "apexcharts": "^3.37.3", + "typescript": "^4.9.5", + "vue": "^3.2.45", + "vue-router": "^4.1.6", + "vue3-apexcharts": "^1.4.1" + }, + "devDependencies": { + "@types/node": "^18.15.3", + "@typescript-eslint/eslint-plugin": "^5.55.0", + "@typescript-eslint/parser": "^5.55.0", + "@vitejs/plugin-vue": "^4.0.0", + "@vue/eslint-config-typescript": "^11.0.2", + "eslint": "^8.36.0", + "eslint-plugin-vue": "^9.9.0", + "ts-node": "^10.9.1", + "vite": "^4.1.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.4.tgz", + "integrity": "sha512-alVJj7k7zIxqBZ7BTRhz0IqJFxW1VJbm6N8JbcYhQ186df9ZBPbZBmWSqAMXwHGsCJdYks7z/voa3ibiS5bCIw==", + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "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, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.15.tgz", + "integrity": "sha512-sRSOVlLawAktpMvDyJIkdLI/c/kdRTOqo8t6ImVxg8yT7LQDUYV5Rp2FKeEosLr6ZCja9UjYAzyRSxGteSJPYg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.15.tgz", + "integrity": "sha512-0kOB6Y7Br3KDVgHeg8PRcvfLkq+AccreK///B4Z6fNZGr/tNHX0z2VywCc7PTeWp+bPvjA5WMvNXltHw5QjAIA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.15.tgz", + "integrity": "sha512-MzDqnNajQZ63YkaUWVl9uuhcWyEyh69HGpMIrf+acR4otMkfLJ4sUCxqwbCyPGicE9dVlrysI3lMcDBjGiBBcQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.15.tgz", + "integrity": "sha512-7siLjBc88Z4+6qkMDxPT2juf2e8SJxmsbNVKFY2ifWCDT72v5YJz9arlvBw5oB4W/e61H1+HDB/jnu8nNg0rLA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.15.tgz", + "integrity": "sha512-NbImBas2rXwYI52BOKTW342Tm3LTeVlaOQ4QPZ7XuWNKiO226DisFk/RyPk3T0CKZkKMuU69yOvlapJEmax7cg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.15.tgz", + "integrity": "sha512-Xk9xMDjBVG6CfgoqlVczHAdJnCs0/oeFOspFap5NkYAmRCT2qTn1vJWA2f419iMtsHSLm+O8B6SLV/HlY5cYKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.15.tgz", + "integrity": "sha512-3TWAnnEOdclvb2pnfsTWtdwthPfOz7qAfcwDLcfZyGJwm1SRZIMOeB5FODVhnM93mFSPsHB9b/PmxNNbSnd0RQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.15.tgz", + "integrity": "sha512-MLTgiXWEMAMr8nmS9Gigx43zPRmEfeBfGCwxFQEMgJ5MC53QKajaclW6XDPjwJvhbebv+RzK05TQjvH3/aM4Xw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.15.tgz", + "integrity": "sha512-T0MVnYw9KT6b83/SqyznTs/3Jg2ODWrZfNccg11XjDehIved2oQfrX/wVuev9N936BpMRaTR9I1J0tdGgUgpJA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.15.tgz", + "integrity": "sha512-wp02sHs015T23zsQtU4Cj57WiteiuASHlD7rXjKUyAGYzlOKDAjqK6bk5dMi2QEl/KVOcsjwL36kD+WW7vJt8Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.15.tgz", + "integrity": "sha512-k7FsUJjGGSxwnBmMh8d7IbObWu+sF/qbwc+xKZkBe/lTAF16RqxRCnNHA7QTd3oS2AfGBAnHlXL67shV5bBThQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.15.tgz", + "integrity": "sha512-ZLWk6czDdog+Q9kE/Jfbilu24vEe/iW/Sj2d8EVsmiixQ1rM2RKH2n36qfxK4e8tVcaXkvuV3mU5zTZviE+NVQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.15.tgz", + "integrity": "sha512-mY6dPkIRAiFHRsGfOYZC8Q9rmr8vOBZBme0/j15zFUKM99d4ILY4WpOC7i/LqoY+RE7KaMaSfvY8CqjJtuO4xg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.15.tgz", + "integrity": "sha512-EcyUtxffdDtWjjwIH8sKzpDRLcVtqANooMNASO59y+xmqqRYBBM7xVLQhqF7nksIbm2yHABptoioS9RAbVMWVA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.15.tgz", + "integrity": "sha512-BuS6Jx/ezxFuHxgsfvz7T4g4YlVrmCmg7UAwboeyNNg0OzNzKsIZXpr3Sb/ZREDXWgt48RO4UQRDBxJN3B9Rbg==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.15.tgz", + "integrity": "sha512-JsdS0EgEViwuKsw5tiJQo9UdQdUJYuB+Mf6HxtJSPN35vez1hlrNb1KajvKWF5Sa35j17+rW1ECEO9iNrIXbNg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.15.tgz", + "integrity": "sha512-R6fKjtUysYGym6uXf6qyNephVUQAGtf3n2RCsOST/neIwPqRWcnc3ogcielOd6pT+J0RDR1RGcy0ZY7d3uHVLA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.15.tgz", + "integrity": "sha512-mVD4PGc26b8PI60QaPUltYKeSX0wxuy0AltC+WCTFwvKCq2+OgLP4+fFd+hZXzO2xW1HPKcytZBdjqL6FQFa7w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.15.tgz", + "integrity": "sha512-U6tYPovOkw3459t2CBwGcFYfFRjivcJJc1WC8Q3funIwX8x4fP+R6xL/QuTPNGOblbq/EUDxj9GU+dWKX0oWlQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.15.tgz", + "integrity": "sha512-W+Z5F++wgKAleDABemiyXVnzXgvRFs+GVKThSI+mGgleLWluv0D7Diz4oQpgdpNzh4i2nNDzQtWbjJiqutRp6Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.15.tgz", + "integrity": "sha512-Muz/+uGgheShKGqSVS1KsHtCyEzcdOn/W/Xbh6H91Etm+wiIfwZaBn1W58MeGtfI8WA961YMHFYTthBdQs4t+w==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.15.tgz", + "integrity": "sha512-DjDa9ywLUUmjhV2Y9wUTIF+1XsmuFGvZoCmOWkli1XcNAh5t25cc7fgsCx4Zi/Uurep3TTLyDiKATgGEg61pkA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.0.tgz", + "integrity": "sha512-vITaYzIcNmjn5tF5uxcZ/ft7/RXGrMUIS9HalWckEOF6ESiwXKoMzAQf2UW0aVd6rnOeExTJVd5hmWXucBKGXQ==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.2.tgz", + "integrity": "sha512-3W4f5tDUra+pA+FzgugqL2pRimUTDJWKr7BINqOpkZrC0uYI0NIc0/JFgBROCU07HR6GieA5m3/rsPIhDmCXTQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.5.1", + "globals": "^13.19.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": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/js": { + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.38.0.tgz", + "integrity": "sha512-IoD2MfUnOV58ghIHCiil01PcohxjbYR/qCxsoC+xNgUwh1EY8jOOrYmu3d3a71+tJJ23uscEV4X2HJWMsPJu4g==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", + "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "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, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "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, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "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, + "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, + "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, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "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 + }, + "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 + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", + "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", + "dev": true + }, + "node_modules/@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, + "node_modules/@types/node": { + "version": "18.15.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.11.tgz", + "integrity": "sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q==", + "dev": true + }, + "node_modules/@types/semver": { + "version": "7.3.13", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", + "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", + "dev": true + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "5.57.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.57.1.tgz", + "integrity": "sha512-1MeobQkQ9tztuleT3v72XmY0XuKXVXusAhryoLuU5YZ+mXoYKZP9SQ7Flulh1NX4DTjpGTc2b/eMu4u7M7dhnQ==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.4.0", + "@typescript-eslint/scope-manager": "5.57.1", + "@typescript-eslint/type-utils": "5.57.1", + "@typescript-eslint/utils": "5.57.1", + "debug": "^4.3.4", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "5.57.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.57.1.tgz", + "integrity": "sha512-hlA0BLeVSA/wBPKdPGxoVr9Pp6GutGoY380FEhbVi0Ph4WNe8kLvqIRx76RSQt1lynZKfrXKs0/XeEk4zZycuA==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.57.1", + "@typescript-eslint/types": "5.57.1", + "@typescript-eslint/typescript-estree": "5.57.1", + "debug": "^4.3.4" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.57.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.57.1.tgz", + "integrity": "sha512-N/RrBwEUKMIYxSKl0oDK5sFVHd6VI7p9K5MyUlVYAY6dyNb/wHUqndkTd3XhpGlXgnQsBkRZuu4f9kAHghvgPw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.57.1", + "@typescript-eslint/visitor-keys": "5.57.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "5.57.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.57.1.tgz", + "integrity": "sha512-/RIPQyx60Pt6ga86hKXesXkJ2WOS4UemFrmmq/7eOyiYjYv/MUSHPlkhU6k9T9W1ytnTJueqASW+wOmW4KrViw==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "5.57.1", + "@typescript-eslint/utils": "5.57.1", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "5.57.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.57.1.tgz", + "integrity": "sha512-bSs4LOgyV3bJ08F5RDqO2KXqg3WAdwHCu06zOqcQ6vqbTJizyBhuh1o1ImC69X4bV2g1OJxbH71PJqiO7Y1RuA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "5.57.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.57.1.tgz", + "integrity": "sha512-A2MZqD8gNT0qHKbk2wRspg7cHbCDCk2tcqt6ScCFLr5Ru8cn+TCfM786DjPhqwseiS+PrYwcXht5ztpEQ6TFTw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.57.1", + "@typescript-eslint/visitor-keys": "5.57.1", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "5.57.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.57.1.tgz", + "integrity": "sha512-kN6vzzf9NkEtawECqze6v99LtmDiUJCVpvieTFA1uL7/jDghiJGubGZ5csicYHU1Xoqb3oH/R5cN5df6W41Nfg==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.57.1", + "@typescript-eslint/types": "5.57.1", + "@typescript-eslint/typescript-estree": "5.57.1", + "eslint-scope": "^5.1.1", + "semver": "^7.3.7" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.57.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.57.1.tgz", + "integrity": "sha512-RjQrAniDU0CEk5r7iphkm731zKlFiUjvcBS2yHAg8WWqFMCaCrD0rKEVOMUyMMcbGPZ0bPp56srkGWrgfZqLRA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.57.1", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@vitejs/plugin-vue": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-4.1.0.tgz", + "integrity": "sha512-++9JOAFdcXI3lyer9UKUV4rfoQ3T1RN8yDqoCLar86s0xQct5yblxAE+yWgRnU5/0FOlVCpTZpYSBV/bGWrSrQ==", + "dev": true, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.0.0", + "vue": "^3.2.25" + } + }, + "node_modules/@vue/compiler-core": { + "version": "3.2.47", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.47.tgz", + "integrity": "sha512-p4D7FDnQb7+YJmO2iPEv0SQNeNzcbHdGByJDsT4lynf63AFkOTFN07HsiRSvjGo0QrxR/o3d0hUyNCUnBU2Tig==", + "dependencies": { + "@babel/parser": "^7.16.4", + "@vue/shared": "3.2.47", + "estree-walker": "^2.0.2", + "source-map": "^0.6.1" + } + }, + "node_modules/@vue/compiler-dom": { + "version": "3.2.47", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.47.tgz", + "integrity": "sha512-dBBnEHEPoftUiS03a4ggEig74J2YBZ2UIeyfpcRM2tavgMWo4bsEfgCGsu+uJIL/vax9S+JztH8NmQerUo7shQ==", + "dependencies": { + "@vue/compiler-core": "3.2.47", + "@vue/shared": "3.2.47" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.2.47", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.47.tgz", + "integrity": "sha512-rog05W+2IFfxjMcFw10tM9+f7i/+FFpZJJ5XHX72NP9eC2uRD+42M3pYcQqDXVYoj74kHMSEdQ/WmCjt8JFksQ==", + "dependencies": { + "@babel/parser": "^7.16.4", + "@vue/compiler-core": "3.2.47", + "@vue/compiler-dom": "3.2.47", + "@vue/compiler-ssr": "3.2.47", + "@vue/reactivity-transform": "3.2.47", + "@vue/shared": "3.2.47", + "estree-walker": "^2.0.2", + "magic-string": "^0.25.7", + "postcss": "^8.1.10", + "source-map": "^0.6.1" + } + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.2.47", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.47.tgz", + "integrity": "sha512-wVXC+gszhulcMD8wpxMsqSOpvDZ6xKXSVWkf50Guf/S+28hTAXPDYRTbLQ3EDkOP5Xz/+SY37YiwDquKbJOgZw==", + "dependencies": { + "@vue/compiler-dom": "3.2.47", + "@vue/shared": "3.2.47" + } + }, + "node_modules/@vue/devtools-api": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.5.0.tgz", + "integrity": "sha512-o9KfBeaBmCKl10usN4crU53fYtC1r7jJwdGKjPT24t348rHxgfpZ0xL3Xm/gLUYnc0oTp8LAmrxOeLyu6tbk2Q==" + }, + "node_modules/@vue/eslint-config-typescript": { + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/@vue/eslint-config-typescript/-/eslint-config-typescript-11.0.2.tgz", + "integrity": "sha512-EiKud1NqlWmSapBFkeSrE994qpKx7/27uCGnhdqzllYDpQZroyX/O6bwjEpeuyKamvLbsGdO6PMR2faIf+zFnw==", + "dev": true, + "dependencies": { + "@typescript-eslint/eslint-plugin": "^5.0.0", + "@typescript-eslint/parser": "^5.0.0", + "vue-eslint-parser": "^9.0.0" + }, + "engines": { + "node": "^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.2.0 || ^7.0.0 || ^8.0.0", + "eslint-plugin-vue": "^9.0.0", + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@vue/reactivity": { + "version": "3.2.47", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.2.47.tgz", + "integrity": "sha512-7khqQ/75oyyg+N/e+iwV6lpy1f5wq759NdlS1fpAhFXa8VeAIKGgk2E/C4VF59lx5b+Ezs5fpp/5WsRYXQiKxQ==", + "dependencies": { + "@vue/shared": "3.2.47" + } + }, + "node_modules/@vue/reactivity-transform": { + "version": "3.2.47", + "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.2.47.tgz", + "integrity": "sha512-m8lGXw8rdnPVVIdIFhf0LeQ/ixyHkH5plYuS83yop5n7ggVJU+z5v0zecwEnX7fa7HNLBhh2qngJJkxpwEEmYA==", + "dependencies": { + "@babel/parser": "^7.16.4", + "@vue/compiler-core": "3.2.47", + "@vue/shared": "3.2.47", + "estree-walker": "^2.0.2", + "magic-string": "^0.25.7" + } + }, + "node_modules/@vue/runtime-core": { + "version": "3.2.47", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.2.47.tgz", + "integrity": "sha512-RZxbLQIRB/K0ev0K9FXhNbBzT32H9iRtYbaXb0ZIz2usLms/D55dJR2t6cIEUn6vyhS3ALNvNthI+Q95C+NOpA==", + "dependencies": { + "@vue/reactivity": "3.2.47", + "@vue/shared": "3.2.47" + } + }, + "node_modules/@vue/runtime-dom": { + "version": "3.2.47", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.2.47.tgz", + "integrity": "sha512-ArXrFTjS6TsDei4qwNvgrdmHtD930KgSKGhS5M+j8QxXrDJYLqYw4RRcDy1bz1m1wMmb6j+zGLifdVHtkXA7gA==", + "dependencies": { + "@vue/runtime-core": "3.2.47", + "@vue/shared": "3.2.47", + "csstype": "^2.6.8" + } + }, + "node_modules/@vue/server-renderer": { + "version": "3.2.47", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.2.47.tgz", + "integrity": "sha512-dN9gc1i8EvmP9RCzvneONXsKfBRgqFeFZLurmHOveL7oH6HiFXJw5OGu294n1nHc/HMgTy6LulU/tv5/A7f/LA==", + "dependencies": { + "@vue/compiler-ssr": "3.2.47", + "@vue/shared": "3.2.47" + }, + "peerDependencies": { + "vue": "3.2.47" + } + }, + "node_modules/@vue/shared": { + "version": "3.2.47", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.47.tgz", + "integrity": "sha512-BHGyyGN3Q97EZx0taMQ+OLNuZcW3d37ZEVmEAyeoA9ERdGvm9Irc/0Fua8SNyOtV1w6BS4q25wbMzJujO9HIfQ==" + }, + "node_modules/acorn": { + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", + "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "dev": true, + "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, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "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/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, + "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==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/apexcharts": { + "version": "3.37.3", + "resolved": "https://registry.npmjs.org/apexcharts/-/apexcharts-3.37.3.tgz", + "integrity": "sha512-+rnUui9uC3Mvh9qbQxUfqBnuJ0nAJOYTp+yKnA5bVmmndKXj5X/Q+OVIxkq0Jr5ysiK200Dsg1Tuz/OUG+DEpw==", + "dependencies": { + "svg.draggable.js": "^2.2.2", + "svg.easing.js": "^2.0.0", + "svg.filter.js": "^2.0.2", + "svg.pathmorphing.js": "^0.1.3", + "svg.resize.js": "^1.4.3", + "svg.select.js": "^3.0.1" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true + }, + "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, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "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, + "engines": { + "node": ">=6" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "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/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "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==", + "dev": true + }, + "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 + }, + "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 + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/csstype": { + "version": "2.6.21", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.21.tgz", + "integrity": "sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==" + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "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 + }, + "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, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/esbuild": { + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.15.tgz", + "integrity": "sha512-LBUV2VsUIc/iD9ME75qhT4aJj0r75abCVS0jakhFzOtR7TQsqQA5w0tZ+KTKnwl3kXE0MhskNdHDh/I5aCR1Zw==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.17.15", + "@esbuild/android-arm64": "0.17.15", + "@esbuild/android-x64": "0.17.15", + "@esbuild/darwin-arm64": "0.17.15", + "@esbuild/darwin-x64": "0.17.15", + "@esbuild/freebsd-arm64": "0.17.15", + "@esbuild/freebsd-x64": "0.17.15", + "@esbuild/linux-arm": "0.17.15", + "@esbuild/linux-arm64": "0.17.15", + "@esbuild/linux-ia32": "0.17.15", + "@esbuild/linux-loong64": "0.17.15", + "@esbuild/linux-mips64el": "0.17.15", + "@esbuild/linux-ppc64": "0.17.15", + "@esbuild/linux-riscv64": "0.17.15", + "@esbuild/linux-s390x": "0.17.15", + "@esbuild/linux-x64": "0.17.15", + "@esbuild/netbsd-x64": "0.17.15", + "@esbuild/openbsd-x64": "0.17.15", + "@esbuild/sunos-x64": "0.17.15", + "@esbuild/win32-arm64": "0.17.15", + "@esbuild/win32-ia32": "0.17.15", + "@esbuild/win32-x64": "0.17.15" + } + }, + "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, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.38.0.tgz", + "integrity": "sha512-pIdsD2jwlUGf/U38Jv97t8lq6HpaU/G9NKbYmpWpZGw3LdTNhZLbJePqxOXGB5+JEKfOPU/XLxYxFh03nr1KTg==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.4.0", + "@eslint/eslintrc": "^2.0.2", + "@eslint/js": "8.38.0", + "@humanwhocodes/config-array": "^0.11.8", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-visitor-keys": "^3.4.0", + "espree": "^9.5.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-sdsl": "^4.1.4", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-plugin-vue": { + "version": "9.10.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.10.0.tgz", + "integrity": "sha512-2MgP31OBf8YilUvtakdVMc8xVbcMp7z7/iQj8LHVpXrSXHPXSJRUIGSPFI6b6pyCx/buKaFJ45ycqfHvQRiW2g==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.3.0", + "natural-compare": "^1.4.0", + "nth-check": "^2.0.1", + "postcss-selector-parser": "^6.0.9", + "semver": "^7.3.5", + "vue-eslint-parser": "^9.0.1", + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.2.0 || ^7.0.0 || ^8.0.0" + } + }, + "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, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz", + "integrity": "sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/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, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/espree": { + "version": "9.5.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.1.tgz", + "integrity": "sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg==", + "dev": true, + "dependencies": { + "acorn": "^8.8.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/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, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/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, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" + }, + "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, + "engines": { + "node": ">=0.10.0" + } + }, + "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 + }, + "node_modules/fast-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "dev": true, + "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-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "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 + }, + "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 + }, + "node_modules/fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "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, + "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": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, + "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 + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "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/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, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "dev": true + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true, + "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, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "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, + "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==", + "dev": true, + "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==", + "dev": true + }, + "node_modules/is-core-module": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "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, + "engines": { + "node": ">=0.10.0" + } + }, + "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, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/js-sdsl": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.4.0.tgz", + "integrity": "sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/js-sdsl" + } + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "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 + }, + "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 + }, + "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, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "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, + "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==", + "dev": true + }, + "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 + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/magic-string": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", + "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", + "dependencies": { + "sourcemap-codec": "^1.4.8" + } + }, + "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 + }, + "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, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "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, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/nanoid": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", + "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", + "dev": true + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "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, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "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.3" + }, + "engines": { + "node": ">= 0.8.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, + "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, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "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, + "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, + "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, + "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 + }, + "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, + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.4.21", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz", + "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + } + ], + "dependencies": { + "nanoid": "^3.3.4", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.11", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz", + "integrity": "sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "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, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "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" + } + ] + }, + "node_modules/resolve": { + "version": "1.22.2", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", + "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", + "dev": true, + "dependencies": { + "is-core-module": "^2.11.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-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, + "engines": { + "node": ">=4" + } + }, + "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, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rollup": { + "version": "3.20.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.20.2.tgz", + "integrity": "sha512-3zwkBQl7Ai7MFYQE0y1MeQ15+9jsi7XxfrqwTb/9EK8D9C9+//EBR4M+CuA1KODRaNbFez/lWxA5vhEGZp4MUg==", + "dev": true, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=14.18.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "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" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "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, + "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, + "engines": { + "node": ">=8" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "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==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "deprecated": "Please use @jridgewell/sourcemap-codec instead" + }, + "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, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "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, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "dev": true, + "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, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/svg.draggable.js": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/svg.draggable.js/-/svg.draggable.js-2.2.2.tgz", + "integrity": "sha512-JzNHBc2fLQMzYCZ90KZHN2ohXL0BQJGQimK1kGk6AvSeibuKcIdDX9Kr0dT9+UJ5O8nYA0RB839Lhvk4CY4MZw==", + "dependencies": { + "svg.js": "^2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/svg.easing.js": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/svg.easing.js/-/svg.easing.js-2.0.0.tgz", + "integrity": "sha512-//ctPdJMGy22YoYGV+3HEfHbm6/69LJUTAqI2/5qBvaNHZ9uUFVC82B0Pl299HzgH13rKrBgi4+XyXXyVWWthA==", + "dependencies": { + "svg.js": ">=2.3.x" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/svg.filter.js": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/svg.filter.js/-/svg.filter.js-2.0.2.tgz", + "integrity": "sha512-xkGBwU+dKBzqg5PtilaTb0EYPqPfJ9Q6saVldX+5vCRy31P6TlRCP3U9NxH3HEufkKkpNgdTLBJnmhDHeTqAkw==", + "dependencies": { + "svg.js": "^2.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/svg.js": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/svg.js/-/svg.js-2.7.1.tgz", + "integrity": "sha512-ycbxpizEQktk3FYvn/8BH+6/EuWXg7ZpQREJvgacqn46gIddG24tNNe4Son6omdXCnSOaApnpZw6MPCBA1dODA==" + }, + "node_modules/svg.pathmorphing.js": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/svg.pathmorphing.js/-/svg.pathmorphing.js-0.1.3.tgz", + "integrity": "sha512-49HWI9X4XQR/JG1qXkSDV8xViuTLIWm/B/7YuQELV5KMOPtXjiwH4XPJvr/ghEDibmLQ9Oc22dpWpG0vUDDNww==", + "dependencies": { + "svg.js": "^2.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/svg.resize.js": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/svg.resize.js/-/svg.resize.js-1.4.3.tgz", + "integrity": "sha512-9k5sXJuPKp+mVzXNvxz7U0uC9oVMQrrf7cFsETznzUDDm0x8+77dtZkWdMfRlmbkEEYvUn9btKuZ3n41oNA+uw==", + "dependencies": { + "svg.js": "^2.6.5", + "svg.select.js": "^2.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/svg.resize.js/node_modules/svg.select.js": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/svg.select.js/-/svg.select.js-2.1.2.tgz", + "integrity": "sha512-tH6ABEyJsAOVAhwcCjF8mw4crjXSI1aa7j2VQR8ZuJ37H2MBUbyeqYr5nEO7sSN3cy9AR9DUwNg0t/962HlDbQ==", + "dependencies": { + "svg.js": "^2.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/svg.select.js": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/svg.select.js/-/svg.select.js-3.0.1.tgz", + "integrity": "sha512-h5IS/hKkuVCbKSieR9uQCj9w+zLHoPh+ce19bBYyqF53g6mnPB8sAtIbe1s9dh2S2fCmYX2xel1Ln3PJBbK4kw==", + "dependencies": { + "svg.js": "^2.6.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "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, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-node": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "dev": true, + "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/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "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, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.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, + "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==", + "dev": true + }, + "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 + }, + "node_modules/vite": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.2.1.tgz", + "integrity": "sha512-7MKhqdy0ISo4wnvwtqZkjke6XN4taqQ2TBaTccLIpOKv7Vp2h4Y+NpmWCnGDeSvvn45KxvWgGyb0MkHvY1vgbg==", + "dev": true, + "dependencies": { + "esbuild": "^0.17.5", + "postcss": "^8.4.21", + "resolve": "^1.22.1", + "rollup": "^3.18.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + }, + "peerDependencies": { + "@types/node": ">= 14", + "less": "*", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vue": { + "version": "3.2.47", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.2.47.tgz", + "integrity": "sha512-60188y/9Dc9WVrAZeUVSDxRQOZ+z+y5nO2ts9jWXSTkMvayiWxCWOWtBQoYjLeccfXkiiPZWAHcV+WTPhkqJHQ==", + "dependencies": { + "@vue/compiler-dom": "3.2.47", + "@vue/compiler-sfc": "3.2.47", + "@vue/runtime-dom": "3.2.47", + "@vue/server-renderer": "3.2.47", + "@vue/shared": "3.2.47" + } + }, + "node_modules/vue-eslint-parser": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.1.1.tgz", + "integrity": "sha512-C2aI/r85Q6tYcz4dpgvrs4wH/MqVrRAVIdpYedrxnATDHHkb+TroeRcDpKWGZCx/OcECMWfz7tVwQ8e+Opy6rA==", + "dev": true, + "dependencies": { + "debug": "^4.3.4", + "eslint-scope": "^7.1.1", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.1", + "esquery": "^1.4.0", + "lodash": "^4.17.21", + "semver": "^7.3.6" + }, + "engines": { + "node": "^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=6.0.0" + } + }, + "node_modules/vue-eslint-parser/node_modules/eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/vue-eslint-parser/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, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/vue-router": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.1.6.tgz", + "integrity": "sha512-DYWYwsG6xNPmLq/FmZn8Ip+qrhFEzA14EI12MsMgVxvHFDYvlr4NXpVF5hrRH1wVcDP8fGi5F4rxuJSl8/r+EQ==", + "dependencies": { + "@vue/devtools-api": "^6.4.5" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "vue": "^3.2.0" + } + }, + "node_modules/vue3-apexcharts": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/vue3-apexcharts/-/vue3-apexcharts-1.4.1.tgz", + "integrity": "sha512-96qP8JDqB9vwU7bkG5nVU+E0UGQn7yYQVqUUCLQMYWDuQyu2vE77H/UFZ1yI+hwzlSTBKT9BqnNG8JsFegB3eg==", + "peerDependencies": { + "apexcharts": "> 3.0.0", + "vue": "> 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, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "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 + }, + "node_modules/xml-name-validator": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", + "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "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, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/Epsilon.Host.Frontend/package.json b/Epsilon.Host.Frontend/package.json new file mode 100644 index 00000000..88dfe202 --- /dev/null +++ b/Epsilon.Host.Frontend/package.json @@ -0,0 +1,36 @@ +{ + "name": "learningtool.webapp", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "prestart": "node aspnetcore-https && node aspnetcore-vite", + "dev": "vite", + "build": "vite build", + "preview": "vite preview", + "lint": "eslint --ext .ts,vue --ignore-path .gitignore .", + "modelGeneration": "NODE_TLS_REJECT_UNAUTHORIZED=0 pnpm dlx swagger-typescript-api -p https://localhost:7084/swagger/v1/swagger.json -o src/logic -n Api.ts" + }, + "dependencies": { + "apexcharts": "^3.37.3", + "typescript": "^4.9.5", + "vue": "^3.2.45", + "vue-router": "^4.1.6", + "vue3-apexcharts": "^1.4.1" + }, + "devDependencies": { + "@types/node": "^18.15.3", + "@typescript-eslint/eslint-plugin": "^5.55.0", + "@typescript-eslint/parser": "^5.55.0", + "@vitejs/plugin-vue": "^4.0.0", + "@vue/eslint-config-typescript": "^11.0.2", + "eslint": "^8.36.0", + "eslint-config-prettier": "^8.8.0", + "eslint-plugin-prettier": "^4.2.1", + "eslint-plugin-vue": "^9.9.0", + "prettier": "^2.8.7", + "ts-node": "^10.9.1", + "vite": "^4.1.0", + "vue-eslint-parser": "^9.1.1" + } +} diff --git a/Epsilon.Host.Frontend/pnpm-lock.yaml b/Epsilon.Host.Frontend/pnpm-lock.yaml new file mode 100644 index 00000000..080f12d4 --- /dev/null +++ b/Epsilon.Host.Frontend/pnpm-lock.yaml @@ -0,0 +1,1806 @@ +lockfileVersion: '6.0' + +dependencies: + apexcharts: + specifier: ^3.37.3 + version: 3.37.3 + typescript: + specifier: ^4.9.5 + version: 4.9.5 + vue: + specifier: ^3.2.45 + version: 3.2.47 + vue-router: + specifier: ^4.1.6 + version: 4.1.6(vue@3.2.47) + vue3-apexcharts: + specifier: ^1.4.1 + version: 1.4.1(apexcharts@3.37.3)(vue@3.2.47) + +devDependencies: + '@types/node': + specifier: ^18.15.3 + version: 18.15.3 + '@typescript-eslint/eslint-plugin': + specifier: ^5.55.0 + version: 5.55.0(@typescript-eslint/parser@5.55.0)(eslint@8.36.0)(typescript@4.9.5) + '@typescript-eslint/parser': + specifier: ^5.55.0 + version: 5.55.0(eslint@8.36.0)(typescript@4.9.5) + '@vitejs/plugin-vue': + specifier: ^4.0.0 + version: 4.0.0(vite@4.1.4)(vue@3.2.47) + '@vue/eslint-config-typescript': + specifier: ^11.0.2 + version: 11.0.2(eslint-plugin-vue@9.9.0)(eslint@8.36.0)(typescript@4.9.5) + eslint: + specifier: ^8.36.0 + version: 8.36.0 + eslint-config-prettier: + specifier: ^8.8.0 + version: 8.8.0(eslint@8.36.0) + eslint-plugin-prettier: + specifier: ^4.2.1 + version: 4.2.1(eslint-config-prettier@8.8.0)(eslint@8.36.0)(prettier@2.8.7) + eslint-plugin-vue: + specifier: ^9.9.0 + version: 9.9.0(eslint@8.36.0) + prettier: + specifier: ^2.8.7 + version: 2.8.7 + ts-node: + specifier: ^10.9.1 + version: 10.9.1(@types/node@18.15.3)(typescript@4.9.5) + vite: + specifier: ^4.1.0 + version: 4.1.4(@types/node@18.15.3) + vue-eslint-parser: + specifier: ^9.1.1 + version: 9.1.1(eslint@8.36.0) + +packages: + + /@babel/helper-string-parser@7.19.4: + resolution: {integrity: sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==} + engines: {node: '>=6.9.0'} + + /@babel/helper-validator-identifier@7.19.1: + resolution: {integrity: sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==} + engines: {node: '>=6.9.0'} + + /@babel/parser@7.21.3: + resolution: {integrity: sha512-lobG0d7aOfQRXh8AyklEAgZGvA4FShxo6xQbUrrT/cNBPUdIDojlokwJsQyCC/eKia7ifqM0yP+2DRZ4WKw2RQ==} + engines: {node: '>=6.0.0'} + hasBin: true + dependencies: + '@babel/types': 7.21.3 + + /@babel/types@7.21.3: + resolution: {integrity: sha512-sBGdETxC+/M4o/zKC0sl6sjWv62WFR/uzxrJ6uYyMLZOUlPnwzw0tKgVHOXxaAd5l2g8pEDM5RZ495GPQI77kg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-string-parser': 7.19.4 + '@babel/helper-validator-identifier': 7.19.1 + to-fast-properties: 2.0.0 + + /@cspotcode/source-map-support@0.8.1: + resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} + engines: {node: '>=12'} + dependencies: + '@jridgewell/trace-mapping': 0.3.9 + dev: true + + /@esbuild/android-arm64@0.16.17: + resolution: {integrity: sha512-MIGl6p5sc3RDTLLkYL1MyL8BMRN4tLMRCn+yRJJmEDvYZ2M7tmAf80hx1kbNEUX2KJ50RRtxZ4JHLvCfuB6kBg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-arm@0.16.17: + resolution: {integrity: sha512-N9x1CMXVhtWEAMS7pNNONyA14f71VPQN9Cnavj1XQh6T7bskqiLLrSca4O0Vr8Wdcga943eThxnVp3JLnBMYtw==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-x64@0.16.17: + resolution: {integrity: sha512-a3kTv3m0Ghh4z1DaFEuEDfz3OLONKuFvI4Xqczqx4BqLyuFaFkuaG4j2MtA6fuWEFeC5x9IvqnX7drmRq/fyAQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-arm64@0.16.17: + resolution: {integrity: sha512-/2agbUEfmxWHi9ARTX6OQ/KgXnOWfsNlTeLcoV7HSuSTv63E4DqtAc+2XqGw1KHxKMHGZgbVCZge7HXWX9Vn+w==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-x64@0.16.17: + resolution: {integrity: sha512-2By45OBHulkd9Svy5IOCZt376Aa2oOkiE9QWUK9fe6Tb+WDr8hXL3dpqi+DeLiMed8tVXspzsTAvd0jUl96wmg==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-arm64@0.16.17: + resolution: {integrity: sha512-mt+cxZe1tVx489VTb4mBAOo2aKSnJ33L9fr25JXpqQqzbUIw/yzIzi+NHwAXK2qYV1lEFp4OoVeThGjUbmWmdw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-x64@0.16.17: + resolution: {integrity: sha512-8ScTdNJl5idAKjH8zGAsN7RuWcyHG3BAvMNpKOBaqqR7EbUhhVHOqXRdL7oZvz8WNHL2pr5+eIT5c65kA6NHug==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm64@0.16.17: + resolution: {integrity: sha512-7S8gJnSlqKGVJunnMCrXHU9Q8Q/tQIxk/xL8BqAP64wchPCTzuM6W3Ra8cIa1HIflAvDnNOt2jaL17vaW+1V0g==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm@0.16.17: + resolution: {integrity: sha512-iihzrWbD4gIT7j3caMzKb/RsFFHCwqqbrbH9SqUSRrdXkXaygSZCZg1FybsZz57Ju7N/SHEgPyaR0LZ8Zbe9gQ==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ia32@0.16.17: + resolution: {integrity: sha512-kiX69+wcPAdgl3Lonh1VI7MBr16nktEvOfViszBSxygRQqSpzv7BffMKRPMFwzeJGPxcio0pdD3kYQGpqQ2SSg==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-loong64@0.16.17: + resolution: {integrity: sha512-dTzNnQwembNDhd654cA4QhbS9uDdXC3TKqMJjgOWsC0yNCbpzfWoXdZvp0mY7HU6nzk5E0zpRGGx3qoQg8T2DQ==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-mips64el@0.16.17: + resolution: {integrity: sha512-ezbDkp2nDl0PfIUn0CsQ30kxfcLTlcx4Foz2kYv8qdC6ia2oX5Q3E/8m6lq84Dj/6b0FrkgD582fJMIfHhJfSw==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ppc64@0.16.17: + resolution: {integrity: sha512-dzS678gYD1lJsW73zrFhDApLVdM3cUF2MvAa1D8K8KtcSKdLBPP4zZSLy6LFZ0jYqQdQ29bjAHJDgz0rVbLB3g==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-riscv64@0.16.17: + resolution: {integrity: sha512-ylNlVsxuFjZK8DQtNUwiMskh6nT0vI7kYl/4fZgV1llP5d6+HIeL/vmmm3jpuoo8+NuXjQVZxmKuhDApK0/cKw==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-s390x@0.16.17: + resolution: {integrity: sha512-gzy7nUTO4UA4oZ2wAMXPNBGTzZFP7mss3aKR2hH+/4UUkCOyqmjXiKpzGrY2TlEUhbbejzXVKKGazYcQTZWA/w==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-x64@0.16.17: + resolution: {integrity: sha512-mdPjPxfnmoqhgpiEArqi4egmBAMYvaObgn4poorpUaqmvzzbvqbowRllQ+ZgzGVMGKaPkqUmPDOOFQRUFDmeUw==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/netbsd-x64@0.16.17: + resolution: {integrity: sha512-/PzmzD/zyAeTUsduZa32bn0ORug+Jd1EGGAUJvqfeixoEISYpGnAezN6lnJoskauoai0Jrs+XSyvDhppCPoKOA==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/openbsd-x64@0.16.17: + resolution: {integrity: sha512-2yaWJhvxGEz2RiftSk0UObqJa/b+rIAjnODJgv2GbGGpRwAfpgzyrg1WLK8rqA24mfZa9GvpjLcBBg8JHkoodg==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/sunos-x64@0.16.17: + resolution: {integrity: sha512-xtVUiev38tN0R3g8VhRfN7Zl42YCJvyBhRKw1RJjwE1d2emWTVToPLNEQj/5Qxc6lVFATDiy6LjVHYhIPrLxzw==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-arm64@0.16.17: + resolution: {integrity: sha512-ga8+JqBDHY4b6fQAmOgtJJue36scANy4l/rL97W+0wYmijhxKetzZdKOJI7olaBaMhWt8Pac2McJdZLxXWUEQw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-ia32@0.16.17: + resolution: {integrity: sha512-WnsKaf46uSSF/sZhwnqE4L/F89AYNMiD4YtEcYekBt9Q7nj0DiId2XH2Ng2PHM54qi5oPrQ8luuzGszqi/veig==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-x64@0.16.17: + resolution: {integrity: sha512-y+EHuSchhL7FjHgvQL/0fnnFmO4T1bhvWANX6gcnqTjtnKWbTvUMCpGnv2+t+31d7RzyEAYAd4u2fnIhHL6N/Q==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@eslint-community/eslint-utils@4.2.0(eslint@8.36.0): + resolution: {integrity: sha512-gB8T4H4DEfX2IV9zGDJPOBgP1e/DbfCPDTtEqUMckpvzS1OYtva8JdFYBqMwYk7xAQ429WGF/UPqn8uQ//h2vQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + dependencies: + eslint: 8.36.0 + eslint-visitor-keys: 3.3.0 + dev: true + + /@eslint-community/regexpp@4.4.0: + resolution: {integrity: sha512-A9983Q0LnDGdLPjxyXQ00sbV+K+O+ko2Dr+CZigbHWtX9pNfxlaBkMR8X1CztI73zuEyEBXTVjx7CE+/VSwDiQ==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + dev: true + + /@eslint/eslintrc@2.0.1: + resolution: {integrity: sha512-eFRmABvW2E5Ho6f5fHLqgena46rOj7r7OKHYfLElqcBfGFHHpjBhivyi5+jOEQuSpdc/1phIZJlbC2te+tZNIw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + ajv: 6.12.6 + debug: 4.3.4 + espree: 9.5.0 + globals: 13.20.0 + ignore: 5.2.4 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + dev: true + + /@eslint/js@8.36.0: + resolution: {integrity: sha512-lxJ9R5ygVm8ZWgYdUweoq5ownDlJ4upvoWmO4eLxBYHdMo+vZ/Rx0EN6MbKWDJOSUGrqJy2Gt+Dyv/VKml0fjg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + + /@humanwhocodes/config-array@0.11.8: + resolution: {integrity: sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==} + engines: {node: '>=10.10.0'} + dependencies: + '@humanwhocodes/object-schema': 1.2.1 + debug: 4.3.4 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@humanwhocodes/module-importer@1.0.1: + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + dev: true + + /@humanwhocodes/object-schema@1.2.1: + resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} + dev: true + + /@jridgewell/resolve-uri@3.1.0: + resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==} + engines: {node: '>=6.0.0'} + dev: true + + /@jridgewell/sourcemap-codec@1.4.14: + resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==} + dev: true + + /@jridgewell/trace-mapping@0.3.9: + resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + dependencies: + '@jridgewell/resolve-uri': 3.1.0 + '@jridgewell/sourcemap-codec': 1.4.14 + dev: true + + /@nodelib/fs.scandir@2.1.5: + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + dev: true + + /@nodelib/fs.stat@2.0.5: + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + dev: true + + /@nodelib/fs.walk@1.2.8: + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.15.0 + dev: true + + /@tsconfig/node10@1.0.9: + resolution: {integrity: sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==} + dev: true + + /@tsconfig/node12@1.0.11: + resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} + dev: true + + /@tsconfig/node14@1.0.3: + resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} + dev: true + + /@tsconfig/node16@1.0.3: + resolution: {integrity: sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==} + dev: true + + /@types/json-schema@7.0.11: + resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==} + dev: true + + /@types/node@18.15.3: + resolution: {integrity: sha512-p6ua9zBxz5otCmbpb5D3U4B5Nanw6Pk3PPyX05xnxbB/fRv71N7CPmORg7uAD5P70T0xmx1pzAx/FUfa5X+3cw==} + dev: true + + /@types/semver@7.3.13: + resolution: {integrity: sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==} + dev: true + + /@typescript-eslint/eslint-plugin@5.55.0(@typescript-eslint/parser@5.55.0)(eslint@8.36.0)(typescript@4.9.5): + resolution: {integrity: sha512-IZGc50rtbjk+xp5YQoJvmMPmJEYoC53SiKPXyqWfv15XoD2Y5Kju6zN0DwlmaGJp1Iw33JsWJcQ7nw0lGCGjVg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + '@typescript-eslint/parser': ^5.0.0 + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@eslint-community/regexpp': 4.4.0 + '@typescript-eslint/parser': 5.55.0(eslint@8.36.0)(typescript@4.9.5) + '@typescript-eslint/scope-manager': 5.55.0 + '@typescript-eslint/type-utils': 5.55.0(eslint@8.36.0)(typescript@4.9.5) + '@typescript-eslint/utils': 5.55.0(eslint@8.36.0)(typescript@4.9.5) + debug: 4.3.4 + eslint: 8.36.0 + grapheme-splitter: 1.0.4 + ignore: 5.2.4 + natural-compare-lite: 1.4.0 + semver: 7.3.8 + tsutils: 3.21.0(typescript@4.9.5) + typescript: 4.9.5 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/parser@5.55.0(eslint@8.36.0)(typescript@4.9.5): + resolution: {integrity: sha512-ppvmeF7hvdhUUZWSd2EEWfzcFkjJzgNQzVST22nzg958CR+sphy8A6K7LXQZd6V75m1VKjp+J4g/PCEfSCmzhw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/scope-manager': 5.55.0 + '@typescript-eslint/types': 5.55.0 + '@typescript-eslint/typescript-estree': 5.55.0(typescript@4.9.5) + debug: 4.3.4 + eslint: 8.36.0 + typescript: 4.9.5 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/scope-manager@5.55.0: + resolution: {integrity: sha512-OK+cIO1ZGhJYNCL//a3ROpsd83psf4dUJ4j7pdNVzd5DmIk+ffkuUIX2vcZQbEW/IR41DYsfJTB19tpCboxQuw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + '@typescript-eslint/types': 5.55.0 + '@typescript-eslint/visitor-keys': 5.55.0 + dev: true + + /@typescript-eslint/type-utils@5.55.0(eslint@8.36.0)(typescript@4.9.5): + resolution: {integrity: sha512-ObqxBgHIXj8rBNm0yh8oORFrICcJuZPZTqtAFh0oZQyr5DnAHZWfyw54RwpEEH+fD8suZaI0YxvWu5tYE/WswA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: '*' + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/typescript-estree': 5.55.0(typescript@4.9.5) + '@typescript-eslint/utils': 5.55.0(eslint@8.36.0)(typescript@4.9.5) + debug: 4.3.4 + eslint: 8.36.0 + tsutils: 3.21.0(typescript@4.9.5) + typescript: 4.9.5 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/types@5.55.0: + resolution: {integrity: sha512-M4iRh4AG1ChrOL6Y+mETEKGeDnT7Sparn6fhZ5LtVJF1909D5O4uqK+C5NPbLmpfZ0XIIxCdwzKiijpZUOvOug==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + + /@typescript-eslint/typescript-estree@5.55.0(typescript@4.9.5): + resolution: {integrity: sha512-I7X4A9ovA8gdpWMpr7b1BN9eEbvlEtWhQvpxp/yogt48fy9Lj3iE3ild/1H3jKBBIYj5YYJmS2+9ystVhC7eaQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/types': 5.55.0 + '@typescript-eslint/visitor-keys': 5.55.0 + debug: 4.3.4 + globby: 11.1.0 + is-glob: 4.0.3 + semver: 7.3.8 + tsutils: 3.21.0(typescript@4.9.5) + typescript: 4.9.5 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/utils@5.55.0(eslint@8.36.0)(typescript@4.9.5): + resolution: {integrity: sha512-FkW+i2pQKcpDC3AY6DU54yl8Lfl14FVGYDgBTyGKB75cCwV3KpkpTMFi9d9j2WAJ4271LR2HeC5SEWF/CZmmfw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + '@eslint-community/eslint-utils': 4.2.0(eslint@8.36.0) + '@types/json-schema': 7.0.11 + '@types/semver': 7.3.13 + '@typescript-eslint/scope-manager': 5.55.0 + '@typescript-eslint/types': 5.55.0 + '@typescript-eslint/typescript-estree': 5.55.0(typescript@4.9.5) + eslint: 8.36.0 + eslint-scope: 5.1.1 + semver: 7.3.8 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + /@typescript-eslint/visitor-keys@5.55.0: + resolution: {integrity: sha512-q2dlHHwWgirKh1D3acnuApXG+VNXpEY5/AwRxDVuEQpxWaB0jCDe0jFMVMALJ3ebSfuOVE8/rMS+9ZOYGg1GWw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + '@typescript-eslint/types': 5.55.0 + eslint-visitor-keys: 3.3.0 + dev: true + + /@vitejs/plugin-vue@4.0.0(vite@4.1.4)(vue@3.2.47): + resolution: {integrity: sha512-e0X4jErIxAB5oLtDqbHvHpJe/uWNkdpYV83AOG2xo2tEVSzCzewgJMtREZM30wXnM5ls90hxiOtAuVU6H5JgbA==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + vite: ^4.0.0 + vue: ^3.2.25 + dependencies: + vite: 4.1.4(@types/node@18.15.3) + vue: 3.2.47 + dev: true + + /@vue/compiler-core@3.2.47: + resolution: {integrity: sha512-p4D7FDnQb7+YJmO2iPEv0SQNeNzcbHdGByJDsT4lynf63AFkOTFN07HsiRSvjGo0QrxR/o3d0hUyNCUnBU2Tig==} + dependencies: + '@babel/parser': 7.21.3 + '@vue/shared': 3.2.47 + estree-walker: 2.0.2 + source-map: 0.6.1 + + /@vue/compiler-dom@3.2.47: + resolution: {integrity: sha512-dBBnEHEPoftUiS03a4ggEig74J2YBZ2UIeyfpcRM2tavgMWo4bsEfgCGsu+uJIL/vax9S+JztH8NmQerUo7shQ==} + dependencies: + '@vue/compiler-core': 3.2.47 + '@vue/shared': 3.2.47 + + /@vue/compiler-sfc@3.2.47: + resolution: {integrity: sha512-rog05W+2IFfxjMcFw10tM9+f7i/+FFpZJJ5XHX72NP9eC2uRD+42M3pYcQqDXVYoj74kHMSEdQ/WmCjt8JFksQ==} + dependencies: + '@babel/parser': 7.21.3 + '@vue/compiler-core': 3.2.47 + '@vue/compiler-dom': 3.2.47 + '@vue/compiler-ssr': 3.2.47 + '@vue/reactivity-transform': 3.2.47 + '@vue/shared': 3.2.47 + estree-walker: 2.0.2 + magic-string: 0.25.9 + postcss: 8.4.21 + source-map: 0.6.1 + + /@vue/compiler-ssr@3.2.47: + resolution: {integrity: sha512-wVXC+gszhulcMD8wpxMsqSOpvDZ6xKXSVWkf50Guf/S+28hTAXPDYRTbLQ3EDkOP5Xz/+SY37YiwDquKbJOgZw==} + dependencies: + '@vue/compiler-dom': 3.2.47 + '@vue/shared': 3.2.47 + + /@vue/devtools-api@6.5.0: + resolution: {integrity: sha512-o9KfBeaBmCKl10usN4crU53fYtC1r7jJwdGKjPT24t348rHxgfpZ0xL3Xm/gLUYnc0oTp8LAmrxOeLyu6tbk2Q==} + dev: false + + /@vue/eslint-config-typescript@11.0.2(eslint-plugin-vue@9.9.0)(eslint@8.36.0)(typescript@4.9.5): + resolution: {integrity: sha512-EiKud1NqlWmSapBFkeSrE994qpKx7/27uCGnhdqzllYDpQZroyX/O6bwjEpeuyKamvLbsGdO6PMR2faIf+zFnw==} + engines: {node: ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.2.0 || ^7.0.0 || ^8.0.0 + eslint-plugin-vue: ^9.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/eslint-plugin': 5.55.0(@typescript-eslint/parser@5.55.0)(eslint@8.36.0)(typescript@4.9.5) + '@typescript-eslint/parser': 5.55.0(eslint@8.36.0)(typescript@4.9.5) + eslint: 8.36.0 + eslint-plugin-vue: 9.9.0(eslint@8.36.0) + typescript: 4.9.5 + vue-eslint-parser: 9.1.1(eslint@8.36.0) + transitivePeerDependencies: + - supports-color + dev: true + + /@vue/reactivity-transform@3.2.47: + resolution: {integrity: sha512-m8lGXw8rdnPVVIdIFhf0LeQ/ixyHkH5plYuS83yop5n7ggVJU+z5v0zecwEnX7fa7HNLBhh2qngJJkxpwEEmYA==} + dependencies: + '@babel/parser': 7.21.3 + '@vue/compiler-core': 3.2.47 + '@vue/shared': 3.2.47 + estree-walker: 2.0.2 + magic-string: 0.25.9 + + /@vue/reactivity@3.2.47: + resolution: {integrity: sha512-7khqQ/75oyyg+N/e+iwV6lpy1f5wq759NdlS1fpAhFXa8VeAIKGgk2E/C4VF59lx5b+Ezs5fpp/5WsRYXQiKxQ==} + dependencies: + '@vue/shared': 3.2.47 + + /@vue/runtime-core@3.2.47: + resolution: {integrity: sha512-RZxbLQIRB/K0ev0K9FXhNbBzT32H9iRtYbaXb0ZIz2usLms/D55dJR2t6cIEUn6vyhS3ALNvNthI+Q95C+NOpA==} + dependencies: + '@vue/reactivity': 3.2.47 + '@vue/shared': 3.2.47 + + /@vue/runtime-dom@3.2.47: + resolution: {integrity: sha512-ArXrFTjS6TsDei4qwNvgrdmHtD930KgSKGhS5M+j8QxXrDJYLqYw4RRcDy1bz1m1wMmb6j+zGLifdVHtkXA7gA==} + dependencies: + '@vue/runtime-core': 3.2.47 + '@vue/shared': 3.2.47 + csstype: 2.6.21 + + /@vue/server-renderer@3.2.47(vue@3.2.47): + resolution: {integrity: sha512-dN9gc1i8EvmP9RCzvneONXsKfBRgqFeFZLurmHOveL7oH6HiFXJw5OGu294n1nHc/HMgTy6LulU/tv5/A7f/LA==} + peerDependencies: + vue: 3.2.47 + dependencies: + '@vue/compiler-ssr': 3.2.47 + '@vue/shared': 3.2.47 + vue: 3.2.47 + + /@vue/shared@3.2.47: + resolution: {integrity: sha512-BHGyyGN3Q97EZx0taMQ+OLNuZcW3d37ZEVmEAyeoA9ERdGvm9Irc/0Fua8SNyOtV1w6BS4q25wbMzJujO9HIfQ==} + + /acorn-jsx@5.3.2(acorn@8.8.2): + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + acorn: 8.8.2 + dev: true + + /acorn-walk@8.2.0: + resolution: {integrity: sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==} + engines: {node: '>=0.4.0'} + dev: true + + /acorn@8.8.2: + resolution: {integrity: sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==} + engines: {node: '>=0.4.0'} + hasBin: true + dev: true + + /ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + dev: true + + /ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + dev: true + + /ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + dependencies: + color-convert: 2.0.1 + dev: true + + /apexcharts@3.37.3: + resolution: {integrity: sha512-+rnUui9uC3Mvh9qbQxUfqBnuJ0nAJOYTp+yKnA5bVmmndKXj5X/Q+OVIxkq0Jr5ysiK200Dsg1Tuz/OUG+DEpw==} + dependencies: + svg.draggable.js: 2.2.2 + svg.easing.js: 2.0.0 + svg.filter.js: 2.0.2 + svg.pathmorphing.js: 0.1.3 + svg.resize.js: 1.4.3 + svg.select.js: 3.0.1 + dev: false + + /arg@4.1.3: + resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} + dev: true + + /argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + dev: true + + /array-union@2.1.0: + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} + engines: {node: '>=8'} + dev: true + + /balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + dev: true + + /boolbase@1.0.0: + resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + dev: true + + /brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + dev: true + + /braces@3.0.2: + resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} + engines: {node: '>=8'} + dependencies: + fill-range: 7.0.1 + dev: true + + /callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + dev: true + + /chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + dev: true + + /color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + dependencies: + color-name: 1.1.4 + dev: true + + /color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + dev: true + + /concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + dev: true + + /create-require@1.1.1: + resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} + dev: true + + /cross-spawn@7.0.3: + resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + engines: {node: '>= 8'} + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + dev: true + + /cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + dev: true + + /csstype@2.6.21: + resolution: {integrity: sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==} + + /debug@4.3.4: + resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.2 + dev: true + + /deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + dev: true + + /diff@4.0.2: + resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} + engines: {node: '>=0.3.1'} + dev: true + + /dir-glob@3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + dependencies: + path-type: 4.0.0 + dev: true + + /doctrine@3.0.0: + resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} + engines: {node: '>=6.0.0'} + dependencies: + esutils: 2.0.3 + dev: true + + /esbuild@0.16.17: + resolution: {integrity: sha512-G8LEkV0XzDMNwXKgM0Jwu3nY3lSTwSGY6XbxM9cr9+s0T/qSV1q1JVPBGzm3dcjhCic9+emZDmMffkwgPeOeLg==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/android-arm': 0.16.17 + '@esbuild/android-arm64': 0.16.17 + '@esbuild/android-x64': 0.16.17 + '@esbuild/darwin-arm64': 0.16.17 + '@esbuild/darwin-x64': 0.16.17 + '@esbuild/freebsd-arm64': 0.16.17 + '@esbuild/freebsd-x64': 0.16.17 + '@esbuild/linux-arm': 0.16.17 + '@esbuild/linux-arm64': 0.16.17 + '@esbuild/linux-ia32': 0.16.17 + '@esbuild/linux-loong64': 0.16.17 + '@esbuild/linux-mips64el': 0.16.17 + '@esbuild/linux-ppc64': 0.16.17 + '@esbuild/linux-riscv64': 0.16.17 + '@esbuild/linux-s390x': 0.16.17 + '@esbuild/linux-x64': 0.16.17 + '@esbuild/netbsd-x64': 0.16.17 + '@esbuild/openbsd-x64': 0.16.17 + '@esbuild/sunos-x64': 0.16.17 + '@esbuild/win32-arm64': 0.16.17 + '@esbuild/win32-ia32': 0.16.17 + '@esbuild/win32-x64': 0.16.17 + dev: true + + /escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + dev: true + + /eslint-config-prettier@8.8.0(eslint@8.36.0): + resolution: {integrity: sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA==} + hasBin: true + peerDependencies: + eslint: '>=7.0.0' + dependencies: + eslint: 8.36.0 + dev: true + + /eslint-plugin-prettier@4.2.1(eslint-config-prettier@8.8.0)(eslint@8.36.0)(prettier@2.8.7): + resolution: {integrity: sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==} + engines: {node: '>=12.0.0'} + peerDependencies: + eslint: '>=7.28.0' + eslint-config-prettier: '*' + prettier: '>=2.0.0' + peerDependenciesMeta: + eslint-config-prettier: + optional: true + dependencies: + eslint: 8.36.0 + eslint-config-prettier: 8.8.0(eslint@8.36.0) + prettier: 2.8.7 + prettier-linter-helpers: 1.0.0 + dev: true + + /eslint-plugin-vue@9.9.0(eslint@8.36.0): + resolution: {integrity: sha512-YbubS7eK0J7DCf0U2LxvVP7LMfs6rC6UltihIgval3azO3gyDwEGVgsCMe1TmDiEkl6GdMKfRpaME6QxIYtzDQ==} + engines: {node: ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.2.0 || ^7.0.0 || ^8.0.0 + dependencies: + eslint: 8.36.0 + eslint-utils: 3.0.0(eslint@8.36.0) + natural-compare: 1.4.0 + nth-check: 2.1.1 + postcss-selector-parser: 6.0.11 + semver: 7.3.8 + vue-eslint-parser: 9.1.1(eslint@8.36.0) + xml-name-validator: 4.0.0 + transitivePeerDependencies: + - supports-color + dev: true + + /eslint-scope@5.1.1: + resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} + engines: {node: '>=8.0.0'} + dependencies: + esrecurse: 4.3.0 + estraverse: 4.3.0 + dev: true + + /eslint-scope@7.1.1: + resolution: {integrity: sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + dev: true + + /eslint-utils@3.0.0(eslint@8.36.0): + resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==} + engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0} + peerDependencies: + eslint: '>=5' + dependencies: + eslint: 8.36.0 + eslint-visitor-keys: 2.1.0 + dev: true + + /eslint-visitor-keys@2.1.0: + resolution: {integrity: sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==} + engines: {node: '>=10'} + dev: true + + /eslint-visitor-keys@3.3.0: + resolution: {integrity: sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + + /eslint@8.36.0: + resolution: {integrity: sha512-Y956lmS7vDqomxlaaQAHVmeb4tNMp2FWIvU/RnU5BD3IKMD/MJPr76xdyr68P8tV1iNMvN2mRK0yy3c+UjL+bw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + hasBin: true + dependencies: + '@eslint-community/eslint-utils': 4.2.0(eslint@8.36.0) + '@eslint-community/regexpp': 4.4.0 + '@eslint/eslintrc': 2.0.1 + '@eslint/js': 8.36.0 + '@humanwhocodes/config-array': 0.11.8 + '@humanwhocodes/module-importer': 1.0.1 + '@nodelib/fs.walk': 1.2.8 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.3 + debug: 4.3.4 + doctrine: 3.0.0 + escape-string-regexp: 4.0.0 + eslint-scope: 7.1.1 + eslint-visitor-keys: 3.3.0 + espree: 9.5.0 + esquery: 1.5.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 6.0.1 + find-up: 5.0.0 + glob-parent: 6.0.2 + globals: 13.20.0 + grapheme-splitter: 1.0.4 + ignore: 5.2.4 + import-fresh: 3.3.0 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + is-path-inside: 3.0.3 + js-sdsl: 4.3.0 + js-yaml: 4.1.0 + json-stable-stringify-without-jsonify: 1.0.1 + levn: 0.4.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.1 + strip-ansi: 6.0.1 + strip-json-comments: 3.1.1 + text-table: 0.2.0 + transitivePeerDependencies: + - supports-color + dev: true + + /espree@9.5.0: + resolution: {integrity: sha512-JPbJGhKc47++oo4JkEoTe2wjy4fmMwvFpgJT9cQzmfXKp22Dr6Hf1tdCteLz1h0P3t+mGvWZ+4Uankvh8+c6zw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + acorn: 8.8.2 + acorn-jsx: 5.3.2(acorn@8.8.2) + eslint-visitor-keys: 3.3.0 + dev: true + + /esquery@1.5.0: + resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} + engines: {node: '>=0.10'} + dependencies: + estraverse: 5.3.0 + dev: true + + /esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + dependencies: + estraverse: 5.3.0 + dev: true + + /estraverse@4.3.0: + resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} + engines: {node: '>=4.0'} + dev: true + + /estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + dev: true + + /estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + + /esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + dev: true + + /fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + dev: true + + /fast-diff@1.2.0: + resolution: {integrity: sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==} + dev: true + + /fast-glob@3.2.12: + resolution: {integrity: sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==} + engines: {node: '>=8.6.0'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.5 + dev: true + + /fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + dev: true + + /fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + dev: true + + /fastq@1.15.0: + resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} + dependencies: + reusify: 1.0.4 + dev: true + + /file-entry-cache@6.0.1: + resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} + engines: {node: ^10.12.0 || >=12.0.0} + dependencies: + flat-cache: 3.0.4 + dev: true + + /fill-range@7.0.1: + resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} + engines: {node: '>=8'} + dependencies: + to-regex-range: 5.0.1 + dev: true + + /find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + dev: true + + /flat-cache@3.0.4: + resolution: {integrity: sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==} + engines: {node: ^10.12.0 || >=12.0.0} + dependencies: + flatted: 3.2.7 + rimraf: 3.0.2 + dev: true + + /flatted@3.2.7: + resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==} + dev: true + + /fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + dev: true + + /fsevents@2.3.2: + resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /function-bind@1.1.1: + resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} + dev: true + + /glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + dependencies: + is-glob: 4.0.3 + dev: true + + /glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + dependencies: + is-glob: 4.0.3 + dev: true + + /glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + dev: true + + /globals@13.20.0: + resolution: {integrity: sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==} + engines: {node: '>=8'} + dependencies: + type-fest: 0.20.2 + dev: true + + /globby@11.1.0: + resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} + engines: {node: '>=10'} + dependencies: + array-union: 2.1.0 + dir-glob: 3.0.1 + fast-glob: 3.2.12 + ignore: 5.2.4 + merge2: 1.4.1 + slash: 3.0.0 + dev: true + + /grapheme-splitter@1.0.4: + resolution: {integrity: sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==} + dev: true + + /has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + dev: true + + /has@1.0.3: + resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} + engines: {node: '>= 0.4.0'} + dependencies: + function-bind: 1.1.1 + dev: true + + /ignore@5.2.4: + resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} + engines: {node: '>= 4'} + dev: true + + /import-fresh@3.3.0: + resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} + engines: {node: '>=6'} + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + dev: true + + /imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + dev: true + + /inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + dev: true + + /inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + dev: true + + /is-core-module@2.11.0: + resolution: {integrity: sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==} + dependencies: + has: 1.0.3 + dev: true + + /is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + dev: true + + /is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + dependencies: + is-extglob: 2.1.1 + dev: true + + /is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + dev: true + + /is-path-inside@3.0.3: + resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} + engines: {node: '>=8'} + dev: true + + /isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + dev: true + + /js-sdsl@4.3.0: + resolution: {integrity: sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==} + dev: true + + /js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + dependencies: + argparse: 2.0.1 + dev: true + + /json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + dev: true + + /json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + dev: true + + /levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + dev: true + + /locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + dependencies: + p-locate: 5.0.0 + dev: true + + /lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + dev: true + + /lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + dev: true + + /lru-cache@6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} + dependencies: + yallist: 4.0.0 + dev: true + + /magic-string@0.25.9: + resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==} + dependencies: + sourcemap-codec: 1.4.8 + + /make-error@1.3.6: + resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + dev: true + + /merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + dev: true + + /micromatch@4.0.5: + resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} + engines: {node: '>=8.6'} + dependencies: + braces: 3.0.2 + picomatch: 2.3.1 + dev: true + + /minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + dependencies: + brace-expansion: 1.1.11 + dev: true + + /ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + dev: true + + /nanoid@3.3.4: + resolution: {integrity: sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + /natural-compare-lite@1.4.0: + resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==} + dev: true + + /natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + dev: true + + /nth-check@2.1.1: + resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + dependencies: + boolbase: 1.0.0 + dev: true + + /once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + dependencies: + wrappy: 1.0.2 + dev: true + + /optionator@0.9.1: + resolution: {integrity: sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==} + engines: {node: '>= 0.8.0'} + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.3 + dev: true + + /p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + dependencies: + yocto-queue: 0.1.0 + dev: true + + /p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + dependencies: + p-limit: 3.1.0 + dev: true + + /parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + dependencies: + callsites: 3.1.0 + dev: true + + /path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + dev: true + + /path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + dev: true + + /path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + dev: true + + /path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + dev: true + + /path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + dev: true + + /picocolors@1.0.0: + resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} + + /picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + dev: true + + /postcss-selector-parser@6.0.11: + resolution: {integrity: sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g==} + engines: {node: '>=4'} + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + dev: true + + /postcss@8.4.21: + resolution: {integrity: sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==} + engines: {node: ^10 || ^12 || >=14} + dependencies: + nanoid: 3.3.4 + picocolors: 1.0.0 + source-map-js: 1.0.2 + + /prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + dev: true + + /prettier-linter-helpers@1.0.0: + resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==} + engines: {node: '>=6.0.0'} + dependencies: + fast-diff: 1.2.0 + dev: true + + /prettier@2.8.7: + resolution: {integrity: sha512-yPngTo3aXUUmyuTjeTUT75txrf+aMh9FiD7q9ZE/i6r0bPb22g4FsE6Y338PQX1bmfy08i9QQCB7/rcUAVntfw==} + engines: {node: '>=10.13.0'} + hasBin: true + dev: true + + /punycode@2.3.0: + resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==} + engines: {node: '>=6'} + dev: true + + /queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + dev: true + + /resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + dev: true + + /resolve@1.22.1: + resolution: {integrity: sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==} + hasBin: true + dependencies: + is-core-module: 2.11.0 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + dev: true + + /reusify@1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + dev: true + + /rimraf@3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + hasBin: true + dependencies: + glob: 7.2.3 + dev: true + + /rollup@3.19.1: + resolution: {integrity: sha512-lAbrdN7neYCg/8WaoWn/ckzCtz+jr70GFfYdlf50OF7387HTg+wiuiqJRFYawwSPpqfqDNYqK7smY/ks2iAudg==} + engines: {node: '>=14.18.0', npm: '>=8.0.0'} + hasBin: true + optionalDependencies: + fsevents: 2.3.2 + dev: true + + /run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + dependencies: + queue-microtask: 1.2.3 + dev: true + + /semver@7.3.8: + resolution: {integrity: sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==} + engines: {node: '>=10'} + hasBin: true + dependencies: + lru-cache: 6.0.0 + dev: true + + /shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + dependencies: + shebang-regex: 3.0.0 + dev: true + + /shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + dev: true + + /slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + dev: true + + /source-map-js@1.0.2: + resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} + engines: {node: '>=0.10.0'} + + /source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + + /sourcemap-codec@1.4.8: + resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==} + deprecated: Please use @jridgewell/sourcemap-codec instead + + /strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + dependencies: + ansi-regex: 5.0.1 + dev: true + + /strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + dev: true + + /supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + dependencies: + has-flag: 4.0.0 + dev: true + + /supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + dev: true + + /svg.draggable.js@2.2.2: + resolution: {integrity: sha512-JzNHBc2fLQMzYCZ90KZHN2ohXL0BQJGQimK1kGk6AvSeibuKcIdDX9Kr0dT9+UJ5O8nYA0RB839Lhvk4CY4MZw==} + engines: {node: '>= 0.8.0'} + dependencies: + svg.js: 2.7.1 + dev: false + + /svg.easing.js@2.0.0: + resolution: {integrity: sha512-//ctPdJMGy22YoYGV+3HEfHbm6/69LJUTAqI2/5qBvaNHZ9uUFVC82B0Pl299HzgH13rKrBgi4+XyXXyVWWthA==} + engines: {node: '>= 0.8.0'} + dependencies: + svg.js: 2.7.1 + dev: false + + /svg.filter.js@2.0.2: + resolution: {integrity: sha512-xkGBwU+dKBzqg5PtilaTb0EYPqPfJ9Q6saVldX+5vCRy31P6TlRCP3U9NxH3HEufkKkpNgdTLBJnmhDHeTqAkw==} + engines: {node: '>= 0.8.0'} + dependencies: + svg.js: 2.7.1 + dev: false + + /svg.js@2.7.1: + resolution: {integrity: sha512-ycbxpizEQktk3FYvn/8BH+6/EuWXg7ZpQREJvgacqn46gIddG24tNNe4Son6omdXCnSOaApnpZw6MPCBA1dODA==} + dev: false + + /svg.pathmorphing.js@0.1.3: + resolution: {integrity: sha512-49HWI9X4XQR/JG1qXkSDV8xViuTLIWm/B/7YuQELV5KMOPtXjiwH4XPJvr/ghEDibmLQ9Oc22dpWpG0vUDDNww==} + engines: {node: '>= 0.8.0'} + dependencies: + svg.js: 2.7.1 + dev: false + + /svg.resize.js@1.4.3: + resolution: {integrity: sha512-9k5sXJuPKp+mVzXNvxz7U0uC9oVMQrrf7cFsETznzUDDm0x8+77dtZkWdMfRlmbkEEYvUn9btKuZ3n41oNA+uw==} + engines: {node: '>= 0.8.0'} + dependencies: + svg.js: 2.7.1 + svg.select.js: 2.1.2 + dev: false + + /svg.select.js@2.1.2: + resolution: {integrity: sha512-tH6ABEyJsAOVAhwcCjF8mw4crjXSI1aa7j2VQR8ZuJ37H2MBUbyeqYr5nEO7sSN3cy9AR9DUwNg0t/962HlDbQ==} + engines: {node: '>= 0.8.0'} + dependencies: + svg.js: 2.7.1 + dev: false + + /svg.select.js@3.0.1: + resolution: {integrity: sha512-h5IS/hKkuVCbKSieR9uQCj9w+zLHoPh+ce19bBYyqF53g6mnPB8sAtIbe1s9dh2S2fCmYX2xel1Ln3PJBbK4kw==} + engines: {node: '>= 0.8.0'} + dependencies: + svg.js: 2.7.1 + dev: false + + /text-table@0.2.0: + resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + dev: true + + /to-fast-properties@2.0.0: + resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} + engines: {node: '>=4'} + + /to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + dependencies: + is-number: 7.0.0 + dev: true + + /ts-node@10.9.1(@types/node@18.15.3)(typescript@4.9.5): + resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==} + hasBin: true + 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 + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.9 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.3 + '@types/node': 18.15.3 + acorn: 8.8.2 + acorn-walk: 8.2.0 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 4.9.5 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + dev: true + + /tslib@1.14.1: + resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} + dev: true + + /tsutils@3.21.0(typescript@4.9.5): + resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} + engines: {node: '>= 6'} + peerDependencies: + typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' + dependencies: + tslib: 1.14.1 + typescript: 4.9.5 + dev: true + + /type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + dependencies: + prelude-ls: 1.2.1 + dev: true + + /type-fest@0.20.2: + resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} + engines: {node: '>=10'} + dev: true + + /typescript@4.9.5: + resolution: {integrity: sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==} + engines: {node: '>=4.2.0'} + hasBin: true + + /uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + dependencies: + punycode: 2.3.0 + dev: true + + /util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + dev: true + + /v8-compile-cache-lib@3.0.1: + resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} + dev: true + + /vite@4.1.4(@types/node@18.15.3): + resolution: {integrity: sha512-3knk/HsbSTKEin43zHu7jTwYWv81f8kgAL99G5NWBcA1LKvtvcVAC4JjBH1arBunO9kQka+1oGbrMKOjk4ZrBg==} + engines: {node: ^14.18.0 || >=16.0.0} + hasBin: true + peerDependencies: + '@types/node': '>= 14' + less: '*' + sass: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + sass: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + dependencies: + '@types/node': 18.15.3 + esbuild: 0.16.17 + postcss: 8.4.21 + resolve: 1.22.1 + rollup: 3.19.1 + optionalDependencies: + fsevents: 2.3.2 + dev: true + + /vue-eslint-parser@9.1.1(eslint@8.36.0): + resolution: {integrity: sha512-C2aI/r85Q6tYcz4dpgvrs4wH/MqVrRAVIdpYedrxnATDHHkb+TroeRcDpKWGZCx/OcECMWfz7tVwQ8e+Opy6rA==} + engines: {node: ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: '>=6.0.0' + dependencies: + debug: 4.3.4 + eslint: 8.36.0 + eslint-scope: 7.1.1 + eslint-visitor-keys: 3.3.0 + espree: 9.5.0 + esquery: 1.5.0 + lodash: 4.17.21 + semver: 7.3.8 + transitivePeerDependencies: + - supports-color + dev: true + + /vue-router@4.1.6(vue@3.2.47): + resolution: {integrity: sha512-DYWYwsG6xNPmLq/FmZn8Ip+qrhFEzA14EI12MsMgVxvHFDYvlr4NXpVF5hrRH1wVcDP8fGi5F4rxuJSl8/r+EQ==} + peerDependencies: + vue: ^3.2.0 + dependencies: + '@vue/devtools-api': 6.5.0 + vue: 3.2.47 + dev: false + + /vue3-apexcharts@1.4.1(apexcharts@3.37.3)(vue@3.2.47): + resolution: {integrity: sha512-96qP8JDqB9vwU7bkG5nVU+E0UGQn7yYQVqUUCLQMYWDuQyu2vE77H/UFZ1yI+hwzlSTBKT9BqnNG8JsFegB3eg==} + peerDependencies: + apexcharts: '> 3.0.0' + vue: '> 3.0.0' + dependencies: + apexcharts: 3.37.3 + vue: 3.2.47 + dev: false + + /vue@3.2.47: + resolution: {integrity: sha512-60188y/9Dc9WVrAZeUVSDxRQOZ+z+y5nO2ts9jWXSTkMvayiWxCWOWtBQoYjLeccfXkiiPZWAHcV+WTPhkqJHQ==} + dependencies: + '@vue/compiler-dom': 3.2.47 + '@vue/compiler-sfc': 3.2.47 + '@vue/runtime-dom': 3.2.47 + '@vue/server-renderer': 3.2.47(vue@3.2.47) + '@vue/shared': 3.2.47 + + /which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + dependencies: + isexe: 2.0.0 + dev: true + + /word-wrap@1.2.3: + resolution: {integrity: sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==} + engines: {node: '>=0.10.0'} + dev: true + + /wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + dev: true + + /xml-name-validator@4.0.0: + resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==} + engines: {node: '>=12'} + dev: true + + /yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + dev: true + + /yn@3.1.1: + resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} + engines: {node: '>=6'} + dev: true + + /yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + dev: true diff --git a/Epsilon.Host.Frontend/src/App.vue b/Epsilon.Host.Frontend/src/App.vue new file mode 100644 index 00000000..5e1bb628 --- /dev/null +++ b/Epsilon.Host.Frontend/src/App.vue @@ -0,0 +1,3 @@ + diff --git a/Epsilon.Host.Frontend/src/assets/vite.svg b/Epsilon.Host.Frontend/src/assets/vite.svg new file mode 100644 index 00000000..e7b8dfb1 --- /dev/null +++ b/Epsilon.Host.Frontend/src/assets/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Epsilon.Host.Frontend/src/assets/vue.svg b/Epsilon.Host.Frontend/src/assets/vue.svg new file mode 100644 index 00000000..770e9d33 --- /dev/null +++ b/Epsilon.Host.Frontend/src/assets/vue.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Epsilon.Host.Frontend/src/components/CompetenceGraph.vue b/Epsilon.Host.Frontend/src/components/CompetenceGraph.vue new file mode 100644 index 00000000..44185abb --- /dev/null +++ b/Epsilon.Host.Frontend/src/components/CompetenceGraph.vue @@ -0,0 +1,115 @@ + + + diff --git a/Epsilon.Host.Frontend/src/components/CompetenceProfile.vue b/Epsilon.Host.Frontend/src/components/CompetenceProfile.vue new file mode 100644 index 00000000..2b36945e --- /dev/null +++ b/Epsilon.Host.Frontend/src/components/CompetenceProfile.vue @@ -0,0 +1,104 @@ + + + + + diff --git a/Epsilon.Host.Frontend/src/components/CompetenceProfileLegend.vue b/Epsilon.Host.Frontend/src/components/CompetenceProfileLegend.vue new file mode 100644 index 00000000..0ff197a7 --- /dev/null +++ b/Epsilon.Host.Frontend/src/components/CompetenceProfileLegend.vue @@ -0,0 +1,43 @@ + + + + + diff --git a/Epsilon.Host.Frontend/src/components/EnrollmentTermButtons.vue b/Epsilon.Host.Frontend/src/components/EnrollmentTermButtons.vue new file mode 100644 index 00000000..19b3b764 --- /dev/null +++ b/Epsilon.Host.Frontend/src/components/EnrollmentTermButtons.vue @@ -0,0 +1,55 @@ + + + + + diff --git a/Epsilon.Host.Frontend/src/components/KPIMatrix.vue b/Epsilon.Host.Frontend/src/components/KPIMatrix.vue new file mode 100644 index 00000000..ffafaa3c --- /dev/null +++ b/Epsilon.Host.Frontend/src/components/KPIMatrix.vue @@ -0,0 +1,69 @@ + + + + + diff --git a/Epsilon.Host.Frontend/src/components/PersonalDevelopmentGraph.vue b/Epsilon.Host.Frontend/src/components/PersonalDevelopmentGraph.vue new file mode 100644 index 00000000..6190ea02 --- /dev/null +++ b/Epsilon.Host.Frontend/src/components/PersonalDevelopmentGraph.vue @@ -0,0 +1,122 @@ + + + diff --git a/Epsilon.Host.Frontend/src/components/RoundLoader.vue b/Epsilon.Host.Frontend/src/components/RoundLoader.vue new file mode 100644 index 00000000..67ed62ee --- /dev/null +++ b/Epsilon.Host.Frontend/src/components/RoundLoader.vue @@ -0,0 +1,39 @@ + + + + + diff --git a/Epsilon.Host.Frontend/src/logic/Api.ts b/Epsilon.Host.Frontend/src/logic/Api.ts new file mode 100644 index 00000000..c04b7680 --- /dev/null +++ b/Epsilon.Host.Frontend/src/logic/Api.ts @@ -0,0 +1,448 @@ +/* eslint-disable */ +/* tslint:disable */ +/* + * --------------------------------------------------------------- + * ## THIS FILE WAS GENERATED VIA SWAGGER-TYPESCRIPT-API ## + * ## ## + * ## AUTHOR: acacode ## + * ## SOURCE: https://github.com/acacode/swagger-typescript-api ## + * --------------------------------------------------------------- + */ + +export interface Activity { + /** @format int32 */ + id?: number; + name?: string | null; + color?: string | null; +} + +export interface ArchitectureLayer { + /** @format int32 */ + id?: number; + name?: string | null; + shortName?: string | null; + color?: string | null; +} + +export interface CompetenceProfile { + hboIDomain?: IHboIDomain; + professionalTaskOutcomes?: ProfessionalTaskResult[] | null; + professionalSkillOutcomes?: ProfessionalSkillResult[] | null; + terms?: EnrollmentTerm[] | null; + decayingAveragesPerTask?: DecayingAveragePerLayer[] | null; + decayingAveragesPerSkill?: DecayingAveragePerSkill[] | null; +} + +export interface DecayingAveragePerActivity { + /** @format int32 */ + activity?: number; + /** @format double */ + decayingAverage?: number; +} + +export interface DecayingAveragePerLayer { + /** @format int32 */ + architectureLayer?: number; + layerActivities?: DecayingAveragePerActivity[] | null; +} + +export interface DecayingAveragePerSkill { + /** @format int32 */ + skill?: number; + /** @format double */ + decayingAverage?: number; +} + +export interface EnrollmentTerm { + name?: string | null; + /** @format date-time */ + start_at?: string | null; + /** @format date-time */ + end_at?: string | null; +} + +export interface IHboIDomain { + architectureLayers?: ArchitectureLayer[] | null; + activities?: Activity[] | null; + professionalSkills?: ProfessionalSkill[] | null; + masteryLevels?: MasteryLevel[] | null; +} + +export interface MasteryLevel { + /** @format int32 */ + id?: number; + /** @format int32 */ + level?: number; + color?: string | null; +} + +export interface ProfessionalSkill { + /** @format int32 */ + id?: number; + name?: string | null; + shortName?: string | null; + color?: string | null; +} + +export interface ProfessionalSkillResult { + /** @format int32 */ + skill?: number; + /** @format int32 */ + masteryLevel?: number; + /** @format double */ + grade?: number; + /** @format date-time */ + assessedAt?: string; +} + +export interface ProfessionalTaskResult { + /** @format int32 */ + architectureLayer?: number; + /** @format int32 */ + activity?: number; + /** @format int32 */ + masteryLevel?: number; + /** @format double */ + grade?: number; + /** @format date-time */ + assessedAt?: string; +} + +export type QueryParamsType = Record; +export type ResponseFormat = keyof Omit; + +export interface FullRequestParams extends Omit { + /** set parameter to `true` for call `securityWorker` for this request */ + secure?: boolean; + /** request path */ + path: string; + /** content type of request body */ + type?: ContentType; + /** query params */ + query?: QueryParamsType; + /** format of response (i.e. response.json() -> format: "json") */ + format?: ResponseFormat; + /** request body */ + body?: unknown; + /** base url */ + baseUrl?: string; + /** request cancellation token */ + cancelToken?: CancelToken; +} + +export type RequestParams = Omit< + FullRequestParams, + "body" | "method" | "query" | "path" +>; + +export interface ApiConfig { + baseUrl?: string; + baseApiParams?: Omit; + securityWorker?: ( + securityData: SecurityDataType | null + ) => Promise | RequestParams | void; + customFetch?: typeof fetch; +} + +export interface HttpResponse + extends Response { + data: D; + error: E; +} + +type CancelToken = Symbol | string | number; + +export enum ContentType { + Json = "application/json", + FormData = "multipart/form-data", + UrlEncoded = "application/x-www-form-urlencoded", + Text = "text/plain", +} + +export class HttpClient { + public baseUrl: string = "https://localhost:7084"; + private securityData: SecurityDataType | null = null; + private securityWorker?: ApiConfig["securityWorker"]; + private abortControllers = new Map(); + private customFetch = (...fetchParams: Parameters) => + fetch(...fetchParams); + + private baseApiParams: RequestParams = { + credentials: "same-origin", + headers: {}, + redirect: "follow", + referrerPolicy: "no-referrer", + }; + + constructor(apiConfig: ApiConfig = {}) { + Object.assign(this, apiConfig); + } + + public setSecurityData = (data: SecurityDataType | null) => { + this.securityData = data; + }; + + protected encodeQueryParam(key: string, value: any) { + const encodedKey = encodeURIComponent(key); + return `${encodedKey}=${encodeURIComponent( + typeof value === "number" ? value : `${value}` + )}`; + } + + protected addQueryParam(query: QueryParamsType, key: string) { + return this.encodeQueryParam(key, query[key]); + } + + protected addArrayQueryParam(query: QueryParamsType, key: string) { + const value = query[key]; + return value.map((v: any) => this.encodeQueryParam(key, v)).join("&"); + } + + protected toQueryString(rawQuery?: QueryParamsType): string { + const query = rawQuery || {}; + const keys = Object.keys(query).filter( + (key) => "undefined" !== typeof query[key] + ); + return keys + .map((key) => + Array.isArray(query[key]) + ? this.addArrayQueryParam(query, key) + : this.addQueryParam(query, key) + ) + .join("&"); + } + + protected addQueryParams(rawQuery?: QueryParamsType): string { + const queryString = this.toQueryString(rawQuery); + return queryString ? `?${queryString}` : ""; + } + + private contentFormatters: Record any> = { + [ContentType.Json]: (input: any) => + input !== null && + (typeof input === "object" || typeof input === "string") + ? JSON.stringify(input) + : input, + [ContentType.Text]: (input: any) => + input !== null && typeof input !== "string" + ? JSON.stringify(input) + : input, + [ContentType.FormData]: (input: any) => + Object.keys(input || {}).reduce((formData, key) => { + const property = input[key]; + formData.append( + key, + property instanceof Blob + ? property + : typeof property === "object" && property !== null + ? JSON.stringify(property) + : `${property}` + ); + return formData; + }, new FormData()), + [ContentType.UrlEncoded]: (input: any) => this.toQueryString(input), + }; + + protected mergeRequestParams( + params1: RequestParams, + params2?: RequestParams + ): RequestParams { + return { + ...this.baseApiParams, + ...params1, + ...(params2 || {}), + headers: { + ...(this.baseApiParams.headers || {}), + ...(params1.headers || {}), + ...((params2 && params2.headers) || {}), + }, + }; + } + + protected createAbortSignal = ( + cancelToken: CancelToken + ): AbortSignal | undefined => { + if (this.abortControllers.has(cancelToken)) { + const abortController = this.abortControllers.get(cancelToken); + if (abortController) { + return abortController.signal; + } + return void 0; + } + + const abortController = new AbortController(); + this.abortControllers.set(cancelToken, abortController); + return abortController.signal; + }; + + public abortRequest = (cancelToken: CancelToken) => { + const abortController = this.abortControllers.get(cancelToken); + + if (abortController) { + abortController.abort(); + this.abortControllers.delete(cancelToken); + } + }; + + public request = async ({ + body, + secure, + path, + type, + query, + format, + baseUrl, + cancelToken, + ...params + }: FullRequestParams): Promise> => { + const secureParams = + ((typeof secure === "boolean" + ? secure + : this.baseApiParams.secure) && + this.securityWorker && + (await this.securityWorker(this.securityData))) || + {}; + const requestParams = this.mergeRequestParams(params, secureParams); + const queryString = query && this.toQueryString(query); + const payloadFormatter = + this.contentFormatters[type || ContentType.Json]; + const responseFormat = format || requestParams.format; + + return this.customFetch( + `${baseUrl || this.baseUrl || ""}${path}${ + queryString ? `?${queryString}` : "" + }`, + { + ...requestParams, + headers: { + ...(requestParams.headers || {}), + ...(type && type !== ContentType.FormData + ? { "Content-Type": type } + : {}), + }, + signal: cancelToken + ? this.createAbortSignal(cancelToken) + : requestParams.signal, + body: + typeof body === "undefined" || body === null + ? null + : payloadFormatter(body), + } + ).then(async (response) => { + const r = response as HttpResponse; + r.data = null as unknown as T; + r.error = null as unknown as E; + + const data = !responseFormat + ? r + : await response[responseFormat]() + .then((data) => { + if (r.ok) { + r.data = data; + } else { + r.error = data; + } + return r; + }) + .catch((e) => { + r.error = e; + return r; + }); + + if (cancelToken) { + this.abortControllers.delete(cancelToken); + } + + if (!response.ok) throw data; + return data; + }); + }; +} + +/** + * @title Epsilon.Host.WebApi + * @version 1.0 + */ +export class Api< + SecurityDataType extends unknown +> extends HttpClient { + auth = { + /** + * No description + * + * @tags Auth + * @name ChallengeList + * @request GET:/Auth/challenge + */ + challengeList: (params: RequestParams = {}) => + this.request({ + path: `/Auth/challenge`, + method: "GET", + ...params, + }), + + /** + * No description + * + * @tags Auth + * @name CallbackList + * @request GET:/Auth/callback + */ + callbackList: (params: RequestParams = {}) => + this.request({ + path: `/Auth/callback`, + method: "GET", + ...params, + }), + }; + component = { + /** + * No description + * + * @tags Component + * @name ComponentDetail + * @request GET:/Component/{componentName} + */ + componentDetail: ( + componentName: string, + query?: { + /** @format date-time */ + startDate?: string; + /** @format date-time */ + endDate?: string; + }, + params: RequestParams = {} + ) => + this.request({ + path: `/Component/${componentName}`, + method: "GET", + query: query, + format: "json", + ...params, + }), + }; + document = { + /** + * No description + * + * @tags Document + * @name WordList + * @request GET:/Document/word + */ + wordList: ( + query?: { + /** @format date-time */ + startDate?: string; + /** @format date-time */ + endDate?: string; + }, + params: RequestParams = {} + ) => + this.request({ + path: `/Document/word`, + method: "GET", + query: query, + ...params, + }), + }; +} diff --git a/Epsilon.Host.Frontend/src/logic/DecayingAverageLogic.ts b/Epsilon.Host.Frontend/src/logic/DecayingAverageLogic.ts new file mode 100644 index 00000000..186262b9 --- /dev/null +++ b/Epsilon.Host.Frontend/src/logic/DecayingAverageLogic.ts @@ -0,0 +1,199 @@ +import { + IHboIDomain, + ProfessionalSkillResult, + ProfessionalTaskResult, +} from "/@/logic/Api" + +export interface DecayingAveragePerActivity { + outcome: number + activity: number + decayingAverage: number +} + +export interface DecayingAveragePerLayer { + architectureLayer: number + layerActivities: DecayingAveragePerActivity[] +} + +export interface DecayingAveragePerSkill { + skill: number + decayingAverage: number + masteryLevel: number +} + +export class DecayingAverageLogic { + /** + * Calculate the averages for each skill type + * @param taskResults + * @param domain + * @constructor + */ + public static getAverageSkillOutcomeScores( + taskResults: ProfessionalSkillResult[], + domain: IHboIDomain + ): DecayingAveragePerSkill[] { + const listOfResults = Object.entries( + this.groupBy(taskResults, (r) => r.outcomeId as unknown as string) + ).map(([, j]) => { + return { + decayingAverage: this.getDecayingAverageFromOneOutcomeType(j), + skill: j.at(0)?.skill, + masteryLevel: j + .sort((a) => a.masteryLevel as never as number) + .at(0)?.masteryLevel, + } as DecayingAveragePerSkill + }) + + return domain.professionalSkills?.map((s) => { + let score = 0.0 + const filteredResults = listOfResults.filter( + (r) => r.skill === s.id + ) + filteredResults.map((result) => { + score += result.decayingAverage + }) + return { + decayingAverage: score / filteredResults.length, + skill: s.id, + masteryLevel: filteredResults + .sort((a) => a.masteryLevel as never as number) + .at(0)?.masteryLevel, + } as DecayingAveragePerSkill + }) as DecayingAveragePerSkill[] + } + + /** + * Calculate the averages for each task type divided in architecture layers. + * @param taskResults + * @param domain + * @constructor + */ + public static getAverageTaskOutcomeScores( + taskResults: ProfessionalTaskResult[], + domain: IHboIDomain + ): DecayingAveragePerLayer[] { + const canvasDecaying = this.getDecayingAverageForAllOutcomes( + taskResults, + domain + ) + return domain.architectureLayers?.map((layer) => { + return { + architectureLayer: layer.id, + layerActivities: domain.activities?.map((activity) => { + let totalScoreActivity = 0 + let totalScoreArchitectureActivity = 0 + let amountOfActivities = 0 + + //Calculate the total score from activity + canvasDecaying.map((l) => + l.layerActivities + ?.filter((la) => la.activity === activity.id) + .map( + (la) => + (totalScoreActivity += + la.decayingAverage && + amountOfActivities++) + ) + ) + + //Calculate the total score from activity inside this architecture layer + canvasDecaying + .filter((l) => l.architectureLayer === layer.id) + .map((l) => + l.layerActivities + ?.filter((la) => la.activity === activity.id) + .map( + (la) => + (totalScoreArchitectureActivity += + la.decayingAverage) + ) + ) + + return { + activity: activity.id, + decayingAverage: + ((totalScoreActivity / amountOfActivities) * + totalScoreArchitectureActivity) / + totalScoreActivity, + } as DecayingAveragePerActivity + }), + } + }) as DecayingAveragePerLayer[] + } + + /** + * Calculate average of given tasks divided in architectural layers + * @param taskResults + * @param domain + * @constructor + * @private + */ + private static getDecayingAverageForAllOutcomes( + taskResults: ProfessionalTaskResult[], + domain: IHboIDomain + ): DecayingAveragePerLayer[] { + return domain.architectureLayers?.map((l) => { + return { + architectureLayer: l.id, + layerActivities: Object.entries( + this.groupBy( + //Ensure that given results are only relined on the architecture that is currently being used. + taskResults.filter( + (layer) => layer.architectureLayer === l.id + ), + (r) => r.outcomeId as unknown as string + ) + ).map(([i, j]) => { + //From all selected outcomes calculate the decaying average, Give outcome id and activity layer. + return { + outcome: i, + activity: j.at(0)?.activity, + decayingAverage: + this.getDecayingAverageFromOneOutcomeType(j), + } + }) as unknown as DecayingAveragePerActivity[], + } + }) as DecayingAveragePerLayer[] + } + + /** + * Calculate decaying average described by Canvas: https://community.canvaslms.com/t5/Canvas-Basics-Guide/What-are-Outcomes/ta-p/75#decaying_average + * !IMPORTANT, The list of results will always have to be a list of the same outcome id. Not a list of equal activity and architecture layer. + * @param results + * @constructor + * @private + */ + private static getDecayingAverageFromOneOutcomeType( + results: ProfessionalTaskResult[] | ProfessionalSkillResult[] + ): number { + let totalGradeScore = 0.0 + + const recentResult = results.reverse().pop() + if (recentResult && recentResult.grade) { + if (results.length > 0) { + results.forEach( + (r) => (totalGradeScore += r.grade ? r.grade : 0) + ) + totalGradeScore = + (totalGradeScore / results.length) * 0.35 + + recentResult.grade * 0.65 + } else { + totalGradeScore = recentResult.grade + } + } + + return totalGradeScore + } + + private static groupBy( + arr: T[], + fn: (item: T) => number | string + ): Record { + return arr.reduce>((prev, curr) => { + const groupKey = fn(curr) + const group = prev[groupKey] || [] + group.push(curr) + return { ...prev, [groupKey]: group } + }, {}) + } +} diff --git a/Epsilon.Host.Frontend/src/main.ts b/Epsilon.Host.Frontend/src/main.ts new file mode 100644 index 00000000..67b860a0 --- /dev/null +++ b/Epsilon.Host.Frontend/src/main.ts @@ -0,0 +1,6 @@ +import { createApp } from "vue" +import router from "./router" +import "./style.css" +import App from "./App.vue" + +createApp(App).use(router).mount("#app") diff --git a/Epsilon.Host.Frontend/src/router/index.ts b/Epsilon.Host.Frontend/src/router/index.ts new file mode 100644 index 00000000..6e2c32ce --- /dev/null +++ b/Epsilon.Host.Frontend/src/router/index.ts @@ -0,0 +1,21 @@ +import { createRouter, createWebHistory } from "vue-router" +import PerformanceDashboard from "@/views/PerformanceDashboard.vue" +import AuthorizeUser from "@/views/AuthorizeUser.vue" + +const routes = [ + { + path: "/", + name: "PerformanceDashboard", + component: PerformanceDashboard, + }, + { + path: "/auth", + name: "Authorize", + component: AuthorizeUser, + }, +] +const router = createRouter({ + history: createWebHistory(import.meta.env.BASE_URL), + routes, +}) +export default router diff --git a/Epsilon.Host.Frontend/src/shimd-vue.d.ts b/Epsilon.Host.Frontend/src/shimd-vue.d.ts new file mode 100644 index 00000000..b9f00b3c --- /dev/null +++ b/Epsilon.Host.Frontend/src/shimd-vue.d.ts @@ -0,0 +1 @@ +declare module "*.vue" diff --git a/Epsilon.Host.Frontend/src/style.css b/Epsilon.Host.Frontend/src/style.css new file mode 100644 index 00000000..b3a72ebf --- /dev/null +++ b/Epsilon.Host.Frontend/src/style.css @@ -0,0 +1,92 @@ +:root { + font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; + line-height: 1.5; + font-weight: 400; + + color: #333; + background-color: #ffffff; + + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + -webkit-text-size-adjust: 100%; +} + +a { + font-weight: 500; + color: #646cff; + text-decoration: inherit; +} + +a:hover { + color: #535bf2; +} + +a { + font-weight: 500; + color: #646cff; + text-decoration: inherit; +} + +a:hover { + color: #535bf2; +} + +body { + margin: 0; + display: flex; + min-width: 320px; +} + +h1 { + font-size: 3.2em; + line-height: 1.1; +} + +button { + border-radius: 8px; + border: 1px solid transparent; + padding: 0.6em 1.2em; + font-size: 1em; + font-weight: 500; + font-family: inherit; + background-color: #1a1a1a; + cursor: pointer; + transition: border-color 0.25s; +} + +button:hover { + border-color: #646cff; +} + +button:focus, +button:focus-visible { + outline: 4px auto -webkit-focus-ring-color; +} + +.card { + padding: 2em; +} + +#app { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + text-align: center; +} + +@media (prefers-color-scheme: light) { + :root { + color: #213547; + background-color: #ffffff; + } + + a:hover { + color: #747bff; + } + + button { + background-color: #f9f9f9; + } +} diff --git a/Epsilon.Host.Frontend/src/views/Authorize.vue b/Epsilon.Host.Frontend/src/views/Authorize.vue new file mode 100644 index 00000000..9182fef0 --- /dev/null +++ b/Epsilon.Host.Frontend/src/views/Authorize.vue @@ -0,0 +1,33 @@ + + + + + diff --git a/Epsilon.Host.Frontend/src/views/AuthorizeUser.vue b/Epsilon.Host.Frontend/src/views/AuthorizeUser.vue new file mode 100644 index 00000000..25523c8c --- /dev/null +++ b/Epsilon.Host.Frontend/src/views/AuthorizeUser.vue @@ -0,0 +1,31 @@ + + + + + diff --git a/Epsilon.Host.Frontend/src/views/PerformanceDashboard.vue b/Epsilon.Host.Frontend/src/views/PerformanceDashboard.vue new file mode 100644 index 00000000..ed466c4d --- /dev/null +++ b/Epsilon.Host.Frontend/src/views/PerformanceDashboard.vue @@ -0,0 +1,99 @@ + + + + + diff --git a/Epsilon.Host.Frontend/tsconfig.json b/Epsilon.Host.Frontend/tsconfig.json new file mode 100644 index 00000000..4f16565f --- /dev/null +++ b/Epsilon.Host.Frontend/tsconfig.json @@ -0,0 +1,34 @@ +{ + "compilerOptions": { + "target": "esnext", + "module": "esnext", + "moduleResolution": "node", + "strict": true, + "jsx": "preserve", + "importHelpers": true, + "skipLibCheck": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "sourceMap": true, + "baseUrl": ".", + "paths": { + "/@/*": [ // / to begin with. + "src/*" + ] + }, + "lib": [ + "esnext", + "dom", + "dom.iterable", + "scripthost" + ] + }, + "include": [ + "src/**/*.ts", + "src/**/*.tsx", + "src/**/*.vue", + ], + "exclude": [ + "node_modules" + ] +} \ No newline at end of file diff --git a/Epsilon.Host.Frontend/vite.config.ts b/Epsilon.Host.Frontend/vite.config.ts new file mode 100644 index 00000000..35173825 --- /dev/null +++ b/Epsilon.Host.Frontend/vite.config.ts @@ -0,0 +1,25 @@ +import { defineConfig, loadEnv, UserConfigExport } from "vite" +import vue from "@vitejs/plugin-vue" +import { resolve } from "path" +import { readFileSync } from "fs" + +export default ({ mode }: { mode: string }): UserConfigExport => { + process.env = { ...process.env, ...loadEnv(mode, process.cwd()) } + const certificate = process.env.VITE_SSL_CRT_FILE + const key = process.env.VITE_SSL_KEY_FILE + + return defineConfig({ + resolve: { + alias: { + "@": resolve(__dirname, "src"), + }, + }, + server: { + https: { + cert: certificate ? readFileSync(certificate) : undefined, + key: key ? readFileSync(key) : undefined, + }, + }, + plugins: [vue()], + }) +} diff --git a/Epsilon.Host.WebApi/Controllers/AuthController.cs b/Epsilon.Host.WebApi/Controllers/AuthController.cs new file mode 100644 index 00000000..1350e037 --- /dev/null +++ b/Epsilon.Host.WebApi/Controllers/AuthController.cs @@ -0,0 +1,28 @@ +using System.Net.Mime; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Mvc; + +namespace Epsilon.Host.WebApi.Controllers; + +[ApiController] +[Route("[controller]")] +public class AuthController : ControllerBase +{ + [HttpGet("challenge")] + public IActionResult ProcessChallenge() + { + var properties = new AuthenticationProperties + { + RedirectUri = "/auth/callback", + }; + + return Challenge(properties, "canvas-docker"); + } + + [HttpGet("callback")] + public IActionResult ProcessCallback() + { + // Close the login window popup + return Content("", MediaTypeNames.Text.Html); + } +} \ No newline at end of file diff --git a/Epsilon.Host.WebApi/Controllers/ComponentController.cs b/Epsilon.Host.WebApi/Controllers/ComponentController.cs new file mode 100644 index 00000000..862aa6c7 --- /dev/null +++ b/Epsilon.Host.WebApi/Controllers/ComponentController.cs @@ -0,0 +1,30 @@ +using Epsilon.Abstractions.Component; +using Epsilon.Abstractions.Service; +using Microsoft.AspNetCore.Mvc; + +namespace Epsilon.Host.WebApi.Controllers; + +[ApiController] +[Route("[controller]")] +public class ComponentController : ControllerBase +{ + private readonly ICompetenceComponentService _competenceComponentService; + + public ComponentController(ICompetenceComponentService competenceComponentService) + { + _competenceComponentService = competenceComponentService; + } + + [HttpGet("{componentName}")] + [Produces(typeof(CompetenceProfile))] + public async Task> GetCompetenceProfile(string componentName, DateTime startDate, DateTime endDate) + { + var component = await _competenceComponentService.GetComponent(componentName, startDate, endDate); + if (component == null) + { + return NotFound(); + } + + return Ok(component); + } +} \ No newline at end of file diff --git a/Epsilon.Host.WebApi/Controllers/DocumentController.cs b/Epsilon.Host.WebApi/Controllers/DocumentController.cs new file mode 100644 index 00000000..553328bf --- /dev/null +++ b/Epsilon.Host.WebApi/Controllers/DocumentController.cs @@ -0,0 +1,29 @@ +using Epsilon.Abstractions.Service; +using Microsoft.AspNetCore.Mvc; + +namespace Epsilon.Host.WebApi.Controllers; + +[ApiController] +[Route("[controller]")] +public class DocumentController : Controller +{ + private readonly ICompetenceDocumentService _competenceDocumentService; + + public DocumentController(ICompetenceDocumentService competenceDocumentService) + { + _competenceDocumentService = competenceDocumentService; + } + + [HttpGet("word")] + public async Task DownloadWordDocument(DateTime startDate, DateTime endDate) + { + var stream = new MemoryStream(); + await _competenceDocumentService.WriteDocument(stream, startDate, endDate); + + return File( + stream, + "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + "CompetenceDocument.docx" + ); + } +} \ No newline at end of file diff --git a/Epsilon.Host.WebApi/Epsilon.Host.WebApi.csproj b/Epsilon.Host.WebApi/Epsilon.Host.WebApi.csproj new file mode 100644 index 00000000..876338de --- /dev/null +++ b/Epsilon.Host.WebApi/Epsilon.Host.WebApi.csproj @@ -0,0 +1,23 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + + + Never + + + + diff --git a/Epsilon.Host.WebApi/Program.cs b/Epsilon.Host.WebApi/Program.cs new file mode 100644 index 00000000..bec0ec0f --- /dev/null +++ b/Epsilon.Host.WebApi/Program.cs @@ -0,0 +1,54 @@ +using Epsilon.Abstractions.Component; +using Epsilon.Abstractions.Service; +using Epsilon.Canvas; +using Epsilon.Component; +using Epsilon.Service; + +var builder = WebApplication.CreateBuilder(args); + +// Add services to the container. +var canvasConfiguration = builder.Configuration.GetSection("Canvas"); + +builder.Services.AddCors(options => +{ + options.AddDefaultPolicy(policy => + { + policy.WithOrigins(builder.Configuration["Lti:TargetUri"]) + .AllowCredentials(); + }); +}); + +builder.Services.AddControllers(); +// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle +builder.Services.AddEndpointsApiExplorer(); +builder.Services.AddSwaggerGen(); + +builder.Services.AddCanvas(canvasConfiguration); + +builder.Services.AddScoped(); +builder.Services.AddScoped(); + +builder.Services.AddComponentFetcher(); +builder.Services.AddComponentFetcher(); +builder.Services.AddComponentFetcher(); + +var app = builder.Build(); + +// Configure the HTTP request pipeline. +if (app.Environment.IsDevelopment()) +{ + app.UseSwaggerUI(); +} + +app.UseSwagger(); + + +app.UseHttpsRedirection(); + +app.UseCors(); + +app.UseAuthorization(); + +app.MapControllers(); + +app.Run(); \ No newline at end of file diff --git a/Epsilon.Host.WebApi/Properties/launchSettings.json b/Epsilon.Host.WebApi/Properties/launchSettings.json new file mode 100644 index 00000000..13617ef2 --- /dev/null +++ b/Epsilon.Host.WebApi/Properties/launchSettings.json @@ -0,0 +1,15 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "profiles": { + "Epsilon.Host.WebApi": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": false, + "launchUrl": "swagger", + "applicationUrl": "https://localhost:7084", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/Epsilon.Tests/Epsilon.Tests.csproj b/Epsilon.Tests/Epsilon.Tests.csproj index f23c3c35..21b261e1 100644 --- a/Epsilon.Tests/Epsilon.Tests.csproj +++ b/Epsilon.Tests/Epsilon.Tests.csproj @@ -15,9 +15,9 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive
- - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive all @@ -29,8 +29,8 @@ - - + + diff --git a/Epsilon.Tests/Usings.cs b/Epsilon.Tests/Usings.cs index 8c927eb7..e69de29b 100644 --- a/Epsilon.Tests/Usings.cs +++ b/Epsilon.Tests/Usings.cs @@ -1 +0,0 @@ -global using Xunit; \ No newline at end of file diff --git a/Epsilon.sln b/Epsilon.sln index 45b12d06..0689a3bb 100644 --- a/Epsilon.sln +++ b/Epsilon.sln @@ -1,10 +1,5 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.5.33414.496 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Epsilon.Cli", "Epsilon.Cli\Epsilon.Cli.csproj", "{358E6BB1-E2A2-4397-A831-A2194604D532}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Epsilon.Canvas", "Epsilon.Canvas\Epsilon.Canvas.csproj", "{AD6AB75F-D71B-4FDD-8B37-1FB547AAC753}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Epsilon.Canvas.Abstractions", "Epsilon.Canvas.Abstractions\Epsilon.Canvas.Abstractions.csproj", "{A8301F2C-F889-464F-9385-862BFB447435}" @@ -17,16 +12,14 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Epsilon.Abstractions", "Eps EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Epsilon.Tests", "Epsilon.Tests\Epsilon.Tests.csproj", "{4F5E4A10-5D0E-4C7D-B24C-33C9B6FA52CF}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Epsilon.Host.WebApi", "Epsilon.Host.WebApi\Epsilon.Host.WebApi.csproj", "{194C4770-0BCD-4EC2-BC7C-5D672A3B6557}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {358E6BB1-E2A2-4397-A831-A2194604D532}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {358E6BB1-E2A2-4397-A831-A2194604D532}.Debug|Any CPU.Build.0 = Debug|Any CPU - {358E6BB1-E2A2-4397-A831-A2194604D532}.Release|Any CPU.ActiveCfg = Release|Any CPU - {358E6BB1-E2A2-4397-A831-A2194604D532}.Release|Any CPU.Build.0 = Release|Any CPU {AD6AB75F-D71B-4FDD-8B37-1FB547AAC753}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {AD6AB75F-D71B-4FDD-8B37-1FB547AAC753}.Debug|Any CPU.Build.0 = Debug|Any CPU {AD6AB75F-D71B-4FDD-8B37-1FB547AAC753}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -51,11 +44,17 @@ Global {4F5E4A10-5D0E-4C7D-B24C-33C9B6FA52CF}.Debug|Any CPU.Build.0 = Debug|Any CPU {4F5E4A10-5D0E-4C7D-B24C-33C9B6FA52CF}.Release|Any CPU.ActiveCfg = Release|Any CPU {4F5E4A10-5D0E-4C7D-B24C-33C9B6FA52CF}.Release|Any CPU.Build.0 = Release|Any CPU + {194C4770-0BCD-4EC2-BC7C-5D672A3B6557}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {194C4770-0BCD-4EC2-BC7C-5D672A3B6557}.Debug|Any CPU.Build.0 = Debug|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {63F9A5D2-3979-4C37-9A45-C0AF94B7FEE9} + {194C4770-0BCD-4EC2-BC7C-5D672A3B6557}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {194C4770-0BCD-4EC2-BC7C-5D672A3B6557}.Debug|Any CPU.Build.0 = Debug|Any CPU + {194C4770-0BCD-4EC2-BC7C-5D672A3B6557}.Release|Any CPU.ActiveCfg = Release|Any CPU + {194C4770-0BCD-4EC2-BC7C-5D672A3B6557}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection -EndGlobal +EndGlobal \ No newline at end of file diff --git a/Epsilon/Component/CompetenceProfileCompetenceComponentFetcher.cs b/Epsilon/Component/CompetenceProfileCompetenceComponentFetcher.cs new file mode 100644 index 00000000..ce422ee6 --- /dev/null +++ b/Epsilon/Component/CompetenceProfileCompetenceComponentFetcher.cs @@ -0,0 +1,148 @@ +using Epsilon.Abstractions.Component; +using Epsilon.Abstractions.Model; +using Epsilon.Canvas.Abstractions.Model; +using Epsilon.Canvas.Abstractions.Model.GraphQl; +using Epsilon.Canvas.Abstractions.Service; +using Microsoft.Extensions.Configuration; + +namespace Epsilon.Component; + +public class CompetenceProfileCompetenceComponentFetcher : CompetenceComponentFetcher +{ + private const string GetAllUserCoursesSubmissionOutcomes = @" + query MyQuery { + allCourses { + submissionsConnection(studentIds: $studentIds) { + nodes { + submissionHistoriesConnection { + nodes { + rubricAssessmentsConnection { + nodes { + assessmentRatings { + criterion { + outcome { + _id + } + masteryPoints + } + points + } + } + } + attempt + submittedAt + } + } + postedAt + } + } + } + } + "; + + private readonly IConfiguration _configuration; + private readonly IGraphQlHttpService _graphQlService; + private readonly IAccountHttpService _accountHttpService; + + public CompetenceProfileCompetenceComponentFetcher( + IGraphQlHttpService graphQlService, + IAccountHttpService accountHttpService, + IConfiguration configuration + ) + { + _graphQlService = graphQlService; + _accountHttpService = accountHttpService; + _configuration = configuration; + } + + public override async Task Fetch(DateTime startDate, DateTime endDate) + { + var studentId = _configuration["Canvas:StudentId"]; + var outcomesQuery = GetAllUserCoursesSubmissionOutcomes.Replace("$studentIds", $"{studentId}", StringComparison.InvariantCulture); + + var outcomes = await _graphQlService.Query(outcomesQuery); + var terms = await _accountHttpService.GetAllTerms(1); + + var competenceProfile = ConvertToComponent(outcomes, new HboIDomain2018(), terms); + + return competenceProfile; + } + + private static CompetenceProfile ConvertToComponent( + CanvasGraphQlQueryResponse queryResponse, + IHboIDomain domain, + IEnumerable enrollmentTerms + ) + { + var taskResults = new List(); + var professionalResults = new List(); + + foreach (var course in queryResponse.Data.Courses) + { + foreach (var submissionsConnection in course.SubmissionsConnection.Nodes.Where(static s => + s.PostedAt != null)) + { + var submission = submissionsConnection.SubmissionsHistories.Nodes + .Where(static h => h.RubricAssessments.Nodes.Any()) + .OrderByDescending(static h => h.SubmittedAt) + .MaxBy(static h => h.Attempt); + + if (submission != null) + { + var rubricAssessments = submission.RubricAssessments.Nodes; + + foreach (var assessmentRating in rubricAssessments.SelectMany(static rubricAssessment => + rubricAssessment.AssessmentRatings.Where(static ar => + ar is + { + Points: not null, Criterion.MasteryPoints: not null, + Criterion.Outcome: not null, + } && ar.Points >= ar.Criterion.MasteryPoints))) + { + if (FhictConstants.ProfessionalTasks.TryGetValue(assessmentRating.Criterion.Outcome.Id, out var professionalTask)) + { + taskResults.Add( + new ProfessionalTaskResult( + assessmentRating.Criterion.Outcome.Id, + professionalTask.Layer, + professionalTask.Activity, + professionalTask.MasteryLevel, + assessmentRating.Points!.Value, + submission.SubmittedAt!.Value + ) + ); + } + else if (FhictConstants.ProfessionalSkills.TryGetValue(assessmentRating.Criterion.Outcome.Id, out var professionalSkill)) + { + professionalResults.Add( + new ProfessionalSkillResult( + assessmentRating.Criterion.Outcome.Id, + professionalSkill.Skill, + professionalSkill.MasteryLevel, + assessmentRating.Points!.Value, + submission.SubmittedAt!.Value + ) + ); + } + } + } + } + } + + var filteredTerms = enrollmentTerms + .Where(static term => term is { StartAt: not null, EndAt: not null, }) + .Where(term => + taskResults.Any(taskOutcome => taskOutcome.SubmittedAt >= term.StartAt && taskOutcome.SubmittedAt <= term.EndAt) + || professionalResults.Any(skillOutcome => skillOutcome.SubmittedAt > term.StartAt && skillOutcome.SubmittedAt < term.EndAt) + ) + .Distinct() + .OrderByDescending(static term => term.StartAt); + + return new CompetenceProfile( + domain, + taskResults.OrderByDescending(static task => task.SubmittedAt), + professionalResults.OrderByDescending(static skill => skill.SubmittedAt), + filteredTerms + ); + } +} \ No newline at end of file diff --git a/Epsilon/Component/ComponentServiceCollectionExtensions.cs b/Epsilon/Component/ComponentServiceCollectionExtensions.cs new file mode 100644 index 00000000..0a867056 --- /dev/null +++ b/Epsilon/Component/ComponentServiceCollectionExtensions.cs @@ -0,0 +1,17 @@ +using Epsilon.Abstractions.Component; +using Microsoft.Extensions.DependencyInjection; + +namespace Epsilon.Component; + +public static class ComponentServiceCollectionExtensions +{ + public static IServiceCollection AddComponentFetcher(this IServiceCollection services) + where TFetcher : class, ICompetenceComponentFetcher, ICompetenceComponentFetcher + where TComponent : ICompetenceComponent + { + services.AddScoped(); + services.AddScoped, TFetcher>(); + + return services; + } +} \ No newline at end of file diff --git a/Epsilon/Component/KpiMatrixComponentFetcher.cs b/Epsilon/Component/KpiMatrixComponentFetcher.cs new file mode 100644 index 00000000..22161df9 --- /dev/null +++ b/Epsilon/Component/KpiMatrixComponentFetcher.cs @@ -0,0 +1,137 @@ +using Epsilon.Abstractions.Component; +using Epsilon.Canvas.Abstractions.Model; +using Epsilon.Canvas.Abstractions.Model.GraphQl; +using Epsilon.Canvas.Abstractions.Service; +using Microsoft.Extensions.Configuration; + +namespace Epsilon.Component; + +public class KpiMatrixComponentFetcher : CompetenceComponentFetcher +{ + private const string GetUserKpiMatrixOutcomes = @" + query GetUserKpiMatrixOutcomes { + allCourses { + submissionsConnection(studentIds: $studentIds) { + nodes { + submissionHistoriesConnection { + nodes { + rubricAssessmentsConnection { + nodes { + assessmentRatings { + criterion { + outcome { + _id + title + } + masteryPoints + } + points + } + } + } + attempt + submittedAt + assignment { + name + rubric { + criteria { + outcome { + title + _id + masteryPoints + } + } + } + } + } + } + postedAt + } + } + } + } + "; + + private readonly IConfiguration _configuration; + private readonly IGraphQlHttpService _graphQlService; + + public KpiMatrixComponentFetcher( + IGraphQlHttpService graphQlService, + IConfiguration configuration + ) + { + _graphQlService = graphQlService; + _configuration = configuration; + } + + public override async Task Fetch(DateTime startDate, DateTime endDate) + { + var studentId = _configuration["Canvas:StudentId"]; + var outcomesQuery = GetUserKpiMatrixOutcomes.Replace("$studentIds", $"{studentId}", StringComparison.InvariantCultureIgnoreCase); + var outcomes = await _graphQlService.Query(outcomesQuery); + + + var assignments = new List(); + foreach (var course in outcomes.Data!.Courses!) + { + foreach (var submissionsConnection in course.SubmissionsConnection!.Nodes) + { + var submission = submissionsConnection.SubmissionsHistories.Nodes + .Where(sub => sub.SubmittedAt > startDate && sub.SubmittedAt < endDate) + .MaxBy(static h => h.Attempt); + + if (submission is + { + Assignment.Rubric: not null, + RubricAssessments.Nodes: not null, + }) + { + var rubricCriteria = submission.Assignment.Rubric.Criteria?.ToArray(); + var kpiMatrixOutcomes = new List(); + + if (rubricCriteria != null) + { + foreach (var outcome in rubricCriteria.Select(static criteria => criteria.Outcome)) + { + //Validate that outcome is a HboI KPI + if (outcome != null + && (FhictConstants.ProfessionalTasks.ContainsKey(outcome.Id) || FhictConstants.ProfessionalSkills.ContainsKey(outcome.Id)) + && rubricCriteria.Any()) + { + var assessmentRatings = submission.RubricAssessments.Nodes.FirstOrDefault()?.AssessmentRatings; + var gradeStatus = GetGradeStatus(assessmentRatings?.FirstOrDefault(ar => ar?.Criterion?.Outcome?.Id == outcome.Id)); + + kpiMatrixOutcomes.Add(new KpiMatrixOutcome(outcome.Id, outcome.Title, KpiMatrixCollection.DefaultGradeStatus[gradeStatus])); + } + } + } + + if (kpiMatrixOutcomes.Count > 0 && submission.Assignment.Name != null) + { + var assignment = new KpiMatrixAssignment(submission.Assignment.Name, kpiMatrixOutcomes); + assignments.Add(assignment); + } + } + } + } + + return new KpiMatrixCollection(assignments, KpiMatrixCollection.DefaultGradeStatus); + } + + private static OutcomeGradeStatus GetGradeStatus(AssessmentRating? rating) + { + if (rating != null) + { + if (rating.Points != null) + { + return rating.IsMastery + ? OutcomeGradeStatus.Mastered + : OutcomeGradeStatus.NotMastered; + } + + return OutcomeGradeStatus.NotGraded; + } + + return OutcomeGradeStatus.NotAssessed; + } +} \ No newline at end of file diff --git a/Epsilon/Component/PersonaPageComponentFetcher.cs b/Epsilon/Component/PersonaPageComponentFetcher.cs new file mode 100644 index 00000000..889fddef --- /dev/null +++ b/Epsilon/Component/PersonaPageComponentFetcher.cs @@ -0,0 +1,66 @@ +using Epsilon.Abstractions.Component; +using Epsilon.Canvas; +using Epsilon.Canvas.Abstractions.Service; +using HtmlAgilityPack; +using Microsoft.Extensions.Options; + +namespace Epsilon.Component; + +public class PersonaPageComponentFetcher : CompetenceComponentFetcher +{ + private readonly IPageHttpService _pageHttpService; + private readonly IFileHttpService _fileHttpService; + private readonly CanvasSettings _canvasSettings; + + public PersonaPageComponentFetcher( + IPageHttpService pageHttpService, + IFileHttpService fileHttpService, + IOptions canvasSettings + ) + { + _pageHttpService = pageHttpService; + _fileHttpService = fileHttpService; + _canvasSettings = canvasSettings.Value; + } + + public override async Task Fetch(DateTime startDate, DateTime endDate) + { + var courseId = _canvasSettings.CourseId; + var personaHtml = await _pageHttpService.GetPageByName(courseId, "front_page"); + + var updatedPersonaHtml = await GetPersonaHtmlDocument(personaHtml); + + var personaPage = new PersonaPage(updatedPersonaHtml.Text); + + return personaPage; + } + + private async Task GetPersonaHtmlDocument(string htmlString) + { + var htmlDoc = new HtmlDocument(); + htmlDoc.LoadHtml(htmlString); + if (htmlDoc.DocumentNode.SelectNodes("//img") == null) + { + return htmlDoc; + } + + foreach (var node in htmlDoc.DocumentNode.SelectNodes("//img")) + { + var imageSrc = node + .SelectNodes("//img") + .First() + .Attributes["src"].Value; + + if (imageSrc != null) + { + var imageBytes = await _fileHttpService.GetFileByteArray(new Uri(imageSrc)); + var imageBase64 = Convert.ToBase64String(imageBytes.ToArray()); + + node.SetAttributeValue("src", $"data:image/jpeg;base64,{imageBase64}"); + } + } + + return htmlDoc; + } + +} \ No newline at end of file diff --git a/Epsilon/Constants.cs b/Epsilon/Constants.cs deleted file mode 100644 index 8998b4c2..00000000 --- a/Epsilon/Constants.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Epsilon; - -public static class Constants -{ - public const string ProjectName = "Epsilon"; - public static readonly Uri RepositoryUri = new Uri("https://github.com/Typiqally/epsilon"); -} \ No newline at end of file diff --git a/Epsilon/Epsilon.csproj b/Epsilon/Epsilon.csproj index 1615dfdc..ed42d439 100644 --- a/Epsilon/Epsilon.csproj +++ b/Epsilon/Epsilon.csproj @@ -10,8 +10,8 @@ - - + + @@ -19,11 +19,11 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - + + + + + diff --git a/Epsilon/Export/Exceptions/NoExportersFoundException.cs b/Epsilon/Export/Exceptions/NoExportersFoundException.cs deleted file mode 100644 index a855e603..00000000 --- a/Epsilon/Export/Exceptions/NoExportersFoundException.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System.Runtime.Serialization; - -namespace Epsilon.Export.Exceptions; - -[Serializable] -public class NoExportersFoundException : Exception -{ - public NoExportersFoundException() - { - } - - public NoExportersFoundException(IEnumerable formats) - : base($"No exporters could be found with the given formats {string.Join(",", formats)}") - { - } - - public NoExportersFoundException(string? message) - : base(message) - { - } - - public NoExportersFoundException(string? message, Exception? innerException) - : base(message, innerException) - { - } - - protected NoExportersFoundException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } -} \ No newline at end of file diff --git a/Epsilon/Export/ExportDataPackager.cs b/Epsilon/Export/ExportDataPackager.cs deleted file mode 100644 index 3df63a3c..00000000 --- a/Epsilon/Export/ExportDataPackager.cs +++ /dev/null @@ -1,86 +0,0 @@ -using System.Diagnostics; -using Epsilon.Abstractions.Export; -using Epsilon.Abstractions.Model; -using Epsilon.Canvas; -using Epsilon.Canvas.Abstractions.Model; -using Epsilon.Canvas.Abstractions.Service; -using Microsoft.Extensions.Options; - -namespace Epsilon.Export; - -public class ExportDataPackager : IExportDataPackager -{ - private readonly CanvasSettings _canvasSettings; - private readonly IPageHttpService _pageService; - - public ExportDataPackager( - IPageHttpService pageService, - IOptions canvasSettings - ) - { - _pageService = pageService; - _canvasSettings = canvasSettings.Value; - } - - public async Task GetExportData(IAsyncEnumerable data) - { - var courseId = _canvasSettings.CourseId; - var personaHtml = await _pageService.GetPageByName(courseId, "front_page"); - - var output = new List(); - - await foreach (var item in data.Where(static m => m.Collection.OutcomeResults.Any())) - { - var module = new CourseModulePackage - { - Name = item.CourseModule.Name, - }; - var links = item.Collection.Links; - - Debug.Assert(links != null, nameof(links) + " != null"); - - var alignments = links.AlignmentsDictionary; - var outcomes = links.OutcomesDictionary; - - var moduleOutcomes = new List(); - - foreach (var (outcomeId, outcome) in outcomes) - { - var assignmentIds = item.Collection.OutcomeResults - .Where(o => o.Link.Outcome == outcomeId && o.Grade() != null) - .Select(static o => o.Link.Assignment).ToArray(); - - if (assignmentIds.Any()) - { - var assignments = assignmentIds - .Select(assignmentId => new CourseAssignment - { - Name = alignments[assignmentId!].Name, - Url = alignments[assignmentId!].Url, - Score = item.Collection.OutcomeResults - .First(o => o.Link.Outcome == outcomeId && o.Link.Assignment == assignmentId) - .Grade() ?? "N/A", - }) - .ToList(); - - moduleOutcomes.Add(new CourseOutcome - { - Name = outcome.Title, - Description = outcome.ShortDescription(), - Assignments = assignments, - }); - } - } - - module.Outcomes = moduleOutcomes; - - output.Add(module); - } - - return new ExportData - { - CourseModules = output, - PersonaHtml = personaHtml, - }; - } -} \ No newline at end of file diff --git a/Epsilon/Export/ExportOptions.cs b/Epsilon/Export/ExportOptions.cs deleted file mode 100644 index 361f2896..00000000 --- a/Epsilon/Export/ExportOptions.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Globalization; - -namespace Epsilon.Export; - -public class ExportOptions -{ - public string OutputName { get; set; } = $"{Constants.ProjectName}-Export-{{DateTime}}"; - - public string Formats { get; set; } = "console"; - - public string? Modules { get; set; } - - public string FormattedOutputName => OutputName.Replace("{DateTime}", DateTime.Now.ToString("ddMMyyyyHHmmss", CultureInfo.InvariantCulture), StringComparison.InvariantCulture); -} \ No newline at end of file diff --git a/Epsilon/Export/Exporters/ConsoleModuleExporter.cs b/Epsilon/Export/Exporters/ConsoleModuleExporter.cs deleted file mode 100644 index 6d7f7ef3..00000000 --- a/Epsilon/Export/Exporters/ConsoleModuleExporter.cs +++ /dev/null @@ -1,62 +0,0 @@ -using System.Diagnostics.CodeAnalysis; -using System.Text; -using Epsilon.Abstractions.Export; -using Epsilon.Abstractions.Model; -using Microsoft.Extensions.Logging; - -namespace Epsilon.Export.Exporters; - -public class ConsoleModuleExporter : ICanvasModuleExporter -{ - private readonly ILogger _logger; - - public ConsoleModuleExporter(ILogger logger) - { - _logger = logger; - } - - public IEnumerable Formats { get; } = new[] - { - "CONSOLE", - "LOGS", - "TXT", - }; - - public string FileExtension => "txt"; - - public async Task Export(ExportData data, string format) - { - var stream = new MemoryStream(); - await using var writer = new StreamWriter(stream, Encoding.UTF8, 1024, true); - - foreach (var module in data.CourseModules) - { - await WriteLineAndLog(writer, "--------------------------------"); - await WriteLineAndLog(writer, $"Module: {module.Name}"); - - foreach (var outcome in module.Outcomes) - { - await WriteLineAndLog(writer, string.Empty); - await WriteLineAndLog(writer, $"KPI: {outcome.Name}"); - - foreach (var assignment in outcome.Assignments) - { - await WriteLineAndLog(writer, $"- Assignment: {assignment.Name}"); - await WriteLineAndLog(writer, $" Score: {assignment.Score}"); - } - } - } - - await writer.FlushAsync(); - - return stream; - } - - [SuppressMessage("Usage", "CA2254:Template should be a static expression", Justification = "Cleanest way right now")] - [SuppressMessage("Performance", "CA1848: Use the LoggerMessage delegates", Justification = "https://github.com/dotnet/roslyn-analyzers/issues/6281")] - private async Task WriteLineAndLog(TextWriter writer, string line) - { - await writer.WriteLineAsync(line); - _logger.LogInformation(line); - } -} \ No newline at end of file diff --git a/Epsilon/Export/Exporters/CsvModuleExporter.cs b/Epsilon/Export/Exporters/CsvModuleExporter.cs deleted file mode 100644 index 1391ef5f..00000000 --- a/Epsilon/Export/Exporters/CsvModuleExporter.cs +++ /dev/null @@ -1,97 +0,0 @@ -using System.Data; -using System.Text; -using Epsilon.Abstractions.Export; -using Epsilon.Abstractions.Model; - -namespace Epsilon.Export.Exporters; - -public class CsvModuleExporter : ICanvasModuleExporter -{ - public IEnumerable Formats { get; } = new[] - { - "CSV", - }; - - public string FileExtension => "csv"; - - public async Task Export(ExportData data, string format) - { - var stream = new MemoryStream(); - await using var writer = new StreamWriter(stream, Encoding.UTF8, 1024, true); - - using var dt = CreateDataTable(data.CourseModules); - WriteHeader(writer, dt); - WriteRows(writer, dt); - - await writer.FlushAsync(); - - return stream; - } - - private static DataTable CreateDataTable(IEnumerable data) - { - var dataTable = new DataTable(); - - dataTable.Columns.Add("Module", typeof(string)); - dataTable.Columns.Add("KPI", typeof(string)); - dataTable.Columns.Add("Assignment", typeof(string)); - dataTable.Columns.Add("Score", typeof(string)); - - foreach (var module in data) - { - foreach (var kpi in module.Outcomes) - { - foreach (var assignment in kpi.Assignments) - { - dataTable.Rows.Add(module.Name, kpi.Name, assignment.Name, assignment.Score); - } - } - } - - return dataTable; - } - - private static void WriteHeader(TextWriter writer, DataTable dt) - { - for (var i = 0; i < dt.Columns.Count; i++) - { - writer.Write(dt.Columns[i]); - if (i < dt.Columns.Count - 1) - { - writer.Write(";"); - } - } - - writer.Write(writer.NewLine); - } - - private static void WriteRows(TextWriter writer, DataTable dt) - { - foreach (DataRow dr in dt.Rows) - { - foreach (DataColumn dtColumn in dt.Columns) - { - var value = dr[dtColumn.Ordinal].ToString(); - if (value != null) - { - if (value.Contains(';', StringComparison.InvariantCulture)) - { - value = $"\"{value}\""; - writer.Write(value); - } - else - { - writer.Write(value); - } - } - - if (dtColumn.Ordinal < dt.Columns.Count - 1) - { - writer.Write(";"); - } - } - - writer.Write(writer.NewLine); - } - } -} \ No newline at end of file diff --git a/Epsilon/Export/Exporters/ExcelModuleExporter.cs b/Epsilon/Export/Exporters/ExcelModuleExporter.cs deleted file mode 100644 index a94d63ac..00000000 --- a/Epsilon/Export/Exporters/ExcelModuleExporter.cs +++ /dev/null @@ -1,132 +0,0 @@ -using System.Globalization; -using System.Text; -using DocumentFormat.OpenXml; -using DocumentFormat.OpenXml.Packaging; -using DocumentFormat.OpenXml.Spreadsheet; -using Epsilon.Abstractions.Export; -using Epsilon.Abstractions.Model; - -namespace Epsilon.Export.Exporters; - -public class ExcelModuleExporter : ICanvasModuleExporter -{ - public IEnumerable Formats { get; } = new[] - { - "XLS", - "XLSX", - "EXCEL", - }; - - public string FileExtension => "xlsx"; - - public Task Export(ExportData data, string format) - { - var stream = new MemoryStream(); - using var spreadsheetDocument = SpreadsheetDocument.Create(stream, SpreadsheetDocumentType.Workbook); - var workbookPart = spreadsheetDocument.AddWorkbookPart(); - workbookPart.Workbook = new Workbook(); - - // Add Sheets to the Workbook. - spreadsheetDocument.WorkbookPart!.Workbook.AppendChild(new Sheets()); - - var cellValueBuilder = new StringBuilder(); - var cellValueOutComeResultsBuilder = new StringBuilder(); - - foreach (var module in data.CourseModules) - { - var worksheetPart = CreateWorksheet(module, workbookPart); - - InsertCellsInWorksheet( - worksheetPart, - 1, - CreateTextCell("KPI", "A", 1), - CreateTextCell("Assignment", "B", 1), - CreateTextCell("Grade", "C", 1) - ); - - uint count = 2; - foreach (var outcome in module.Outcomes) - { - foreach (var assignment in outcome.Assignments) - { - cellValueBuilder.AppendLine(CultureInfo.InvariantCulture, $"{assignment.Name} {assignment.Url}"); - cellValueOutComeResultsBuilder.AppendLine(assignment.Score); - } - - InsertCellsInWorksheet( - worksheetPart, - count, - CreateTextCell($"{outcome.Name} {outcome.Description}", "A", count), - CreateTextCell(cellValueBuilder.ToString(), "B", count), - CreateTextCell(cellValueOutComeResultsBuilder.ToString(), "C", count) - ); - - cellValueBuilder.Clear(); - cellValueOutComeResultsBuilder.Clear(); - - count++; - } - } - - return Task.FromResult(stream); - } - - // Given a WorkbookPart, inserts a new worksheet. - private static WorksheetPart CreateWorksheet(CourseModulePackage modulePackage, WorkbookPart workbookPart) - { - var worksheetPart = workbookPart.AddNewPart(); - worksheetPart.Worksheet = new Worksheet(new SheetData()); - worksheetPart.Worksheet.Save(); - - var sheets = workbookPart.Workbook.GetFirstChild()!; - var relationshipId = workbookPart.GetIdOfPart(worksheetPart); - - uint sheetId = 1; - if (sheets.Elements().Any()) - { - sheetId = sheets.Elements().Select(static s => s.SheetId!.Value).Max() + 1; - } - - var sheet = new Sheet - { - Id = relationshipId, - SheetId = sheetId, - Name = modulePackage.Name, - }; - - sheets.Append(sheet); - - workbookPart.Workbook.Save(); - - return worksheetPart; - } - - private static void InsertCellsInWorksheet(WorksheetPart worksheetPart, uint rowIndex, params Cell[] cells) - { - var worksheet = worksheetPart.Worksheet; - var sheetData = worksheet.GetFirstChild()!; - - var row = sheetData.Elements().FirstOrDefault(r => r.RowIndex! == rowIndex); - if (row == null) - { - row = new Row - { - RowIndex = rowIndex, - }; - sheetData.Append(row); - } - - row.Append(cells); - worksheet.Save(); - } - - private static Cell CreateTextCell(string value, string columnName, uint rowIndex) - { - return new Cell - { - CellReference = columnName + rowIndex, - CellValue = new CellValue(value), - DataType = CellValues.String, - }; - } -} \ No newline at end of file diff --git a/Epsilon/Export/Exporters/WordModuleExporter.cs b/Epsilon/Export/Exporters/WordModuleExporter.cs deleted file mode 100644 index a2debaae..00000000 --- a/Epsilon/Export/Exporters/WordModuleExporter.cs +++ /dev/null @@ -1,167 +0,0 @@ -using System.Globalization; -using System.Text; -using DocumentFormat.OpenXml; -using DocumentFormat.OpenXml.Packaging; -using DocumentFormat.OpenXml.Wordprocessing; -using Epsilon.Abstractions.Export; -using Epsilon.Abstractions.Model; -using Epsilon.Canvas.Abstractions.Service; -using HtmlAgilityPack; - -namespace Epsilon.Export.Exporters; - -public class WordModuleExporter : ICanvasModuleExporter -{ - private readonly IFileHttpService _fileService; - - public WordModuleExporter(IFileHttpService fileService) - { - _fileService = fileService; - } - - private static readonly TableBorders s_defaultBorders = new TableBorders(new TopBorder - { - Val = new EnumValue(BorderValues.Single), Size = 3, - }, new BottomBorder - { - Val = new EnumValue(BorderValues.Single), Size = 3, - }, new LeftBorder - { - Val = new EnumValue(BorderValues.Single), Size = 3, - }, new RightBorder - { - Val = new EnumValue(BorderValues.Single), Size = 3, - }, new InsideHorizontalBorder - { - Val = new EnumValue(BorderValues.Single), Size = 6, - }, new InsideVerticalBorder - { - Val = new EnumValue(BorderValues.Single), Size = 6, - }); - - private static readonly TableProperties s_defaultTableProperties = new TableProperties(s_defaultBorders); - - private static readonly TableRow s_defaultHeader = new TableRow(CreateTextCell("KPI's"), CreateTextCell("Assignments"), CreateTextCell("Score")); - - public IEnumerable Formats { get; } = new[] - { - "WORD", - "DOCX", - }; - - public string FileExtension => "docx"; - - public async Task Export(ExportData data, string format) - { - var stream = new MemoryStream(); - var document = WordprocessingDocument.Create(stream, WordprocessingDocumentType.Document); - - document.AddMainDocumentPart(); - document.MainDocumentPart!.Document = new Document(new Body()); - - var body = document.MainDocumentPart.Document.Body; - var cellValueBuilder = new StringBuilder(); - var cellValueOutComeResultsBuilder = new StringBuilder(); - - const string altChunkId = "HomePage"; - - var personaHtml = await GetPersonaHtmlDocument(_fileService, data.PersonaHtml); - - using var personaHtmlStream = new MemoryStream(Encoding.UTF8.GetPreamble().Concat(Encoding.UTF8.GetBytes($"{personaHtml.Text}")).ToArray()); - var formatImportPart = document.MainDocumentPart.AddAlternativeFormatImportPart(AlternativeFormatImportPartType.Html, altChunkId); - - formatImportPart.FeedData(personaHtmlStream); - var altChunk = new AltChunk - { - Id = altChunkId, - }; - - body?.Append(altChunk); - body?.Append(new Paragraph(new Run(new Break - { - Type = BreakValues.Page, - }))); - - await personaHtmlStream.DisposeAsync(); - - foreach (var module in data.CourseModules) - { - body?.Append(CreateText(module.Name)); - - var table = new Table(); - - table.AppendChild(s_defaultTableProperties.CloneNode(true)); - table.Append(s_defaultHeader.CloneNode(true)); - - var rows = module.Outcomes.Select(kpi => - { - foreach (var assignment in kpi.Assignments) - { - cellValueBuilder.AppendLine(CultureInfo.InvariantCulture, $"{assignment.Name} {assignment.Url}"); - cellValueOutComeResultsBuilder.AppendLine(assignment.Score); - } - - var row = new TableRow( - CreateTextCell($"{kpi.Name} {kpi.Description}"), - CreateTextCell(cellValueBuilder.ToString()), - CreateTextCell(cellValueOutComeResultsBuilder.ToString()) - ); - - cellValueBuilder.Clear(); - cellValueOutComeResultsBuilder.Clear(); - - return row; - }); - - table.Append(rows); - - body?.Append(table); - } - - document.Save(); - document.Close(); - - return stream; - } - - private static Paragraph CreateText(string text) - { - return new Paragraph(new Run(new Text(text))); - } - - private static TableCell CreateTextCell(string text) - { - return new TableCell(CreateText(text), new TableCellProperties(new TableCellWidth - { - Type = TableWidthUnitValues.Auto, - })); - } - - private static async Task GetPersonaHtmlDocument(IFileHttpService fileService, string htmlString) - { - var htmlDoc = new HtmlDocument(); - htmlDoc.LoadHtml(htmlString); - if (htmlDoc.DocumentNode.SelectNodes("//img") == null) - { - return htmlDoc; - } - - foreach (var node in htmlDoc.DocumentNode.SelectNodes("//img")) - { - var imageSrc = node - .SelectNodes("//img") - .First() - .Attributes["src"].Value; - - if (imageSrc != null) - { - var imageBytes = await fileService.GetFileByteArray(new Uri(imageSrc)); - var imageBase64 = Convert.ToBase64String(imageBytes.ToArray()); - - node.SetAttributeValue("src", $"data:image/jpeg;base64,{imageBase64}"); - } - } - - return htmlDoc; - } -} \ No newline at end of file diff --git a/Epsilon/Export/ModuleExporterCollection.cs b/Epsilon/Export/ModuleExporterCollection.cs deleted file mode 100644 index 3b61bb17..00000000 --- a/Epsilon/Export/ModuleExporterCollection.cs +++ /dev/null @@ -1,37 +0,0 @@ -using Epsilon.Abstractions.Export; -using Epsilon.Export.Exceptions; - -namespace Epsilon.Export; - -public class ModuleExporterCollection : IModuleExporterCollection -{ - private readonly IEnumerable _exporters; - - public ModuleExporterCollection(IEnumerable exporters) - { - _exporters = exporters; - } - - public IEnumerable Formats() - { - return _exporters.SelectMany(static x => x.Formats); - } - - public IDictionary DetermineExporters(IEnumerable formats) - { - var formatsArray = formats.ToArray(); // To prevent multiple enumeration - var foundExporters = new Dictionary(); - - foreach (var exporter in _exporters) - { - foreach (var format in formatsArray.Where(f => exporter.Formats.Contains(f.ToUpperInvariant()))) - { - foundExporters.Add(format, exporter); - } - } - - return !foundExporters.Any() - ? throw new NoExportersFoundException(formatsArray) - : (IDictionary)foundExporters; - } -} \ No newline at end of file diff --git a/Epsilon/Extensions/CoreServiceCollectionExtensions.cs b/Epsilon/Extensions/CoreServiceCollectionExtensions.cs deleted file mode 100644 index 63515668..00000000 --- a/Epsilon/Extensions/CoreServiceCollectionExtensions.cs +++ /dev/null @@ -1,34 +0,0 @@ -using Epsilon.Abstractions.Export; -using Epsilon.Canvas; -using Epsilon.Export; -using Epsilon.Export.Exporters; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; - -namespace Epsilon.Extensions; - -public static class CoreServiceCollectionExtensions -{ - public static IServiceCollection AddCore(this IServiceCollection services, IConfiguration config) - { - services.AddCanvas(config.GetSection("Canvas")); - services.AddExport(config); - - return services; - } - - private static IServiceCollection AddExport(this IServiceCollection services, IConfiguration config) - { - services.Configure(config); - - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - - services.AddScoped(); - services.AddScoped(); - - return services; - } -} \ No newline at end of file diff --git a/Epsilon/FhictConstants.cs b/Epsilon/FhictConstants.cs new file mode 100644 index 00000000..2dcd8709 --- /dev/null +++ b/Epsilon/FhictConstants.cs @@ -0,0 +1,265 @@ +using Epsilon.Abstractions.Model; + +namespace Epsilon; + +public static class FhictConstants +{ + public static readonly IDictionary ProfessionalTasks = new Dictionary + { + { 6785, new ProfessionalTask(HboIDomain2018.HardwareInterfacing.Id, HboIDomain2018.Advise.Id, HboIDomain2018.LevelOne.Id) }, + { 6786, new ProfessionalTask(HboIDomain2018.HardwareInterfacing.Id, HboIDomain2018.Advise.Id, HboIDomain2018.LevelOne.Id) }, + { 6787, new ProfessionalTask(HboIDomain2018.HardwareInterfacing.Id, HboIDomain2018.Advise.Id, HboIDomain2018.LevelTwo.Id) }, + { 6788, new ProfessionalTask(HboIDomain2018.HardwareInterfacing.Id, HboIDomain2018.Advise.Id, HboIDomain2018.LevelTwo.Id) }, + { 6789, new ProfessionalTask(HboIDomain2018.HardwareInterfacing.Id, HboIDomain2018.Advise.Id, HboIDomain2018.LevelThree.Id) }, + { 6790, new ProfessionalTask(HboIDomain2018.HardwareInterfacing.Id, HboIDomain2018.Advise.Id, HboIDomain2018.LevelFour.Id) }, + { 6791, new ProfessionalTask(HboIDomain2018.HardwareInterfacing.Id, HboIDomain2018.Advise.Id, HboIDomain2018.LevelFour.Id) }, + { 6792, new ProfessionalTask(HboIDomain2018.HardwareInterfacing.Id, HboIDomain2018.Advise.Id, HboIDomain2018.LevelFour.Id) }, + { 6773, new ProfessionalTask(HboIDomain2018.HardwareInterfacing.Id, HboIDomain2018.Analysis.Id, HboIDomain2018.LevelOne.Id) }, + { 6774, new ProfessionalTask(HboIDomain2018.HardwareInterfacing.Id, HboIDomain2018.Analysis.Id, HboIDomain2018.LevelOne.Id) }, + { 6775, new ProfessionalTask(HboIDomain2018.HardwareInterfacing.Id, HboIDomain2018.Analysis.Id, HboIDomain2018.LevelOne.Id) }, + { 6776, new ProfessionalTask(HboIDomain2018.HardwareInterfacing.Id, HboIDomain2018.Analysis.Id, HboIDomain2018.LevelTwo.Id) }, + { 6777, new ProfessionalTask(HboIDomain2018.HardwareInterfacing.Id, HboIDomain2018.Analysis.Id, HboIDomain2018.LevelTwo.Id) }, + { 6778, new ProfessionalTask(HboIDomain2018.HardwareInterfacing.Id, HboIDomain2018.Analysis.Id, HboIDomain2018.LevelTwo.Id) }, + { 6779, new ProfessionalTask(HboIDomain2018.HardwareInterfacing.Id, HboIDomain2018.Analysis.Id, HboIDomain2018.LevelTwo.Id) }, + { 6780, new ProfessionalTask(HboIDomain2018.HardwareInterfacing.Id, HboIDomain2018.Analysis.Id, HboIDomain2018.LevelThree.Id) }, + { 6781, new ProfessionalTask(HboIDomain2018.HardwareInterfacing.Id, HboIDomain2018.Analysis.Id, HboIDomain2018.LevelThree.Id) }, + { 6782, new ProfessionalTask(HboIDomain2018.HardwareInterfacing.Id, HboIDomain2018.Analysis.Id, HboIDomain2018.LevelThree.Id) }, + { 6783, new ProfessionalTask(HboIDomain2018.HardwareInterfacing.Id, HboIDomain2018.Analysis.Id, HboIDomain2018.LevelFour.Id) }, + { 6784, new ProfessionalTask(HboIDomain2018.HardwareInterfacing.Id, HboIDomain2018.Analysis.Id, HboIDomain2018.LevelFour.Id) }, + { 6801, new ProfessionalTask(HboIDomain2018.HardwareInterfacing.Id, HboIDomain2018.Design.Id, HboIDomain2018.LevelOne.Id) }, + { 6802, new ProfessionalTask(HboIDomain2018.HardwareInterfacing.Id, HboIDomain2018.Design.Id, HboIDomain2018.LevelTwo.Id) }, + { 6803, new ProfessionalTask(HboIDomain2018.HardwareInterfacing.Id, HboIDomain2018.Design.Id, HboIDomain2018.LevelThree.Id) }, + { 6804, new ProfessionalTask(HboIDomain2018.HardwareInterfacing.Id, HboIDomain2018.Design.Id, HboIDomain2018.LevelFour.Id) }, + { 6812, new ProfessionalTask(HboIDomain2018.HardwareInterfacing.Id, HboIDomain2018.ManageAndControl.Id, HboIDomain2018.LevelOne.Id) }, + { 6813, new ProfessionalTask(HboIDomain2018.HardwareInterfacing.Id, HboIDomain2018.ManageAndControl.Id, HboIDomain2018.LevelTwo.Id) }, + { 6814, new ProfessionalTask(HboIDomain2018.HardwareInterfacing.Id, HboIDomain2018.ManageAndControl.Id, HboIDomain2018.LevelTwo.Id) }, + { 6815, new ProfessionalTask(HboIDomain2018.HardwareInterfacing.Id, HboIDomain2018.ManageAndControl.Id, HboIDomain2018.LevelThree.Id) }, + { 6816, new ProfessionalTask(HboIDomain2018.HardwareInterfacing.Id, HboIDomain2018.ManageAndControl.Id, HboIDomain2018.LevelFour.Id) }, + { 6805, new ProfessionalTask(HboIDomain2018.HardwareInterfacing.Id, HboIDomain2018.Realisation.Id, HboIDomain2018.LevelOne.Id) }, + { 6806, new ProfessionalTask(HboIDomain2018.HardwareInterfacing.Id, HboIDomain2018.Realisation.Id, HboIDomain2018.LevelTwo.Id) }, + { 6807, new ProfessionalTask(HboIDomain2018.HardwareInterfacing.Id, HboIDomain2018.Realisation.Id, HboIDomain2018.LevelTwo.Id) }, + { 6808, new ProfessionalTask(HboIDomain2018.HardwareInterfacing.Id, HboIDomain2018.Realisation.Id, HboIDomain2018.LevelTwo.Id) }, + { 6809, new ProfessionalTask(HboIDomain2018.HardwareInterfacing.Id, HboIDomain2018.Realisation.Id, HboIDomain2018.LevelThree.Id) }, + { 6810, new ProfessionalTask(HboIDomain2018.HardwareInterfacing.Id, HboIDomain2018.Realisation.Id, HboIDomain2018.LevelThree.Id) }, + { 6811, new ProfessionalTask(HboIDomain2018.HardwareInterfacing.Id, HboIDomain2018.Realisation.Id, HboIDomain2018.LevelFour.Id) }, + { 6863, new ProfessionalTask(HboIDomain2018.Infrastructure.Id, HboIDomain2018.Advise.Id, HboIDomain2018.LevelOne.Id) }, + { 6864, new ProfessionalTask(HboIDomain2018.Infrastructure.Id, HboIDomain2018.Advise.Id, HboIDomain2018.LevelTwo.Id) }, + { 6865, new ProfessionalTask(HboIDomain2018.Infrastructure.Id, HboIDomain2018.Advise.Id, HboIDomain2018.LevelTwo.Id) }, + { 6866, new ProfessionalTask(HboIDomain2018.Infrastructure.Id, HboIDomain2018.Advise.Id, HboIDomain2018.LevelThree.Id) }, + { 6867, new ProfessionalTask(HboIDomain2018.Infrastructure.Id, HboIDomain2018.Advise.Id, HboIDomain2018.LevelThree.Id) }, + { 6868, new ProfessionalTask(HboIDomain2018.Infrastructure.Id, HboIDomain2018.Advise.Id, HboIDomain2018.LevelFour.Id) }, + { 6857, new ProfessionalTask(HboIDomain2018.Infrastructure.Id, HboIDomain2018.Analysis.Id, HboIDomain2018.LevelOne.Id) }, + { 6858, new ProfessionalTask(HboIDomain2018.Infrastructure.Id, HboIDomain2018.Analysis.Id, HboIDomain2018.LevelTwo.Id) }, + { 6859, new ProfessionalTask(HboIDomain2018.Infrastructure.Id, HboIDomain2018.Analysis.Id, HboIDomain2018.LevelTwo.Id) }, + { 6860, new ProfessionalTask(HboIDomain2018.Infrastructure.Id, HboIDomain2018.Analysis.Id, HboIDomain2018.LevelThree.Id) }, + { 6861, new ProfessionalTask(HboIDomain2018.Infrastructure.Id, HboIDomain2018.Analysis.Id, HboIDomain2018.LevelThree.Id) }, + { 6862, new ProfessionalTask(HboIDomain2018.Infrastructure.Id, HboIDomain2018.Analysis.Id, HboIDomain2018.LevelFour.Id) }, + { 6869, new ProfessionalTask(HboIDomain2018.Infrastructure.Id, HboIDomain2018.Design.Id, HboIDomain2018.LevelOne.Id) }, + { 6870, new ProfessionalTask(HboIDomain2018.Infrastructure.Id, HboIDomain2018.Design.Id, HboIDomain2018.LevelTwo.Id) }, + { 6871, new ProfessionalTask(HboIDomain2018.Infrastructure.Id, HboIDomain2018.Design.Id, HboIDomain2018.LevelTwo.Id) }, + { 6872, new ProfessionalTask(HboIDomain2018.Infrastructure.Id, HboIDomain2018.Design.Id, HboIDomain2018.LevelTwo.Id) }, + { 6873, new ProfessionalTask(HboIDomain2018.Infrastructure.Id, HboIDomain2018.Design.Id, HboIDomain2018.LevelThree.Id) }, + { 6874, new ProfessionalTask(HboIDomain2018.Infrastructure.Id, HboIDomain2018.Design.Id, HboIDomain2018.LevelThree.Id) }, + { 6875, new ProfessionalTask(HboIDomain2018.Infrastructure.Id, HboIDomain2018.Design.Id, HboIDomain2018.LevelFour.Id) }, + { 6885, new ProfessionalTask(HboIDomain2018.Infrastructure.Id, HboIDomain2018.ManageAndControl.Id, HboIDomain2018.LevelOne.Id) }, + { 6886, new ProfessionalTask(HboIDomain2018.Infrastructure.Id, HboIDomain2018.ManageAndControl.Id, HboIDomain2018.LevelTwo.Id) }, + { 6887, new ProfessionalTask(HboIDomain2018.Infrastructure.Id, HboIDomain2018.ManageAndControl.Id, HboIDomain2018.LevelTwo.Id) }, + { 6888, new ProfessionalTask(HboIDomain2018.Infrastructure.Id, HboIDomain2018.ManageAndControl.Id, HboIDomain2018.LevelTwo.Id) }, + { 6889, new ProfessionalTask(HboIDomain2018.Infrastructure.Id, HboIDomain2018.ManageAndControl.Id, HboIDomain2018.LevelThree.Id) }, + { 6890, new ProfessionalTask(HboIDomain2018.Infrastructure.Id, HboIDomain2018.ManageAndControl.Id, HboIDomain2018.LevelThree.Id) }, + { 6891, new ProfessionalTask(HboIDomain2018.Infrastructure.Id, HboIDomain2018.ManageAndControl.Id, HboIDomain2018.LevelFour.Id) }, + { 6876, new ProfessionalTask(HboIDomain2018.Infrastructure.Id, HboIDomain2018.Realisation.Id, HboIDomain2018.LevelOne.Id) }, + { 6877, new ProfessionalTask(HboIDomain2018.Infrastructure.Id, HboIDomain2018.Realisation.Id, HboIDomain2018.LevelTwo.Id) }, + { 6878, new ProfessionalTask(HboIDomain2018.Infrastructure.Id, HboIDomain2018.Realisation.Id, HboIDomain2018.LevelTwo.Id) }, + { 6879, new ProfessionalTask(HboIDomain2018.Infrastructure.Id, HboIDomain2018.Realisation.Id, HboIDomain2018.LevelTwo.Id) }, + { 6880, new ProfessionalTask(HboIDomain2018.Infrastructure.Id, HboIDomain2018.Realisation.Id, HboIDomain2018.LevelThree.Id) }, + { 6881, new ProfessionalTask(HboIDomain2018.Infrastructure.Id, HboIDomain2018.Realisation.Id, HboIDomain2018.LevelThree.Id) }, + { 6882, new ProfessionalTask(HboIDomain2018.Infrastructure.Id, HboIDomain2018.Realisation.Id, HboIDomain2018.LevelThree.Id) }, + { 6883, new ProfessionalTask(HboIDomain2018.Infrastructure.Id, HboIDomain2018.Realisation.Id, HboIDomain2018.LevelFour.Id) }, + { 6884, new ProfessionalTask(HboIDomain2018.Infrastructure.Id, HboIDomain2018.Realisation.Id, HboIDomain2018.LevelFour.Id) }, + { 6903, new ProfessionalTask(HboIDomain2018.OrganisationalProcesses.Id, HboIDomain2018.Advise.Id, HboIDomain2018.LevelOne.Id) }, + { 6904, new ProfessionalTask(HboIDomain2018.OrganisationalProcesses.Id, HboIDomain2018.Advise.Id, HboIDomain2018.LevelTwo.Id) }, + { 6905, new ProfessionalTask(HboIDomain2018.OrganisationalProcesses.Id, HboIDomain2018.Advise.Id, HboIDomain2018.LevelTwo.Id) }, + { 6906, new ProfessionalTask(HboIDomain2018.OrganisationalProcesses.Id, HboIDomain2018.Advise.Id, HboIDomain2018.LevelThree.Id) }, + { 6907, new ProfessionalTask(HboIDomain2018.OrganisationalProcesses.Id, HboIDomain2018.Advise.Id, HboIDomain2018.LevelThree.Id) }, + { 6908, new ProfessionalTask(HboIDomain2018.OrganisationalProcesses.Id, HboIDomain2018.Advise.Id, HboIDomain2018.LevelThree.Id) }, + { 6909, new ProfessionalTask(HboIDomain2018.OrganisationalProcesses.Id, HboIDomain2018.Advise.Id, HboIDomain2018.LevelFour.Id) }, + { 6910, new ProfessionalTask(HboIDomain2018.OrganisationalProcesses.Id, HboIDomain2018.Advise.Id, HboIDomain2018.LevelFour.Id) }, + { 6892, new ProfessionalTask(HboIDomain2018.OrganisationalProcesses.Id, HboIDomain2018.Analysis.Id, HboIDomain2018.LevelOne.Id) }, + { 6893, new ProfessionalTask(HboIDomain2018.OrganisationalProcesses.Id, HboIDomain2018.Analysis.Id, HboIDomain2018.LevelOne.Id) }, + { 6894, new ProfessionalTask(HboIDomain2018.OrganisationalProcesses.Id, HboIDomain2018.Analysis.Id, HboIDomain2018.LevelTwo.Id) }, + { 6895, new ProfessionalTask(HboIDomain2018.OrganisationalProcesses.Id, HboIDomain2018.Analysis.Id, HboIDomain2018.LevelTwo.Id) }, + { 6896, new ProfessionalTask(HboIDomain2018.OrganisationalProcesses.Id, HboIDomain2018.Analysis.Id, HboIDomain2018.LevelTwo.Id) }, + { 6897, new ProfessionalTask(HboIDomain2018.OrganisationalProcesses.Id, HboIDomain2018.Analysis.Id, HboIDomain2018.LevelTwo.Id) }, + { 6898, new ProfessionalTask(HboIDomain2018.OrganisationalProcesses.Id, HboIDomain2018.Analysis.Id, HboIDomain2018.LevelThree.Id) }, + { 6899, new ProfessionalTask(HboIDomain2018.OrganisationalProcesses.Id, HboIDomain2018.Analysis.Id, HboIDomain2018.LevelThree.Id) }, + { 6900, new ProfessionalTask(HboIDomain2018.OrganisationalProcesses.Id, HboIDomain2018.Analysis.Id, HboIDomain2018.LevelThree.Id) }, + { 6901, new ProfessionalTask(HboIDomain2018.OrganisationalProcesses.Id, HboIDomain2018.Analysis.Id, HboIDomain2018.LevelThree.Id) }, + { 6902, new ProfessionalTask(HboIDomain2018.OrganisationalProcesses.Id, HboIDomain2018.Analysis.Id, HboIDomain2018.LevelFour.Id) }, + { 6911, new ProfessionalTask(HboIDomain2018.OrganisationalProcesses.Id, HboIDomain2018.Design.Id, HboIDomain2018.LevelOne.Id) }, + { 6912, new ProfessionalTask(HboIDomain2018.OrganisationalProcesses.Id, HboIDomain2018.Design.Id, HboIDomain2018.LevelTwo.Id) }, + { 6913, new ProfessionalTask(HboIDomain2018.OrganisationalProcesses.Id, HboIDomain2018.Design.Id, HboIDomain2018.LevelTwo.Id) }, + { 6914, new ProfessionalTask(HboIDomain2018.OrganisationalProcesses.Id, HboIDomain2018.Design.Id, HboIDomain2018.LevelTwo.Id) }, + { 6915, new ProfessionalTask(HboIDomain2018.OrganisationalProcesses.Id, HboIDomain2018.Design.Id, HboIDomain2018.LevelThree.Id) }, + { 6916, new ProfessionalTask(HboIDomain2018.OrganisationalProcesses.Id, HboIDomain2018.Design.Id, HboIDomain2018.LevelThree.Id) }, + { 6917, new ProfessionalTask(HboIDomain2018.OrganisationalProcesses.Id, HboIDomain2018.Design.Id, HboIDomain2018.LevelThree.Id) }, + { 6918, new ProfessionalTask(HboIDomain2018.OrganisationalProcesses.Id, HboIDomain2018.Design.Id, HboIDomain2018.LevelFour.Id) }, + { 6919, new ProfessionalTask(HboIDomain2018.OrganisationalProcesses.Id, HboIDomain2018.Design.Id, HboIDomain2018.LevelFour.Id) }, + { 6930, new ProfessionalTask(HboIDomain2018.OrganisationalProcesses.Id, HboIDomain2018.ManageAndControl.Id, HboIDomain2018.LevelOne.Id) }, + { 6931, new ProfessionalTask(HboIDomain2018.OrganisationalProcesses.Id, HboIDomain2018.ManageAndControl.Id, HboIDomain2018.LevelOne.Id) }, + { 6932, new ProfessionalTask(HboIDomain2018.OrganisationalProcesses.Id, HboIDomain2018.ManageAndControl.Id, HboIDomain2018.LevelTwo.Id) }, + { 6933, new ProfessionalTask(HboIDomain2018.OrganisationalProcesses.Id, HboIDomain2018.ManageAndControl.Id, HboIDomain2018.LevelTwo.Id) }, + { 6934, new ProfessionalTask(HboIDomain2018.OrganisationalProcesses.Id, HboIDomain2018.ManageAndControl.Id, HboIDomain2018.LevelThree.Id) }, + { 6935, new ProfessionalTask(HboIDomain2018.OrganisationalProcesses.Id, HboIDomain2018.ManageAndControl.Id, HboIDomain2018.LevelThree.Id) }, + { 6920, new ProfessionalTask(HboIDomain2018.OrganisationalProcesses.Id, HboIDomain2018.Realisation.Id, HboIDomain2018.LevelOne.Id) }, + { 6921, new ProfessionalTask(HboIDomain2018.OrganisationalProcesses.Id, HboIDomain2018.Realisation.Id, HboIDomain2018.LevelOne.Id) }, + { 6922, new ProfessionalTask(HboIDomain2018.OrganisationalProcesses.Id, HboIDomain2018.Realisation.Id, HboIDomain2018.LevelOne.Id) }, + { 6923, new ProfessionalTask(HboIDomain2018.OrganisationalProcesses.Id, HboIDomain2018.Realisation.Id, HboIDomain2018.LevelTwo.Id) }, + { 6924, new ProfessionalTask(HboIDomain2018.OrganisationalProcesses.Id, HboIDomain2018.Realisation.Id, HboIDomain2018.LevelTwo.Id) }, + { 6925, new ProfessionalTask(HboIDomain2018.OrganisationalProcesses.Id, HboIDomain2018.Realisation.Id, HboIDomain2018.LevelTwo.Id) }, + { 6926, new ProfessionalTask(HboIDomain2018.OrganisationalProcesses.Id, HboIDomain2018.Realisation.Id, HboIDomain2018.LevelTwo.Id) }, + { 6927, new ProfessionalTask(HboIDomain2018.OrganisationalProcesses.Id, HboIDomain2018.Realisation.Id, HboIDomain2018.LevelThree.Id) }, + { 6928, new ProfessionalTask(HboIDomain2018.OrganisationalProcesses.Id, HboIDomain2018.Realisation.Id, HboIDomain2018.LevelThree.Id) }, + { 6929, new ProfessionalTask(HboIDomain2018.OrganisationalProcesses.Id, HboIDomain2018.Realisation.Id, HboIDomain2018.LevelFour.Id) }, + { 6825, new ProfessionalTask(HboIDomain2018.Software.Id, HboIDomain2018.Advise.Id, HboIDomain2018.LevelOne.Id) }, + { 6826, new ProfessionalTask(HboIDomain2018.Software.Id, HboIDomain2018.Advise.Id, HboIDomain2018.LevelTwo.Id) }, + { 6827, new ProfessionalTask(HboIDomain2018.Software.Id, HboIDomain2018.Advise.Id, HboIDomain2018.LevelTwo.Id) }, + { 6828, new ProfessionalTask(HboIDomain2018.Software.Id, HboIDomain2018.Advise.Id, HboIDomain2018.LevelTwo.Id) }, + { 6829, new ProfessionalTask(HboIDomain2018.Software.Id, HboIDomain2018.Advise.Id, HboIDomain2018.LevelThree.Id) }, + { 6830, new ProfessionalTask(HboIDomain2018.Software.Id, HboIDomain2018.Advise.Id, HboIDomain2018.LevelThree.Id) }, + { 6831, new ProfessionalTask(HboIDomain2018.Software.Id, HboIDomain2018.Advise.Id, HboIDomain2018.LevelThree.Id) }, + { 6832, new ProfessionalTask(HboIDomain2018.Software.Id, HboIDomain2018.Advise.Id, HboIDomain2018.LevelFour.Id) }, + { 6817, new ProfessionalTask(HboIDomain2018.Software.Id, HboIDomain2018.Analysis.Id, HboIDomain2018.LevelOne.Id) }, + { 6818, new ProfessionalTask(HboIDomain2018.Software.Id, HboIDomain2018.Analysis.Id, HboIDomain2018.LevelOne.Id) }, + { 6819, new ProfessionalTask(HboIDomain2018.Software.Id, HboIDomain2018.Analysis.Id, HboIDomain2018.LevelTwo.Id) }, + { 6820, new ProfessionalTask(HboIDomain2018.Software.Id, HboIDomain2018.Analysis.Id, HboIDomain2018.LevelTwo.Id) }, + { 6821, new ProfessionalTask(HboIDomain2018.Software.Id, HboIDomain2018.Analysis.Id, HboIDomain2018.LevelTwo.Id) }, + { 6822, new ProfessionalTask(HboIDomain2018.Software.Id, HboIDomain2018.Analysis.Id, HboIDomain2018.LevelThree.Id) }, + { 6823, new ProfessionalTask(HboIDomain2018.Software.Id, HboIDomain2018.Analysis.Id, HboIDomain2018.LevelThree.Id) }, + { 6824, new ProfessionalTask(HboIDomain2018.Software.Id, HboIDomain2018.Analysis.Id, HboIDomain2018.LevelFour.Id) }, + { 6833, new ProfessionalTask(HboIDomain2018.Software.Id, HboIDomain2018.Design.Id, HboIDomain2018.LevelOne.Id) }, + { 6834, new ProfessionalTask(HboIDomain2018.Software.Id, HboIDomain2018.Design.Id, HboIDomain2018.LevelTwo.Id) }, + { 6835, new ProfessionalTask(HboIDomain2018.Software.Id, HboIDomain2018.Design.Id, HboIDomain2018.LevelTwo.Id) }, + { 6836, new ProfessionalTask(HboIDomain2018.Software.Id, HboIDomain2018.Design.Id, HboIDomain2018.LevelTwo.Id) }, + { 6837, new ProfessionalTask(HboIDomain2018.Software.Id, HboIDomain2018.Design.Id, HboIDomain2018.LevelTwo.Id) }, + { 6838, new ProfessionalTask(HboIDomain2018.Software.Id, HboIDomain2018.Design.Id, HboIDomain2018.LevelTwo.Id) }, + { 6839, new ProfessionalTask(HboIDomain2018.Software.Id, HboIDomain2018.Design.Id, HboIDomain2018.LevelThree.Id) }, + { 6840, new ProfessionalTask(HboIDomain2018.Software.Id, HboIDomain2018.Design.Id, HboIDomain2018.LevelThree.Id) }, + { 6841, new ProfessionalTask(HboIDomain2018.Software.Id, HboIDomain2018.Design.Id, HboIDomain2018.LevelFour.Id) }, + { 6842, new ProfessionalTask(HboIDomain2018.Software.Id, HboIDomain2018.Design.Id, HboIDomain2018.LevelFour.Id) }, + { 6851, new ProfessionalTask(HboIDomain2018.Software.Id, HboIDomain2018.ManageAndControl.Id, HboIDomain2018.LevelOne.Id) }, + { 6852, new ProfessionalTask(HboIDomain2018.Software.Id, HboIDomain2018.ManageAndControl.Id, HboIDomain2018.LevelTwo.Id) }, + { 6853, new ProfessionalTask(HboIDomain2018.Software.Id, HboIDomain2018.ManageAndControl.Id, HboIDomain2018.LevelTwo.Id) }, + { 6854, new ProfessionalTask(HboIDomain2018.Software.Id, HboIDomain2018.ManageAndControl.Id, HboIDomain2018.LevelThree.Id) }, + { 6855, new ProfessionalTask(HboIDomain2018.Software.Id, HboIDomain2018.ManageAndControl.Id, HboIDomain2018.LevelThree.Id) }, + { 6856, new ProfessionalTask(HboIDomain2018.Software.Id, HboIDomain2018.ManageAndControl.Id, HboIDomain2018.LevelFour.Id) }, + { 6843, new ProfessionalTask(HboIDomain2018.Software.Id, HboIDomain2018.Realisation.Id, HboIDomain2018.LevelOne.Id) }, + { 6844, new ProfessionalTask(HboIDomain2018.Software.Id, HboIDomain2018.Realisation.Id, HboIDomain2018.LevelTwo.Id) }, + { 6845, new ProfessionalTask(HboIDomain2018.Software.Id, HboIDomain2018.Realisation.Id, HboIDomain2018.LevelTwo.Id) }, + { 6846, new ProfessionalTask(HboIDomain2018.Software.Id, HboIDomain2018.Realisation.Id, HboIDomain2018.LevelTwo.Id) }, + { 6847, new ProfessionalTask(HboIDomain2018.Software.Id, HboIDomain2018.Realisation.Id, HboIDomain2018.LevelThree.Id) }, + { 6848, new ProfessionalTask(HboIDomain2018.Software.Id, HboIDomain2018.Realisation.Id, HboIDomain2018.LevelThree.Id) }, + { 6849, new ProfessionalTask(HboIDomain2018.Software.Id, HboIDomain2018.Realisation.Id, HboIDomain2018.LevelFour.Id) }, + { 6850, new ProfessionalTask(HboIDomain2018.Software.Id, HboIDomain2018.Realisation.Id, HboIDomain2018.LevelFour.Id) }, + { 6946, new ProfessionalTask(HboIDomain2018.UserInteraction.Id, HboIDomain2018.Advise.Id, HboIDomain2018.LevelOne.Id) }, + { 6947, new ProfessionalTask(HboIDomain2018.UserInteraction.Id, HboIDomain2018.Advise.Id, HboIDomain2018.LevelOne.Id) }, + { 6948, new ProfessionalTask(HboIDomain2018.UserInteraction.Id, HboIDomain2018.Advise.Id, HboIDomain2018.LevelTwo.Id) }, + { 6949, new ProfessionalTask(HboIDomain2018.UserInteraction.Id, HboIDomain2018.Advise.Id, HboIDomain2018.LevelTwo.Id) }, + { 6950, new ProfessionalTask(HboIDomain2018.UserInteraction.Id, HboIDomain2018.Advise.Id, HboIDomain2018.LevelTwo.Id) }, + { 6951, new ProfessionalTask(HboIDomain2018.UserInteraction.Id, HboIDomain2018.Advise.Id, HboIDomain2018.LevelThree.Id) }, + { 6952, new ProfessionalTask(HboIDomain2018.UserInteraction.Id, HboIDomain2018.Advise.Id, HboIDomain2018.LevelThree.Id) }, + { 6953, new ProfessionalTask(HboIDomain2018.UserInteraction.Id, HboIDomain2018.Advise.Id, HboIDomain2018.LevelFour.Id) }, + { 6936, new ProfessionalTask(HboIDomain2018.UserInteraction.Id, HboIDomain2018.Analysis.Id, HboIDomain2018.LevelOne.Id) }, + { 6937, new ProfessionalTask(HboIDomain2018.UserInteraction.Id, HboIDomain2018.Analysis.Id, HboIDomain2018.LevelOne.Id) }, + { 6938, new ProfessionalTask(HboIDomain2018.UserInteraction.Id, HboIDomain2018.Analysis.Id, HboIDomain2018.LevelOne.Id) }, + { 6939, new ProfessionalTask(HboIDomain2018.UserInteraction.Id, HboIDomain2018.Analysis.Id, HboIDomain2018.LevelTwo.Id) }, + { 6940, new ProfessionalTask(HboIDomain2018.UserInteraction.Id, HboIDomain2018.Analysis.Id, HboIDomain2018.LevelTwo.Id) }, + { 6941, new ProfessionalTask(HboIDomain2018.UserInteraction.Id, HboIDomain2018.Analysis.Id, HboIDomain2018.LevelTwo.Id) }, + { 6942, new ProfessionalTask(HboIDomain2018.UserInteraction.Id, HboIDomain2018.Analysis.Id, HboIDomain2018.LevelThree.Id) }, + { 6943, new ProfessionalTask(HboIDomain2018.UserInteraction.Id, HboIDomain2018.Analysis.Id, HboIDomain2018.LevelThree.Id) }, + { 6944, new ProfessionalTask(HboIDomain2018.UserInteraction.Id, HboIDomain2018.Analysis.Id, HboIDomain2018.LevelThree.Id) }, + { 6945, new ProfessionalTask(HboIDomain2018.UserInteraction.Id, HboIDomain2018.Analysis.Id, HboIDomain2018.LevelFour.Id) }, + { 6954, new ProfessionalTask(HboIDomain2018.UserInteraction.Id, HboIDomain2018.Design.Id, HboIDomain2018.LevelOne.Id) }, + { 6955, new ProfessionalTask(HboIDomain2018.UserInteraction.Id, HboIDomain2018.Design.Id, HboIDomain2018.LevelOne.Id) }, + { 6956, new ProfessionalTask(HboIDomain2018.UserInteraction.Id, HboIDomain2018.Design.Id, HboIDomain2018.LevelOne.Id) }, + { 6957, new ProfessionalTask(HboIDomain2018.UserInteraction.Id, HboIDomain2018.Design.Id, HboIDomain2018.LevelTwo.Id) }, + { 6958, new ProfessionalTask(HboIDomain2018.UserInteraction.Id, HboIDomain2018.Design.Id, HboIDomain2018.LevelTwo.Id) }, + { 6959, new ProfessionalTask(HboIDomain2018.UserInteraction.Id, HboIDomain2018.Design.Id, HboIDomain2018.LevelThree.Id) }, + { 6960, new ProfessionalTask(HboIDomain2018.UserInteraction.Id, HboIDomain2018.Design.Id, HboIDomain2018.LevelThree.Id) }, + { 6961, new ProfessionalTask(HboIDomain2018.UserInteraction.Id, HboIDomain2018.Design.Id, HboIDomain2018.LevelFour.Id) }, + { 6970, new ProfessionalTask(HboIDomain2018.UserInteraction.Id, HboIDomain2018.ManageAndControl.Id, HboIDomain2018.LevelOne.Id) }, + { 6971, new ProfessionalTask(HboIDomain2018.UserInteraction.Id, HboIDomain2018.ManageAndControl.Id, HboIDomain2018.LevelTwo.Id) }, + { 6972, new ProfessionalTask(HboIDomain2018.UserInteraction.Id, HboIDomain2018.ManageAndControl.Id, HboIDomain2018.LevelTwo.Id) }, + { 6973, new ProfessionalTask(HboIDomain2018.UserInteraction.Id, HboIDomain2018.ManageAndControl.Id, HboIDomain2018.LevelThree.Id) }, + { 6974, new ProfessionalTask(HboIDomain2018.UserInteraction.Id, HboIDomain2018.ManageAndControl.Id, HboIDomain2018.LevelThree.Id) }, + { 6975, new ProfessionalTask(HboIDomain2018.UserInteraction.Id, HboIDomain2018.ManageAndControl.Id, HboIDomain2018.LevelThree.Id) }, + { 6976, new ProfessionalTask(HboIDomain2018.UserInteraction.Id, HboIDomain2018.ManageAndControl.Id, HboIDomain2018.LevelFour.Id) }, + { 6962, new ProfessionalTask(HboIDomain2018.UserInteraction.Id, HboIDomain2018.Realisation.Id, HboIDomain2018.LevelOne.Id) }, + { 6963, new ProfessionalTask(HboIDomain2018.UserInteraction.Id, HboIDomain2018.Realisation.Id, HboIDomain2018.LevelTwo.Id) }, + { 6964, new ProfessionalTask(HboIDomain2018.UserInteraction.Id, HboIDomain2018.Realisation.Id, HboIDomain2018.LevelTwo.Id) }, + { 6965, new ProfessionalTask(HboIDomain2018.UserInteraction.Id, HboIDomain2018.Realisation.Id, HboIDomain2018.LevelTwo.Id) }, + { 6966, new ProfessionalTask(HboIDomain2018.UserInteraction.Id, HboIDomain2018.Realisation.Id, HboIDomain2018.LevelThree.Id) }, + { 6967, new ProfessionalTask(HboIDomain2018.UserInteraction.Id, HboIDomain2018.Realisation.Id, HboIDomain2018.LevelThree.Id) }, + { 6968, new ProfessionalTask(HboIDomain2018.UserInteraction.Id, HboIDomain2018.Realisation.Id, HboIDomain2018.LevelFour.Id) }, + { 6969, new ProfessionalTask(HboIDomain2018.UserInteraction.Id, HboIDomain2018.Realisation.Id, HboIDomain2018.LevelFour.Id) }, + }; + + public static readonly IDictionary ProfessionalSkills = new Dictionary + { + { 22323, new ProfessionalSkillLevel(HboIDomain2018.FutureOrientedOrganisation.Id, HboIDomain2018.LevelOne.Id) }, + { 22324, new ProfessionalSkillLevel(HboIDomain2018.FutureOrientedOrganisation.Id, HboIDomain2018.LevelOne.Id) }, + { 22338, new ProfessionalSkillLevel(HboIDomain2018.FutureOrientedOrganisation.Id, HboIDomain2018.LevelOne.Id) }, + { 22339, new ProfessionalSkillLevel(HboIDomain2018.FutureOrientedOrganisation.Id, HboIDomain2018.LevelOne.Id) }, + { 22340, new ProfessionalSkillLevel(HboIDomain2018.FutureOrientedOrganisation.Id, HboIDomain2018.LevelOne.Id) }, + { 22325, new ProfessionalSkillLevel(HboIDomain2018.InvestigativeProblemSolving.Id, HboIDomain2018.LevelOne.Id) }, + { 22326, new ProfessionalSkillLevel(HboIDomain2018.InvestigativeProblemSolving.Id, HboIDomain2018.LevelOne.Id) }, + { 22327, new ProfessionalSkillLevel(HboIDomain2018.PersonalLeadership.Id, HboIDomain2018.LevelOne.Id) }, + { 22328, new ProfessionalSkillLevel(HboIDomain2018.PersonalLeadership.Id, HboIDomain2018.LevelOne.Id) }, + { 22329, new ProfessionalSkillLevel(HboIDomain2018.PersonalLeadership.Id, HboIDomain2018.LevelOne.Id) }, + { 22330, new ProfessionalSkillLevel(HboIDomain2018.PersonalLeadership.Id, HboIDomain2018.LevelOne.Id) }, + { 22331, new ProfessionalSkillLevel(HboIDomain2018.PersonalLeadership.Id, HboIDomain2018.LevelOne.Id) }, + { 22332, new ProfessionalSkillLevel(HboIDomain2018.PersonalLeadership.Id, HboIDomain2018.LevelOne.Id) }, + { 22333, new ProfessionalSkillLevel(HboIDomain2018.TargetedInteraction.Id, HboIDomain2018.LevelOne.Id) }, + { 22334, new ProfessionalSkillLevel(HboIDomain2018.TargetedInteraction.Id, HboIDomain2018.LevelOne.Id) }, + { 22335, new ProfessionalSkillLevel(HboIDomain2018.TargetedInteraction.Id, HboIDomain2018.LevelOne.Id) }, + { 22336, new ProfessionalSkillLevel(HboIDomain2018.TargetedInteraction.Id, HboIDomain2018.LevelOne.Id) }, + { 22337, new ProfessionalSkillLevel(HboIDomain2018.TargetedInteraction.Id, HboIDomain2018.LevelOne.Id) }, + { 11460, new ProfessionalSkillLevel(HboIDomain2018.FutureOrientedOrganisation.Id, HboIDomain2018.LevelTwo.Id) }, + { 11462, new ProfessionalSkillLevel(HboIDomain2018.FutureOrientedOrganisation.Id, HboIDomain2018.LevelTwo.Id) }, + { 11463, new ProfessionalSkillLevel(HboIDomain2018.FutureOrientedOrganisation.Id, HboIDomain2018.LevelTwo.Id) }, + { 11464, new ProfessionalSkillLevel(HboIDomain2018.FutureOrientedOrganisation.Id, HboIDomain2018.LevelTwo.Id) }, + { 11465, new ProfessionalSkillLevel(HboIDomain2018.FutureOrientedOrganisation.Id, HboIDomain2018.LevelTwo.Id) }, + { 11466, new ProfessionalSkillLevel(HboIDomain2018.InvestigativeProblemSolving.Id, HboIDomain2018.LevelTwo.Id) }, + { 11467, new ProfessionalSkillLevel(HboIDomain2018.InvestigativeProblemSolving.Id, HboIDomain2018.LevelTwo.Id) }, + { 11468, new ProfessionalSkillLevel(HboIDomain2018.InvestigativeProblemSolving.Id, HboIDomain2018.LevelTwo.Id) }, + { 11469, new ProfessionalSkillLevel(HboIDomain2018.InvestigativeProblemSolving.Id, HboIDomain2018.LevelTwo.Id) }, + { 11470, new ProfessionalSkillLevel(HboIDomain2018.PersonalLeadership.Id, HboIDomain2018.LevelTwo.Id) }, + { 11471, new ProfessionalSkillLevel(HboIDomain2018.PersonalLeadership.Id, HboIDomain2018.LevelTwo.Id) }, + { 11472, new ProfessionalSkillLevel(HboIDomain2018.PersonalLeadership.Id, HboIDomain2018.LevelTwo.Id) }, + { 11473, new ProfessionalSkillLevel(HboIDomain2018.PersonalLeadership.Id, HboIDomain2018.LevelTwo.Id) }, + { 11474, new ProfessionalSkillLevel(HboIDomain2018.PersonalLeadership.Id, HboIDomain2018.LevelTwo.Id) }, + { 11475, new ProfessionalSkillLevel(HboIDomain2018.PersonalLeadership.Id, HboIDomain2018.LevelTwo.Id) }, + { 11476, new ProfessionalSkillLevel(HboIDomain2018.TargetedInteraction.Id, HboIDomain2018.LevelTwo.Id) }, + { 11477, new ProfessionalSkillLevel(HboIDomain2018.TargetedInteraction.Id, HboIDomain2018.LevelTwo.Id) }, + { 11478, new ProfessionalSkillLevel(HboIDomain2018.TargetedInteraction.Id, HboIDomain2018.LevelTwo.Id) }, + { 11479, new ProfessionalSkillLevel(HboIDomain2018.TargetedInteraction.Id, HboIDomain2018.LevelTwo.Id) }, + { 11480, new ProfessionalSkillLevel(HboIDomain2018.TargetedInteraction.Id, HboIDomain2018.LevelTwo.Id) }, + { 11481, new ProfessionalSkillLevel(HboIDomain2018.TargetedInteraction.Id, HboIDomain2018.LevelTwo.Id) }, + { 12286, new ProfessionalSkillLevel(HboIDomain2018.FutureOrientedOrganisation.Id, HboIDomain2018.LevelThree.Id) }, + { 12287, new ProfessionalSkillLevel(HboIDomain2018.FutureOrientedOrganisation.Id, HboIDomain2018.LevelThree.Id) }, + { 12288, new ProfessionalSkillLevel(HboIDomain2018.FutureOrientedOrganisation.Id, HboIDomain2018.LevelThree.Id) }, + { 12289, new ProfessionalSkillLevel(HboIDomain2018.FutureOrientedOrganisation.Id, HboIDomain2018.LevelThree.Id) }, + { 12290, new ProfessionalSkillLevel(HboIDomain2018.FutureOrientedOrganisation.Id, HboIDomain2018.LevelThree.Id) }, + { 12291, new ProfessionalSkillLevel(HboIDomain2018.InvestigativeProblemSolving.Id, HboIDomain2018.LevelThree.Id) }, + { 12292, new ProfessionalSkillLevel(HboIDomain2018.InvestigativeProblemSolving.Id, HboIDomain2018.LevelThree.Id) }, + { 12293, new ProfessionalSkillLevel(HboIDomain2018.InvestigativeProblemSolving.Id, HboIDomain2018.LevelThree.Id) }, + { 12294, new ProfessionalSkillLevel(HboIDomain2018.PersonalLeadership.Id, HboIDomain2018.LevelThree.Id) }, + { 12295, new ProfessionalSkillLevel(HboIDomain2018.PersonalLeadership.Id, HboIDomain2018.LevelThree.Id) }, + { 12296, new ProfessionalSkillLevel(HboIDomain2018.PersonalLeadership.Id, HboIDomain2018.LevelThree.Id) }, + { 12297, new ProfessionalSkillLevel(HboIDomain2018.PersonalLeadership.Id, HboIDomain2018.LevelThree.Id) }, + { 12298, new ProfessionalSkillLevel(HboIDomain2018.PersonalLeadership.Id, HboIDomain2018.LevelThree.Id) }, + { 12299, new ProfessionalSkillLevel(HboIDomain2018.TargetedInteraction.Id, HboIDomain2018.LevelThree.Id) }, + { 12300, new ProfessionalSkillLevel(HboIDomain2018.TargetedInteraction.Id, HboIDomain2018.LevelThree.Id) }, + { 12301, new ProfessionalSkillLevel(HboIDomain2018.TargetedInteraction.Id, HboIDomain2018.LevelThree.Id) }, + }; +} \ No newline at end of file diff --git a/Epsilon/Service/CompetenceComponentService.cs b/Epsilon/Service/CompetenceComponentService.cs new file mode 100644 index 00000000..46ac0143 --- /dev/null +++ b/Epsilon/Service/CompetenceComponentService.cs @@ -0,0 +1,57 @@ +using System.Reflection; +using Epsilon.Abstractions.Component; +using Epsilon.Abstractions.Service; + +namespace Epsilon.Service; + +public class CompetenceComponentService : ICompetenceComponentService +{ + private readonly IEnumerable _componentFetchers; + + public CompetenceComponentService(IEnumerable componentFetchers) + { + _componentFetchers = componentFetchers; + } + + public async IAsyncEnumerable GetComponents(DateTime startDate, DateTime endDate) + { + foreach (var componentFetcher in _componentFetchers) + { + yield return await componentFetcher.FetchUnknown(startDate, endDate); + } + } + + public async IAsyncEnumerable GetComponents(DateTime startDate, DateTime endDate) where TComponent : ICompetenceComponent + { + await foreach (var component in GetComponents(startDate, endDate)) + { + if (component is TComponent componentOfT) + { + yield return componentOfT; + } + } + } + + public async Task GetComponent(string name, DateTime startDate, DateTime endDate) + { + var fetcher = _componentFetchers.SingleOrDefault(f => + { + var componentType = f.GetType().BaseType?.GetGenericArguments()[0]; + if (componentType != null) + { + var componentNameAttribute = componentType.GetCustomAttribute(false); + return componentNameAttribute?.Name == name; + } + + return false; + }); + return fetcher == null + ? null + : await fetcher.FetchUnknown(startDate, endDate); + } + + public async Task GetComponent(string name, DateTime startDate, DateTime endDate) where TComponent : class, ICompetenceComponent + { + return await GetComponent(name, startDate, endDate) as TComponent; + } +} \ No newline at end of file diff --git a/Epsilon/Service/CompetenceDocumentService.cs b/Epsilon/Service/CompetenceDocumentService.cs new file mode 100644 index 00000000..ea67e5b8 --- /dev/null +++ b/Epsilon/Service/CompetenceDocumentService.cs @@ -0,0 +1,41 @@ +using DocumentFormat.OpenXml; +using DocumentFormat.OpenXml.Packaging; +using DocumentFormat.OpenXml.Wordprocessing; +using Epsilon.Abstractions.Component; +using Epsilon.Abstractions.Service; + +namespace Epsilon.Service; + +public class CompetenceDocumentService : ICompetenceDocumentService +{ + private readonly ICompetenceComponentService _competenceComponentService; + + public CompetenceDocumentService(ICompetenceComponentService competenceComponentService) + { + _competenceComponentService = competenceComponentService; + } + + public async Task WriteDocument(Stream stream, DateTime startDate, DateTime endDate) + { + var startPosition = stream.Position; + + var components = await _competenceComponentService.GetComponents(startDate, endDate).ToListAsync(); + using var document = WordprocessingDocument.Create(stream, WordprocessingDocumentType.Document); + + document.AddMainDocumentPart(); + document.MainDocumentPart!.Document = new Document(); + + foreach (var competenceWordComponent in components) + { + competenceWordComponent.AddToWordDocument(document.MainDocumentPart); + } + + document.Save(); + document.Close(); + + // Reset stream position to start position + stream.Position = startPosition; + + return stream; + } +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..a757501c --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "epsilon", + "lockfileVersion": 3, + "requires": true, + "packages": {} +}