From c96f8dc1b9604a4f0bf2ca822dbdf5c683752b70 Mon Sep 17 00:00:00 2001 From: grant-dot-dev <12433404+grant-dot-dev@users.noreply.github.com> Date: Tue, 18 Feb 2025 10:58:04 +0000 Subject: [PATCH 1/3] Upgrade to .Net 8 & add test coverage --- .github/workflows/continuous-integration.yml | 4 +- .gitignore | 6 +- README.md | 57 +- source/.gitignore | 3 +- source/.runsettings | 26 + source/Core.Tests/.gitignore | 264 ++++++ source/Core.Tests/Core.Tests.csproj | 38 + .../Helpers/ApplicationHelperTests.cs | 104 +++ .../Helpers/AttributeExtensionsTests.cs | 87 ++ .../Helpers/ConnectionStringsTests.cs | 20 + .../Helpers/DateFormatConstantsTests.cs | 19 + .../Core.Tests/Helpers/DateTimeHelperTests.cs | 59 ++ source/Core.Tests/Helpers/FilePathTests.cs | 47 + .../Core.Tests/Services/DataServiceTests.cs | 209 +++++ source/Core/.gitignore | 265 ++++++ source/Core/Core.csproj | 23 + source/Core/DTOs/AppConfiguration.cs | 7 + .../DTOs}/Request/AsidLookup.cs | 4 +- source/Core/DTOs/Request/AsidLookupRun.cs | 6 + .../DTOs}/Request/BaseRun.cs | 6 +- .../DTOs}/Request/File.cs | 4 +- .../Request/OrganisationHeirarchyProvider.cs | 15 + .../DTOs}/Request/RequestUri.cs | 6 +- .../DTOs}/Request/SspTransaction.cs | 4 +- .../DTOs}/Request/SspTransactionRun.cs | 6 +- .../Response/Configuration/BlobStorage.cs | 4 +- .../DTOs}/Response/Configuration/Email.cs | 4 +- .../Configuration/FilePathConstants.cs | 4 +- .../DTOs}/Response/Configuration/FileType.cs | 6 +- .../Response/Configuration/SplunkClient.cs | 4 +- .../Response/Configuration/SplunkInstance.cs | 4 +- .../DTOs}/Response/Queue/Message.cs | 4 +- .../DTOs}/Response/Splunk/Extract.cs | 6 +- .../DTOs}/Response/Splunk/ExtractResponse.cs | 8 +- source/Core/Helpers/ApplicationHelper.cs | 23 + source/Core/Helpers/AttributeExtensions.cs | 27 + .../Helpers}/ConnectionStrings.cs | 6 +- .../Helpers}/DateFormatConstants.cs | 6 +- .../Helpers}/DateTimeHelper.cs | 5 +- .../Helpers}/FilePath.cs | 8 +- source/Core/Helpers/FileTypes.cs | 9 + .../Helpers}/SplunkInstance.cs | 4 +- source/Core/Helpers/TimeProvider.cs | 9 + source/Core/IConnectionFactory.cs | 8 + source/Core/ITimeProvider.cs | 16 + .../Mapping/SplunkInstanceMap.cs | 6 +- source/Core/Repositories/DapperWrapper.cs | 68 ++ .../HierarchyProviderConsumerRepo.cs | 66 ++ .../IHierarchyProviderConsumerRepo.cs | 8 + .../Interfaces/IConfigurationService.cs | 10 +- .../Services/Interfaces/ICoreConfiguration.cs | 6 + .../Core/Services/Interfaces/IDataService.cs | 15 + source/Functions.Tests/FilePathHelperTests.cs | 121 +++ source/Functions.Tests/Functions.Tests.csproj | 31 + .../Functions.Tests.csproj.DotSettings | 2 + .../Functions/ExecuteImportByTriggerTests.cs | 57 ++ .../GetDataFromApiByDateRangeTests.cs | 164 ++++ .../Functions/GetDataFromApiManualTests.cs | 104 +++ .../Functions/GetDataFromApiTodayTests.cs | 234 +++++ .../GetDataFromApiTodayTimerTests.cs | 67 ++ .../Functions/PurgeErrorLogByTriggerTests.cs | 33 + .../StoreProviderConsumerDataTests.cs | 146 +++ .../HttpClientExtensionsTests.cs | 39 + source/Functions.Tests/LoggingServiceTests.cs | 33 + source/Functions.Tests/RequestWrappers.cs | 42 + .../Services/BatchServiceTests.cs | 277 ++++++ .../Services/BlobServiceTests.cs | 326 +++++++ .../Services/ConfigurationServiceTests.cs | 255 ++++++ .../Services/CoreConfigurationServiceTests.cs | 56 ++ .../Services/FileServiceTests.cs | 29 + .../Services/ImportServiceTests.cs | 315 +++++++ .../Services/SplunkServicesTests.cs | 294 ++++++ .../TestHelpers/ConfigurationHelpers.cs | 30 + .../TestHelpers/MockRequests.cs | 56 ++ .../TestHelpers/MockTriggers.cs | 14 + .../.gitignore | 0 .../EmailConfigurationProvider.cs | 29 + .../HttpClient/HttpClientExtensions.cs | 23 + .../Logging/LoggingExtensions.cs | 87 +- .../Mapping/MappingExtensions.cs | 13 + .../Dockerfile | 0 source/Functions/ExecuteImportByTrigger.cs | 16 + source/Functions/Functions.csproj | 39 + source/Functions/GetDataFromApiByDateRange.cs | 85 ++ source/Functions/GetDataFromApiByTrigger.cs | 34 + source/Functions/GetDataFromApiManual.cs | 42 + source/Functions/GetDataFromApiToday.cs | 98 ++ .../Functions/HelperClasses/FilePathHelper.cs | 54 ++ source/Functions/Program.cs | 54 ++ .../Properties/launchSettings.json | 0 source/Functions/PurgeErrorLogByTrigger.cs | 16 + source/Functions/Services/BatchService.cs | 146 +++ .../Services}/BlobService.cs | 59 +- .../Services/ConfigurationService.cs | 61 ++ .../Services/CoreConfigurationService.cs | 14 + source/Functions/Services/DataService.cs | 113 +++ source/Functions/Services/FileService.cs | 19 + source/Functions/Services/ImportService.cs | 84 ++ .../Services/Interfaces/IBatchService.cs | 14 + .../Services/Interfaces/IBlobService.cs | 11 + .../Services/Interfaces/IFileService.cs | 6 + .../Services/Interfaces/IImportService.cs | 13 + .../Services}/Interfaces/ILoggingService.cs | 6 +- .../Services/Interfaces/ISplunkService.cs | 12 + .../Services}/LoggingService.cs | 8 +- .../Services}/SplunkService.cs | 115 +-- source/Functions/SqlConnectionFactory.cs | 13 + source/Functions/StoreProviderConsumerData.cs | 68 ++ .../host.json | 5 - source/Functions/nlog.config.xml | 15 + .../DapperTestSetupFixture.cs | 74 ++ .../DapperWrapperIntegrationTests.cs | 147 +++ .../EmailConfigurationProviderTests.cs | 131 +++ .../HierarchyProviderConsumerRepoTests.cs | 119 +++ .../IntegrationTests/IntegrationTests.csproj | 51 ++ .../IntegrationTests/MsSqlContainerFixture.cs | 77 ++ .../TestHelpers/ConfigurationHelpers.cs | 25 + source/coverage/Core_ApplicationHelper.html | 198 +++++ source/coverage/Core_AttributeExtensions.html | 202 +++++ source/coverage/Core_ConnectionStrings.html | 180 ++++ source/coverage/Core_DapperWrapper.html | 247 ++++++ source/coverage/Core_DateTimeHelper.html | 184 ++++ source/coverage/Core_FilePathAttribute.html | 185 ++++ .../Core_HierarchyProviderConsumerRepo.html | 235 +++++ .../Core_OrganisationHierarchyProvider.html | 192 ++++ source/coverage/Core_SplunkInstanceMap.html | 187 ++++ source/coverage/Core_TimeProvider.html | 187 ++++ source/coverage/Functions_BatchService.html | 327 +++++++ source/coverage/Functions_BlobService.html | 270 ++++++ .../Functions_ConfigurationService.html | 244 +++++ .../Functions_CoreConfigurationService.html | 187 ++++ source/coverage/Functions_DataService.html | 296 +++++++ .../Functions_DirectFunctionExecutor.html | 169 ++++ .../Functions_EmailConfigurationProvider.html | 202 +++++ .../Functions_ExecuteImportByTrigger.html | 189 ++++ source/coverage/Functions_FileService.html | 192 ++++ ...Functions_FunctionExecutorAutoStartup.html | 167 ++++ ...FunctionExecutorHostBuilderExtensions.html | 167 ++++ ...s_FunctionMetadataProviderAutoStartup.html | 167 ++++ ...ons_GeneratedFunctionMetadataProvider.html | 167 ++++ .../Functions_GetDataFromApiByDateRange.html | 262 ++++++ .../Functions_GetDataFromApiByTrigger.html | 211 +++++ .../Functions_GetDataFromApiManual.html | 215 +++++ .../Functions_GetDataFromApiToday.html | 275 ++++++ .../Functions_HttpClientExtensions.html | 198 +++++ source/coverage/Functions_ImportService.html | 261 ++++++ .../coverage/Functions_LoggingExtensions.html | 368 ++++++++ source/coverage/Functions_LoggingService.html | 196 ++++ .../coverage/Functions_MappingExtensions.html | 186 ++++ source/coverage/Functions_Program.html | 227 +++++ .../Functions_PurgeErrorLogByTrigger.html | 189 ++++ source/coverage/Functions_SplunkService.html | 366 ++++++++ .../Functions_SqlConnectionFactory.html | 186 ++++ .../Functions_StoreProviderConsumerData.html | 242 +++++ ...ns_WorkerExtensionStartupCodeExecutor.html | 167 ++++ ...lderFunctionMetadataProviderExtension.html | 167 ++++ source/coverage/class.js | 218 +++++ source/coverage/icon_cog.svg | 1 + source/coverage/icon_cog_dark.svg | 1 + source/coverage/icon_cube.svg | 2 + source/coverage/icon_cube_dark.svg | 1 + source/coverage/icon_fork.svg | 2 + source/coverage/icon_fork_dark.svg | 1 + source/coverage/icon_info-circled.svg | 2 + source/coverage/icon_info-circled_dark.svg | 2 + source/coverage/icon_minus.svg | 2 + source/coverage/icon_minus_dark.svg | 1 + source/coverage/icon_plus.svg | 2 + source/coverage/icon_plus_dark.svg | 1 + source/coverage/icon_search-minus.svg | 2 + source/coverage/icon_search-minus_dark.svg | 1 + source/coverage/icon_search-plus.svg | 2 + source/coverage/icon_search-plus_dark.svg | 1 + source/coverage/icon_sponsor.svg | 2 + source/coverage/icon_star.svg | 2 + source/coverage/icon_star_dark.svg | 2 + source/coverage/icon_up-dir.svg | 2 + source/coverage/icon_up-dir_active.svg | 2 + source/coverage/icon_up-down-dir.svg | 2 + source/coverage/icon_up-down-dir_dark.svg | 2 + source/coverage/icon_wrench.svg | 2 + source/coverage/icon_wrench_dark.svg | 1 + source/coverage/index.htm | 234 +++++ source/coverage/index.html | 234 +++++ source/coverage/main.js | 334 +++++++ source/coverage/report.css | 834 ++++++++++++++++++ source/global.json | 5 + .../gpconnect-analytics.DAL/BatchService.cs | 161 ---- .../ConfigurationService.cs | 63 -- source/gpconnect-analytics.DAL/DataService.cs | 88 -- .../gpconnect-analytics.DAL/ImportService.cs | 101 --- .../Interfaces/IBatchService.cs | 19 - .../Interfaces/IBlobService.cs | 12 - .../Interfaces/IDataService.cs | 13 - .../Interfaces/IImportService.cs | 17 - .../Interfaces/ISplunkService.cs | 12 - .../gpconnect-analytics.DAL.csproj | 29 - .../Request/AsidLookupRun.cs | 6 - .../Response/Import/NextFile.cs | 7 - .../gpconnect-analytics.DTO.csproj | 13 - .../HttpClient/HttpClientExtensions.cs | 27 - .../Mapping/MappingExtensions.cs | 16 - .../ExecuteImportByTrigger.cs | 24 - .../GetDataFromApiByDateRange.cs | 39 - .../GetDataFromApiByTrigger.cs | 36 - .../GetDataFromApiManual.cs | 26 - .../GetDataFromApiToday.cs | 39 - .../PurgeErrorLogByTrigger.cs | 23 - .../gpconnect-analytics.Functions/Startup.cs | 31 - .../gpconnect-analytics.Functions.csproj | 32 - .../ApplicationHelper.cs | 20 - .../AttributeExtensions.cs | 21 - .../ConfigurationHelper.cs | 15 - .../gpconnect-analytics.Helpers/FileTypes.cs | 12 - .../NumberExtensions.cs | 23 - .../StringExtensions.cs | 13 - .../gpconnect-analytics.Helpers.csproj | 12 - source/gpconnect-analytics.sln | 38 +- source/gpconnect-analytics.sln.DotSettings | 16 + 219 files changed, 16537 insertions(+), 1178 deletions(-) create mode 100644 source/.runsettings create mode 100644 source/Core.Tests/.gitignore create mode 100644 source/Core.Tests/Core.Tests.csproj create mode 100644 source/Core.Tests/Helpers/ApplicationHelperTests.cs create mode 100644 source/Core.Tests/Helpers/AttributeExtensionsTests.cs create mode 100644 source/Core.Tests/Helpers/ConnectionStringsTests.cs create mode 100644 source/Core.Tests/Helpers/DateFormatConstantsTests.cs create mode 100644 source/Core.Tests/Helpers/DateTimeHelperTests.cs create mode 100644 source/Core.Tests/Helpers/FilePathTests.cs create mode 100644 source/Core.Tests/Services/DataServiceTests.cs create mode 100644 source/Core/.gitignore create mode 100644 source/Core/Core.csproj create mode 100644 source/Core/DTOs/AppConfiguration.cs rename source/{gpconnect-analytics.DTO => Core/DTOs}/Request/AsidLookup.cs (87%) create mode 100644 source/Core/DTOs/Request/AsidLookupRun.cs rename source/{gpconnect-analytics.DTO => Core/DTOs}/Request/BaseRun.cs (86%) rename source/{gpconnect-analytics.DTO => Core/DTOs}/Request/File.cs (72%) create mode 100644 source/Core/DTOs/Request/OrganisationHeirarchyProvider.cs rename source/{gpconnect-analytics.DTO => Core/DTOs}/Request/RequestUri.cs (78%) rename source/{gpconnect-analytics.DTO => Core/DTOs}/Request/SspTransaction.cs (91%) rename source/{gpconnect-analytics.DTO => Core/DTOs}/Request/SspTransactionRun.cs (72%) rename source/{gpconnect-analytics.DTO => Core/DTOs}/Response/Configuration/BlobStorage.cs (83%) rename source/{gpconnect-analytics.DTO => Core/DTOs}/Response/Configuration/Email.cs (88%) rename source/{gpconnect-analytics.DTO => Core/DTOs}/Response/Configuration/FilePathConstants.cs (83%) rename source/{gpconnect-analytics.DTO => Core/DTOs}/Response/Configuration/FileType.cs (84%) rename source/{gpconnect-analytics.DTO => Core/DTOs}/Response/Configuration/SplunkClient.cs (85%) rename source/{gpconnect-analytics.DTO => Core/DTOs}/Response/Configuration/SplunkInstance.cs (68%) rename source/{gpconnect-analytics.DTO => Core/DTOs}/Response/Queue/Message.cs (76%) rename source/{gpconnect-analytics.DTO => Core/DTOs}/Response/Splunk/Extract.cs (80%) rename source/{gpconnect-analytics.DTO => Core/DTOs}/Response/Splunk/ExtractResponse.cs (71%) create mode 100644 source/Core/Helpers/ApplicationHelper.cs create mode 100644 source/Core/Helpers/AttributeExtensions.cs rename source/{gpconnect-analytics.DAL => Core/Helpers}/ConnectionStrings.cs (65%) rename source/{gpconnect-analytics.Helpers => Core/Helpers}/DateFormatConstants.cs (82%) rename source/{gpconnect-analytics.Helpers => Core/Helpers}/DateTimeHelper.cs (74%) rename source/{gpconnect-analytics.Helpers => Core/Helpers}/FilePath.cs (57%) create mode 100644 source/Core/Helpers/FileTypes.cs rename source/{gpconnect-analytics.Helpers => Core/Helpers}/SplunkInstance.cs (68%) create mode 100644 source/Core/Helpers/TimeProvider.cs create mode 100644 source/Core/IConnectionFactory.cs create mode 100644 source/Core/ITimeProvider.cs rename source/{gpconnect-analytics.DAL => Core}/Mapping/SplunkInstanceMap.cs (74%) create mode 100644 source/Core/Repositories/DapperWrapper.cs create mode 100644 source/Core/Repositories/HierarchyProviderConsumerRepo.cs create mode 100644 source/Core/Repositories/IHierarchyProviderConsumerRepo.cs rename source/{gpconnect-analytics.DAL => Core/Services}/Interfaces/IConfigurationService.cs (66%) create mode 100644 source/Core/Services/Interfaces/ICoreConfiguration.cs create mode 100644 source/Core/Services/Interfaces/IDataService.cs create mode 100644 source/Functions.Tests/FilePathHelperTests.cs create mode 100644 source/Functions.Tests/Functions.Tests.csproj create mode 100644 source/Functions.Tests/Functions.Tests.csproj.DotSettings create mode 100644 source/Functions.Tests/Functions/ExecuteImportByTriggerTests.cs create mode 100644 source/Functions.Tests/Functions/GetDataFromApiByDateRangeTests.cs create mode 100644 source/Functions.Tests/Functions/GetDataFromApiManualTests.cs create mode 100644 source/Functions.Tests/Functions/GetDataFromApiTodayTests.cs create mode 100644 source/Functions.Tests/Functions/GetDataFromApiTodayTimerTests.cs create mode 100644 source/Functions.Tests/Functions/PurgeErrorLogByTriggerTests.cs create mode 100644 source/Functions.Tests/Functions/StoreProviderConsumerDataTests.cs create mode 100644 source/Functions.Tests/HttpClientExtensionsTests.cs create mode 100644 source/Functions.Tests/LoggingServiceTests.cs create mode 100644 source/Functions.Tests/RequestWrappers.cs create mode 100644 source/Functions.Tests/Services/BatchServiceTests.cs create mode 100644 source/Functions.Tests/Services/BlobServiceTests.cs create mode 100644 source/Functions.Tests/Services/ConfigurationServiceTests.cs create mode 100644 source/Functions.Tests/Services/CoreConfigurationServiceTests.cs create mode 100644 source/Functions.Tests/Services/FileServiceTests.cs create mode 100644 source/Functions.Tests/Services/ImportServiceTests.cs create mode 100644 source/Functions.Tests/Services/SplunkServicesTests.cs create mode 100644 source/Functions.Tests/TestHelpers/ConfigurationHelpers.cs create mode 100644 source/Functions.Tests/TestHelpers/MockRequests.cs create mode 100644 source/Functions.Tests/TestHelpers/MockTriggers.cs rename source/{gpconnect-analytics.Functions => Functions}/.gitignore (100%) create mode 100644 source/Functions/Configuration/EmailConfigurationProvider.cs create mode 100644 source/Functions/Configuration/Infrastructure/HttpClient/HttpClientExtensions.cs rename source/{gpconnect-analytics.Functions => Functions}/Configuration/Infrastructure/Logging/LoggingExtensions.cs (69%) create mode 100644 source/Functions/Configuration/Infrastructure/Mapping/MappingExtensions.cs rename source/{gpconnect-analytics.Functions => Functions}/Dockerfile (100%) create mode 100644 source/Functions/ExecuteImportByTrigger.cs create mode 100644 source/Functions/Functions.csproj create mode 100644 source/Functions/GetDataFromApiByDateRange.cs create mode 100644 source/Functions/GetDataFromApiByTrigger.cs create mode 100644 source/Functions/GetDataFromApiManual.cs create mode 100644 source/Functions/GetDataFromApiToday.cs create mode 100644 source/Functions/HelperClasses/FilePathHelper.cs create mode 100644 source/Functions/Program.cs rename source/{gpconnect-analytics.Functions => Functions}/Properties/launchSettings.json (100%) create mode 100644 source/Functions/PurgeErrorLogByTrigger.cs create mode 100644 source/Functions/Services/BatchService.cs rename source/{gpconnect-analytics.DAL => Functions/Services}/BlobService.cs (56%) create mode 100644 source/Functions/Services/ConfigurationService.cs create mode 100644 source/Functions/Services/CoreConfigurationService.cs create mode 100644 source/Functions/Services/DataService.cs create mode 100644 source/Functions/Services/FileService.cs create mode 100644 source/Functions/Services/ImportService.cs create mode 100644 source/Functions/Services/Interfaces/IBatchService.cs create mode 100644 source/Functions/Services/Interfaces/IBlobService.cs create mode 100644 source/Functions/Services/Interfaces/IFileService.cs create mode 100644 source/Functions/Services/Interfaces/IImportService.cs rename source/{gpconnect-analytics.DAL => Functions/Services}/Interfaces/ILoggingService.cs (50%) create mode 100644 source/Functions/Services/Interfaces/ISplunkService.cs rename source/{gpconnect-analytics.DAL => Functions/Services}/LoggingService.cs (79%) rename source/{gpconnect-analytics.DAL => Functions/Services}/SplunkService.cs (55%) create mode 100644 source/Functions/SqlConnectionFactory.cs create mode 100644 source/Functions/StoreProviderConsumerData.cs rename source/{gpconnect-analytics.Functions => Functions}/host.json (61%) create mode 100644 source/Functions/nlog.config.xml create mode 100644 source/IntegrationTests/DapperTestSetupFixture.cs create mode 100644 source/IntegrationTests/DapperWrapperIntegrationTests.cs create mode 100644 source/IntegrationTests/EmailConfigurationProviderTests.cs create mode 100644 source/IntegrationTests/HierarchyProviderConsumerRepoTests.cs create mode 100644 source/IntegrationTests/IntegrationTests.csproj create mode 100644 source/IntegrationTests/MsSqlContainerFixture.cs create mode 100644 source/IntegrationTests/TestHelpers/ConfigurationHelpers.cs create mode 100644 source/coverage/Core_ApplicationHelper.html create mode 100644 source/coverage/Core_AttributeExtensions.html create mode 100644 source/coverage/Core_ConnectionStrings.html create mode 100644 source/coverage/Core_DapperWrapper.html create mode 100644 source/coverage/Core_DateTimeHelper.html create mode 100644 source/coverage/Core_FilePathAttribute.html create mode 100644 source/coverage/Core_HierarchyProviderConsumerRepo.html create mode 100644 source/coverage/Core_OrganisationHierarchyProvider.html create mode 100644 source/coverage/Core_SplunkInstanceMap.html create mode 100644 source/coverage/Core_TimeProvider.html create mode 100644 source/coverage/Functions_BatchService.html create mode 100644 source/coverage/Functions_BlobService.html create mode 100644 source/coverage/Functions_ConfigurationService.html create mode 100644 source/coverage/Functions_CoreConfigurationService.html create mode 100644 source/coverage/Functions_DataService.html create mode 100644 source/coverage/Functions_DirectFunctionExecutor.html create mode 100644 source/coverage/Functions_EmailConfigurationProvider.html create mode 100644 source/coverage/Functions_ExecuteImportByTrigger.html create mode 100644 source/coverage/Functions_FileService.html create mode 100644 source/coverage/Functions_FunctionExecutorAutoStartup.html create mode 100644 source/coverage/Functions_FunctionExecutorHostBuilderExtensions.html create mode 100644 source/coverage/Functions_FunctionMetadataProviderAutoStartup.html create mode 100644 source/coverage/Functions_GeneratedFunctionMetadataProvider.html create mode 100644 source/coverage/Functions_GetDataFromApiByDateRange.html create mode 100644 source/coverage/Functions_GetDataFromApiByTrigger.html create mode 100644 source/coverage/Functions_GetDataFromApiManual.html create mode 100644 source/coverage/Functions_GetDataFromApiToday.html create mode 100644 source/coverage/Functions_HttpClientExtensions.html create mode 100644 source/coverage/Functions_ImportService.html create mode 100644 source/coverage/Functions_LoggingExtensions.html create mode 100644 source/coverage/Functions_LoggingService.html create mode 100644 source/coverage/Functions_MappingExtensions.html create mode 100644 source/coverage/Functions_Program.html create mode 100644 source/coverage/Functions_PurgeErrorLogByTrigger.html create mode 100644 source/coverage/Functions_SplunkService.html create mode 100644 source/coverage/Functions_SqlConnectionFactory.html create mode 100644 source/coverage/Functions_StoreProviderConsumerData.html create mode 100644 source/coverage/Functions_WorkerExtensionStartupCodeExecutor.html create mode 100644 source/coverage/Functions_WorkerHostBuilderFunctionMetadataProviderExtension.html create mode 100644 source/coverage/class.js create mode 100644 source/coverage/icon_cog.svg create mode 100644 source/coverage/icon_cog_dark.svg create mode 100644 source/coverage/icon_cube.svg create mode 100644 source/coverage/icon_cube_dark.svg create mode 100644 source/coverage/icon_fork.svg create mode 100644 source/coverage/icon_fork_dark.svg create mode 100644 source/coverage/icon_info-circled.svg create mode 100644 source/coverage/icon_info-circled_dark.svg create mode 100644 source/coverage/icon_minus.svg create mode 100644 source/coverage/icon_minus_dark.svg create mode 100644 source/coverage/icon_plus.svg create mode 100644 source/coverage/icon_plus_dark.svg create mode 100644 source/coverage/icon_search-minus.svg create mode 100644 source/coverage/icon_search-minus_dark.svg create mode 100644 source/coverage/icon_search-plus.svg create mode 100644 source/coverage/icon_search-plus_dark.svg create mode 100644 source/coverage/icon_sponsor.svg create mode 100644 source/coverage/icon_star.svg create mode 100644 source/coverage/icon_star_dark.svg create mode 100644 source/coverage/icon_up-dir.svg create mode 100644 source/coverage/icon_up-dir_active.svg create mode 100644 source/coverage/icon_up-down-dir.svg create mode 100644 source/coverage/icon_up-down-dir_dark.svg create mode 100644 source/coverage/icon_wrench.svg create mode 100644 source/coverage/icon_wrench_dark.svg create mode 100644 source/coverage/index.htm create mode 100644 source/coverage/index.html create mode 100644 source/coverage/main.js create mode 100644 source/coverage/report.css create mode 100644 source/global.json delete mode 100644 source/gpconnect-analytics.DAL/BatchService.cs delete mode 100644 source/gpconnect-analytics.DAL/ConfigurationService.cs delete mode 100644 source/gpconnect-analytics.DAL/DataService.cs delete mode 100644 source/gpconnect-analytics.DAL/ImportService.cs delete mode 100644 source/gpconnect-analytics.DAL/Interfaces/IBatchService.cs delete mode 100644 source/gpconnect-analytics.DAL/Interfaces/IBlobService.cs delete mode 100644 source/gpconnect-analytics.DAL/Interfaces/IDataService.cs delete mode 100644 source/gpconnect-analytics.DAL/Interfaces/IImportService.cs delete mode 100644 source/gpconnect-analytics.DAL/Interfaces/ISplunkService.cs delete mode 100644 source/gpconnect-analytics.DAL/gpconnect-analytics.DAL.csproj delete mode 100644 source/gpconnect-analytics.DTO/Request/AsidLookupRun.cs delete mode 100644 source/gpconnect-analytics.DTO/Response/Import/NextFile.cs delete mode 100644 source/gpconnect-analytics.DTO/gpconnect-analytics.DTO.csproj delete mode 100644 source/gpconnect-analytics.Functions/Configuration/Infrastructure/HttpClient/HttpClientExtensions.cs delete mode 100644 source/gpconnect-analytics.Functions/Configuration/Infrastructure/Mapping/MappingExtensions.cs delete mode 100644 source/gpconnect-analytics.Functions/ExecuteImportByTrigger.cs delete mode 100644 source/gpconnect-analytics.Functions/GetDataFromApiByDateRange.cs delete mode 100644 source/gpconnect-analytics.Functions/GetDataFromApiByTrigger.cs delete mode 100644 source/gpconnect-analytics.Functions/GetDataFromApiManual.cs delete mode 100644 source/gpconnect-analytics.Functions/GetDataFromApiToday.cs delete mode 100644 source/gpconnect-analytics.Functions/PurgeErrorLogByTrigger.cs delete mode 100644 source/gpconnect-analytics.Functions/Startup.cs delete mode 100644 source/gpconnect-analytics.Functions/gpconnect-analytics.Functions.csproj delete mode 100644 source/gpconnect-analytics.Helpers/ApplicationHelper.cs delete mode 100644 source/gpconnect-analytics.Helpers/AttributeExtensions.cs delete mode 100644 source/gpconnect-analytics.Helpers/ConfigurationHelper.cs delete mode 100644 source/gpconnect-analytics.Helpers/FileTypes.cs delete mode 100644 source/gpconnect-analytics.Helpers/NumberExtensions.cs delete mode 100644 source/gpconnect-analytics.Helpers/StringExtensions.cs delete mode 100644 source/gpconnect-analytics.Helpers/gpconnect-analytics.Helpers.csproj create mode 100644 source/gpconnect-analytics.sln.DotSettings diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 25c730e..7fa3c31 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -25,8 +25,8 @@ jobs: - name: Set up dotnet uses: actions/setup-dotnet@v1 with: - dotnet-version: '3.1.x' - + dotnet-version: '8.0.x' + - name: Build dotnet solution run: dotnet build source/gpconnect-analytics.sln diff --git a/.gitignore b/.gitignore index 7dbaf57..7b4683f 100644 --- a/.gitignore +++ b/.gitignore @@ -4,8 +4,12 @@ .vs *.ps1 +.vscode +**/CoverageReport/ +**/TestResults/ database/flyway-7.0.0/ serviceDependencies.json serviceDependencies.local.json *.arm.json -/source/gpconnect-analytics.Functions/Properties/PublishProfiles/GPConnectAnalytics - Zip Deploy.pubxml +/source/gpconnect-analytics.Functions/Properties/PublishProfiles/GPConnectAnalytics - Zip Deploy.pubxml.DS_Store +.DS_Store \ No newline at end of file diff --git a/README.md b/README.md index 579c36a..fea345c 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ [![Build Actions Status](https://github.com/nhsconnect/gpconnect-analytics/workflows/continuous-integration/badge.svg)](https://github.com/nhsconnect/gpconnect-analytics/actions?) ## End-to-end data flow + ![End-to-end diagram](documentation/end-to-end-data-flow.png) ## Data extracts @@ -41,13 +42,13 @@ General format: `PROJECTNAME-EXTRACTNAME-QUERYFROMDATE-QUERYTODATE-SPLUNKINSTANCE-EXTRACTDATE.csv` -Where - - PROJECTNAME is `gpcanalytics` - - EXTRACTNAME is `asidlookup`, `ssptrans` (MESH transactions TBC) - - QUERYDATEFROM and QUERYDATETO is `YYYYMMDDTHHmmss` - - SPLUNKINSTANCE is `cloud`, `spinea`, `spineb` - - EXTRACTDATE is `YYYYMMDDTHHmmss` +Where +- PROJECTNAME is `gpcanalytics` +- EXTRACTNAME is `asidlookup`, `ssptrans` (MESH transactions TBC) +- QUERYDATEFROM and QUERYDATETO is `YYYYMMDDTHHmmss` +- SPLUNKINSTANCE is `cloud`, `spinea`, `spineb` +- EXTRACTDATE is `YYYYMMDDTHHmmss` Examples: @@ -55,7 +56,8 @@ Examples: - `gpcanalytics-ssptrans-20200101T000000-20200107T000000-cloud-20210105T103000.csv` - `gpcanalytics-ssptrans-20200107T000000-2020014T000000-spinea-20210105T103000.csv` -Note: The QUERYDATEFROM and QUERYDATETO don't affect the output of the ASID lookup data query from Splunk, however are included for consistency. +Note: The QUERYDATEFROM and QUERYDATETO don't affect the output of the ASID lookup data query from Splunk, however are +included for consistency. ## Run a local SQL Server instance @@ -67,3 +69,44 @@ To run the instance on the default port: `docker run -e 'ACCEPT_EULA=Y' -e 'SA_PASSWORD=StrongP@ssword1' -p 1433:1433 -d mcr.microsoft.com/mssql/server` +## Testing + +Tests were added the project on 8th Feb 2025 by Grant Riordan covering: + +- Core Project +- Functions Project +- Integration test for Hierarchy repository + +### How To Run Coverage Report + +**Run the coverage tests**: + +If you do not own a DotCover license or equivalent, you can use `coverlet` a free tool for running coverage reports. + +- navigate to the `/source` directory +- open terminal and paste + +```bash +dotnet test --collect:"XPlat Code Coverage" -m:1 +``` + +or + +```bash +dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=lcov + +``` + +**Install Report Generator Globally** +Report generator allows us to build a html report of the coverage making it easier to view. + +run the following to install: +```bash +dotnet tool install -g dotnet-reportgenerator-globaltool + +``` +then run the following to merge the coverage results into 1 report file + +```bash +reportgenerator -reports:"../**/coverage.cobertura.xml" -reporttypes:"html" -targetdir:"./CoverageReport" +- ``` diff --git a/source/.gitignore b/source/.gitignore index ffdf0c2..9824b04 100644 --- a/source/.gitignore +++ b/source/.gitignore @@ -44,6 +44,7 @@ dlldata.c project.lock.json project.fragment.lock.json artifacts/ +coverage/* *_i.c *_p.c @@ -254,4 +255,4 @@ paket-files/ *.sln.iml # CodeRush -.cr/ \ No newline at end of file +.cr/.DS_Store diff --git a/source/.runsettings b/source/.runsettings new file mode 100644 index 0000000..3a90f83 --- /dev/null +++ b/source/.runsettings @@ -0,0 +1,26 @@ + + + + + + + cobertura,opencover + + [Core.DTOs]*, + [Core.DTOs.*]* + + + **/*.g.cs, + **/Generated*.cs, + **/Program.cs, + **/Microsoft.Azure.Functions.Worker.Sdk.Generators/**/*.cs + + + GeneratedCodeAttribute + + true + + + + + \ No newline at end of file diff --git a/source/Core.Tests/.gitignore b/source/Core.Tests/.gitignore new file mode 100644 index 0000000..c74c428 --- /dev/null +++ b/source/Core.Tests/.gitignore @@ -0,0 +1,264 @@ +/coveragereport +/TestResults + +# Azure Functions localsettings file +local.settings.json + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +project.fragment.lock.json +artifacts/ + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +#*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignoreable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc \ No newline at end of file diff --git a/source/Core.Tests/Core.Tests.csproj b/source/Core.Tests/Core.Tests.csproj new file mode 100644 index 0000000..6891900 --- /dev/null +++ b/source/Core.Tests/Core.Tests.csproj @@ -0,0 +1,38 @@ + + + + net8.0 + enable + enable + + false + true + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + diff --git a/source/Core.Tests/Helpers/ApplicationHelperTests.cs b/source/Core.Tests/Helpers/ApplicationHelperTests.cs new file mode 100644 index 0000000..dc23801 --- /dev/null +++ b/source/Core.Tests/Helpers/ApplicationHelperTests.cs @@ -0,0 +1,104 @@ +using System.Reflection; +using Core.Helpers; +using FluentAssertions; +using Moq; +using Xunit; + +namespace Core.Tests.Helpers; + +public class ApplicationHelperTests +{ + public ApplicationHelperTests() + { + // Reset the environment variable before each test + Environment.SetEnvironmentVariable("BUILD_TAG", null); + } + + [Fact] + public void GetAssemblyVersionInternal_ShouldReturnAssemblyFullName_WhenBuildTagIsNull() + { + // Arrange + Environment.SetEnvironmentVariable("BUILD_TAG", null); + var mockAssembly = new Mock>(); + mockAssembly.Setup(x => x.Invoke()).Returns(typeof(ApplicationHelper).Assembly); + + // Act + var result = ApplicationHelper.ApplicationVersion.GetAssemblyVersionInternal(mockAssembly.Object); + + // Assert + result.Should().Be(typeof(ApplicationHelper).Assembly.GetName().FullName); + } + + [Fact] + public void GetAssemblyVersion_ShouldReturnAssemblyFullName_WhenBuildTagIsNull() + { + // Arrange + Environment.SetEnvironmentVariable("BUILD_TAG", null); + + // Act + var result = ApplicationHelper.ApplicationVersion.GetAssemblyVersion(); + + // Assert + result.Should().Be(typeof(ApplicationHelper).Assembly.GetName().FullName); + } + + [Fact] + public void GetAssemblyVersionInternal_ShouldReturnAssemblyFullName_WhenBuildTagIsEmpty() + { + // Arrange + Environment.SetEnvironmentVariable("BUILD_TAG", ""); + var mockAssembly = new Mock>(); + mockAssembly.Setup(x => x.Invoke()).Returns(typeof(ApplicationHelper).Assembly); + + // Act + var result = ApplicationHelper.ApplicationVersion.GetAssemblyVersionInternal(mockAssembly.Object); + + // Assert + result.Should().Be(typeof(ApplicationHelper).Assembly.GetName().FullName); + } + + [Fact] + public void GetAssemblyVersionInternal_ShouldReturnAssemblyFullName_WhenBuildTagIsWhitespace() + { + // Arrange + Environment.SetEnvironmentVariable("BUILD_TAG", " "); + var mockAssembly = new Mock>(); + mockAssembly.Setup(x => x.Invoke()).Returns(typeof(ApplicationHelper).Assembly); + + // Act + var result = ApplicationHelper.ApplicationVersion.GetAssemblyVersionInternal(mockAssembly.Object); + + // Assert + result.Should().Be(typeof(ApplicationHelper).Assembly.GetName().FullName); + } + + [Fact] + public void GetAssemblyVersionInternal_ShouldReturnBuildTag_WhenBuildTagIsSet() + { + // Arrange + string expectedBuildTag = "1.0.0-Build123"; + Environment.SetEnvironmentVariable("BUILD_TAG", expectedBuildTag); + var mockAssembly = new Mock>(); + + // Act + var result = ApplicationHelper.ApplicationVersion.GetAssemblyVersionInternal(mockAssembly.Object); + + // Assert + result.Should().Be(expectedBuildTag); + } + + [Fact] + public void GetAssemblyVersionInternal_ShouldHandleNullAssembly() + { + // Arrange + Environment.SetEnvironmentVariable("BUILD_TAG", null); + var mockAssembly = new Mock>(); + mockAssembly.Setup(x => x.Invoke()).Returns((Assembly)null); + + // Act + var result = ApplicationHelper.ApplicationVersion.GetAssemblyVersionInternal(mockAssembly.Object); + + // Assert + result.Should().BeNull(); + } +} \ No newline at end of file diff --git a/source/Core.Tests/Helpers/AttributeExtensionsTests.cs b/source/Core.Tests/Helpers/AttributeExtensionsTests.cs new file mode 100644 index 0000000..32974bb --- /dev/null +++ b/source/Core.Tests/Helpers/AttributeExtensionsTests.cs @@ -0,0 +1,87 @@ +using Core.Helpers; +using FluentAssertions; +using Xunit; + +namespace Core.Tests.Helpers +{ + public class AttributeExtensionsTests + { + [Fact] + public void GetFileType_ShouldReturnDocument_ForDocumentPath() + { + // Arrange + const string filePath = "/asid-lookup-data/report.docx"; + + // Act + var fileType = filePath.GetFileType(); + + // Assert + fileType.Should().Be(FileTypes.asidlookup); + } + + [Fact] + public void GetFileType_ShouldReturnImage_ForImagePath() + { + // Arrange + const string filePath = "/ssp-transactions/file1.csv"; + + // Act + var fileType = filePath.GetFileType(); + + // Assert + fileType.Should().Be(FileTypes.ssptrans); + } + + [Fact] + public void GetFileType_ShouldReturnVideo_ForVideoPath() + { + // Arrange + const string filePath = "/mesh-transactions/file1.csv"; + + // Act + var fileType = filePath.GetFileType(); + + // Assert + fileType.Should().Be(FileTypes.meshtrans); + } + + [Fact] + public void GetFileType_ShouldReturnNull_ForUnknownPath() + { + // Arrange + const string filePath = "/unknown/path/file.txt"; + + // Act + var fileType = filePath.GetFileType(); + + // Assert + fileType.Should().BeNull(); + } + + [Fact] + public void GetFileType_ShouldReturnNull_ForEmptyPath() + { + // Arrange + const string filePath = ""; + + // Act + var fileType = filePath.GetFileType(); + + // Assert + fileType.Should().BeNull(); + } + + [Fact] + public void GetFileType_ShouldReturnNull_ForNullPath() + { + // Arrange + const string filePath = null; + + // Act + var fileType = filePath.GetFileType(); + + // Assert + fileType.Should().BeNull(); + } + } +} \ No newline at end of file diff --git a/source/Core.Tests/Helpers/ConnectionStringsTests.cs b/source/Core.Tests/Helpers/ConnectionStringsTests.cs new file mode 100644 index 0000000..b9e01d4 --- /dev/null +++ b/source/Core.Tests/Helpers/ConnectionStringsTests.cs @@ -0,0 +1,20 @@ +using Core.Helpers; +using FluentAssertions; +using Xunit; + +namespace Core.Tests.Helpers; + +public class ConnectionStringsTests +{ + [Fact] + public void GpConnectAnalytics_ShouldNotBeEmpty() + { + // Arrange + // Act + var result = ConnectionStrings.GpConnectAnalytics; + + // Assert + result.Should().NotBeEmpty(); + result.Should().Be("GpConnectAnalytics"); + } +} \ No newline at end of file diff --git a/source/Core.Tests/Helpers/DateFormatConstantsTests.cs b/source/Core.Tests/Helpers/DateFormatConstantsTests.cs new file mode 100644 index 0000000..8ed0af8 --- /dev/null +++ b/source/Core.Tests/Helpers/DateFormatConstantsTests.cs @@ -0,0 +1,19 @@ +using Core.Helpers; +using FluentAssertions; +using Xunit; + +namespace Core.Tests.Helpers; + +public class DateFormatConstantsTests +{ + [Fact] + public void ValidateDateFormatConstants() + { + DateFormatConstants.FilePathQueryDate.Should().Be("yyyyMMdd"); + DateFormatConstants.FilePathQueryHour.Should().Be("hhmmss"); + DateFormatConstants.FilePathQueryDateYearMonth.Should().Be("yyyy-MM"); + DateFormatConstants.FilePathNowDate.Should().Be("yyyyMMddTHHmmss"); + DateFormatConstants.SplunkQueryDate.Should().Be("MM/dd/yyyy:HH:mm:ss"); + DateFormatConstants.SplunkQueryHour.Should().Be("hhmm"); + } +} \ No newline at end of file diff --git a/source/Core.Tests/Helpers/DateTimeHelperTests.cs b/source/Core.Tests/Helpers/DateTimeHelperTests.cs new file mode 100644 index 0000000..d8bc089 --- /dev/null +++ b/source/Core.Tests/Helpers/DateTimeHelperTests.cs @@ -0,0 +1,59 @@ +using Core.Helpers; +using FluentAssertions; +using Xunit; + +namespace Core.Tests.Helpers +{ + public class DateTimeHelperTests + { + [Fact] + public void EachDay_ShouldReturnAllDaysBetweenTwoDates_Inclusive() + { + // Arrange + var fromDate = new DateTime(2025, 1, 1); + var toDate = new DateTime(2025, 1, 5); + + // Act + var result = DateTimeHelper.EachDay(fromDate, toDate).ToList(); + + // Assert + result.Should().HaveCount(5); + result.Should().ContainInOrder( + new DateTime(2025, 1, 1), + new DateTime(2025, 1, 2), + new DateTime(2025, 1, 3), + new DateTime(2025, 1, 4), + new DateTime(2025, 1, 5) + ); + } + + [Fact] + public void EachDay_ShouldReturnSingleDay_WhenFromAndToDatesAreSame() + { + // Arrange + var fromDate = new DateTime(2025, 1, 1); + var toDate = new DateTime(2025, 1, 1); + + // Act + var result = DateTimeHelper.EachDay(fromDate, toDate).ToList(); + + // Assert + result.Should().HaveCount(1); + result.First().Should().Be(fromDate); + } + + [Fact] + public void EachDay_ShouldReturnEmpty_WhenFromDateIsAfterToDate() + { + // Arrange + var fromDate = new DateTime(2025, 1, 5); + var toDate = new DateTime(2025, 1, 1); + + // Act + var result = DateTimeHelper.EachDay(fromDate, toDate).ToList(); + + // Assert + result.Should().BeEmpty(); + } + } +} \ No newline at end of file diff --git a/source/Core.Tests/Helpers/FilePathTests.cs b/source/Core.Tests/Helpers/FilePathTests.cs new file mode 100644 index 0000000..d64db8c --- /dev/null +++ b/source/Core.Tests/Helpers/FilePathTests.cs @@ -0,0 +1,47 @@ +using Core.Helpers; +using FluentAssertions; +using Xunit; + +namespace Core.Tests.Helpers; + +public class FilePathTests +{ + [Fact] + public void FilePathValue_Returns_Value_WhenEmptyIsProvidedToConstructor() + { + // Arrange + var filePathAttribute = new FilePathAttribute("test_file_path"); + + // Act + var filePath = filePathAttribute.FilePath; + + // Assert + filePath.Should().Be("test_file_path"); + } + + [Fact] + public void FilePathValue_Returns_Empty_WhenEmptyIsProvidedToConstructor() + { + // Arrange + var filePathAttribute = new FilePathAttribute(""); + + // Act + var filePath = filePathAttribute.FilePath; + + // Assert + filePath.Should().Be(""); + } + + [Fact] + public void FilePathValue_Returns_Null_WhenNullIsProvidedToConstructor() + { + // Arrange + var filePathAttribute = new FilePathAttribute(null!); + + // Act + var filePath = filePathAttribute.FilePath; + + // Assert + filePath.Should().Be(null); + } +} \ No newline at end of file diff --git a/source/Core.Tests/Services/DataServiceTests.cs b/source/Core.Tests/Services/DataServiceTests.cs new file mode 100644 index 0000000..5d8fc49 --- /dev/null +++ b/source/Core.Tests/Services/DataServiceTests.cs @@ -0,0 +1,209 @@ +using System.Data; +using System.Data.Common; +using Core.Repositories; +using Core.Services.Interfaces; +using Dapper; +using FluentAssertions; +using Functions.Services; +using Microsoft.Data.SqlClient; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Testing; +using Moq; +using Xunit; + +namespace Core.Tests.Services +{ + public class DataServiceTests + { + private readonly Mock _mockConfigService; + private readonly Mock _mockDapper; + private readonly DataService _dataService; + private readonly string _testConnectionString = "Server=localhost;Database=TestDb;User Id=test;Password=test;"; + private readonly Mock _mockConnectionFactory; + private readonly FakeLogger _fakeLogger; + private readonly Mock _mockConnection; + + public DataServiceTests() + { + _fakeLogger = new FakeLogger(); + _mockConfigService = new Mock(); + _mockDapper = new Mock(); + _mockConnectionFactory = new Mock(); + + _mockDapper.Setup(d => d.ExecuteAsync( + It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(1); + + _mockConfigService.Setup(c => c.GetConnectionString(It.IsAny())) + .Returns(_testConnectionString); + + _mockConnection = new Mock(); + _mockConnectionFactory.Setup(cf => cf.CreateConnection(_testConnectionString)) + .Returns(_mockConnection.Object); + + _dataService = new DataService(_fakeLogger, _mockConfigService.Object, _mockDapper.Object, + _mockConnectionFactory.Object); + } + + [Fact] + public async Task ExecuteRawUpsertSqlAsync_ShouldReturnRowsAffected() + { + // Arrange + const string sqlCommand = "INSERT INTO TestTable (Id, Name) VALUES (@Id, @Name);"; + var parameters = new { Id = 1, Name = "Test" }; + + _mockDapper.Setup(d => d.ExecuteAsync( + It.IsAny(), sqlCommand, parameters, It.IsAny())) + .ReturnsAsync(1); + + // Act + var result = await _dataService.ExecuteRawUpsertSqlAsync(sqlCommand, parameters); + + // Assert + result.Should().Be(1); + } + + [Fact] + public async Task ExecuteRawUpsertSqlAsync_ShouldLogAndThrowOnError() + { + // Arrange + const string sqlCommand = "INVALID SQL COMMAND"; + var parameters = new { Id = 1, Name = "Test" }; + + _mockDapper.Setup(d => d.ExecuteAsync( + It.IsAny(), sqlCommand, parameters, It.IsAny())) + .ThrowsAsync(new Exception("Simulated SQL error")); + + // Act + var act = async () => await _dataService.ExecuteRawUpsertSqlAsync(sqlCommand, parameters); + + // Assert + await act.Should().ThrowAsync(); + var r = _fakeLogger.LatestRecord; + Assert.Equal(LogLevel.Error, r.Level); + Assert.Contains($"An error has occurred while executing the raw SQL command: {sqlCommand}", r.Message); + } + + [Fact] + public async Task ExecuteStoreProcedure_ShouldReturn_Integer() + { + // Arrange + const string procedureName = "TestProcedure"; + var parameters = new DynamicParameters(); + var expectedResult = 1; + + _mockDapper.Setup(d => d.ExecuteAsync( + It.IsAny(), procedureName, parameters, null)) + .ReturnsAsync(expectedResult); + + // Act + var result = await _dataService.ExecuteStoredProcedure(procedureName, parameters); + + // Assert + result.Should().Be(expectedResult); + } + + [Fact] + public async Task ExecuteStoreProcedure_Should_LogErrorAndThrow() + { + // Arrange + const string procedureName = "TestProcedure"; + var parameters = new DynamicParameters(); + var expectedResult = 1; + + _mockDapper.Setup(d => d.ExecuteAsync( + It.IsAny(), procedureName, parameters, null)) + .ThrowsAsync(new Exception("Database went wrong")); + + // Act + await _dataService.Invoking(x => x.ExecuteStoredProcedure(procedureName, parameters)) + .Should().ThrowAsync(); + + var log = _fakeLogger.LatestRecord; + log.Message.Should().Be($"An error has occurred while attempting to execute the function {procedureName}"); + } + + [Fact] + public async Task ExecuteQueryStoredProcedure_ShouldReturnResults() + { + // Arrange + const string procedureName = "TestProcedure"; + var parameters = new DynamicParameters(); + var expectedResult = new List { "Result1", "Result2" }; + + _mockDapper.Setup(d => d.QueryStoredProcedureAsync( + It.IsAny(), procedureName, parameters, 0)) + .ReturnsAsync(expectedResult); + + // Act + var result = await _dataService.ExecuteQueryStoredProcedure(procedureName, parameters); + + // Assert + result.Should().BeEquivalentTo(expectedResult); + } + + [Fact] + public async Task ExecuteQueryStoredProcedure_ShouldLogAndThrowOnError() + { + // Arrange + const string procedureName = "TestProcedure"; + var parameters = new DynamicParameters(); + + _mockDapper.Setup(d => d.QueryStoredProcedureAsync( + It.IsAny(), procedureName, parameters, 0)) + .ThrowsAsync(new Exception("Simulated SQL error")); + + // Act + var act = async () => await _dataService.ExecuteQueryStoredProcedure(procedureName, parameters); + + // Assert + await act.Should().ThrowAsync(); + var r = _fakeLogger.LatestRecord; + Assert.Equal(LogLevel.Error, r.Level); + Assert.Contains($"An error has occurred while attempting to execute the function {procedureName}", + r.Message); + } + + [Fact] + public async Task ExecuteStoredProcedureWithOutputParameters_ShouldReturnParameters() + { + // Arrange + const string procedureName = "TestProcedure"; + var parameters = new DynamicParameters(); + parameters.Add("OutputParam", dbType: DbType.String, direction: ParameterDirection.Output); + + _mockDapper.Setup(d => d.ExecuteAsync( + It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(1); + + // Act + var result = await _dataService.ExecuteStoredProcedureWithOutputParameters(procedureName, parameters); + + // Assert + result.Should().BeSameAs(parameters); + } + + [Fact] + public async Task ExecuteStoredProcedureWithOutputParameters_ShouldLogAndThrowOnError() + { + // Arrange + const string procedureName = "TestProcedure"; + var parameters = new DynamicParameters(); + + _mockDapper.Setup(d => d.ExecuteStoredProcedureAsync( + It.IsAny(), procedureName, parameters, 0)) + .ThrowsAsync(new Exception("Simulated SQL error")); + + // Act + var act = async () => + await _dataService.ExecuteStoredProcedureWithOutputParameters(procedureName, parameters); + + // Assert + await act.Should().ThrowAsync(); + var r = _fakeLogger.LatestRecord; + Assert.Equal(LogLevel.Error, r.Level); + Assert.Contains($"An error has occurred while attempting to execute the function {procedureName}", + r.Message); + } + } +} \ No newline at end of file diff --git a/source/Core/.gitignore b/source/Core/.gitignore new file mode 100644 index 0000000..b5b508a --- /dev/null +++ b/source/Core/.gitignore @@ -0,0 +1,265 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# Azure Functions localsettings file +local.settings.json + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +project.fragment.lock.json +artifacts/ + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +#*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignoreable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc \ No newline at end of file diff --git a/source/Core/Core.csproj b/source/Core/Core.csproj new file mode 100644 index 0000000..57aafe7 --- /dev/null +++ b/source/Core/Core.csproj @@ -0,0 +1,23 @@ + + + + net8.0 + enable + enable + Core + Core + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/Core/DTOs/AppConfiguration.cs b/source/Core/DTOs/AppConfiguration.cs new file mode 100644 index 0000000..4aee1f4 --- /dev/null +++ b/source/Core/DTOs/AppConfiguration.cs @@ -0,0 +1,7 @@ +namespace Core.DTOs +{ + public class AppConfiguration + { + public string GpConnectAnalyticsConnectionString { get; set; } + } +} \ No newline at end of file diff --git a/source/gpconnect-analytics.DTO/Request/AsidLookup.cs b/source/Core/DTOs/Request/AsidLookup.cs similarity index 87% rename from source/gpconnect-analytics.DTO/Request/AsidLookup.cs rename to source/Core/DTOs/Request/AsidLookup.cs index dd8deaf..5b65270 100644 --- a/source/gpconnect-analytics.DTO/Request/AsidLookup.cs +++ b/source/Core/DTOs/Request/AsidLookup.cs @@ -1,4 +1,4 @@ -namespace gpconnect_analytics.DTO.Request +namespace Core.DTOs.Request { public class AsidLookup { @@ -10,4 +10,4 @@ public class AsidLookup public string PName { get; set; } public string PostCode { get; set; } } -} +} \ No newline at end of file diff --git a/source/Core/DTOs/Request/AsidLookupRun.cs b/source/Core/DTOs/Request/AsidLookupRun.cs new file mode 100644 index 0000000..79c43fd --- /dev/null +++ b/source/Core/DTOs/Request/AsidLookupRun.cs @@ -0,0 +1,6 @@ +namespace Core.DTOs.Request +{ + public class AsidLookupRun : BaseRun + { + } +} \ No newline at end of file diff --git a/source/gpconnect-analytics.DTO/Request/BaseRun.cs b/source/Core/DTOs/Request/BaseRun.cs similarity index 86% rename from source/gpconnect-analytics.DTO/Request/BaseRun.cs rename to source/Core/DTOs/Request/BaseRun.cs index 359d1f2..12cb663 100644 --- a/source/gpconnect-analytics.DTO/Request/BaseRun.cs +++ b/source/Core/DTOs/Request/BaseRun.cs @@ -1,6 +1,4 @@ -using System; - -namespace gpconnect_analytics.DTO.Request +namespace Core.DTOs.Request { public class BaseRun { @@ -12,4 +10,4 @@ public class BaseRun public int FileRowCount { get; set; } public string ErrorMessage { get; set; } } -} +} \ No newline at end of file diff --git a/source/gpconnect-analytics.DTO/Request/File.cs b/source/Core/DTOs/Request/File.cs similarity index 72% rename from source/gpconnect-analytics.DTO/Request/File.cs rename to source/Core/DTOs/Request/File.cs index 59a8821..36f19ab 100644 --- a/source/gpconnect-analytics.DTO/Request/File.cs +++ b/source/Core/DTOs/Request/File.cs @@ -1,8 +1,8 @@ -namespace gpconnect_analytics.DTO.Request +namespace Core.DTOs.Request { public class File { public int FileTypeId { get; set; } public string FilePath { get; set; } } -} +} \ No newline at end of file diff --git a/source/Core/DTOs/Request/OrganisationHeirarchyProvider.cs b/source/Core/DTOs/Request/OrganisationHeirarchyProvider.cs new file mode 100644 index 0000000..5841837 --- /dev/null +++ b/source/Core/DTOs/Request/OrganisationHeirarchyProvider.cs @@ -0,0 +1,15 @@ +#nullable enable +namespace Core.DTOs.Request +{ + public class OrganisationHierarchyProvider + { + public required string OdsCode { get; set; } + public string? PracticeName { get; set; } + public int RegisteredPatientCount { get; set; } + public string? RegionCode { get; set; } + public string? RegionName { get; set; } + public string? Icb22Name { get; set; } + public string? PcnName { get; set; } + public int Appointments13000 { get; set; } + } +} \ No newline at end of file diff --git a/source/gpconnect-analytics.DTO/Request/RequestUri.cs b/source/Core/DTOs/Request/RequestUri.cs similarity index 78% rename from source/gpconnect-analytics.DTO/Request/RequestUri.cs rename to source/Core/DTOs/Request/RequestUri.cs index e4798d6..6b52c97 100644 --- a/source/gpconnect-analytics.DTO/Request/RequestUri.cs +++ b/source/Core/DTOs/Request/RequestUri.cs @@ -1,6 +1,4 @@ -using System; - -namespace gpconnect_analytics.DTO.Request +namespace Core.DTOs.Request { public class UriRequest { @@ -9,4 +7,4 @@ public class UriRequest public DateTime LatestDate { get; set; } public TimeSpan Hour { get; set; } } -} +} \ No newline at end of file diff --git a/source/gpconnect-analytics.DTO/Request/SspTransaction.cs b/source/Core/DTOs/Request/SspTransaction.cs similarity index 91% rename from source/gpconnect-analytics.DTO/Request/SspTransaction.cs rename to source/Core/DTOs/Request/SspTransaction.cs index 3e16793..955d7a0 100644 --- a/source/gpconnect-analytics.DTO/Request/SspTransaction.cs +++ b/source/Core/DTOs/Request/SspTransaction.cs @@ -1,4 +1,4 @@ -namespace gpconnect_analytics.DTO.Request +namespace Core.DTOs.Request { public class SspTransaction { @@ -13,4 +13,4 @@ public class SspTransaction public string responseErrorMessage { get; set; } public string method { get; set; } } -} +} \ No newline at end of file diff --git a/source/gpconnect-analytics.DTO/Request/SspTransactionRun.cs b/source/Core/DTOs/Request/SspTransactionRun.cs similarity index 72% rename from source/gpconnect-analytics.DTO/Request/SspTransactionRun.cs rename to source/Core/DTOs/Request/SspTransactionRun.cs index 05183d2..bb64c47 100644 --- a/source/gpconnect-analytics.DTO/Request/SspTransactionRun.cs +++ b/source/Core/DTOs/Request/SspTransactionRun.cs @@ -1,10 +1,8 @@ -using System; - -namespace gpconnect_analytics.DTO.Request +namespace Core.DTOs.Request { public class SspTransactionRun : BaseRun { public DateTime QueryFromDate { get; set; } public DateTime QueryToDate { get; set; } } -} +} \ No newline at end of file diff --git a/source/gpconnect-analytics.DTO/Response/Configuration/BlobStorage.cs b/source/Core/DTOs/Response/Configuration/BlobStorage.cs similarity index 83% rename from source/gpconnect-analytics.DTO/Response/Configuration/BlobStorage.cs rename to source/Core/DTOs/Response/Configuration/BlobStorage.cs index 75736d1..ce4588d 100644 --- a/source/gpconnect-analytics.DTO/Response/Configuration/BlobStorage.cs +++ b/source/Core/DTOs/Response/Configuration/BlobStorage.cs @@ -1,4 +1,4 @@ -namespace gpconnect_analytics.DTO.Response.Configuration +namespace Core.DTOs.Response.Configuration { public class BlobStorage { @@ -8,4 +8,4 @@ public class BlobStorage public string QueueName { get; set; } public string SqlExternalDataSourceName { get; set; } } -} +} \ No newline at end of file diff --git a/source/gpconnect-analytics.DTO/Response/Configuration/Email.cs b/source/Core/DTOs/Response/Configuration/Email.cs similarity index 88% rename from source/gpconnect-analytics.DTO/Response/Configuration/Email.cs rename to source/Core/DTOs/Response/Configuration/Email.cs index c00a4e4..bc79e50 100644 --- a/source/gpconnect-analytics.DTO/Response/Configuration/Email.cs +++ b/source/Core/DTOs/Response/Configuration/Email.cs @@ -1,4 +1,4 @@ -namespace gpconnect_analytics.DTO.Response.Configuration +namespace Core.DTOs.Response.Configuration { public class Email { @@ -12,4 +12,4 @@ public class Email public string DefaultSubject { get; set; } public string RecipientAddress { get; set; } } -} +} \ No newline at end of file diff --git a/source/gpconnect-analytics.DTO/Response/Configuration/FilePathConstants.cs b/source/Core/DTOs/Response/Configuration/FilePathConstants.cs similarity index 83% rename from source/gpconnect-analytics.DTO/Response/Configuration/FilePathConstants.cs rename to source/Core/DTOs/Response/Configuration/FilePathConstants.cs index 921e4f2..3dcaa54 100644 --- a/source/gpconnect-analytics.DTO/Response/Configuration/FilePathConstants.cs +++ b/source/Core/DTOs/Response/Configuration/FilePathConstants.cs @@ -1,4 +1,4 @@ -namespace gpconnect_analytics.DTO.Response.Configuration +namespace Core.DTOs.Response.Configuration { public class FilePathConstants { @@ -8,4 +8,4 @@ public class FilePathConstants public string FileExtension { get; set; } public string EmptyDateCharacter { get; set; } } -} +} \ No newline at end of file diff --git a/source/gpconnect-analytics.DTO/Response/Configuration/FileType.cs b/source/Core/DTOs/Response/Configuration/FileType.cs similarity index 84% rename from source/gpconnect-analytics.DTO/Response/Configuration/FileType.cs rename to source/Core/DTOs/Response/Configuration/FileType.cs index c201267..68a3144 100644 --- a/source/gpconnect-analytics.DTO/Response/Configuration/FileType.cs +++ b/source/Core/DTOs/Response/Configuration/FileType.cs @@ -1,6 +1,4 @@ -using System; - -namespace gpconnect_analytics.DTO.Response.Configuration +namespace Core.DTOs.Response.Configuration { public class FileType { @@ -13,4 +11,4 @@ public class FileType public int QueryPeriodHours { get; set; } public bool Enabled { get; set; } } -} +} \ No newline at end of file diff --git a/source/gpconnect-analytics.DTO/Response/Configuration/SplunkClient.cs b/source/Core/DTOs/Response/Configuration/SplunkClient.cs similarity index 85% rename from source/gpconnect-analytics.DTO/Response/Configuration/SplunkClient.cs rename to source/Core/DTOs/Response/Configuration/SplunkClient.cs index a378baf..684150b 100644 --- a/source/gpconnect-analytics.DTO/Response/Configuration/SplunkClient.cs +++ b/source/Core/DTOs/Response/Configuration/SplunkClient.cs @@ -1,4 +1,4 @@ -namespace gpconnect_analytics.DTO.Response.Configuration +namespace Core.DTOs.Response.Configuration { public class SplunkClient { @@ -10,4 +10,4 @@ public class SplunkClient public int QueryTimeout { get; set; } public string ApiToken { get; set; } } -} +} \ No newline at end of file diff --git a/source/gpconnect-analytics.DTO/Response/Configuration/SplunkInstance.cs b/source/Core/DTOs/Response/Configuration/SplunkInstance.cs similarity index 68% rename from source/gpconnect-analytics.DTO/Response/Configuration/SplunkInstance.cs rename to source/Core/DTOs/Response/Configuration/SplunkInstance.cs index f8ecc16..9560903 100644 --- a/source/gpconnect-analytics.DTO/Response/Configuration/SplunkInstance.cs +++ b/source/Core/DTOs/Response/Configuration/SplunkInstance.cs @@ -1,8 +1,8 @@ -namespace gpconnect_analytics.DTO.Response.Configuration +namespace Core.DTOs.Response.Configuration { public class SplunkInstance { public string Source { get; set; } public string SourceGroup { get; set; } } -} +} \ No newline at end of file diff --git a/source/gpconnect-analytics.DTO/Response/Queue/Message.cs b/source/Core/DTOs/Response/Queue/Message.cs similarity index 76% rename from source/gpconnect-analytics.DTO/Response/Queue/Message.cs rename to source/Core/DTOs/Response/Queue/Message.cs index 0f5e84f..a2e554d 100644 --- a/source/gpconnect-analytics.DTO/Response/Queue/Message.cs +++ b/source/Core/DTOs/Response/Queue/Message.cs @@ -1,4 +1,4 @@ -namespace gpconnect_analytics.DTO.Response.Queue +namespace Core.DTOs.Response.Queue { public class Message { @@ -6,4 +6,4 @@ public class Message public string BlobName { get; set; } public bool Override { get; set; } = false; } -} +} \ No newline at end of file diff --git a/source/gpconnect-analytics.DTO/Response/Splunk/Extract.cs b/source/Core/DTOs/Response/Splunk/Extract.cs similarity index 80% rename from source/gpconnect-analytics.DTO/Response/Splunk/Extract.cs rename to source/Core/DTOs/Response/Splunk/Extract.cs index 1935562..1e74fb1 100644 --- a/source/gpconnect-analytics.DTO/Response/Splunk/Extract.cs +++ b/source/Core/DTOs/Response/Splunk/Extract.cs @@ -1,6 +1,4 @@ -using System; - -namespace gpconnect_analytics.DTO.Response.Splunk +namespace Core.DTOs.Response.Splunk { public class Extract { @@ -10,4 +8,4 @@ public class Extract public TimeSpan QueryHour { get; set; } public bool Override { get; set; } = false; } -} +} \ No newline at end of file diff --git a/source/gpconnect-analytics.DTO/Response/Splunk/ExtractResponse.cs b/source/Core/DTOs/Response/Splunk/ExtractResponse.cs similarity index 71% rename from source/gpconnect-analytics.DTO/Response/Splunk/ExtractResponse.cs rename to source/Core/DTOs/Response/Splunk/ExtractResponse.cs index 49e5e39..46b9343 100644 --- a/source/gpconnect-analytics.DTO/Response/Splunk/ExtractResponse.cs +++ b/source/Core/DTOs/Response/Splunk/ExtractResponse.cs @@ -1,8 +1,6 @@ -using gpconnect_analytics.DTO.Request; -using System.IO; -using System.Net.Http; +using Core.DTOs.Request; -namespace gpconnect_analytics.DTO.Response.Splunk +namespace Core.DTOs.Response.Splunk { public class ExtractResponse { @@ -12,4 +10,4 @@ public class ExtractResponse public string FilePath { get; set; } public UriRequest UriRequest { get; set; } } -} +} \ No newline at end of file diff --git a/source/Core/Helpers/ApplicationHelper.cs b/source/Core/Helpers/ApplicationHelper.cs new file mode 100644 index 0000000..283f1d4 --- /dev/null +++ b/source/Core/Helpers/ApplicationHelper.cs @@ -0,0 +1,23 @@ +using System.Reflection; + +namespace Core.Helpers +{ + public class ApplicationHelper + { + public static class ApplicationVersion + { + public static string GetAssemblyVersion() + { + return GetAssemblyVersionInternal(Assembly.GetCallingAssembly); + } + + // Internal method to allow dependency injection for testing + public static string GetAssemblyVersionInternal(Func getAssembly) + { + var buildTag = System.Environment.GetEnvironmentVariable("BUILD_TAG"); + + return string.IsNullOrWhiteSpace(buildTag) ? getAssembly()?.GetName().FullName : buildTag; + } + } + } +} \ No newline at end of file diff --git a/source/Core/Helpers/AttributeExtensions.cs b/source/Core/Helpers/AttributeExtensions.cs new file mode 100644 index 0000000..d8b2572 --- /dev/null +++ b/source/Core/Helpers/AttributeExtensions.cs @@ -0,0 +1,27 @@ +using System.Reflection; + +namespace Core.Helpers +{ + public static class AttributeExtensions + { + public static FileTypes? GetFileType(this string filePath) + { + return GetValueFromPath(filePath); + } + + private static FileTypes? GetValueFromPath(string filePath) + { + if (string.IsNullOrEmpty(filePath)) + { + return null; + } + + var fileType = typeof(T).GetFields() + .FirstOrDefault(field => + field.GetCustomAttribute() is { } attribute && + filePath.Contains(attribute.FilePath)); + + return fileType?.GetValue(null) as FileTypes?; + } + } +} \ No newline at end of file diff --git a/source/gpconnect-analytics.DAL/ConnectionStrings.cs b/source/Core/Helpers/ConnectionStrings.cs similarity index 65% rename from source/gpconnect-analytics.DAL/ConnectionStrings.cs rename to source/Core/Helpers/ConnectionStrings.cs index dcc1cc6..fa09863 100644 --- a/source/gpconnect-analytics.DAL/ConnectionStrings.cs +++ b/source/Core/Helpers/ConnectionStrings.cs @@ -1,7 +1,7 @@ -namespace gpconnect_analytics.DAL +namespace Core.Helpers { public static class ConnectionStrings { - public static string GpConnectAnalytics { get; } = "GpConnectAnalytics"; + public static string GpConnectAnalytics { get; } = "GpConnectAnalytics"; } -} +} \ No newline at end of file diff --git a/source/gpconnect-analytics.Helpers/DateFormatConstants.cs b/source/Core/Helpers/DateFormatConstants.cs similarity index 82% rename from source/gpconnect-analytics.Helpers/DateFormatConstants.cs rename to source/Core/Helpers/DateFormatConstants.cs index b30d318..a6f6dc9 100644 --- a/source/gpconnect-analytics.Helpers/DateFormatConstants.cs +++ b/source/Core/Helpers/DateFormatConstants.cs @@ -1,6 +1,6 @@ -namespace gpconnect_analytics.Helpers +namespace Core.Helpers { - public class DateFormatConstants + public static class DateFormatConstants { public const string FilePathQueryDate = "yyyyMMdd"; public const string FilePathQueryHour = "hhmmss"; @@ -9,4 +9,4 @@ public class DateFormatConstants public const string SplunkQueryDate = "MM/dd/yyyy:HH:mm:ss"; public const string SplunkQueryHour = "hhmm"; } -} +} \ No newline at end of file diff --git a/source/gpconnect-analytics.Helpers/DateTimeHelper.cs b/source/Core/Helpers/DateTimeHelper.cs similarity index 74% rename from source/gpconnect-analytics.Helpers/DateTimeHelper.cs rename to source/Core/Helpers/DateTimeHelper.cs index c4db187..92d7241 100644 --- a/source/gpconnect-analytics.Helpers/DateTimeHelper.cs +++ b/source/Core/Helpers/DateTimeHelper.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; - -namespace gpconnect_analytics.Helpers +namespace Core.Helpers { public static class DateTimeHelper { diff --git a/source/gpconnect-analytics.Helpers/FilePath.cs b/source/Core/Helpers/FilePath.cs similarity index 57% rename from source/gpconnect-analytics.Helpers/FilePath.cs rename to source/Core/Helpers/FilePath.cs index cc28f59..85b4e83 100644 --- a/source/gpconnect-analytics.Helpers/FilePath.cs +++ b/source/Core/Helpers/FilePath.cs @@ -1,14 +1,12 @@ -using System; - -namespace gpconnect_analytics.Helpers +namespace Core.Helpers { public class FilePathAttribute : Attribute { - public string FilePath { get; protected set; } = ""; + public string FilePath { get; } = ""; public FilePathAttribute(string value) { FilePath = value; } } -} +} \ No newline at end of file diff --git a/source/Core/Helpers/FileTypes.cs b/source/Core/Helpers/FileTypes.cs new file mode 100644 index 0000000..cf68883 --- /dev/null +++ b/source/Core/Helpers/FileTypes.cs @@ -0,0 +1,9 @@ +namespace Core.Helpers +{ + public enum FileTypes + { + [FilePath("asid-lookup-data")] asidlookup, + [FilePath("ssp-transactions")] ssptrans, + [FilePath("mesh-transactions")] meshtrans + } +} \ No newline at end of file diff --git a/source/gpconnect-analytics.Helpers/SplunkInstance.cs b/source/Core/Helpers/SplunkInstance.cs similarity index 68% rename from source/gpconnect-analytics.Helpers/SplunkInstance.cs rename to source/Core/Helpers/SplunkInstance.cs index fd57a09..83f7227 100644 --- a/source/gpconnect-analytics.Helpers/SplunkInstance.cs +++ b/source/Core/Helpers/SplunkInstance.cs @@ -1,4 +1,4 @@ -namespace gpconnect_analytics.Helpers +namespace Core.Helpers { public enum SplunkInstances { @@ -6,4 +6,4 @@ public enum SplunkInstances spinea, spineb } -} +} \ No newline at end of file diff --git a/source/Core/Helpers/TimeProvider.cs b/source/Core/Helpers/TimeProvider.cs new file mode 100644 index 0000000..65defc9 --- /dev/null +++ b/source/Core/Helpers/TimeProvider.cs @@ -0,0 +1,9 @@ +using Core; + +public class TimeProvider : ITimeProvider +{ + public DateTime UtcDateTime() => DateTime.UtcNow; + + + public DateTime CurrentDate() => DateTime.Today; +} \ No newline at end of file diff --git a/source/Core/IConnectionFactory.cs b/source/Core/IConnectionFactory.cs new file mode 100644 index 0000000..46b2cf2 --- /dev/null +++ b/source/Core/IConnectionFactory.cs @@ -0,0 +1,8 @@ +using System.Data.Common; + +namespace Core; + +public interface IConnectionFactory +{ + DbConnection CreateConnection(string connectionString); +} \ No newline at end of file diff --git a/source/Core/ITimeProvider.cs b/source/Core/ITimeProvider.cs new file mode 100644 index 0000000..669d433 --- /dev/null +++ b/source/Core/ITimeProvider.cs @@ -0,0 +1,16 @@ +namespace Core; + +public interface ITimeProvider +{ + /// + /// Returns the Current Date and Time as UTC + /// + /// + DateTime UtcDateTime(); + + /// + /// Gets current Date, time is set at 00:00 + /// + /// current DateTime + DateTime CurrentDate(); +} \ No newline at end of file diff --git a/source/gpconnect-analytics.DAL/Mapping/SplunkInstanceMap.cs b/source/Core/Mapping/SplunkInstanceMap.cs similarity index 74% rename from source/gpconnect-analytics.DAL/Mapping/SplunkInstanceMap.cs rename to source/Core/Mapping/SplunkInstanceMap.cs index fe18d81..9ab7dfd 100644 --- a/source/gpconnect-analytics.DAL/Mapping/SplunkInstanceMap.cs +++ b/source/Core/Mapping/SplunkInstanceMap.cs @@ -1,7 +1,7 @@ -using gpconnect_analytics.DTO.Response.Configuration; +using Core.DTOs.Response.Configuration; using Dapper.FluentMap.Mapping; -namespace gpconnect_analytics.DAL.Mapping +namespace Core.Mapping { public class SplunkInstanceMap : EntityMap { @@ -11,4 +11,4 @@ public SplunkInstanceMap() Map(p => p.SourceGroup).ToColumn("SplunkInstanceGroup"); } } -} +} \ No newline at end of file diff --git a/source/Core/Repositories/DapperWrapper.cs b/source/Core/Repositories/DapperWrapper.cs new file mode 100644 index 0000000..3e31970 --- /dev/null +++ b/source/Core/Repositories/DapperWrapper.cs @@ -0,0 +1,68 @@ +using System.Data; +using Dapper; + +namespace Core.Repositories; + +public interface IDapperWrapper +{ + Task ExecuteAsync(IDbConnection connection, string sql, object param = null, + IDbTransaction? transaction = null); + + Task> QueryAsync(IDbConnection connection, string sql, object param = null, + IDbTransaction transaction = null); + + Task ExecuteStoredProcedureAsync(IDbConnection connection, string procedureName, + object parameters, int commandTimeout = 30); + + Task> QueryStoredProcedureAsync(IDbConnection connection, string procedureName, + object parameters, int commandTimeout = 30); +} + +public class DapperWrapper : IDapperWrapper +{ + public async Task ExecuteAsync(IDbConnection connection, string sql, object param = null, + IDbTransaction transaction = null) + { + return await connection.ExecuteAsync(sql, param, transaction); + } + + public async Task ExecuteStoredProcedureAsync(IDbConnection connection, string procedureName, + object parameters, int commandTimeout = 30) + { + try + { + return await connection.ExecuteAsync( + procedureName, + parameters, + commandType: CommandType.StoredProcedure, + commandTimeout: commandTimeout); + } + catch (Exception ex) + { + throw new Exception($"Error executing stored procedure: {procedureName}", ex); + } + } + + public async Task> QueryStoredProcedureAsync(IDbConnection connection, string procedureName, + object parameters, int commandTimeout = 30) + { + try + { + return await connection.QueryAsync( + procedureName, + parameters, + commandType: CommandType.StoredProcedure, + commandTimeout: commandTimeout); + } + catch (Exception ex) + { + throw new Exception($"Error executing stored procedure: {procedureName}", ex); + } + } + + public async Task> QueryAsync(IDbConnection connection, string sql, object param = null, + IDbTransaction transaction = null) + { + return await connection.QueryAsync(sql, param, transaction); + } +} \ No newline at end of file diff --git a/source/Core/Repositories/HierarchyProviderConsumerRepo.cs b/source/Core/Repositories/HierarchyProviderConsumerRepo.cs new file mode 100644 index 0000000..31dcd5e --- /dev/null +++ b/source/Core/Repositories/HierarchyProviderConsumerRepo.cs @@ -0,0 +1,66 @@ +using System.Data; +using Core.DTOs.Request; +using Core.Helpers; +using Core.Services.Interfaces; +using Microsoft.Data.SqlClient; +using Microsoft.Extensions.Logging; + +namespace Core.Repositories; + +public class HierarchyProviderConsumerRepo( + ICoreConfigurationService configurationService, + IDapperWrapper dapperWrapper, + IConnectionFactory connectionFactory, + ILogger logger) + : IHierarchyProviderConsumerRepo +{ + public async Task InsertHierarchyProviderConsumers(List providers) + { + var connectionString = configurationService.GetConnectionString(ConnectionStrings.GpConnectAnalytics); + await using var connection = connectionFactory.CreateConnection(connectionString); + + // Explicitly open the connection + if (connection.State != ConnectionState.Open) + { + await connection.OpenAsync(); + } + + await using var transaction = await connection.BeginTransactionAsync(); + + const string sql = """ + INSERT INTO [Data].[HierarchyProviderConsumers] ( + OdsCode, + PracticeName, + RegisteredPatientCount, + RegionCode, + RegionName, + Icb22Name, + PcnName, + Appointments13000 + ) + VALUES ( + @OdsCode, + @PracticeName, + @RegisteredPatientCount, + @RegionCode, + @RegionName, + @Icb22Name, + @PcnName, + @Appointments13000 + ); + """; + + try + { + await dapperWrapper.ExecuteAsync(connection, sql, providers, transaction); + await transaction.CommitAsync(); + return providers.Count; + } + catch (Exception ex) + { + await transaction.RollbackAsync(); + logger.LogError(ex, "Error inserting hierarchy provider consumers"); + return 0; + } + } +} \ No newline at end of file diff --git a/source/Core/Repositories/IHierarchyProviderConsumerRepo.cs b/source/Core/Repositories/IHierarchyProviderConsumerRepo.cs new file mode 100644 index 0000000..5086756 --- /dev/null +++ b/source/Core/Repositories/IHierarchyProviderConsumerRepo.cs @@ -0,0 +1,8 @@ +using Core.DTOs.Request; + +namespace Core.Repositories; + +public interface IHierarchyProviderConsumerRepo +{ + Task InsertHierarchyProviderConsumers(List providers); +} \ No newline at end of file diff --git a/source/gpconnect-analytics.DAL/Interfaces/IConfigurationService.cs b/source/Core/Services/Interfaces/IConfigurationService.cs similarity index 66% rename from source/gpconnect-analytics.DAL/Interfaces/IConfigurationService.cs rename to source/Core/Services/Interfaces/IConfigurationService.cs index 7208521..9468dc4 100644 --- a/source/gpconnect-analytics.DAL/Interfaces/IConfigurationService.cs +++ b/source/Core/Services/Interfaces/IConfigurationService.cs @@ -1,9 +1,7 @@ -using gpconnect_analytics.DTO.Response.Configuration; -using gpconnect_analytics.Helpers; -using System.Collections.Generic; -using System.Threading.Tasks; +using Core.DTOs.Response.Configuration; +using Core.Helpers; -namespace gpconnect_analytics.DAL.Interfaces +namespace Core.Services.Interfaces { public interface IConfigurationService { @@ -14,4 +12,4 @@ public interface IConfigurationService Task GetSplunkClientConfiguration(); Task GetSplunkInstance(SplunkInstances splunkInstance); } -} +} \ No newline at end of file diff --git a/source/Core/Services/Interfaces/ICoreConfiguration.cs b/source/Core/Services/Interfaces/ICoreConfiguration.cs new file mode 100644 index 0000000..52be50f --- /dev/null +++ b/source/Core/Services/Interfaces/ICoreConfiguration.cs @@ -0,0 +1,6 @@ +namespace Core.Services.Interfaces; + +public interface ICoreConfigurationService +{ + string GetConnectionString(string name); +} \ No newline at end of file diff --git a/source/Core/Services/Interfaces/IDataService.cs b/source/Core/Services/Interfaces/IDataService.cs new file mode 100644 index 0000000..4e13a13 --- /dev/null +++ b/source/Core/Services/Interfaces/IDataService.cs @@ -0,0 +1,15 @@ +using Dapper; + +namespace Core.Services.Interfaces +{ + public interface IDataService + { + Task> ExecuteQueryStoredProcedure(string procedureName, DynamicParameters parameters = null) + where T : class; + + Task ExecuteStoredProcedureWithOutputParameters(string procedureName, + DynamicParameters parameters); + + Task ExecuteStoredProcedure(string procedureName, DynamicParameters parameters = null); + } +} \ No newline at end of file diff --git a/source/Functions.Tests/FilePathHelperTests.cs b/source/Functions.Tests/FilePathHelperTests.cs new file mode 100644 index 0000000..d875c78 --- /dev/null +++ b/source/Functions.Tests/FilePathHelperTests.cs @@ -0,0 +1,121 @@ +using Moq; +using System; +using System.Threading.Tasks; +using Xunit; +using Core; +using Core.DTOs.Response.Configuration; +using Core.DTOs.Response.Splunk; +using Core.Helpers; +using Core.Services.Interfaces; +using System.Text; +using FluentAssertions; +using Functions.HelperClasses; +using Functions.Tests.TestHelpers; + +namespace Functions.Tests +{ + public class FilePathHelperTests + { + private readonly Mock _mockConfigurationService; + private readonly Mock _mockTimeProvider; + private readonly Extract _mockExtract; + private readonly FilePathHelper _filePathHelper; + + public FilePathHelperTests() + { + _mockConfigurationService = new Mock(); + _mockTimeProvider = new Mock(); + + _mockTimeProvider.Setup(x => x.CurrentDate()).Returns(new DateTime(2025, 12, 25, 0, 0, 0)); + _mockTimeProvider.Setup(x => x.UtcDateTime()).Returns(new DateTime(2025, 12, 25, 11, 11, 0)); + + _mockExtract = new Extract + { + ExtractRequired = false, + QueryFromDate = new DateTime(2025, 1, 1, 0, 0, 0), + QueryToDate = new DateTime(2025, 1, 2, 0, 0, 0), + QueryHour = TimeSpan.Zero, + Override = false + }; + + _filePathHelper = new FilePathHelper( + _mockConfigurationService.Object, + _mockTimeProvider.Object, + _mockExtract + ); + } + + [Fact] + public async Task ConstructFilePath_WhenIsTodayTrue_MidnightIsFalse_ReturnsExpectedFilePath() + { + // Arrange + var splunkInstance = new SplunkInstance { Source = "source" }; + var fileType = new FileType { DirectoryName = "dir", FileTypeFilePrefix = "filePrefix" }; + + var filePathConstants = ConfigurationHelpers.GenerateFilePathConstants(); + + _mockConfigurationService.Setup(x => x.GetFilePathConstants()) + .ReturnsAsync(filePathConstants); + + // Act + var result = await _filePathHelper.ConstructFilePath(splunkInstance, fileType, true); + + // Assert + var expectedFilePath = + "dir/source/2025-01/proj__filePrefix_20250101T000000_20250102T000000_source_20251225T235959.csv"; + result.Should().Be(expectedFilePath); + } + + [Fact] + public async Task ConstructFilePath_WhenIsTodayFalseAndSetDateAsMidnightTrue_ReturnsExpectedFilePath() + { + // Arrange + var splunkInstance = new SplunkInstance { Source = "source" }; + var fileType = new FileType { DirectoryName = "dir", FileTypeFilePrefix = "filePrefix" }; + + var filePathConstants = ConfigurationHelpers.GenerateFilePathConstants(); + + _mockConfigurationService.Setup(x => x.GetFilePathConstants()) + .ReturnsAsync(filePathConstants); + + + // Act + var result = await _filePathHelper.ConstructFilePath(splunkInstance, fileType, false, true); //midnight true + + // Assert + var expectedFilePath = + "dir/source/2025-01/proj__filePrefix_20250101T000000_20250102T000000_source_20251225T000000.csv"; + result.Should().Be(expectedFilePath); + } + + [Fact] + public async Task ConstructFilePath_WhenIsTodayFalseAndSetDateAsMidnightFalse_ReturnsExpectedFilePath() + { + // Arrange + var splunkInstance = new SplunkInstance { Source = "source" }; + var fileType = new FileType { DirectoryName = "dir", FileTypeFilePrefix = "filePrefix" }; + + // expectations + var directory = "dir"; + var source = "source"; + var dateFolder = "2025-01"; + var filePrefix = "filePrefix"; + var queryDateFrom = "20250101T000000"; + var queryDateTo = "20250102T000000"; + var date = "20251225T111100"; + + var filePathConstants = ConfigurationHelpers.GenerateFilePathConstants(); + + _mockConfigurationService.Setup(x => x.GetFilePathConstants()) + .ReturnsAsync(filePathConstants); + + // Act + var result = await _filePathHelper.ConstructFilePath(splunkInstance, fileType, false); + + // Assert + var expectedFilePath = + $"{directory}/{source}/{dateFolder}/{filePathConstants.ProjectNameFilePrefix}_{filePrefix}_{queryDateFrom}_{queryDateTo}_{source}_{date}{filePathConstants.FileExtension}"; + result.Should().Be(expectedFilePath); + } + } +} \ No newline at end of file diff --git a/source/Functions.Tests/Functions.Tests.csproj b/source/Functions.Tests/Functions.Tests.csproj new file mode 100644 index 0000000..64345f1 --- /dev/null +++ b/source/Functions.Tests/Functions.Tests.csproj @@ -0,0 +1,31 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + + + + + + + + + + + + + + + + diff --git a/source/Functions.Tests/Functions.Tests.csproj.DotSettings b/source/Functions.Tests/Functions.Tests.csproj.DotSettings new file mode 100644 index 0000000..f4b6a50 --- /dev/null +++ b/source/Functions.Tests/Functions.Tests.csproj.DotSettings @@ -0,0 +1,2 @@ + + True \ No newline at end of file diff --git a/source/Functions.Tests/Functions/ExecuteImportByTriggerTests.cs b/source/Functions.Tests/Functions/ExecuteImportByTriggerTests.cs new file mode 100644 index 0000000..ca625c1 --- /dev/null +++ b/source/Functions.Tests/Functions/ExecuteImportByTriggerTests.cs @@ -0,0 +1,57 @@ +using Core.DTOs.Response.Queue; +using FluentAssertions; +using Functions.Services.Interfaces; +using Microsoft.Extensions.Logging; +using Moq; + +namespace Functions.Tests; + +public class ExecuteImportByTriggerTests +{ + private readonly Mock _importServiceMock; + private readonly Mock _loggerMock; + private readonly ExecuteImportByTrigger _function; + + public ExecuteImportByTriggerTests() + { + _importServiceMock = new Mock(); + _loggerMock = new Mock(); + _function = new ExecuteImportByTrigger(_importServiceMock.Object); + } + + [Fact] + public async Task Run_Should_Call_InstallData_With_Correct_QueueItem() + { + // Arrange + var queueItem = new Message + { + Override = true, + BlobName = "fakeBlob", + FileTypeId = 123 + }; + + // Act + await _function.Run(queueItem, _loggerMock.Object); + + // Assert + _importServiceMock.Verify(s => s.InstallData(queueItem), Times.Once); + } + + [Fact] + public async Task Run_Should_Not_Throw_Exception() + { + // Arrange + var queueItem = new Message + { + Override = true, + BlobName = "fakeBlob", + FileTypeId = 123 + }; + + // Act + var act = async () => await _function.Run(queueItem, _loggerMock.Object); + + // Assert + await act.Should().NotThrowAsync(); + } +} \ No newline at end of file diff --git a/source/Functions.Tests/Functions/GetDataFromApiByDateRangeTests.cs b/source/Functions.Tests/Functions/GetDataFromApiByDateRangeTests.cs new file mode 100644 index 0000000..255dbc2 --- /dev/null +++ b/source/Functions.Tests/Functions/GetDataFromApiByDateRangeTests.cs @@ -0,0 +1,164 @@ +using System.Net; +using Core.Helpers; +using FluentAssertions; +using Functions.Services.Interfaces; +using Functions.Tests.TestHelpers; +using Microsoft.Extensions.Logging; +using Moq; + +namespace Functions.Tests; + +public class GetDataFromApiByDateRangeTests +{ + private readonly Mock _batchServiceMock; + private readonly Mock _loggerMock; + private readonly GetDataFromApiByDateRange _function; + + public GetDataFromApiByDateRangeTests() + { + _batchServiceMock = new Mock(); + _loggerMock = new Mock(); + _function = new GetDataFromApiByDateRange(_batchServiceMock.Object, _loggerMock.Object); + } + + + [Fact] + public async Task GetDataFromSspTransByDateRange_Should_Return_Successful_Response() + { + // Arrange + var request = MockRequests.CreateDateRangeMockRequest("2024-01-01", "2024-01-31"); + + _batchServiceMock + .Setup(s => s.StartBatchDownloadAsync(FileTypes.ssptrans, It.IsAny(), It.IsAny())) + .ReturnsAsync(10); // Simulate 10 rows processed + + + // Act + var result = await _function.GetDataFromSspTransByDateRange(request); + + // Assert + result.Body.Position = 0; // reset the position to the beginning of the stream + result.StatusCode.Should().Be(HttpStatusCode.OK); + + using var reader = new StreamReader(result.Body); + var responseBody = await reader.ReadToEndAsync(); + responseBody.Should().Contain("Batch Download successful: 10 requests processed"); + } + + [Fact] + public async Task GetDataFromSSpTransByDateRange_Should_LogError_AndReturn_InternalServerError_OnError() + { + // Arrange + var request = MockRequests.CreateDateRangeMockRequest("2024-01-01", "2024-01-31"); + + _batchServiceMock + .Setup(s => s.StartBatchDownloadAsync(FileTypes.ssptrans, It.IsAny(), It.IsAny())) + .ThrowsAsync(new Exception("Error processing batch")); // Simulate an error + + + // Act + var result = await _function.GetDataFromSspTransByDateRange(request); + + // Assert + result.Body.Position = 0; // reset the position to the beginning of the stream + result.StatusCode.Should().Be(HttpStatusCode.InternalServerError); + + using var reader = new StreamReader(result.Body); + var responseBody = await reader.ReadToEndAsync(); + responseBody.Should().Contain("Failed to download - see logs"); + } + + [Fact] + public async Task GetDataFromApiDateRange_MeshTrans_Should_Return_Successful_Response() + + { + // Arrange + var request = MockRequests.CreateDateRangeMockRequest("2024-01-01", "2024-01-31"); + + _batchServiceMock + .Setup(s => s.StartBatchDownloadAsync(FileTypes.meshtrans, It.IsAny(), It.IsAny())) + .ReturnsAsync(10); // Simulate 10 rows processed + + + // Act + var result = await _function.GetDataFromMeshTransByDateRange(request); + + // Assert + result.Body.Position = 0; // reset the position to the beginning of the stream + result.StatusCode.Should().Be(HttpStatusCode.OK); + + using var reader = new StreamReader(result.Body); + var responseBody = await reader.ReadToEndAsync(); + responseBody.Should().Contain("Batch Download successful: 10 requests processed"); + } + + [Fact] + public async Task GetDataFromMeshTransByDateRange_Should_LogError_AndReturn_InternalServerError_OnError() + { + // Arrange + var request = MockRequests.CreateDateRangeMockRequest("2024-01-01", "2024-01-31"); + + _batchServiceMock + .Setup(s => s.StartBatchDownloadAsync(FileTypes.meshtrans, It.IsAny(), It.IsAny())) + .ThrowsAsync(new Exception("Error processing batch")); // Simulate an error + + + // Act + var result = await _function.GetDataFromMeshTransByDateRange(request); + + // Assert + result.Body.Position = 0; // reset the position to the beginning of the stream + result.StatusCode.Should().Be(HttpStatusCode.InternalServerError); + + using var reader = new StreamReader(result.Body); + var responseBody = await reader.ReadToEndAsync(); + responseBody.Should().Contain("Failed to download - see logs"); + } + + [Fact] + public async Task GetDataFromApiByDateRange_AsidLookup_Should_Return_Successful_Response() + + { + // Arrange + var request = MockRequests.CreateDateRangeMockRequest("2024-01-01", "2024-01-31"); + + _batchServiceMock + .Setup(s => s.StartBatchDownloadAsync(FileTypes.asidlookup, It.IsAny(), It.IsAny())) + .ReturnsAsync(10); // Simulate 10 rows processed + + + // Act + var result = await _function.GetDataFromAsidLookupByDateRange(request); + + // Assert + result.Body.Position = 0; // reset the position to the beginning of the stream + result.StatusCode.Should().Be(HttpStatusCode.OK); + + using var reader = new StreamReader(result.Body); + var responseBody = await reader.ReadToEndAsync(); + responseBody.Should().Contain("Batch Download successful: 10 requests processed"); + } + + [Fact] + public async Task GetDataFromAsidLookupByDateRange_Should_LogError_AndReturn_InternalServerError_OnError() + { + // Arrange + var request = MockRequests.CreateDateRangeMockRequest("2024-01-01", "2024-01-31"); + + _batchServiceMock + .Setup(s => s.StartBatchDownloadAsync(FileTypes.asidlookup, It.IsAny(), It.IsAny())) + .ThrowsAsync(new Exception("Error processing batch")); // Simulate an error + + + // Act + var result = await _function.GetDataFromAsidLookupByDateRange(request); + + // Assert + result.Body.Position = 0; // reset the position to the beginning of the stream + result.StatusCode.Should().Be(HttpStatusCode.InternalServerError); + + using var reader = new StreamReader(result.Body); + var responseBody = await reader.ReadToEndAsync(); + responseBody.Should().Contain("Failed to download - see logs"); + } +} \ No newline at end of file diff --git a/source/Functions.Tests/Functions/GetDataFromApiManualTests.cs b/source/Functions.Tests/Functions/GetDataFromApiManualTests.cs new file mode 100644 index 0000000..6b65e49 --- /dev/null +++ b/source/Functions.Tests/Functions/GetDataFromApiManualTests.cs @@ -0,0 +1,104 @@ +using System.Net; +using FluentAssertions; +using Functions.Services.Interfaces; +using Functions.Tests.TestHelpers; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Testing; +using Moq; + +namespace Functions.Tests; + +public class GetDataFromApiManualTests +{ + private readonly Mock _importService; + private readonly FakeLogger _loggerMock; + private readonly GetDataFromApiManual _function; + + + public GetDataFromApiManualTests() + { + _importService = new Mock(); + _loggerMock = new FakeLogger(); + _function = new GetDataFromApiManual(_importService.Object, _loggerMock); + } + + [Fact] + public async Task GetDataFromApi_ShouldReturnSuccessfulResponse() + { + // Arrange + var request = MockRequests.MockAddDownloadRequest(); + _importService.Setup(x => x.AddDownloadedFileManually(It.IsAny())) + .Returns(Task.CompletedTask); + + + // Act + var response = await _function.AddDownloadedFile(request); + + response.StatusCode.Should().Be(HttpStatusCode.OK); + response.Body.Position = 0; // reset the position to the beginning of the stream + + using var reader = new StreamReader(response.Body); + var responseBody = await reader.ReadToEndAsync(); + responseBody.Should().Contain("Successfully added files"); + + // Assert + } + + [Fact] + public async Task GetDataFromApi_ReturnBadRequest_WhenMissingFilePathQueryParam() + { + // Arrange + var request = MockRequests.MockRequestNoQuery(); + + // Act + var response = await _function.AddDownloadedFile(request); + + response.StatusCode.Should().Be(HttpStatusCode.BadRequest); + response.Body.Position = 0; // reset the position to the beginning of the stream + + // Assert + using var reader = new StreamReader(response.Body); + var responseBody = await reader.ReadToEndAsync(); + responseBody.Should().Contain("Filepath missing"); + } + + [Fact] + public async Task GetDataFromApi_ReturnInternalServerError_WhenExceptionThrown() + { + // Arrange + var request = MockRequests.MockAddDownloadRequest(); + _importService.Setup(x => x.AddDownloadedFileManually(It.IsAny())) + .Throws(new Exception("An error occurred")); + + // Act + var response = await _function.AddDownloadedFile(request); + + response.StatusCode.Should().Be(HttpStatusCode.InternalServerError); + response.Body.Position = 0; // reset the position to the beginning of the stream + + // Assert + using var reader = new StreamReader(response.Body); + var responseBody = await reader.ReadToEndAsync(); + responseBody.Should().Contain("Something went wrong - see error logs for more details"); + } + + [Fact] + public async Task GetDataFromApi_LogsError_WhenExceptionThrown() + { + // Arrange + var request = MockRequests.MockAddDownloadRequest(); + _importService.Setup(x => x.AddDownloadedFileManually(It.IsAny())) + .Throws(new Exception("An error occurred")); + + // Act + var response = await _function.AddDownloadedFile(request); + + response.StatusCode.Should().Be(HttpStatusCode.InternalServerError); + response.Body.Position = 0; // reset the position to the beginning of the stream + + // Assert + _loggerMock.Collector.LatestRecord.Message.Should().Be("Error adding downloaded file: An error occurred"); + _loggerMock.Collector.LatestRecord.Exception.Should().BeOfType(); + _loggerMock.Collector.LatestRecord.Level.Should().Be(LogLevel.Error); + } +} \ No newline at end of file diff --git a/source/Functions.Tests/Functions/GetDataFromApiTodayTests.cs b/source/Functions.Tests/Functions/GetDataFromApiTodayTests.cs new file mode 100644 index 0000000..9a5e6da --- /dev/null +++ b/source/Functions.Tests/Functions/GetDataFromApiTodayTests.cs @@ -0,0 +1,234 @@ +using System.Net; +using Core.Helpers; +using FluentAssertions; +using Functions.Services.Interfaces; +using Functions.Tests.TestHelpers; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Testing; +using Moq; + +namespace Functions.Tests; + +public class GetDataFromApiTodayTests +{ + private readonly GetDataFromApiToday _function; + private readonly FakeLogger _loggerMock; + private readonly Mock _batchService; + + public GetDataFromApiTodayTests() + { + _batchService = new Mock(); + _loggerMock = new FakeLogger(); + _function = new GetDataFromApiToday(_batchService.Object, _loggerMock); + } + + [Fact] + public async Task SspTrans_ShouldReturnSuccessful() + { + // Arrange + var request = MockRequests.CreateTodayMockRequest(); + + _batchService + .Setup(s => s.StartBatchDownloadForTodayAsync(FileTypes.ssptrans)) + .ReturnsAsync(2); + + + // Act + var result = await _function.GetDataFromSspTransByDateRange(request); + + // Assert + result.Body.Position = 0; // reset the position to the beginning of the stream + result.StatusCode.Should().Be(HttpStatusCode.OK); + + using var reader = new StreamReader(result.Body); + var responseBody = await reader.ReadToEndAsync(); + responseBody.Should().Contain("Processed 2 requests"); + } + + [Fact] + public async Task SspTrans_ShouldReturn500_WhenErrorThrown() + { + // Arrange + var request = MockRequests.CreateTodayMockRequest(); + + _batchService + .Setup(s => s.StartBatchDownloadForTodayAsync(FileTypes.ssptrans)) + .ThrowsAsync(new Exception("Error while downloading")); + + + // Act + var result = await _function.GetDataFromSspTransByDateRange(request); + + // Assert + result.Body.Position = 0; // reset the position to the beginning of the stream + result.StatusCode.Should().Be(HttpStatusCode.InternalServerError); + + using var reader = new StreamReader(result.Body); + var responseBody = await reader.ReadToEndAsync(); + responseBody.Should().Be("An error occurred whilst processing batch download - see logs for more details"); + } + + [Fact] + public async Task SspTrans_ShouldLogError_WhenErrorThrown() + { + // Arrange + var request = MockRequests.CreateTodayMockRequest(); + + _batchService + .Setup(s => s.StartBatchDownloadForTodayAsync(FileTypes.ssptrans)) + .ThrowsAsync(new Exception("Error while downloading")); + + + // Act + var result = await _function.GetDataFromSspTransByDateRange(request); + + // Assert + _loggerMock.Collector.LatestRecord.Message.Should() + .Be("An error occurred during batch download when processing urls"); + + _loggerMock.Collector.LatestRecord.Exception.Should().BeOfType(); + _loggerMock.Collector.LatestRecord.Level.Should().Be(LogLevel.Error); + _loggerMock.Collector.LatestRecord.Exception?.Message.Should() + .Be("Error while downloading"); + } + + [Fact] + public async Task AsidLookup_ShouldReturnSuccessful() + { + // Arrange + var request = MockRequests.CreateTodayMockRequest(); + + _batchService + .Setup(s => s.StartBatchDownloadForTodayAsync(FileTypes.asidlookup)) + .ReturnsAsync(2); + + + // Act + var result = await _function.GetDataFromAsidLookupByDateRange(request); + + // Assert + result.Body.Position = 0; // reset the position to the beginning of the stream + result.StatusCode.Should().Be(HttpStatusCode.OK); + + using var reader = new StreamReader(result.Body); + var responseBody = await reader.ReadToEndAsync(); + responseBody.Should().Contain("Processed 2 requests"); + } + + [Fact] + public async Task AsidLookup_ShouldReturn500_WhenErrorThrown() + { + // Arrange + var request = MockRequests.CreateTodayMockRequest(); + + _batchService + .Setup(s => s.StartBatchDownloadForTodayAsync(FileTypes.asidlookup)) + .ThrowsAsync(new Exception("Error while downloading")); + + + // Act + var result = await _function.GetDataFromAsidLookupByDateRange(request); + + // Assert + result.Body.Position = 0; // reset the position to the beginning of the stream + result.StatusCode.Should().Be(HttpStatusCode.InternalServerError); + + using var reader = new StreamReader(result.Body); + var responseBody = await reader.ReadToEndAsync(); + responseBody.Should().Be("An error occurred whilst processing batch download - see logs for more details"); + } + + [Fact] + public async Task AsidLookup_ShouldLogError_WhenErrorThrown() + { + // Arrange + var request = MockRequests.CreateTodayMockRequest(); + + _batchService + .Setup(s => s.StartBatchDownloadForTodayAsync(FileTypes.asidlookup)) + .ThrowsAsync(new Exception("Error while downloading")); + + + // Act + var result = await _function.GetDataFromAsidLookupByDateRange(request); + + // Assert + _loggerMock.Collector.LatestRecord.Message.Should() + .Be("An error occurred during batch download when processing urls"); + + _loggerMock.Collector.LatestRecord.Exception.Should().BeOfType(); + _loggerMock.Collector.LatestRecord.Level.Should().Be(LogLevel.Error); + _loggerMock.Collector.LatestRecord.Exception?.Message.Should() + .Be("Error while downloading"); + } + + [Fact] + public async Task MeshTrans_ShouldReturnSuccessful() + { + // Arrange + var request = MockRequests.CreateTodayMockRequest(); + + _batchService + .Setup(s => s.StartBatchDownloadForTodayAsync(FileTypes.meshtrans)) + .ReturnsAsync(2); + + + // Act + var result = await _function.GetDataFromMeshTransByDateRange(request); + + // Assert + result.Body.Position = 0; // reset the position to the beginning of the stream + result.StatusCode.Should().Be(HttpStatusCode.OK); + + using var reader = new StreamReader(result.Body); + var responseBody = await reader.ReadToEndAsync(); + responseBody.Should().Contain("Processed 2 requests"); + } + + [Fact] + public async Task MeshTrans_ShouldReturn500_WhenErrorThrown() + { + // Arrange + var request = MockRequests.CreateTodayMockRequest(); + + _batchService + .Setup(s => s.StartBatchDownloadForTodayAsync(FileTypes.meshtrans)) + .ThrowsAsync(new Exception("Error while downloading")); + + + // Act + var result = await _function.GetDataFromMeshTransByDateRange(request); + + // Assert + result.Body.Position = 0; // reset the position to the beginning of the stream + result.StatusCode.Should().Be(HttpStatusCode.InternalServerError); + + using var reader = new StreamReader(result.Body); + var responseBody = await reader.ReadToEndAsync(); + responseBody.Should().Be("An error occurred whilst processing batch download - see logs for more details"); + } + + [Fact] + public async Task MeshTrans_ShouldLogError_WhenErrorThrown() + { + // Arrange + var request = MockRequests.CreateTodayMockRequest(); + + _batchService + .Setup(s => s.StartBatchDownloadForTodayAsync(FileTypes.meshtrans)) + .ThrowsAsync(new Exception("Error while downloading")); + + + // Act + var result = await _function.GetDataFromMeshTransByDateRange(request); + + // Assert + _loggerMock.Collector.LatestRecord.Message.Should() + .Be("An error occurred during batch download when processing urls"); + + _loggerMock.Collector.LatestRecord.Exception.Should().BeOfType(); + _loggerMock.Collector.LatestRecord.Level.Should().Be(LogLevel.Error); + _loggerMock.Collector.LatestRecord.Exception?.Message.Should() + .Be("Error while downloading"); + } +} \ No newline at end of file diff --git a/source/Functions.Tests/Functions/GetDataFromApiTodayTimerTests.cs b/source/Functions.Tests/Functions/GetDataFromApiTodayTimerTests.cs new file mode 100644 index 0000000..7910af2 --- /dev/null +++ b/source/Functions.Tests/Functions/GetDataFromApiTodayTimerTests.cs @@ -0,0 +1,67 @@ +using Core.Helpers; +using Functions.Services.Interfaces; +using Functions.Tests.TestHelpers; +using Microsoft.Extensions.Logging; +using Moq; + +namespace Functions.Tests; + +public class GetDataFromApiByTriggerTests +{ + private readonly Mock _batchServiceMock; + private readonly Mock _loggerMock; + private readonly GetDataFromApiByTrigger _function; + + public GetDataFromApiByTriggerTests() + { + _batchServiceMock = new Mock(); + _loggerMock = new Mock(); + _function = new GetDataFromApiByTrigger(_batchServiceMock.Object, _loggerMock.Object); + } + + + [Fact] + public async Task GetDataFromAsidLookup_Should_Invoke_BatchService() + { + // Arrange + var timerInfo = MockTriggers.CreateMockTimerInfo(); + + // Act + await _function.GetDataFromAsidLookup(timerInfo); + + // Assert + _batchServiceMock.Verify( + x => x.StartBatchDownloadForTodayAsync(FileTypes.asidlookup), + Times.Once); + } + + [Fact] + public async Task GetDataFromSspTrans_Should_Invoke_BatchService() + { + // Arrange + var timerInfo = MockTriggers.CreateMockTimerInfo(); + + // Act + await _function.GetDataFromSspTrans(timerInfo); + + // Assert + _batchServiceMock.Verify( + x => x.StartBatchDownloadForTodayAsync(FileTypes.ssptrans), + Times.Once); + } + + [Fact] + public async Task GetDataFromMeshTrans_Should_Invoke_BatchService() + { + // Arrange + var timerInfo = MockTriggers.CreateMockTimerInfo(); + + // Act + await _function.GetDataFromMeshTrans(timerInfo); + + // Assert + _batchServiceMock.Verify( + x => x.StartBatchDownloadForTodayAsync(FileTypes.meshtrans), + Times.Once); + } +} \ No newline at end of file diff --git a/source/Functions.Tests/Functions/PurgeErrorLogByTriggerTests.cs b/source/Functions.Tests/Functions/PurgeErrorLogByTriggerTests.cs new file mode 100644 index 0000000..e0f09a7 --- /dev/null +++ b/source/Functions.Tests/Functions/PurgeErrorLogByTriggerTests.cs @@ -0,0 +1,33 @@ +using Functions.Services.Interfaces; +using Functions.Tests.TestHelpers; +using Microsoft.Azure.Functions.Worker; +using Moq; + +namespace Functions.Tests; + +public class PurgeErrorLogByTriggerTests +{ + private readonly TimerInfo _timerInfo; + private readonly Mock _loggingServiceMock; + private PurgeErrorLogByTrigger _function; + + public PurgeErrorLogByTriggerTests() + { + _loggingServiceMock = new Mock(); + _timerInfo = MockTriggers.CreateMockTimerInfo(); + + + _function = new PurgeErrorLogByTrigger(_loggingServiceMock.Object); + } + + [Fact] + public async Task PurgeErrorLogByTrigger_Should_Invoke_LoggingServiceCorrectly() + { + // Arrange + // Act + await _function.PurgeErrorLog(_timerInfo); + + // Assert + _loggingServiceMock.Verify(x => x.PurgeErrorLog(), Times.Once); + } +} \ No newline at end of file diff --git a/source/Functions.Tests/Functions/StoreProviderConsumerDataTests.cs b/source/Functions.Tests/Functions/StoreProviderConsumerDataTests.cs new file mode 100644 index 0000000..7b80462 --- /dev/null +++ b/source/Functions.Tests/Functions/StoreProviderConsumerDataTests.cs @@ -0,0 +1,146 @@ +using System.Net; +using System.Text; +using System.Text.Json; +using Core.DTOs.Request; +using Core.Repositories; +using FluentAssertions; +using Functions.Tests.TestHelpers; +using Microsoft.Azure.Functions.Worker; +using Microsoft.Azure.Functions.Worker.Http; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Testing; +using Moq; + +namespace Functions.Tests; + +public class StoreProviderConsumerDataTests +{ + private readonly Mock _repositoryMock; + private readonly FakeLogger _loggerMock; + private readonly StoreProviderConsumerData _function; + + public StoreProviderConsumerDataTests() + { + _repositoryMock = new Mock(); + _loggerMock = new FakeLogger(); + _function = new StoreProviderConsumerData(_repositoryMock.Object, _loggerMock); + } + + + [Fact] + public async Task Run_ShouldReturnBadRequest_WhenRequestBodyIsEmpty() + { + // Arrange + var request = MockRequests.MockRequestNoQuery(); + + // Act + var response = await _function.Run(request); + + // Assert + response.StatusCode.Should().Be(HttpStatusCode.BadRequest); + } + + [Fact] + public async Task Run_ShouldReturnBadRequest_WhenInvalidJsonIsProvided() + { + // Arrange + var request = MockRequests.MockRequestNoQuery(); + + // Act + var response = await _function.Run(request); + + // Assert + response.StatusCode.Should().Be(HttpStatusCode.BadRequest); + } + + [Fact] + public async Task Run_ShouldReturnOk_WhenValidInputIsProvided() + { + // Arrange + var records = new List + { + new() + { + OdsCode = null, + PracticeName = null, + RegisteredPatientCount = 0, + RegionCode = null, + RegionName = null, + Icb22Name = null, + PcnName = null, + Appointments13000 = 0 + } + }; + var json = JsonSerializer.Serialize(records); + var request = MockRequests.MockRequestWithBody(json); + + _repositoryMock.Setup(r => r.InsertHierarchyProviderConsumers(It.IsAny>())) + .ReturnsAsync(1); + + // Act + var response = await _function.Run(request); + + // Assert + response.StatusCode.Should().Be(HttpStatusCode.OK); + } + + [Fact] + public async Task Run_ShouldReturnBadRequest_WhenRepositoryFails() + { + // Arrange + var records = new List + { + new() + { + OdsCode = null, + PracticeName = null, + RegisteredPatientCount = 0, + RegionCode = null, + RegionName = null, + Icb22Name = null, + PcnName = null, + Appointments13000 = 0 + } + }; + var json = JsonSerializer.Serialize(records); + var request = MockRequests.MockRequestWithBody(json); + + _repositoryMock.Setup(r => r.InsertHierarchyProviderConsumers(It.IsAny>())) + .ReturnsAsync(0); + + // Act + var response = await _function.Run(request); + + // Assert + response.StatusCode.Should().Be(HttpStatusCode.BadRequest); + response.Headers.GetValues("Content-Type").Should().Contain("text/plain; charset=utf-8"); + _loggerMock.Collector.LatestRecord.Message.Should().Be("No items of 1 were saved to the database"); + + response.Body.Position = 0; + using var reader = new StreamReader(response.Body); + var responseBody = await reader.ReadToEndAsync(); + responseBody.Should().Be("Failed to save to the database - see logs for more information"); + } + + [Fact] + public async Task Test_InvalidJson_ReturnsBadRequest_WithCorrectMessage() + { + // Arrange: + var invalidJsonBody = "{ message: 'Invalid JSON' "; // Invalid JSON (missing closing brace) + + var mockHttpRequest = MockRequests.MockRequestWithBody(invalidJsonBody); + + // Act + var result = await _function.Run(mockHttpRequest); + + // Assert + result.StatusCode.Should().Be(HttpStatusCode.BadRequest); + + result.Body.Position = 0; + using var reader = new StreamReader(result.Body); + var responseBody = await reader.ReadToEndAsync(); + responseBody.Should().Contain("Invalid json input"); + + _loggerMock.Collector.LatestRecord.Message.Should().Contain("Failed to deserialize request body:"); + } +} \ No newline at end of file diff --git a/source/Functions.Tests/HttpClientExtensionsTests.cs b/source/Functions.Tests/HttpClientExtensionsTests.cs new file mode 100644 index 0000000..5a10350 --- /dev/null +++ b/source/Functions.Tests/HttpClientExtensionsTests.cs @@ -0,0 +1,39 @@ +using System.Security.Authentication; +using FluentAssertions; +using Functions.Configuration.Infrastructure.HttpClient; + +namespace Functions.Tests; + +public class HttpClientExtensionsTests +{ + [Fact] + public void ConfigureHttpClient_ShouldSetTimeoutAndAcceptHeader() + { + // Arrange + var options = new HttpClient(); + + // Act + HttpClientExtensions.ConfigureHttpClient(options); + + // Assert + options.Timeout.Should().Be(new TimeSpan(0, 0, 1, 0)); + options.DefaultRequestHeaders.Accept.Should().ContainSingle(h => h.MediaType == "text/csv"); + options.DefaultRequestHeaders.CacheControl?.NoCache.Should().BeTrue(); + } + + [Fact] + public void CreateHttpMessageHandler_ShouldReturnHandlerWithCorrectSslProtocols() + { + // Act + var handler = HttpClientExtensions.CreateHttpMessageHandler(); + + // Assert + handler.Should().BeOfType(); // Verify type + var httpClientHandler = (HttpClientHandler)handler; + + httpClientHandler.SslProtocols.Should().Be( + SslProtocols.Tls13 | SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls, + because: "the handler should support TLS 1.0, 1.1, 1.2, and 1.3" + ); + } +} \ No newline at end of file diff --git a/source/Functions.Tests/LoggingServiceTests.cs b/source/Functions.Tests/LoggingServiceTests.cs new file mode 100644 index 0000000..37dca06 --- /dev/null +++ b/source/Functions.Tests/LoggingServiceTests.cs @@ -0,0 +1,33 @@ +using Core.Services.Interfaces; +using Dapper; +using Functions.Services; +using Moq; + +namespace Functions.Tests; + +public class LoggingServiceTests +{ + private readonly Mock _mockDataService; + private readonly LoggingService _loggingService; + + public LoggingServiceTests() + { + _mockDataService = new Mock(); + _loggingService = new LoggingService(_mockDataService.Object); + } + + [Fact] + public async Task PurgeErrorLog_ShouldCallDataService() + { + // Arrange + _mockDataService.Setup(m => m.ExecuteStoredProcedure("Logging.PurgeErrorLog", It.IsAny())) + .ReturnsAsync(1); + + // Act + await _loggingService.PurgeErrorLog(); + + // Assert + _mockDataService.Verify(m => m.ExecuteStoredProcedure("Logging.PurgeErrorLog", It.IsAny()), + Times.Once); + } +} \ No newline at end of file diff --git a/source/Functions.Tests/RequestWrappers.cs b/source/Functions.Tests/RequestWrappers.cs new file mode 100644 index 0000000..16d468a --- /dev/null +++ b/source/Functions.Tests/RequestWrappers.cs @@ -0,0 +1,42 @@ +using System.Diagnostics.CodeAnalysis; +using System.Net; +using System.Security.Claims; +using Microsoft.Azure.Functions.Worker; +using Microsoft.Azure.Functions.Worker.Http; + +namespace Functions.Tests; + +[ExcludeFromCodeCoverage] +public class FakeHttpRequestData : HttpRequestData +{ + public FakeHttpRequestData(FunctionContext functionContext, Uri url, Stream body = null) : base(functionContext) + { + Url = url; + Body = body ?? new MemoryStream(); + } + + public override Stream Body { get; } = new MemoryStream(); + public override HttpHeadersCollection Headers { get; } = new HttpHeadersCollection(); + public override IReadOnlyCollection Cookies { get; } + public override Uri Url { get; } + public override IEnumerable Identities { get; } + public override string Method { get; } + + public override HttpResponseData CreateResponse() + { + return new FakeHttpResponseData(FunctionContext); + } +} + +[ExcludeFromCodeCoverage] +public class FakeHttpResponseData : HttpResponseData +{ + public FakeHttpResponseData(FunctionContext functionContext) : base(functionContext) + { + } + + public override HttpStatusCode StatusCode { get; set; } + public override HttpHeadersCollection Headers { get; set; } = new HttpHeadersCollection(); + public override Stream Body { get; set; } = new MemoryStream(); + public override HttpCookies Cookies { get; } +} \ No newline at end of file diff --git a/source/Functions.Tests/Services/BatchServiceTests.cs b/source/Functions.Tests/Services/BatchServiceTests.cs new file mode 100644 index 0000000..4531f45 --- /dev/null +++ b/source/Functions.Tests/Services/BatchServiceTests.cs @@ -0,0 +1,277 @@ +using System.Net; +using Bogus; +using Core.DTOs.Request; +using Core.DTOs.Response.Configuration; +using Core.DTOs.Response.Splunk; +using Core.Helpers; +using Core.Services.Interfaces; +using Dapper; +using FluentAssertions; +using Functions.Services; +using Functions.Services.Interfaces; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Testing; +using Moq; +using Xunit.Abstractions; +using static System.DateTime; + +namespace Functions.Tests.Services; + +public class BatchServiceTests +{ + private readonly ITestOutputHelper _testOutputHelper; + private readonly Mock _mockConfigurationService; + private readonly Mock _mockSplunkService; + private readonly Mock _mockDataService; + private readonly BatchService _batchService; + private readonly FileType _fileType; + private readonly SplunkClient _splunkClient; + private readonly List _uriList; + private readonly ExtractResponse _mockExtractResponse; + + private readonly FakeLogger _fakeLogger; + + public BatchServiceTests(ITestOutputHelper testOutputHelper) + { + _testOutputHelper = testOutputHelper; + _mockConfigurationService = new Mock(); + _mockSplunkService = new Mock(); + _fakeLogger = new FakeLogger(); + _mockDataService = new Mock(); + + _batchService = new BatchService( + _mockConfigurationService.Object, + _mockSplunkService.Object, + _fakeLogger, + _mockDataService.Object + ); + + _fileType = new FileType + { + Enabled = true, + FileTypeId = 1, + FileTypeFilePrefix = "test", + SplunkQuery = "test query {latest}, {earliest}, {hour}" + }; + + _splunkClient = new SplunkClient + { + HostName = "fake.splunk.com", + HostPort = 8089, + BaseUrl = "/services/search/jobs", + QueryParameters = "search={0}" + }; + + _uriList = new List + { + new() { Request = new Uri("https://example.com"), EarliestDate = Now, LatestDate = Now } + }; + + _mockExtractResponse = new ExtractResponse + { + ExtractResponseMessage = new HttpResponseMessage(HttpStatusCode.OK), + ExtractResponseStream = Stream.Null, + ExtractRequestDetails = new Extract(), + FilePath = "test.csv", + UriRequest = new UriRequest() + }; + + // Common Mocks + _mockConfigurationService.Setup(x => x.GetFileType(It.IsAny())) + .ReturnsAsync(_fileType); + + _mockConfigurationService.Setup(x => x.GetSplunkClientConfiguration()) + .ReturnsAsync(_splunkClient); + + _mockSplunkService.Setup(x => x.DownloadCSVDateRangeAsync(It.IsAny(), It.IsAny(), true)) + .Callback(() => _testOutputHelper.WriteLine("DownloadCSVDateRangeAsync called")) + .ReturnsAsync(_mockExtractResponse); + + _mockSplunkService.Setup(x => + x.ExecuteBatchDownloadFromSplunk(It.IsAny(), It.IsAny(), It.IsAny())) + .Returns(Task.CompletedTask); + } + + #region StartBatchForToday + + [Fact] + public async Task StartBatchDownloadForTodayAsync_ShouldProcessUrisAndReturnCount() + { + // Act + var result = await _batchService.StartBatchDownloadForTodayAsync(FileTypes.asidlookup); + + // Assert + result.Should().Be(24); // One for each hour + _mockConfigurationService.Verify(x => x.GetFileType(It.IsAny()), Times.Once); + + _mockSplunkService.Verify( + x => x.ExecuteBatchDownloadFromSplunk(It.IsAny(), It.IsAny(), true), + Times.Exactly(24)); + } + + [Fact] + public async Task StartBatchDownLoadForToday_ShouldCallRemovePreviousDownloads() + { + //Arrange + var expectedProcedureName = "Import.RemovePreviousDownload"; + + // Act + await _batchService.StartBatchDownloadForTodayAsync(FileTypes.asidlookup); + + // Assert + // RemovePreviousDownload executes the remove stored procedure + _mockDataService.Verify(x => x.ExecuteStoredProcedure(expectedProcedureName, It.IsAny()), + Times.Once); + } + + #endregion + + #region StartBatchDownloadForDateRange + + [Fact] + public async Task StartBatchDownloadAsync_ShouldReturnReturnProcessCount() + { + // Arrange + var startDate = "2023-01-01"; + var endDate = "2023-01-03"; + + // Act + var result = await _batchService.StartBatchDownloadAsync(FileTypes.asidlookup, startDate, endDate); + + // Assert + result.Should().Be(72); // 3 days * 24 hours + } + + [Fact] + public async Task StartBatchDownloadAsync_ShouldThrowException_WhenStartDateIsAfterEndDate() + { + // Arrange + var startDate = "2023-01-03"; + var endDate = "2023-01-01"; + + // Act + var action = async () => await _batchService.StartBatchDownloadAsync(FileTypes.asidlookup, startDate, endDate); + + // Assert + await action.Should().ThrowAsync().WithMessage("Start date cannot be later than end date"); + _fakeLogger.Collector.LatestRecord.Should().NotBeNull(); + _fakeLogger.Collector.LatestRecord.Message.Should().Be("Start date cannot be later than end date"); + _fakeLogger.Collector.LatestRecord.Level.Should().Be(LogLevel.Error); + _fakeLogger.Collector.Count.Should().Be(1); + } + + [Fact] + public async Task StartBatchDownLoad_Should_CallRemovePreviousDownloads() + { + //Arrange + var expectedProcedureName = "Import.RemovePreviousDownload"; + var start = DateTime.Now.AddDays(-2).ToString(); + var end = DateTime.Now.AddDays(1).ToString(); + + // Act + await _batchService.StartBatchDownloadAsync(FileTypes.asidlookup, start, end); + + // Assert + _mockDataService.Verify(x => x.ExecuteStoredProcedure(expectedProcedureName, It.IsAny()), + Times.Once); + } + + [Fact] + public async Task GetBatchDownloadAsync_Should_HandleNullOrEmptyDateInputs() + { + // Act + + await _batchService.Invoking(x => x.StartBatchDownloadAsync(FileTypes.asidlookup, null, null)) + .Should() + .ThrowAsync().WithMessage("Start and end dates are required for batch download"); + + _fakeLogger.Collector.LatestRecord.Should().NotBeNull(); + _fakeLogger.Collector.LatestRecord.Message.Should().Be("Start and end dates are required for batch download"); + _fakeLogger.Collector.LatestRecord.Level.Should().Be(LogLevel.Error); + _fakeLogger.Collector.Count.Should().Be(1); + } + + [Fact] + public async Task GetBatchDownloadAsync_Should_HandleGenericExceptions_LoggingError() + { + // Act + var startDate = "2023-01-01"; + var endDate = "2023-01-03"; + + + _mockSplunkService.Setup(x => + x.ExecuteBatchDownloadFromSplunk(It.IsAny(), It.IsAny(), false)) + .Throws(new Exception("Something went wrong")); + + await _batchService.Invoking(x => + x.StartBatchDownloadAsync(FileTypes.asidlookup, startDate, endDate)) + .Should() + .ThrowAsync().WithMessage("Something went wrong"); + + _fakeLogger.Collector.LatestRecord.Should().NotBeNull(); + _fakeLogger.Collector.LatestRecord.Message.Should() + .Be("An error occurred during batch download when processing urls"); + _fakeLogger.Collector.LatestRecord.Level.Should().Be(LogLevel.Error); + } + + #endregion + + + [Fact] + public async Task GetBatchDownloadUriList_ShouldGenerateCorrectUris() + { + // Arrange + + var faker = new Faker(); + var fakeDates = faker.Make(3, () => faker.Date.Past(1)).ToList(); // 3 random past dates + + // Fake FileType with a sample SplunkQuery template + var fakeFileType = new FileType + { + SplunkQuery = "index=main | earliest={earliest} latest={latest} hour={hour}" + }; + + // Act + var result = await _batchService.GetBatchDownloadUriList(fakeFileType, fakeDates); + + // Assert + result.Should().NotBeNull(); + result.Count.Should().Be(fakeDates.Count * 24); // 24 URIs per date + + // Validate a sample URI format + var sampleUriRequest = result.First(); + sampleUriRequest.Request.Should().NotBeNull(); + sampleUriRequest.EarliestDate = fakeDates.First().AddDays(-2); + sampleUriRequest.LatestDate = fakeDates.First().AddDays(-1); + sampleUriRequest.Request.AbsoluteUri.Should().Contain("fake.splunk.com"); + sampleUriRequest.Request.Query.Should().Contain("search="); + } + + [Fact] + public async Task RemovePreviousDownloads_Calls_DataService_ExecuteStoreProcedureCorrectly() + { + // Arrange + var startDate = DateTime.Now.AddDays(-4); + var endDate = DateTime.Now.AddDays(-2); + + var expectedProcedureName = "Import.RemovePreviousDownload"; + var expectedParameters = new DynamicParameters(); + expectedParameters.Add("@StartDate", startDate); + expectedParameters.Add("@EndDate", endDate); + expectedParameters.Add("@FileTypeId", _fileType.FileTypeId); + + + // Act + await _batchService.RemovePreviousDownloads(_fileType, startDate, endDate); + + // Assert + _mockDataService.Verify(x => x.ExecuteStoredProcedure( + expectedProcedureName, + It.Is(p => + p.Get("@StartDate") == startDate.AddDays(-2) && + p.Get("@EndDate") == endDate.AddDays(-1) && + p.Get("@FileTypeId") == _fileType.FileTypeId + )), + Times.Once); + } +} \ No newline at end of file diff --git a/source/Functions.Tests/Services/BlobServiceTests.cs b/source/Functions.Tests/Services/BlobServiceTests.cs new file mode 100644 index 0000000..28b2fdb --- /dev/null +++ b/source/Functions.Tests/Services/BlobServiceTests.cs @@ -0,0 +1,326 @@ +using System.Text; +using Azure; +using Azure.Storage.Blobs; +using Azure.Storage.Blobs.Models; +using Azure.Storage.Queues; +using Bogus; +using Core.DTOs.Response.Configuration; +using Core.DTOs.Response.Splunk; +using Core.Services.Interfaces; +using FluentAssertions; +using Functions.Services; +using Microsoft.Extensions.Logging; +using Moq; + +namespace Functions.Tests.Services +{ + public class BlobServiceTests + { + private readonly Mock _mockConfigService; + private readonly Mock> _mockLogger; + private readonly Mock _mockQueueClient; + private readonly Mock _mockBlobServiceClient; + private readonly Mock _mockContainerClient; + private readonly Mock _mockBlobClient; + private readonly Faker _faker; + + public BlobServiceTests() + { + _faker = new Faker(); + _mockConfigService = new Mock(); + _mockLogger = new Mock>(); + _mockQueueClient = new Mock(); + _mockBlobServiceClient = new Mock(); + _mockContainerClient = new Mock(); + _mockBlobClient = new Mock(); + } + + private BlobService CreateBlobService( + BlobStorage blobStorageConfig = null, + QueueClient queueClient = null) + { + string connectionString = + "DefaultEndpointsProtocol=https;" + + "AccountName=mystorageaccount;" + + "AccountKey=myAccountKey;" + + "EndpointSuffix=core.windows.net"; + + blobStorageConfig ??= new BlobStorage + { + ConnectionString = connectionString, + ContainerName = _faker.Random.Word(), + QueueName = _faker.Random.Word() + }; + + _mockConfigService + .Setup(x => x.GetBlobStorageConfiguration()) + .ReturnsAsync(blobStorageConfig); + + var service = new BlobService( + _mockConfigService.Object, + _mockLogger.Object, + queueClient ?? _mockQueueClient.Object); + + // Replace private BlobServiceClient with mock + var serviceField = typeof(BlobService) + .GetField("_blobServiceClient", + System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); + serviceField.SetValue(service, _mockBlobServiceClient.Object); + + return service; + } + + [Fact] + public async Task AddObjectToBlob_WhenContainerExists_ShouldUploadSuccessfully() + { + // Arrange + var extractResponse = new ExtractResponse + { + FilePath = _faker.System.FileName(), + ExtractResponseStream = new MemoryStream(Encoding.UTF8.GetBytes(_faker.Lorem.Paragraph())) + }; + + var mockBlobContentInfo = new Mock(); + var mockResponse = new Mock>(); + mockResponse.Setup(x => x.Value).Returns(mockBlobContentInfo.Object); + + _mockBlobServiceClient + .Setup(x => x.GetBlobContainerClient(It.IsAny())) + .Returns(_mockContainerClient.Object); + + _mockContainerClient + .Setup(x => x.ExistsAsync(It.IsAny())) + .ReturnsAsync(Response.FromValue(true, new Mock().Object)); + + _mockContainerClient + .Setup(x => x.GetBlobClient(It.IsAny())) + .Returns(_mockBlobClient.Object); + + _mockBlobClient + .Setup(x => x.UploadAsync( + It.IsAny(), + It.Is(o => o == true), + It.IsAny())) + .ReturnsAsync(mockResponse.Object); + + var service = CreateBlobService(); + + // Act + var result = await service.AddObjectToBlob(extractResponse); + + // Assert + result.Should().Be(mockBlobContentInfo.Object); + } + + [Fact] + public async Task AddObjectToBlob_WhenContainerDoesNotExist_ShouldReturnNull() + { + // Arrange + var extractResponse = new ExtractResponse + { + FilePath = _faker.System.FileName(), + ExtractResponseStream = new MemoryStream(Encoding.UTF8.GetBytes(_faker.Lorem.Paragraph())) + }; + + _mockBlobServiceClient + .Setup(x => x.GetBlobContainerClient(It.IsAny())) + .Returns(_mockContainerClient.Object); + + _mockContainerClient + .Setup(x => x.ExistsAsync(It.IsAny())) + .ReturnsAsync(Response.FromValue(false, Mock.Of())); + + var service = CreateBlobService(); + + // Act + var result = await service.AddObjectToBlob(extractResponse); + + // Assert + result.Should().BeNull(); + } + + [Fact] + public async Task AddMessageToBlobQueue_WhenQueueExists_ShouldSendMessage() + { + // Arrange + var fileTypeId = _faker.Random.Int(1, 100); + var blobName = _faker.System.FileName(); + + _mockQueueClient + .Setup(x => x.ExistsAsync(It.IsAny())) + .ReturnsAsync(Response.FromValue(true, Mock.Of())); + + var service = CreateBlobService(); + + // Act + await service.AddMessageToBlobQueue(1, fileTypeId, blobName); + + // Assert + _mockQueueClient.Verify(x => x.SendMessageAsync(It.IsAny()), Times.Once); + + _mockLogger.Verify( + x => x.Log( + LogLevel.Information, + It.IsAny(), + It.Is((o, t) => o.ToString().Contains("Adding message to blob queue")), + null, + It.IsAny>()), + Times.Once); + } + + [Fact] + public async Task AddMessageToBlobQueue_WhenFileCountNotOne_ShouldNotSendMessage() + { + // Arrange + var fileTypeId = _faker.Random.Int(1, 100); + var blobName = _faker.System.FileName(); + + _mockQueueClient + .Setup(x => x.ExistsAsync(It.IsAny())) + .ReturnsAsync(Response.FromValue(true, Mock.Of())); + + var service = CreateBlobService(); + + // Act + await service.AddMessageToBlobQueue(2, fileTypeId, blobName); + + // Assert + _mockQueueClient.Verify( + x => x.SendMessageAsync(It.IsAny(), + It.IsAny()), + Times.Never); + } + + [Fact] + public async Task AddObjectToBlob_WhenRequestFailedExceptionOccurs_ShouldThrowException() + { + // Arrange + var extractResponse = new ExtractResponse + { + FilePath = _faker.System.FileName(), + ExtractResponseStream = new MemoryStream(Encoding.UTF8.GetBytes(_faker.Lorem.Paragraph())) + }; + + var requestFailedException = new RequestFailedException("Container does not exist"); + + _mockBlobServiceClient + .Setup(x => x.GetBlobContainerClient(It.IsAny())) + .Returns(_mockContainerClient.Object); + + _mockContainerClient + .Setup(x => x.ExistsAsync(It.IsAny())) + .ThrowsAsync(requestFailedException); + + var service = CreateBlobService(); + + // Act & Assert + await Assert.ThrowsAsync(() => + service.AddObjectToBlob(extractResponse)); + + _mockLogger.Verify( + x => x.Log( + LogLevel.Error, + It.IsAny(), + It.Is((o, t) => o.ToString().Contains("The container does not exist")), + requestFailedException, + It.IsAny>()), + Times.Once); + } + + [Fact] + public async Task AddObjectToBlob_ShouldLogError_AndThrow_OnGenericException() + { + // Arrange + var extractResponse = new ExtractResponse + { + FilePath = _faker.System.FileName(), + ExtractResponseStream = new MemoryStream(Encoding.UTF8.GetBytes(_faker.Lorem.Paragraph())) + }; + + var genericException = new Exception("Something bad happened"); + + _mockBlobServiceClient + .Setup(x => x.GetBlobContainerClient(It.IsAny())) + .Returns(_mockContainerClient.Object); + + _mockContainerClient + .Setup(x => x.ExistsAsync(It.IsAny())) + .ThrowsAsync(genericException); + + var service = CreateBlobService(); + + // Act & Assert + await Assert.ThrowsAsync(() => + service.AddObjectToBlob(extractResponse)); + + _mockLogger.Verify( + x => x.Log( + LogLevel.Error, + It.IsAny(), + It.Is((o, t) => + o.ToString().Contains("An error occurred while trying to add a blob to the storage")), + genericException, + It.IsAny>()), + Times.Once); + } + + [Fact] + public async Task AddMessageToBlobQueue_WhenQueueDoesNotExist_ShouldThrowException() + { + // Arrange + var fileTypeId = _faker.Random.Int(1, 100); + var blobName = _faker.System.FileName(); + + var requestFailedException = new RequestFailedException("Queue does not exist"); + + _mockQueueClient + .Setup(x => x.ExistsAsync(It.IsAny())) + .ThrowsAsync(requestFailedException); + + var service = CreateBlobService(); + + // Act & Assert + await Assert.ThrowsAsync(() => + service.AddMessageToBlobQueue(1, fileTypeId, blobName)); + + _mockLogger.Verify( + x => x.Log( + LogLevel.Error, + It.IsAny(), + It.Is((o, t) => o.ToString().Contains("The queue does not exist")), + requestFailedException, + It.IsAny>()), + Times.Once); + } + + [Fact] + public async Task AddMessageToBlobQueue_ShouldThrowError_AndLogMessage_OnGenericException() + { + // Arrange + var fileTypeId = _faker.Random.Int(1, 100); + var blobName = _faker.System.FileName(); + + var genericException = new Exception("Something bad happened"); + + _mockQueueClient + .Setup(x => x.ExistsAsync(It.IsAny())) + .ThrowsAsync(genericException); + + var service = CreateBlobService(); + + // Act & Assert + await Assert.ThrowsAsync(() => + service.AddMessageToBlobQueue(1, fileTypeId, blobName)); + + _mockLogger.Verify( + x => x.Log( + LogLevel.Error, + It.IsAny(), + It.Is((o, t) => + o.ToString().Contains("An error occurred while trying to add a message to the queue")), + genericException, + It.IsAny>()), + Times.Once); + } + } +} \ No newline at end of file diff --git a/source/Functions.Tests/Services/ConfigurationServiceTests.cs b/source/Functions.Tests/Services/ConfigurationServiceTests.cs new file mode 100644 index 0000000..1ba3191 --- /dev/null +++ b/source/Functions.Tests/Services/ConfigurationServiceTests.cs @@ -0,0 +1,255 @@ +using Bogus; +using Core.DTOs.Response.Configuration; +using Core.Helpers; +using Core.Services.Interfaces; +using Dapper; +using FluentAssertions; +using Functions.Services; +using Microsoft.Extensions.Logging.Testing; +using Moq; + +namespace Functions.Tests.Services +{ + public class ConfigurationServiceTests + { + private readonly Mock _mockDataService; + private readonly FakeLogger _fakeLogger; + private readonly ConfigurationService _configurationService; + + public ConfigurationServiceTests() + { + _mockDataService = new Mock(); + _fakeLogger = new FakeLogger(); + + _configurationService = new ConfigurationService(_mockDataService.Object, _fakeLogger); + } + + private static BlobStorage GenerateBlobStorage() => + new Faker() + .RuleFor(b => b.ConnectionString, f => f.Internet.Url()) + .RuleFor(b => b.ContainerName, f => f.Random.Word()) + .RuleFor(b => b.QueueName, f => f.Random.Word()) + .Generate(); + + private static FilePathConstants GenerateFilePathConstants() => + new Faker() + .RuleFor(f => f.PathSeparator, "/") + .RuleFor(f => f.ProjectNameFilePrefix, "proj_") + .RuleFor(f => f.ComponentSeparator, "_") + .RuleFor(f => f.FileExtension, ".csv") + .Generate(); + + private static List GenerateFileTypes(int count = 3) => + new Faker() + .RuleFor(f => f.FileTypeFilePrefix, f => f.Random.Word()) + .RuleFor(f => f.DirectoryName, f => f.System.DirectoryPath()) + .RuleFor(f => f.Enabled, true) + .Generate(count); + + private static SplunkClient GenerateSplunkClient() => + new Faker() + .RuleFor(s => s.ApiToken, f => f.Random.AlphaNumeric(32)) + .RuleFor(s => s.QueryTimeout, f => f.Random.Int(10, 60)) + .Generate(); + + private static List GenerateSplunkInstances(int count = 3) => new List() + { + new SplunkInstance() + { + Source = SplunkInstances.cloud.ToString(), + SourceGroup = "fakeGroup1", + }, + new SplunkInstance() + { + Source = SplunkInstances.spineb.ToString(), + SourceGroup = "fakeGroup2", + }, + new SplunkInstance() + { + Source = SplunkInstances.spinea.ToString(), + SourceGroup = "fakeGroup3", + }, + }; + + #region GetBlobStorageConfiguration Tests + + [Fact] + public async Task GetBlobStorageConfiguration_ShouldReturnBlobStorage_WhenDataExists() + { + var expected = GenerateBlobStorage(); + _mockDataService + .Setup(x => x.ExecuteQueryStoredProcedure("[Configuration].[GetBlobStorageConfiguration]", + It.IsAny())) + .ReturnsAsync(new List { expected }); + + var result = await _configurationService.GetBlobStorageConfiguration(); + + result.Should().BeEquivalentTo(expected); + } + + [Fact] + public async Task GetBlobStorageConfiguration_ShouldReturnNull_WhenNoDataExists() + { + _mockDataService + .Setup(x => x.ExecuteQueryStoredProcedure( + It.IsAny(), + It.IsAny())) + .ReturnsAsync(new List()); + + var result = await _configurationService.GetBlobStorageConfiguration(); + + result.Should().BeNull(); + } + + #endregion + + #region GetFilePathConstants Tests + + [Fact] + public async Task GetFilePathConstants_ShouldReturnFilePathConstants_WhenDataExists() + { + var expected = GenerateFilePathConstants(); + _mockDataService + .Setup(x => x.ExecuteQueryStoredProcedure( + "[Configuration].[GetFilePathConstants]", + It.IsAny())) + .ReturnsAsync(new List { expected }); + + var result = await _configurationService.GetFilePathConstants(); + + result.Should().BeEquivalentTo(expected); + } + + [Fact] + public async Task GetFilePathConstants_ShouldReturnNull_WhenNoDataExists() + { + _mockDataService + .Setup(x => x.ExecuteQueryStoredProcedure( + "[Configuration].[GetFilePathConstants]", + It.IsAny())) + .ReturnsAsync(new List()); + + var result = await _configurationService.GetFilePathConstants(); + + result.Should().BeNull(); + } + + #endregion + + #region GetFileTypes Tests + + [Fact] + public async Task GetFileTypes_ShouldReturnFileTypes_WhenDataExists() + { + var expected = GenerateFileTypes(); + _mockDataService + .Setup(x => x.ExecuteQueryStoredProcedure("[Configuration].[GetFileTypes]", + It.IsAny())) + .ReturnsAsync(expected); + + var result = await _configurationService.GetFileTypes(); + + result.Should().BeEquivalentTo(expected); + } + + + [Fact] + public async Task GetFileTypes_ShouldReturnEmptyList_WhenNoDataExists() + { + _mockDataService + .Setup(x => x.ExecuteQueryStoredProcedure("[Configuration].[GetFileTypes]", + It.IsAny())) + .ReturnsAsync([]); + + var result = await _configurationService.GetFileTypes(); + + result.Should().BeEmpty(); + } + + #endregion + + #region GetFileType + + [Fact] + public async Task GetFileType_ShouldReturnMatchingFiletTypeFromConfiguration() + { + var expectedResult = new FileType() + { + FileTypeId = 1, + DirectoryName = "fakeDir", + FileTypeFilePrefix = "asidlookup", + Enabled = true, + }; + + var fakeResults = new List() + { + new() + { + FileTypeId = 2, + DirectoryName = "fakeDir", + FileTypeFilePrefix = "ssptrans", + Enabled = true, + }, + new() + { + FileTypeId = 3, + DirectoryName = "fakeDir", + FileTypeFilePrefix = "meshtrans", + Enabled = true, + }, + expectedResult + }; + + _mockDataService.Setup(x => + x.ExecuteQueryStoredProcedure("[Configuration].[GetFileTypes]", + It.IsAny())) + .ReturnsAsync(fakeResults); + + var result = await _configurationService.GetFileType(FileTypes.asidlookup); + + result.Should().BeEquivalentTo(expectedResult); + } + + #endregion + + #region GetSplunkClientConfiguration Tests + + [Fact] + public async Task GetSplunkClientConfiguration_ShouldReturnSplunkClient_WhenDataExists() + { + var expected = GenerateSplunkClient(); + _mockDataService + .Setup(x => + x.ExecuteQueryStoredProcedure("[Configuration].[GetSplunkClientConfiguration]", + It.IsAny())) + .ReturnsAsync(new List { expected }); + + var result = await _configurationService.GetSplunkClientConfiguration(); + + result.Should().BeEquivalentTo(expected); + } + + #endregion + + #region GetSplunkInstance Tests + + [Fact] + public async Task GetSplunkInstance_ShouldReturnMatchingInstance_WhenExists() + { + var instances = GenerateSplunkInstances(); + var targetInstance = instances.First(); + + _mockDataService + .Setup(x => x.ExecuteQueryStoredProcedure("[Configuration].[GetSplunkInstances]", + It.IsAny())) + .ReturnsAsync(instances); + + var result = + await _configurationService.GetSplunkInstance(Enum.Parse(targetInstance.Source)); + + result.Should().BeEquivalentTo(targetInstance); + } + + #endregion + } +} \ No newline at end of file diff --git a/source/Functions.Tests/Services/CoreConfigurationServiceTests.cs b/source/Functions.Tests/Services/CoreConfigurationServiceTests.cs new file mode 100644 index 0000000..fbd5ed0 --- /dev/null +++ b/source/Functions.Tests/Services/CoreConfigurationServiceTests.cs @@ -0,0 +1,56 @@ +using FluentAssertions; +using Functions.Services; +using Microsoft.Extensions.Configuration; +using Moq; + +namespace Functions.Tests.Services; + +public class CoreConfigurationServiceTests +{ + private readonly Mock _mockConfiguration; + private readonly CoreConfigurationService _configurationService; + + public CoreConfigurationServiceTests() + { + var inMemorySettings = new Dictionary + { + { "ConnectionStrings:GPConnectAnalytics", "Server=myServer;Database=myDB;User Id=myUser;Password=myPass;" } + }; + + var configuration = new ConfigurationBuilder() + .AddInMemoryCollection(inMemorySettings!) + .Build(); + + + _configurationService = new CoreConfigurationService(configuration); + } + + [Fact] + public void GetConnectionString_ShouldReturnConnectionString_WhenValidNameIsProvided() + { + // Arrange + const string connectionName = "GPConnectAnalytics"; + const string expectedConnectionString = "Server=myServer;Database=myDB;User Id=myUser;Password=myPass;"; + + // Act + var result = _configurationService.GetConnectionString(connectionName); + + // Assert + result.Should().Be(expectedConnectionString); + } + + + [Fact] + public void GetConnectionString_ShouldThrowArgumentException_WhenConnectionStringIsNull() + { + // Arrange + const string connectionName = "InvalidConnection"; + + // Act + Action act = () => _configurationService.GetConnectionString(connectionName); + + // Assert + act.Should().Throw() + .WithMessage("No connection string with given name"); + } +} \ No newline at end of file diff --git a/source/Functions.Tests/Services/FileServiceTests.cs b/source/Functions.Tests/Services/FileServiceTests.cs new file mode 100644 index 0000000..dcae812 --- /dev/null +++ b/source/Functions.Tests/Services/FileServiceTests.cs @@ -0,0 +1,29 @@ +using Core.Services.Interfaces; +using Dapper; +using Functions.Services; +using Moq; + +namespace Functions.Tests.Services; + +public class FileServiceTests +{ + [Fact] + public void ApiReaderAddFile_ShouldCallStoredProcedure() + { + // Arrange + var _mockDataService = new Mock(); + var _fileService = new FileService(_mockDataService.Object); + + // Act + _fileService.ApiReaderAddFile(1, "path/to/file", true); + + // Assert + _mockDataService.Verify(x => x.ExecuteStoredProcedure("ApiReader.AddFile", + It.Is(p => + p.Get("FileTypeId") == 1 && + p.Get("FilePath") == "path/to/file" && + p.Get("Override") == true + )), + Times.Once); + } +} \ No newline at end of file diff --git a/source/Functions.Tests/Services/ImportServiceTests.cs b/source/Functions.Tests/Services/ImportServiceTests.cs new file mode 100644 index 0000000..54de01f --- /dev/null +++ b/source/Functions.Tests/Services/ImportServiceTests.cs @@ -0,0 +1,315 @@ +using System.Data; +using Azure.Storage.Blobs.Models; +using Bogus; +using Core.DTOs.Request; +using Core.DTOs.Response.Configuration; +using Core.DTOs.Response.Queue; +using Core.DTOs.Response.Splunk; +using Core.Helpers; +using Core.Services.Interfaces; +using Dapper; +using FluentAssertions; +using Functions.Services; +using Functions.Services.Interfaces; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Testing; +using Moq; + +namespace Functions.Tests.Services; + +public class ImportServiceTests +{ + private readonly Mock _mockConfigService; + private readonly Mock _mockDataService; + private readonly Mock _mockBlobService; + private readonly FakeLogger _fakeLogger; + private readonly ImportService _importService; + private readonly Mock _mockFileService; + + public ImportServiceTests() + { + _fakeLogger = new FakeLogger(); + _mockConfigService = new Mock(); + _mockDataService = new Mock(); + _mockBlobService = new Mock(); + _mockFileService = new Mock(); + + + _importService = new ImportService( + _mockConfigService.Object, + _mockDataService.Object, + _mockBlobService.Object, + _fakeLogger, + _mockFileService.Object + ); + } + + #region AddDownloadFileManually Tests + + [Fact] + public void AddDownloadFileManually_ShouldAddFileToDb_And_AddToBlobQueue() + { + // Arrange + var fakeFileType = GenerateFileType(); + var filePath = "asid-lookup-data/testfile.csv"; + _mockConfigService.Setup(x => x.GetFileType(FileTypes.asidlookup)).ReturnsAsync(fakeFileType); + + _mockBlobService + .Setup(x => x.AddMessageToBlobQueue(It.IsAny(), It.IsAny(), It.IsAny(), + It.IsAny())); + + + _mockFileService.Setup(x => x.ApiReaderAddFile(fakeFileType.FileTypeId, filePath, true)) + .ReturnsAsync(1); + + // Act + var result = _importService.AddDownloadedFileManually(filePath); + + // Assert + _mockBlobService.Verify(x => + x.AddMessageToBlobQueue( + 1, // mocked file count added + fakeFileType.FileTypeId, + filePath, + true), Times.Once + ); + + // Verify it calls internal AddFileMessage - which in turn calls the stored procedure + _mockFileService.Verify(x => x.ApiReaderAddFile(fakeFileType.FileTypeId, filePath, true), Times.Once); + } + + [Fact] + public async Task AddDownloadFileManually_ShouldThrowArgumentException_WhenFileTypeFromPathNull() + { + // Arrange + var filePath = "non-existant-fileType/testfile.csv"; + + // Act + var ex = await Assert.ThrowsAsync(() => + _importService.AddDownloadedFileManually(filePath) + ); + + // Assert + ex.Message.Should().Be("Filepath does not contain vailid file type suffix"); + } + + #endregion + + + #region AddObjectFileMessage Tests + + [Fact] + public async Task AddObjectFileMessage_ShouldAddObjectToBlob_WhenSuccessfulStatusCode() + { + //Arrange + var fileType = GenerateFileType(); + var extractResponse = new ExtractResponse() + { + ExtractResponseMessage = new HttpResponseMessage() + { + StatusCode = System.Net.HttpStatusCode.OK, + }, + FilePath = "asid-lookup-data/testfile.csv", + }; + + // Act + await _importService.AddObjectFileMessage(fileType, extractResponse); + + // Assert + _mockBlobService.Verify(x => x.AddObjectToBlob(extractResponse), Times.Once); + } + + [Fact] + public async Task AddObjectFileMessage_LogsWarning_WhenStatusCodeNotOk() + { + //Arrange + var fileType = GenerateFileType(); + var extractResponse = new ExtractResponse() + { + ExtractResponseMessage = new HttpResponseMessage() + { + StatusCode = System.Net.HttpStatusCode.BadRequest, + }, + FilePath = "asid-lookup-data/testfile.csv", + }; + + // Act + await _importService.AddObjectFileMessage(fileType, extractResponse); + + // Assert + _fakeLogger.LatestRecord.Message.Should().Be(extractResponse.ExtractResponseMessage.ToString()); + _fakeLogger.LatestRecord.Level.Should().Be(LogLevel.Warning); + } + + [Fact] + public async Task AddObjectFileMessage_DoesNotCallAddObjectToBlob_WhenStatusCodeNotOk() + { + //Arrange + var fileType = GenerateFileType(); + var extractResponse = new ExtractResponse() + { + ExtractResponseMessage = new HttpResponseMessage() + { + StatusCode = System.Net.HttpStatusCode.BadRequest, + }, + FilePath = "asid-lookup-data/testfile.csv", + }; + + // Act + await _importService.AddObjectFileMessage(fileType, extractResponse); + + // Assert + _mockBlobService.Verify(x => x.AddObjectToBlob(extractResponse), Times.Never); + } + + [Fact] + public async Task AddObjectFileMessage_ShouldAddFileToDb_And_AddMessageToBlobQueue() + { + // Arrange + var fileType = GenerateFileType(); + var extractResponse = new ExtractResponse() + { + ExtractResponseMessage = new HttpResponseMessage() + { + StatusCode = System.Net.HttpStatusCode.OK, + }, + FilePath = "asid-lookup-data/testfile.csv", + }; + + _mockBlobService + .Setup(x => x.AddObjectToBlob(extractResponse)) + .ReturnsAsync(Mock.Of()); + + _mockFileService.Setup(x => x.ApiReaderAddFile(fileType.FileTypeId, extractResponse.FilePath, true)) + .ReturnsAsync(1); + + // Act + await _importService.AddObjectFileMessage(fileType, extractResponse); + + // Assert + _mockBlobService.Verify(x => + x.AddMessageToBlobQueue( + 1, // mocked file count added + fileType.FileTypeId, + extractResponse.FilePath, + true), Times.Once + ); + + _mockFileService.Verify(x => x.ApiReaderAddFile(fileType.FileTypeId, extractResponse.FilePath, true), + Times.Once); + } + + [Fact] + public async Task AddObjectFileMessage_ShouldNotAddFileToDb_And_AddMessageToBlobQueue_WhenStatusNotOk() + { + // Arrange + var fileType = GenerateFileType(); + var extractResponse = new ExtractResponse() + { + ExtractResponseMessage = new HttpResponseMessage() + { + StatusCode = System.Net.HttpStatusCode.BadRequest, + }, + FilePath = "asid-lookup-data/testfile.csv", + }; + + _mockBlobService + .Setup(x => x.AddObjectToBlob(extractResponse)) + .ReturnsAsync(Mock.Of()); + + _mockFileService.Setup(x => x.ApiReaderAddFile(fileType.FileTypeId, extractResponse.FilePath, true)) + .ReturnsAsync(1); + + // Act + await _importService.AddObjectFileMessage(fileType, extractResponse); + + // Assert + _mockBlobService.Verify(x => + x.AddMessageToBlobQueue( + 1, // mocked file count added + fileType.FileTypeId, + extractResponse.FilePath, + true), Times.Never + ); + + _mockFileService.Verify(x => x.ApiReaderAddFile(fileType.FileTypeId, extractResponse.FilePath, true), + Times.Never); + } + + #endregion + + #region InstallData Tests + + [Fact] + public async Task InstallData_ShouldExecuteStoredProcedure_InstallNextFile_WithCorrectParameters() + { + // Arrange + var fileType = GenerateFileType(); + var mockQueueItem = new Message + { + FileTypeId = fileType.FileTypeId, + BlobName = "RandomBlobName", + Override = true, + }; + + var procedureName = "Import.InstallNextFile"; + var callCount = 0; + var capturedParams = new List(); + + _mockDataService + .Setup(x => x.ExecuteStoredProcedureWithOutputParameters(procedureName, It.IsAny())) + .Callback((_, parameters) => + { + // Capture a copy of the parameters + var copiedParams = new DynamicParameters(parameters); + capturedParams.Add(copiedParams); + + // Simulate stored procedure behavior: first call sets MoreFilesToInstall = true, second = false + parameters.Add("@MoreFilesToInstall", callCount == 0, DbType.Boolean, ParameterDirection.Output); + callCount++; + }) + .ReturnsAsync((string proc, DynamicParameters parameters) => parameters); + + + // Act + await _importService.InstallData(mockQueueItem); + + // Assert + _mockDataService.Verify( + x => x.ExecuteStoredProcedureWithOutputParameters(procedureName, It.IsAny()), + Times.Exactly(2)); + + // Validate first call parameters + Assert.Equal(mockQueueItem.FileTypeId, capturedParams[0].Get("@FileTypeId")); + Assert.Equal(mockQueueItem.Override, capturedParams[0].Get("@Override")); + + // Validate second call parameters + Assert.Equal(mockQueueItem.FileTypeId, capturedParams[1].Get("@FileTypeId")); + Assert.Equal(mockQueueItem.Override, capturedParams[1].Get("@Override")); + + // Validate log messages are recorded: + _fakeLogger.Collector.GetSnapshot()[0].Message.Should().Be("Installing file into database"); + var messages = _fakeLogger.Collector.GetSnapshot(); + + var moreFilesMessageTrue = messages + .Any(x => x.Message.Contains("More files to install? True")); + moreFilesMessageTrue.Should().BeTrue(); + + var moreFilesMessageFalse = messages + .Any(x => x.Message.Contains("More files to install? False")); + + moreFilesMessageFalse.Should().BeTrue(); + } + + #endregion + + #region Private Methods + + private static FileType GenerateFileType() => new Faker() + .RuleFor(f => f.FileTypeFilePrefix, f => f.Random.Word()) + .RuleFor(f => f.DirectoryName, f => f.System.DirectoryPath()) + .RuleFor(f => f.Enabled, true) + .Generate(); + + #endregion +} \ No newline at end of file diff --git a/source/Functions.Tests/Services/SplunkServicesTests.cs b/source/Functions.Tests/Services/SplunkServicesTests.cs new file mode 100644 index 0000000..d56ea49 --- /dev/null +++ b/source/Functions.Tests/Services/SplunkServicesTests.cs @@ -0,0 +1,294 @@ +using System.IdentityModel.Tokens.Jwt; +using System.Net; +using System.Security.Claims; +using System.Text; +using Bogus; +using Core; +using Core.DTOs.Request; +using Core.DTOs.Response.Configuration; +using Core.DTOs.Response.Splunk; +using Core.Helpers; +using Core.Services.Interfaces; +using FluentAssertions; +using Functions.Services; +using Functions.Services.Interfaces; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Testing; +using Microsoft.IdentityModel.Tokens; +using Moq; +using Moq.Protected; +using Newtonsoft.Json; + +namespace Functions.Tests.Services; + +public class SplunkServiceTests +{ + private readonly Mock _mockConfigService; + private readonly Mock _mockHttpClientFactory; + private readonly Mock _mockImportService; + private readonly FakeLogger _fakeLogger; + private readonly SplunkService _splunkService; + private readonly Mock _mockTimeProvider; + + public SplunkServiceTests() + { + _mockTimeProvider = new Mock(); + _mockConfigService = new Mock(); + _mockHttpClientFactory = new Mock(); + _mockImportService = new Mock(); + _fakeLogger = new FakeLogger(); + + _mockConfigService.Setup(x => x.GetFilePathConstants()) + .ReturnsAsync(new FilePathConstants + { + PathSeparator = "/", ProjectNameFilePrefix = "proj_", ComponentSeparator = "_", FileExtension = ".csv" + }); + + var splunkInstance = new SplunkInstance { Source = "splunk-source" }; + _mockConfigService.Setup(x => x.GetSplunkInstance(It.IsAny())).ReturnsAsync(splunkInstance); + + _splunkService = new SplunkService( + _mockConfigService.Object, + _mockHttpClientFactory.Object, + _mockImportService.Object, + _fakeLogger, + _mockTimeProvider.Object + ); + } + + private static FileType GenerateFileType() => new Faker() + .RuleFor(f => f.FileTypeFilePrefix, f => f.Random.Word()) + .RuleFor(f => f.DirectoryName, f => f.System.DirectoryPath()) + .RuleFor(f => f.Enabled, true) + .Generate(); + + private static UriRequest GenerateUriRequest(DateTime? fixedFromDate = null, DateTime? fixedToDate = null, + TimeSpan? hour = null, bool isFake = true) + { + if (!isFake) + { + return new UriRequest + { + Request = new Uri("https://splunk.com/api/fixed-test"), + EarliestDate = fixedFromDate ?? DateTime.Now.AddDays(-1), + LatestDate = fixedToDate ?? DateTime.Now, + Hour = hour ?? new TimeSpan(0, 0, 0) + }; + } + + var faker = new Faker(); + return new UriRequest() + { + Request = new Uri("https://splunk.com/api/fake-test"), + EarliestDate = faker.Date.Past(), + LatestDate = faker.Date.Recent(1), + Hour = faker.Date.Timespan() + }; + } + + + [Fact] + public async Task DownloadCSVDateRangeAsync_ShouldReturnExtractResponse_WhenValidInput() + { + var fileType = GenerateFileType(); + var uriRequest = GenerateUriRequest(); + + var httpClient = new HttpClient(new Mock().Object); + _mockHttpClientFactory.Setup(x => x.CreateClient(It.IsAny())).Returns(httpClient); + + var result = await _splunkService.DownloadCSVDateRangeAsync(fileType, uriRequest, true); + + result.Should().NotBeNull(); + result.FilePath.Should().Contain(fileType.FileTypeFilePrefix); + } + + [Fact] + public async Task DownloadCSVDateRangeAsync_ShouldThrowTimeoutException() + { + var fileType = GenerateFileType(); + var uriRequest = GenerateUriRequest(); + _mockConfigService.Setup(x => x.GetFilePathConstants()).ThrowsAsync(new TimeoutException()); + + Func act = async () => await _splunkService.DownloadCSVDateRangeAsync(fileType, uriRequest, true); + + await act.Should().ThrowAsync(); + _fakeLogger.Collector.LatestRecord.Message.Should().Be("A timeout error has occurred"); + } + + [Fact] + public async Task DownloadCSVDateRangeAsync_ShouldThrowException() + { + var fileType = GenerateFileType(); + var uriRequest = GenerateUriRequest(); + _mockConfigService.Setup(x => x.GetFilePathConstants()).ThrowsAsync(new Exception()); + + Func act = async () => await _splunkService.DownloadCSVDateRangeAsync(fileType, uriRequest, true); + await act.Should().ThrowAsync(); + + _fakeLogger.Collector.LatestRecord.Message.Should().Be("An error occurred in trying to execute a GET request"); + } + + [Fact] + public async Task ExecuteBatchDownloadFromSplunk_ShouldCallDownloadAndImport_WhenFileTypeIsEnabled() + { + var fileType = GenerateFileType(); + var uriRequest = GenerateUriRequest(); + var extractResponse = new ExtractResponse { FilePath = "mock-path" }; + + _mockConfigService.Setup(x => x.GetFilePathConstants()).ReturnsAsync(new FilePathConstants()); + _mockConfigService.Setup(x => x.GetSplunkInstance(It.IsAny())) + .ReturnsAsync(new SplunkInstance()); + + _mockImportService.Setup(x => x.AddObjectFileMessage(fileType, extractResponse)).Returns(Task.CompletedTask); + + await _splunkService.ExecuteBatchDownloadFromSplunk(fileType, uriRequest, true); + + _mockImportService.Verify(x => x.AddObjectFileMessage(fileType, It.IsAny()), Times.Once); + } + + [Fact] + public void ExecuteBatchDownloadFromSplunk_ShouldLogWarning_WhenFileTypeIsDisabled() + { + var fileType = GenerateFileType(); + fileType.Enabled = false; + + var uriRequest = GenerateUriRequest(); + + + _splunkService.ExecuteBatchDownloadFromSplunk(fileType, uriRequest, true); + + _fakeLogger.Collector.LatestRecord.Message.Should() + .Be($"Filetype {fileType.FileTypeFilePrefix} is not enabled. Please check if this is correct"); + + _fakeLogger.Collector.LatestRecord.Level.Should().Be(LogLevel.Warning); + } + + [Fact] + public void ExecuteBatchDownloadFromSplunk_ShouldLogError_WhenExceptionThrown() + { + var fileType = GenerateFileType(); + + var uriRequest = GenerateUriRequest(); + _mockConfigService.Setup(x => x.GetFilePathConstants()).ThrowsAsync(new Exception()); + + _ = _splunkService.ExecuteBatchDownloadFromSplunk(fileType, uriRequest, true); + + _fakeLogger.Collector.LatestRecord.Message.Should() + .Be("An error has occurred while attempting to execute an Azure function"); + + _fakeLogger.Collector.LatestRecord.Level.Should().Be(LogLevel.Error); + } + + [Fact] + public async Task GetSearchResultsFromRequestUri_ShouldReturnExtractResponse_ApiTokenValid() + { + var fakeToken = GenerateFakeJwt(); + + var uriRequest = GenerateUriRequest(isFake: false); + var mockHandler = new Mock(); + + mockHandler + .Protected() + .Setup>( + "SendAsync", + ItExpr.IsAny(), + ItExpr.IsAny() + ) + .ReturnsAsync(new HttpResponseMessage + { + StatusCode = HttpStatusCode.OK, + Content = new StringContent("{ \"message\": \"Success\" }", Encoding.UTF8, "application/json") + }); + + var httpClient = new HttpClient(mockHandler.Object); + _mockHttpClientFactory.Setup(x => x.CreateClient("SplunkApiClient")).Returns(httpClient); + _mockConfigService.Setup(x => x.GetSplunkClientConfiguration()).ReturnsAsync(new SplunkClient + { + QueryTimeout = 30, + ApiToken = fakeToken, + }); + + // Act + var resultMessage = await _splunkService.GetSearchResultFromRequestUri(uriRequest); + + // Assert: Ensure the response is not null + resultMessage.Should().NotBeNull(); + resultMessage.ExtractResponseMessage.Should().NotBeNull(); + resultMessage.ExtractResponseStream.Should().NotBeNull(); + resultMessage.UriRequest.Should().Be(uriRequest); + + resultMessage.ExtractResponseMessage.StatusCode.Should().Be(HttpStatusCode.OK); + + // Assert: Read and verify response content + var contentString = await new StreamReader(resultMessage.ExtractResponseStream).ReadToEndAsync(); + contentString.Should().Contain("Success"); // Verify the JSON content + } + + [Fact] + public async Task GetSearchResultsFromRequestUri_ShouldReturnExtractResponse_ApiToken_NotValid() + { + var fakeToken = GenerateFakeJwt(isValid: false); + var uriRequest = GenerateUriRequest(isFake: false); + _mockConfigService.Setup(x => x.GetSplunkClientConfiguration()).ReturnsAsync(new SplunkClient + { + QueryTimeout = 30, + ApiToken = fakeToken, + }); + + // Act + var resultMessage = await _splunkService.GetSearchResultFromRequestUri(uriRequest); + + // Assert: Ensure the response is not null + resultMessage.ExtractResponseMessage.StatusCode.Should().Be(HttpStatusCode.Unauthorized); + resultMessage.ExtractResponseMessage.ReasonPhrase.Should().Be("The authentication token has expired"); + } + + [Fact] + public async Task GetSearchResultsFromRequestUri_ShouldReturnRequestTimeout_OnOperationCancelledException() + { + var fakeToken = GenerateFakeJwt(isValid: false); + var uriRequest = GenerateUriRequest(isFake: false); + _mockConfigService.Setup(x => x.GetSplunkClientConfiguration()) + .ThrowsAsync(new OperationCanceledException("Operation timed out")); + + // Act + var resultMessage = await _splunkService.GetSearchResultFromRequestUri(uriRequest); + + // Assert: Ensure the response is not null + resultMessage.ExtractResponseMessage.StatusCode.Should().Be(HttpStatusCode.RequestTimeout); + resultMessage.ExtractResponseMessage.ReasonPhrase.Should().Be("Operation timed out"); + } + + + #region Helpers + + private string GenerateFakeJwt(bool isValid = true) + { + var securityKey = + new SymmetricSecurityKey("your-very-secure-and-long-secret-key-123456"u8.ToArray()); + var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256); + + var claims = new[] + { + new Claim(JwtRegisteredClaimNames.Sub, "test-user"), + new Claim(JwtRegisteredClaimNames.Iss, "fake-issuer"), + new Claim(JwtRegisteredClaimNames.Aud, "expected-audience"), + new Claim(JwtRegisteredClaimNames.Exp, + isValid + ? (DateTimeOffset.UtcNow.AddYears(10)).ToUnixTimeSeconds().ToString() + : (DateTimeOffset.UtcNow.AddYears(-10)).ToUnixTimeSeconds().ToString()) + }; + + var token = new JwtSecurityToken( + issuer: "fake-issuer", + audience: "expected-audience", + claims: claims, + expires: isValid ? DateTime.UtcNow.AddYears(10) : DateTime.UtcNow.AddYears(-10), + signingCredentials: credentials + ); + + return new JwtSecurityTokenHandler().WriteToken(token); + } + + #endregion +} \ No newline at end of file diff --git a/source/Functions.Tests/TestHelpers/ConfigurationHelpers.cs b/source/Functions.Tests/TestHelpers/ConfigurationHelpers.cs new file mode 100644 index 0000000..2a474b0 --- /dev/null +++ b/source/Functions.Tests/TestHelpers/ConfigurationHelpers.cs @@ -0,0 +1,30 @@ +using Bogus; +using Core.DTOs.Response.Configuration; +using Microsoft.Extensions.Configuration; + +namespace Functions.Tests.TestHelpers; + +public class ConfigurationHelpers +{ + public static IConfiguration CreateDefaultConfiguration(string connectionString) + { + var inMemorySettings = new Dictionary + { + { "ConnectionStrings:GPConnectAnalytics", connectionString } + }; + + var configuration = new ConfigurationBuilder() + .AddInMemoryCollection(inMemorySettings!) + .Build(); + + return configuration; + } + + public static FilePathConstants GenerateFilePathConstants() => + new Faker() + .RuleFor(f => f.PathSeparator, "/") + .RuleFor(f => f.ProjectNameFilePrefix, "proj_") + .RuleFor(f => f.ComponentSeparator, "_") + .RuleFor(f => f.FileExtension, ".csv") + .Generate(); +} \ No newline at end of file diff --git a/source/Functions.Tests/TestHelpers/MockRequests.cs b/source/Functions.Tests/TestHelpers/MockRequests.cs new file mode 100644 index 0000000..f254701 --- /dev/null +++ b/source/Functions.Tests/TestHelpers/MockRequests.cs @@ -0,0 +1,56 @@ +using System.Text; +using Microsoft.Azure.Functions.Worker; +using Moq; + +namespace Functions.Tests.TestHelpers; + +public class MockRequests +{ + public static FakeHttpRequestData CreateDateRangeMockRequest(string startDate, string endDate) + { + var context = new Mock(); + var requestMock = new FakeHttpRequestData(context.Object, + new Uri($"https://localhost/api?StartDate={startDate}&EndDate={endDate}")); + + return requestMock; + } + + public static FakeHttpRequestData CreateTodayMockRequest() + { + var context = new Mock(); + var requestMock = new FakeHttpRequestData(context.Object, + new Uri($"https://localhost/api/getDataFromToday")); + + return requestMock; + } + + public static FakeHttpRequestData MockAddDownloadRequest() + { + var context = new Mock(); + var requestMock = new FakeHttpRequestData(context.Object, + new Uri($"https://localhost/api?FilePath=asid-lookup-data/test.csv")); + + return requestMock; + } + + public static FakeHttpRequestData MockRequestNoQuery() + { + var context = new Mock(); + var requestMock = new FakeHttpRequestData(context.Object, + new Uri($"https://localhost/api")); + + return requestMock; + } + + public static FakeHttpRequestData MockRequestWithBody(string jsonBody) + { + var context = new Mock(); + var requestMock = new FakeHttpRequestData( + context.Object, + new Uri($"https://localhost/api"), + new MemoryStream(Encoding.UTF8.GetBytes(jsonBody))); + + + return requestMock; + } +} \ No newline at end of file diff --git a/source/Functions.Tests/TestHelpers/MockTriggers.cs b/source/Functions.Tests/TestHelpers/MockTriggers.cs new file mode 100644 index 0000000..7939c30 --- /dev/null +++ b/source/Functions.Tests/TestHelpers/MockTriggers.cs @@ -0,0 +1,14 @@ +using Microsoft.Azure.Functions.Worker; + +namespace Functions.Tests.TestHelpers; + +public class MockTriggers +{ + public static TimerInfo CreateMockTimerInfo() + { + return new TimerInfo + { + ScheduleStatus = new ScheduleStatus() + }; + } +} \ No newline at end of file diff --git a/source/gpconnect-analytics.Functions/.gitignore b/source/Functions/.gitignore similarity index 100% rename from source/gpconnect-analytics.Functions/.gitignore rename to source/Functions/.gitignore diff --git a/source/Functions/Configuration/EmailConfigurationProvider.cs b/source/Functions/Configuration/EmailConfigurationProvider.cs new file mode 100644 index 0000000..c259c06 --- /dev/null +++ b/source/Functions/Configuration/EmailConfigurationProvider.cs @@ -0,0 +1,29 @@ +using System.Data; +using Core; +using Core.DTOs.Response.Configuration; +using Core.Helpers; +using Dapper; +using Microsoft.Extensions.Configuration; + +namespace Functions.Configuration; + +public interface IEmailConfigurationProvider +{ + Email? GetEmailConfiguration(IConfiguration configuration); +} + +public class EmailConfigurationProvider(IConnectionFactory connectionFactory) : IEmailConfigurationProvider +{ + public Email? GetEmailConfiguration(IConfiguration configuration) + { + var connectionString = configuration.GetConnectionString(ConnectionStrings.GpConnectAnalytics) ?? + throw new InvalidOperationException("connection string cannot be null at this point."); + + using var sqlConnection = connectionFactory.CreateConnection(connectionString); + + IEnumerable result = sqlConnection.Query("[Configuration].[GetEmailConfiguration]", + commandType: CommandType.StoredProcedure); + + return result.FirstOrDefault(); + } +} \ No newline at end of file diff --git a/source/Functions/Configuration/Infrastructure/HttpClient/HttpClientExtensions.cs b/source/Functions/Configuration/Infrastructure/HttpClient/HttpClientExtensions.cs new file mode 100644 index 0000000..87fbeee --- /dev/null +++ b/source/Functions/Configuration/Infrastructure/HttpClient/HttpClientExtensions.cs @@ -0,0 +1,23 @@ +using System.Net.Http.Headers; +using System.Security.Authentication; + +namespace Functions.Configuration.Infrastructure.HttpClient; + +public static class HttpClientExtensions +{ + public static void ConfigureHttpClient(System.Net.Http.HttpClient options) + { + options.Timeout = new TimeSpan(0, 0, 1, 0); + options.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/csv")); + options.DefaultRequestHeaders.CacheControl = new CacheControlHeaderValue { NoCache = true }; + } + + public static HttpMessageHandler CreateHttpMessageHandler() + { + var httpClientHandler = new HttpClientHandler + { + SslProtocols = SslProtocols.Tls13 | SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls + }; + return httpClientHandler; + } +} \ No newline at end of file diff --git a/source/gpconnect-analytics.Functions/Configuration/Infrastructure/Logging/LoggingExtensions.cs b/source/Functions/Configuration/Infrastructure/Logging/LoggingExtensions.cs similarity index 69% rename from source/gpconnect-analytics.Functions/Configuration/Infrastructure/Logging/LoggingExtensions.cs rename to source/Functions/Configuration/Infrastructure/Logging/LoggingExtensions.cs index 5c9b259..5d96cc0 100644 --- a/source/gpconnect-analytics.Functions/Configuration/Infrastructure/Logging/LoggingExtensions.cs +++ b/source/Functions/Configuration/Infrastructure/Logging/LoggingExtensions.cs @@ -1,29 +1,39 @@ -using Dapper; -using gpconnect_analytics.DAL; -using gpconnect_analytics.DTO.Response.Configuration; -using gpconnect_analytics.Helpers; +using System.Data; +using Core.DTOs.Response.Configuration; +using Core.Helpers; +using Dapper; +using Microsoft.Data.SqlClient; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; +using NLog; +using NLog.Extensions.Logging; using NLog.Layouts; using NLog.Targets; -using NLog.Web; -using System.Data; -using System.Data.SqlClient; -using System.Linq; -namespace gpconnect_analytics.Configuration.Infrastructure.Logging +namespace Functions.Configuration.Infrastructure.Logging { public static class LoggingExtensions { - public static ILoggingBuilder ConfigureLoggingServices(ILoggingBuilder loggingBuilder, IConfiguration configuration) + public static ILoggingBuilder ConfigureLoggingServices( + ILoggingBuilder loggingBuilder, + IConfiguration configuration, + IEmailConfigurationProvider emailConfigurationProvider) { + // Set up NLog + LogManager.Setup().LoadConfigurationFromFile("nlog.config"); + + // Add NLog to the logging pipeline + loggingBuilder.AddNLog(); + + // Add custom targets manually (optional) var nLogConfiguration = new NLog.Config.LoggingConfiguration(); var consoleTarget = AddConsoleTarget(); var databaseTarget = AddDatabaseTarget(configuration); - var mailTarget = AddMailTarget(configuration); + var mailTarget = AddMailTarget(configuration, emailConfigurationProvider); - nLogConfiguration.Variables.Add("applicationVersion", ApplicationHelper.ApplicationVersion.GetAssemblyVersion()); + nLogConfiguration.Variables.Add("applicationVersion", + ApplicationHelper.ApplicationVersion.GetAssemblyVersion()); nLogConfiguration.AddRule(NLog.LogLevel.Trace, NLog.LogLevel.Fatal, consoleTarget); nLogConfiguration.AddRule(NLog.LogLevel.Trace, NLog.LogLevel.Fatal, databaseTarget); @@ -33,32 +43,26 @@ public static ILoggingBuilder ConfigureLoggingServices(ILoggingBuilder loggingBu nLogConfiguration.AddTarget(databaseTarget); nLogConfiguration.AddTarget(mailTarget); - var nLogOptions = new NLogAspNetCoreOptions - { - RegisterHttpContextAccessor = true, - IgnoreEmptyEventId = true, - IncludeScopes = true, - ShutdownOnDispose = true - }; - - var logFactory = NLogBuilder.ConfigureNLog(nLogConfiguration); - logFactory.AutoShutdown = false; - - var nLogConfig = logFactory.Configuration; - loggingBuilder.AddNLog(nLogConfig, nLogOptions); - return loggingBuilder; } - private static MailTarget AddMailTarget(IConfiguration configuration) + private static MailTarget AddMailTarget(IConfiguration configuration, + IEmailConfigurationProvider emailConfigurationProvider) { - var emailConfiguration = GetEmailConfiguration(configuration); + var emailConfiguration = emailConfigurationProvider.GetEmailConfiguration(configuration); + if (emailConfiguration == null) + { + throw new InvalidOperationException("EmailConfiguration cannot be null"); + } + var mailTarget = new MailTarget { Name = "Mail", Html = false, SmtpServer = emailConfiguration.Hostname, - SmtpAuthentication = emailConfiguration.AuthenticationRequired ? SmtpAuthenticationMode.Basic : SmtpAuthenticationMode.None, + SmtpAuthentication = emailConfiguration.AuthenticationRequired + ? SmtpAuthenticationMode.Basic + : SmtpAuthenticationMode.None, SmtpUserName = emailConfiguration.Username, SmtpPort = emailConfiguration.Port, SmtpPassword = emailConfiguration.Password, @@ -82,22 +86,27 @@ private static JsonLayout GetExceptionLayout() { Attributes = { - new JsonAttribute("type", "${exception:format=:innerFormat=Type:MaxInnerExceptionLevel=1:InnerExceptionSeparator=}"), - new JsonAttribute("message", "${exception:format=:innerFormat=Message:MaxInnerExceptionLevel=1:InnerExceptionSeparator=}"), - new JsonAttribute("stacktrace", "${exception:format=:innerFormat=StackTrace:MaxInnerExceptionLevel=1:InnerExceptionSeparator=}") + new JsonAttribute("type", + "${exception:format=:innerFormat=Type:MaxInnerExceptionLevel=1:InnerExceptionSeparator=}"), + new JsonAttribute("message", + "${exception:format=:innerFormat=Message:MaxInnerExceptionLevel=1:InnerExceptionSeparator=}"), + new JsonAttribute("stacktrace", + "${exception:format=:innerFormat=StackTrace:MaxInnerExceptionLevel=1:InnerExceptionSeparator=}") }, RenderEmptyObject = false }, false)); return exceptionLayout; } - private static Email GetEmailConfiguration(IConfiguration configuration) + private static Email? GetEmailConfiguration(IConfiguration configuration) { - using (var sqlConnection = new SqlConnection(configuration.GetConnectionString(ConnectionStrings.GpConnectAnalytics))) - { - var result = sqlConnection.Query("[Configuration].[GetEmailConfiguration]", commandType: CommandType.StoredProcedure); - return result.FirstOrDefault(); - } + using var sqlConnection = + new SqlConnection(configuration.GetConnectionString(ConnectionStrings.GpConnectAnalytics)); + + IEnumerable result = sqlConnection.Query("[Configuration].[GetEmailConfiguration]", + commandType: CommandType.StoredProcedure); + + return result.FirstOrDefault(); } private static DatabaseTarget AddDatabaseTarget(IConfiguration configuration) @@ -173,4 +182,4 @@ private static ConsoleTarget AddConsoleTarget() return consoleTarget; } } -} +} \ No newline at end of file diff --git a/source/Functions/Configuration/Infrastructure/Mapping/MappingExtensions.cs b/source/Functions/Configuration/Infrastructure/Mapping/MappingExtensions.cs new file mode 100644 index 0000000..b243854 --- /dev/null +++ b/source/Functions/Configuration/Infrastructure/Mapping/MappingExtensions.cs @@ -0,0 +1,13 @@ +using Core.Mapping; +using Dapper.FluentMap; + +namespace Functions.Configuration.Infrastructure.Mapping +{ + public static class MappingExtensions + { + public static void ConfigureMappingServices() + { + FluentMapper.Initialize(config => { config.AddMap(new SplunkInstanceMap()); }); + } + } +} \ No newline at end of file diff --git a/source/gpconnect-analytics.Functions/Dockerfile b/source/Functions/Dockerfile similarity index 100% rename from source/gpconnect-analytics.Functions/Dockerfile rename to source/Functions/Dockerfile diff --git a/source/Functions/ExecuteImportByTrigger.cs b/source/Functions/ExecuteImportByTrigger.cs new file mode 100644 index 0000000..3eb66a3 --- /dev/null +++ b/source/Functions/ExecuteImportByTrigger.cs @@ -0,0 +1,16 @@ +using Core.DTOs.Response.Queue; +using Functions.Services.Interfaces; +using Microsoft.Azure.Functions.Worker; +using Microsoft.Extensions.Logging; + +namespace Functions +{ + public class ExecuteImportByTrigger(IImportService importService) + { + [Function("ExecuteImportByTrigger")] + public async Task Run([QueueTrigger("%QueueName%")] Message queueItem, ILogger log) + { + await importService.InstallData(queueItem); + } + } +} \ No newline at end of file diff --git a/source/Functions/Functions.csproj b/source/Functions/Functions.csproj new file mode 100644 index 0000000..f476f14 --- /dev/null +++ b/source/Functions/Functions.csproj @@ -0,0 +1,39 @@ + + + net8.0 + V4 + Exe + enable + enable + + + + + + + + + + + + + + + + PreserveNewest + + + PreserveNewest + Never + + + PreserveNewest + + + + + + + + + \ No newline at end of file diff --git a/source/Functions/GetDataFromApiByDateRange.cs b/source/Functions/GetDataFromApiByDateRange.cs new file mode 100644 index 0000000..4699464 --- /dev/null +++ b/source/Functions/GetDataFromApiByDateRange.cs @@ -0,0 +1,85 @@ +using System.Net; +using Core.Helpers; +using Functions.Services.Interfaces; +using Microsoft.Azure.Functions.Worker; +using Microsoft.Azure.Functions.Worker.Http; +using Microsoft.Extensions.Logging; + +namespace Functions +{ + public class GetDataFromApiByDateRange(IBatchService batchService, ILogger log) + { + [Function("GetDataFromApiByDateRangeSspTrans")] + public async Task GetDataFromSspTransByDateRange( + [HttpTrigger(AuthorizationLevel.Function, "GET", Route = null)] + HttpRequestData req) + { + try + { + var startDate = req.Query["StartDate"]; + var endDate = req.Query["EndDate"]; + var rows = await batchService.StartBatchDownloadAsync(FileTypes.ssptrans, startDate, endDate); + + + var response = req.CreateResponse(HttpStatusCode.OK); + await response.WriteStringAsync($"Batch Download successful: {rows} requests processed"); + return response; + } + catch (Exception ex) + { + log.LogError(ex, "Error starting batch download for SSP Trans"); + var response = req.CreateResponse(HttpStatusCode.InternalServerError); + await response.WriteStringAsync("Failed to download - see logs"); + return response; + } + } + + [Function("GetDataFromApiByDateRangeMeshTrans")] + public async Task GetDataFromMeshTransByDateRange( + [HttpTrigger(AuthorizationLevel.Function, "GET", Route = null)] + HttpRequestData req) + { + try + { + var startDate = req.Query["StartDate"]; + var endDate = req.Query["EndDate"]; + var processed = await batchService.StartBatchDownloadAsync(FileTypes.meshtrans, startDate, endDate); + + var response = req.CreateResponse(HttpStatusCode.OK); + await response.WriteStringAsync($"Batch Download successful: {processed} requests processed"); + return response; + } + catch (Exception ex) + { + log.LogError(ex, "Error starting batch download for Mesh Trans"); + var response = req.CreateResponse(HttpStatusCode.InternalServerError); + await response.WriteStringAsync("Failed to download - see logs"); + return response; + } + } + + [Function("GetDataFromApiByDateRangeAsidLookup")] + public async Task GetDataFromAsidLookupByDateRange( + [HttpTrigger(AuthorizationLevel.Function, "GET", Route = null)] + HttpRequestData req) + { + try + { + var startDate = req.Query["StartDate"]; + var endDate = req.Query["EndDate"]; + var processed = await batchService.StartBatchDownloadAsync(FileTypes.asidlookup, startDate, endDate); + + var response = req.CreateResponse(HttpStatusCode.OK); + await response.WriteStringAsync($"Batch Download successful: {processed} requests processed"); + return response; + } + catch (Exception ex) + { + log.LogError(ex, "Error starting batch download for Asid Lookup"); + var response = req.CreateResponse(HttpStatusCode.InternalServerError); + await response.WriteStringAsync("Failed to download - see logs"); + return response; + } + } + } +} \ No newline at end of file diff --git a/source/Functions/GetDataFromApiByTrigger.cs b/source/Functions/GetDataFromApiByTrigger.cs new file mode 100644 index 0000000..c4b214d --- /dev/null +++ b/source/Functions/GetDataFromApiByTrigger.cs @@ -0,0 +1,34 @@ +using Core.Helpers; +using Functions.Services.Interfaces; +using Microsoft.Azure.Functions.Worker; +using Microsoft.Extensions.Logging; + +namespace Functions +{ + public class GetDataFromApiByTrigger(IBatchService batchService, ILogger log) + { + [Function("GetDataFromApiByTriggerAsidLookup")] + public async Task GetDataFromAsidLookup( + [TimerTrigger("%GetDataFromApiByTriggerAsidLookupSchedule%", RunOnStartup = false)] + TimerInfo myTimer) + { + await batchService.StartBatchDownloadForTodayAsync(FileTypes.asidlookup); + } + + [Function("GetDataFromApiByTriggerSspTrans")] + public async Task GetDataFromSspTrans( + [TimerTrigger("%GetDataFromApiByTriggerSspTransSchedule%", RunOnStartup = false)] + TimerInfo myTimer) + { + await batchService.StartBatchDownloadForTodayAsync(FileTypes.ssptrans); + } + + [Function("GetDataFromApiByTriggerMeshTrans")] + public async Task GetDataFromMeshTrans( + [TimerTrigger("%GetDataFromApiByTriggerMeshTransSchedule%", RunOnStartup = false)] + TimerInfo myTimer) + { + await batchService.StartBatchDownloadForTodayAsync(FileTypes.meshtrans); + } + } +} \ No newline at end of file diff --git a/source/Functions/GetDataFromApiManual.cs b/source/Functions/GetDataFromApiManual.cs new file mode 100644 index 0000000..c8c79a0 --- /dev/null +++ b/source/Functions/GetDataFromApiManual.cs @@ -0,0 +1,42 @@ +using System.Net; +using Functions.Services.Interfaces; +using Microsoft.Azure.Functions.Worker; +using Microsoft.Azure.Functions.Worker.Http; +using Microsoft.Extensions.Logging; + +namespace Functions +{ + public class GetDataFromApiManual(IImportService importService, ILogger log) + { + [Function("GetDataFromApiManual")] + public async Task AddDownloadedFile( + [HttpTrigger(AuthorizationLevel.Function, "GET", Route = null)] + HttpRequestData req) + { + var response = req.CreateResponse(); + response.Headers.Add("Content-Type", "application/text"); + try + { + var filePath = req.Query["FilePath"]; + if (string.IsNullOrEmpty(filePath)) + { + response.StatusCode = HttpStatusCode.BadRequest; + await response.WriteStringAsync("Filepath missing"); + return response; + } + + await importService.AddDownloadedFileManually(filePath); + response.StatusCode = HttpStatusCode.OK; + await response.WriteStringAsync("Successfully added files"); + return response; + } + catch (Exception ex) + { + log.LogError(ex, $"Error adding downloaded file: {ex.Message}"); + response.StatusCode = HttpStatusCode.InternalServerError; + await response.WriteStringAsync("Something went wrong - see error logs for more details"); + return response; + } + } + } +} \ No newline at end of file diff --git a/source/Functions/GetDataFromApiToday.cs b/source/Functions/GetDataFromApiToday.cs new file mode 100644 index 0000000..f4b69a4 --- /dev/null +++ b/source/Functions/GetDataFromApiToday.cs @@ -0,0 +1,98 @@ +using System.Net; +using Core.Helpers; +using Functions.Services.Interfaces; +using Microsoft.Azure.Functions.Worker; +using Microsoft.Azure.Functions.Worker.Http; +using Microsoft.Extensions.Logging; + +namespace Functions +{ + public class GetDataFromApiToday(IBatchService batchService, ILogger log) + { + [Function("GetDataFromApiTodaySspTrans")] + public async Task GetDataFromSspTransByDateRange( + [HttpTrigger(AuthorizationLevel.Function, "GET", Route = null)] + HttpRequestData req) + { + var response = req.CreateResponse(); + response.Headers.Add("Content-Type", "application/text"); + + + var affectedCount = 0; + try + { + affectedCount = await batchService.StartBatchDownloadForTodayAsync(FileTypes.ssptrans); + } + catch (Exception ex) + { + log.LogError(ex, "An error occurred during batch download when processing urls"); + response.StatusCode = HttpStatusCode.InternalServerError; + await response.WriteStringAsync( + $"An error occurred whilst processing batch download - see logs for more details"); + + return response; + } + + response.StatusCode = HttpStatusCode.OK; + await response.WriteStringAsync($"Processed {affectedCount} requests"); + return response; + } + + [Function("GetDataFromApiTodayMeshTrans")] + public async Task GetDataFromMeshTransByDateRange( + [HttpTrigger(AuthorizationLevel.Function, "GET", Route = null)] + HttpRequestData req) + { + var response = req.CreateResponse(); + response.Headers.Add("Content-Type", "application/text"); + + + var affectedCount = 0; + try + { + affectedCount = await batchService.StartBatchDownloadForTodayAsync(FileTypes.meshtrans); + } + catch (Exception ex) + { + log.LogError(ex, "An error occurred during batch download when processing urls"); + response.StatusCode = HttpStatusCode.InternalServerError; + await response.WriteStringAsync( + $"An error occurred whilst processing batch download - see logs for more details"); + + return response; + } + + response.StatusCode = HttpStatusCode.OK; + await response.WriteStringAsync($"Processed {affectedCount} requests"); + return response; + } + + [Function("GetDataFromApiTodayAsidLookup")] + public async Task GetDataFromAsidLookupByDateRange( + [HttpTrigger(AuthorizationLevel.Function, "GET", Route = null)] + HttpRequestData req) + { + var response = req.CreateResponse(); + response.Headers.Add("Content-Type", "application/text"); + var affectedCount = 0; + try + { + affectedCount = await batchService.StartBatchDownloadForTodayAsync(FileTypes.asidlookup); + } + catch (Exception ex) + { + log.LogError(ex, "An error occurred during batch download when processing urls"); + response.StatusCode = HttpStatusCode.InternalServerError; + await response.WriteStringAsync( + $"An error occurred whilst processing batch download - see logs for more details"); + + + return response; + } + + response.StatusCode = HttpStatusCode.OK; + await response.WriteStringAsync($"Processed {affectedCount} requests"); + return response; + } + } +} \ No newline at end of file diff --git a/source/Functions/HelperClasses/FilePathHelper.cs b/source/Functions/HelperClasses/FilePathHelper.cs new file mode 100644 index 0000000..810d72a --- /dev/null +++ b/source/Functions/HelperClasses/FilePathHelper.cs @@ -0,0 +1,54 @@ +using System.Text; +using Core; +using Core.DTOs.Response.Configuration; +using Core.DTOs.Response.Splunk; +using Core.Helpers; +using Core.Services.Interfaces; + +namespace Functions.HelperClasses; + +public class FilePathHelper(IConfigurationService configurationService, ITimeProvider timeProvider, Extract extract) +{ + public async Task ConstructFilePath(SplunkInstance splunkInstance, FileType fileType, bool isToday, + bool setDateAsMidnight = false) + { + //TODO: fix this - replace with less convoluted approach to filePath building + + var filePathConstants = await configurationService.GetFilePathConstants(); + var filePathString = new StringBuilder(); + filePathString.Append(fileType.DirectoryName); + filePathString.Append(filePathConstants.PathSeparator); + filePathString.Append(splunkInstance.Source); + filePathString.Append(filePathConstants.PathSeparator); + filePathString.Append(extract.QueryFromDate.ToString(DateFormatConstants.FilePathQueryDateYearMonth)); + filePathString.Append(filePathConstants.PathSeparator); + filePathString.Append(filePathConstants.ProjectNameFilePrefix); + filePathString.Append(filePathConstants.ComponentSeparator); + filePathString.Append(fileType.FileTypeFilePrefix); + filePathString.Append(filePathConstants.ComponentSeparator); + filePathString.Append( + $"{extract.QueryFromDate.ToString(DateFormatConstants.FilePathQueryDate)}T{extract.QueryHour.ToString(DateFormatConstants.FilePathQueryHour)}"); + filePathString.Append(filePathConstants.ComponentSeparator); + filePathString.Append( + $"{extract.QueryToDate.ToString(DateFormatConstants.FilePathQueryDate)}T{extract.QueryHour.ToString(DateFormatConstants.FilePathQueryHour)}"); + filePathString.Append(filePathConstants.ComponentSeparator); + filePathString.Append(splunkInstance.Source); + filePathString.Append(filePathConstants.ComponentSeparator); + + //TODO: is the correct ? seems should be the other way round , or a simpler logic for Today Midnight, Today End of Day, or Right Now. + if (!isToday) + { + filePathString.Append(setDateAsMidnight + ? timeProvider.CurrentDate().ToString(DateFormatConstants.FilePathNowDate) + : timeProvider.UtcDateTime().ToString(DateFormatConstants.FilePathNowDate)); + } + else + { + filePathString.Append(timeProvider.CurrentDate().AddDays(1).AddSeconds(-1) + .ToString(DateFormatConstants.FilePathNowDate)); + } + + filePathString.Append(filePathConstants.FileExtension); + return filePathString.ToString(); + } +} \ No newline at end of file diff --git a/source/Functions/Program.cs b/source/Functions/Program.cs new file mode 100644 index 0000000..fc6366c --- /dev/null +++ b/source/Functions/Program.cs @@ -0,0 +1,54 @@ +using Core; +using Core.Repositories; +using Core.Services.Interfaces; +using Functions; +using Functions.Configuration; +using Functions.Configuration.Infrastructure.HttpClient; +using Functions.Configuration.Infrastructure.Logging; +using Functions.Configuration.Infrastructure.Mapping; +using Functions.Services; +using Functions.Services.Interfaces; +using Microsoft.Data.SqlClient; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; + + +var builder = Host.CreateDefaultBuilder(args) + .ConfigureFunctionsWorkerDefaults() + .ConfigureServices((context, services) => + { + // Configure your services here + MappingExtensions.ConfigureMappingServices(); + services.AddSingleton(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddSingleton(); + services.AddSingleton(); + services.AddScoped(); + + // Configure logging with email configuration provider + services.AddLogging(loggingBuilder => + { + var emailProvider = services.BuildServiceProvider().GetRequiredService(); + LoggingExtensions.ConfigureLoggingServices(loggingBuilder, context.Configuration, emailProvider); + }); + + // Configure HttpClient + services.AddHttpClient("SplunkApiClient", options => + HttpClientExtensions + .ConfigureHttpClient(options)) + .ConfigurePrimaryHttpMessageHandler(() => + HttpClientExtensions + .CreateHttpMessageHandler()); + }); + + +var host = builder.Build(); +host.Run(); \ No newline at end of file diff --git a/source/gpconnect-analytics.Functions/Properties/launchSettings.json b/source/Functions/Properties/launchSettings.json similarity index 100% rename from source/gpconnect-analytics.Functions/Properties/launchSettings.json rename to source/Functions/Properties/launchSettings.json diff --git a/source/Functions/PurgeErrorLogByTrigger.cs b/source/Functions/PurgeErrorLogByTrigger.cs new file mode 100644 index 0000000..51e401e --- /dev/null +++ b/source/Functions/PurgeErrorLogByTrigger.cs @@ -0,0 +1,16 @@ +using Functions.Services.Interfaces; +using Microsoft.Azure.Functions.Worker; + +namespace Functions +{ + public class PurgeErrorLogByTrigger(ILoggingService loggingService) + { + [Function("PurgeErrorLogByTrigger")] + public async Task PurgeErrorLog( + [TimerTrigger("%PurgeErrorLogByTriggerSchedule%", RunOnStartup = false)] + TimerInfo myTimer) + { + await loggingService.PurgeErrorLog(); + } + } +} \ No newline at end of file diff --git a/source/Functions/Services/BatchService.cs b/source/Functions/Services/BatchService.cs new file mode 100644 index 0000000..3b2d526 --- /dev/null +++ b/source/Functions/Services/BatchService.cs @@ -0,0 +1,146 @@ +using System.Web; +using Core.DTOs.Request; +using Core.DTOs.Response.Configuration; +using Core.Helpers; +using Core.Services.Interfaces; +using Dapper; +using Functions.Services.Interfaces; +using Microsoft.Extensions.Logging; + +namespace Functions.Services +{ + public class BatchService( + IConfigurationService configurationService, + ISplunkService splunkService, + ILogger logger, + IDataService dataService) + : IBatchService + { + private SplunkClient _splunkClient; + + public async Task StartBatchDownloadForTodayAsync(FileTypes fileTypes) + { + var dateInScope = DateTime.Today.AddDays(1); + var fileType = await configurationService.GetFileType(fileTypes); + var uriList = + await GetBatchDownloadUriList(fileType, DateTimeHelper.EachDay(dateInScope, dateInScope).ToList()); + + await RemovePreviousDownloads(fileType, dateInScope, dateInScope); + + await ProcessUrls(fileType, uriList, true); + return uriList.Count; + } + + public async Task StartBatchDownloadAsync(FileTypes fileTypes, string? startDate, string? endDate) + { + if (string.IsNullOrWhiteSpace(startDate) || string.IsNullOrWhiteSpace(endDate)) + { + logger.LogError("Start and end dates are required for batch download"); + throw new ArgumentException("Start and end dates are required for batch download"); + } + + var start = DateTime.TryParse(startDate, out DateTime parsedStart) + ? parsedStart + : DateTime.Today; + var end = DateTime.TryParse(endDate, out DateTime parsedEnd) + ? parsedEnd + : DateTime.Today; + + if (parsedEnd >= parsedStart) + { + var fileType = await configurationService.GetFileType(fileTypes); + var uriList = + await GetBatchDownloadUriList(fileType, DateTimeHelper.EachDay(start, end).ToList()); + + await RemovePreviousDownloads(fileType, start, end); + + try + { + await ProcessUrls(fileType, uriList, false); + return uriList.Count; + } + catch (Exception ex) + { + logger.LogError(ex, "An error occurred during batch download when processing urls"); + throw; + } + } + + logger.LogError("Start date cannot be later than end date"); + throw new ArgumentException("Start date cannot be later than end date"); + } + + private async Task ProcessUrls(FileType fileType, List uriList, bool isToday) + { + var downloadTasks = new List(); + + // Create and start all download tasks + for (var i = 0; i < uriList.Count; i++) + { + var requestUri = uriList[i]; + downloadTasks.Add(splunkService.ExecuteBatchDownloadFromSplunk(fileType, requestUri, isToday)); + } + + // Wait for tasks to complete + while (downloadTasks.Count > 0) + { + var finishedTask = await Task.WhenAny(downloadTasks); + downloadTasks.Remove(finishedTask); + } + } + + public async Task> GetBatchDownloadUriList(FileType fileType, List dateTimeList) + { + var uriList = new List(); + _splunkClient = await configurationService.GetSplunkClientConfiguration(); + + foreach (var dateTime in dateTimeList) + { + var earliestDate = dateTime.AddDays(-2); + var latestDate = dateTime.AddDays(-1); + + for (var i = 0; i < 24; i++) + { + var splunkQuery = fileType.SplunkQuery; + var hour = TimeSpan.Zero.Add(TimeSpan.FromHours(i)); + + splunkQuery = splunkQuery.Replace("{earliest}", + earliestDate.ToString(DateFormatConstants.SplunkQueryDate)); + splunkQuery = splunkQuery.Replace("{latest}", + latestDate.ToString(DateFormatConstants.SplunkQueryDate)); + splunkQuery = splunkQuery.Replace("{hour}", + hour.ToString(DateFormatConstants.SplunkQueryHour)); + + var uriBuilder = new UriBuilder + { + Scheme = Uri.UriSchemeHttps, + Host = _splunkClient.HostName, + Port = _splunkClient.HostPort, + Path = _splunkClient.BaseUrl, + Query = string.Format(_splunkClient.QueryParameters, HttpUtility.UrlEncode(splunkQuery)) + }; + + uriList.Add(new UriRequest() + { + Request = uriBuilder.Uri, + EarliestDate = earliestDate, + LatestDate = latestDate, + Hour = hour + }); + } + } + + return uriList; + } + + public async Task RemovePreviousDownloads(FileType fileType, DateTime startDate, DateTime endDate) + { + var procedureName = "Import.RemovePreviousDownload"; + var parameters = new DynamicParameters(); + parameters.Add("@FileTypeId", fileType.FileTypeId); + parameters.Add("@StartDate", startDate.AddDays(-2)); + parameters.Add("@EndDate", endDate.AddDays(-1)); + await dataService.ExecuteStoredProcedure(procedureName, parameters); + } + } +} \ No newline at end of file diff --git a/source/gpconnect-analytics.DAL/BlobService.cs b/source/Functions/Services/BlobService.cs similarity index 56% rename from source/gpconnect-analytics.DAL/BlobService.cs rename to source/Functions/Services/BlobService.cs index 9ffb709..cec51fe 100644 --- a/source/gpconnect-analytics.DAL/BlobService.cs +++ b/source/Functions/Services/BlobService.cs @@ -1,49 +1,51 @@ -using Azure; +using System.Text; +using System.Text.Json; +using Azure; using Azure.Storage.Blobs; using Azure.Storage.Blobs.Models; using Azure.Storage.Queues; -using gpconnect_analytics.DAL.Interfaces; -using gpconnect_analytics.DTO.Response.Configuration; -using gpconnect_analytics.DTO.Response.Splunk; -using gpconnect_analytics.Helpers; +using Core.DTOs.Response.Configuration; +using Core.DTOs.Response.Queue; +using Core.DTOs.Response.Splunk; +using Core.Services.Interfaces; +using Functions.Services.Interfaces; using Microsoft.Extensions.Logging; -using Newtonsoft.Json; -using System; -using System.Threading.Tasks; -namespace gpconnect_analytics.DAL +namespace Functions.Services { public class BlobService : IBlobService { private readonly ILogger _logger; - private readonly IConfigurationService _configurationService; private readonly BlobStorage _blobStorageConfiguration; private readonly QueueClient _queueClient; private readonly BlobServiceClient _blobServiceClient; - public BlobService(IConfigurationService configurationService, ILogger logger) + public BlobService(IConfigurationService configurationService, ILogger logger, + QueueClient? queueClient) { _logger = logger; - _configurationService = configurationService; - _blobStorageConfiguration = _configurationService.GetBlobStorageConfiguration().Result; + _blobStorageConfiguration = configurationService.GetBlobStorageConfiguration().Result; _blobServiceClient = new BlobServiceClient(_blobStorageConfiguration.ConnectionString); - _queueClient = new QueueClient(_blobStorageConfiguration.ConnectionString, _blobStorageConfiguration.QueueName); + _queueClient = queueClient ?? new QueueClient(_blobStorageConfiguration.ConnectionString, + _blobStorageConfiguration.QueueName); } - public async Task AddObjectToBlob(ExtractResponse extractResponse) + public async Task AddObjectToBlob(ExtractResponse extractResponse) { _logger.LogInformation($"Adding object to blob storage", extractResponse); try { - var containerClient = _blobServiceClient.GetBlobContainerClient(_blobStorageConfiguration.ContainerName); - if (await containerClient.ExistsAsync()) - { - var blobClient = containerClient.GetBlobClient(extractResponse.FilePath); - var uploadedBlob = await blobClient.UploadAsync(extractResponse.ExtractResponseStream, overwrite: true); - return uploadedBlob; - } - return null; + var containerClient = + _blobServiceClient.GetBlobContainerClient(_blobStorageConfiguration.ContainerName); + + if (!await containerClient.ExistsAsync()) return null; + + var blobClient = containerClient.GetBlobClient(extractResponse.FilePath); + var response = + await blobClient.UploadAsync(extractResponse.ExtractResponseStream, overwrite: true); + + return response; } catch (RequestFailedException requestFailedException) { @@ -57,22 +59,23 @@ public async Task AddObjectToBlob(ExtractResponse extractRespon } } - public async Task AddMessageToBlobQueue(int fileAddedCount, int fileTypeId, string blobName, bool overrideEntry = false) + public async Task AddMessageToBlobQueue(int fileAddedCount, int fileTypeId, string blobName, + bool overrideEntry = false) { try { if ((await _queueClient.ExistsAsync()) && fileAddedCount == 1) { - var message = new DTO.Response.Queue.Message + var message = new Message { FileTypeId = fileTypeId, BlobName = blobName, Override = overrideEntry }; - var messageText = JsonConvert.SerializeObject(message); + var messageText = JsonSerializer.Serialize(message); _logger.LogInformation($"Adding message to blob queue", message); - await _queueClient.SendMessageAsync(messageText.StringToBase64()); + await _queueClient.SendMessageAsync(Convert.ToBase64String(Encoding.UTF8.GetBytes(messageText))); } } catch (RequestFailedException requestFailedException) @@ -87,4 +90,4 @@ public async Task AddMessageToBlobQueue(int fileAddedCount, int fileTypeId, stri } } } -} +} \ No newline at end of file diff --git a/source/Functions/Services/ConfigurationService.cs b/source/Functions/Services/ConfigurationService.cs new file mode 100644 index 0000000..76dfa60 --- /dev/null +++ b/source/Functions/Services/ConfigurationService.cs @@ -0,0 +1,61 @@ +using Core.DTOs.Response.Configuration; +using Core.Helpers; +using Core.Services.Interfaces; +using Microsoft.Extensions.Logging; + +namespace Functions.Services +{ + public class ConfigurationService( + IDataService dataService, + ILogger logger) + : IConfigurationService + { + public async Task GetBlobStorageConfiguration() + { + var result = + await dataService.ExecuteQueryStoredProcedure( + "[Configuration].[GetBlobStorageConfiguration]"); + logger.LogInformation("Loading blob storage configuration", result.FirstOrDefault()); + return result.FirstOrDefault(); + } + + public async Task GetFilePathConstants() + { + var result = + await dataService.ExecuteQueryStoredProcedure( + "[Configuration].[GetFilePathConstants]"); + logger.LogInformation("Loading file path constants", result.FirstOrDefault()); + return result.FirstOrDefault(); + } + + public async Task> GetFileTypes() + { + var result = await dataService.ExecuteQueryStoredProcedure("[Configuration].[GetFileTypes]"); + logger.LogInformation("Loading file types", result); + return result; + } + + public async Task GetFileType(FileTypes fileTypes) + { + var result = await dataService.ExecuteQueryStoredProcedure("[Configuration].[GetFileTypes]"); + return result.FirstOrDefault(ft => ft.FileTypeFilePrefix == fileTypes.ToString()); + } + + public async Task GetSplunkClientConfiguration() + { + var result = + await dataService.ExecuteQueryStoredProcedure( + "[Configuration].[GetSplunkClientConfiguration]"); + logger.LogInformation("Loading splunk client configuration", result.FirstOrDefault()); + return result.FirstOrDefault(); + } + + public async Task GetSplunkInstance(SplunkInstances splunkInstance) + { + var result = + await dataService.ExecuteQueryStoredProcedure("[Configuration].[GetSplunkInstances]"); + logger.LogInformation("Loading splunk instance", result); + return result.FirstOrDefault(x => x.Source == splunkInstance.ToString()); + } + } +} \ No newline at end of file diff --git a/source/Functions/Services/CoreConfigurationService.cs b/source/Functions/Services/CoreConfigurationService.cs new file mode 100644 index 0000000..9790614 --- /dev/null +++ b/source/Functions/Services/CoreConfigurationService.cs @@ -0,0 +1,14 @@ +using Core.Services.Interfaces; +using Microsoft.Extensions.Configuration; + +namespace Functions.Services +{ + public class CoreConfigurationService(IConfiguration configuration) : ICoreConfigurationService + { + public string GetConnectionString(string name) + { + var connectionString = configuration.GetConnectionString(name); + return connectionString ?? throw new ArgumentException("No connection string with given name"); + } + } +} \ No newline at end of file diff --git a/source/Functions/Services/DataService.cs b/source/Functions/Services/DataService.cs new file mode 100644 index 0000000..463b4da --- /dev/null +++ b/source/Functions/Services/DataService.cs @@ -0,0 +1,113 @@ +using Core; +using Core.Helpers; +using Core.Repositories; +using Core.Services.Interfaces; +using Dapper; +using Microsoft.Data.SqlClient; +using Microsoft.Extensions.Logging; + +namespace Functions.Services +{ + public class DataService( + ILogger logger, + ICoreConfigurationService coreConfigurationService, + IDapperWrapper dapper, + IConnectionFactory connectionFactory) + : IDataService + { + private readonly string _connectionString = + coreConfigurationService.GetConnectionString(ConnectionStrings.GpConnectAnalytics); + + public async Task ExecuteRawUpsertSqlAsync(string sqlCommand, object parameters) + { + try + { + await using var sqlConnection = connectionFactory.CreateConnection(_connectionString); + await sqlConnection.OpenAsync(); + logger.LogInformation($"Executing raw SQL command"); + var rowsAffected = await dapper.ExecuteAsync(sqlConnection, sqlCommand, parameters); + return rowsAffected; + } + catch (Exception ex) + { + logger.LogError(ex, $"An error has occurred while executing the raw SQL command: {sqlCommand}"); + throw; + } + } + + public async Task> ExecuteQueryStoredProcedure(string procedureName, DynamicParameters parameters) + where T : class + { + await using var sqlConnection = connectionFactory.CreateConnection(_connectionString); + try + { + if (sqlConnection is SqlConnection connection) + { + connection.InfoMessage += SqlConnection_InfoMessage; + } + + logger.LogInformation($"Executing stored procedure {procedureName}", parameters); + + var results = await dapper.QueryStoredProcedureAsync(sqlConnection, procedureName, parameters, 0); + return results.AsList(); + } + catch (Exception exc) + { + logger.LogError(exc, $"An error has occurred while attempting to execute the function {procedureName}"); + throw; + } + } + + + public async Task ExecuteStoredProcedureWithOutputParameters(string procedureName, + DynamicParameters parameters) + { + await using var sqlConnection = connectionFactory.CreateConnection(_connectionString); + try + { + if (sqlConnection is SqlConnection connection) + { + connection.InfoMessage += SqlConnection_InfoMessage; + } + + logger.LogInformation($"Executing stored procedure {procedureName}", parameters); + await dapper.ExecuteStoredProcedureAsync(sqlConnection, procedureName, parameters, + 0); + return parameters; + } + catch (Exception exc) + { + logger?.LogError(exc, + $"An error has occurred while attempting to execute the function {procedureName}"); + throw; + } + } + + public async Task ExecuteStoredProcedure(string procedureName, DynamicParameters parameters) + { + await using var sqlConnection = connectionFactory.CreateConnection(_connectionString); + try + { + if (sqlConnection is SqlConnection connection) + { + connection.InfoMessage += SqlConnection_InfoMessage; + } + + logger.LogInformation($"Executing stored procedure {procedureName}", parameters); + var result = await dapper.ExecuteAsync(sqlConnection, procedureName, parameters); + return result; + } + catch (Exception exc) + { + logger?.LogError(exc, + $"An error has occurred while attempting to execute the function {procedureName}"); + throw; + } + } + + private void SqlConnection_InfoMessage(object sender, SqlInfoMessageEventArgs e) + { + logger?.LogInformation(e.Message); + } + } +} \ No newline at end of file diff --git a/source/Functions/Services/FileService.cs b/source/Functions/Services/FileService.cs new file mode 100644 index 0000000..f764463 --- /dev/null +++ b/source/Functions/Services/FileService.cs @@ -0,0 +1,19 @@ +using Core.Services.Interfaces; +using Dapper; +using Functions.Services.Interfaces; + +namespace Functions.Services; + +public class FileService(IDataService dataService) : IFileService +{ + public async Task ApiReaderAddFile(int fileTypeId, string filePath, bool overrideFile) + { + const string procedureName = "ApiReader.AddFile"; + var parameters = new DynamicParameters(); + parameters.Add("@FileTypeId", fileTypeId); + parameters.Add("@FilePath", filePath); + parameters.Add("@Override", overrideFile); + var result = await dataService.ExecuteStoredProcedure(procedureName, parameters); + return result; + } +} \ No newline at end of file diff --git a/source/Functions/Services/ImportService.cs b/source/Functions/Services/ImportService.cs new file mode 100644 index 0000000..36fa134 --- /dev/null +++ b/source/Functions/Services/ImportService.cs @@ -0,0 +1,84 @@ +using System.Data; +using Core.DTOs.Response.Configuration; +using Core.DTOs.Response.Queue; +using Core.DTOs.Response.Splunk; +using Core.Helpers; +using Core.Services.Interfaces; +using Dapper; +using Functions.Services.Interfaces; +using Microsoft.Extensions.Logging; + +namespace Functions.Services +{ + public class ImportService( + IConfigurationService configurationService, + IDataService dataService, + IBlobService blobService, + ILogger logger, + IFileService fileService) + : IImportService + { + public async Task AddDownloadedFileManually(string filePath) + { + var fileTypeFromPath = filePath.GetFileType(); + + if (fileTypeFromPath == null) + { + throw new ArgumentException("Filepath does not contain vailid file type suffix"); + } + + var fileType = await configurationService.GetFileType((FileTypes)fileTypeFromPath); + var fileAddedCount = + await fileService.ApiReaderAddFile(fileType.FileTypeId, filePath, true); + + await blobService.AddMessageToBlobQueue(fileAddedCount, fileType.FileTypeId, filePath, + true); + } + + public async Task AddObjectFileMessage(FileType fileType, ExtractResponse extractResponse) + { + if (extractResponse.ExtractResponseMessage.StatusCode == System.Net.HttpStatusCode.OK) + { + var uploadedBlob = await blobService.AddObjectToBlob(extractResponse); + if (uploadedBlob != null) + { + var fileAddedCount = + await fileService.ApiReaderAddFile(fileType.FileTypeId, extractResponse.FilePath, true); + + await blobService.AddMessageToBlobQueue(fileAddedCount, fileType.FileTypeId, + extractResponse.FilePath, + true); + } + } + else + { + logger?.LogWarning(extractResponse?.ExtractResponseMessage.ToString()); + } + } + + + public async Task InstallData(Message queueItem) + { + var moreFilesToInstall = true; + const string procedureName = "Import.InstallNextFile"; + var parameters = new DynamicParameters(); + parameters.Add("@FileTypeId", queueItem.FileTypeId); + if (queueItem.Override) + { + parameters.Add("@Override", queueItem.Override, dbType: DbType.Boolean, + direction: ParameterDirection.Input); + } + + parameters.Add("@MoreFilesToInstall", dbType: DbType.Boolean, direction: ParameterDirection.Output); + + while (moreFilesToInstall) + { + logger.LogInformation($"Installing file into database", parameters); + var result = await dataService.ExecuteStoredProcedureWithOutputParameters(procedureName, parameters); + + moreFilesToInstall = result.Get("@MoreFilesToInstall"); + logger.LogInformation($"More files to install? {moreFilesToInstall}"); + } + } + } +} \ No newline at end of file diff --git a/source/Functions/Services/Interfaces/IBatchService.cs b/source/Functions/Services/Interfaces/IBatchService.cs new file mode 100644 index 0000000..c65b60f --- /dev/null +++ b/source/Functions/Services/Interfaces/IBatchService.cs @@ -0,0 +1,14 @@ +using Core.DTOs.Request; +using Core.DTOs.Response.Configuration; +using Core.Helpers; + +namespace Functions.Services.Interfaces +{ + public interface IBatchService + { + Task> GetBatchDownloadUriList(FileType fileType, List dateTimeList); + Task RemovePreviousDownloads(FileType fileType, DateTime startDate, DateTime endDate); + Task StartBatchDownloadForTodayAsync(FileTypes fileTypes); + Task StartBatchDownloadAsync(FileTypes fileTypes, string? startDate, string? endDate); + } +} \ No newline at end of file diff --git a/source/Functions/Services/Interfaces/IBlobService.cs b/source/Functions/Services/Interfaces/IBlobService.cs new file mode 100644 index 0000000..7b6817c --- /dev/null +++ b/source/Functions/Services/Interfaces/IBlobService.cs @@ -0,0 +1,11 @@ +using Azure.Storage.Blobs.Models; +using Core.DTOs.Response.Splunk; + +namespace Functions.Services.Interfaces +{ + public interface IBlobService + { + Task AddMessageToBlobQueue(int fileAddedCount, int fileTypeId, string blobName, bool overrideEntry = false); + Task AddObjectToBlob(ExtractResponse extractResponse); + } +} \ No newline at end of file diff --git a/source/Functions/Services/Interfaces/IFileService.cs b/source/Functions/Services/Interfaces/IFileService.cs new file mode 100644 index 0000000..c569467 --- /dev/null +++ b/source/Functions/Services/Interfaces/IFileService.cs @@ -0,0 +1,6 @@ +namespace Functions.Services.Interfaces; + +public interface IFileService +{ + Task ApiReaderAddFile(int fileTypeID, string filePath, bool overrideFile); +} \ No newline at end of file diff --git a/source/Functions/Services/Interfaces/IImportService.cs b/source/Functions/Services/Interfaces/IImportService.cs new file mode 100644 index 0000000..3594bef --- /dev/null +++ b/source/Functions/Services/Interfaces/IImportService.cs @@ -0,0 +1,13 @@ +using Core.DTOs.Response.Configuration; +using Core.DTOs.Response.Queue; +using Core.DTOs.Response.Splunk; + +namespace Functions.Services.Interfaces +{ + public interface IImportService + { + Task InstallData(Message message); + Task AddDownloadedFileManually(string filePath); + Task AddObjectFileMessage(FileType fileType, ExtractResponse extractResponse); + } +} \ No newline at end of file diff --git a/source/gpconnect-analytics.DAL/Interfaces/ILoggingService.cs b/source/Functions/Services/Interfaces/ILoggingService.cs similarity index 50% rename from source/gpconnect-analytics.DAL/Interfaces/ILoggingService.cs rename to source/Functions/Services/Interfaces/ILoggingService.cs index 545973d..728dac2 100644 --- a/source/gpconnect-analytics.DAL/Interfaces/ILoggingService.cs +++ b/source/Functions/Services/Interfaces/ILoggingService.cs @@ -1,9 +1,7 @@ -using System.Threading.Tasks; - -namespace gpconnect_analytics.DAL.Interfaces +namespace Functions.Services.Interfaces { public interface ILoggingService { Task PurgeErrorLog(); } -} +} \ No newline at end of file diff --git a/source/Functions/Services/Interfaces/ISplunkService.cs b/source/Functions/Services/Interfaces/ISplunkService.cs new file mode 100644 index 0000000..550ba11 --- /dev/null +++ b/source/Functions/Services/Interfaces/ISplunkService.cs @@ -0,0 +1,12 @@ +using Core.DTOs.Request; +using Core.DTOs.Response.Configuration; +using Core.DTOs.Response.Splunk; + +namespace Functions.Services.Interfaces +{ + public interface ISplunkService + { + Task DownloadCSVDateRangeAsync(FileType fileType, UriRequest uriRequest, bool isToday); + Task ExecuteBatchDownloadFromSplunk(FileType fileType, UriRequest uriRequest, bool isToday); + } +} \ No newline at end of file diff --git a/source/gpconnect-analytics.DAL/LoggingService.cs b/source/Functions/Services/LoggingService.cs similarity index 79% rename from source/gpconnect-analytics.DAL/LoggingService.cs rename to source/Functions/Services/LoggingService.cs index 52c7d5b..a6c54c8 100644 --- a/source/gpconnect-analytics.DAL/LoggingService.cs +++ b/source/Functions/Services/LoggingService.cs @@ -1,7 +1,7 @@ -using gpconnect_analytics.DAL.Interfaces; -using System.Threading.Tasks; +using Core.Services.Interfaces; +using Functions.Services.Interfaces; -namespace gpconnect_analytics.DAL +namespace Functions.Services { public class LoggingService : ILoggingService { @@ -18,4 +18,4 @@ public async Task PurgeErrorLog() await _dataService.ExecuteStoredProcedure(procedureName); } } -} +} \ No newline at end of file diff --git a/source/gpconnect-analytics.DAL/SplunkService.cs b/source/Functions/Services/SplunkService.cs similarity index 55% rename from source/gpconnect-analytics.DAL/SplunkService.cs rename to source/Functions/Services/SplunkService.cs index 14fd682..82aa31e 100644 --- a/source/gpconnect-analytics.DAL/SplunkService.cs +++ b/source/Functions/Services/SplunkService.cs @@ -1,47 +1,57 @@ -using gpconnect_analytics.DAL.Interfaces; -using gpconnect_analytics.DTO.Request; -using gpconnect_analytics.DTO.Response.Configuration; -using gpconnect_analytics.DTO.Response.Splunk; -using Microsoft.Extensions.Logging; -using System; -using System.IdentityModel.Tokens.Jwt; -using System.Net.Http; +using System.IdentityModel.Tokens.Jwt; using System.Net.Http.Headers; using System.Text; -using System.Threading.Tasks; +using Core; +using Core.DTOs.Request; +using Core.DTOs.Response.Configuration; +using Core.DTOs.Response.Splunk; +using Core.Helpers; +using Core.Services.Interfaces; +using Functions.HelperClasses; +using Functions.Services.Interfaces; +using Microsoft.Extensions.Logging; -namespace gpconnect_analytics.DAL +namespace Functions.Services { public class SplunkService : ISplunkService { - private readonly IConfigurationService _configurationService; - private readonly IHttpClientFactory _httpClientFactory; - private readonly ILogger _logger; private SplunkClient _splunkClient; private FilePathConstants _filePathConstants; private Extract _extract; - public SplunkService(IConfigurationService configurationService, IHttpClientFactory httpClientFactory, ILogger logger) + private FilePathHelper filePathHelper; + private readonly IConfigurationService _configurationService; + private readonly IHttpClientFactory _httpClientFactory; + private readonly IImportService _importService; + private readonly ILogger _logger; + + public SplunkService(IConfigurationService configurationService, + IHttpClientFactory httpClientFactory, + IImportService importService, + ILogger logger, + ITimeProvider timeProvider) { + _extract = new(); _configurationService = configurationService; - _logger = logger; _httpClientFactory = httpClientFactory; - _extract = new Extract(); + _importService = importService; + _logger = logger; + filePathHelper = new FilePathHelper(configurationService, timeProvider, _extract); } - public async Task DownloadCSVDateRangeAsync(FileType fileType, UriRequest uriRequest, bool isToday) + public async Task DownloadCSVDateRangeAsync(FileType fileType, UriRequest uriRequest, + bool isToday) { try { - _filePathConstants = await _configurationService.GetFilePathConstants(); - var splunkInstance = await _configurationService.GetSplunkInstance(Helpers.SplunkInstances.cloud); + var splunkInstance = await _configurationService.GetSplunkInstance(SplunkInstances.cloud); _extract.Override = true; _extract.QueryFromDate = uriRequest.EarliestDate; _extract.QueryToDate = uriRequest.LatestDate; _extract.QueryHour = uriRequest.Hour; - var filePath = ConstructFilePath(splunkInstance, fileType, isToday, true); + var filePath = await filePathHelper.ConstructFilePath(splunkInstance, fileType, isToday, true); var extractResponse = await GetSearchResultFromRequestUri(uriRequest); extractResponse.FilePath = filePath; @@ -59,9 +69,9 @@ public async Task DownloadCSVDateRangeAsync(FileType fileType, _logger.LogError(exc, "An error occurred in trying to execute a GET request"); throw; } - } + } - private async Task GetSearchResultFromRequestUri(UriRequest uriRequest) + public async Task GetSearchResultFromRequestUri(UriRequest uriRequest) { var extractResponseMessage = new ExtractResponse { @@ -72,10 +82,11 @@ private async Task GetSearchResultFromRequestUri(UriRequest uri _splunkClient = await _configurationService.GetSplunkClientConfiguration(); var apiTokenExpiry = HasApiTokenExpired(_splunkClient.ApiToken); - if (!apiTokenExpiry.Item1) + if (!apiTokenExpiry.Expired) { var client = _httpClientFactory.CreateClient("SplunkApiClient"); - client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _splunkClient.ApiToken); + client.DefaultRequestHeaders.Authorization = + new AuthenticationHeaderValue("Bearer", _splunkClient.ApiToken); client.Timeout = new TimeSpan(0, 0, _splunkClient.QueryTimeout); var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, uriRequest.Request); @@ -89,7 +100,8 @@ private async Task GetSearchResultFromRequestUri(UriRequest uri } else { - extractResponseMessage.ExtractResponseMessage.ReasonPhrase = $"The authentication token has expired because it is valid up to {apiTokenExpiry.Item2}"; + extractResponseMessage.ExtractResponseMessage.ReasonPhrase = + "The authentication token has expired"; extractResponseMessage.ExtractResponseMessage.StatusCode = System.Net.HttpStatusCode.Unauthorized; } } @@ -101,46 +113,45 @@ private async Task GetSearchResultFromRequestUri(UriRequest uri catch (Exception exc) { extractResponseMessage.ExtractResponseMessage.ReasonPhrase = exc.Message; - extractResponseMessage.ExtractResponseMessage.StatusCode = System.Net.HttpStatusCode.InternalServerError; + extractResponseMessage.ExtractResponseMessage.StatusCode = + System.Net.HttpStatusCode.InternalServerError; } + return extractResponseMessage; } - private string ConstructFilePath(SplunkInstance splunkInstance, FileType fileType, bool isToday, bool setDateAsMidnight = false) + + public async Task ExecuteBatchDownloadFromSplunk(FileType fileType, UriRequest uriRequest, bool isToday) { - var filePathString = new StringBuilder(); - filePathString.Append(fileType.DirectoryName); - filePathString.Append(_filePathConstants.PathSeparator); - filePathString.Append(splunkInstance.Source); - filePathString.Append(_filePathConstants.PathSeparator); - filePathString.Append(_extract.QueryFromDate.ToString(Helpers.DateFormatConstants.FilePathQueryDateYearMonth)); - filePathString.Append(_filePathConstants.PathSeparator); - filePathString.Append(_filePathConstants.ProjectNameFilePrefix); - filePathString.Append(_filePathConstants.ComponentSeparator); - filePathString.Append(fileType.FileTypeFilePrefix); - filePathString.Append(_filePathConstants.ComponentSeparator); - filePathString.Append($"{_extract.QueryFromDate.ToString(Helpers.DateFormatConstants.FilePathQueryDate)}T{_extract.QueryHour.ToString(Helpers.DateFormatConstants.FilePathQueryHour)}"); - filePathString.Append(_filePathConstants.ComponentSeparator); - filePathString.Append($"{_extract.QueryToDate.ToString(Helpers.DateFormatConstants.FilePathQueryDate)}T{_extract.QueryHour.ToString(Helpers.DateFormatConstants.FilePathQueryHour)}"); - filePathString.Append(_filePathConstants.ComponentSeparator); - filePathString.Append(splunkInstance.Source); - filePathString.Append(_filePathConstants.ComponentSeparator); - if (!isToday) + try { - filePathString.Append(setDateAsMidnight ? DateTime.Today.ToString(Helpers.DateFormatConstants.FilePathNowDate) : DateTime.UtcNow.ToString(Helpers.DateFormatConstants.FilePathNowDate)); + if (FileTypeEnabled(fileType)) + { + var extractResponse = await DownloadCSVDateRangeAsync(fileType, uriRequest, isToday); + await _importService.AddObjectFileMessage(fileType, extractResponse); + } + else + { + _logger?.LogWarning( + $"Filetype {fileType.FileTypeFilePrefix} is not enabled. Please check if this is correct"); + } } - else + catch (Exception exc) { - filePathString.Append(DateTime.Today.AddDays(1).AddSeconds(-1).ToString(Helpers.DateFormatConstants.FilePathNowDate)); + _logger?.LogError(exc, $"An error has occurred while attempting to execute an Azure function"); + throw; } - filePathString.Append(_filePathConstants.FileExtension); - return filePathString.ToString(); } - private (bool, DateTime) HasApiTokenExpired(string apiToken) + private (bool Expired, DateTime ValidTo) HasApiTokenExpired(string apiToken) { var jwtToken = new JwtSecurityToken(apiToken); return (DateTime.UtcNow > jwtToken.ValidTo, jwtToken.ValidTo); } + + internal static bool FileTypeEnabled(FileType fileType) + { + return fileType is { Enabled: true }; + } } -} +} \ No newline at end of file diff --git a/source/Functions/SqlConnectionFactory.cs b/source/Functions/SqlConnectionFactory.cs new file mode 100644 index 0000000..a83f328 --- /dev/null +++ b/source/Functions/SqlConnectionFactory.cs @@ -0,0 +1,13 @@ +using System.Data.Common; +using Core; +using Microsoft.Data.SqlClient; + +namespace Functions; + +public class SqlConnectionFactory : IConnectionFactory +{ + public DbConnection CreateConnection(string connectionString) + { + return new SqlConnection(connectionString); + } +} \ No newline at end of file diff --git a/source/Functions/StoreProviderConsumerData.cs b/source/Functions/StoreProviderConsumerData.cs new file mode 100644 index 0000000..98a6839 --- /dev/null +++ b/source/Functions/StoreProviderConsumerData.cs @@ -0,0 +1,68 @@ +using System.Net; +using System.Text.Json; +using Core.DTOs.Request; +using Core.Repositories; +using Microsoft.Azure.Functions.Worker; +using Microsoft.Azure.Functions.Worker.Http; +using Microsoft.Extensions.Logging; + +namespace Functions +{ + public class StoreProviderConsumerData( + IHierarchyProviderConsumerRepo repository, + ILogger logger) + { + [Function("StoreProviderConsumerData")] + public async Task Run( + [HttpTrigger(AuthorizationLevel.Function, "post", Route = "StoreProviderConsumerData")] + HttpRequestData req) + { + logger.LogInformation("Processing HTTP request."); + + var requestBody = await new StreamReader(req.Body).ReadToEndAsync(); + + if (requestBody.Length == 0) + { + var errorLengthResponse = req.CreateResponse(HttpStatusCode.BadRequest); + errorLengthResponse.Headers.Add("Content-Type", "text/plain; charset=utf-8"); + await errorLengthResponse.WriteStringAsync("Request body length is 0"); + return errorLengthResponse; + } + + List records = null; + try + { + records = JsonSerializer.Deserialize>(requestBody) ?? throw new + InvalidOperationException("Unable to deserialize input"); + } + catch (JsonException ex) + { + logger.LogError("Failed to deserialize request body: {exceptionMessage}", ex.Message); + var serializeErrorResponse = req.CreateResponse(HttpStatusCode.BadRequest); + serializeErrorResponse.Headers.Add("Content-Type", "text/plain; charset=utf-8"); + await serializeErrorResponse.WriteStringAsync("Invalid json input"); + return serializeErrorResponse; + } + + + logger.LogInformation($"Attempting to save {records.Count} items into databases"); + var count = await repository.InsertHierarchyProviderConsumers(records); + + if (count > 0) + { + var errorResponse = req.CreateResponse(HttpStatusCode.OK); + errorResponse.Headers.Add("Content-Type", "text/plain; charset=utf-8"); + await errorResponse.WriteStringAsync("Storing of items successful"); + return errorResponse; + } + + var response = req.CreateResponse(HttpStatusCode.BadRequest); + response.Headers.Add("Content-Type", "text/plain; charset=utf-8"); + + logger.LogInformation($"No items of {records.Count} were saved to the database"); + + await response.WriteStringAsync("Failed to save to the database - see logs for more information"); + return response; + } + } +} \ No newline at end of file diff --git a/source/gpconnect-analytics.Functions/host.json b/source/Functions/host.json similarity index 61% rename from source/gpconnect-analytics.Functions/host.json rename to source/Functions/host.json index c07c3c7..6e338e5 100644 --- a/source/gpconnect-analytics.Functions/host.json +++ b/source/Functions/host.json @@ -1,11 +1,6 @@ { "version": "2.0", "functionTimeout": "12:00:00", - "Values": { - "GetDataFromApiByTriggerAsidLookupSchedule": "0 0 2 1-7 * MON", - "GetDataFromApiByTriggerSspTransSchedule": "0 0 3 * * *", - "GetDataFromApiByTriggerMeshTransSchedule": "0 0 4 * * *" - }, "logging": { "applicationInsights": { "samplingSettings": { diff --git a/source/Functions/nlog.config.xml b/source/Functions/nlog.config.xml new file mode 100644 index 0000000..dcabb8f --- /dev/null +++ b/source/Functions/nlog.config.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/IntegrationTests/DapperTestSetupFixture.cs b/source/IntegrationTests/DapperTestSetupFixture.cs new file mode 100644 index 0000000..089c16e --- /dev/null +++ b/source/IntegrationTests/DapperTestSetupFixture.cs @@ -0,0 +1,74 @@ +using Core.Repositories; +using Core.Services.Interfaces; +using Dapper; +using DotNet.Testcontainers.Builders; +using Microsoft.Data.SqlClient; +using Microsoft.Extensions.Logging.Testing; +using Moq; +using Testcontainers.MsSql; + +namespace IntegrationTests; + +public class DapperTestSetupFixture : IAsyncLifetime +{ + public MsSqlContainer Container; + + + public async Task InitializeAsync() + { + Container = new MsSqlBuilder() + .WithImage("mcr.microsoft.com/mssql/server:2022-latest") + .WithPortBinding(1443, true) + .WithPassword("P@ssw0rd123") + .WithWaitStrategy(Wait.ForUnixContainer().UntilPortIsAvailable(1433)) + .Build(); + + // Create docker container for testing + await Container.StartAsync(); + + var mockCoreConfigurationService = new Mock(); + + // Set up the GetConnectionString method to return container's connection string + mockCoreConfigurationService.Setup(x => x.GetConnectionString(It.IsAny())) + .Returns(Container.GetConnectionString()); + + // Step 1: Create the table + var createTableSql = @" + CREATE TABLE Users ( + Id INT IDENTITY(1,1) PRIMARY KEY, + Name NVARCHAR(100) + )"; + + using var connection = new SqlConnection(Container.GetConnectionString()); + await connection.ExecuteAsync(createTableSql); + + // Step 2: Create the stored procedure (must be executed separately) + var createProcedureSql = @" + CREATE PROCEDURE sp_TestAddUser + @Name NVARCHAR(100) + AS + BEGIN + INSERT INTO Users (Name) VALUES (@Name); + SELECT SCOPE_IDENTITY() AS Id; -- Correct way to return the inserted ID + END; + "; + + await connection.ExecuteAsync(createProcedureSql); + + // Step 3: Add Query SP + var createQuerySql = @" + CREATE PROCEDURE sp_TestGetAllUsers + AS + BEGIN + SELECT * FROM Users; + END; + "; + + await connection.ExecuteAsync(createQuerySql); + } + + public async Task DisposeAsync() + { + await Container.DisposeAsync(); + } +} \ No newline at end of file diff --git a/source/IntegrationTests/DapperWrapperIntegrationTests.cs b/source/IntegrationTests/DapperWrapperIntegrationTests.cs new file mode 100644 index 0000000..9f06828 --- /dev/null +++ b/source/IntegrationTests/DapperWrapperIntegrationTests.cs @@ -0,0 +1,147 @@ +using Bogus; +using Core.Repositories; +using Dapper; +using DotNet.Testcontainers.Builders; +using FluentAssertions; +using Microsoft.Data.SqlClient; +using Testcontainers.MsSql; + +namespace IntegrationTests; + +public class DapperWrapperIntegrationTests(DapperTestSetupFixture fixture) : IClassFixture +{ + private readonly string _connectionString = fixture.Container.GetConnectionString(); + private readonly DapperWrapper _dapperWrapper = new(); + private readonly Faker _faker = new(); + + [Fact] + public async Task ExecuteStoredProcedureAsync_Should_Insert_User() + { + // Arrange + await using var connection = new SqlConnection(_connectionString); + await connection.OpenAsync(); + + var name = _faker.Name.FullName(); + var parameters = new { Name = name }; + + // Act + var result = await _dapperWrapper.ExecuteStoredProcedureAsync(connection, "sp_TestAddUser", parameters); + + // Assert + result.Should().BeGreaterThan(0); + + var users = await connection.QueryAsync("SELECT Name FROM Users WHERE NAME = @name", new { name }); + users.Should().Contain(name); + } + + [Fact] + public async Task ExecuteSqlAsync_Should_Insert_User() + { + // Arrange + await using var connection = new SqlConnection(_connectionString); + await connection.OpenAsync(); + + var name = _faker.Name.FullName(); + var sql = "INSERT INTO Users (Name) VALUES(@name)"; + + // Act + await _dapperWrapper.ExecuteAsync(connection, sql, new { name }); + + // Assert + var users = await connection.QueryAsync("SELECT Name FROM Users WHERE NAME = @name", new { name }); + users.Should().Contain(name); + } + + [Fact] + public async Task QueryStoredProcedureAsync_ShouldReturn_ExpectedQueryResult() + { + // Arrange + await using var connection = new SqlConnection(_connectionString); + await connection.OpenAsync(); + var name = _faker.Name.FullName(); + var parameters = new { name }; + + await InsertUser(name, connection); + + // Act + var result = + await _dapperWrapper.QueryStoredProcedureAsync(connection, "sp_TestGetAllUsers", new { }); + + // Assert + result.Should().Contain(x => x.Name == name); + } + + [Fact] + public async Task QueryAsync_Should_QueryDb() + { + // Arrange + await using var connection = new SqlConnection(_connectionString); + await connection.OpenAsync(); + + var parameters = new { name = _faker.Name.FullName() }; + await InsertUser(parameters.name, connection); + + // Act + var result = + await _dapperWrapper.QueryAsync(connection, "SELECT name FROM USERS WHERE name = @name", + parameters); + + // Assert + result.Should().NotBeNullOrEmpty(); + result.Should().HaveCount(1); + result.First().Should().BeEquivalentTo(new TestUser + { + Name = parameters.name + }); + } + + // ------- ERRORS + + [Fact] + public async Task ExecuteStoredProcedureAsync_Should_Throw_Exception_On_Error() + { + // Arrange + await using var connection = new SqlConnection(_connectionString); + await connection.OpenAsync(); + + var parameters = new { Name = _faker.Name.FullName() }; + + // Act & Assert + _dapperWrapper.Invoking(x => + x.ExecuteStoredProcedureAsync(connection, "sp_NonExistentProcedure", parameters)) + .Should().ThrowAsync() + .WithMessage("Error executing stored procedure: sp_NonExistentProcedure"); + } + + [Fact] + public async Task QueryStoredProcedureAsync_Should_Throw_Exception_On_Error() + { + // Arrange + await using var connection = new SqlConnection(_connectionString); + await connection.OpenAsync(); + + var parameters = new { Name = _faker.Name.FullName() }; + + // Act & Assert + _dapperWrapper.Invoking(x => + x.QueryStoredProcedureAsync(connection, "sp_NonExistentProcedure", parameters)) + .Should().ThrowAsync() + .WithMessage("Error executing stored procedure: sp_NonExistentProcedure"); + } + + #region Helper Methods + + private async Task InsertUser(string name, SqlConnection connection) + { + var sql = "INSERT INTO USERS (NAME) VALUES(@name)"; + await connection.ExecuteAsync(sql, new { name }); + } + + private class TestUser + { + public string Name { get; set; } + public int Id { get; set; } + } + + #endregion +} \ No newline at end of file diff --git a/source/IntegrationTests/EmailConfigurationProviderTests.cs b/source/IntegrationTests/EmailConfigurationProviderTests.cs new file mode 100644 index 0000000..467dcea --- /dev/null +++ b/source/IntegrationTests/EmailConfigurationProviderTests.cs @@ -0,0 +1,131 @@ +using Core.Services.Interfaces; +using Dapper; +using DotNet.Testcontainers.Builders; +using FluentAssertions; +using Functions; +using Functions.Configuration; +using IntegrationTests.TestHelpers; +using Microsoft.Data.SqlClient; +using Moq; +using Testcontainers.MsSql; + +namespace IntegrationTests; + +public class EmailConfigurationProviderTests : IAsyncLifetime +{ + private readonly MsSqlContainer _container = new MsSqlBuilder() + .WithImage("mcr.microsoft.com/mssql/server:2022-latest") + .WithPassword("P@ssw0rd123") + .WithPortBinding(1433, true) + .WithWaitStrategy(Wait.ForUnixContainer().UntilPortIsAvailable(1433)) + .Build(); + + + [Fact] + public void GetEmailConfiguration_ShouldReturnEmailConfiguration() + { + // Arrange + var configuration = ConfigurationHelpers.CreateDefaultConfiguration(_container.GetConnectionString()); + var connectionFactory = new SqlConnectionFactory(); + var emailConfiguration = new EmailConfigurationProvider(connectionFactory); + + // Act + var result = emailConfiguration.GetEmailConfiguration(configuration); + + // Assert + result.Should().NotBeNull(); + result!.SenderAddress.Should().Be("gpconnectappointmentchecker.test@test.net"); + result!.Hostname.Should().Be("fakeHost"); + result!.Port.Should().Be(587); + result!.Encryption.Should().Be("Tls12"); + result!.AuthenticationRequired.Should().Be(true); + result.DefaultSubject.Should().Be("GP Connect Analytics - Error"); + result.RecipientAddress.Should().Be("gpconnectappointmentchecker.test@test.net"); + result.Username.Should().Be("gpconnectappointmentchecker.test@test.net"); + result.Password.Should().Be("fakePassword123!"); + } + + public async Task InitializeAsync() + { + // Create docker container for testing + await _container.StartAsync(); + + var mockCoreConfigurationService = new Mock(); + + // Set up the GetConnectionString method to return container's connection string + mockCoreConfigurationService.Setup(x => x.GetConnectionString(It.IsAny())) + .Returns(_container.GetConnectionString()); + + await using var sqlConnection = new SqlConnection(_container.GetConnectionString()); + await sqlConnection.OpenAsync(); + await sqlConnection.ExecuteAsync("CREATE SCHEMA Configuration"); + + // CREATE EMAIL PROCEDURE + using (var command = new SqlCommand(@" + create procedure Configuration.GetEmailConfiguration as + select + SenderAddress, + Hostname, + Port, + Encryption, + AuthenticationRequired, + Username, + Password, + DefaultSubject, + RecipientAddress + from Configuration.Email;", sqlConnection)) + { + await command.ExecuteNonQueryAsync(); + } + + // CREATE EMAIL TABLE + await sqlConnection.ExecuteAsync(""" + BEGIN + SET ANSI_NULLS ON + SET QUOTED_IDENTIFIER ON + + CREATE TABLE [Configuration].[Email]( + [SingleRowLock] [bit] NOT NULL, + [SenderAddress] [varchar](100) NOT NULL, + [Hostname] [varchar](100) NOT NULL, + [Port] [smallint] NOT NULL, + [Encryption] [varchar](10) NOT NULL, + [AuthenticationRequired] [bit] NOT NULL, + [Username] [varchar](100) NOT NULL, + [Password] [varchar](100) NOT NULL, + [DefaultSubject] [varchar](100) NOT NULL, + [RecipientAddress] [varchar](100) NOT NULL + ) ON [PRIMARY] + END + """); + + // SEED TABLE + await sqlConnection.ExecuteAsync(""" + INSERT INTO [Configuration].[Email]( + SingleRowLock, + SenderAddress, + Hostname, + Port, + Encryption, + AuthenticationRequired, + Username, + Password, + DefaultSubject, + RecipientAddress) + VALUES (1, + 'gpconnectappointmentchecker.test@test.net', + 'fakeHost', + 587, + 'Tls12', + 1, + 'gpconnectappointmentchecker.test@test.net', + 'fakePassword123!', + 'GP Connect Analytics - Error', + 'gpconnectappointmentchecker.test@test.net') + """); + + await sqlConnection.CloseAsync(); + } + + public async Task DisposeAsync() => await _container.DisposeAsync(); +} \ No newline at end of file diff --git a/source/IntegrationTests/HierarchyProviderConsumerRepoTests.cs b/source/IntegrationTests/HierarchyProviderConsumerRepoTests.cs new file mode 100644 index 0000000..0ea8e4f --- /dev/null +++ b/source/IntegrationTests/HierarchyProviderConsumerRepoTests.cs @@ -0,0 +1,119 @@ +using Core; +using Core.DTOs.Request; +using Core.Repositories; +using Core.Services.Interfaces; +using Dapper; +using DotNet.Testcontainers.Builders; +using FluentAssertions; +using Functions; +using Microsoft.Data.SqlClient; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Testing; +using Moq; +using Testcontainers.MsSql; + + +namespace IntegrationTests +{ + public class HierarchyProviderConsumerRepoTests : IClassFixture + { + private readonly string _connectionString; + private readonly HierarchyProviderConsumerRepo _repo; + private readonly FakeLogger _logger = new(); + + + public HierarchyProviderConsumerRepoTests(MsSqlContainerFixture fixture) + { + _connectionString = fixture.Container.GetConnectionString(); + var mockCoreConfigurationService = new Mock(); + + mockCoreConfigurationService.Setup(x => x.GetConnectionString(It.IsAny())) + .Returns(_connectionString); + + _repo = new HierarchyProviderConsumerRepo(mockCoreConfigurationService.Object, new DapperWrapper(), + new SqlConnectionFactory(), _logger); + } + + [Fact] + public async Task InsertHierarchyProviderConsumers_ShouldInsertMultipleRecordsAndVerifyFirstRecord() + { + // Arrange + var providers = new List + { + new OrganisationHierarchyProvider + { + OdsCode = "ABC123", + PracticeName = "Test Practice 1", + RegisteredPatientCount = 1500, + RegionCode = "Region1", + RegionName = "Test Region 1", + Icb22Name = "ICB Name 1", + PcnName = "PCN Name 1", + Appointments13000 = 120 + }, + new OrganisationHierarchyProvider + { + OdsCode = "XYZ456", + PracticeName = "Test Practice 2", + RegisteredPatientCount = 2000, + RegionCode = "Region2", + RegionName = "Test Region 2", + Icb22Name = "ICB Name 2", + PcnName = "PCN Name 2", + Appointments13000 = 220 + } + }; + + // Act + var insertResult = await _repo.InsertHierarchyProviderConsumers(providers); + + // Assert + + insertResult.Should().Be(2); + + await using var connection = new SqlConnection(_connectionString); + await connection.OpenAsync(); + + // Verify record count + const string countQuery = "SELECT COUNT(*) FROM [Data].[HierarchyProviderConsumers]"; + var count = await connection.QuerySingleAsync(countQuery); + count.Should().Be(2); + + // Verify specific record + const string selectQuery = "SELECT * FROM [Data].[HierarchyProviderConsumers] WHERE OdsCode = @OdsCode"; + var result = await connection.QuerySingleAsync(selectQuery, + new { OdsCode = "ABC123" }); + + result.OdsCode.Should().Be("ABC123"); + result.PracticeName.Should().Be("Test Practice 1"); + result.RegisteredPatientCount.Should().Be(1500); + result.RegionCode.Should().Be("Region1"); + result.RegionName.Should().Be("Test Region 1"); + result.Icb22Name.Should().Be("ICB Name 1"); + result.PcnName.Should().Be("PCN Name 1"); + result.Appointments13000.Should().Be(120); + } + + [Fact] + public async Task InsertHierarchyProviderConsumers_ShouldLogError_WhenConnectionFails() + { + // Arrange + var providers = new List + { + new() { OdsCode = string.Empty, PracticeName = "Test1", RegisteredPatientCount = 100 }, + new() { OdsCode = string.Empty, PracticeName = "Test2", RegisteredPatientCount = 200 } // Duplicate PK + }; + + + // Act + var result = await _repo.InsertHierarchyProviderConsumers(providers); + + // Assert + result.Should().Be(0); // Should return 0 due to exception + _logger.Collector.LatestRecord.Message.Should().Be("Error inserting hierarchy provider consumers"); + _logger.Collector.LatestRecord.Level.Should().Be(LogLevel.Error); + _logger.Collector.LatestRecord.Exception?.Message.Should() + .Contain("Violation of PRIMARY KEY constraint 'PK_Hierarchy"); + } + } +} \ No newline at end of file diff --git a/source/IntegrationTests/IntegrationTests.csproj b/source/IntegrationTests/IntegrationTests.csproj new file mode 100644 index 0000000..a67a3e5 --- /dev/null +++ b/source/IntegrationTests/IntegrationTests.csproj @@ -0,0 +1,51 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Always + + + + diff --git a/source/IntegrationTests/MsSqlContainerFixture.cs b/source/IntegrationTests/MsSqlContainerFixture.cs new file mode 100644 index 0000000..ddf1849 --- /dev/null +++ b/source/IntegrationTests/MsSqlContainerFixture.cs @@ -0,0 +1,77 @@ +using Core.Repositories; +using Core.Services.Interfaces; +using Dapper; +using DotNet.Testcontainers.Builders; +using Functions; +using Microsoft.Data.SqlClient; +using Microsoft.Extensions.Logging.Testing; +using Moq; +using Testcontainers.MsSql; + +namespace IntegrationTests; + +public class MsSqlContainerFixture : IAsyncLifetime +{ + public MsSqlContainer Container; + private HierarchyProviderConsumerRepo _repo; + private FakeLogger _logger; + + + public async Task InitializeAsync() + { + _logger = new FakeLogger(); + + Container = new MsSqlBuilder() + .WithImage("mcr.microsoft.com/mssql/server:2022-latest") + .WithPortBinding(1443, true) + .WithPassword("P@ssw0rd123") + .WithWaitStrategy(Wait.ForUnixContainer().UntilPortIsAvailable(1433)) + .Build(); + + // Create docker container for testing + await Container.StartAsync(); + + var mockCoreConfigurationService = new Mock(); + + // Set up the GetConnectionString method to return container's connection string + mockCoreConfigurationService.Setup(x => x.GetConnectionString(It.IsAny())) + .Returns(Container.GetConnectionString()); + + + _repo = new HierarchyProviderConsumerRepo(mockCoreConfigurationService.Object, new DapperWrapper(), + new SqlConnectionFactory(), _logger); + + await using var sqlConnection = new SqlConnection(Container.GetConnectionString()); + await sqlConnection.OpenAsync(); + await sqlConnection.ExecuteAsync("CREATE SCHEMA DATA"); + await sqlConnection.ExecuteAsync(@"SET ANSI_NULLS ON + BEGIN + SET QUOTED_IDENTIFIER ON + END + BEGIN + CREATE TABLE [Data].[HierarchyProviderConsumers]( + [OdsCode] [nvarchar](450) NOT NULL, + [PracticeName] [nvarchar](max) NULL, + [RegisteredPatientCount] [int] NOT NULL, + [RegionCode] [nvarchar](max) NULL, + [RegionName] [nvarchar](max) NULL, + [Icb22Name] [nvarchar](max) NULL, + [PcnName] [nvarchar](max) NULL, + [Appointments13000] [int] NOT NULL + ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] + END + BEGIN + SET ANSI_PADDING ON + END + BEGIN + ALTER TABLE [Data].[HierarchyProviderConsumers] ADD CONSTRAINT [PK_HierarchyProviderConsumers] PRIMARY KEY CLUSTERED + ( + [OdsCode] ASC + )WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] + END"); + + await sqlConnection.CloseAsync(); + } + + public async Task DisposeAsync() => await Container.DisposeAsync(); +} \ No newline at end of file diff --git a/source/IntegrationTests/TestHelpers/ConfigurationHelpers.cs b/source/IntegrationTests/TestHelpers/ConfigurationHelpers.cs new file mode 100644 index 0000000..9ef0cee --- /dev/null +++ b/source/IntegrationTests/TestHelpers/ConfigurationHelpers.cs @@ -0,0 +1,25 @@ +using Microsoft.Extensions.Configuration; + +namespace IntegrationTests.TestHelpers; + +public class ConfigurationHelpers +{ + public static IConfiguration CreateDefaultConfiguration(string connectionString = "") + { + var connection = + string.IsNullOrEmpty(connectionString) + ? "Server=myServer;Database=myDB;User Id=myUser;Password=myPass;" + : connectionString; + + var inMemorySettings = new Dictionary + { + { "ConnectionStrings:GPConnectAnalytics", connection } + }; + + var configuration = new ConfigurationBuilder() + .AddInMemoryCollection(inMemorySettings!) + .Build(); + + return configuration; + } +} \ No newline at end of file diff --git a/source/coverage/Core_ApplicationHelper.html b/source/coverage/Core_ApplicationHelper.html new file mode 100644 index 0000000..9ec4665 --- /dev/null +++ b/source/coverage/Core_ApplicationHelper.html @@ -0,0 +1,198 @@ + + + + + + + +Core.Helpers.ApplicationHelper - Coverage Report + +
+

< Summary

+
+
+
Information
+
+
+ + + + + + + + + + + + + +
Class:Core.Helpers.ApplicationHelper
Assembly:Core
File(s):/Users/griordan/git/gpconnect-analytics/source/Core/Helpers/ApplicationHelper.cs
+
+
+
+
+
+
+
Line coverage
+
+
100%
+
+ + + + + + + + + + + + + + + + + + + + + +
Covered lines:7
Uncovered lines:0
Coverable lines:7
Total lines:23
Line coverage:100%
+
+
+
+
+
Branch coverage
+
+
66%
+
+ + + + + + + + + + + + + +
Covered branches:4
Total branches:6
Branch coverage:66.6%
+
+
+
+
+
Method coverage
+
+
+

Feature is only available for sponsors

+Upgrade to PRO version +
+
+
+
+

Metrics

+
+ +++++++ + + + + + +
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
GetAssemblyVersion()100%11100%
GetAssemblyVersionInternal(...)100%44100%
+
+

File(s)

+

/Users/griordan/git/gpconnect-analytics/source/Core/Helpers/ApplicationHelper.cs

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System.Reflection;
 2
 3namespace Core.Helpers
 4{
 5    public class ApplicationHelper
 6    {
 7        public static class ApplicationVersion
 8        {
 9            public static string GetAssemblyVersion()
 110            {
 111                return GetAssemblyVersionInternal(Assembly.GetCallingAssembly);
 112            }
 13
 14            // Internal method to allow dependency injection for testing
 15            public static string GetAssemblyVersionInternal(Func<Assembly> getAssembly)
 616            {
 617                var buildTag = System.Environment.GetEnvironmentVariable("BUILD_TAG");
 18
 619                return string.IsNullOrWhiteSpace(buildTag) ? getAssembly()?.GetName().FullName : buildTag;
 620            }
 21        }
 22    }
 23}
+
+
+
+ \ No newline at end of file diff --git a/source/coverage/Core_AttributeExtensions.html b/source/coverage/Core_AttributeExtensions.html new file mode 100644 index 0000000..1b07772 --- /dev/null +++ b/source/coverage/Core_AttributeExtensions.html @@ -0,0 +1,202 @@ + + + + + + + +Core.Helpers.AttributeExtensions - Coverage Report + +
+

< Summary

+
+
+
Information
+
+
+ + + + + + + + + + + + + +
Class:Core.Helpers.AttributeExtensions
Assembly:Core
File(s):/Users/griordan/git/gpconnect-analytics/source/Core/Helpers/AttributeExtensions.cs
+
+
+
+
+
+
+
Line coverage
+
+
100%
+
+ + + + + + + + + + + + + + + + + + + + + +
Covered lines:13
Uncovered lines:0
Coverable lines:13
Total lines:27
Line coverage:100%
+
+
+
+
+
Branch coverage
+
+
100%
+
+ + + + + + + + + + + + + +
Covered branches:6
Total branches:6
Branch coverage:100%
+
+
+
+
+
Method coverage
+
+
+

Feature is only available for sponsors

+Upgrade to PRO version +
+
+
+
+

Metrics

+
+ +++++++ + + + + + +
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
GetFileType(...)100%11100%
GetValueFromPath(...)100%44100%
+
+

File(s)

+

/Users/griordan/git/gpconnect-analytics/source/Core/Helpers/AttributeExtensions.cs

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System.Reflection;
 2
 3namespace Core.Helpers
 4{
 5    public static class AttributeExtensions
 6    {
 7        public static FileTypes? GetFileType<TFilePath>(this string filePath)
 88        {
 89            return GetValueFromPath<TFilePath>(filePath);
 810        }
 11
 12        private static FileTypes? GetValueFromPath<T>(string filePath)
 813        {
 814            if (string.IsNullOrEmpty(filePath))
 215            {
 216                return null;
 17            }
 18
 619            var fileType = typeof(T).GetFields()
 620                .FirstOrDefault(field =>
 1221                    field.GetCustomAttribute<FilePathAttribute>() is { } attribute &&
 1222                    filePath.Contains(attribute.FilePath));
 23
 624            return fileType?.GetValue(null) as FileTypes?;
 825        }
 26    }
 27}
+
+
+
+ \ No newline at end of file diff --git a/source/coverage/Core_ConnectionStrings.html b/source/coverage/Core_ConnectionStrings.html new file mode 100644 index 0000000..6fec525 --- /dev/null +++ b/source/coverage/Core_ConnectionStrings.html @@ -0,0 +1,180 @@ + + + + + + + +Core.Helpers.ConnectionStrings - Coverage Report + +
+

< Summary

+
+
+
Information
+
+
+ + + + + + + + + + + + + +
Class:Core.Helpers.ConnectionStrings
Assembly:Core
File(s):/Users/griordan/git/gpconnect-analytics/source/Core/Helpers/ConnectionStrings.cs
+
+
+
+
+
+
+
Line coverage
+
+
100%
+
+ + + + + + + + + + + + + + + + + + + + + +
Covered lines:1
Uncovered lines:0
Coverable lines:1
Total lines:7
Line coverage:100%
+
+
+
+
+
Branch coverage
+
+
N/A
+
+ + + + + + + + + + + + + +
Covered branches:0
Total branches:0
Branch coverage:N/A
+
+
+
+
+
Method coverage
+
+
+

Feature is only available for sponsors

+Upgrade to PRO version +
+
+
+
+

Metrics

+
+ +++++++ + + + + +
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.cctor()100%11100%
+
+

File(s)

+

/Users/griordan/git/gpconnect-analytics/source/Core/Helpers/ConnectionStrings.cs

+
+ + + + + + + + + + + +
#LineLine coverage
 1namespace Core.Helpers
 2{
 3    public static class ConnectionStrings
 4    {
 15        public static string GpConnectAnalytics { get; } = "GpConnectAnalytics";
 6    }
 7}
+
+
+
+
+

Methods/Properties

+.cctor()
+
+
+ \ No newline at end of file diff --git a/source/coverage/Core_DapperWrapper.html b/source/coverage/Core_DapperWrapper.html new file mode 100644 index 0000000..60e8176 --- /dev/null +++ b/source/coverage/Core_DapperWrapper.html @@ -0,0 +1,247 @@ + + + + + + + +Core.Repositories.DapperWrapper - Coverage Report + +
+

< Summary

+
+
+
Information
+
+
+ + + + + + + + + + + + + +
Class:Core.Repositories.DapperWrapper
Assembly:Core
File(s):/Users/griordan/git/gpconnect-analytics/source/Core/Repositories/DapperWrapper.cs
+
+
+
+
+
+
+
Line coverage
+
+
96%
+
+ + + + + + + + + + + + + + + + + + + + + +
Covered lines:27
Uncovered lines:1
Coverable lines:28
Total lines:68
Line coverage:96.4%
+
+
+
+
+
Branch coverage
+
+
N/A
+
+ + + + + + + + + + + + + +
Covered branches:0
Total branches:0
Branch coverage:N/A
+
+
+
+
+
Method coverage
+
+
+

Feature is only available for sponsors

+Upgrade to PRO version +
+
+
+
+

Metrics

+
+ +++++++ + + + + + + + +
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
ExecuteAsync()100%11100%
ExecuteStoredProcedureAsync()100%11100%
QueryStoredProcedureAsync()100%1190.9%
QueryAsync()100%11100%
+
+

File(s)

+

/Users/griordan/git/gpconnect-analytics/source/Core/Repositories/DapperWrapper.cs

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System.Data;
 2using Dapper;
 3
 4namespace Core.Repositories;
 5
 6public interface IDapperWrapper
 7{
 8    Task<int> ExecuteAsync(IDbConnection connection, string sql, object param = null,
 9        IDbTransaction transaction = null);
 10
 11    Task<IEnumerable<T>> QueryAsync<T>(IDbConnection connection, string sql, object param = null,
 12        IDbTransaction transaction = null);
 13
 14    Task<int> ExecuteStoredProcedureAsync<T>(IDbConnection connection, string procedureName,
 15        object parameters, int commandTimeout = 30);
 16
 17    Task<IEnumerable<T>> QueryStoredProcedureAsync<T>(IDbConnection connection, string procedureName,
 18        object parameters, int commandTimeout = 30);
 19}
 20
 21public class DapperWrapper : IDapperWrapper
 22{
 23    public async Task<int> ExecuteAsync(IDbConnection connection, string sql, object param = null,
 24        IDbTransaction transaction = null)
 125    {
 126        return await connection.ExecuteAsync(sql, param, transaction);
 127    }
 28
 29    public async Task<int> ExecuteStoredProcedureAsync<T>(IDbConnection connection, string procedureName,
 30        object parameters, int commandTimeout = 30)
 231    {
 32        try
 233        {
 234            return await connection.ExecuteAsync(
 235                procedureName,
 236                parameters,
 237                commandType: CommandType.StoredProcedure,
 238                commandTimeout: commandTimeout);
 39        }
 140        catch (Exception ex)
 141        {
 142            throw new Exception($"Error executing stored procedure: {procedureName}", ex);
 43        }
 144    }
 45
 46    public async Task<IEnumerable<T>> QueryStoredProcedureAsync<T>(IDbConnection connection, string procedureName,
 47        object parameters, int commandTimeout = 30)
 148    {
 49        try
 150        {
 151            return await connection.QueryAsync<T>(
 152                procedureName,
 153                parameters,
 154                commandType: CommandType.StoredProcedure,
 155                commandTimeout: commandTimeout);
 56        }
 157        catch (Exception ex)
 158        {
 159            throw new Exception($"Error executing stored procedure: {procedureName}", ex);
 60        }
 061    }
 62
 63    public async Task<IEnumerable<T>> QueryAsync<T>(IDbConnection connection, string sql, object param = null,
 64        IDbTransaction transaction = null)
 165    {
 166        return await connection.QueryAsync<T>(sql, param, transaction);
 167    }
 68}
+
+
+
+ \ No newline at end of file diff --git a/source/coverage/Core_DateTimeHelper.html b/source/coverage/Core_DateTimeHelper.html new file mode 100644 index 0000000..7f4b186 --- /dev/null +++ b/source/coverage/Core_DateTimeHelper.html @@ -0,0 +1,184 @@ + + + + + + + +Core.Helpers.DateTimeHelper - Coverage Report + +
+

< Summary

+
+
+
Information
+
+
+ + + + + + + + + + + + + +
Class:Core.Helpers.DateTimeHelper
Assembly:Core
File(s):/Users/griordan/git/gpconnect-analytics/source/Core/Helpers/DateTimeHelper.cs
+
+
+
+
+
+
+
Line coverage
+
+
100%
+
+ + + + + + + + + + + + + + + + + + + + + +
Covered lines:4
Uncovered lines:0
Coverable lines:4
Total lines:11
Line coverage:100%
+
+
+
+
+
Branch coverage
+
+
100%
+
+ + + + + + + + + + + + + +
Covered branches:2
Total branches:2
Branch coverage:100%
+
+
+
+
+
Method coverage
+
+
+

Feature is only available for sponsors

+Upgrade to PRO version +
+
+
+
+

Metrics

+
+ +++++++ + + + + +
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
EachDay()100%22100%
+
+

File(s)

+

/Users/griordan/git/gpconnect-analytics/source/Core/Helpers/DateTimeHelper.cs

+
+ + + + + + + + + + + + + + + +
#LineLine coverage
 1namespace Core.Helpers
 2{
 3    public static class DateTimeHelper
 4    {
 5        public static IEnumerable<DateTime> EachDay(DateTime from, DateTime to)
 46        {
 267            for (var day = from.Date; day.Date <= to.Date; day = day.AddDays(1))
 98                yield return day;
 49        }
 10    }
 11}
+
+
+
+
+

Methods/Properties

+EachDay()
+
+
+ \ No newline at end of file diff --git a/source/coverage/Core_FilePathAttribute.html b/source/coverage/Core_FilePathAttribute.html new file mode 100644 index 0000000..d4817b5 --- /dev/null +++ b/source/coverage/Core_FilePathAttribute.html @@ -0,0 +1,185 @@ + + + + + + + +Core.Helpers.FilePathAttribute - Coverage Report + +
+

< Summary

+
+
+
Information
+
+
+ + + + + + + + + + + + + +
Class:Core.Helpers.FilePathAttribute
Assembly:Core
File(s):/Users/griordan/git/gpconnect-analytics/source/Core/Helpers/FilePath.cs
+
+
+
+
+
+
+
Line coverage
+
+
100%
+
+ + + + + + + + + + + + + + + + + + + + + +
Covered lines:3
Uncovered lines:0
Coverable lines:3
Total lines:12
Line coverage:100%
+
+
+
+
+
Branch coverage
+
+
N/A
+
+ + + + + + + + + + + + + +
Covered branches:0
Total branches:0
Branch coverage:N/A
+
+
+
+
+
Method coverage
+
+
+

Feature is only available for sponsors

+Upgrade to PRO version +
+
+
+
+

Metrics

+
+ +++++++ + + + + +
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
+
+

File(s)

+

/Users/griordan/git/gpconnect-analytics/source/Core/Helpers/FilePath.cs

+
+ + + + + + + + + + + + + + + + +
#LineLine coverage
 1namespace Core.Helpers
 2{
 3    public class FilePathAttribute : Attribute
 4    {
 5        public string FilePath { get; } = "";
 6
 167        public FilePathAttribute(string value)
 168        {
 9            FilePath = value;
 1610        }
 11    }
 12}
+
+
+
+
+

Methods/Properties

+.ctor(System.String)
+
+
+ \ No newline at end of file diff --git a/source/coverage/Core_HierarchyProviderConsumerRepo.html b/source/coverage/Core_HierarchyProviderConsumerRepo.html new file mode 100644 index 0000000..7b9eb8d --- /dev/null +++ b/source/coverage/Core_HierarchyProviderConsumerRepo.html @@ -0,0 +1,235 @@ + + + + + + + +Core.Repositories.HierarchyProviderConsumerRepo - Coverage Report + +
+

< Summary

+
+
+
Information
+
+
+ + + + + + + + + + + + + +
Class:Core.Repositories.HierarchyProviderConsumerRepo
Assembly:Core
File(s):/Users/griordan/git/gpconnect-analytics/source/Core/Repositories/HierarchyProviderConsumerRepo.cs
+
+
+
+
+
+
+
Line coverage
+
+
0%
+
+ + + + + + + + + + + + + + + + + + + + + +
Covered lines:0
Uncovered lines:17
Coverable lines:17
Total lines:62
Line coverage:0%
+
+
+
+
+
Branch coverage
+
+
0%
+
+ + + + + + + + + + + + + +
Covered branches:0
Total branches:4
Branch coverage:0%
+
+
+
+
+
Method coverage
+
+
+

Feature is only available for sponsors

+Upgrade to PRO version +
+
+
+
+

Metrics

+
+ +++++++ + + + + +
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
InsertHierarchyProviderConsumers()0%2040%
+
+

File(s)

+

/Users/griordan/git/gpconnect-analytics/source/Core/Repositories/HierarchyProviderConsumerRepo.cs

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System.Data;
 2using Core.DTOs.Request;
 3using Core.Helpers;
 4using Core.Services.Interfaces;
 5using Microsoft.Data.SqlClient;
 6
 7namespace Core.Repositories;
 8
 9public class HierarchyProviderConsumerRepo(
 10    ICoreConfigurationService configurationService,
 11    IDapperWrapper dapperWrapper,
 12    IConnectionFactory connectionFactory)
 13    : IHierarchyProviderConsumerRepo
 14{
 15    public async Task InsertHierarchyProviderConsumers(List<OrganisationHierarchyProvider> providers)
 016    {
 017        var connectionString = configurationService.GetConnectionString(ConnectionStrings.GpConnectAnalytics);
 018        await using var connection = connectionFactory.CreateConnection(connectionString);
 19
 20        // Explicitly open the connection
 021        if (connection.State != ConnectionState.Open)
 022        {
 023            await connection.OpenAsync();
 024        }
 25
 026        await using var transaction = await connection.BeginTransactionAsync();
 27
 28        const string sql = """
 29                               INSERT INTO [Data].[HierarchyProviderConsumers] (
 30                                   OdsCode,
 31                                   PracticeName,
 32                                   RegisteredPatientCount,
 33                                   RegionCode,
 34                                   RegionName,
 35                                   Icb22Name,
 36                                   PcnName,
 37                                   Appointments13000
 38                               )
 39                               VALUES (
 40                                   @OdsCode,
 41                                   @PracticeName,
 42                                   @RegisteredPatientCount,
 43                                   @RegionCode,
 44                                   @RegionName,
 45                                   @Icb22Name,
 46                                   @PcnName,
 47                                   @Appointments13000
 48                               );
 49                           """;
 50
 51        try
 052        {
 053            await dapperWrapper.ExecuteAsync(connection, sql, providers, transaction);
 054            await transaction.CommitAsync();
 055        }
 056        catch
 057        {
 058            await transaction.RollbackAsync();
 059            throw;
 60        }
 061    }
 62}
+
+
+
+
+

Methods/Properties

+InsertHierarchyProviderConsumers()
+
+
+ \ No newline at end of file diff --git a/source/coverage/Core_OrganisationHierarchyProvider.html b/source/coverage/Core_OrganisationHierarchyProvider.html new file mode 100644 index 0000000..323010e --- /dev/null +++ b/source/coverage/Core_OrganisationHierarchyProvider.html @@ -0,0 +1,192 @@ + + + + + + + +Core.DTOs.Request.OrganisationHierarchyProvider - Coverage Report + +
+

< Summary

+
+
+
Information
+
+
+ + + + + + + + + + + + + +
Class:Core.DTOs.Request.OrganisationHierarchyProvider
Assembly:Core
File(s):/Users/griordan/git/gpconnect-analytics/source/Core/DTOs/Request/OrganisationHeirarchyProvider.cs
+
+
+
+
+
+
+
Line coverage
+
+
100%
+
+ + + + + + + + + + + + + + + + + + + + + +
Covered lines:2
Uncovered lines:0
Coverable lines:2
Total lines:19
Line coverage:100%
+
+
+
+
+
Branch coverage
+
+
N/A
+
+ + + + + + + + + + + + + +
Covered branches:0
Total branches:0
Branch coverage:N/A
+
+
+
+
+
Method coverage
+
+
+

Feature is only available for sponsors

+Upgrade to PRO version +
+
+
+
+

Metrics

+
+ +++++++ + + + + +
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor()100%11100%
+
+

File(s)

+

/Users/griordan/git/gpconnect-analytics/source/Core/DTOs/Request/OrganisationHeirarchyProvider.cs

+
+ + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1#nullable enable
 2namespace Core.DTOs.Request
 3{
 4    public class OrganisationHierarchyProvider
 5    {
 6        public required string OdsCode { get; set; }
 7        public string? PracticeName { get; set; }
 8        public int RegisteredPatientCount { get; set; }
 9        public string? RegionCode { get; set; }
 10        public string? RegionName { get; set; }
 11        public string? Icb22Name { get; set; }
 12        public string? PcnName { get; set; }
 13        public int Appointments13000 { get; set; }
 14
 15        public OrganisationHierarchyProvider()
 316        {
 317        }
 18    }
 19}
+
+
+
+
+

Methods/Properties

+.ctor()
+
+
+ \ No newline at end of file diff --git a/source/coverage/Core_SplunkInstanceMap.html b/source/coverage/Core_SplunkInstanceMap.html new file mode 100644 index 0000000..1799c42 --- /dev/null +++ b/source/coverage/Core_SplunkInstanceMap.html @@ -0,0 +1,187 @@ + + + + + + + +Core.Mapping.SplunkInstanceMap - Coverage Report + +
+

< Summary

+
+
+
Information
+
+
+ + + + + + + + + + + + + +
Class:Core.Mapping.SplunkInstanceMap
Assembly:Core
File(s):/Users/griordan/git/gpconnect-analytics/source/Core/Mapping/SplunkInstanceMap.cs
+
+
+
+
+
+
+
Line coverage
+
+
0%
+
+ + + + + + + + + + + + + + + + + + + + + +
Covered lines:0
Uncovered lines:5
Coverable lines:5
Total lines:14
Line coverage:0%
+
+
+
+
+
Branch coverage
+
+
N/A
+
+ + + + + + + + + + + + + +
Covered branches:0
Total branches:0
Branch coverage:N/A
+
+
+
+
+
Method coverage
+
+
+

Feature is only available for sponsors

+Upgrade to PRO version +
+
+
+
+

Metrics

+
+ +++++++ + + + + +
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor()100%210%
+
+

File(s)

+

/Users/griordan/git/gpconnect-analytics/source/Core/Mapping/SplunkInstanceMap.cs

+
+ + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using Core.DTOs.Response.Configuration;
 2using Dapper.FluentMap.Mapping;
 3
 4namespace Core.Mapping
 5{
 6    public class SplunkInstanceMap : EntityMap<SplunkInstance>
 7    {
 08        public SplunkInstanceMap()
 09        {
 010            Map(p => p.Source).ToColumn("SplunkInstance");
 011            Map(p => p.SourceGroup).ToColumn("SplunkInstanceGroup");
 012        }
 13    }
 14}
+
+
+
+
+

Methods/Properties

+.ctor()
+
+
+ \ No newline at end of file diff --git a/source/coverage/Core_TimeProvider.html b/source/coverage/Core_TimeProvider.html new file mode 100644 index 0000000..9187520 --- /dev/null +++ b/source/coverage/Core_TimeProvider.html @@ -0,0 +1,187 @@ + + + + + + + +TimeProvider - Coverage Report + +
+

< Summary

+
+
+
Information
+
+
+ + + + + + + + + + + + + +
Class:TimeProvider
Assembly:Core
File(s):/Users/griordan/git/gpconnect-analytics/source/Core/Helpers/TimeProvider.cs
+
+
+
+
+
+
+
Line coverage
+
+
0%
+
+ + + + + + + + + + + + + + + + + + + + + +
Covered lines:0
Uncovered lines:2
Coverable lines:2
Total lines:12
Line coverage:0%
+
+
+
+
+
Branch coverage
+
+
N/A
+
+ + + + + + + + + + + + + +
Covered branches:0
Total branches:0
Branch coverage:N/A
+
+
+
+
+
Method coverage
+
+
+

Feature is only available for sponsors

+Upgrade to PRO version +
+
+
+
+

Metrics

+
+ +++++++ + + + + + +
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
UtcDateTime()100%210%
CurrentDate()100%210%
+
+

File(s)

+

/Users/griordan/git/gpconnect-analytics/source/Core/Helpers/TimeProvider.cs

+
+ + + + + + + + + + + + + + + + +
#LineLine coverage
 1using Core;
 2
 3public class TimeProvider : ITimeProvider
 4{
 05    public DateTime UtcDateTime() => DateTime.UtcNow;
 6
 7    /// <summary>
 8    /// Gets current Date, time is set at 00:00
 9    /// </summary>
 10    /// <returns>current DateTime</returns>
 011    public DateTime CurrentDate() => DateTime.Today;
 12}
+
+
+
+
+

Methods/Properties

+UtcDateTime()
+CurrentDate()
+
+
+ \ No newline at end of file diff --git a/source/coverage/Functions_BatchService.html b/source/coverage/Functions_BatchService.html new file mode 100644 index 0000000..5fd4098 --- /dev/null +++ b/source/coverage/Functions_BatchService.html @@ -0,0 +1,327 @@ + + + + + + + +Functions.Services.BatchService - Coverage Report + +
+

< Summary

+
+
+
Information
+
+
+ + + + + + + + + + + + + +
Class:Functions.Services.BatchService
Assembly:Functions
File(s):/Users/griordan/git/gpconnect-analytics/source/Functions/Services/BatchService.cs
+
+
+
+
+
+
+
Line coverage
+
+
92%
+
+ + + + + + + + + + + + + + + + + + + + + +
Covered lines:86
Uncovered lines:7
Coverable lines:93
Total lines:146
Line coverage:92.4%
+
+
+
+
+
Branch coverage
+
+
77%
+
+ + + + + + + + + + + + + +
Covered branches:14
Total branches:18
Branch coverage:77.7%
+
+
+
+
+
Method coverage
+
+
+

Feature is only available for sponsors

+Upgrade to PRO version +
+
+
+
+

Metrics

+
+ +++++++ + + + + + + + + +
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
StartBatchDownloadForTodayAsync()100%11100%
StartBatchDownloadAsync()60%121074.07%
ProcessUrls()100%44100%
GetBatchDownloadUriList()100%44100%
RemovePreviousDownloads()100%11100%
+
+

File(s)

+

/Users/griordan/git/gpconnect-analytics/source/Functions/Services/BatchService.cs

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System.Web;
 2using Core.DTOs.Request;
 3using Core.DTOs.Response.Configuration;
 4using Core.Helpers;
 5using Core.Services.Interfaces;
 6using Dapper;
 7using Functions.Services.Interfaces;
 8using Microsoft.Extensions.Logging;
 9
 10namespace Functions.Services
 11{
 12    public class BatchService(
 13        IConfigurationService configurationService,
 14        ISplunkService splunkService,
 15        ILogger<BatchService> logger,
 16        IDataService dataService)
 17        : IBatchService
 18    {
 19        private SplunkClient _splunkClient;
 20
 21        public async Task<int> StartBatchDownloadForTodayAsync(FileTypes fileTypes)
 222        {
 223            var dateInScope = DateTime.Today.AddDays(1);
 224            var fileType = await configurationService.GetFileType(fileTypes);
 225            var uriList =
 226                await GetBatchDownloadUriList(fileType, DateTimeHelper.EachDay(dateInScope, dateInScope).ToList());
 27
 228            await RemovePreviousDownloads(fileType, dateInScope, dateInScope);
 29
 230            await ProcessUrls(fileType, uriList, true);
 231            return uriList.Count;
 232        }
 33
 34        public async Task<int> StartBatchDownloadAsync(FileTypes fileTypes, string? startDate, string? endDate)
 335        {
 336            if (string.IsNullOrWhiteSpace(startDate) || string.IsNullOrWhiteSpace(endDate))
 037            {
 038                logger.LogError("Start and end dates are required for batch download");
 039                throw new ArgumentException("Start and end dates are required for batch download");
 40            }
 41
 342            var start = DateTime.TryParse(startDate, out DateTime parsedStart)
 343                ? parsedStart
 344                : DateTime.Today;
 345            var end = DateTime.TryParse(endDate, out DateTime parsedEnd)
 346                ? parsedEnd
 347                : DateTime.Today;
 48
 349            if (parsedEnd >= parsedStart)
 250            {
 251                var fileType = await configurationService.GetFileType(fileTypes);
 252                var uriList =
 253                    await GetBatchDownloadUriList(fileType, DateTimeHelper.EachDay(start, end).ToList());
 54
 255                await RemovePreviousDownloads(fileType, start, end);
 56
 57                try
 258                {
 259                    await ProcessUrls(fileType, uriList, false);
 260                    return uriList.Count;
 61                }
 062                catch (Exception ex)
 063                {
 064                    logger.LogError(ex, "An error occurred during batch download when processing urls");
 065                    throw;
 66                }
 67            }
 68
 169            logger.LogError("Start date cannot be later than end date");
 170            throw new ArgumentException("Start date cannot be later than end date");
 271        }
 72
 73        private async Task ProcessUrls(FileType fileType, List<UriRequest> uriList, bool isToday)
 474        {
 475            var downloadTasks = new List<Task>();
 76
 77            // Create and start all download tasks
 44078            for (var i = 0; i < uriList.Count; i++)
 21679            {
 21680                var requestUri = uriList[i];
 21681                downloadTasks.Add(splunkService.ExecuteBatchDownloadFromSplunk(fileType, requestUri, isToday));
 21682            }
 83
 84            // Wait for tasks to complete
 22085            while (downloadTasks.Count > 0)
 21686            {
 21687                var finishedTask = await Task.WhenAny(downloadTasks);
 21688                downloadTasks.Remove(finishedTask);
 21689            }
 490        }
 91
 92        public async Task<List<UriRequest>> GetBatchDownloadUriList(FileType fileType, List<DateTime> dateTimeList)
 593        {
 594            var uriList = new List<UriRequest>();
 595            _splunkClient = await configurationService.GetSplunkClientConfiguration();
 96
 3997            foreach (var dateTime in dateTimeList)
 1298            {
 1299                var earliestDate = dateTime.AddDays(-2);
 12100                var latestDate = dateTime.AddDays(-1);
 101
 600102                for (var i = 0; i < 24; i++)
 288103                {
 288104                    var splunkQuery = fileType.SplunkQuery;
 288105                    var hour = TimeSpan.Zero.Add(TimeSpan.FromHours(i));
 106
 288107                    splunkQuery = splunkQuery.Replace("{earliest}",
 288108                        earliestDate.ToString(DateFormatConstants.SplunkQueryDate));
 288109                    splunkQuery = splunkQuery.Replace("{latest}",
 288110                        latestDate.ToString(DateFormatConstants.SplunkQueryDate));
 288111                    splunkQuery = splunkQuery.Replace("{hour}",
 288112                        hour.ToString(DateFormatConstants.SplunkQueryHour));
 113
 288114                    var uriBuilder = new UriBuilder
 288115                    {
 288116                        Scheme = Uri.UriSchemeHttps,
 288117                        Host = _splunkClient.HostName,
 288118                        Port = _splunkClient.HostPort,
 288119                        Path = _splunkClient.BaseUrl,
 288120                        Query = string.Format(_splunkClient.QueryParameters, HttpUtility.UrlEncode(splunkQuery))
 288121                    };
 122
 288123                    uriList.Add(new UriRequest()
 288124                    {
 288125                        Request = uriBuilder.Uri,
 288126                        EarliestDate = earliestDate,
 288127                        LatestDate = latestDate,
 288128                        Hour = hour
 288129                    });
 288130                }
 12131            }
 132
 5133            return uriList;
 5134        }
 135
 136        public async Task RemovePreviousDownloads(FileType fileType, DateTime startDate, DateTime endDate)
 5137        {
 5138            var procedureName = "Import.RemovePreviousDownload";
 5139            var parameters = new DynamicParameters();
 5140            parameters.Add("@FileTypeId", fileType.FileTypeId);
 5141            parameters.Add("@StartDate", startDate.AddDays(-2));
 5142            parameters.Add("@EndDate", endDate.AddDays(-1));
 5143            await dataService.ExecuteStoredProcedure(procedureName, parameters);
 5144        }
 145    }
 146}
+
+
+
+ \ No newline at end of file diff --git a/source/coverage/Functions_BlobService.html b/source/coverage/Functions_BlobService.html new file mode 100644 index 0000000..5878523 --- /dev/null +++ b/source/coverage/Functions_BlobService.html @@ -0,0 +1,270 @@ + + + + + + + +Functions.Services.BlobService - Coverage Report + +
+

< Summary

+
+
+
Information
+
+
+ + + + + + + + + + + + + +
Class:Functions.Services.BlobService
Assembly:Functions
File(s):/Users/griordan/git/gpconnect-analytics/source/Functions/Services/BlobService.cs
+
+
+
+
+
+
+
Line coverage
+
+
84%
+
+ + + + + + + + + + + + + + + + + + + + + +
Covered lines:42
Uncovered lines:8
Coverable lines:50
Total lines:93
Line coverage:84%
+
+
+
+
+
Branch coverage
+
+
75%
+
+ + + + + + + + + + + + + +
Covered branches:6
Total branches:8
Branch coverage:75%
+
+
+
+
+
Method coverage
+
+
+

Feature is only available for sponsors

+Upgrade to PRO version +
+
+
+
+

Metrics

+
+ +++++++ + + + + + + +
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)50%22100%
AddObjectToBlob()100%2278.94%
AddMessageToBlobQueue()75%4483.33%
+
+

File(s)

+

/Users/griordan/git/gpconnect-analytics/source/Functions/Services/BlobService.cs

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System.Text;
 2using System.Text.Json;
 3using Azure;
 4using Azure.Storage.Blobs;
 5using Azure.Storage.Blobs.Models;
 6using Azure.Storage.Queues;
 7using Core.DTOs.Response.Configuration;
 8using Core.DTOs.Response.Queue;
 9using Core.DTOs.Response.Splunk;
 10using Core.Services.Interfaces;
 11using Functions.Services.Interfaces;
 12using Microsoft.Extensions.Logging;
 13
 14namespace Functions.Services
 15{
 16    public class BlobService : IBlobService
 17    {
 18        private readonly ILogger<BlobService> _logger;
 19        private readonly BlobStorage _blobStorageConfiguration;
 20        private readonly QueueClient _queueClient;
 21        private readonly BlobServiceClient _blobServiceClient;
 22
 23        public BlobService(IConfigurationService configurationService, ILogger<BlobService> logger,
 24            QueueClient? queueClient)
 625        {
 626            _logger = logger;
 627            _blobStorageConfiguration = configurationService.GetBlobStorageConfiguration().Result;
 628            _blobServiceClient = new BlobServiceClient(_blobStorageConfiguration.ConnectionString);
 629            _queueClient = queueClient ?? new QueueClient(_blobStorageConfiguration.ConnectionString,
 630                _blobStorageConfiguration.QueueName);
 631        }
 32
 33        public async Task<BlobContentInfo?> AddObjectToBlob(ExtractResponse extractResponse)
 334        {
 335            _logger.LogInformation($"Adding object to blob storage", extractResponse);
 36
 37            try
 338            {
 339                var containerClient =
 340                    _blobServiceClient.GetBlobContainerClient(_blobStorageConfiguration.ContainerName);
 41
 442                if (!await containerClient.ExistsAsync()) return null;
 43
 144                var blobClient = containerClient.GetBlobClient(extractResponse.FilePath);
 145                var response =
 146                    await blobClient.UploadAsync(extractResponse.ExtractResponseStream, overwrite: true);
 47
 148                return response;
 49            }
 150            catch (RequestFailedException requestFailedException)
 151            {
 152                _logger.LogError(requestFailedException, "The container does not exist");
 153                throw;
 54            }
 055            catch (Exception exc)
 056            {
 057                _logger.LogError(exc, "An error occurred while trying to add a blob to the storage");
 058                throw;
 59            }
 260        }
 61
 62        public async Task AddMessageToBlobQueue(int fileAddedCount, int fileTypeId, string blobName,
 63            bool overrideEntry = false)
 364        {
 65            try
 366            {
 367                if ((await _queueClient.ExistsAsync()) && fileAddedCount == 1)
 168                {
 169                    var message = new Message
 170                    {
 171                        FileTypeId = fileTypeId,
 172                        BlobName = blobName,
 173                        Override = overrideEntry
 174                    };
 75
 176                    var messageText = JsonSerializer.Serialize(message);
 177                    _logger.LogInformation($"Adding message to blob queue", message);
 178                    await _queueClient.SendMessageAsync(Convert.ToBase64String(Encoding.UTF8.GetBytes(messageText)));
 179                }
 280            }
 181            catch (RequestFailedException requestFailedException)
 182            {
 183                _logger.LogError(requestFailedException, "The queue does not exist");
 184                throw;
 85            }
 086            catch (Exception exc)
 087            {
 088                _logger.LogError(exc, "An error occurred while trying to add a message to the queue");
 089                throw;
 90            }
 291        }
 92    }
 93}
+
+
+
+ \ No newline at end of file diff --git a/source/coverage/Functions_ConfigurationService.html b/source/coverage/Functions_ConfigurationService.html new file mode 100644 index 0000000..17b4c71 --- /dev/null +++ b/source/coverage/Functions_ConfigurationService.html @@ -0,0 +1,244 @@ + + + + + + + +Functions.Services.ConfigurationService - Coverage Report + +
+

< Summary

+
+
+
Information
+
+
+ + + + + + + + + + + + + +
Class:Functions.Services.ConfigurationService
Assembly:Functions
File(s):/Users/griordan/git/gpconnect-analytics/source/Functions/Services/ConfigurationService.cs
+
+
+
+
+
+
+
Line coverage
+
+
88%
+
+ + + + + + + + + + + + + + + + + + + + + +
Covered lines:32
Uncovered lines:4
Coverable lines:36
Total lines:61
Line coverage:88.8%
+
+
+
+
+
Branch coverage
+
+
N/A
+
+ + + + + + + + + + + + + +
Covered branches:0
Total branches:0
Branch coverage:N/A
+
+
+
+
+
Method coverage
+
+
+

Feature is only available for sponsors

+Upgrade to PRO version +
+
+
+
+

Metrics

+
+ +++++++ + + + + + + + + + +
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
GetBlobStorageConfiguration()100%11100%
GetFilePathConstants()100%11100%
GetFileTypes()100%11100%
GetFileType()100%210%
GetSplunkClientConfiguration()100%11100%
GetSplunkInstance()100%11100%
+
+

File(s)

+

/Users/griordan/git/gpconnect-analytics/source/Functions/Services/ConfigurationService.cs

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using Core.DTOs.Response.Configuration;
 2using Core.Helpers;
 3using Core.Services.Interfaces;
 4using Microsoft.Extensions.Logging;
 5
 6namespace Functions.Services
 7{
 8    public class ConfigurationService(
 9        IDataService dataService,
 10        ILogger<ConfigurationService> logger)
 11        : IConfigurationService
 12    {
 13        public async Task<BlobStorage> GetBlobStorageConfiguration()
 214        {
 215            var result =
 216                await dataService.ExecuteQueryStoredProcedure<BlobStorage>(
 217                    "[Configuration].[GetBlobStorageConfiguration]");
 218            logger.LogInformation("Loading blob storage configuration", result.FirstOrDefault());
 219            return result.FirstOrDefault();
 220        }
 21
 22        public async Task<FilePathConstants> GetFilePathConstants()
 223        {
 224            var result =
 225                await dataService.ExecuteQueryStoredProcedure<FilePathConstants>(
 226                    "[Configuration].[GetFilePathConstants]");
 227            logger.LogInformation("Loading file path constants", result.FirstOrDefault());
 228            return result.FirstOrDefault();
 229        }
 30
 31        public async Task<List<FileType>> GetFileTypes()
 232        {
 233            var result = await dataService.ExecuteQueryStoredProcedure<FileType>("[Configuration].[GetFileTypes]");
 234            logger.LogInformation("Loading file types", result);
 235            return result;
 236        }
 37
 38        public async Task<FileType> GetFileType(FileTypes fileTypes)
 039        {
 040            var result = await dataService.ExecuteQueryStoredProcedure<FileType>("[Configuration].[GetFileTypes]");
 041            return result.FirstOrDefault(ft => ft.FileTypeFilePrefix == fileTypes.ToString());
 042        }
 43
 44        public async Task<SplunkClient> GetSplunkClientConfiguration()
 145        {
 146            var result =
 147                await dataService.ExecuteQueryStoredProcedure<SplunkClient>(
 148                    "[Configuration].[GetSplunkClientConfiguration]");
 149            logger.LogInformation("Loading splunk client configuration", result.FirstOrDefault());
 150            return result.FirstOrDefault();
 151        }
 52
 53        public async Task<SplunkInstance> GetSplunkInstance(SplunkInstances splunkInstance)
 154        {
 155            var result =
 156                await dataService.ExecuteQueryStoredProcedure<SplunkInstance>("[Configuration].[GetSplunkInstances]");
 157            logger.LogInformation("Loading splunk instance", result);
 258            return result.FirstOrDefault(x => x.Source == splunkInstance.ToString());
 159        }
 60    }
 61}
+
+
+
+ \ No newline at end of file diff --git a/source/coverage/Functions_CoreConfigurationService.html b/source/coverage/Functions_CoreConfigurationService.html new file mode 100644 index 0000000..9609a3d --- /dev/null +++ b/source/coverage/Functions_CoreConfigurationService.html @@ -0,0 +1,187 @@ + + + + + + + +Functions.Services.CoreConfigurationService - Coverage Report + +
+

< Summary

+
+
+
Information
+
+
+ + + + + + + + + + + + + +
Class:Functions.Services.CoreConfigurationService
Assembly:Functions
File(s):/Users/griordan/git/gpconnect-analytics/source/Functions/Services/CoreConfigurationService.cs
+
+
+
+
+
+
+
Line coverage
+
+
100%
+
+ + + + + + + + + + + + + + + + + + + + + +
Covered lines:4
Uncovered lines:0
Coverable lines:4
Total lines:14
Line coverage:100%
+
+
+
+
+
Branch coverage
+
+
100%
+
+ + + + + + + + + + + + + +
Covered branches:2
Total branches:2
Branch coverage:100%
+
+
+
+
+
Method coverage
+
+
+

Feature is only available for sponsors

+Upgrade to PRO version +
+
+
+
+

Metrics

+
+ +++++++ + + + + +
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
GetConnectionString(...)100%22100%
+
+

File(s)

+

/Users/griordan/git/gpconnect-analytics/source/Functions/Services/CoreConfigurationService.cs

+
+ + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using Core.Services.Interfaces;
 2using Microsoft.Extensions.Configuration;
 3
 4namespace Functions.Services
 5{
 6    public class CoreConfigurationService(IConfiguration configuration) : ICoreConfigurationService
 7    {
 8        public string GetConnectionString(string name)
 29        {
 210            var connectionString = configuration.GetConnectionString(name);
 211            return connectionString ?? throw new ArgumentException("No connection string with given name");
 112        }
 13    }
 14}
+
+
+
+
+

Methods/Properties

+GetConnectionString(System.String)
+
+
+ \ No newline at end of file diff --git a/source/coverage/Functions_DataService.html b/source/coverage/Functions_DataService.html new file mode 100644 index 0000000..3e64d4b --- /dev/null +++ b/source/coverage/Functions_DataService.html @@ -0,0 +1,296 @@ + + + + + + + +Functions.Services.DataService - Coverage Report + +
+

< Summary

+
+
+
Information
+
+
+ + + + + + + + + + + + + +
Class:Functions.Services.DataService
Assembly:Functions
File(s):/Users/griordan/git/gpconnect-analytics/source/Functions/Services/DataService.cs
+
+
+
+
+
+
+
Line coverage
+
+
3%
+
+ + + + + + + + + + + + + + + + + + + + + +
Covered lines:2
Uncovered lines:64
Coverable lines:66
Total lines:113
Line coverage:3%
+
+
+
+
+
Branch coverage
+
+
0%
+
+ + + + + + + + + + + + + +
Covered branches:0
Total branches:16
Branch coverage:0%
+
+
+
+
+
Method coverage
+
+
+

Feature is only available for sponsors

+Upgrade to PRO version +
+
+
+
+

Metrics

+
+ +++++++ + + + + + + + + + +
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
ExecuteRawUpsertSqlAsync()100%210%
ExecuteQueryStoredProcedure()0%4260%
ExecuteStoredProcedureWithOutputParameters()0%2040%
ExecuteStoredProcedure()0%2040%
SqlConnection_InfoMessage(...)0%620%
+
+

File(s)

+

/Users/griordan/git/gpconnect-analytics/source/Functions/Services/DataService.cs

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using Core;
 2using Core.Helpers;
 3using Core.Repositories;
 4using Core.Services.Interfaces;
 5using Dapper;
 6using Microsoft.Data.SqlClient;
 7using Microsoft.Extensions.Logging;
 8
 9namespace Functions.Services
 10{
 11    public class DataService(
 12        ILogger<DataService> logger,
 13        ICoreConfigurationService coreConfigurationService,
 14        IDapperWrapper dapper,
 15        IConnectionFactory connectionFactory)
 16        : IDataService
 17    {
 618        private readonly string _connectionString =
 619            coreConfigurationService.GetConnectionString(ConnectionStrings.GpConnectAnalytics);
 20
 21        public async Task<int> ExecuteRawUpsertSqlAsync(string sqlCommand, object parameters)
 022        {
 23            try
 024            {
 025                await using var sqlConnection = connectionFactory.CreateConnection(_connectionString);
 026                await sqlConnection.OpenAsync();
 027                logger.LogInformation($"Executing raw SQL command");
 028                var rowsAffected = await dapper.ExecuteAsync(sqlConnection, sqlCommand, parameters);
 029                return rowsAffected;
 030            }
 031            catch (Exception ex)
 032            {
 033                logger.LogError(ex, $"An error has occurred while executing the raw SQL command: {sqlCommand}");
 034                throw;
 35            }
 036        }
 37
 38        public async Task<List<T>> ExecuteQueryStoredProcedure<T>(string procedureName, DynamicParameters parameters)
 39            where T : class
 040        {
 041            await using var sqlConnection = connectionFactory.CreateConnection(_connectionString);
 42            try
 043            {
 044                if (sqlConnection is SqlConnection connection)
 045                {
 046                    connection.InfoMessage += SqlConnection_InfoMessage;
 047                }
 48
 049                logger.LogInformation($"Executing stored procedure {procedureName}", parameters);
 50
 051                var results = await dapper.QueryStoredProcedureAsync<T>(sqlConnection, procedureName, parameters, 0);
 052                return results.AsList();
 53            }
 054            catch (Exception exc)
 055            {
 056                logger.LogError(exc, $"An error has occurred while attempting to execute the function {procedureName}");
 057                throw;
 58            }
 059        }
 60
 61
 62        public async Task<DynamicParameters> ExecuteStoredProcedureWithOutputParameters(string procedureName,
 63            DynamicParameters parameters)
 064        {
 065            await using var sqlConnection = connectionFactory.CreateConnection(_connectionString);
 66            try
 067            {
 068                if (sqlConnection is SqlConnection connection)
 069                {
 070                    connection.InfoMessage += SqlConnection_InfoMessage;
 071                }
 72
 073                logger.LogInformation($"Executing stored procedure {procedureName}", parameters);
 074                await dapper.ExecuteStoredProcedureAsync<DynamicParameters>(sqlConnection, procedureName, parameters,
 075                    0);
 076                return parameters;
 77            }
 078            catch (Exception exc)
 079            {
 080                logger?.LogError(exc,
 081                    $"An error has occurred while attempting to execute the function {procedureName}");
 082                throw;
 83            }
 084        }
 85
 86        public async Task<int> ExecuteStoredProcedure(string procedureName, DynamicParameters parameters)
 087        {
 088            await using var sqlConnection = connectionFactory.CreateConnection(_connectionString);
 89            try
 090            {
 091                if (sqlConnection is SqlConnection connection)
 092                {
 093                    connection.InfoMessage += SqlConnection_InfoMessage;
 094                }
 95
 096                logger.LogInformation($"Executing stored procedure {procedureName}", parameters);
 097                var result = await dapper.ExecuteAsync(sqlConnection, procedureName, parameters);
 098                return result;
 99            }
 0100            catch (Exception exc)
 0101            {
 0102                logger?.LogError(exc,
 0103                    $"An error has occurred while attempting to execute the function {procedureName}");
 0104                throw;
 105            }
 0106        }
 107
 108        private void SqlConnection_InfoMessage(object sender, SqlInfoMessageEventArgs e)
 0109        {
 0110            logger?.LogInformation(e.Message);
 0111        }
 112    }
 113}
+
+
+
+ \ No newline at end of file diff --git a/source/coverage/Functions_DirectFunctionExecutor.html b/source/coverage/Functions_DirectFunctionExecutor.html new file mode 100644 index 0000000..b2e9ba1 --- /dev/null +++ b/source/coverage/Functions_DirectFunctionExecutor.html @@ -0,0 +1,169 @@ + + + + + + + +Functions.DirectFunctionExecutor - Coverage Report + +
+

< Summary

+ +
+
+
Line coverage
+
+
0%
+
+ + + + + + + + + + + + + + + + + + + + + +
Covered lines:0
Uncovered lines:96
Coverable lines:96
Total lines:132
Line coverage:0%
+
+
+
+
+
Branch coverage
+
+
0%
+
+ + + + + + + + + + + + + +
Covered branches:0
Total branches:28
Branch coverage:0%
+
+
+
+
+
Method coverage
+
+
+

Feature is only available for sponsors

+Upgrade to PRO version +
+
+
+
+

Metrics

+
+ +++++++ + + + + + +
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)0%620%
ExecuteAsync()0%702260%
+
+

File(s)

+

/Users/griordan/git/gpconnect-analytics/source/Functions/Microsoft.Azure.Functions.Worker.Sdk.Generators/Microsoft.Azure.Functions.Worker.Sdk.Generators.FunctionExecutorGenerator/GeneratedFunctionExecutor.g.cs

+

File '/Users/griordan/git/gpconnect-analytics/source/Functions/Microsoft.Azure.Functions.Worker.Sdk.Generators/Microsoft.Azure.Functions.Worker.Sdk.Generators.FunctionExecutorGenerator/GeneratedFunctionExecutor.g.cs' does not exist (any more).

+
+
+ \ No newline at end of file diff --git a/source/coverage/Functions_EmailConfigurationProvider.html b/source/coverage/Functions_EmailConfigurationProvider.html new file mode 100644 index 0000000..91845a9 --- /dev/null +++ b/source/coverage/Functions_EmailConfigurationProvider.html @@ -0,0 +1,202 @@ + + + + + + + +Functions.Configuration.EmailConfigurationProvider - Coverage Report + +
+

< Summary

+
+
+
Information
+
+
+ + + + + + + + + + + + + +
Class:Functions.Configuration.EmailConfigurationProvider
Assembly:Functions
File(s):/Users/griordan/git/gpconnect-analytics/source/Functions/Configuration/EmailConfigurationProvider.cs
+
+
+
+
+
+
+
Line coverage
+
+
0%
+
+ + + + + + + + + + + + + + + + + + + + + +
Covered lines:0
Uncovered lines:8
Coverable lines:8
Total lines:29
Line coverage:0%
+
+
+
+
+
Branch coverage
+
+
0%
+
+ + + + + + + + + + + + + +
Covered branches:0
Total branches:2
Branch coverage:0%
+
+
+
+
+
Method coverage
+
+
+

Feature is only available for sponsors

+Upgrade to PRO version +
+
+
+
+

Metrics

+
+ +++++++ + + + + +
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
GetEmailConfiguration(...)0%620%
+
+

File(s)

+

/Users/griordan/git/gpconnect-analytics/source/Functions/Configuration/EmailConfigurationProvider.cs

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System.Data;
 2using Core;
 3using Core.DTOs.Response.Configuration;
 4using Core.Helpers;
 5using Dapper;
 6using Microsoft.Extensions.Configuration;
 7
 8namespace Functions.Configuration;
 9
 10public interface IEmailConfigurationProvider
 11{
 12    Email? GetEmailConfiguration(IConfiguration configuration);
 13}
 14
 15public class EmailConfigurationProvider(IConnectionFactory connectionFactory) : IEmailConfigurationProvider
 16{
 17    public Email? GetEmailConfiguration(IConfiguration configuration)
 018    {
 019        var connectionString = configuration.GetConnectionString(ConnectionStrings.GpConnectAnalytics) ??
 020                               throw new InvalidOperationException("connection string cannot be null at this point.");
 21
 022        using var sqlConnection = connectionFactory.CreateConnection(connectionString);
 23
 024        IEnumerable<Email?> result = sqlConnection.Query<Email>("[Configuration].[GetEmailConfiguration]",
 025            commandType: CommandType.StoredProcedure);
 26
 027        return result.FirstOrDefault();
 028    }
 29}
+
+
+
+ \ No newline at end of file diff --git a/source/coverage/Functions_ExecuteImportByTrigger.html b/source/coverage/Functions_ExecuteImportByTrigger.html new file mode 100644 index 0000000..6476c6f --- /dev/null +++ b/source/coverage/Functions_ExecuteImportByTrigger.html @@ -0,0 +1,189 @@ + + + + + + + +Functions.ExecuteImportByTrigger - Coverage Report + +
+

< Summary

+
+
+
Information
+
+
+ + + + + + + + + + + + + +
Class:Functions.ExecuteImportByTrigger
Assembly:Functions
File(s):/Users/griordan/git/gpconnect-analytics/source/Functions/ExecuteImportByTrigger.cs
+
+
+
+
+
+
+
Line coverage
+
+
100%
+
+ + + + + + + + + + + + + + + + + + + + + +
Covered lines:3
Uncovered lines:0
Coverable lines:3
Total lines:16
Line coverage:100%
+
+
+
+
+
Branch coverage
+
+
N/A
+
+ + + + + + + + + + + + + +
Covered branches:0
Total branches:0
Branch coverage:N/A
+
+
+
+
+
Method coverage
+
+
+

Feature is only available for sponsors

+Upgrade to PRO version +
+
+
+
+

Metrics

+
+ +++++++ + + + + +
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
Run()100%11100%
+
+

File(s)

+

/Users/griordan/git/gpconnect-analytics/source/Functions/ExecuteImportByTrigger.cs

+
+ + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using Core.DTOs.Response.Queue;
 2using Functions.Services.Interfaces;
 3using Microsoft.Azure.Functions.Worker;
 4using Microsoft.Extensions.Logging;
 5
 6namespace Functions
 7{
 8    public class ExecuteImportByTrigger(IImportService importService)
 9    {
 10        [Function("ExecuteImportByTrigger")]
 11        public async Task Run([QueueTrigger("%QueueName%")] Message queueItem, ILogger log)
 212        {
 213            await importService.InstallData(queueItem);
 214        }
 15    }
 16}
+
+
+
+
+

Methods/Properties

+Run()
+
+
+ \ No newline at end of file diff --git a/source/coverage/Functions_FileService.html b/source/coverage/Functions_FileService.html new file mode 100644 index 0000000..3f1e038 --- /dev/null +++ b/source/coverage/Functions_FileService.html @@ -0,0 +1,192 @@ + + + + + + + +Functions.Services.FileService - Coverage Report + +
+

< Summary

+
+
+
Information
+
+
+ + + + + + + + + + + + + +
Class:Functions.Services.FileService
Assembly:Functions
File(s):/Users/griordan/git/gpconnect-analytics/source/Functions/Services/FileService.cs
+
+
+
+
+
+
+
Line coverage
+
+
100%
+
+ + + + + + + + + + + + + + + + + + + + + +
Covered lines:8
Uncovered lines:0
Coverable lines:8
Total lines:19
Line coverage:100%
+
+
+
+
+
Branch coverage
+
+
N/A
+
+ + + + + + + + + + + + + +
Covered branches:0
Total branches:0
Branch coverage:N/A
+
+
+
+
+
Method coverage
+
+
+

Feature is only available for sponsors

+Upgrade to PRO version +
+
+
+
+

Metrics

+
+ +++++++ + + + + +
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
ApiReaderAddFile()100%11100%
+
+

File(s)

+

/Users/griordan/git/gpconnect-analytics/source/Functions/Services/FileService.cs

+
+ + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using Core.Services.Interfaces;
 2using Dapper;
 3using Functions.Services.Interfaces;
 4
 5namespace Functions.Services;
 6
 7public class FileService(IDataService dataService) : IFileService
 8{
 9    public async Task<int> ApiReaderAddFile(int fileTypeId, string filePath, bool overrideFile)
 110    {
 11        const string procedureName = "ApiReader.AddFile";
 112        var parameters = new DynamicParameters();
 113        parameters.Add("@FileTypeId", fileTypeId);
 114        parameters.Add("@FilePath", filePath);
 115        parameters.Add("@Override", overrideFile);
 116        var result = await dataService.ExecuteStoredProcedure(procedureName, parameters);
 117        return result;
 118    }
 19}
+
+
+
+
+

Methods/Properties

+ApiReaderAddFile()
+
+
+ \ No newline at end of file diff --git a/source/coverage/Functions_FunctionExecutorAutoStartup.html b/source/coverage/Functions_FunctionExecutorAutoStartup.html new file mode 100644 index 0000000..e6701d1 --- /dev/null +++ b/source/coverage/Functions_FunctionExecutorAutoStartup.html @@ -0,0 +1,167 @@ + + + + + + + +Functions.FunctionExecutorAutoStartup - Coverage Report + +
+

< Summary

+ +
+
+
Line coverage
+
+
0%
+
+ + + + + + + + + + + + + + + + + + + + + +
Covered lines:0
Uncovered lines:3
Coverable lines:3
Total lines:164
Line coverage:0%
+
+
+
+
+
Branch coverage
+
+
N/A
+
+ + + + + + + + + + + + + +
Covered branches:0
Total branches:0
Branch coverage:N/A
+
+
+
+
+
Method coverage
+
+
+

Feature is only available for sponsors

+Upgrade to PRO version +
+
+
+
+

Metrics

+
+ +++++++ + + + + +
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
Configure(...)100%210%
+
+

File(s)

+

/Users/griordan/git/gpconnect-analytics/source/Functions/Microsoft.Azure.Functions.Worker.Sdk.Generators/Microsoft.Azure.Functions.Worker.Sdk.Generators.FunctionExecutorGenerator/GeneratedFunctionExecutor.g.cs

+

File '/Users/griordan/git/gpconnect-analytics/source/Functions/Microsoft.Azure.Functions.Worker.Sdk.Generators/Microsoft.Azure.Functions.Worker.Sdk.Generators.FunctionExecutorGenerator/GeneratedFunctionExecutor.g.cs' does not exist (any more).

+
+
+ \ No newline at end of file diff --git a/source/coverage/Functions_FunctionExecutorHostBuilderExtensions.html b/source/coverage/Functions_FunctionExecutorHostBuilderExtensions.html new file mode 100644 index 0000000..ed2e3e0 --- /dev/null +++ b/source/coverage/Functions_FunctionExecutorHostBuilderExtensions.html @@ -0,0 +1,167 @@ + + + + + + + +Functions.FunctionExecutorHostBuilderExtensions - Coverage Report + +
+

< Summary

+ +
+
+
Line coverage
+
+
0%
+
+ + + + + + + + + + + + + + + + + + + + + +
Covered lines:0
Uncovered lines:6
Coverable lines:6
Total lines:149
Line coverage:0%
+
+
+
+
+
Branch coverage
+
+
N/A
+
+ + + + + + + + + + + + + +
Covered branches:0
Total branches:0
Branch coverage:N/A
+
+
+
+
+
Method coverage
+
+
+

Feature is only available for sponsors

+Upgrade to PRO version +
+
+
+
+

Metrics

+
+ +++++++ + + + + +
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
ConfigureGeneratedFunctionExecutor(...)100%210%
+
+

File(s)

+

/Users/griordan/git/gpconnect-analytics/source/Functions/Microsoft.Azure.Functions.Worker.Sdk.Generators/Microsoft.Azure.Functions.Worker.Sdk.Generators.FunctionExecutorGenerator/GeneratedFunctionExecutor.g.cs

+

File '/Users/griordan/git/gpconnect-analytics/source/Functions/Microsoft.Azure.Functions.Worker.Sdk.Generators/Microsoft.Azure.Functions.Worker.Sdk.Generators.FunctionExecutorGenerator/GeneratedFunctionExecutor.g.cs' does not exist (any more).

+
+
+ \ No newline at end of file diff --git a/source/coverage/Functions_FunctionMetadataProviderAutoStartup.html b/source/coverage/Functions_FunctionMetadataProviderAutoStartup.html new file mode 100644 index 0000000..1b59ce5 --- /dev/null +++ b/source/coverage/Functions_FunctionMetadataProviderAutoStartup.html @@ -0,0 +1,167 @@ + + + + + + + +Functions.FunctionMetadataProviderAutoStartup - Coverage Report + +
+

< Summary

+ +
+
+
Line coverage
+
+
0%
+
+ + + + + + + + + + + + + + + + + + + + + +
Covered lines:0
Uncovered lines:3
Coverable lines:3
Total lines:226
Line coverage:0%
+
+
+
+
+
Branch coverage
+
+
N/A
+
+ + + + + + + + + + + + + +
Covered branches:0
Total branches:0
Branch coverage:N/A
+
+
+
+
+
Method coverage
+
+
+

Feature is only available for sponsors

+Upgrade to PRO version +
+
+
+
+

Metrics

+
+ +++++++ + + + + +
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
Configure(...)100%210%
+
+

File(s)

+

/Users/griordan/git/gpconnect-analytics/source/Functions/Microsoft.Azure.Functions.Worker.Sdk.Generators/Microsoft.Azure.Functions.Worker.Sdk.Generators.FunctionMetadataProviderGenerator/GeneratedFunctionMetadataProvider.g.cs

+

File '/Users/griordan/git/gpconnect-analytics/source/Functions/Microsoft.Azure.Functions.Worker.Sdk.Generators/Microsoft.Azure.Functions.Worker.Sdk.Generators.FunctionMetadataProviderGenerator/GeneratedFunctionMetadataProvider.g.cs' does not exist (any more).

+
+
+ \ No newline at end of file diff --git a/source/coverage/Functions_GeneratedFunctionMetadataProvider.html b/source/coverage/Functions_GeneratedFunctionMetadataProvider.html new file mode 100644 index 0000000..00bd679 --- /dev/null +++ b/source/coverage/Functions_GeneratedFunctionMetadataProvider.html @@ -0,0 +1,167 @@ + + + + + + + +Functions.GeneratedFunctionMetadataProvider - Coverage Report + +
+

< Summary

+ +
+
+
Line coverage
+
+
0%
+
+ + + + + + + + + + + + + + + + + + + + + +
Covered lines:0
Uncovered lines:155
Coverable lines:155
Total lines:192
Line coverage:0%
+
+
+
+
+
Branch coverage
+
+
N/A
+
+ + + + + + + + + + + + + +
Covered branches:0
Total branches:0
Branch coverage:N/A
+
+
+
+
+
Method coverage
+
+
+

Feature is only available for sponsors

+Upgrade to PRO version +
+
+
+
+

Metrics

+
+ +++++++ + + + + +
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
GetFunctionMetadataAsync(...)100%210%
+
+

File(s)

+

/Users/griordan/git/gpconnect-analytics/source/Functions/Microsoft.Azure.Functions.Worker.Sdk.Generators/Microsoft.Azure.Functions.Worker.Sdk.Generators.FunctionMetadataProviderGenerator/GeneratedFunctionMetadataProvider.g.cs

+

File '/Users/griordan/git/gpconnect-analytics/source/Functions/Microsoft.Azure.Functions.Worker.Sdk.Generators/Microsoft.Azure.Functions.Worker.Sdk.Generators.FunctionMetadataProviderGenerator/GeneratedFunctionMetadataProvider.g.cs' does not exist (any more).

+
+
+ +
+ \ No newline at end of file diff --git a/source/coverage/Functions_GetDataFromApiByDateRange.html b/source/coverage/Functions_GetDataFromApiByDateRange.html new file mode 100644 index 0000000..85b9a32 --- /dev/null +++ b/source/coverage/Functions_GetDataFromApiByDateRange.html @@ -0,0 +1,262 @@ + + + + + + + +Functions.GetDataFromApiByDateRange - Coverage Report + +
+

< Summary

+
+
+
Information
+
+
+ + + + + + + + + + + + + +
Class:Functions.GetDataFromApiByDateRange
Assembly:Functions
File(s):/Users/griordan/git/gpconnect-analytics/source/Functions/GetDataFromApiByDateRange.cs
+
+
+
+
+
+
+
Line coverage
+
+
60%
+
+ + + + + + + + + + + + + + + + + + + + + +
Covered lines:27
Uncovered lines:18
Coverable lines:45
Total lines:85
Line coverage:60%
+
+
+
+
+
Branch coverage
+
+
N/A
+
+ + + + + + + + + + + + + +
Covered branches:0
Total branches:0
Branch coverage:N/A
+
+
+
+
+
Method coverage
+
+
+

Feature is only available for sponsors

+Upgrade to PRO version +
+
+
+
+

Metrics

+
+ +++++++ + + + + + + +
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
GetDataFromSspTransByDateRange()100%1160%
GetDataFromMeshTransByDateRange()100%1160%
GetDataFromAsidLookupByDateRange()100%1160%
+
+

File(s)

+

/Users/griordan/git/gpconnect-analytics/source/Functions/GetDataFromApiByDateRange.cs

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System.Net;
 2using Core.Helpers;
 3using Functions.Services.Interfaces;
 4using Microsoft.Azure.Functions.Worker;
 5using Microsoft.Azure.Functions.Worker.Http;
 6using Microsoft.Extensions.Logging;
 7
 8namespace Functions
 9{
 10    public class GetDataFromApiByDateRange(IBatchService batchService, ILogger log)
 11    {
 12        [Function("GetDataFromApiByDateRangeSspTrans")]
 13        public async Task<HttpResponseData> GetDataFromSspTransByDateRange(
 14            [HttpTrigger(AuthorizationLevel.Function, "GET", Route = null)]
 15            HttpRequestData req)
 116        {
 17            try
 118            {
 119                var startDate = req.Query["StartDate"];
 120                var endDate = req.Query["EndDate"];
 121                var rows = await batchService.StartBatchDownloadAsync(FileTypes.ssptrans, startDate, endDate);
 22
 23
 124                var response = req.CreateResponse(HttpStatusCode.OK);
 125                await response.WriteStringAsync($"Batch Download successful: {rows} requests processed");
 126                return response;
 27            }
 028            catch (Exception ex)
 029            {
 030                log.LogError(ex, "Error starting batch download for SSP Trans");
 031                var response = req.CreateResponse(HttpStatusCode.InternalServerError);
 032                await response.WriteStringAsync("Failed to download - see logs");
 033                return response;
 34            }
 135        }
 36
 37        [Function("GetDataFromApiByDateRangeMeshTrans")]
 38        public async Task<HttpResponseData> GetDataFromMeshTransByDateRange(
 39            [HttpTrigger(AuthorizationLevel.Function, "GET", Route = null)]
 40            HttpRequestData req)
 141        {
 42            try
 143            {
 144                var startDate = req.Query["StartDate"];
 145                var endDate = req.Query["EndDate"];
 146                var processed = await batchService.StartBatchDownloadAsync(FileTypes.meshtrans, startDate, endDate);
 47
 148                var response = req.CreateResponse(HttpStatusCode.OK);
 149                await response.WriteStringAsync($"Batch Download successful: {processed} requests processed");
 150                return response;
 51            }
 052            catch (Exception ex)
 053            {
 054                log.LogError(ex, "Error starting batch download for Mesh Trans");
 055                var response = req.CreateResponse(HttpStatusCode.InternalServerError);
 056                await response.WriteStringAsync("Failed to download - see logs");
 057                return response;
 58            }
 159        }
 60
 61        [Function("GetDataFromApiByDateRangeAsidLookup")]
 62        public async Task<HttpResponseData> GetDataFromAsidLookupByDateRange(
 63            [HttpTrigger(AuthorizationLevel.Function, "GET", Route = null)]
 64            HttpRequestData req)
 165        {
 66            try
 167            {
 168                var startDate = req.Query["StartDate"];
 169                var endDate = req.Query["EndDate"];
 170                var processed = await batchService.StartBatchDownloadAsync(FileTypes.asidlookup, startDate, endDate);
 71
 172                var response = req.CreateResponse(HttpStatusCode.OK);
 173                await response.WriteStringAsync($"Batch Download successful: {processed} requests processed");
 174                return response;
 75            }
 076            catch (Exception ex)
 077            {
 078                log.LogError(ex, "Error starting batch download for Asid Lookup");
 079                var response = req.CreateResponse(HttpStatusCode.InternalServerError);
 080                await response.WriteStringAsync("Failed to download - see logs");
 081                return response;
 82            }
 183        }
 84    }
 85}
+
+
+
+ \ No newline at end of file diff --git a/source/coverage/Functions_GetDataFromApiByTrigger.html b/source/coverage/Functions_GetDataFromApiByTrigger.html new file mode 100644 index 0000000..b53eb9a --- /dev/null +++ b/source/coverage/Functions_GetDataFromApiByTrigger.html @@ -0,0 +1,211 @@ + + + + + + + +Functions.GetDataFromApiByTrigger - Coverage Report + +
+

< Summary

+
+
+
Information
+
+
+ + + + + + + + + + + + + +
Class:Functions.GetDataFromApiByTrigger
Assembly:Functions
File(s):/Users/griordan/git/gpconnect-analytics/source/Functions/GetDataFromApiByTrigger.cs
+
+
+
+
+
+
+
Line coverage
+
+
100%
+
+ + + + + + + + + + + + + + + + + + + + + +
Covered lines:9
Uncovered lines:0
Coverable lines:9
Total lines:34
Line coverage:100%
+
+
+
+
+
Branch coverage
+
+
N/A
+
+ + + + + + + + + + + + + +
Covered branches:0
Total branches:0
Branch coverage:N/A
+
+
+
+
+
Method coverage
+
+
+

Feature is only available for sponsors

+Upgrade to PRO version +
+
+
+
+

Metrics

+
+ +++++++ + + + + + + +
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
GetDataFromAsidLookup()100%11100%
GetDataFromSspTrans()100%11100%
GetDataFromMeshTrans()100%11100%
+
+

File(s)

+

/Users/griordan/git/gpconnect-analytics/source/Functions/GetDataFromApiByTrigger.cs

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using Core.Helpers;
 2using Functions.Services.Interfaces;
 3using Microsoft.Azure.Functions.Worker;
 4using Microsoft.Extensions.Logging;
 5
 6namespace Functions
 7{
 8    public class GetDataFromApiByTrigger(IBatchService batchService, ILogger log)
 9    {
 10        [Function("GetDataFromApiByTriggerAsidLookup")]
 11        public async Task GetDataFromAsidLookup(
 12            [TimerTrigger("%GetDataFromApiByTriggerAsidLookupSchedule%", RunOnStartup = false)]
 13            TimerInfo myTimer)
 114        {
 115            await batchService.StartBatchDownloadForTodayAsync(FileTypes.asidlookup);
 116        }
 17
 18        [Function("GetDataFromApiByTriggerSspTrans")]
 19        public async Task GetDataFromSspTrans(
 20            [TimerTrigger("%GetDataFromApiByTriggerSspTransSchedule%", RunOnStartup = false)]
 21            TimerInfo myTimer)
 122        {
 123            await batchService.StartBatchDownloadForTodayAsync(FileTypes.ssptrans);
 124        }
 25
 26        [Function("GetDataFromApiByTriggerMeshTrans")]
 27        public async Task GetDataFromMeshTrans(
 28            [TimerTrigger("%GetDataFromApiByTriggerMeshTransSchedule%", RunOnStartup = false)]
 29            TimerInfo myTimer)
 130        {
 131            await batchService.StartBatchDownloadForTodayAsync(FileTypes.meshtrans);
 132        }
 33    }
 34}
+
+
+
+ \ No newline at end of file diff --git a/source/coverage/Functions_GetDataFromApiManual.html b/source/coverage/Functions_GetDataFromApiManual.html new file mode 100644 index 0000000..2d4a269 --- /dev/null +++ b/source/coverage/Functions_GetDataFromApiManual.html @@ -0,0 +1,215 @@ + + + + + + + +Functions.GetDataFromApiManual - Coverage Report + +
+

< Summary

+
+
+
Information
+
+
+ + + + + + + + + + + + + +
Class:Functions.GetDataFromApiManual
Assembly:Functions
File(s):/Users/griordan/git/gpconnect-analytics/source/Functions/GetDataFromApiManual.cs
+
+
+
+
+
+
+
Line coverage
+
+
100%
+
+ + + + + + + + + + + + + + + + + + + + + +
Covered lines:21
Uncovered lines:0
Coverable lines:21
Total lines:42
Line coverage:100%
+
+
+
+
+
Branch coverage
+
+
100%
+
+ + + + + + + + + + + + + +
Covered branches:2
Total branches:2
Branch coverage:100%
+
+
+
+
+
Method coverage
+
+
+

Feature is only available for sponsors

+Upgrade to PRO version +
+
+
+
+

Metrics

+
+ +++++++ + + + + +
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
AddDownloadedFile()100%22100%
+
+

File(s)

+

/Users/griordan/git/gpconnect-analytics/source/Functions/GetDataFromApiManual.cs

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System.Net;
 2using Functions.Services.Interfaces;
 3using Microsoft.Azure.Functions.Worker;
 4using Microsoft.Azure.Functions.Worker.Http;
 5using Microsoft.Extensions.Logging;
 6
 7namespace Functions
 8{
 9    public class GetDataFromApiManual(IImportService importService, ILogger log)
 10    {
 11        [Function("GetDataFromApiManual")]
 12        public async Task<HttpResponseData> AddDownloadedFile(
 13            [HttpTrigger(AuthorizationLevel.Function, "GET", Route = null)]
 14            HttpRequestData req)
 415        {
 416            var response = req.CreateResponse();
 417            response.Headers.Add("Content-Type", "application/text");
 18            try
 419            {
 420                var filePath = req.Query["FilePath"];
 421                if (string.IsNullOrEmpty(filePath))
 122                {
 123                    response.StatusCode = HttpStatusCode.BadRequest;
 124                    await response.WriteStringAsync("Filepath missing");
 125                    return response;
 26                }
 27
 328                await importService.AddDownloadedFileManually(filePath);
 129                response.StatusCode = HttpStatusCode.OK;
 130                await response.WriteStringAsync("Successfully added files");
 131                return response;
 32            }
 233            catch (Exception ex)
 234            {
 235                log.LogError(ex, $"Error adding downloaded file: {ex.Message}");
 236                response.StatusCode = HttpStatusCode.InternalServerError;
 237                await response.WriteStringAsync("Something went wrong - see error logs for more details");
 238                return response;
 39            }
 440        }
 41    }
 42}
+
+
+
+
+

Methods/Properties

+AddDownloadedFile()
+
+
+ \ No newline at end of file diff --git a/source/coverage/Functions_GetDataFromApiToday.html b/source/coverage/Functions_GetDataFromApiToday.html new file mode 100644 index 0000000..f1873fa --- /dev/null +++ b/source/coverage/Functions_GetDataFromApiToday.html @@ -0,0 +1,275 @@ + + + + + + + +Functions.GetDataFromApiToday - Coverage Report + +
+

< Summary

+
+
+
Information
+
+
+ + + + + + + + + + + + + +
Class:Functions.GetDataFromApiToday
Assembly:Functions
File(s):/Users/griordan/git/gpconnect-analytics/source/Functions/GetDataFromApiToday.cs
+
+
+
+
+
+
+
Line coverage
+
+
100%
+
+ + + + + + + + + + + + + + + + + + + + + +
Covered lines:54
Uncovered lines:0
Coverable lines:54
Total lines:98
Line coverage:100%
+
+
+
+
+
Branch coverage
+
+
N/A
+
+ + + + + + + + + + + + + +
Covered branches:0
Total branches:0
Branch coverage:N/A
+
+
+
+
+
Method coverage
+
+
+

Feature is only available for sponsors

+Upgrade to PRO version +
+
+
+
+

Metrics

+
+ +++++++ + + + + + + +
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
GetDataFromSspTransByDateRange()100%11100%
GetDataFromMeshTransByDateRange()100%11100%
GetDataFromAsidLookupByDateRange()100%11100%
+
+

File(s)

+

/Users/griordan/git/gpconnect-analytics/source/Functions/GetDataFromApiToday.cs

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System.Net;
 2using Core.Helpers;
 3using Functions.Services.Interfaces;
 4using Microsoft.Azure.Functions.Worker;
 5using Microsoft.Azure.Functions.Worker.Http;
 6using Microsoft.Extensions.Logging;
 7
 8namespace Functions
 9{
 10    public class GetDataFromApiToday(IBatchService batchService, ILogger log)
 11    {
 12        [Function("GetDataFromApiTodaySspTrans")]
 13        public async Task<HttpResponseData> GetDataFromSspTransByDateRange(
 14            [HttpTrigger(AuthorizationLevel.Function, "GET", Route = null)]
 15            HttpRequestData req)
 316        {
 317            var response = req.CreateResponse();
 318            response.Headers.Add("Content-Type", "application/text");
 19
 20
 321            var affectedCount = 0;
 22            try
 323            {
 324                affectedCount = await batchService.StartBatchDownloadForTodayAsync(FileTypes.ssptrans);
 125            }
 226            catch (Exception ex)
 227            {
 228                log.LogError(ex, "An error occurred during batch download when processing urls");
 229                response.StatusCode = HttpStatusCode.InternalServerError;
 230                await response.WriteStringAsync(
 231                    $"An error occurred whilst processing batch download - see logs for more details");
 32
 233                return response;
 34            }
 35
 136            response.StatusCode = HttpStatusCode.OK;
 137            await response.WriteStringAsync($"Processed {affectedCount} requests");
 138            return response;
 339        }
 40
 41        [Function("GetDataFromApiTodayMeshTrans")]
 42        public async Task<HttpResponseData> GetDataFromMeshTransByDateRange(
 43            [HttpTrigger(AuthorizationLevel.Function, "GET", Route = null)]
 44            HttpRequestData req)
 345        {
 346            var response = req.CreateResponse();
 347            response.Headers.Add("Content-Type", "application/text");
 48
 49
 350            var affectedCount = 0;
 51            try
 352            {
 353                affectedCount = await batchService.StartBatchDownloadForTodayAsync(FileTypes.meshtrans);
 154            }
 255            catch (Exception ex)
 256            {
 257                log.LogError(ex, "An error occurred during batch download when processing urls");
 258                response.StatusCode = HttpStatusCode.InternalServerError;
 259                await response.WriteStringAsync(
 260                    $"An error occurred whilst processing batch download - see logs for more details");
 61
 262                return response;
 63            }
 64
 165            response.StatusCode = HttpStatusCode.OK;
 166            await response.WriteStringAsync($"Processed {affectedCount} requests");
 167            return response;
 368        }
 69
 70        [Function("GetDataFromApiTodayAsidLookup")]
 71        public async Task<HttpResponseData> GetDataFromAsidLookupByDateRange(
 72            [HttpTrigger(AuthorizationLevel.Function, "GET", Route = null)]
 73            HttpRequestData req)
 374        {
 375            var response = req.CreateResponse();
 376            response.Headers.Add("Content-Type", "application/text");
 377            var affectedCount = 0;
 78            try
 379            {
 380                affectedCount = await batchService.StartBatchDownloadForTodayAsync(FileTypes.asidlookup);
 181            }
 282            catch (Exception ex)
 283            {
 284                log.LogError(ex, "An error occurred during batch download when processing urls");
 285                response.StatusCode = HttpStatusCode.InternalServerError;
 286                await response.WriteStringAsync(
 287                    $"An error occurred whilst processing batch download - see logs for more details");
 88
 89
 290                return response;
 91            }
 92
 193            response.StatusCode = HttpStatusCode.OK;
 194            await response.WriteStringAsync($"Processed {affectedCount} requests");
 195            return response;
 396        }
 97    }
 98}
+
+
+
+ \ No newline at end of file diff --git a/source/coverage/Functions_HttpClientExtensions.html b/source/coverage/Functions_HttpClientExtensions.html new file mode 100644 index 0000000..234c5b9 --- /dev/null +++ b/source/coverage/Functions_HttpClientExtensions.html @@ -0,0 +1,198 @@ + + + + + + + +Functions.Configuration.Infrastructure.HttpClient.HttpClientExtensions - Coverage Report + +
+

< Summary

+
+
+
Information
+
+
+ + + + + + + + + + + + + +
Class:Functions.Configuration.Infrastructure.HttpClient.HttpClientExtensions
Assembly:Functions
File(s):/Users/griordan/git/gpconnect-analytics/source/Functions/Configuration/Infrastructure/HttpClient/HttpClientExtensions.cs
+
+
+
+
+
+
+
Line coverage
+
+
100%
+
+ + + + + + + + + + + + + + + + + + + + + +
Covered lines:12
Uncovered lines:0
Coverable lines:12
Total lines:23
Line coverage:100%
+
+
+
+
+
Branch coverage
+
+
N/A
+
+ + + + + + + + + + + + + +
Covered branches:0
Total branches:0
Branch coverage:N/A
+
+
+
+
+
Method coverage
+
+
+

Feature is only available for sponsors

+Upgrade to PRO version +
+
+
+
+

Metrics

+
+ +++++++ + + + + + +
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
ConfigureHttpClient(...)100%11100%
CreateHttpMessageHandler()100%11100%
+
+

File(s)

+

/Users/griordan/git/gpconnect-analytics/source/Functions/Configuration/Infrastructure/HttpClient/HttpClientExtensions.cs

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System.Net.Http.Headers;
 2using System.Security.Authentication;
 3
 4namespace Functions.Configuration.Infrastructure.HttpClient;
 5
 6public static class HttpClientExtensions
 7{
 8    public static void ConfigureHttpClient(System.Net.Http.HttpClient options)
 19    {
 110        options.Timeout = new TimeSpan(0, 0, 1, 0);
 111        options.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/csv"));
 112        options.DefaultRequestHeaders.CacheControl = new CacheControlHeaderValue { NoCache = true };
 113    }
 14
 15    public static HttpMessageHandler CreateHttpMessageHandler()
 116    {
 117        var httpClientHandler = new HttpClientHandler
 118        {
 119            SslProtocols = SslProtocols.Tls13 | SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls
 120        };
 121        return httpClientHandler;
 122    }
 23}
+
+
+
+ \ No newline at end of file diff --git a/source/coverage/Functions_ImportService.html b/source/coverage/Functions_ImportService.html new file mode 100644 index 0000000..00b6aa4 --- /dev/null +++ b/source/coverage/Functions_ImportService.html @@ -0,0 +1,261 @@ + + + + + + + +Functions.Services.ImportService - Coverage Report + +
+

< Summary

+
+
+
Information
+
+
+ + + + + + + + + + + + + +
Class:Functions.Services.ImportService
Assembly:Functions
File(s):/Users/griordan/git/gpconnect-analytics/source/Functions/Services/ImportService.cs
+
+
+
+
+
+
+
Line coverage
+
+
100%
+
+ + + + + + + + + + + + + + + + + + + + + +
Covered lines:46
Uncovered lines:0
Coverable lines:46
Total lines:84
Line coverage:100%
+
+
+
+
+
Branch coverage
+
+
85%
+
+ + + + + + + + + + + + + +
Covered branches:12
Total branches:14
Branch coverage:85.7%
+
+
+
+
+
Method coverage
+
+
+

Feature is only available for sponsors

+Upgrade to PRO version +
+
+
+
+

Metrics

+
+ +++++++ + + + + + + +
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
AddDownloadedFileManually()100%22100%
AddObjectFileMessage()75%88100%
InstallData()100%44100%
+
+

File(s)

+

/Users/griordan/git/gpconnect-analytics/source/Functions/Services/ImportService.cs

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System.Data;
 2using Core.DTOs.Response.Configuration;
 3using Core.DTOs.Response.Queue;
 4using Core.DTOs.Response.Splunk;
 5using Core.Helpers;
 6using Core.Services.Interfaces;
 7using Dapper;
 8using Functions.Services.Interfaces;
 9using Microsoft.Extensions.Logging;
 10
 11namespace Functions.Services
 12{
 13    public class ImportService(
 14        IConfigurationService configurationService,
 15        IDataService dataService,
 16        IBlobService blobService,
 17        ILogger<ImportService> logger,
 18        IFileService fileService)
 19        : IImportService
 20    {
 21        public async Task AddDownloadedFileManually(string filePath)
 222        {
 223            var fileTypeFromPath = filePath.GetFileType<FileTypes>();
 24
 225            if (fileTypeFromPath == null)
 126            {
 127                throw new ArgumentException("Filepath does not contain vailid file type suffix");
 28            }
 29
 130            var fileType = await configurationService.GetFileType((FileTypes)fileTypeFromPath);
 131            var fileAddedCount =
 132                await fileService.ApiReaderAddFile(fileType.FileTypeId, filePath, true);
 33
 134            await blobService.AddMessageToBlobQueue(fileAddedCount, fileType.FileTypeId, filePath,
 135                true);
 136        }
 37
 38        public async Task AddObjectFileMessage(FileType fileType, ExtractResponse extractResponse)
 539        {
 540            if (extractResponse.ExtractResponseMessage.StatusCode == System.Net.HttpStatusCode.OK)
 241            {
 242                var uploadedBlob = await blobService.AddObjectToBlob(extractResponse);
 243                if (uploadedBlob != null)
 144                {
 145                    var fileAddedCount =
 146                        await fileService.ApiReaderAddFile(fileType.FileTypeId, extractResponse.FilePath, true);
 47
 148                    await blobService.AddMessageToBlobQueue(fileAddedCount, fileType.FileTypeId,
 149                        extractResponse.FilePath,
 150                        true);
 151                }
 252            }
 53            else
 354            {
 355                logger?.LogWarning(extractResponse?.ExtractResponseMessage.ToString());
 356            }
 557        }
 58
 59
 60        public async Task InstallData(Message queueItem)
 161        {
 162            var moreFilesToInstall = true;
 63            const string procedureName = "Import.InstallNextFile";
 164            var parameters = new DynamicParameters();
 165            parameters.Add("@FileTypeId", queueItem.FileTypeId);
 166            if (queueItem.Override)
 167            {
 168                parameters.Add("@Override", queueItem.Override, dbType: DbType.Boolean,
 169                    direction: ParameterDirection.Input);
 170            }
 71
 172            parameters.Add("@MoreFilesToInstall", dbType: DbType.Boolean, direction: ParameterDirection.Output);
 73
 374            while (moreFilesToInstall)
 275            {
 276                logger.LogInformation($"Installing file into database", parameters);
 277                var result = await dataService.ExecuteStoredProcedureWithOutputParameters(procedureName, parameters);
 78
 279                moreFilesToInstall = result.Get<bool>("@MoreFilesToInstall");
 280                logger.LogInformation($"More files to install? {moreFilesToInstall}");
 281            }
 182        }
 83    }
 84}
+
+
+
+ \ No newline at end of file diff --git a/source/coverage/Functions_LoggingExtensions.html b/source/coverage/Functions_LoggingExtensions.html new file mode 100644 index 0000000..ef39463 --- /dev/null +++ b/source/coverage/Functions_LoggingExtensions.html @@ -0,0 +1,368 @@ + + + + + + + +Functions.Configuration.Infrastructure.Logging.LoggingExtensions - Coverage Report + +
+

< Summary

+
+
+
Information
+
+
+ + + + + + + + + + + + + +
Class:Functions.Configuration.Infrastructure.Logging.LoggingExtensions
Assembly:Functions
File(s):/Users/griordan/git/gpconnect-analytics/source/Functions/Configuration/Infrastructure/Logging/LoggingExtensions.cs
+
+
+
+
+
+
+
Line coverage
+
+
0%
+
+ + + + + + + + + + + + + + + + + + + + + +
Covered lines:0
Uncovered lines:130
Coverable lines:130
Total lines:185
Line coverage:0%
+
+
+
+
+
Branch coverage
+
+
0%
+
+ + + + + + + + + + + + + +
Covered branches:0
Total branches:4
Branch coverage:0%
+
+
+
+
+
Method coverage
+
+
+

Feature is only available for sponsors

+Upgrade to PRO version +
+
+
+
+

Metrics

+
+ +++++++ + + + + + + + + + +
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
ConfigureLoggingServices(...)100%210%
AddMailTarget(...)0%2040%
GetExceptionLayout()100%210%
GetEmailConfiguration(...)100%210%
AddDatabaseTarget(...)100%210%
AddConsoleTarget()100%210%
+
+

File(s)

+

/Users/griordan/git/gpconnect-analytics/source/Functions/Configuration/Infrastructure/Logging/LoggingExtensions.cs

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System.Data;
 2using Core.DTOs.Response.Configuration;
 3using Core.Helpers;
 4using Dapper;
 5using Microsoft.Data.SqlClient;
 6using Microsoft.Extensions.Configuration;
 7using Microsoft.Extensions.Logging;
 8using NLog;
 9using NLog.Extensions.Logging;
 10using NLog.Layouts;
 11using NLog.Targets;
 12
 13namespace Functions.Configuration.Infrastructure.Logging
 14{
 15    public static class LoggingExtensions
 16    {
 17        public static ILoggingBuilder ConfigureLoggingServices(
 18            ILoggingBuilder loggingBuilder,
 19            IConfiguration configuration,
 20            IEmailConfigurationProvider emailConfigurationProvider)
 021        {
 22            // Set up NLog
 023            LogManager.Setup().LoadConfigurationFromFile("nlog.config");
 24
 25            // Add NLog to the logging pipeline
 026            loggingBuilder.AddNLog();
 27
 28            // Add custom targets manually (optional)
 029            var nLogConfiguration = new NLog.Config.LoggingConfiguration();
 30
 031            var consoleTarget = AddConsoleTarget();
 032            var databaseTarget = AddDatabaseTarget(configuration);
 033            var mailTarget = AddMailTarget(configuration, emailConfigurationProvider);
 34
 035            nLogConfiguration.Variables.Add("applicationVersion",
 036                ApplicationHelper.ApplicationVersion.GetAssemblyVersion());
 37
 038            nLogConfiguration.AddRule(NLog.LogLevel.Trace, NLog.LogLevel.Fatal, consoleTarget);
 039            nLogConfiguration.AddRule(NLog.LogLevel.Trace, NLog.LogLevel.Fatal, databaseTarget);
 040            nLogConfiguration.AddRule(NLog.LogLevel.Error, NLog.LogLevel.Fatal, mailTarget);
 41
 042            nLogConfiguration.AddTarget(consoleTarget);
 043            nLogConfiguration.AddTarget(databaseTarget);
 044            nLogConfiguration.AddTarget(mailTarget);
 45
 046            return loggingBuilder;
 047        }
 48
 49        private static MailTarget AddMailTarget(IConfiguration configuration,
 50            IEmailConfigurationProvider emailConfigurationProvider)
 051        {
 052            var emailConfiguration = emailConfigurationProvider.GetEmailConfiguration(configuration);
 053            if (emailConfiguration == null)
 054            {
 055                throw new InvalidOperationException("EmailConfiguration cannot be null");
 56            }
 57
 058            var mailTarget = new MailTarget
 059            {
 060                Name = "Mail",
 061                Html = false,
 062                SmtpServer = emailConfiguration.Hostname,
 063                SmtpAuthentication = emailConfiguration.AuthenticationRequired
 064                    ? SmtpAuthenticationMode.Basic
 065                    : SmtpAuthenticationMode.None,
 066                SmtpUserName = emailConfiguration.Username,
 067                SmtpPort = emailConfiguration.Port,
 068                SmtpPassword = emailConfiguration.Password,
 069                To = emailConfiguration.RecipientAddress,
 070                From = emailConfiguration.SenderAddress,
 071                Body = GetExceptionLayout(),
 072                Subject = emailConfiguration.DefaultSubject,
 073                EnableSsl = true,
 074                DeliveryMethod = System.Net.Mail.SmtpDeliveryMethod.Network
 075            };
 076            return mailTarget;
 077        }
 78
 79        private static JsonLayout GetExceptionLayout()
 080        {
 081            var exceptionLayout = new JsonLayout();
 082            exceptionLayout.Attributes.Add(new JsonAttribute("type", "${exception:format=Type}"));
 083            exceptionLayout.Attributes.Add(new JsonAttribute("message", "${exception:format=Message}"));
 084            exceptionLayout.Attributes.Add(new JsonAttribute("stacktrace", "${exception:format=StackTrace}"));
 085            exceptionLayout.Attributes.Add(new JsonAttribute("innerException", new JsonLayout
 086            {
 087                Attributes =
 088                {
 089                    new JsonAttribute("type",
 090                        "${exception:format=:innerFormat=Type:MaxInnerExceptionLevel=1:InnerExceptionSeparator=}"),
 091                    new JsonAttribute("message",
 092                        "${exception:format=:innerFormat=Message:MaxInnerExceptionLevel=1:InnerExceptionSeparator=}"),
 093                    new JsonAttribute("stacktrace",
 094                        "${exception:format=:innerFormat=StackTrace:MaxInnerExceptionLevel=1:InnerExceptionSeparator=}")
 095                },
 096                RenderEmptyObject = false
 097            }, false));
 098            return exceptionLayout;
 099        }
 100
 101        private static Email? GetEmailConfiguration(IConfiguration configuration)
 0102        {
 0103            using var sqlConnection =
 0104                new SqlConnection(configuration.GetConnectionString(ConnectionStrings.GpConnectAnalytics));
 105
 0106            IEnumerable<Email?> result = sqlConnection.Query<Email>("[Configuration].[GetEmailConfiguration]",
 0107                commandType: CommandType.StoredProcedure);
 108
 0109            return result.FirstOrDefault();
 0110        }
 111
 112        private static DatabaseTarget AddDatabaseTarget(IConfiguration configuration)
 0113        {
 0114            var databaseTarget = new DatabaseTarget
 0115            {
 0116                Name = "Database",
 0117                ConnectionString = configuration.GetConnectionString(ConnectionStrings.GpConnectAnalytics),
 0118                CommandType = CommandType.StoredProcedure,
 0119                CommandText = "Logging.WriteLog",
 0120                DBProvider = "System.Data.SqlClient"
 0121            };
 122
 0123            databaseTarget.Parameters.Add(new DatabaseParameterInfo
 0124            {
 0125                Name = "@Application",
 0126                Layout = "${var:applicationVersion}",
 0127                DbType = DbType.String.ToString()
 0128            });
 129
 0130            databaseTarget.Parameters.Add(new DatabaseParameterInfo
 0131            {
 0132                Name = "@Logged",
 0133                Layout = "${date}",
 0134                DbType = DbType.DateTime.ToString()
 0135            });
 136
 0137            databaseTarget.Parameters.Add(new DatabaseParameterInfo
 0138            {
 0139                Name = "@Level",
 0140                Layout = "${level:uppercase=true}",
 0141                DbType = DbType.String.ToString()
 0142            });
 143
 0144            databaseTarget.Parameters.Add(new DatabaseParameterInfo
 0145            {
 0146                Name = "@Message",
 0147                Layout = "${message}",
 0148                DbType = DbType.String.ToString()
 0149            });
 150
 0151            databaseTarget.Parameters.Add(new DatabaseParameterInfo
 0152            {
 0153                Name = "@Logger",
 0154                Layout = "${logger}",
 0155                DbType = DbType.String.ToString()
 0156            });
 157
 0158            databaseTarget.Parameters.Add(new DatabaseParameterInfo
 0159            {
 0160                Name = "@Callsite",
 0161                Layout = "${callsite:filename=true}",
 0162                DbType = DbType.String.ToString()
 0163            });
 164
 0165            databaseTarget.Parameters.Add(new DatabaseParameterInfo
 0166            {
 0167                Name = "@Exception",
 0168                Layout = GetExceptionLayout(),
 0169                DbType = DbType.String.ToString()
 0170            });
 171
 0172            return databaseTarget;
 0173        }
 174
 175        private static ConsoleTarget AddConsoleTarget()
 0176        {
 0177            var consoleTarget = new ConsoleTarget
 0178            {
 0179                Name = "Console",
 0180                Layout = "${date}|${message}|${exception:format=stackTrace}"
 0181            };
 0182            return consoleTarget;
 0183        }
 184    }
 185}
+
+
+
+ \ No newline at end of file diff --git a/source/coverage/Functions_LoggingService.html b/source/coverage/Functions_LoggingService.html new file mode 100644 index 0000000..58b08f3 --- /dev/null +++ b/source/coverage/Functions_LoggingService.html @@ -0,0 +1,196 @@ + + + + + + + +Functions.Services.LoggingService - Coverage Report + +
+

< Summary

+
+
+
Information
+
+
+ + + + + + + + + + + + + +
Class:Functions.Services.LoggingService
Assembly:Functions
File(s):/Users/griordan/git/gpconnect-analytics/source/Functions/Services/LoggingService.cs
+
+
+
+
+
+
+
Line coverage
+
+
0%
+
+ + + + + + + + + + + + + + + + + + + + + +
Covered lines:0
Uncovered lines:7
Coverable lines:7
Total lines:21
Line coverage:0%
+
+
+
+
+
Branch coverage
+
+
N/A
+
+ + + + + + + + + + + + + +
Covered branches:0
Total branches:0
Branch coverage:N/A
+
+
+
+
+
Method coverage
+
+
+

Feature is only available for sponsors

+Upgrade to PRO version +
+
+
+
+

Metrics

+
+ +++++++ + + + + + +
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%210%
PurgeErrorLog()100%210%
+
+

File(s)

+

/Users/griordan/git/gpconnect-analytics/source/Functions/Services/LoggingService.cs

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using Core.Services.Interfaces;
 2using Functions.Services.Interfaces;
 3
 4namespace Functions.Services
 5{
 6    public class LoggingService : ILoggingService
 7    {
 8        private readonly IDataService _dataService;
 9
 10        public LoggingService(IDataService dataService)
 011        {
 012            _dataService = dataService;
 013        }
 14
 15        public async Task PurgeErrorLog()
 016        {
 017            var procedureName = "Logging.PurgeErrorLog";
 018            await _dataService.ExecuteStoredProcedure(procedureName);
 019        }
 20    }
 21}
+
+
+
+ \ No newline at end of file diff --git a/source/coverage/Functions_MappingExtensions.html b/source/coverage/Functions_MappingExtensions.html new file mode 100644 index 0000000..68a5307 --- /dev/null +++ b/source/coverage/Functions_MappingExtensions.html @@ -0,0 +1,186 @@ + + + + + + + +Functions.Configuration.Infrastructure.Mapping.MappingExtensions - Coverage Report + +
+

< Summary

+
+
+
Information
+
+
+ + + + + + + + + + + + + +
Class:Functions.Configuration.Infrastructure.Mapping.MappingExtensions
Assembly:Functions
File(s):/Users/griordan/git/gpconnect-analytics/source/Functions/Configuration/Infrastructure/Mapping/MappingExtensions.cs
+
+
+
+
+
+
+
Line coverage
+
+
0%
+
+ + + + + + + + + + + + + + + + + + + + + +
Covered lines:0
Uncovered lines:3
Coverable lines:3
Total lines:13
Line coverage:0%
+
+
+
+
+
Branch coverage
+
+
N/A
+
+ + + + + + + + + + + + + +
Covered branches:0
Total branches:0
Branch coverage:N/A
+
+
+
+
+
Method coverage
+
+
+

Feature is only available for sponsors

+Upgrade to PRO version +
+
+
+
+

Metrics

+
+ +++++++ + + + + +
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
ConfigureMappingServices()100%210%
+
+

File(s)

+

/Users/griordan/git/gpconnect-analytics/source/Functions/Configuration/Infrastructure/Mapping/MappingExtensions.cs

+
+ + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using Core.Mapping;
 2using Dapper.FluentMap;
 3
 4namespace Functions.Configuration.Infrastructure.Mapping
 5{
 6    public static class MappingExtensions
 7    {
 8        public static void ConfigureMappingServices()
 09        {
 010            FluentMapper.Initialize(config => { config.AddMap(new SplunkInstanceMap()); });
 011        }
 12    }
 13}
+
+
+
+
+

Methods/Properties

+ConfigureMappingServices()
+
+
+ \ No newline at end of file diff --git a/source/coverage/Functions_Program.html b/source/coverage/Functions_Program.html new file mode 100644 index 0000000..002fa9b --- /dev/null +++ b/source/coverage/Functions_Program.html @@ -0,0 +1,227 @@ + + + + + + + +Program - Coverage Report + +
+

< Summary

+
+
+
Information
+
+
+ + + + + + + + + + + + + +
Class:Program
Assembly:Functions
File(s):/Users/griordan/git/gpconnect-analytics/source/Functions/Program.cs
+
+
+
+
+
+
+
Line coverage
+
+
0%
+
+ + + + + + + + + + + + + + + + + + + + + +
Covered lines:0
Uncovered lines:37
Coverable lines:37
Total lines:54
Line coverage:0%
+
+
+
+
+
Branch coverage
+
+
N/A
+
+ + + + + + + + + + + + + +
Covered branches:0
Total branches:0
Branch coverage:N/A
+
+
+
+
+
Method coverage
+
+
+

Feature is only available for sponsors

+Upgrade to PRO version +
+
+
+
+

Metrics

+
+ +++++++ + + + + +
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
<Main>$(...)100%210%
+
+

File(s)

+

/Users/griordan/git/gpconnect-analytics/source/Functions/Program.cs

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using Core;
 2using Core.Repositories;
 3using Core.Services.Interfaces;
 4using Functions;
 5using Functions.Configuration;
 6using Functions.Configuration.Infrastructure.HttpClient;
 7using Functions.Configuration.Infrastructure.Logging;
 8using Functions.Configuration.Infrastructure.Mapping;
 9using Functions.Services;
 10using Functions.Services.Interfaces;
 11using Microsoft.Data.SqlClient;
 12using Microsoft.Extensions.DependencyInjection;
 13using Microsoft.Extensions.Hosting;
 14
 15
 016var builder = Host.CreateDefaultBuilder(args)
 017    .ConfigureFunctionsWorkerDefaults()
 018    .ConfigureServices((context, services) =>
 019    {
 020        // Configure your services here
 021        MappingExtensions.ConfigureMappingServices();
 022        services.AddSingleton<ICoreConfigurationService, CoreConfigurationService>();
 023        services.AddScoped<IConfigurationService, ConfigurationService>();
 024        services.AddScoped<IBlobService, BlobService>();
 025        services.AddScoped<IImportService, ImportService>();
 026        services.AddScoped<ISplunkService, SplunkService>();
 027        services.AddScoped<IDataService, DataService>();
 028        services.AddScoped<IBatchService, BatchService>();
 029        services.AddScoped<ILoggingService, LoggingService>();
 030        services.AddScoped<IDapperWrapper, DapperWrapper>();
 031        services.AddScoped<IHierarchyProviderConsumerRepo, HierarchyProviderConsumerRepo>();
 032        services.AddSingleton<IConnectionFactory, SqlConnectionFactory>();
 033        services.AddSingleton<IEmailConfigurationProvider, EmailConfigurationProvider>();
 034        services.AddScoped<ITimeProvider, TimeProvider>();
 035
 036        // Configure logging with email configuration provider
 037        services.AddLogging(loggingBuilder =>
 038        {
 039            var emailProvider = services.BuildServiceProvider().GetRequiredService<IEmailConfigurationProvider>();
 040            LoggingExtensions.ConfigureLoggingServices(loggingBuilder, context.Configuration, emailProvider);
 041        });
 042
 043        // Configure HttpClient
 044        services.AddHttpClient("SplunkApiClient", options =>
 045                HttpClientExtensions
 046                    .ConfigureHttpClient(options))
 047            .ConfigurePrimaryHttpMessageHandler(() =>
 048                HttpClientExtensions
 049                    .CreateHttpMessageHandler());
 050    });
 51
 52
 053var host = builder.Build();
 054host.Run();
+
+
+
+
+

Methods/Properties

+<Main>$(System.String[])
+
+
+ \ No newline at end of file diff --git a/source/coverage/Functions_PurgeErrorLogByTrigger.html b/source/coverage/Functions_PurgeErrorLogByTrigger.html new file mode 100644 index 0000000..572ff12 --- /dev/null +++ b/source/coverage/Functions_PurgeErrorLogByTrigger.html @@ -0,0 +1,189 @@ + + + + + + + +Functions.PurgeErrorLogByTrigger - Coverage Report + +
+

< Summary

+
+
+
Information
+
+
+ + + + + + + + + + + + + +
Class:Functions.PurgeErrorLogByTrigger
Assembly:Functions
File(s):/Users/griordan/git/gpconnect-analytics/source/Functions/PurgeErrorLogByTrigger.cs
+
+
+
+
+
+
+
Line coverage
+
+
100%
+
+ + + + + + + + + + + + + + + + + + + + + +
Covered lines:3
Uncovered lines:0
Coverable lines:3
Total lines:16
Line coverage:100%
+
+
+
+
+
Branch coverage
+
+
N/A
+
+ + + + + + + + + + + + + +
Covered branches:0
Total branches:0
Branch coverage:N/A
+
+
+
+
+
Method coverage
+
+
+

Feature is only available for sponsors

+Upgrade to PRO version +
+
+
+
+

Metrics

+
+ +++++++ + + + + +
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
PurgeErrorLog()100%11100%
+
+

File(s)

+

/Users/griordan/git/gpconnect-analytics/source/Functions/PurgeErrorLogByTrigger.cs

+
+ + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using Functions.Services.Interfaces;
 2using Microsoft.Azure.Functions.Worker;
 3
 4namespace Functions
 5{
 6    public class PurgeErrorLogByTrigger(ILoggingService loggingService)
 7    {
 8        [Function("PurgeErrorLogByTrigger")]
 9        public async Task PurgeErrorLog(
 10            [TimerTrigger("%PurgeErrorLogByTriggerSchedule%", RunOnStartup = false)]
 11            TimerInfo myTimer)
 112        {
 113            await loggingService.PurgeErrorLog();
 114        }
 15    }
 16}
+
+
+
+
+

Methods/Properties

+PurgeErrorLog()
+
+
+ \ No newline at end of file diff --git a/source/coverage/Functions_SplunkService.html b/source/coverage/Functions_SplunkService.html new file mode 100644 index 0000000..f2f731c --- /dev/null +++ b/source/coverage/Functions_SplunkService.html @@ -0,0 +1,366 @@ + + + + + + + +Functions.Services.SplunkService - Coverage Report + +
+

< Summary

+
+
+
Information
+
+
+ + + + + + + + + + + + + +
Class:Functions.Services.SplunkService
Assembly:Functions
File(s):/Users/griordan/git/gpconnect-analytics/source/Functions/Services/SplunkService.cs
+
+
+
+
+
+
+
Line coverage
+
+
78%
+
+ + + + + + + + + + + + + + + + + + + + + +
Covered lines:96
Uncovered lines:26
Coverable lines:122
Total lines:181
Line coverage:78.6%
+
+
+
+
+
Branch coverage
+
+
57%
+
+ + + + + + + + + + + + + +
Covered branches:8
Total branches:14
Branch coverage:57.1%
+
+
+
+
+
Method coverage
+
+
+

Feature is only available for sponsors

+Upgrade to PRO version +
+
+
+
+

Metrics

+
+ +++++++ + + + + + + + + + + +
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
DownloadCSVDateRangeAsync()100%1181.81%
GetSearchResultFromRequestUri()50%2256.09%
ConstructFilePath(...)75%44100%
ExecuteBatchDownloadFromSplunk()50%6676.47%
HasApiTokenExpired(...)100%11100%
FileTypeEnabled(...)50%22100%
+
+

File(s)

+

/Users/griordan/git/gpconnect-analytics/source/Functions/Services/SplunkService.cs

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System.IdentityModel.Tokens.Jwt;
 2using System.Net.Http.Headers;
 3using System.Text;
 4using Core;
 5using Core.DTOs.Request;
 6using Core.DTOs.Response.Configuration;
 7using Core.DTOs.Response.Splunk;
 8using Core.Helpers;
 9using Core.Services.Interfaces;
 10using Functions.Services.Interfaces;
 11using Microsoft.Extensions.Logging;
 12
 13namespace Functions.Services
 14{
 15    public class SplunkService(
 16        IConfigurationService configurationService,
 17        IHttpClientFactory httpClientFactory,
 18        IImportService importService,
 19        ILogger<SplunkService> logger,
 20        ITimeProvider timeProvider)
 21        : ISplunkService
 22    {
 23        private SplunkClient _splunkClient;
 24        private FilePathConstants _filePathConstants;
 725        private Extract _extract = new();
 26
 27        public async Task<ExtractResponse> DownloadCSVDateRangeAsync(FileType fileType, UriRequest uriRequest,
 28            bool isToday)
 629        {
 30            try
 631            {
 632                _filePathConstants = await configurationService.GetFilePathConstants();
 533                var splunkInstance = await configurationService.GetSplunkInstance(SplunkInstances.cloud);
 34
 535                _extract.Override = true;
 536                _extract.QueryFromDate = uriRequest.EarliestDate;
 537                _extract.QueryToDate = uriRequest.LatestDate;
 538                _extract.QueryHour = uriRequest.Hour;
 39
 540                var filePath = ConstructFilePath(splunkInstance, fileType, isToday, true);
 541                var extractResponse = await GetSearchResultFromRequestUri(uriRequest);
 42
 543                extractResponse.FilePath = filePath;
 544                extractResponse.ExtractRequestDetails = _extract;
 45
 546                return extractResponse;
 47            }
 148            catch (TimeoutException timeoutException)
 149            {
 150                logger.LogError(timeoutException, "A timeout error has occurred");
 151                throw;
 52            }
 053            catch (Exception exc)
 054            {
 055                logger.LogError(exc, "An error occurred in trying to execute a GET request");
 056                throw;
 57            }
 558        }
 59
 60        private async Task<ExtractResponse> GetSearchResultFromRequestUri(UriRequest uriRequest)
 561        {
 562            var extractResponseMessage = new ExtractResponse
 563            {
 564                ExtractResponseMessage = new HttpResponseMessage()
 565            };
 66            try
 567            {
 568                _splunkClient = await configurationService.GetSplunkClientConfiguration();
 469                var apiTokenExpiry = HasApiTokenExpired(_splunkClient.ApiToken);
 70
 171                if (!apiTokenExpiry.Item1)
 072                {
 073                    var client = httpClientFactory.CreateClient("SplunkApiClient");
 074                    client.DefaultRequestHeaders.Authorization =
 075                        new AuthenticationHeaderValue("Bearer", _splunkClient.ApiToken);
 076                    client.Timeout = new TimeSpan(0, 0, _splunkClient.QueryTimeout);
 77
 078                    var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, uriRequest.Request);
 079                    var response = await client.SendAsync(httpRequestMessage);
 080                    var responseStream = await response.Content.ReadAsStreamAsync();
 81
 082                    extractResponseMessage.ExtractResponseStream = responseStream;
 083                    extractResponseMessage.ExtractResponseMessage = response;
 084                    extractResponseMessage.ExtractRequestDetails = _extract;
 085                    extractResponseMessage.UriRequest = uriRequest;
 086                }
 87                else
 188                {
 189                    extractResponseMessage.ExtractResponseMessage.ReasonPhrase =
 190                        $"The authentication token has expired because it is valid up to {apiTokenExpiry.Item2}";
 191                    extractResponseMessage.ExtractResponseMessage.StatusCode = System.Net.HttpStatusCode.Unauthorized;
 192                }
 193            }
 094            catch (OperationCanceledException operationCancelledException)
 095            {
 096                extractResponseMessage.ExtractResponseMessage.ReasonPhrase = operationCancelledException.Message;
 097                extractResponseMessage.ExtractResponseMessage.StatusCode = System.Net.HttpStatusCode.RequestTimeout;
 098            }
 499            catch (Exception exc)
 4100            {
 4101                extractResponseMessage.ExtractResponseMessage.ReasonPhrase = exc.Message;
 4102                extractResponseMessage.ExtractResponseMessage.StatusCode =
 4103                    System.Net.HttpStatusCode.InternalServerError;
 4104            }
 105
 5106            return extractResponseMessage;
 5107        }
 108
 109        private string ConstructFilePath(SplunkInstance splunkInstance, FileType fileType, bool isToday,
 110            bool setDateAsMidnight = false)
 5111        {
 5112            var filePathString = new StringBuilder();
 5113            filePathString.Append(fileType.DirectoryName);
 5114            filePathString.Append(_filePathConstants.PathSeparator);
 5115            filePathString.Append(splunkInstance.Source);
 5116            filePathString.Append(_filePathConstants.PathSeparator);
 5117            filePathString.Append(
 5118                _extract.QueryFromDate.ToString(DateFormatConstants.FilePathQueryDateYearMonth));
 5119            filePathString.Append(_filePathConstants.PathSeparator);
 5120            filePathString.Append(_filePathConstants.ProjectNameFilePrefix);
 5121            filePathString.Append(_filePathConstants.ComponentSeparator);
 5122            filePathString.Append(fileType.FileTypeFilePrefix);
 5123            filePathString.Append(_filePathConstants.ComponentSeparator);
 5124            filePathString.Append(
 5125                $"{_extract.QueryFromDate.ToString(DateFormatConstants.FilePathQueryDate)}T{_extract.QueryHour.ToString(
 5126            filePathString.Append(_filePathConstants.ComponentSeparator);
 5127            filePathString.Append(
 5128                $"{_extract.QueryToDate.ToString(DateFormatConstants.FilePathQueryDate)}T{_extract.QueryHour.ToString(Da
 5129            filePathString.Append(_filePathConstants.ComponentSeparator);
 5130            filePathString.Append(splunkInstance.Source);
 5131            filePathString.Append(_filePathConstants.ComponentSeparator);
 5132            if (!isToday)
 1133            {
 1134                filePathString.Append(setDateAsMidnight
 1135                    ? timeProvider.CurrentDate().ToString(DateFormatConstants.FilePathNowDate)
 1136                    : timeProvider.UtcDateTime().ToString(DateFormatConstants.FilePathNowDate));
 1137            }
 138            else
 4139            {
 4140                filePathString.Append(DateTime.Today.AddDays(1).AddSeconds(-1)
 4141                    .ToString(DateFormatConstants.FilePathNowDate));
 4142            }
 143
 5144            filePathString.Append(_filePathConstants.FileExtension);
 5145            return filePathString.ToString();
 5146        }
 147
 148        public async Task ExecuteBatchDownloadFromSplunk(FileType fileType, UriRequest uriRequest, bool isToday)
 2149        {
 150            try
 2151            {
 2152                if (FileTypeEnabled(fileType))
 1153                {
 1154                    var extractResponse = await DownloadCSVDateRangeAsync(fileType, uriRequest, isToday);
 1155                    await importService.AddObjectFileMessage(fileType, extractResponse);
 1156                }
 157                else
 1158                {
 1159                    logger?.LogWarning(
 1160                        $"Filetype {fileType.FileTypeFilePrefix} is not enabled. Please check if this is correct");
 1161                }
 2162            }
 0163            catch (Exception exc)
 0164            {
 0165                logger?.LogError(exc, $"An error has occurred while attempting to execute an Azure function");
 0166                throw;
 167            }
 2168        }
 169
 170        private (bool, DateTime) HasApiTokenExpired(string apiToken)
 1171        {
 1172            var jwtToken = new JwtSecurityToken(apiToken);
 1173            return (DateTime.UtcNow > jwtToken.ValidTo, jwtToken.ValidTo);
 1174        }
 175
 176        private static bool FileTypeEnabled(FileType fileType)
 2177        {
 2178            return fileType is { Enabled: true };
 2179        }
 180    }
 181}
+
+
+
+ \ No newline at end of file diff --git a/source/coverage/Functions_SqlConnectionFactory.html b/source/coverage/Functions_SqlConnectionFactory.html new file mode 100644 index 0000000..fd12539 --- /dev/null +++ b/source/coverage/Functions_SqlConnectionFactory.html @@ -0,0 +1,186 @@ + + + + + + + +Functions.SqlConnectionFactory - Coverage Report + +
+

< Summary

+
+
+
Information
+
+
+ + + + + + + + + + + + + +
Class:Functions.SqlConnectionFactory
Assembly:Functions
File(s):/Users/griordan/git/gpconnect-analytics/source/Functions/SqlConnectionFactory.cs
+
+
+
+
+
+
+
Line coverage
+
+
0%
+
+ + + + + + + + + + + + + + + + + + + + + +
Covered lines:0
Uncovered lines:3
Coverable lines:3
Total lines:13
Line coverage:0%
+
+
+
+
+
Branch coverage
+
+
N/A
+
+ + + + + + + + + + + + + +
Covered branches:0
Total branches:0
Branch coverage:N/A
+
+
+
+
+
Method coverage
+
+
+

Feature is only available for sponsors

+Upgrade to PRO version +
+
+
+
+

Metrics

+
+ +++++++ + + + + +
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
CreateConnection(...)100%210%
+
+

File(s)

+

/Users/griordan/git/gpconnect-analytics/source/Functions/SqlConnectionFactory.cs

+
+ + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System.Data.Common;
 2using Core;
 3using Microsoft.Data.SqlClient;
 4
 5namespace Functions;
 6
 7public class SqlConnectionFactory : IConnectionFactory
 8{
 9    public DbConnection CreateConnection(string connectionString)
 010    {
 011        return new SqlConnection(connectionString);
 012    }
 13}
+
+
+
+
+

Methods/Properties

+CreateConnection(System.String)
+
+
+ \ No newline at end of file diff --git a/source/coverage/Functions_StoreProviderConsumerData.html b/source/coverage/Functions_StoreProviderConsumerData.html new file mode 100644 index 0000000..c6b0d47 --- /dev/null +++ b/source/coverage/Functions_StoreProviderConsumerData.html @@ -0,0 +1,242 @@ + + + + + + + +Functions.StoreProviderConsumerData - Coverage Report + +
+

< Summary

+
+
+
Information
+
+
+ + + + + + + + + + + + + +
Class:Functions.StoreProviderConsumerData
Assembly:Functions
File(s):/Users/griordan/git/gpconnect-analytics/source/Functions/StoreProviderConsumerData.cs
+
+
+
+
+
+
+
Line coverage
+
+
61%
+
+ + + + + + + + + + + + + + + + + + + + + +
Covered lines:22
Uncovered lines:14
Coverable lines:36
Total lines:69
Line coverage:61.1%
+
+
+
+
+
Branch coverage
+
+
75%
+
+ + + + + + + + + + + + + +
Covered branches:3
Total branches:4
Branch coverage:75%
+
+
+
+
+
Method coverage
+
+
+

Feature is only available for sponsors

+Upgrade to PRO version +
+
+
+
+

Metrics

+
+ +++++++ + + + + +
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
Run()75%5461.11%
+
+

File(s)

+

/Users/griordan/git/gpconnect-analytics/source/Functions/StoreProviderConsumerData.cs

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#LineLine coverage
 1using System.Net;
 2using System.Text.Json;
 3using Core.DTOs.Request;
 4using Core.Repositories;
 5using Microsoft.Azure.Functions.Worker;
 6using Microsoft.Azure.Functions.Worker.Http;
 7using Microsoft.Extensions.Logging;
 8
 9namespace Functions
 10{
 11    public class StoreProviderConsumerData(
 12        IHierarchyProviderConsumerRepo repository,
 13        ILogger<StoreProviderConsumerData> logger)
 14    {
 15        [Function("StoreProviderConsumerData")]
 16        public async Task<HttpResponseData> Run(
 17            [HttpTrigger(AuthorizationLevel.Function, "post", Route = "StoreProviderConsumerData")]
 18            HttpRequestData req)
 419        {
 420            logger.LogInformation("Processing HTTP request.");
 21
 422            var requestBody = await new StreamReader(req.Body).ReadToEndAsync();
 23
 424            if (requestBody.Length == 0)
 325            {
 326                var response = req.CreateResponse(HttpStatusCode.BadRequest);
 327                response.Headers.Add("Content-Type", "text/plain; charset=utf-8");
 328                await response.WriteStringAsync("Request body length is 0");
 329                return response;
 30            }
 31
 132            List<OrganisationHierarchyProvider> records = null;
 33            try
 134            {
 135                records = JsonSerializer.Deserialize<List<OrganisationHierarchyProvider>>(requestBody) ?? throw new
 136                    InvalidOperationException("Unable to deserialize input");
 137            }
 038            catch (JsonException ex)
 039            {
 040                logger.LogError($"Failed to deserialize request body: {ex.Message}");
 041                var response = req.CreateResponse(HttpStatusCode.BadRequest);
 042                response.Headers.Add("Content-Type", "text/plain; charset=utf-8");
 043                await response.WriteStringAsync("Invalid json input");
 044                return response;
 45            }
 46
 47
 48            try
 149            {
 150                logger.LogInformation($"Attempting to save {records.Count} items into databases");
 151                await repository.InsertHierarchyProviderConsumers(records);
 52
 153                var response = req.CreateResponse(HttpStatusCode.OK);
 154                response.Headers.Add("Content-Type", "text/plain; charset=utf-8");
 155                await response.WriteStringAsync("Storing of items successful");
 156                return response;
 57            }
 058            catch (Exception ex)
 059            {
 060                logger.LogError($"Failed to save data to databases: {ex.Message}");
 61
 062                var response = req.CreateResponse(HttpStatusCode.BadRequest);
 063                response.Headers.Add("Content-Type", "text/plain; charset=utf-8");
 064                await response.WriteStringAsync("Failed to save to the database - see logs for more information");
 065                return response;
 66            }
 467        }
 68    }
 69}
+
+
+
+
+

Methods/Properties

+Run()
+
+
+ \ No newline at end of file diff --git a/source/coverage/Functions_WorkerExtensionStartupCodeExecutor.html b/source/coverage/Functions_WorkerExtensionStartupCodeExecutor.html new file mode 100644 index 0000000..8ae3d35 --- /dev/null +++ b/source/coverage/Functions_WorkerExtensionStartupCodeExecutor.html @@ -0,0 +1,167 @@ + + + + + + + +Functions.WorkerExtensionStartupCodeExecutor - Coverage Report + +
+

< Summary

+ +
+
+
Line coverage
+
+
0%
+
+ + + + + + + + + + + + + + + + + + + + + +
Covered lines:0
Uncovered lines:9
Coverable lines:9
Total lines:29
Line coverage:0%
+
+
+
+
+
Branch coverage
+
+
N/A
+
+ + + + + + + + + + + + + +
Covered branches:0
Total branches:0
Branch coverage:N/A
+
+
+
+
+
Method coverage
+
+
+

Feature is only available for sponsors

+Upgrade to PRO version +
+
+
+
+

Metrics

+
+ +++++++ + + + + +
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
Configure(...)100%210%
+
+

File(s)

+

/Users/griordan/git/gpconnect-analytics/source/Functions/Microsoft.Azure.Functions.Worker.Sdk.Generators/Microsoft.Azure.Functions.Worker.Sdk.Generators.ExtensionStartupRunnerGenerator/WorkerExtensionStartupCodeExecutor.g.cs

+

File '/Users/griordan/git/gpconnect-analytics/source/Functions/Microsoft.Azure.Functions.Worker.Sdk.Generators/Microsoft.Azure.Functions.Worker.Sdk.Generators.ExtensionStartupRunnerGenerator/WorkerExtensionStartupCodeExecutor.g.cs' does not exist (any more).

+
+
+ \ No newline at end of file diff --git a/source/coverage/Functions_WorkerHostBuilderFunctionMetadataProviderExtension.html b/source/coverage/Functions_WorkerHostBuilderFunctionMetadataProviderExtension.html new file mode 100644 index 0000000..a719f15 --- /dev/null +++ b/source/coverage/Functions_WorkerHostBuilderFunctionMetadataProviderExtension.html @@ -0,0 +1,167 @@ + + + + + + + +Functions.WorkerHostBuilderFunctionMetadataProviderExtension - Coverage Report + +
+

< Summary

+ +
+
+
Line coverage
+
+
0%
+
+ + + + + + + + + + + + + + + + + + + + + +
Covered lines:0
Uncovered lines:7
Coverable lines:7
Total lines:211
Line coverage:0%
+
+
+
+
+
Branch coverage
+
+
N/A
+
+ + + + + + + + + + + + + +
Covered branches:0
Total branches:0
Branch coverage:N/A
+
+
+
+
+
Method coverage
+
+
+

Feature is only available for sponsors

+Upgrade to PRO version +
+
+
+
+

Metrics

+
+ +++++++ + + + + +
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
ConfigureGeneratedFunctionMetadataProvider(...)100%210%
+
+

File(s)

+

/Users/griordan/git/gpconnect-analytics/source/Functions/Microsoft.Azure.Functions.Worker.Sdk.Generators/Microsoft.Azure.Functions.Worker.Sdk.Generators.FunctionMetadataProviderGenerator/GeneratedFunctionMetadataProvider.g.cs

+

File '/Users/griordan/git/gpconnect-analytics/source/Functions/Microsoft.Azure.Functions.Worker.Sdk.Generators/Microsoft.Azure.Functions.Worker.Sdk.Generators.FunctionMetadataProviderGenerator/GeneratedFunctionMetadataProvider.g.cs' does not exist (any more).

+
+
+ \ No newline at end of file diff --git a/source/coverage/class.js b/source/coverage/class.js new file mode 100644 index 0000000..b7a43b2 --- /dev/null +++ b/source/coverage/class.js @@ -0,0 +1,218 @@ +/* Chartist.js 0.11.4 + * Copyright © 2019 Gion Kunz + * Free to use under either the WTFPL license or the MIT license. + * https://raw.githubusercontent.com/gionkunz/chartist-js/master/LICENSE-WTFPL + * https://raw.githubusercontent.com/gionkunz/chartist-js/master/LICENSE-MIT + */ + +!function (a, b) { "function" == typeof define && define.amd ? define("Chartist", [], function () { return a.Chartist = b() }) : "object" == typeof module && module.exports ? module.exports = b() : a.Chartist = b() }(this, function () { + var a = { version: "0.11.4" }; return function (a, b) { "use strict"; var c = a.window, d = a.document; b.namespaces = { svg: "http://www.w3.org/2000/svg", xmlns: "http://www.w3.org/2000/xmlns/", xhtml: "http://www.w3.org/1999/xhtml", xlink: "http://www.w3.org/1999/xlink", ct: "http://gionkunz.github.com/chartist-js/ct" }, b.noop = function (a) { return a }, b.alphaNumerate = function (a) { return String.fromCharCode(97 + a % 26) }, b.extend = function (a) { var c, d, e; for (a = a || {}, c = 1; c < arguments.length; c++) { d = arguments[c]; for (var f in d) e = d[f], "object" != typeof e || null === e || e instanceof Array ? a[f] = e : a[f] = b.extend(a[f], e) } return a }, b.replaceAll = function (a, b, c) { return a.replace(new RegExp(b, "g"), c) }, b.ensureUnit = function (a, b) { return "number" == typeof a && (a += b), a }, b.quantity = function (a) { if ("string" == typeof a) { var b = /^(\d+)\s*(.*)$/g.exec(a); return { value: +b[1], unit: b[2] || void 0 } } return { value: a } }, b.querySelector = function (a) { return a instanceof Node ? a : d.querySelector(a) }, b.times = function (a) { return Array.apply(null, new Array(a)) }, b.sum = function (a, b) { return a + (b ? b : 0) }, b.mapMultiply = function (a) { return function (b) { return b * a } }, b.mapAdd = function (a) { return function (b) { return b + a } }, b.serialMap = function (a, c) { var d = [], e = Math.max.apply(null, a.map(function (a) { return a.length })); return b.times(e).forEach(function (b, e) { var f = a.map(function (a) { return a[e] }); d[e] = c.apply(null, f) }), d }, b.roundWithPrecision = function (a, c) { var d = Math.pow(10, c || b.precision); return Math.round(a * d) / d }, b.precision = 8, b.escapingMap = { "&": "&", "<": "<", ">": ">", '"': """, "'": "'" }, b.serialize = function (a) { return null === a || void 0 === a ? a : ("number" == typeof a ? a = "" + a : "object" == typeof a && (a = JSON.stringify({ data: a })), Object.keys(b.escapingMap).reduce(function (a, c) { return b.replaceAll(a, c, b.escapingMap[c]) }, a)) }, b.deserialize = function (a) { if ("string" != typeof a) return a; a = Object.keys(b.escapingMap).reduce(function (a, c) { return b.replaceAll(a, b.escapingMap[c], c) }, a); try { a = JSON.parse(a), a = void 0 !== a.data ? a.data : a } catch (c) { } return a }, b.createSvg = function (a, c, d, e) { var f; return c = c || "100%", d = d || "100%", Array.prototype.slice.call(a.querySelectorAll("svg")).filter(function (a) { return a.getAttributeNS(b.namespaces.xmlns, "ct") }).forEach(function (b) { a.removeChild(b) }), f = new b.Svg("svg").attr({ width: c, height: d }).addClass(e), f._node.style.width = c, f._node.style.height = d, a.appendChild(f._node), f }, b.normalizeData = function (a, c, d) { var e, f = { raw: a, normalized: {} }; return f.normalized.series = b.getDataArray({ series: a.series || [] }, c, d), e = f.normalized.series.every(function (a) { return a instanceof Array }) ? Math.max.apply(null, f.normalized.series.map(function (a) { return a.length })) : f.normalized.series.length, f.normalized.labels = (a.labels || []).slice(), Array.prototype.push.apply(f.normalized.labels, b.times(Math.max(0, e - f.normalized.labels.length)).map(function () { return "" })), c && b.reverseData(f.normalized), f }, b.safeHasProperty = function (a, b) { return null !== a && "object" == typeof a && a.hasOwnProperty(b) }, b.isDataHoleValue = function (a) { return null === a || void 0 === a || "number" == typeof a && isNaN(a) }, b.reverseData = function (a) { a.labels.reverse(), a.series.reverse(); for (var b = 0; b < a.series.length; b++)"object" == typeof a.series[b] && void 0 !== a.series[b].data ? a.series[b].data.reverse() : a.series[b] instanceof Array && a.series[b].reverse() }, b.getDataArray = function (a, c, d) { function e(a) { if (b.safeHasProperty(a, "value")) return e(a.value); if (b.safeHasProperty(a, "data")) return e(a.data); if (a instanceof Array) return a.map(e); if (!b.isDataHoleValue(a)) { if (d) { var c = {}; return "string" == typeof d ? c[d] = b.getNumberOrUndefined(a) : c.y = b.getNumberOrUndefined(a), c.x = a.hasOwnProperty("x") ? b.getNumberOrUndefined(a.x) : c.x, c.y = a.hasOwnProperty("y") ? b.getNumberOrUndefined(a.y) : c.y, c } return b.getNumberOrUndefined(a) } } return a.series.map(e) }, b.normalizePadding = function (a, b) { return b = b || 0, "number" == typeof a ? { top: a, right: a, bottom: a, left: a } : { top: "number" == typeof a.top ? a.top : b, right: "number" == typeof a.right ? a.right : b, bottom: "number" == typeof a.bottom ? a.bottom : b, left: "number" == typeof a.left ? a.left : b } }, b.getMetaData = function (a, b) { var c = a.data ? a.data[b] : a[b]; return c ? c.meta : void 0 }, b.orderOfMagnitude = function (a) { return Math.floor(Math.log(Math.abs(a)) / Math.LN10) }, b.projectLength = function (a, b, c) { return b / c.range * a }, b.getAvailableHeight = function (a, c) { return Math.max((b.quantity(c.height).value || a.height()) - (c.chartPadding.top + c.chartPadding.bottom) - c.axisX.offset, 0) }, b.getHighLow = function (a, c, d) { function e(a) { if (void 0 !== a) if (a instanceof Array) for (var b = 0; b < a.length; b++)e(a[b]); else { var c = d ? +a[d] : +a; g && c > f.high && (f.high = c), h && c < f.low && (f.low = c) } } c = b.extend({}, c, d ? c["axis" + d.toUpperCase()] : {}); var f = { high: void 0 === c.high ? -Number.MAX_VALUE : +c.high, low: void 0 === c.low ? Number.MAX_VALUE : +c.low }, g = void 0 === c.high, h = void 0 === c.low; return (g || h) && e(a), (c.referenceValue || 0 === c.referenceValue) && (f.high = Math.max(c.referenceValue, f.high), f.low = Math.min(c.referenceValue, f.low)), f.high <= f.low && (0 === f.low ? f.high = 1 : f.low < 0 ? f.high = 0 : f.high > 0 ? f.low = 0 : (f.high = 1, f.low = 0)), f }, b.isNumeric = function (a) { return null !== a && isFinite(a) }, b.isFalseyButZero = function (a) { return !a && 0 !== a }, b.getNumberOrUndefined = function (a) { return b.isNumeric(a) ? +a : void 0 }, b.isMultiValue = function (a) { return "object" == typeof a && ("x" in a || "y" in a) }, b.getMultiValue = function (a, c) { return b.isMultiValue(a) ? b.getNumberOrUndefined(a[c || "y"]) : b.getNumberOrUndefined(a) }, b.rho = function (a) { function b(a, c) { return a % c === 0 ? c : b(c, a % c) } function c(a) { return a * a + 1 } if (1 === a) return a; var d, e = 2, f = 2; if (a % 2 === 0) return 2; do e = c(e) % a, f = c(c(f)) % a, d = b(Math.abs(e - f), a); while (1 === d); return d }, b.getBounds = function (a, c, d, e) { function f(a, b) { return a === (a += b) && (a *= 1 + (b > 0 ? o : -o)), a } var g, h, i, j = 0, k = { high: c.high, low: c.low }; k.valueRange = k.high - k.low, k.oom = b.orderOfMagnitude(k.valueRange), k.step = Math.pow(10, k.oom), k.min = Math.floor(k.low / k.step) * k.step, k.max = Math.ceil(k.high / k.step) * k.step, k.range = k.max - k.min, k.numberOfSteps = Math.round(k.range / k.step); var l = b.projectLength(a, k.step, k), m = l < d, n = e ? b.rho(k.range) : 0; if (e && b.projectLength(a, 1, k) >= d) k.step = 1; else if (e && n < k.step && b.projectLength(a, n, k) >= d) k.step = n; else for (; ;) { if (m && b.projectLength(a, k.step, k) <= d) k.step *= 2; else { if (m || !(b.projectLength(a, k.step / 2, k) >= d)) break; if (k.step /= 2, e && k.step % 1 !== 0) { k.step *= 2; break } } if (j++ > 1e3) throw new Error("Exceeded maximum number of iterations while optimizing scale step!") } var o = 2.221e-16; for (k.step = Math.max(k.step, o), h = k.min, i = k.max; h + k.step <= k.low;)h = f(h, k.step); for (; i - k.step >= k.high;)i = f(i, -k.step); k.min = h, k.max = i, k.range = k.max - k.min; var p = []; for (g = k.min; g <= k.max; g = f(g, k.step)) { var q = b.roundWithPrecision(g); q !== p[p.length - 1] && p.push(q) } return k.values = p, k }, b.polarToCartesian = function (a, b, c, d) { var e = (d - 90) * Math.PI / 180; return { x: a + c * Math.cos(e), y: b + c * Math.sin(e) } }, b.createChartRect = function (a, c, d) { var e = !(!c.axisX && !c.axisY), f = e ? c.axisY.offset : 0, g = e ? c.axisX.offset : 0, h = a.width() || b.quantity(c.width).value || 0, i = a.height() || b.quantity(c.height).value || 0, j = b.normalizePadding(c.chartPadding, d); h = Math.max(h, f + j.left + j.right), i = Math.max(i, g + j.top + j.bottom); var k = { padding: j, width: function () { return this.x2 - this.x1 }, height: function () { return this.y1 - this.y2 } }; return e ? ("start" === c.axisX.position ? (k.y2 = j.top + g, k.y1 = Math.max(i - j.bottom, k.y2 + 1)) : (k.y2 = j.top, k.y1 = Math.max(i - j.bottom - g, k.y2 + 1)), "start" === c.axisY.position ? (k.x1 = j.left + f, k.x2 = Math.max(h - j.right, k.x1 + 1)) : (k.x1 = j.left, k.x2 = Math.max(h - j.right - f, k.x1 + 1))) : (k.x1 = j.left, k.x2 = Math.max(h - j.right, k.x1 + 1), k.y2 = j.top, k.y1 = Math.max(i - j.bottom, k.y2 + 1)), k }, b.createGrid = function (a, c, d, e, f, g, h, i) { var j = {}; j[d.units.pos + "1"] = a, j[d.units.pos + "2"] = a, j[d.counterUnits.pos + "1"] = e, j[d.counterUnits.pos + "2"] = e + f; var k = g.elem("line", j, h.join(" ")); i.emit("draw", b.extend({ type: "grid", axis: d, index: c, group: g, element: k }, j)) }, b.createGridBackground = function (a, b, c, d) { var e = a.elem("rect", { x: b.x1, y: b.y2, width: b.width(), height: b.height() }, c, !0); d.emit("draw", { type: "gridBackground", group: a, element: e }) }, b.createLabel = function (a, c, e, f, g, h, i, j, k, l, m) { var n, o = {}; if (o[g.units.pos] = a + i[g.units.pos], o[g.counterUnits.pos] = i[g.counterUnits.pos], o[g.units.len] = c, o[g.counterUnits.len] = Math.max(0, h - 10), l) { var p = d.createElement("span"); p.className = k.join(" "), p.setAttribute("xmlns", b.namespaces.xhtml), p.innerText = f[e], p.style[g.units.len] = Math.round(o[g.units.len]) + "px", p.style[g.counterUnits.len] = Math.round(o[g.counterUnits.len]) + "px", n = j.foreignObject(p, b.extend({ style: "overflow: visible;" }, o)) } else n = j.elem("text", o, k.join(" ")).text(f[e]); m.emit("draw", b.extend({ type: "label", axis: g, index: e, group: j, element: n, text: f[e] }, o)) }, b.getSeriesOption = function (a, b, c) { if (a.name && b.series && b.series[a.name]) { var d = b.series[a.name]; return d.hasOwnProperty(c) ? d[c] : b[c] } return b[c] }, b.optionsProvider = function (a, d, e) { function f(a) { var f = h; if (h = b.extend({}, j), d) for (i = 0; i < d.length; i++) { var g = c.matchMedia(d[i][0]); g.matches && (h = b.extend(h, d[i][1])) } e && a && e.emit("optionsChanged", { previousOptions: f, currentOptions: h }) } function g() { k.forEach(function (a) { a.removeListener(f) }) } var h, i, j = b.extend({}, a), k = []; if (!c.matchMedia) throw "window.matchMedia not found! Make sure you're using a polyfill."; if (d) for (i = 0; i < d.length; i++) { var l = c.matchMedia(d[i][0]); l.addListener(f), k.push(l) } return f(), { removeMediaQueryListeners: g, getCurrentOptions: function () { return b.extend({}, h) } } }, b.splitIntoSegments = function (a, c, d) { var e = { increasingX: !1, fillHoles: !1 }; d = b.extend({}, e, d); for (var f = [], g = !0, h = 0; h < a.length; h += 2)void 0 === b.getMultiValue(c[h / 2].value) ? d.fillHoles || (g = !0) : (d.increasingX && h >= 2 && a[h] <= a[h - 2] && (g = !0), g && (f.push({ pathCoordinates: [], valueData: [] }), g = !1), f[f.length - 1].pathCoordinates.push(a[h], a[h + 1]), f[f.length - 1].valueData.push(c[h / 2])); return f } }(this || global, a), function (a, b) { "use strict"; b.Interpolation = {}, b.Interpolation.none = function (a) { var c = { fillHoles: !1 }; return a = b.extend({}, c, a), function (c, d) { for (var e = new b.Svg.Path, f = !0, g = 0; g < c.length; g += 2) { var h = c[g], i = c[g + 1], j = d[g / 2]; void 0 !== b.getMultiValue(j.value) ? (f ? e.move(h, i, !1, j) : e.line(h, i, !1, j), f = !1) : a.fillHoles || (f = !0) } return e } }, b.Interpolation.simple = function (a) { var c = { divisor: 2, fillHoles: !1 }; a = b.extend({}, c, a); var d = 1 / Math.max(1, a.divisor); return function (c, e) { for (var f, g, h, i = new b.Svg.Path, j = 0; j < c.length; j += 2) { var k = c[j], l = c[j + 1], m = (k - f) * d, n = e[j / 2]; void 0 !== n.value ? (void 0 === h ? i.move(k, l, !1, n) : i.curve(f + m, g, k - m, l, k, l, !1, n), f = k, g = l, h = n) : a.fillHoles || (f = k = h = void 0) } return i } }, b.Interpolation.cardinal = function (a) { var c = { tension: 1, fillHoles: !1 }; a = b.extend({}, c, a); var d = Math.min(1, Math.max(0, a.tension)), e = 1 - d; return function f(c, g) { var h = b.splitIntoSegments(c, g, { fillHoles: a.fillHoles }); if (h.length) { if (h.length > 1) { var i = []; return h.forEach(function (a) { i.push(f(a.pathCoordinates, a.valueData)) }), b.Svg.Path.join(i) } if (c = h[0].pathCoordinates, g = h[0].valueData, c.length <= 4) return b.Interpolation.none()(c, g); for (var j, k = (new b.Svg.Path).move(c[0], c[1], !1, g[0]), l = 0, m = c.length; m - 2 * !j > l; l += 2) { var n = [{ x: +c[l - 2], y: +c[l - 1] }, { x: +c[l], y: +c[l + 1] }, { x: +c[l + 2], y: +c[l + 3] }, { x: +c[l + 4], y: +c[l + 5] }]; j ? l ? m - 4 === l ? n[3] = { x: +c[0], y: +c[1] } : m - 2 === l && (n[2] = { x: +c[0], y: +c[1] }, n[3] = { x: +c[2], y: +c[3] }) : n[0] = { x: +c[m - 2], y: +c[m - 1] } : m - 4 === l ? n[3] = n[2] : l || (n[0] = { x: +c[l], y: +c[l + 1] }), k.curve(d * (-n[0].x + 6 * n[1].x + n[2].x) / 6 + e * n[2].x, d * (-n[0].y + 6 * n[1].y + n[2].y) / 6 + e * n[2].y, d * (n[1].x + 6 * n[2].x - n[3].x) / 6 + e * n[2].x, d * (n[1].y + 6 * n[2].y - n[3].y) / 6 + e * n[2].y, n[2].x, n[2].y, !1, g[(l + 2) / 2]) } return k } return b.Interpolation.none()([]) } }, b.Interpolation.monotoneCubic = function (a) { var c = { fillHoles: !1 }; return a = b.extend({}, c, a), function d(c, e) { var f = b.splitIntoSegments(c, e, { fillHoles: a.fillHoles, increasingX: !0 }); if (f.length) { if (f.length > 1) { var g = []; return f.forEach(function (a) { g.push(d(a.pathCoordinates, a.valueData)) }), b.Svg.Path.join(g) } if (c = f[0].pathCoordinates, e = f[0].valueData, c.length <= 4) return b.Interpolation.none()(c, e); var h, i, j = [], k = [], l = c.length / 2, m = [], n = [], o = [], p = []; for (h = 0; h < l; h++)j[h] = c[2 * h], k[h] = c[2 * h + 1]; for (h = 0; h < l - 1; h++)o[h] = k[h + 1] - k[h], p[h] = j[h + 1] - j[h], n[h] = o[h] / p[h]; for (m[0] = n[0], m[l - 1] = n[l - 2], h = 1; h < l - 1; h++)0 === n[h] || 0 === n[h - 1] || n[h - 1] > 0 != n[h] > 0 ? m[h] = 0 : (m[h] = 3 * (p[h - 1] + p[h]) / ((2 * p[h] + p[h - 1]) / n[h - 1] + (p[h] + 2 * p[h - 1]) / n[h]), isFinite(m[h]) || (m[h] = 0)); for (i = (new b.Svg.Path).move(j[0], k[0], !1, e[0]), h = 0; h < l - 1; h++)i.curve(j[h] + p[h] / 3, k[h] + m[h] * p[h] / 3, j[h + 1] - p[h] / 3, k[h + 1] - m[h + 1] * p[h] / 3, j[h + 1], k[h + 1], !1, e[h + 1]); return i } return b.Interpolation.none()([]) } }, b.Interpolation.step = function (a) { var c = { postpone: !0, fillHoles: !1 }; return a = b.extend({}, c, a), function (c, d) { for (var e, f, g, h = new b.Svg.Path, i = 0; i < c.length; i += 2) { var j = c[i], k = c[i + 1], l = d[i / 2]; void 0 !== l.value ? (void 0 === g ? h.move(j, k, !1, l) : (a.postpone ? h.line(j, f, !1, g) : h.line(e, k, !1, l), h.line(j, k, !1, l)), e = j, f = k, g = l) : a.fillHoles || (e = f = g = void 0) } return h } } }(this || global, a), function (a, b) { "use strict"; b.EventEmitter = function () { function a(a, b) { d[a] = d[a] || [], d[a].push(b) } function b(a, b) { d[a] && (b ? (d[a].splice(d[a].indexOf(b), 1), 0 === d[a].length && delete d[a]) : delete d[a]) } function c(a, b) { d[a] && d[a].forEach(function (a) { a(b) }), d["*"] && d["*"].forEach(function (c) { c(a, b) }) } var d = []; return { addEventHandler: a, removeEventHandler: b, emit: c } } }(this || global, a), function (a, b) { "use strict"; function c(a) { var b = []; if (a.length) for (var c = 0; c < a.length; c++)b.push(a[c]); return b } function d(a, c) { var d = c || this.prototype || b.Class, e = Object.create(d); b.Class.cloneDefinitions(e, a); var f = function () { var a, c = e.constructor || function () { }; return a = this === b ? Object.create(e) : this, c.apply(a, Array.prototype.slice.call(arguments, 0)), a }; return f.prototype = e, f["super"] = d, f.extend = this.extend, f } function e() { var a = c(arguments), b = a[0]; return a.splice(1, a.length - 1).forEach(function (a) { Object.getOwnPropertyNames(a).forEach(function (c) { delete b[c], Object.defineProperty(b, c, Object.getOwnPropertyDescriptor(a, c)) }) }), b } b.Class = { extend: d, cloneDefinitions: e } }(this || global, a), function (a, b) { "use strict"; function c(a, c, d) { return a && (this.data = a || {}, this.data.labels = this.data.labels || [], this.data.series = this.data.series || [], this.eventEmitter.emit("data", { type: "update", data: this.data })), c && (this.options = b.extend({}, d ? this.options : this.defaultOptions, c), this.initializeTimeoutId || (this.optionsProvider.removeMediaQueryListeners(), this.optionsProvider = b.optionsProvider(this.options, this.responsiveOptions, this.eventEmitter))), this.initializeTimeoutId || this.createChart(this.optionsProvider.getCurrentOptions()), this } function d() { return this.initializeTimeoutId ? i.clearTimeout(this.initializeTimeoutId) : (i.removeEventListener("resize", this.resizeListener), this.optionsProvider.removeMediaQueryListeners()), this } function e(a, b) { return this.eventEmitter.addEventHandler(a, b), this } function f(a, b) { return this.eventEmitter.removeEventHandler(a, b), this } function g() { i.addEventListener("resize", this.resizeListener), this.optionsProvider = b.optionsProvider(this.options, this.responsiveOptions, this.eventEmitter), this.eventEmitter.addEventHandler("optionsChanged", function () { this.update() }.bind(this)), this.options.plugins && this.options.plugins.forEach(function (a) { a instanceof Array ? a[0](this, a[1]) : a(this) }.bind(this)), this.eventEmitter.emit("data", { type: "initial", data: this.data }), this.createChart(this.optionsProvider.getCurrentOptions()), this.initializeTimeoutId = void 0 } function h(a, c, d, e, f) { this.container = b.querySelector(a), this.data = c || {}, this.data.labels = this.data.labels || [], this.data.series = this.data.series || [], this.defaultOptions = d, this.options = e, this.responsiveOptions = f, this.eventEmitter = b.EventEmitter(), this.supportsForeignObject = b.Svg.isSupported("Extensibility"), this.supportsAnimations = b.Svg.isSupported("AnimationEventsAttribute"), this.resizeListener = function () { this.update() }.bind(this), this.container && (this.container.__chartist__ && this.container.__chartist__.detach(), this.container.__chartist__ = this), this.initializeTimeoutId = setTimeout(g.bind(this), 0) } var i = a.window; b.Base = b.Class.extend({ constructor: h, optionsProvider: void 0, container: void 0, svg: void 0, eventEmitter: void 0, createChart: function () { throw new Error("Base chart type can't be instantiated!") }, update: c, detach: d, on: e, off: f, version: b.version, supportsForeignObject: !1 }) }(this || global, a), function (a, b) { "use strict"; function c(a, c, d, e, f) { a instanceof Element ? this._node = a : (this._node = y.createElementNS(b.namespaces.svg, a), "svg" === a && this.attr({ "xmlns:ct": b.namespaces.ct })), c && this.attr(c), d && this.addClass(d), e && (f && e._node.firstChild ? e._node.insertBefore(this._node, e._node.firstChild) : e._node.appendChild(this._node)) } function d(a, c) { return "string" == typeof a ? c ? this._node.getAttributeNS(c, a) : this._node.getAttribute(a) : (Object.keys(a).forEach(function (c) { if (void 0 !== a[c]) if (c.indexOf(":") !== -1) { var d = c.split(":"); this._node.setAttributeNS(b.namespaces[d[0]], c, a[c]) } else this._node.setAttribute(c, a[c]) }.bind(this)), this) } function e(a, c, d, e) { return new b.Svg(a, c, d, this, e) } function f() { return this._node.parentNode instanceof SVGElement ? new b.Svg(this._node.parentNode) : null } function g() { for (var a = this._node; "svg" !== a.nodeName;)a = a.parentNode; return new b.Svg(a) } function h(a) { var c = this._node.querySelector(a); return c ? new b.Svg(c) : null } function i(a) { var c = this._node.querySelectorAll(a); return c.length ? new b.Svg.List(c) : null } function j() { return this._node } function k(a, c, d, e) { if ("string" == typeof a) { var f = y.createElement("div"); f.innerHTML = a, a = f.firstChild } a.setAttribute("xmlns", b.namespaces.xmlns); var g = this.elem("foreignObject", c, d, e); return g._node.appendChild(a), g } function l(a) { return this._node.appendChild(y.createTextNode(a)), this } function m() { for (; this._node.firstChild;)this._node.removeChild(this._node.firstChild); return this } function n() { return this._node.parentNode.removeChild(this._node), this.parent() } function o(a) { return this._node.parentNode.replaceChild(a._node, this._node), a } function p(a, b) { return b && this._node.firstChild ? this._node.insertBefore(a._node, this._node.firstChild) : this._node.appendChild(a._node), this } function q() { return this._node.getAttribute("class") ? this._node.getAttribute("class").trim().split(/\s+/) : [] } function r(a) { return this._node.setAttribute("class", this.classes(this._node).concat(a.trim().split(/\s+/)).filter(function (a, b, c) { return c.indexOf(a) === b }).join(" ")), this } function s(a) { var b = a.trim().split(/\s+/); return this._node.setAttribute("class", this.classes(this._node).filter(function (a) { return b.indexOf(a) === -1 }).join(" ")), this } function t() { return this._node.setAttribute("class", ""), this } function u() { return this._node.getBoundingClientRect().height } function v() { return this._node.getBoundingClientRect().width } function w(a, c, d) { return void 0 === c && (c = !0), Object.keys(a).forEach(function (e) { function f(a, c) { var f, g, h, i = {}; a.easing && (h = a.easing instanceof Array ? a.easing : b.Svg.Easing[a.easing], delete a.easing), a.begin = b.ensureUnit(a.begin, "ms"), a.dur = b.ensureUnit(a.dur, "ms"), h && (a.calcMode = "spline", a.keySplines = h.join(" "), a.keyTimes = "0;1"), c && (a.fill = "freeze", i[e] = a.from, this.attr(i), g = b.quantity(a.begin || 0).value, a.begin = "indefinite"), f = this.elem("animate", b.extend({ attributeName: e }, a)), c && setTimeout(function () { try { f._node.beginElement() } catch (b) { i[e] = a.to, this.attr(i), f.remove() } }.bind(this), g), d && f._node.addEventListener("beginEvent", function () { d.emit("animationBegin", { element: this, animate: f._node, params: a }) }.bind(this)), f._node.addEventListener("endEvent", function () { d && d.emit("animationEnd", { element: this, animate: f._node, params: a }), c && (i[e] = a.to, this.attr(i), f.remove()) }.bind(this)) } a[e] instanceof Array ? a[e].forEach(function (a) { f.bind(this)(a, !1) }.bind(this)) : f.bind(this)(a[e], c) }.bind(this)), this } function x(a) { var c = this; this.svgElements = []; for (var d = 0; d < a.length; d++)this.svgElements.push(new b.Svg(a[d])); Object.keys(b.Svg.prototype).filter(function (a) { return ["constructor", "parent", "querySelector", "querySelectorAll", "replace", "append", "classes", "height", "width"].indexOf(a) === -1 }).forEach(function (a) { c[a] = function () { var d = Array.prototype.slice.call(arguments, 0); return c.svgElements.forEach(function (c) { b.Svg.prototype[a].apply(c, d) }), c } }) } var y = a.document; b.Svg = b.Class.extend({ constructor: c, attr: d, elem: e, parent: f, root: g, querySelector: h, querySelectorAll: i, getNode: j, foreignObject: k, text: l, empty: m, remove: n, replace: o, append: p, classes: q, addClass: r, removeClass: s, removeAllClasses: t, height: u, width: v, animate: w }), b.Svg.isSupported = function (a) { return y.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#" + a, "1.1") }; var z = { easeInSine: [.47, 0, .745, .715], easeOutSine: [.39, .575, .565, 1], easeInOutSine: [.445, .05, .55, .95], easeInQuad: [.55, .085, .68, .53], easeOutQuad: [.25, .46, .45, .94], easeInOutQuad: [.455, .03, .515, .955], easeInCubic: [.55, .055, .675, .19], easeOutCubic: [.215, .61, .355, 1], easeInOutCubic: [.645, .045, .355, 1], easeInQuart: [.895, .03, .685, .22], easeOutQuart: [.165, .84, .44, 1], easeInOutQuart: [.77, 0, .175, 1], easeInQuint: [.755, .05, .855, .06], easeOutQuint: [.23, 1, .32, 1], easeInOutQuint: [.86, 0, .07, 1], easeInExpo: [.95, .05, .795, .035], easeOutExpo: [.19, 1, .22, 1], easeInOutExpo: [1, 0, 0, 1], easeInCirc: [.6, .04, .98, .335], easeOutCirc: [.075, .82, .165, 1], easeInOutCirc: [.785, .135, .15, .86], easeInBack: [.6, -.28, .735, .045], easeOutBack: [.175, .885, .32, 1.275], easeInOutBack: [.68, -.55, .265, 1.55] }; b.Svg.Easing = z, b.Svg.List = b.Class.extend({ constructor: x }) }(this || global, a), function (a, b) { "use strict"; function c(a, c, d, e, f, g) { var h = b.extend({ command: f ? a.toLowerCase() : a.toUpperCase() }, c, g ? { data: g } : {}); d.splice(e, 0, h) } function d(a, b) { a.forEach(function (c, d) { t[c.command.toLowerCase()].forEach(function (e, f) { b(c, e, d, f, a) }) }) } function e(a, c) { this.pathElements = [], this.pos = 0, this.close = a, this.options = b.extend({}, u, c) } function f(a) { return void 0 !== a ? (this.pos = Math.max(0, Math.min(this.pathElements.length, a)), this) : this.pos } function g(a) { return this.pathElements.splice(this.pos, a), this } function h(a, b, d, e) { return c("M", { x: +a, y: +b }, this.pathElements, this.pos++, d, e), this } function i(a, b, d, e) { return c("L", { x: +a, y: +b }, this.pathElements, this.pos++, d, e), this } function j(a, b, d, e, f, g, h, i) { return c("C", { x1: +a, y1: +b, x2: +d, y2: +e, x: +f, y: +g }, this.pathElements, this.pos++, h, i), this } function k(a, b, d, e, f, g, h, i, j) { return c("A", { rx: +a, ry: +b, xAr: +d, lAf: +e, sf: +f, x: +g, y: +h }, this.pathElements, this.pos++, i, j), this } function l(a) { var c = a.replace(/([A-Za-z])([0-9])/g, "$1 $2").replace(/([0-9])([A-Za-z])/g, "$1 $2").split(/[\s,]+/).reduce(function (a, b) { return b.match(/[A-Za-z]/) && a.push([]), a[a.length - 1].push(b), a }, []); "Z" === c[c.length - 1][0].toUpperCase() && c.pop(); var d = c.map(function (a) { var c = a.shift(), d = t[c.toLowerCase()]; return b.extend({ command: c }, d.reduce(function (b, c, d) { return b[c] = +a[d], b }, {})) }), e = [this.pos, 0]; return Array.prototype.push.apply(e, d), Array.prototype.splice.apply(this.pathElements, e), this.pos += d.length, this } function m() { var a = Math.pow(10, this.options.accuracy); return this.pathElements.reduce(function (b, c) { var d = t[c.command.toLowerCase()].map(function (b) { return this.options.accuracy ? Math.round(c[b] * a) / a : c[b] }.bind(this)); return b + c.command + d.join(",") }.bind(this), "") + (this.close ? "Z" : "") } function n(a, b) { return d(this.pathElements, function (c, d) { c[d] *= "x" === d[0] ? a : b }), this } function o(a, b) { return d(this.pathElements, function (c, d) { c[d] += "x" === d[0] ? a : b }), this } function p(a) { return d(this.pathElements, function (b, c, d, e, f) { var g = a(b, c, d, e, f); (g || 0 === g) && (b[c] = g) }), this } function q(a) { var c = new b.Svg.Path(a || this.close); return c.pos = this.pos, c.pathElements = this.pathElements.slice().map(function (a) { return b.extend({}, a) }), c.options = b.extend({}, this.options), c } function r(a) { var c = [new b.Svg.Path]; return this.pathElements.forEach(function (d) { d.command === a.toUpperCase() && 0 !== c[c.length - 1].pathElements.length && c.push(new b.Svg.Path), c[c.length - 1].pathElements.push(d) }), c } function s(a, c, d) { for (var e = new b.Svg.Path(c, d), f = 0; f < a.length; f++)for (var g = a[f], h = 0; h < g.pathElements.length; h++)e.pathElements.push(g.pathElements[h]); return e } var t = { m: ["x", "y"], l: ["x", "y"], c: ["x1", "y1", "x2", "y2", "x", "y"], a: ["rx", "ry", "xAr", "lAf", "sf", "x", "y"] }, u = { accuracy: 3 }; b.Svg.Path = b.Class.extend({ constructor: e, position: f, remove: g, move: h, line: i, curve: j, arc: k, scale: n, translate: o, transform: p, parse: l, stringify: m, clone: q, splitByCommand: r }), b.Svg.Path.elementDescriptions = t, b.Svg.Path.join = s }(this || global, a), function (a, b) { "use strict"; function c(a, b, c, d) { this.units = a, this.counterUnits = a === e.x ? e.y : e.x, this.chartRect = b, this.axisLength = b[a.rectEnd] - b[a.rectStart], this.gridOffset = b[a.rectOffset], this.ticks = c, this.options = d } function d(a, c, d, e, f) { var g = e["axis" + this.units.pos.toUpperCase()], h = this.ticks.map(this.projectValue.bind(this)), i = this.ticks.map(g.labelInterpolationFnc); h.forEach(function (j, k) { var l, m = { x: 0, y: 0 }; l = h[k + 1] ? h[k + 1] - j : Math.max(this.axisLength - j, 30), b.isFalseyButZero(i[k]) && "" !== i[k] || ("x" === this.units.pos ? (j = this.chartRect.x1 + j, m.x = e.axisX.labelOffset.x, "start" === e.axisX.position ? m.y = this.chartRect.padding.top + e.axisX.labelOffset.y + (d ? 5 : 20) : m.y = this.chartRect.y1 + e.axisX.labelOffset.y + (d ? 5 : 20)) : (j = this.chartRect.y1 - j, m.y = e.axisY.labelOffset.y - (d ? l : 0), "start" === e.axisY.position ? m.x = d ? this.chartRect.padding.left + e.axisY.labelOffset.x : this.chartRect.x1 - 10 : m.x = this.chartRect.x2 + e.axisY.labelOffset.x + 10), g.showGrid && b.createGrid(j, k, this, this.gridOffset, this.chartRect[this.counterUnits.len](), a, [e.classNames.grid, e.classNames[this.units.dir]], f), g.showLabel && b.createLabel(j, l, k, i, this, g.offset, m, c, [e.classNames.label, e.classNames[this.units.dir], "start" === g.position ? e.classNames[g.position] : e.classNames.end], d, f)) }.bind(this)) } var e = (a.window, a.document, { x: { pos: "x", len: "width", dir: "horizontal", rectStart: "x1", rectEnd: "x2", rectOffset: "y2" }, y: { pos: "y", len: "height", dir: "vertical", rectStart: "y2", rectEnd: "y1", rectOffset: "x1" } }); b.Axis = b.Class.extend({ constructor: c, createGridAndLabels: d, projectValue: function (a, b, c) { throw new Error("Base axis can't be instantiated!") } }), b.Axis.units = e }(this || global, a), function (a, b) { "use strict"; function c(a, c, d, e) { var f = e.highLow || b.getHighLow(c, e, a.pos); this.bounds = b.getBounds(d[a.rectEnd] - d[a.rectStart], f, e.scaleMinSpace || 20, e.onlyInteger), this.range = { min: this.bounds.min, max: this.bounds.max }, b.AutoScaleAxis["super"].constructor.call(this, a, d, this.bounds.values, e) } function d(a) { return this.axisLength * (+b.getMultiValue(a, this.units.pos) - this.bounds.min) / this.bounds.range } a.window, a.document; b.AutoScaleAxis = b.Axis.extend({ constructor: c, projectValue: d }) }(this || global, a), function (a, b) { "use strict"; function c(a, c, d, e) { var f = e.highLow || b.getHighLow(c, e, a.pos); this.divisor = e.divisor || 1, this.ticks = e.ticks || b.times(this.divisor).map(function (a, b) { return f.low + (f.high - f.low) / this.divisor * b }.bind(this)), this.ticks.sort(function (a, b) { return a - b }), this.range = { min: f.low, max: f.high }, b.FixedScaleAxis["super"].constructor.call(this, a, d, this.ticks, e), this.stepLength = this.axisLength / this.divisor } function d(a) { return this.axisLength * (+b.getMultiValue(a, this.units.pos) - this.range.min) / (this.range.max - this.range.min) } a.window, a.document; b.FixedScaleAxis = b.Axis.extend({ constructor: c, projectValue: d }) }(this || global, a), function (a, b) { "use strict"; function c(a, c, d, e) { b.StepAxis["super"].constructor.call(this, a, d, e.ticks, e); var f = Math.max(1, e.ticks.length - (e.stretch ? 1 : 0)); this.stepLength = this.axisLength / f } function d(a, b) { return this.stepLength * b } a.window, a.document; b.StepAxis = b.Axis.extend({ constructor: c, projectValue: d }) }(this || global, a), function (a, b) { "use strict"; function c(a) { var c = b.normalizeData(this.data, a.reverseData, !0); this.svg = b.createSvg(this.container, a.width, a.height, a.classNames.chart); var d, f, g = this.svg.elem("g").addClass(a.classNames.gridGroup), h = this.svg.elem("g"), i = this.svg.elem("g").addClass(a.classNames.labelGroup), j = b.createChartRect(this.svg, a, e.padding); d = void 0 === a.axisX.type ? new b.StepAxis(b.Axis.units.x, c.normalized.series, j, b.extend({}, a.axisX, { ticks: c.normalized.labels, stretch: a.fullWidth })) : a.axisX.type.call(b, b.Axis.units.x, c.normalized.series, j, a.axisX), f = void 0 === a.axisY.type ? new b.AutoScaleAxis(b.Axis.units.y, c.normalized.series, j, b.extend({}, a.axisY, { high: b.isNumeric(a.high) ? a.high : a.axisY.high, low: b.isNumeric(a.low) ? a.low : a.axisY.low })) : a.axisY.type.call(b, b.Axis.units.y, c.normalized.series, j, a.axisY), d.createGridAndLabels(g, i, this.supportsForeignObject, a, this.eventEmitter), f.createGridAndLabels(g, i, this.supportsForeignObject, a, this.eventEmitter), a.showGridBackground && b.createGridBackground(g, j, a.classNames.gridBackground, this.eventEmitter), c.raw.series.forEach(function (e, g) { var i = h.elem("g"); i.attr({ "ct:series-name": e.name, "ct:meta": b.serialize(e.meta) }), i.addClass([a.classNames.series, e.className || a.classNames.series + "-" + b.alphaNumerate(g)].join(" ")); var k = [], l = []; c.normalized.series[g].forEach(function (a, h) { var i = { x: j.x1 + d.projectValue(a, h, c.normalized.series[g]), y: j.y1 - f.projectValue(a, h, c.normalized.series[g]) }; k.push(i.x, i.y), l.push({ value: a, valueIndex: h, meta: b.getMetaData(e, h) }) }.bind(this)); var m = { lineSmooth: b.getSeriesOption(e, a, "lineSmooth"), showPoint: b.getSeriesOption(e, a, "showPoint"), showLine: b.getSeriesOption(e, a, "showLine"), showArea: b.getSeriesOption(e, a, "showArea"), areaBase: b.getSeriesOption(e, a, "areaBase") }, n = "function" == typeof m.lineSmooth ? m.lineSmooth : m.lineSmooth ? b.Interpolation.monotoneCubic() : b.Interpolation.none(), o = n(k, l); if (m.showPoint && o.pathElements.forEach(function (c) { var h = i.elem("line", { x1: c.x, y1: c.y, x2: c.x + .01, y2: c.y }, a.classNames.point).attr({ "ct:value": [c.data.value.x, c.data.value.y].filter(b.isNumeric).join(","), "ct:meta": b.serialize(c.data.meta) }); this.eventEmitter.emit("draw", { type: "point", value: c.data.value, index: c.data.valueIndex, meta: c.data.meta, series: e, seriesIndex: g, axisX: d, axisY: f, group: i, element: h, x: c.x, y: c.y }) }.bind(this)), m.showLine) { var p = i.elem("path", { d: o.stringify() }, a.classNames.line, !0); this.eventEmitter.emit("draw", { type: "line", values: c.normalized.series[g], path: o.clone(), chartRect: j, index: g, series: e, seriesIndex: g, seriesMeta: e.meta, axisX: d, axisY: f, group: i, element: p }) } if (m.showArea && f.range) { var q = Math.max(Math.min(m.areaBase, f.range.max), f.range.min), r = j.y1 - f.projectValue(q); o.splitByCommand("M").filter(function (a) { return a.pathElements.length > 1 }).map(function (a) { var b = a.pathElements[0], c = a.pathElements[a.pathElements.length - 1]; return a.clone(!0).position(0).remove(1).move(b.x, r).line(b.x, b.y).position(a.pathElements.length + 1).line(c.x, r) }).forEach(function (b) { var h = i.elem("path", { d: b.stringify() }, a.classNames.area, !0); this.eventEmitter.emit("draw", { type: "area", values: c.normalized.series[g], path: b.clone(), series: e, seriesIndex: g, axisX: d, axisY: f, chartRect: j, index: g, group: i, element: h }) }.bind(this)) } }.bind(this)), this.eventEmitter.emit("created", { bounds: f.bounds, chartRect: j, axisX: d, axisY: f, svg: this.svg, options: a }) } function d(a, c, d, f) { b.Line["super"].constructor.call(this, a, c, e, b.extend({}, e, d), f) } var e = (a.window, a.document, { axisX: { offset: 30, position: "end", labelOffset: { x: 0, y: 0 }, showLabel: !0, showGrid: !0, labelInterpolationFnc: b.noop, type: void 0 }, axisY: { offset: 40, position: "start", labelOffset: { x: 0, y: 0 }, showLabel: !0, showGrid: !0, labelInterpolationFnc: b.noop, type: void 0, scaleMinSpace: 20, onlyInteger: !1 }, width: void 0, height: void 0, showLine: !0, showPoint: !0, showArea: !1, areaBase: 0, lineSmooth: !0, showGridBackground: !1, low: void 0, high: void 0, chartPadding: { top: 15, right: 15, bottom: 5, left: 10 }, fullWidth: !1, reverseData: !1, classNames: { chart: "ct-chart-line", label: "ct-label", labelGroup: "ct-labels", series: "ct-series", line: "ct-line", point: "ct-point", area: "ct-area", grid: "ct-grid", gridGroup: "ct-grids", gridBackground: "ct-grid-background", vertical: "ct-vertical", horizontal: "ct-horizontal", start: "ct-start", end: "ct-end" } }); b.Line = b.Base.extend({ constructor: d, createChart: c }) }(this || global, a), function (a, b) { + "use strict"; function c(a) { + var c, d; a.distributeSeries ? (c = b.normalizeData(this.data, a.reverseData, a.horizontalBars ? "x" : "y"), c.normalized.series = c.normalized.series.map(function (a) { return [a] })) : c = b.normalizeData(this.data, a.reverseData, a.horizontalBars ? "x" : "y"), this.svg = b.createSvg(this.container, a.width, a.height, a.classNames.chart + (a.horizontalBars ? " " + a.classNames.horizontalBars : "")); var f = this.svg.elem("g").addClass(a.classNames.gridGroup), g = this.svg.elem("g"), h = this.svg.elem("g").addClass(a.classNames.labelGroup); + if (a.stackBars && 0 !== c.normalized.series.length) { var i = b.serialMap(c.normalized.series, function () { return Array.prototype.slice.call(arguments).map(function (a) { return a }).reduce(function (a, b) { return { x: a.x + (b && b.x) || 0, y: a.y + (b && b.y) || 0 } }, { x: 0, y: 0 }) }); d = b.getHighLow([i], a, a.horizontalBars ? "x" : "y") } else d = b.getHighLow(c.normalized.series, a, a.horizontalBars ? "x" : "y"); d.high = +a.high || (0 === a.high ? 0 : d.high), d.low = +a.low || (0 === a.low ? 0 : d.low); var j, k, l, m, n, o = b.createChartRect(this.svg, a, e.padding); k = a.distributeSeries && a.stackBars ? c.normalized.labels.slice(0, 1) : c.normalized.labels, a.horizontalBars ? (j = m = void 0 === a.axisX.type ? new b.AutoScaleAxis(b.Axis.units.x, c.normalized.series, o, b.extend({}, a.axisX, { highLow: d, referenceValue: 0 })) : a.axisX.type.call(b, b.Axis.units.x, c.normalized.series, o, b.extend({}, a.axisX, { highLow: d, referenceValue: 0 })), l = n = void 0 === a.axisY.type ? new b.StepAxis(b.Axis.units.y, c.normalized.series, o, { ticks: k }) : a.axisY.type.call(b, b.Axis.units.y, c.normalized.series, o, a.axisY)) : (l = m = void 0 === a.axisX.type ? new b.StepAxis(b.Axis.units.x, c.normalized.series, o, { ticks: k }) : a.axisX.type.call(b, b.Axis.units.x, c.normalized.series, o, a.axisX), j = n = void 0 === a.axisY.type ? new b.AutoScaleAxis(b.Axis.units.y, c.normalized.series, o, b.extend({}, a.axisY, { highLow: d, referenceValue: 0 })) : a.axisY.type.call(b, b.Axis.units.y, c.normalized.series, o, b.extend({}, a.axisY, { highLow: d, referenceValue: 0 }))); var p = a.horizontalBars ? o.x1 + j.projectValue(0) : o.y1 - j.projectValue(0), q = []; l.createGridAndLabels(f, h, this.supportsForeignObject, a, this.eventEmitter), j.createGridAndLabels(f, h, this.supportsForeignObject, a, this.eventEmitter), a.showGridBackground && b.createGridBackground(f, o, a.classNames.gridBackground, this.eventEmitter), c.raw.series.forEach(function (d, e) { var f, h, i = e - (c.raw.series.length - 1) / 2; f = a.distributeSeries && !a.stackBars ? l.axisLength / c.normalized.series.length / 2 : a.distributeSeries && a.stackBars ? l.axisLength / 2 : l.axisLength / c.normalized.series[e].length / 2, h = g.elem("g"), h.attr({ "ct:series-name": d.name, "ct:meta": b.serialize(d.meta) }), h.addClass([a.classNames.series, d.className || a.classNames.series + "-" + b.alphaNumerate(e)].join(" ")), c.normalized.series[e].forEach(function (g, k) { var r, s, t, u; if (u = a.distributeSeries && !a.stackBars ? e : a.distributeSeries && a.stackBars ? 0 : k, r = a.horizontalBars ? { x: o.x1 + j.projectValue(g && g.x ? g.x : 0, k, c.normalized.series[e]), y: o.y1 - l.projectValue(g && g.y ? g.y : 0, u, c.normalized.series[e]) } : { x: o.x1 + l.projectValue(g && g.x ? g.x : 0, u, c.normalized.series[e]), y: o.y1 - j.projectValue(g && g.y ? g.y : 0, k, c.normalized.series[e]) }, l instanceof b.StepAxis && (l.options.stretch || (r[l.units.pos] += f * (a.horizontalBars ? -1 : 1)), r[l.units.pos] += a.stackBars || a.distributeSeries ? 0 : i * a.seriesBarDistance * (a.horizontalBars ? -1 : 1)), t = q[k] || p, q[k] = t - (p - r[l.counterUnits.pos]), void 0 !== g) { var v = {}; v[l.units.pos + "1"] = r[l.units.pos], v[l.units.pos + "2"] = r[l.units.pos], !a.stackBars || "accumulate" !== a.stackMode && a.stackMode ? (v[l.counterUnits.pos + "1"] = p, v[l.counterUnits.pos + "2"] = r[l.counterUnits.pos]) : (v[l.counterUnits.pos + "1"] = t, v[l.counterUnits.pos + "2"] = q[k]), v.x1 = Math.min(Math.max(v.x1, o.x1), o.x2), v.x2 = Math.min(Math.max(v.x2, o.x1), o.x2), v.y1 = Math.min(Math.max(v.y1, o.y2), o.y1), v.y2 = Math.min(Math.max(v.y2, o.y2), o.y1); var w = b.getMetaData(d, k); s = h.elem("line", v, a.classNames.bar).attr({ "ct:value": [g.x, g.y].filter(b.isNumeric).join(","), "ct:meta": b.serialize(w) }), this.eventEmitter.emit("draw", b.extend({ type: "bar", value: g, index: k, meta: w, series: d, seriesIndex: e, axisX: m, axisY: n, chartRect: o, group: h, element: s }, v)) } }.bind(this)) }.bind(this)), this.eventEmitter.emit("created", { bounds: j.bounds, chartRect: o, axisX: m, axisY: n, svg: this.svg, options: a }) + } function d(a, c, d, f) { b.Bar["super"].constructor.call(this, a, c, e, b.extend({}, e, d), f) } var e = (a.window, a.document, { axisX: { offset: 30, position: "end", labelOffset: { x: 0, y: 0 }, showLabel: !0, showGrid: !0, labelInterpolationFnc: b.noop, scaleMinSpace: 30, onlyInteger: !1 }, axisY: { offset: 40, position: "start", labelOffset: { x: 0, y: 0 }, showLabel: !0, showGrid: !0, labelInterpolationFnc: b.noop, scaleMinSpace: 20, onlyInteger: !1 }, width: void 0, height: void 0, high: void 0, low: void 0, referenceValue: 0, chartPadding: { top: 15, right: 15, bottom: 5, left: 10 }, seriesBarDistance: 15, stackBars: !1, stackMode: "accumulate", horizontalBars: !1, distributeSeries: !1, reverseData: !1, showGridBackground: !1, classNames: { chart: "ct-chart-bar", horizontalBars: "ct-horizontal-bars", label: "ct-label", labelGroup: "ct-labels", series: "ct-series", bar: "ct-bar", grid: "ct-grid", gridGroup: "ct-grids", gridBackground: "ct-grid-background", vertical: "ct-vertical", horizontal: "ct-horizontal", start: "ct-start", end: "ct-end" } }); b.Bar = b.Base.extend({ constructor: d, createChart: c }) + }(this || global, a), function (a, b) { "use strict"; function c(a, b, c) { var d = b.x > a.x; return d && "explode" === c || !d && "implode" === c ? "start" : d && "implode" === c || !d && "explode" === c ? "end" : "middle" } function d(a) { var d, e, g, h, i, j = b.normalizeData(this.data), k = [], l = a.startAngle; this.svg = b.createSvg(this.container, a.width, a.height, a.donut ? a.classNames.chartDonut : a.classNames.chartPie), e = b.createChartRect(this.svg, a, f.padding), g = Math.min(e.width() / 2, e.height() / 2), i = a.total || j.normalized.series.reduce(function (a, b) { return a + b }, 0); var m = b.quantity(a.donutWidth); "%" === m.unit && (m.value *= g / 100), g -= a.donut && !a.donutSolid ? m.value / 2 : 0, h = "outside" === a.labelPosition || a.donut && !a.donutSolid ? g : "center" === a.labelPosition ? 0 : a.donutSolid ? g - m.value / 2 : g / 2, h += a.labelOffset; var n = { x: e.x1 + e.width() / 2, y: e.y2 + e.height() / 2 }, o = 1 === j.raw.series.filter(function (a) { return a.hasOwnProperty("value") ? 0 !== a.value : 0 !== a }).length; j.raw.series.forEach(function (a, b) { k[b] = this.svg.elem("g", null, null) }.bind(this)), a.showLabel && (d = this.svg.elem("g", null, null)), j.raw.series.forEach(function (e, f) { if (0 !== j.normalized.series[f] || !a.ignoreEmptyValues) { k[f].attr({ "ct:series-name": e.name }), k[f].addClass([a.classNames.series, e.className || a.classNames.series + "-" + b.alphaNumerate(f)].join(" ")); var p = i > 0 ? l + j.normalized.series[f] / i * 360 : 0, q = Math.max(0, l - (0 === f || o ? 0 : .2)); p - q >= 359.99 && (p = q + 359.99); var r, s, t, u = b.polarToCartesian(n.x, n.y, g, q), v = b.polarToCartesian(n.x, n.y, g, p), w = new b.Svg.Path(!a.donut || a.donutSolid).move(v.x, v.y).arc(g, g, 0, p - l > 180, 0, u.x, u.y); a.donut ? a.donutSolid && (t = g - m.value, r = b.polarToCartesian(n.x, n.y, t, l - (0 === f || o ? 0 : .2)), s = b.polarToCartesian(n.x, n.y, t, p), w.line(r.x, r.y), w.arc(t, t, 0, p - l > 180, 1, s.x, s.y)) : w.line(n.x, n.y); var x = a.classNames.slicePie; a.donut && (x = a.classNames.sliceDonut, a.donutSolid && (x = a.classNames.sliceDonutSolid)); var y = k[f].elem("path", { d: w.stringify() }, x); if (y.attr({ "ct:value": j.normalized.series[f], "ct:meta": b.serialize(e.meta) }), a.donut && !a.donutSolid && (y._node.style.strokeWidth = m.value + "px"), this.eventEmitter.emit("draw", { type: "slice", value: j.normalized.series[f], totalDataSum: i, index: f, meta: e.meta, series: e, group: k[f], element: y, path: w.clone(), center: n, radius: g, startAngle: l, endAngle: p }), a.showLabel) { var z; z = 1 === j.raw.series.length ? { x: n.x, y: n.y } : b.polarToCartesian(n.x, n.y, h, l + (p - l) / 2); var A; A = j.normalized.labels && !b.isFalseyButZero(j.normalized.labels[f]) ? j.normalized.labels[f] : j.normalized.series[f]; var B = a.labelInterpolationFnc(A, f); if (B || 0 === B) { var C = d.elem("text", { dx: z.x, dy: z.y, "text-anchor": c(n, z, a.labelDirection) }, a.classNames.label).text("" + B); this.eventEmitter.emit("draw", { type: "label", index: f, group: d, element: C, text: "" + B, x: z.x, y: z.y }) } } l = p } }.bind(this)), this.eventEmitter.emit("created", { chartRect: e, svg: this.svg, options: a }) } function e(a, c, d, e) { b.Pie["super"].constructor.call(this, a, c, f, b.extend({}, f, d), e) } var f = (a.window, a.document, { width: void 0, height: void 0, chartPadding: 5, classNames: { chartPie: "ct-chart-pie", chartDonut: "ct-chart-donut", series: "ct-series", slicePie: "ct-slice-pie", sliceDonut: "ct-slice-donut", sliceDonutSolid: "ct-slice-donut-solid", label: "ct-label" }, startAngle: 0, total: void 0, donut: !1, donutSolid: !1, donutWidth: 60, showLabel: !0, labelOffset: 0, labelPosition: "inside", labelInterpolationFnc: b.noop, labelDirection: "neutral", reverseData: !1, ignoreEmptyValues: !1 }); b.Pie = b.Base.extend({ constructor: e, createChart: d, determineAnchorPosition: c }) }(this || global, a), a +}); +//# sourceMappingURL=chartist.min.js.map + +var i, l, selectedLine = null; + +/* Navigate to hash without browser history entry */ +var navigateToHash = function () { + if (window.history !== undefined && window.history.replaceState !== undefined) { + window.history.replaceState(undefined, undefined, this.getAttribute("href")); + } +}; + +var hashLinks = document.getElementsByClassName('navigatetohash'); +for (i = 0, l = hashLinks.length; i < l; i++) { + hashLinks[i].addEventListener('click', navigateToHash); +} + +/* Switch test method */ +var switchTestMethod = function () { + var method = this.getAttribute("value"); + console.log("Selected test method: " + method); + + var lines, i, l, coverageData, lineAnalysis, cells; + + lines = document.querySelectorAll('.lineAnalysis tr'); + + for (i = 1, l = lines.length; i < l; i++) { + coverageData = JSON.parse(lines[i].getAttribute('data-coverage').replace(/'/g, '"')); + lineAnalysis = coverageData[method]; + cells = lines[i].querySelectorAll('td'); + if (lineAnalysis === undefined) { + lineAnalysis = coverageData.AllTestMethods; + if (lineAnalysis.LVS !== 'gray') { + cells[0].setAttribute('class', 'red'); + cells[1].innerText = cells[1].textContent = '0'; + cells[4].setAttribute('class', 'lightred'); + } + } else { + cells[0].setAttribute('class', lineAnalysis.LVS); + cells[1].innerText = cells[1].textContent = lineAnalysis.VC; + cells[4].setAttribute('class', 'light' + lineAnalysis.LVS); + } + } +}; + +var testMethods = document.getElementsByClassName('switchtestmethod'); +for (i = 0, l = testMethods.length; i < l; i++) { + testMethods[i].addEventListener('change', switchTestMethod); +} + +/* Highlight test method by line */ +var toggleLine = function () { + if (selectedLine === this) { + selectedLine = null; + } else { + selectedLine = null; + unhighlightTestMethods(); + highlightTestMethods.call(this); + selectedLine = this; + } + +}; +var highlightTestMethods = function () { + if (selectedLine !== null) { + return; + } + + var lineAnalysis; + var coverageData = JSON.parse(this.getAttribute('data-coverage').replace(/'/g, '"')); + var testMethods = document.getElementsByClassName('testmethod'); + + for (i = 0, l = testMethods.length; i < l; i++) { + lineAnalysis = coverageData[testMethods[i].id]; + if (lineAnalysis === undefined) { + testMethods[i].className = testMethods[i].className.replace(/\s*light.+/g, ""); + } else { + testMethods[i].className += ' light' + lineAnalysis.LVS; + } + } +}; +var unhighlightTestMethods = function () { + if (selectedLine !== null) { + return; + } + + var testMethods = document.getElementsByClassName('testmethod'); + for (i = 0, l = testMethods.length; i < l; i++) { + testMethods[i].className = testMethods[i].className.replace(/\s*light.+/g, ""); + } +}; +var coverableLines = document.getElementsByClassName('coverableline'); +for (i = 0, l = coverableLines.length; i < l; i++) { + coverableLines[i].addEventListener('click', toggleLine); + coverableLines[i].addEventListener('mouseenter', highlightTestMethods); + coverableLines[i].addEventListener('mouseleave', unhighlightTestMethods); +} + +/* History charts */ +var renderChart = function (chart) { + // Remove current children (e.g. PNG placeholder) + while (chart.firstChild) { + chart.firstChild.remove(); + } + + var chartData = window[chart.getAttribute('data-data')]; + var options = { + axisY: { + type: undefined, + onlyInteger: true + }, + lineSmooth: false, + low: 0, + high: 100, + scaleMinSpace: 20, + onlyInteger: true, + fullWidth: true + }; + var lineChart = new Chartist.Line(chart, { + labels: [], + series: chartData.series + }, options); + + /* Zoom */ + var zoomButtonDiv = document.createElement("div"); + zoomButtonDiv.className = "toggleZoom"; + var zoomButtonLink = document.createElement("a"); + zoomButtonLink.setAttribute("href", ""); + var zoomButtonText = document.createElement("i"); + zoomButtonText.className = "icon-search-plus"; + + zoomButtonLink.appendChild(zoomButtonText); + zoomButtonDiv.appendChild(zoomButtonLink); + + chart.appendChild(zoomButtonDiv); + + zoomButtonDiv.addEventListener('click', function (event) { + event.preventDefault(); + + if (options.axisY.type === undefined) { + options.axisY.type = Chartist.AutoScaleAxis; + zoomButtonText.className = "icon-search-minus"; + } else { + options.axisY.type = undefined; + zoomButtonText.className = "icon-search-plus"; + } + + lineChart.update(null, options); + }); + + var tooltip = document.createElement("div"); + tooltip.className = "tooltip"; + + chart.appendChild(tooltip); + + /* Tooltips */ + var showToolTip = function () { + var index = this.getAttribute('ct:meta'); + + tooltip.innerHTML = chartData.tooltips[index]; + tooltip.style.display = 'block'; + }; + + var moveToolTip = function (event) { + var box = chart.getBoundingClientRect(); + var left = event.pageX - box.left - window.pageXOffset; + var top = event.pageY - box.top - window.pageYOffset; + + left = left + 20; + top = top - tooltip.offsetHeight / 2; + + if (left + tooltip.offsetWidth > box.width) { + left -= tooltip.offsetWidth + 40; + } + + if (top < 0) { + top = 0; + } + + if (top + tooltip.offsetHeight > box.height) { + top = box.height - tooltip.offsetHeight; + } + + tooltip.style.left = left + 'px'; + tooltip.style.top = top + 'px'; + }; + + var hideToolTip = function () { + tooltip.style.display = 'none'; + }; + chart.addEventListener('mousemove', moveToolTip); + + lineChart.on('created', function () { + var chartPoints = chart.getElementsByClassName('ct-point'); + for (i = 0, l = chartPoints.length; i < l; i++) { + chartPoints[i].addEventListener('mousemove', showToolTip); + chartPoints[i].addEventListener('mouseout', hideToolTip); + } + }); +}; + +var charts = document.getElementsByClassName('historychart'); +for (i = 0, l = charts.length; i < l; i++) { + renderChart(charts[i]); +} \ No newline at end of file diff --git a/source/coverage/icon_cog.svg b/source/coverage/icon_cog.svg new file mode 100644 index 0000000..d730bf1 --- /dev/null +++ b/source/coverage/icon_cog.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/source/coverage/icon_cog_dark.svg b/source/coverage/icon_cog_dark.svg new file mode 100644 index 0000000..ccbcd9b --- /dev/null +++ b/source/coverage/icon_cog_dark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/source/coverage/icon_cube.svg b/source/coverage/icon_cube.svg new file mode 100644 index 0000000..3302443 --- /dev/null +++ b/source/coverage/icon_cube.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/source/coverage/icon_cube_dark.svg b/source/coverage/icon_cube_dark.svg new file mode 100644 index 0000000..3e7f0fa --- /dev/null +++ b/source/coverage/icon_cube_dark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/source/coverage/icon_fork.svg b/source/coverage/icon_fork.svg new file mode 100644 index 0000000..f0148b3 --- /dev/null +++ b/source/coverage/icon_fork.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/source/coverage/icon_fork_dark.svg b/source/coverage/icon_fork_dark.svg new file mode 100644 index 0000000..11930c9 --- /dev/null +++ b/source/coverage/icon_fork_dark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/source/coverage/icon_info-circled.svg b/source/coverage/icon_info-circled.svg new file mode 100644 index 0000000..252166b --- /dev/null +++ b/source/coverage/icon_info-circled.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/source/coverage/icon_info-circled_dark.svg b/source/coverage/icon_info-circled_dark.svg new file mode 100644 index 0000000..252166b --- /dev/null +++ b/source/coverage/icon_info-circled_dark.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/source/coverage/icon_minus.svg b/source/coverage/icon_minus.svg new file mode 100644 index 0000000..3c30c36 --- /dev/null +++ b/source/coverage/icon_minus.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/source/coverage/icon_minus_dark.svg b/source/coverage/icon_minus_dark.svg new file mode 100644 index 0000000..2516b6f --- /dev/null +++ b/source/coverage/icon_minus_dark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/source/coverage/icon_plus.svg b/source/coverage/icon_plus.svg new file mode 100644 index 0000000..7932723 --- /dev/null +++ b/source/coverage/icon_plus.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/source/coverage/icon_plus_dark.svg b/source/coverage/icon_plus_dark.svg new file mode 100644 index 0000000..6ed4edd --- /dev/null +++ b/source/coverage/icon_plus_dark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/source/coverage/icon_search-minus.svg b/source/coverage/icon_search-minus.svg new file mode 100644 index 0000000..c174eb5 --- /dev/null +++ b/source/coverage/icon_search-minus.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/source/coverage/icon_search-minus_dark.svg b/source/coverage/icon_search-minus_dark.svg new file mode 100644 index 0000000..9caaffb --- /dev/null +++ b/source/coverage/icon_search-minus_dark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/source/coverage/icon_search-plus.svg b/source/coverage/icon_search-plus.svg new file mode 100644 index 0000000..04b24ec --- /dev/null +++ b/source/coverage/icon_search-plus.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/source/coverage/icon_search-plus_dark.svg b/source/coverage/icon_search-plus_dark.svg new file mode 100644 index 0000000..5324194 --- /dev/null +++ b/source/coverage/icon_search-plus_dark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/source/coverage/icon_sponsor.svg b/source/coverage/icon_sponsor.svg new file mode 100644 index 0000000..bf6d959 --- /dev/null +++ b/source/coverage/icon_sponsor.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/source/coverage/icon_star.svg b/source/coverage/icon_star.svg new file mode 100644 index 0000000..b23c54e --- /dev/null +++ b/source/coverage/icon_star.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/source/coverage/icon_star_dark.svg b/source/coverage/icon_star_dark.svg new file mode 100644 index 0000000..49c0d03 --- /dev/null +++ b/source/coverage/icon_star_dark.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/source/coverage/icon_up-dir.svg b/source/coverage/icon_up-dir.svg new file mode 100644 index 0000000..567c11f --- /dev/null +++ b/source/coverage/icon_up-dir.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/source/coverage/icon_up-dir_active.svg b/source/coverage/icon_up-dir_active.svg new file mode 100644 index 0000000..bb22554 --- /dev/null +++ b/source/coverage/icon_up-dir_active.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/source/coverage/icon_up-down-dir.svg b/source/coverage/icon_up-down-dir.svg new file mode 100644 index 0000000..62a3f9c --- /dev/null +++ b/source/coverage/icon_up-down-dir.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/source/coverage/icon_up-down-dir_dark.svg b/source/coverage/icon_up-down-dir_dark.svg new file mode 100644 index 0000000..2820a25 --- /dev/null +++ b/source/coverage/icon_up-down-dir_dark.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/source/coverage/icon_wrench.svg b/source/coverage/icon_wrench.svg new file mode 100644 index 0000000..b6aa318 --- /dev/null +++ b/source/coverage/icon_wrench.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/source/coverage/icon_wrench_dark.svg b/source/coverage/icon_wrench_dark.svg new file mode 100644 index 0000000..5c77a9c --- /dev/null +++ b/source/coverage/icon_wrench_dark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/source/coverage/index.htm b/source/coverage/index.htm new file mode 100644 index 0000000..0113390 --- /dev/null +++ b/source/coverage/index.htm @@ -0,0 +1,234 @@ + + + + + + + +Summary - Coverage Report + +
+

SummaryStarSponsor

+
+
+
Information
+
+
+ + + + + + + + + + + + + + + + + + + + + +
Parser:MultiReport (3x Cobertura)
Assemblies:2
Classes:31
Files:31
Coverage date:12/02/2025 - 16:32:11 - 12/02/2025 - 16:32:54
+
+
+
+
+
Line coverage
+
+
62%
+
+ + + + + + + + + + + + + + + + + + + + + +
Covered lines:524
Uncovered lines:317
Coverable lines:841
Total lines:1610
Line coverage:62.3%
+
+
+
+
+
Branch coverage
+
+
57%
+
+ + + + + + + + + + + + + +
Covered branches:59
Total branches:102
Branch coverage:57.8%
+
+
+
+
+
Method coverage
+
+
+

Feature is only available for sponsors

+Upgrade to PRO version +
+
+
+
+

Risk Hotspots

+ +
+ +++++++ + + + + + + + + + + + + + + +
AssemblyClassMethodCrap Score Cyclomatic complexity
FunctionsFunctions.Services.DataServiceExecuteQueryStoredProcedure()426
+
+
+

Coverage

+ +
+ +++++++++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Line coverageBranch coverage
NameCoveredUncoveredCoverableTotalPercentageCoveredTotalPercentage
Core57258225569.5%
  
121866.6%
  
Core.DTOs.Request.OrganisationHierarchyProvider20219100%
 
00
 
Core.Helpers.ApplicationHelper70723100%
 
4666.6%
  
Core.Helpers.AttributeExtensions1301327100%
 
66100%
 
Core.Helpers.ConnectionStrings1017100%
 
00
 
Core.Helpers.DateTimeHelper40411100%
 
22100%
 
Core.Helpers.FilePathAttribute30312100%
 
00
 
Core.Mapping.SplunkInstanceMap055140%
 
00
 
Core.Repositories.DapperWrapper271286896.4%
  
00
 
Core.Repositories.HierarchyProviderConsumerRepo01717620%
 
040%
 
TimeProvider022120%
 
00
 
Functions467292759135561.5%
  
478455.9%
  
Functions.Configuration.EmailConfigurationProvider088290%
 
020%
 
Functions.Configuration.Infrastructure.HttpClient.HttpClientExtensions1201223100%
 
00
 
Functions.Configuration.Infrastructure.Logging.LoggingExtensions01301301850%
 
040%
 
Functions.Configuration.Infrastructure.Mapping.MappingExtensions033130%
 
00
 
Functions.ExecuteImportByTrigger30316100%
 
00
 
Functions.GetDataFromApiByDateRange2718458560%
  
00
 
Functions.GetDataFromApiByTrigger90934100%
 
00
 
Functions.GetDataFromApiManual2102142100%
 
22100%
 
Functions.GetDataFromApiToday5405498100%
 
00
 
Functions.PurgeErrorLogByTrigger30316100%
 
00
 
Functions.Services.BatchService8679314692.4%
  
141877.7%
  
Functions.Services.BlobService428509384%
  
6875%
  
Functions.Services.ConfigurationService324366188.8%
  
00
 
Functions.Services.CoreConfigurationService40414100%
 
22100%
 
Functions.Services.DataService264661133%
  
0160%
 
Functions.Services.FileService80819100%
 
00
 
Functions.Services.ImportService4604684100%
 
121485.7%
  
Functions.Services.LoggingService077210%
 
00
 
Functions.Services.SplunkService962612218178.6%
  
81457.1%
  
Functions.SqlConnectionFactory033130%
 
00
 
Functions.StoreProviderConsumerData2214366961.1%
  
3475%
  
+
+
+
+ \ No newline at end of file diff --git a/source/coverage/index.html b/source/coverage/index.html new file mode 100644 index 0000000..0113390 --- /dev/null +++ b/source/coverage/index.html @@ -0,0 +1,234 @@ + + + + + + + +Summary - Coverage Report + +
+

SummaryStarSponsor

+
+
+
Information
+
+
+ + + + + + + + + + + + + + + + + + + + + +
Parser:MultiReport (3x Cobertura)
Assemblies:2
Classes:31
Files:31
Coverage date:12/02/2025 - 16:32:11 - 12/02/2025 - 16:32:54
+
+
+
+
+
Line coverage
+
+
62%
+
+ + + + + + + + + + + + + + + + + + + + + +
Covered lines:524
Uncovered lines:317
Coverable lines:841
Total lines:1610
Line coverage:62.3%
+
+
+
+
+
Branch coverage
+
+
57%
+
+ + + + + + + + + + + + + +
Covered branches:59
Total branches:102
Branch coverage:57.8%
+
+
+
+
+
Method coverage
+
+
+

Feature is only available for sponsors

+Upgrade to PRO version +
+
+
+
+

Risk Hotspots

+ +
+ +++++++ + + + + + + + + + + + + + + +
AssemblyClassMethodCrap Score Cyclomatic complexity
FunctionsFunctions.Services.DataServiceExecuteQueryStoredProcedure()426
+
+
+

Coverage

+ +
+ +++++++++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Line coverageBranch coverage
NameCoveredUncoveredCoverableTotalPercentageCoveredTotalPercentage
Core57258225569.5%
  
121866.6%
  
Core.DTOs.Request.OrganisationHierarchyProvider20219100%
 
00
 
Core.Helpers.ApplicationHelper70723100%
 
4666.6%
  
Core.Helpers.AttributeExtensions1301327100%
 
66100%
 
Core.Helpers.ConnectionStrings1017100%
 
00
 
Core.Helpers.DateTimeHelper40411100%
 
22100%
 
Core.Helpers.FilePathAttribute30312100%
 
00
 
Core.Mapping.SplunkInstanceMap055140%
 
00
 
Core.Repositories.DapperWrapper271286896.4%
  
00
 
Core.Repositories.HierarchyProviderConsumerRepo01717620%
 
040%
 
TimeProvider022120%
 
00
 
Functions467292759135561.5%
  
478455.9%
  
Functions.Configuration.EmailConfigurationProvider088290%
 
020%
 
Functions.Configuration.Infrastructure.HttpClient.HttpClientExtensions1201223100%
 
00
 
Functions.Configuration.Infrastructure.Logging.LoggingExtensions01301301850%
 
040%
 
Functions.Configuration.Infrastructure.Mapping.MappingExtensions033130%
 
00
 
Functions.ExecuteImportByTrigger30316100%
 
00
 
Functions.GetDataFromApiByDateRange2718458560%
  
00
 
Functions.GetDataFromApiByTrigger90934100%
 
00
 
Functions.GetDataFromApiManual2102142100%
 
22100%
 
Functions.GetDataFromApiToday5405498100%
 
00
 
Functions.PurgeErrorLogByTrigger30316100%
 
00
 
Functions.Services.BatchService8679314692.4%
  
141877.7%
  
Functions.Services.BlobService428509384%
  
6875%
  
Functions.Services.ConfigurationService324366188.8%
  
00
 
Functions.Services.CoreConfigurationService40414100%
 
22100%
 
Functions.Services.DataService264661133%
  
0160%
 
Functions.Services.FileService80819100%
 
00
 
Functions.Services.ImportService4604684100%
 
121485.7%
  
Functions.Services.LoggingService077210%
 
00
 
Functions.Services.SplunkService962612218178.6%
  
81457.1%
  
Functions.SqlConnectionFactory033130%
 
00
 
Functions.StoreProviderConsumerData2214366961.1%
  
3475%
  
+
+
+
+ \ No newline at end of file diff --git a/source/coverage/main.js b/source/coverage/main.js new file mode 100644 index 0000000..d585298 --- /dev/null +++ b/source/coverage/main.js @@ -0,0 +1,334 @@ +/* Chartist.js 0.11.4 + * Copyright © 2019 Gion Kunz + * Free to use under either the WTFPL license or the MIT license. + * https://raw.githubusercontent.com/gionkunz/chartist-js/master/LICENSE-WTFPL + * https://raw.githubusercontent.com/gionkunz/chartist-js/master/LICENSE-MIT + */ + +!function (a, b) { "function" == typeof define && define.amd ? define("Chartist", [], function () { return a.Chartist = b() }) : "object" == typeof module && module.exports ? module.exports = b() : a.Chartist = b() }(this, function () { + var a = { version: "0.11.4" }; return function (a, b) { "use strict"; var c = a.window, d = a.document; b.namespaces = { svg: "http://www.w3.org/2000/svg", xmlns: "http://www.w3.org/2000/xmlns/", xhtml: "http://www.w3.org/1999/xhtml", xlink: "http://www.w3.org/1999/xlink", ct: "http://gionkunz.github.com/chartist-js/ct" }, b.noop = function (a) { return a }, b.alphaNumerate = function (a) { return String.fromCharCode(97 + a % 26) }, b.extend = function (a) { var c, d, e; for (a = a || {}, c = 1; c < arguments.length; c++) { d = arguments[c]; for (var f in d) e = d[f], "object" != typeof e || null === e || e instanceof Array ? a[f] = e : a[f] = b.extend(a[f], e) } return a }, b.replaceAll = function (a, b, c) { return a.replace(new RegExp(b, "g"), c) }, b.ensureUnit = function (a, b) { return "number" == typeof a && (a += b), a }, b.quantity = function (a) { if ("string" == typeof a) { var b = /^(\d+)\s*(.*)$/g.exec(a); return { value: +b[1], unit: b[2] || void 0 } } return { value: a } }, b.querySelector = function (a) { return a instanceof Node ? a : d.querySelector(a) }, b.times = function (a) { return Array.apply(null, new Array(a)) }, b.sum = function (a, b) { return a + (b ? b : 0) }, b.mapMultiply = function (a) { return function (b) { return b * a } }, b.mapAdd = function (a) { return function (b) { return b + a } }, b.serialMap = function (a, c) { var d = [], e = Math.max.apply(null, a.map(function (a) { return a.length })); return b.times(e).forEach(function (b, e) { var f = a.map(function (a) { return a[e] }); d[e] = c.apply(null, f) }), d }, b.roundWithPrecision = function (a, c) { var d = Math.pow(10, c || b.precision); return Math.round(a * d) / d }, b.precision = 8, b.escapingMap = { "&": "&", "<": "<", ">": ">", '"': """, "'": "'" }, b.serialize = function (a) { return null === a || void 0 === a ? a : ("number" == typeof a ? a = "" + a : "object" == typeof a && (a = JSON.stringify({ data: a })), Object.keys(b.escapingMap).reduce(function (a, c) { return b.replaceAll(a, c, b.escapingMap[c]) }, a)) }, b.deserialize = function (a) { if ("string" != typeof a) return a; a = Object.keys(b.escapingMap).reduce(function (a, c) { return b.replaceAll(a, b.escapingMap[c], c) }, a); try { a = JSON.parse(a), a = void 0 !== a.data ? a.data : a } catch (c) { } return a }, b.createSvg = function (a, c, d, e) { var f; return c = c || "100%", d = d || "100%", Array.prototype.slice.call(a.querySelectorAll("svg")).filter(function (a) { return a.getAttributeNS(b.namespaces.xmlns, "ct") }).forEach(function (b) { a.removeChild(b) }), f = new b.Svg("svg").attr({ width: c, height: d }).addClass(e), f._node.style.width = c, f._node.style.height = d, a.appendChild(f._node), f }, b.normalizeData = function (a, c, d) { var e, f = { raw: a, normalized: {} }; return f.normalized.series = b.getDataArray({ series: a.series || [] }, c, d), e = f.normalized.series.every(function (a) { return a instanceof Array }) ? Math.max.apply(null, f.normalized.series.map(function (a) { return a.length })) : f.normalized.series.length, f.normalized.labels = (a.labels || []).slice(), Array.prototype.push.apply(f.normalized.labels, b.times(Math.max(0, e - f.normalized.labels.length)).map(function () { return "" })), c && b.reverseData(f.normalized), f }, b.safeHasProperty = function (a, b) { return null !== a && "object" == typeof a && a.hasOwnProperty(b) }, b.isDataHoleValue = function (a) { return null === a || void 0 === a || "number" == typeof a && isNaN(a) }, b.reverseData = function (a) { a.labels.reverse(), a.series.reverse(); for (var b = 0; b < a.series.length; b++)"object" == typeof a.series[b] && void 0 !== a.series[b].data ? a.series[b].data.reverse() : a.series[b] instanceof Array && a.series[b].reverse() }, b.getDataArray = function (a, c, d) { function e(a) { if (b.safeHasProperty(a, "value")) return e(a.value); if (b.safeHasProperty(a, "data")) return e(a.data); if (a instanceof Array) return a.map(e); if (!b.isDataHoleValue(a)) { if (d) { var c = {}; return "string" == typeof d ? c[d] = b.getNumberOrUndefined(a) : c.y = b.getNumberOrUndefined(a), c.x = a.hasOwnProperty("x") ? b.getNumberOrUndefined(a.x) : c.x, c.y = a.hasOwnProperty("y") ? b.getNumberOrUndefined(a.y) : c.y, c } return b.getNumberOrUndefined(a) } } return a.series.map(e) }, b.normalizePadding = function (a, b) { return b = b || 0, "number" == typeof a ? { top: a, right: a, bottom: a, left: a } : { top: "number" == typeof a.top ? a.top : b, right: "number" == typeof a.right ? a.right : b, bottom: "number" == typeof a.bottom ? a.bottom : b, left: "number" == typeof a.left ? a.left : b } }, b.getMetaData = function (a, b) { var c = a.data ? a.data[b] : a[b]; return c ? c.meta : void 0 }, b.orderOfMagnitude = function (a) { return Math.floor(Math.log(Math.abs(a)) / Math.LN10) }, b.projectLength = function (a, b, c) { return b / c.range * a }, b.getAvailableHeight = function (a, c) { return Math.max((b.quantity(c.height).value || a.height()) - (c.chartPadding.top + c.chartPadding.bottom) - c.axisX.offset, 0) }, b.getHighLow = function (a, c, d) { function e(a) { if (void 0 !== a) if (a instanceof Array) for (var b = 0; b < a.length; b++)e(a[b]); else { var c = d ? +a[d] : +a; g && c > f.high && (f.high = c), h && c < f.low && (f.low = c) } } c = b.extend({}, c, d ? c["axis" + d.toUpperCase()] : {}); var f = { high: void 0 === c.high ? -Number.MAX_VALUE : +c.high, low: void 0 === c.low ? Number.MAX_VALUE : +c.low }, g = void 0 === c.high, h = void 0 === c.low; return (g || h) && e(a), (c.referenceValue || 0 === c.referenceValue) && (f.high = Math.max(c.referenceValue, f.high), f.low = Math.min(c.referenceValue, f.low)), f.high <= f.low && (0 === f.low ? f.high = 1 : f.low < 0 ? f.high = 0 : f.high > 0 ? f.low = 0 : (f.high = 1, f.low = 0)), f }, b.isNumeric = function (a) { return null !== a && isFinite(a) }, b.isFalseyButZero = function (a) { return !a && 0 !== a }, b.getNumberOrUndefined = function (a) { return b.isNumeric(a) ? +a : void 0 }, b.isMultiValue = function (a) { return "object" == typeof a && ("x" in a || "y" in a) }, b.getMultiValue = function (a, c) { return b.isMultiValue(a) ? b.getNumberOrUndefined(a[c || "y"]) : b.getNumberOrUndefined(a) }, b.rho = function (a) { function b(a, c) { return a % c === 0 ? c : b(c, a % c) } function c(a) { return a * a + 1 } if (1 === a) return a; var d, e = 2, f = 2; if (a % 2 === 0) return 2; do e = c(e) % a, f = c(c(f)) % a, d = b(Math.abs(e - f), a); while (1 === d); return d }, b.getBounds = function (a, c, d, e) { function f(a, b) { return a === (a += b) && (a *= 1 + (b > 0 ? o : -o)), a } var g, h, i, j = 0, k = { high: c.high, low: c.low }; k.valueRange = k.high - k.low, k.oom = b.orderOfMagnitude(k.valueRange), k.step = Math.pow(10, k.oom), k.min = Math.floor(k.low / k.step) * k.step, k.max = Math.ceil(k.high / k.step) * k.step, k.range = k.max - k.min, k.numberOfSteps = Math.round(k.range / k.step); var l = b.projectLength(a, k.step, k), m = l < d, n = e ? b.rho(k.range) : 0; if (e && b.projectLength(a, 1, k) >= d) k.step = 1; else if (e && n < k.step && b.projectLength(a, n, k) >= d) k.step = n; else for (; ;) { if (m && b.projectLength(a, k.step, k) <= d) k.step *= 2; else { if (m || !(b.projectLength(a, k.step / 2, k) >= d)) break; if (k.step /= 2, e && k.step % 1 !== 0) { k.step *= 2; break } } if (j++ > 1e3) throw new Error("Exceeded maximum number of iterations while optimizing scale step!") } var o = 2.221e-16; for (k.step = Math.max(k.step, o), h = k.min, i = k.max; h + k.step <= k.low;)h = f(h, k.step); for (; i - k.step >= k.high;)i = f(i, -k.step); k.min = h, k.max = i, k.range = k.max - k.min; var p = []; for (g = k.min; g <= k.max; g = f(g, k.step)) { var q = b.roundWithPrecision(g); q !== p[p.length - 1] && p.push(q) } return k.values = p, k }, b.polarToCartesian = function (a, b, c, d) { var e = (d - 90) * Math.PI / 180; return { x: a + c * Math.cos(e), y: b + c * Math.sin(e) } }, b.createChartRect = function (a, c, d) { var e = !(!c.axisX && !c.axisY), f = e ? c.axisY.offset : 0, g = e ? c.axisX.offset : 0, h = a.width() || b.quantity(c.width).value || 0, i = a.height() || b.quantity(c.height).value || 0, j = b.normalizePadding(c.chartPadding, d); h = Math.max(h, f + j.left + j.right), i = Math.max(i, g + j.top + j.bottom); var k = { padding: j, width: function () { return this.x2 - this.x1 }, height: function () { return this.y1 - this.y2 } }; return e ? ("start" === c.axisX.position ? (k.y2 = j.top + g, k.y1 = Math.max(i - j.bottom, k.y2 + 1)) : (k.y2 = j.top, k.y1 = Math.max(i - j.bottom - g, k.y2 + 1)), "start" === c.axisY.position ? (k.x1 = j.left + f, k.x2 = Math.max(h - j.right, k.x1 + 1)) : (k.x1 = j.left, k.x2 = Math.max(h - j.right - f, k.x1 + 1))) : (k.x1 = j.left, k.x2 = Math.max(h - j.right, k.x1 + 1), k.y2 = j.top, k.y1 = Math.max(i - j.bottom, k.y2 + 1)), k }, b.createGrid = function (a, c, d, e, f, g, h, i) { var j = {}; j[d.units.pos + "1"] = a, j[d.units.pos + "2"] = a, j[d.counterUnits.pos + "1"] = e, j[d.counterUnits.pos + "2"] = e + f; var k = g.elem("line", j, h.join(" ")); i.emit("draw", b.extend({ type: "grid", axis: d, index: c, group: g, element: k }, j)) }, b.createGridBackground = function (a, b, c, d) { var e = a.elem("rect", { x: b.x1, y: b.y2, width: b.width(), height: b.height() }, c, !0); d.emit("draw", { type: "gridBackground", group: a, element: e }) }, b.createLabel = function (a, c, e, f, g, h, i, j, k, l, m) { var n, o = {}; if (o[g.units.pos] = a + i[g.units.pos], o[g.counterUnits.pos] = i[g.counterUnits.pos], o[g.units.len] = c, o[g.counterUnits.len] = Math.max(0, h - 10), l) { var p = d.createElement("span"); p.className = k.join(" "), p.setAttribute("xmlns", b.namespaces.xhtml), p.innerText = f[e], p.style[g.units.len] = Math.round(o[g.units.len]) + "px", p.style[g.counterUnits.len] = Math.round(o[g.counterUnits.len]) + "px", n = j.foreignObject(p, b.extend({ style: "overflow: visible;" }, o)) } else n = j.elem("text", o, k.join(" ")).text(f[e]); m.emit("draw", b.extend({ type: "label", axis: g, index: e, group: j, element: n, text: f[e] }, o)) }, b.getSeriesOption = function (a, b, c) { if (a.name && b.series && b.series[a.name]) { var d = b.series[a.name]; return d.hasOwnProperty(c) ? d[c] : b[c] } return b[c] }, b.optionsProvider = function (a, d, e) { function f(a) { var f = h; if (h = b.extend({}, j), d) for (i = 0; i < d.length; i++) { var g = c.matchMedia(d[i][0]); g.matches && (h = b.extend(h, d[i][1])) } e && a && e.emit("optionsChanged", { previousOptions: f, currentOptions: h }) } function g() { k.forEach(function (a) { a.removeListener(f) }) } var h, i, j = b.extend({}, a), k = []; if (!c.matchMedia) throw "window.matchMedia not found! Make sure you're using a polyfill."; if (d) for (i = 0; i < d.length; i++) { var l = c.matchMedia(d[i][0]); l.addListener(f), k.push(l) } return f(), { removeMediaQueryListeners: g, getCurrentOptions: function () { return b.extend({}, h) } } }, b.splitIntoSegments = function (a, c, d) { var e = { increasingX: !1, fillHoles: !1 }; d = b.extend({}, e, d); for (var f = [], g = !0, h = 0; h < a.length; h += 2)void 0 === b.getMultiValue(c[h / 2].value) ? d.fillHoles || (g = !0) : (d.increasingX && h >= 2 && a[h] <= a[h - 2] && (g = !0), g && (f.push({ pathCoordinates: [], valueData: [] }), g = !1), f[f.length - 1].pathCoordinates.push(a[h], a[h + 1]), f[f.length - 1].valueData.push(c[h / 2])); return f } }(this || global, a), function (a, b) { "use strict"; b.Interpolation = {}, b.Interpolation.none = function (a) { var c = { fillHoles: !1 }; return a = b.extend({}, c, a), function (c, d) { for (var e = new b.Svg.Path, f = !0, g = 0; g < c.length; g += 2) { var h = c[g], i = c[g + 1], j = d[g / 2]; void 0 !== b.getMultiValue(j.value) ? (f ? e.move(h, i, !1, j) : e.line(h, i, !1, j), f = !1) : a.fillHoles || (f = !0) } return e } }, b.Interpolation.simple = function (a) { var c = { divisor: 2, fillHoles: !1 }; a = b.extend({}, c, a); var d = 1 / Math.max(1, a.divisor); return function (c, e) { for (var f, g, h, i = new b.Svg.Path, j = 0; j < c.length; j += 2) { var k = c[j], l = c[j + 1], m = (k - f) * d, n = e[j / 2]; void 0 !== n.value ? (void 0 === h ? i.move(k, l, !1, n) : i.curve(f + m, g, k - m, l, k, l, !1, n), f = k, g = l, h = n) : a.fillHoles || (f = k = h = void 0) } return i } }, b.Interpolation.cardinal = function (a) { var c = { tension: 1, fillHoles: !1 }; a = b.extend({}, c, a); var d = Math.min(1, Math.max(0, a.tension)), e = 1 - d; return function f(c, g) { var h = b.splitIntoSegments(c, g, { fillHoles: a.fillHoles }); if (h.length) { if (h.length > 1) { var i = []; return h.forEach(function (a) { i.push(f(a.pathCoordinates, a.valueData)) }), b.Svg.Path.join(i) } if (c = h[0].pathCoordinates, g = h[0].valueData, c.length <= 4) return b.Interpolation.none()(c, g); for (var j, k = (new b.Svg.Path).move(c[0], c[1], !1, g[0]), l = 0, m = c.length; m - 2 * !j > l; l += 2) { var n = [{ x: +c[l - 2], y: +c[l - 1] }, { x: +c[l], y: +c[l + 1] }, { x: +c[l + 2], y: +c[l + 3] }, { x: +c[l + 4], y: +c[l + 5] }]; j ? l ? m - 4 === l ? n[3] = { x: +c[0], y: +c[1] } : m - 2 === l && (n[2] = { x: +c[0], y: +c[1] }, n[3] = { x: +c[2], y: +c[3] }) : n[0] = { x: +c[m - 2], y: +c[m - 1] } : m - 4 === l ? n[3] = n[2] : l || (n[0] = { x: +c[l], y: +c[l + 1] }), k.curve(d * (-n[0].x + 6 * n[1].x + n[2].x) / 6 + e * n[2].x, d * (-n[0].y + 6 * n[1].y + n[2].y) / 6 + e * n[2].y, d * (n[1].x + 6 * n[2].x - n[3].x) / 6 + e * n[2].x, d * (n[1].y + 6 * n[2].y - n[3].y) / 6 + e * n[2].y, n[2].x, n[2].y, !1, g[(l + 2) / 2]) } return k } return b.Interpolation.none()([]) } }, b.Interpolation.monotoneCubic = function (a) { var c = { fillHoles: !1 }; return a = b.extend({}, c, a), function d(c, e) { var f = b.splitIntoSegments(c, e, { fillHoles: a.fillHoles, increasingX: !0 }); if (f.length) { if (f.length > 1) { var g = []; return f.forEach(function (a) { g.push(d(a.pathCoordinates, a.valueData)) }), b.Svg.Path.join(g) } if (c = f[0].pathCoordinates, e = f[0].valueData, c.length <= 4) return b.Interpolation.none()(c, e); var h, i, j = [], k = [], l = c.length / 2, m = [], n = [], o = [], p = []; for (h = 0; h < l; h++)j[h] = c[2 * h], k[h] = c[2 * h + 1]; for (h = 0; h < l - 1; h++)o[h] = k[h + 1] - k[h], p[h] = j[h + 1] - j[h], n[h] = o[h] / p[h]; for (m[0] = n[0], m[l - 1] = n[l - 2], h = 1; h < l - 1; h++)0 === n[h] || 0 === n[h - 1] || n[h - 1] > 0 != n[h] > 0 ? m[h] = 0 : (m[h] = 3 * (p[h - 1] + p[h]) / ((2 * p[h] + p[h - 1]) / n[h - 1] + (p[h] + 2 * p[h - 1]) / n[h]), isFinite(m[h]) || (m[h] = 0)); for (i = (new b.Svg.Path).move(j[0], k[0], !1, e[0]), h = 0; h < l - 1; h++)i.curve(j[h] + p[h] / 3, k[h] + m[h] * p[h] / 3, j[h + 1] - p[h] / 3, k[h + 1] - m[h + 1] * p[h] / 3, j[h + 1], k[h + 1], !1, e[h + 1]); return i } return b.Interpolation.none()([]) } }, b.Interpolation.step = function (a) { var c = { postpone: !0, fillHoles: !1 }; return a = b.extend({}, c, a), function (c, d) { for (var e, f, g, h = new b.Svg.Path, i = 0; i < c.length; i += 2) { var j = c[i], k = c[i + 1], l = d[i / 2]; void 0 !== l.value ? (void 0 === g ? h.move(j, k, !1, l) : (a.postpone ? h.line(j, f, !1, g) : h.line(e, k, !1, l), h.line(j, k, !1, l)), e = j, f = k, g = l) : a.fillHoles || (e = f = g = void 0) } return h } } }(this || global, a), function (a, b) { "use strict"; b.EventEmitter = function () { function a(a, b) { d[a] = d[a] || [], d[a].push(b) } function b(a, b) { d[a] && (b ? (d[a].splice(d[a].indexOf(b), 1), 0 === d[a].length && delete d[a]) : delete d[a]) } function c(a, b) { d[a] && d[a].forEach(function (a) { a(b) }), d["*"] && d["*"].forEach(function (c) { c(a, b) }) } var d = []; return { addEventHandler: a, removeEventHandler: b, emit: c } } }(this || global, a), function (a, b) { "use strict"; function c(a) { var b = []; if (a.length) for (var c = 0; c < a.length; c++)b.push(a[c]); return b } function d(a, c) { var d = c || this.prototype || b.Class, e = Object.create(d); b.Class.cloneDefinitions(e, a); var f = function () { var a, c = e.constructor || function () { }; return a = this === b ? Object.create(e) : this, c.apply(a, Array.prototype.slice.call(arguments, 0)), a }; return f.prototype = e, f["super"] = d, f.extend = this.extend, f } function e() { var a = c(arguments), b = a[0]; return a.splice(1, a.length - 1).forEach(function (a) { Object.getOwnPropertyNames(a).forEach(function (c) { delete b[c], Object.defineProperty(b, c, Object.getOwnPropertyDescriptor(a, c)) }) }), b } b.Class = { extend: d, cloneDefinitions: e } }(this || global, a), function (a, b) { "use strict"; function c(a, c, d) { return a && (this.data = a || {}, this.data.labels = this.data.labels || [], this.data.series = this.data.series || [], this.eventEmitter.emit("data", { type: "update", data: this.data })), c && (this.options = b.extend({}, d ? this.options : this.defaultOptions, c), this.initializeTimeoutId || (this.optionsProvider.removeMediaQueryListeners(), this.optionsProvider = b.optionsProvider(this.options, this.responsiveOptions, this.eventEmitter))), this.initializeTimeoutId || this.createChart(this.optionsProvider.getCurrentOptions()), this } function d() { return this.initializeTimeoutId ? i.clearTimeout(this.initializeTimeoutId) : (i.removeEventListener("resize", this.resizeListener), this.optionsProvider.removeMediaQueryListeners()), this } function e(a, b) { return this.eventEmitter.addEventHandler(a, b), this } function f(a, b) { return this.eventEmitter.removeEventHandler(a, b), this } function g() { i.addEventListener("resize", this.resizeListener), this.optionsProvider = b.optionsProvider(this.options, this.responsiveOptions, this.eventEmitter), this.eventEmitter.addEventHandler("optionsChanged", function () { this.update() }.bind(this)), this.options.plugins && this.options.plugins.forEach(function (a) { a instanceof Array ? a[0](this, a[1]) : a(this) }.bind(this)), this.eventEmitter.emit("data", { type: "initial", data: this.data }), this.createChart(this.optionsProvider.getCurrentOptions()), this.initializeTimeoutId = void 0 } function h(a, c, d, e, f) { this.container = b.querySelector(a), this.data = c || {}, this.data.labels = this.data.labels || [], this.data.series = this.data.series || [], this.defaultOptions = d, this.options = e, this.responsiveOptions = f, this.eventEmitter = b.EventEmitter(), this.supportsForeignObject = b.Svg.isSupported("Extensibility"), this.supportsAnimations = b.Svg.isSupported("AnimationEventsAttribute"), this.resizeListener = function () { this.update() }.bind(this), this.container && (this.container.__chartist__ && this.container.__chartist__.detach(), this.container.__chartist__ = this), this.initializeTimeoutId = setTimeout(g.bind(this), 0) } var i = a.window; b.Base = b.Class.extend({ constructor: h, optionsProvider: void 0, container: void 0, svg: void 0, eventEmitter: void 0, createChart: function () { throw new Error("Base chart type can't be instantiated!") }, update: c, detach: d, on: e, off: f, version: b.version, supportsForeignObject: !1 }) }(this || global, a), function (a, b) { "use strict"; function c(a, c, d, e, f) { a instanceof Element ? this._node = a : (this._node = y.createElementNS(b.namespaces.svg, a), "svg" === a && this.attr({ "xmlns:ct": b.namespaces.ct })), c && this.attr(c), d && this.addClass(d), e && (f && e._node.firstChild ? e._node.insertBefore(this._node, e._node.firstChild) : e._node.appendChild(this._node)) } function d(a, c) { return "string" == typeof a ? c ? this._node.getAttributeNS(c, a) : this._node.getAttribute(a) : (Object.keys(a).forEach(function (c) { if (void 0 !== a[c]) if (c.indexOf(":") !== -1) { var d = c.split(":"); this._node.setAttributeNS(b.namespaces[d[0]], c, a[c]) } else this._node.setAttribute(c, a[c]) }.bind(this)), this) } function e(a, c, d, e) { return new b.Svg(a, c, d, this, e) } function f() { return this._node.parentNode instanceof SVGElement ? new b.Svg(this._node.parentNode) : null } function g() { for (var a = this._node; "svg" !== a.nodeName;)a = a.parentNode; return new b.Svg(a) } function h(a) { var c = this._node.querySelector(a); return c ? new b.Svg(c) : null } function i(a) { var c = this._node.querySelectorAll(a); return c.length ? new b.Svg.List(c) : null } function j() { return this._node } function k(a, c, d, e) { if ("string" == typeof a) { var f = y.createElement("div"); f.innerHTML = a, a = f.firstChild } a.setAttribute("xmlns", b.namespaces.xmlns); var g = this.elem("foreignObject", c, d, e); return g._node.appendChild(a), g } function l(a) { return this._node.appendChild(y.createTextNode(a)), this } function m() { for (; this._node.firstChild;)this._node.removeChild(this._node.firstChild); return this } function n() { return this._node.parentNode.removeChild(this._node), this.parent() } function o(a) { return this._node.parentNode.replaceChild(a._node, this._node), a } function p(a, b) { return b && this._node.firstChild ? this._node.insertBefore(a._node, this._node.firstChild) : this._node.appendChild(a._node), this } function q() { return this._node.getAttribute("class") ? this._node.getAttribute("class").trim().split(/\s+/) : [] } function r(a) { return this._node.setAttribute("class", this.classes(this._node).concat(a.trim().split(/\s+/)).filter(function (a, b, c) { return c.indexOf(a) === b }).join(" ")), this } function s(a) { var b = a.trim().split(/\s+/); return this._node.setAttribute("class", this.classes(this._node).filter(function (a) { return b.indexOf(a) === -1 }).join(" ")), this } function t() { return this._node.setAttribute("class", ""), this } function u() { return this._node.getBoundingClientRect().height } function v() { return this._node.getBoundingClientRect().width } function w(a, c, d) { return void 0 === c && (c = !0), Object.keys(a).forEach(function (e) { function f(a, c) { var f, g, h, i = {}; a.easing && (h = a.easing instanceof Array ? a.easing : b.Svg.Easing[a.easing], delete a.easing), a.begin = b.ensureUnit(a.begin, "ms"), a.dur = b.ensureUnit(a.dur, "ms"), h && (a.calcMode = "spline", a.keySplines = h.join(" "), a.keyTimes = "0;1"), c && (a.fill = "freeze", i[e] = a.from, this.attr(i), g = b.quantity(a.begin || 0).value, a.begin = "indefinite"), f = this.elem("animate", b.extend({ attributeName: e }, a)), c && setTimeout(function () { try { f._node.beginElement() } catch (b) { i[e] = a.to, this.attr(i), f.remove() } }.bind(this), g), d && f._node.addEventListener("beginEvent", function () { d.emit("animationBegin", { element: this, animate: f._node, params: a }) }.bind(this)), f._node.addEventListener("endEvent", function () { d && d.emit("animationEnd", { element: this, animate: f._node, params: a }), c && (i[e] = a.to, this.attr(i), f.remove()) }.bind(this)) } a[e] instanceof Array ? a[e].forEach(function (a) { f.bind(this)(a, !1) }.bind(this)) : f.bind(this)(a[e], c) }.bind(this)), this } function x(a) { var c = this; this.svgElements = []; for (var d = 0; d < a.length; d++)this.svgElements.push(new b.Svg(a[d])); Object.keys(b.Svg.prototype).filter(function (a) { return ["constructor", "parent", "querySelector", "querySelectorAll", "replace", "append", "classes", "height", "width"].indexOf(a) === -1 }).forEach(function (a) { c[a] = function () { var d = Array.prototype.slice.call(arguments, 0); return c.svgElements.forEach(function (c) { b.Svg.prototype[a].apply(c, d) }), c } }) } var y = a.document; b.Svg = b.Class.extend({ constructor: c, attr: d, elem: e, parent: f, root: g, querySelector: h, querySelectorAll: i, getNode: j, foreignObject: k, text: l, empty: m, remove: n, replace: o, append: p, classes: q, addClass: r, removeClass: s, removeAllClasses: t, height: u, width: v, animate: w }), b.Svg.isSupported = function (a) { return y.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#" + a, "1.1") }; var z = { easeInSine: [.47, 0, .745, .715], easeOutSine: [.39, .575, .565, 1], easeInOutSine: [.445, .05, .55, .95], easeInQuad: [.55, .085, .68, .53], easeOutQuad: [.25, .46, .45, .94], easeInOutQuad: [.455, .03, .515, .955], easeInCubic: [.55, .055, .675, .19], easeOutCubic: [.215, .61, .355, 1], easeInOutCubic: [.645, .045, .355, 1], easeInQuart: [.895, .03, .685, .22], easeOutQuart: [.165, .84, .44, 1], easeInOutQuart: [.77, 0, .175, 1], easeInQuint: [.755, .05, .855, .06], easeOutQuint: [.23, 1, .32, 1], easeInOutQuint: [.86, 0, .07, 1], easeInExpo: [.95, .05, .795, .035], easeOutExpo: [.19, 1, .22, 1], easeInOutExpo: [1, 0, 0, 1], easeInCirc: [.6, .04, .98, .335], easeOutCirc: [.075, .82, .165, 1], easeInOutCirc: [.785, .135, .15, .86], easeInBack: [.6, -.28, .735, .045], easeOutBack: [.175, .885, .32, 1.275], easeInOutBack: [.68, -.55, .265, 1.55] }; b.Svg.Easing = z, b.Svg.List = b.Class.extend({ constructor: x }) }(this || global, a), function (a, b) { "use strict"; function c(a, c, d, e, f, g) { var h = b.extend({ command: f ? a.toLowerCase() : a.toUpperCase() }, c, g ? { data: g } : {}); d.splice(e, 0, h) } function d(a, b) { a.forEach(function (c, d) { t[c.command.toLowerCase()].forEach(function (e, f) { b(c, e, d, f, a) }) }) } function e(a, c) { this.pathElements = [], this.pos = 0, this.close = a, this.options = b.extend({}, u, c) } function f(a) { return void 0 !== a ? (this.pos = Math.max(0, Math.min(this.pathElements.length, a)), this) : this.pos } function g(a) { return this.pathElements.splice(this.pos, a), this } function h(a, b, d, e) { return c("M", { x: +a, y: +b }, this.pathElements, this.pos++, d, e), this } function i(a, b, d, e) { return c("L", { x: +a, y: +b }, this.pathElements, this.pos++, d, e), this } function j(a, b, d, e, f, g, h, i) { return c("C", { x1: +a, y1: +b, x2: +d, y2: +e, x: +f, y: +g }, this.pathElements, this.pos++, h, i), this } function k(a, b, d, e, f, g, h, i, j) { return c("A", { rx: +a, ry: +b, xAr: +d, lAf: +e, sf: +f, x: +g, y: +h }, this.pathElements, this.pos++, i, j), this } function l(a) { var c = a.replace(/([A-Za-z])([0-9])/g, "$1 $2").replace(/([0-9])([A-Za-z])/g, "$1 $2").split(/[\s,]+/).reduce(function (a, b) { return b.match(/[A-Za-z]/) && a.push([]), a[a.length - 1].push(b), a }, []); "Z" === c[c.length - 1][0].toUpperCase() && c.pop(); var d = c.map(function (a) { var c = a.shift(), d = t[c.toLowerCase()]; return b.extend({ command: c }, d.reduce(function (b, c, d) { return b[c] = +a[d], b }, {})) }), e = [this.pos, 0]; return Array.prototype.push.apply(e, d), Array.prototype.splice.apply(this.pathElements, e), this.pos += d.length, this } function m() { var a = Math.pow(10, this.options.accuracy); return this.pathElements.reduce(function (b, c) { var d = t[c.command.toLowerCase()].map(function (b) { return this.options.accuracy ? Math.round(c[b] * a) / a : c[b] }.bind(this)); return b + c.command + d.join(",") }.bind(this), "") + (this.close ? "Z" : "") } function n(a, b) { return d(this.pathElements, function (c, d) { c[d] *= "x" === d[0] ? a : b }), this } function o(a, b) { return d(this.pathElements, function (c, d) { c[d] += "x" === d[0] ? a : b }), this } function p(a) { return d(this.pathElements, function (b, c, d, e, f) { var g = a(b, c, d, e, f); (g || 0 === g) && (b[c] = g) }), this } function q(a) { var c = new b.Svg.Path(a || this.close); return c.pos = this.pos, c.pathElements = this.pathElements.slice().map(function (a) { return b.extend({}, a) }), c.options = b.extend({}, this.options), c } function r(a) { var c = [new b.Svg.Path]; return this.pathElements.forEach(function (d) { d.command === a.toUpperCase() && 0 !== c[c.length - 1].pathElements.length && c.push(new b.Svg.Path), c[c.length - 1].pathElements.push(d) }), c } function s(a, c, d) { for (var e = new b.Svg.Path(c, d), f = 0; f < a.length; f++)for (var g = a[f], h = 0; h < g.pathElements.length; h++)e.pathElements.push(g.pathElements[h]); return e } var t = { m: ["x", "y"], l: ["x", "y"], c: ["x1", "y1", "x2", "y2", "x", "y"], a: ["rx", "ry", "xAr", "lAf", "sf", "x", "y"] }, u = { accuracy: 3 }; b.Svg.Path = b.Class.extend({ constructor: e, position: f, remove: g, move: h, line: i, curve: j, arc: k, scale: n, translate: o, transform: p, parse: l, stringify: m, clone: q, splitByCommand: r }), b.Svg.Path.elementDescriptions = t, b.Svg.Path.join = s }(this || global, a), function (a, b) { "use strict"; function c(a, b, c, d) { this.units = a, this.counterUnits = a === e.x ? e.y : e.x, this.chartRect = b, this.axisLength = b[a.rectEnd] - b[a.rectStart], this.gridOffset = b[a.rectOffset], this.ticks = c, this.options = d } function d(a, c, d, e, f) { var g = e["axis" + this.units.pos.toUpperCase()], h = this.ticks.map(this.projectValue.bind(this)), i = this.ticks.map(g.labelInterpolationFnc); h.forEach(function (j, k) { var l, m = { x: 0, y: 0 }; l = h[k + 1] ? h[k + 1] - j : Math.max(this.axisLength - j, 30), b.isFalseyButZero(i[k]) && "" !== i[k] || ("x" === this.units.pos ? (j = this.chartRect.x1 + j, m.x = e.axisX.labelOffset.x, "start" === e.axisX.position ? m.y = this.chartRect.padding.top + e.axisX.labelOffset.y + (d ? 5 : 20) : m.y = this.chartRect.y1 + e.axisX.labelOffset.y + (d ? 5 : 20)) : (j = this.chartRect.y1 - j, m.y = e.axisY.labelOffset.y - (d ? l : 0), "start" === e.axisY.position ? m.x = d ? this.chartRect.padding.left + e.axisY.labelOffset.x : this.chartRect.x1 - 10 : m.x = this.chartRect.x2 + e.axisY.labelOffset.x + 10), g.showGrid && b.createGrid(j, k, this, this.gridOffset, this.chartRect[this.counterUnits.len](), a, [e.classNames.grid, e.classNames[this.units.dir]], f), g.showLabel && b.createLabel(j, l, k, i, this, g.offset, m, c, [e.classNames.label, e.classNames[this.units.dir], "start" === g.position ? e.classNames[g.position] : e.classNames.end], d, f)) }.bind(this)) } var e = (a.window, a.document, { x: { pos: "x", len: "width", dir: "horizontal", rectStart: "x1", rectEnd: "x2", rectOffset: "y2" }, y: { pos: "y", len: "height", dir: "vertical", rectStart: "y2", rectEnd: "y1", rectOffset: "x1" } }); b.Axis = b.Class.extend({ constructor: c, createGridAndLabels: d, projectValue: function (a, b, c) { throw new Error("Base axis can't be instantiated!") } }), b.Axis.units = e }(this || global, a), function (a, b) { "use strict"; function c(a, c, d, e) { var f = e.highLow || b.getHighLow(c, e, a.pos); this.bounds = b.getBounds(d[a.rectEnd] - d[a.rectStart], f, e.scaleMinSpace || 20, e.onlyInteger), this.range = { min: this.bounds.min, max: this.bounds.max }, b.AutoScaleAxis["super"].constructor.call(this, a, d, this.bounds.values, e) } function d(a) { return this.axisLength * (+b.getMultiValue(a, this.units.pos) - this.bounds.min) / this.bounds.range } a.window, a.document; b.AutoScaleAxis = b.Axis.extend({ constructor: c, projectValue: d }) }(this || global, a), function (a, b) { "use strict"; function c(a, c, d, e) { var f = e.highLow || b.getHighLow(c, e, a.pos); this.divisor = e.divisor || 1, this.ticks = e.ticks || b.times(this.divisor).map(function (a, b) { return f.low + (f.high - f.low) / this.divisor * b }.bind(this)), this.ticks.sort(function (a, b) { return a - b }), this.range = { min: f.low, max: f.high }, b.FixedScaleAxis["super"].constructor.call(this, a, d, this.ticks, e), this.stepLength = this.axisLength / this.divisor } function d(a) { return this.axisLength * (+b.getMultiValue(a, this.units.pos) - this.range.min) / (this.range.max - this.range.min) } a.window, a.document; b.FixedScaleAxis = b.Axis.extend({ constructor: c, projectValue: d }) }(this || global, a), function (a, b) { "use strict"; function c(a, c, d, e) { b.StepAxis["super"].constructor.call(this, a, d, e.ticks, e); var f = Math.max(1, e.ticks.length - (e.stretch ? 1 : 0)); this.stepLength = this.axisLength / f } function d(a, b) { return this.stepLength * b } a.window, a.document; b.StepAxis = b.Axis.extend({ constructor: c, projectValue: d }) }(this || global, a), function (a, b) { "use strict"; function c(a) { var c = b.normalizeData(this.data, a.reverseData, !0); this.svg = b.createSvg(this.container, a.width, a.height, a.classNames.chart); var d, f, g = this.svg.elem("g").addClass(a.classNames.gridGroup), h = this.svg.elem("g"), i = this.svg.elem("g").addClass(a.classNames.labelGroup), j = b.createChartRect(this.svg, a, e.padding); d = void 0 === a.axisX.type ? new b.StepAxis(b.Axis.units.x, c.normalized.series, j, b.extend({}, a.axisX, { ticks: c.normalized.labels, stretch: a.fullWidth })) : a.axisX.type.call(b, b.Axis.units.x, c.normalized.series, j, a.axisX), f = void 0 === a.axisY.type ? new b.AutoScaleAxis(b.Axis.units.y, c.normalized.series, j, b.extend({}, a.axisY, { high: b.isNumeric(a.high) ? a.high : a.axisY.high, low: b.isNumeric(a.low) ? a.low : a.axisY.low })) : a.axisY.type.call(b, b.Axis.units.y, c.normalized.series, j, a.axisY), d.createGridAndLabels(g, i, this.supportsForeignObject, a, this.eventEmitter), f.createGridAndLabels(g, i, this.supportsForeignObject, a, this.eventEmitter), a.showGridBackground && b.createGridBackground(g, j, a.classNames.gridBackground, this.eventEmitter), c.raw.series.forEach(function (e, g) { var i = h.elem("g"); i.attr({ "ct:series-name": e.name, "ct:meta": b.serialize(e.meta) }), i.addClass([a.classNames.series, e.className || a.classNames.series + "-" + b.alphaNumerate(g)].join(" ")); var k = [], l = []; c.normalized.series[g].forEach(function (a, h) { var i = { x: j.x1 + d.projectValue(a, h, c.normalized.series[g]), y: j.y1 - f.projectValue(a, h, c.normalized.series[g]) }; k.push(i.x, i.y), l.push({ value: a, valueIndex: h, meta: b.getMetaData(e, h) }) }.bind(this)); var m = { lineSmooth: b.getSeriesOption(e, a, "lineSmooth"), showPoint: b.getSeriesOption(e, a, "showPoint"), showLine: b.getSeriesOption(e, a, "showLine"), showArea: b.getSeriesOption(e, a, "showArea"), areaBase: b.getSeriesOption(e, a, "areaBase") }, n = "function" == typeof m.lineSmooth ? m.lineSmooth : m.lineSmooth ? b.Interpolation.monotoneCubic() : b.Interpolation.none(), o = n(k, l); if (m.showPoint && o.pathElements.forEach(function (c) { var h = i.elem("line", { x1: c.x, y1: c.y, x2: c.x + .01, y2: c.y }, a.classNames.point).attr({ "ct:value": [c.data.value.x, c.data.value.y].filter(b.isNumeric).join(","), "ct:meta": b.serialize(c.data.meta) }); this.eventEmitter.emit("draw", { type: "point", value: c.data.value, index: c.data.valueIndex, meta: c.data.meta, series: e, seriesIndex: g, axisX: d, axisY: f, group: i, element: h, x: c.x, y: c.y }) }.bind(this)), m.showLine) { var p = i.elem("path", { d: o.stringify() }, a.classNames.line, !0); this.eventEmitter.emit("draw", { type: "line", values: c.normalized.series[g], path: o.clone(), chartRect: j, index: g, series: e, seriesIndex: g, seriesMeta: e.meta, axisX: d, axisY: f, group: i, element: p }) } if (m.showArea && f.range) { var q = Math.max(Math.min(m.areaBase, f.range.max), f.range.min), r = j.y1 - f.projectValue(q); o.splitByCommand("M").filter(function (a) { return a.pathElements.length > 1 }).map(function (a) { var b = a.pathElements[0], c = a.pathElements[a.pathElements.length - 1]; return a.clone(!0).position(0).remove(1).move(b.x, r).line(b.x, b.y).position(a.pathElements.length + 1).line(c.x, r) }).forEach(function (b) { var h = i.elem("path", { d: b.stringify() }, a.classNames.area, !0); this.eventEmitter.emit("draw", { type: "area", values: c.normalized.series[g], path: b.clone(), series: e, seriesIndex: g, axisX: d, axisY: f, chartRect: j, index: g, group: i, element: h }) }.bind(this)) } }.bind(this)), this.eventEmitter.emit("created", { bounds: f.bounds, chartRect: j, axisX: d, axisY: f, svg: this.svg, options: a }) } function d(a, c, d, f) { b.Line["super"].constructor.call(this, a, c, e, b.extend({}, e, d), f) } var e = (a.window, a.document, { axisX: { offset: 30, position: "end", labelOffset: { x: 0, y: 0 }, showLabel: !0, showGrid: !0, labelInterpolationFnc: b.noop, type: void 0 }, axisY: { offset: 40, position: "start", labelOffset: { x: 0, y: 0 }, showLabel: !0, showGrid: !0, labelInterpolationFnc: b.noop, type: void 0, scaleMinSpace: 20, onlyInteger: !1 }, width: void 0, height: void 0, showLine: !0, showPoint: !0, showArea: !1, areaBase: 0, lineSmooth: !0, showGridBackground: !1, low: void 0, high: void 0, chartPadding: { top: 15, right: 15, bottom: 5, left: 10 }, fullWidth: !1, reverseData: !1, classNames: { chart: "ct-chart-line", label: "ct-label", labelGroup: "ct-labels", series: "ct-series", line: "ct-line", point: "ct-point", area: "ct-area", grid: "ct-grid", gridGroup: "ct-grids", gridBackground: "ct-grid-background", vertical: "ct-vertical", horizontal: "ct-horizontal", start: "ct-start", end: "ct-end" } }); b.Line = b.Base.extend({ constructor: d, createChart: c }) }(this || global, a), function (a, b) { + "use strict"; function c(a) { + var c, d; a.distributeSeries ? (c = b.normalizeData(this.data, a.reverseData, a.horizontalBars ? "x" : "y"), c.normalized.series = c.normalized.series.map(function (a) { return [a] })) : c = b.normalizeData(this.data, a.reverseData, a.horizontalBars ? "x" : "y"), this.svg = b.createSvg(this.container, a.width, a.height, a.classNames.chart + (a.horizontalBars ? " " + a.classNames.horizontalBars : "")); var f = this.svg.elem("g").addClass(a.classNames.gridGroup), g = this.svg.elem("g"), h = this.svg.elem("g").addClass(a.classNames.labelGroup); + if (a.stackBars && 0 !== c.normalized.series.length) { var i = b.serialMap(c.normalized.series, function () { return Array.prototype.slice.call(arguments).map(function (a) { return a }).reduce(function (a, b) { return { x: a.x + (b && b.x) || 0, y: a.y + (b && b.y) || 0 } }, { x: 0, y: 0 }) }); d = b.getHighLow([i], a, a.horizontalBars ? "x" : "y") } else d = b.getHighLow(c.normalized.series, a, a.horizontalBars ? "x" : "y"); d.high = +a.high || (0 === a.high ? 0 : d.high), d.low = +a.low || (0 === a.low ? 0 : d.low); var j, k, l, m, n, o = b.createChartRect(this.svg, a, e.padding); k = a.distributeSeries && a.stackBars ? c.normalized.labels.slice(0, 1) : c.normalized.labels, a.horizontalBars ? (j = m = void 0 === a.axisX.type ? new b.AutoScaleAxis(b.Axis.units.x, c.normalized.series, o, b.extend({}, a.axisX, { highLow: d, referenceValue: 0 })) : a.axisX.type.call(b, b.Axis.units.x, c.normalized.series, o, b.extend({}, a.axisX, { highLow: d, referenceValue: 0 })), l = n = void 0 === a.axisY.type ? new b.StepAxis(b.Axis.units.y, c.normalized.series, o, { ticks: k }) : a.axisY.type.call(b, b.Axis.units.y, c.normalized.series, o, a.axisY)) : (l = m = void 0 === a.axisX.type ? new b.StepAxis(b.Axis.units.x, c.normalized.series, o, { ticks: k }) : a.axisX.type.call(b, b.Axis.units.x, c.normalized.series, o, a.axisX), j = n = void 0 === a.axisY.type ? new b.AutoScaleAxis(b.Axis.units.y, c.normalized.series, o, b.extend({}, a.axisY, { highLow: d, referenceValue: 0 })) : a.axisY.type.call(b, b.Axis.units.y, c.normalized.series, o, b.extend({}, a.axisY, { highLow: d, referenceValue: 0 }))); var p = a.horizontalBars ? o.x1 + j.projectValue(0) : o.y1 - j.projectValue(0), q = []; l.createGridAndLabels(f, h, this.supportsForeignObject, a, this.eventEmitter), j.createGridAndLabels(f, h, this.supportsForeignObject, a, this.eventEmitter), a.showGridBackground && b.createGridBackground(f, o, a.classNames.gridBackground, this.eventEmitter), c.raw.series.forEach(function (d, e) { var f, h, i = e - (c.raw.series.length - 1) / 2; f = a.distributeSeries && !a.stackBars ? l.axisLength / c.normalized.series.length / 2 : a.distributeSeries && a.stackBars ? l.axisLength / 2 : l.axisLength / c.normalized.series[e].length / 2, h = g.elem("g"), h.attr({ "ct:series-name": d.name, "ct:meta": b.serialize(d.meta) }), h.addClass([a.classNames.series, d.className || a.classNames.series + "-" + b.alphaNumerate(e)].join(" ")), c.normalized.series[e].forEach(function (g, k) { var r, s, t, u; if (u = a.distributeSeries && !a.stackBars ? e : a.distributeSeries && a.stackBars ? 0 : k, r = a.horizontalBars ? { x: o.x1 + j.projectValue(g && g.x ? g.x : 0, k, c.normalized.series[e]), y: o.y1 - l.projectValue(g && g.y ? g.y : 0, u, c.normalized.series[e]) } : { x: o.x1 + l.projectValue(g && g.x ? g.x : 0, u, c.normalized.series[e]), y: o.y1 - j.projectValue(g && g.y ? g.y : 0, k, c.normalized.series[e]) }, l instanceof b.StepAxis && (l.options.stretch || (r[l.units.pos] += f * (a.horizontalBars ? -1 : 1)), r[l.units.pos] += a.stackBars || a.distributeSeries ? 0 : i * a.seriesBarDistance * (a.horizontalBars ? -1 : 1)), t = q[k] || p, q[k] = t - (p - r[l.counterUnits.pos]), void 0 !== g) { var v = {}; v[l.units.pos + "1"] = r[l.units.pos], v[l.units.pos + "2"] = r[l.units.pos], !a.stackBars || "accumulate" !== a.stackMode && a.stackMode ? (v[l.counterUnits.pos + "1"] = p, v[l.counterUnits.pos + "2"] = r[l.counterUnits.pos]) : (v[l.counterUnits.pos + "1"] = t, v[l.counterUnits.pos + "2"] = q[k]), v.x1 = Math.min(Math.max(v.x1, o.x1), o.x2), v.x2 = Math.min(Math.max(v.x2, o.x1), o.x2), v.y1 = Math.min(Math.max(v.y1, o.y2), o.y1), v.y2 = Math.min(Math.max(v.y2, o.y2), o.y1); var w = b.getMetaData(d, k); s = h.elem("line", v, a.classNames.bar).attr({ "ct:value": [g.x, g.y].filter(b.isNumeric).join(","), "ct:meta": b.serialize(w) }), this.eventEmitter.emit("draw", b.extend({ type: "bar", value: g, index: k, meta: w, series: d, seriesIndex: e, axisX: m, axisY: n, chartRect: o, group: h, element: s }, v)) } }.bind(this)) }.bind(this)), this.eventEmitter.emit("created", { bounds: j.bounds, chartRect: o, axisX: m, axisY: n, svg: this.svg, options: a }) + } function d(a, c, d, f) { b.Bar["super"].constructor.call(this, a, c, e, b.extend({}, e, d), f) } var e = (a.window, a.document, { axisX: { offset: 30, position: "end", labelOffset: { x: 0, y: 0 }, showLabel: !0, showGrid: !0, labelInterpolationFnc: b.noop, scaleMinSpace: 30, onlyInteger: !1 }, axisY: { offset: 40, position: "start", labelOffset: { x: 0, y: 0 }, showLabel: !0, showGrid: !0, labelInterpolationFnc: b.noop, scaleMinSpace: 20, onlyInteger: !1 }, width: void 0, height: void 0, high: void 0, low: void 0, referenceValue: 0, chartPadding: { top: 15, right: 15, bottom: 5, left: 10 }, seriesBarDistance: 15, stackBars: !1, stackMode: "accumulate", horizontalBars: !1, distributeSeries: !1, reverseData: !1, showGridBackground: !1, classNames: { chart: "ct-chart-bar", horizontalBars: "ct-horizontal-bars", label: "ct-label", labelGroup: "ct-labels", series: "ct-series", bar: "ct-bar", grid: "ct-grid", gridGroup: "ct-grids", gridBackground: "ct-grid-background", vertical: "ct-vertical", horizontal: "ct-horizontal", start: "ct-start", end: "ct-end" } }); b.Bar = b.Base.extend({ constructor: d, createChart: c }) + }(this || global, a), function (a, b) { "use strict"; function c(a, b, c) { var d = b.x > a.x; return d && "explode" === c || !d && "implode" === c ? "start" : d && "implode" === c || !d && "explode" === c ? "end" : "middle" } function d(a) { var d, e, g, h, i, j = b.normalizeData(this.data), k = [], l = a.startAngle; this.svg = b.createSvg(this.container, a.width, a.height, a.donut ? a.classNames.chartDonut : a.classNames.chartPie), e = b.createChartRect(this.svg, a, f.padding), g = Math.min(e.width() / 2, e.height() / 2), i = a.total || j.normalized.series.reduce(function (a, b) { return a + b }, 0); var m = b.quantity(a.donutWidth); "%" === m.unit && (m.value *= g / 100), g -= a.donut && !a.donutSolid ? m.value / 2 : 0, h = "outside" === a.labelPosition || a.donut && !a.donutSolid ? g : "center" === a.labelPosition ? 0 : a.donutSolid ? g - m.value / 2 : g / 2, h += a.labelOffset; var n = { x: e.x1 + e.width() / 2, y: e.y2 + e.height() / 2 }, o = 1 === j.raw.series.filter(function (a) { return a.hasOwnProperty("value") ? 0 !== a.value : 0 !== a }).length; j.raw.series.forEach(function (a, b) { k[b] = this.svg.elem("g", null, null) }.bind(this)), a.showLabel && (d = this.svg.elem("g", null, null)), j.raw.series.forEach(function (e, f) { if (0 !== j.normalized.series[f] || !a.ignoreEmptyValues) { k[f].attr({ "ct:series-name": e.name }), k[f].addClass([a.classNames.series, e.className || a.classNames.series + "-" + b.alphaNumerate(f)].join(" ")); var p = i > 0 ? l + j.normalized.series[f] / i * 360 : 0, q = Math.max(0, l - (0 === f || o ? 0 : .2)); p - q >= 359.99 && (p = q + 359.99); var r, s, t, u = b.polarToCartesian(n.x, n.y, g, q), v = b.polarToCartesian(n.x, n.y, g, p), w = new b.Svg.Path(!a.donut || a.donutSolid).move(v.x, v.y).arc(g, g, 0, p - l > 180, 0, u.x, u.y); a.donut ? a.donutSolid && (t = g - m.value, r = b.polarToCartesian(n.x, n.y, t, l - (0 === f || o ? 0 : .2)), s = b.polarToCartesian(n.x, n.y, t, p), w.line(r.x, r.y), w.arc(t, t, 0, p - l > 180, 1, s.x, s.y)) : w.line(n.x, n.y); var x = a.classNames.slicePie; a.donut && (x = a.classNames.sliceDonut, a.donutSolid && (x = a.classNames.sliceDonutSolid)); var y = k[f].elem("path", { d: w.stringify() }, x); if (y.attr({ "ct:value": j.normalized.series[f], "ct:meta": b.serialize(e.meta) }), a.donut && !a.donutSolid && (y._node.style.strokeWidth = m.value + "px"), this.eventEmitter.emit("draw", { type: "slice", value: j.normalized.series[f], totalDataSum: i, index: f, meta: e.meta, series: e, group: k[f], element: y, path: w.clone(), center: n, radius: g, startAngle: l, endAngle: p }), a.showLabel) { var z; z = 1 === j.raw.series.length ? { x: n.x, y: n.y } : b.polarToCartesian(n.x, n.y, h, l + (p - l) / 2); var A; A = j.normalized.labels && !b.isFalseyButZero(j.normalized.labels[f]) ? j.normalized.labels[f] : j.normalized.series[f]; var B = a.labelInterpolationFnc(A, f); if (B || 0 === B) { var C = d.elem("text", { dx: z.x, dy: z.y, "text-anchor": c(n, z, a.labelDirection) }, a.classNames.label).text("" + B); this.eventEmitter.emit("draw", { type: "label", index: f, group: d, element: C, text: "" + B, x: z.x, y: z.y }) } } l = p } }.bind(this)), this.eventEmitter.emit("created", { chartRect: e, svg: this.svg, options: a }) } function e(a, c, d, e) { b.Pie["super"].constructor.call(this, a, c, f, b.extend({}, f, d), e) } var f = (a.window, a.document, { width: void 0, height: void 0, chartPadding: 5, classNames: { chartPie: "ct-chart-pie", chartDonut: "ct-chart-donut", series: "ct-series", slicePie: "ct-slice-pie", sliceDonut: "ct-slice-donut", sliceDonutSolid: "ct-slice-donut-solid", label: "ct-label" }, startAngle: 0, total: void 0, donut: !1, donutSolid: !1, donutWidth: 60, showLabel: !0, labelOffset: 0, labelPosition: "inside", labelInterpolationFnc: b.noop, labelDirection: "neutral", reverseData: !1, ignoreEmptyValues: !1 }); b.Pie = b.Base.extend({ constructor: e, createChart: d, determineAnchorPosition: c }) }(this || global, a), a +}); +//# sourceMappingURL=chartist.min.js.map + +var i, l, selectedLine = null; + +/* Navigate to hash without browser history entry */ +var navigateToHash = function () { + if (window.history !== undefined && window.history.replaceState !== undefined) { + window.history.replaceState(undefined, undefined, this.getAttribute("href")); + } +}; + +var hashLinks = document.getElementsByClassName('navigatetohash'); +for (i = 0, l = hashLinks.length; i < l; i++) { + hashLinks[i].addEventListener('click', navigateToHash); +} + +/* Switch test method */ +var switchTestMethod = function () { + var method = this.getAttribute("value"); + console.log("Selected test method: " + method); + + var lines, i, l, coverageData, lineAnalysis, cells; + + lines = document.querySelectorAll('.lineAnalysis tr'); + + for (i = 1, l = lines.length; i < l; i++) { + coverageData = JSON.parse(lines[i].getAttribute('data-coverage').replace(/'/g, '"')); + lineAnalysis = coverageData[method]; + cells = lines[i].querySelectorAll('td'); + if (lineAnalysis === undefined) { + lineAnalysis = coverageData.AllTestMethods; + if (lineAnalysis.LVS !== 'gray') { + cells[0].setAttribute('class', 'red'); + cells[1].innerText = cells[1].textContent = '0'; + cells[4].setAttribute('class', 'lightred'); + } + } else { + cells[0].setAttribute('class', lineAnalysis.LVS); + cells[1].innerText = cells[1].textContent = lineAnalysis.VC; + cells[4].setAttribute('class', 'light' + lineAnalysis.LVS); + } + } +}; + +var testMethods = document.getElementsByClassName('switchtestmethod'); +for (i = 0, l = testMethods.length; i < l; i++) { + testMethods[i].addEventListener('change', switchTestMethod); +} + +/* Highlight test method by line */ +var toggleLine = function () { + if (selectedLine === this) { + selectedLine = null; + } else { + selectedLine = null; + unhighlightTestMethods(); + highlightTestMethods.call(this); + selectedLine = this; + } + +}; +var highlightTestMethods = function () { + if (selectedLine !== null) { + return; + } + + var lineAnalysis; + var coverageData = JSON.parse(this.getAttribute('data-coverage').replace(/'/g, '"')); + var testMethods = document.getElementsByClassName('testmethod'); + + for (i = 0, l = testMethods.length; i < l; i++) { + lineAnalysis = coverageData[testMethods[i].id]; + if (lineAnalysis === undefined) { + testMethods[i].className = testMethods[i].className.replace(/\s*light.+/g, ""); + } else { + testMethods[i].className += ' light' + lineAnalysis.LVS; + } + } +}; +var unhighlightTestMethods = function () { + if (selectedLine !== null) { + return; + } + + var testMethods = document.getElementsByClassName('testmethod'); + for (i = 0, l = testMethods.length; i < l; i++) { + testMethods[i].className = testMethods[i].className.replace(/\s*light.+/g, ""); + } +}; +var coverableLines = document.getElementsByClassName('coverableline'); +for (i = 0, l = coverableLines.length; i < l; i++) { + coverableLines[i].addEventListener('click', toggleLine); + coverableLines[i].addEventListener('mouseenter', highlightTestMethods); + coverableLines[i].addEventListener('mouseleave', unhighlightTestMethods); +} + +/* History charts */ +var renderChart = function (chart) { + // Remove current children (e.g. PNG placeholder) + while (chart.firstChild) { + chart.firstChild.remove(); + } + + var chartData = window[chart.getAttribute('data-data')]; + var options = { + axisY: { + type: undefined, + onlyInteger: true + }, + lineSmooth: false, + low: 0, + high: 100, + scaleMinSpace: 20, + onlyInteger: true, + fullWidth: true + }; + var lineChart = new Chartist.Line(chart, { + labels: [], + series: chartData.series + }, options); + + /* Zoom */ + var zoomButtonDiv = document.createElement("div"); + zoomButtonDiv.className = "toggleZoom"; + var zoomButtonLink = document.createElement("a"); + zoomButtonLink.setAttribute("href", ""); + var zoomButtonText = document.createElement("i"); + zoomButtonText.className = "icon-search-plus"; + + zoomButtonLink.appendChild(zoomButtonText); + zoomButtonDiv.appendChild(zoomButtonLink); + + chart.appendChild(zoomButtonDiv); + + zoomButtonDiv.addEventListener('click', function (event) { + event.preventDefault(); + + if (options.axisY.type === undefined) { + options.axisY.type = Chartist.AutoScaleAxis; + zoomButtonText.className = "icon-search-minus"; + } else { + options.axisY.type = undefined; + zoomButtonText.className = "icon-search-plus"; + } + + lineChart.update(null, options); + }); + + var tooltip = document.createElement("div"); + tooltip.className = "tooltip"; + + chart.appendChild(tooltip); + + /* Tooltips */ + var showToolTip = function () { + var index = this.getAttribute('ct:meta'); + + tooltip.innerHTML = chartData.tooltips[index]; + tooltip.style.display = 'block'; + }; + + var moveToolTip = function (event) { + var box = chart.getBoundingClientRect(); + var left = event.pageX - box.left - window.pageXOffset; + var top = event.pageY - box.top - window.pageYOffset; + + left = left + 20; + top = top - tooltip.offsetHeight / 2; + + if (left + tooltip.offsetWidth > box.width) { + left -= tooltip.offsetWidth + 40; + } + + if (top < 0) { + top = 0; + } + + if (top + tooltip.offsetHeight > box.height) { + top = box.height - tooltip.offsetHeight; + } + + tooltip.style.left = left + 'px'; + tooltip.style.top = top + 'px'; + }; + + var hideToolTip = function () { + tooltip.style.display = 'none'; + }; + chart.addEventListener('mousemove', moveToolTip); + + lineChart.on('created', function () { + var chartPoints = chart.getElementsByClassName('ct-point'); + for (i = 0, l = chartPoints.length; i < l; i++) { + chartPoints[i].addEventListener('mousemove', showToolTip); + chartPoints[i].addEventListener('mouseout', hideToolTip); + } + }); +}; + +var charts = document.getElementsByClassName('historychart'); +for (i = 0, l = charts.length; i < l; i++) { + renderChart(charts[i]); +} + +var assemblies = [ + { + "name": "Core", + "classes": [ + { "name": "Core.DTOs.Request.OrganisationHierarchyProvider", "rp": "Core_OrganisationHierarchyProvider.html", "cl": 2, "ucl": 0, "cal": 2, "tl": 19, "cb": 0, "tb": 0, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, + { "name": "Core.Helpers.ApplicationHelper", "rp": "Core_ApplicationHelper.html", "cl": 7, "ucl": 0, "cal": 7, "tl": 23, "cb": 4, "tb": 6, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, + { "name": "Core.Helpers.AttributeExtensions", "rp": "Core_AttributeExtensions.html", "cl": 13, "ucl": 0, "cal": 13, "tl": 27, "cb": 6, "tb": 6, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, + { "name": "Core.Helpers.ConnectionStrings", "rp": "Core_ConnectionStrings.html", "cl": 1, "ucl": 0, "cal": 1, "tl": 7, "cb": 0, "tb": 0, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, + { "name": "Core.Helpers.DateTimeHelper", "rp": "Core_DateTimeHelper.html", "cl": 4, "ucl": 0, "cal": 4, "tl": 11, "cb": 2, "tb": 2, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, + { "name": "Core.Helpers.FilePathAttribute", "rp": "Core_FilePathAttribute.html", "cl": 3, "ucl": 0, "cal": 3, "tl": 12, "cb": 0, "tb": 0, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, + { "name": "Core.Mapping.SplunkInstanceMap", "rp": "Core_SplunkInstanceMap.html", "cl": 0, "ucl": 5, "cal": 5, "tl": 14, "cb": 0, "tb": 0, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, + { "name": "Core.Repositories.DapperWrapper", "rp": "Core_DapperWrapper.html", "cl": 27, "ucl": 1, "cal": 28, "tl": 68, "cb": 0, "tb": 0, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, + { "name": "Core.Repositories.HierarchyProviderConsumerRepo", "rp": "Core_HierarchyProviderConsumerRepo.html", "cl": 0, "ucl": 17, "cal": 17, "tl": 62, "cb": 0, "tb": 4, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, + { "name": "TimeProvider", "rp": "Core_TimeProvider.html", "cl": 0, "ucl": 2, "cal": 2, "tl": 12, "cb": 0, "tb": 0, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, + ]}, + { + "name": "Functions", + "classes": [ + { "name": "Functions.Configuration.EmailConfigurationProvider", "rp": "Functions_EmailConfigurationProvider.html", "cl": 0, "ucl": 8, "cal": 8, "tl": 29, "cb": 0, "tb": 2, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, + { "name": "Functions.Configuration.Infrastructure.HttpClient.HttpClientExtensions", "rp": "Functions_HttpClientExtensions.html", "cl": 12, "ucl": 0, "cal": 12, "tl": 23, "cb": 0, "tb": 0, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, + { "name": "Functions.Configuration.Infrastructure.Logging.LoggingExtensions", "rp": "Functions_LoggingExtensions.html", "cl": 0, "ucl": 130, "cal": 130, "tl": 185, "cb": 0, "tb": 4, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, + { "name": "Functions.Configuration.Infrastructure.Mapping.MappingExtensions", "rp": "Functions_MappingExtensions.html", "cl": 0, "ucl": 3, "cal": 3, "tl": 13, "cb": 0, "tb": 0, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, + { "name": "Functions.ExecuteImportByTrigger", "rp": "Functions_ExecuteImportByTrigger.html", "cl": 3, "ucl": 0, "cal": 3, "tl": 16, "cb": 0, "tb": 0, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, + { "name": "Functions.GetDataFromApiByDateRange", "rp": "Functions_GetDataFromApiByDateRange.html", "cl": 27, "ucl": 18, "cal": 45, "tl": 85, "cb": 0, "tb": 0, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, + { "name": "Functions.GetDataFromApiByTrigger", "rp": "Functions_GetDataFromApiByTrigger.html", "cl": 9, "ucl": 0, "cal": 9, "tl": 34, "cb": 0, "tb": 0, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, + { "name": "Functions.GetDataFromApiManual", "rp": "Functions_GetDataFromApiManual.html", "cl": 21, "ucl": 0, "cal": 21, "tl": 42, "cb": 2, "tb": 2, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, + { "name": "Functions.GetDataFromApiToday", "rp": "Functions_GetDataFromApiToday.html", "cl": 54, "ucl": 0, "cal": 54, "tl": 98, "cb": 0, "tb": 0, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, + { "name": "Functions.PurgeErrorLogByTrigger", "rp": "Functions_PurgeErrorLogByTrigger.html", "cl": 3, "ucl": 0, "cal": 3, "tl": 16, "cb": 0, "tb": 0, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, + { "name": "Functions.Services.BatchService", "rp": "Functions_BatchService.html", "cl": 86, "ucl": 7, "cal": 93, "tl": 146, "cb": 14, "tb": 18, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, + { "name": "Functions.Services.BlobService", "rp": "Functions_BlobService.html", "cl": 42, "ucl": 8, "cal": 50, "tl": 93, "cb": 6, "tb": 8, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, + { "name": "Functions.Services.ConfigurationService", "rp": "Functions_ConfigurationService.html", "cl": 32, "ucl": 4, "cal": 36, "tl": 61, "cb": 0, "tb": 0, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, + { "name": "Functions.Services.CoreConfigurationService", "rp": "Functions_CoreConfigurationService.html", "cl": 4, "ucl": 0, "cal": 4, "tl": 14, "cb": 2, "tb": 2, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, + { "name": "Functions.Services.DataService", "rp": "Functions_DataService.html", "cl": 2, "ucl": 64, "cal": 66, "tl": 113, "cb": 0, "tb": 16, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, + { "name": "Functions.Services.FileService", "rp": "Functions_FileService.html", "cl": 8, "ucl": 0, "cal": 8, "tl": 19, "cb": 0, "tb": 0, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, + { "name": "Functions.Services.ImportService", "rp": "Functions_ImportService.html", "cl": 46, "ucl": 0, "cal": 46, "tl": 84, "cb": 12, "tb": 14, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, + { "name": "Functions.Services.LoggingService", "rp": "Functions_LoggingService.html", "cl": 0, "ucl": 7, "cal": 7, "tl": 21, "cb": 0, "tb": 0, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, + { "name": "Functions.Services.SplunkService", "rp": "Functions_SplunkService.html", "cl": 96, "ucl": 26, "cal": 122, "tl": 181, "cb": 8, "tb": 14, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, + { "name": "Functions.SqlConnectionFactory", "rp": "Functions_SqlConnectionFactory.html", "cl": 0, "ucl": 3, "cal": 3, "tl": 13, "cb": 0, "tb": 0, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, + { "name": "Functions.StoreProviderConsumerData", "rp": "Functions_StoreProviderConsumerData.html", "cl": 22, "ucl": 14, "cal": 36, "tl": 69, "cb": 3, "tb": 4, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, + ]}, +]; + +var metrics = [{ "name": "Crap Score", "abbreviation": "crp", "explanationUrl": "https://googletesting.blogspot.de/2011/02/this-code-is-crap.html" }, { "name": "Cyclomatic complexity", "abbreviation": "cc", "explanationUrl": "https://en.wikipedia.org/wiki/Cyclomatic_complexity" }, { "name": "Line coverage", "abbreviation": "cov", "explanationUrl": "https://en.wikipedia.org/wiki/Code_coverage" }, { "name": "Branch coverage", "abbreviation": "bcov", "explanationUrl": "https://en.wikipedia.org/wiki/Code_coverage" }]; + +var historicCoverageExecutionTimes = []; + +var riskHotspotMetrics = [ + { "name": "Crap Score", "explanationUrl": "https://googletesting.blogspot.de/2011/02/this-code-is-crap.html" }, + { "name": "Cyclomatic complexity", "explanationUrl": "https://en.wikipedia.org/wiki/Cyclomatic_complexity" }, +]; + +var riskHotspots = [ + { + "assembly": "Functions", "class": "Functions.Services.DataService", "reportPath": "Functions_DataService.html", "methodName": "ExecuteQueryStoredProcedure()", "methodShortName": "ExecuteQueryStoredProcedure()", "fileIndex": 0, "line": 40, + "metrics": [ + { "value": 42, "exceeded": true }, + { "value": 6, "exceeded": false }, + ]}, +]; + +var branchCoverageAvailable = true; +var methodCoverageAvailable = false; +var maximumDecimalPlacesForCoverageQuotas = 1; + + +var translations = { +'top': 'Top:', +'all': 'All', +'assembly': 'Assembly', +'class': 'Class', +'method': 'Method', +'lineCoverage': 'Line coverage', +'noGrouping': 'No grouping', +'byAssembly': 'By assembly', +'byNamespace': 'By namespace, Level:', +'all': 'All', +'collapseAll': 'Collapse all', +'expandAll': 'Expand all', +'grouping': 'Grouping:', +'filter': 'Filter:', +'name': 'Name', +'covered': 'Covered', +'uncovered': 'Uncovered', +'coverable': 'Coverable', +'total': 'Total', +'coverage': 'Line coverage', +'branchCoverage': 'Branch coverage', +'methodCoverage': 'Method coverage', +'fullMethodCoverage': 'Full method coverage', +'percentage': 'Percentage', +'history': 'Coverage history', +'compareHistory': 'Compare with:', +'date': 'Date', +'allChanges': 'All changes', +'selectCoverageTypes': 'Select coverage types', +'selectCoverageTypesAndMetrics': 'Select coverage types & metrics', +'coverageTypes': 'Coverage types', +'metrics': 'Metrics', +'methodCoverageProVersion': 'Feature is only available for sponsors', +'lineCoverageIncreaseOnly': 'Line coverage: Increase only', +'lineCoverageDecreaseOnly': 'Line coverage: Decrease only', +'branchCoverageIncreaseOnly': 'Branch coverage: Increase only', +'branchCoverageDecreaseOnly': 'Branch coverage: Decrease only', +'methodCoverageIncreaseOnly': 'Method coverage: Increase only', +'methodCoverageDecreaseOnly': 'Method coverage: Decrease only', +'fullMethodCoverageIncreaseOnly': 'Full method coverage: Increase only', +'fullMethodCoverageDecreaseOnly': 'Full method coverage: Decrease only' +}; + + +(()=>{"use strict";var e,_={},p={};function n(e){var a=p[e];if(void 0!==a)return a.exports;var r=p[e]={exports:{}};return _[e](r,r.exports,n),r.exports}n.m=_,e=[],n.O=(a,r,u,l)=>{if(!r){var o=1/0;for(f=0;f=l)&&Object.keys(n.O).every(h=>n.O[h](r[t]))?r.splice(t--,1):(v=!1,l0&&e[f-1][2]>l;f--)e[f]=e[f-1];e[f]=[r,u,l]},n.n=e=>{var a=e&&e.__esModule?()=>e.default:()=>e;return n.d(a,{a}),a},n.d=(e,a)=>{for(var r in a)n.o(a,r)&&!n.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:a[r]})},n.o=(e,a)=>Object.prototype.hasOwnProperty.call(e,a),(()=>{var e={121:0};n.O.j=u=>0===e[u];var a=(u,l)=>{var t,c,[f,o,v]=l,s=0;if(f.some(d=>0!==e[d])){for(t in o)n.o(o,t)&&(n.m[t]=o[t]);if(v)var b=v(n)}for(u&&u(l);s{ve(935)},935:()=>{const te=globalThis;function Q(e){return(te.__Zone_symbol_prefix||"__zone_symbol__")+e}const Te=Object.getOwnPropertyDescriptor,Le=Object.defineProperty,Ie=Object.getPrototypeOf,_t=Object.create,Et=Array.prototype.slice,Me="addEventListener",Ze="removeEventListener",Ae=Q(Me),je=Q(Ze),ae="true",le="false",Pe=Q("");function He(e,r){return Zone.current.wrap(e,r)}function xe(e,r,c,t,i){return Zone.current.scheduleMacroTask(e,r,c,t,i)}const j=Q,Ce=typeof window<"u",ge=Ce?window:void 0,$=Ce&&ge||globalThis;function Ve(e,r){for(let c=e.length-1;c>=0;c--)"function"==typeof e[c]&&(e[c]=He(e[c],r+"_"+c));return e}function We(e){return!e||!1!==e.writable&&!("function"==typeof e.get&&typeof e.set>"u")}const qe=typeof WorkerGlobalScope<"u"&&self instanceof WorkerGlobalScope,De=!("nw"in $)&&typeof $.process<"u"&&"[object process]"===$.process.toString(),Ge=!De&&!qe&&!(!Ce||!ge.HTMLElement),Xe=typeof $.process<"u"&&"[object process]"===$.process.toString()&&!qe&&!(!Ce||!ge.HTMLElement),Se={},pt=j("enable_beforeunload"),Ye=function(e){if(!(e=e||$.event))return;let r=Se[e.type];r||(r=Se[e.type]=j("ON_PROPERTY"+e.type));const c=this||e.target||$,t=c[r];let i;return Ge&&c===ge&&"error"===e.type?(i=t&&t.call(this,e.message,e.filename,e.lineno,e.colno,e.error),!0===i&&e.preventDefault()):(i=t&&t.apply(this,arguments),"beforeunload"===e.type&&$[pt]&&"string"==typeof i?e.returnValue=i:null!=i&&!i&&e.preventDefault()),i};function $e(e,r,c){let t=Te(e,r);if(!t&&c&&Te(c,r)&&(t={enumerable:!0,configurable:!0}),!t||!t.configurable)return;const i=j("on"+r+"patched");if(e.hasOwnProperty(i)&&e[i])return;delete t.writable,delete t.value;const u=t.get,E=t.set,T=r.slice(2);let y=Se[T];y||(y=Se[T]=j("ON_PROPERTY"+T)),t.set=function(D){let d=this;!d&&e===$&&(d=$),d&&("function"==typeof d[y]&&d.removeEventListener(T,Ye),E&&E.call(d,null),d[y]=D,"function"==typeof D&&d.addEventListener(T,Ye,!1))},t.get=function(){let D=this;if(!D&&e===$&&(D=$),!D)return null;const d=D[y];if(d)return d;if(u){let w=u.call(this);if(w)return t.set.call(this,w),"function"==typeof D.removeAttribute&&D.removeAttribute(r),w}return null},Le(e,r,t),e[i]=!0}function Ke(e,r,c){if(r)for(let t=0;tfunction(E,T){const y=c(E,T);return y.cbIdx>=0&&"function"==typeof T[y.cbIdx]?xe(y.name,T[y.cbIdx],y,i):u.apply(E,T)})}function fe(e,r){e[j("OriginalDelegate")]=r}let Je=!1,Be=!1;function kt(){if(Je)return Be;Je=!0;try{const e=ge.navigator.userAgent;(-1!==e.indexOf("MSIE ")||-1!==e.indexOf("Trident/")||-1!==e.indexOf("Edge/"))&&(Be=!0)}catch{}return Be}function Qe(e){return"function"==typeof e}function et(e){return"number"==typeof e}let pe=!1;if(typeof window<"u")try{const e=Object.defineProperty({},"passive",{get:function(){pe=!0}});window.addEventListener("test",e,e),window.removeEventListener("test",e,e)}catch{pe=!1}const vt={useG:!0},ne={},tt={},nt=new RegExp("^"+Pe+"(\\w+)(true|false)$"),rt=j("propagationStopped");function ot(e,r){const c=(r?r(e):e)+le,t=(r?r(e):e)+ae,i=Pe+c,u=Pe+t;ne[e]={},ne[e][le]=i,ne[e][ae]=u}function bt(e,r,c,t){const i=t&&t.add||Me,u=t&&t.rm||Ze,E=t&&t.listeners||"eventListeners",T=t&&t.rmAll||"removeAllListeners",y=j(i),D="."+i+":",d="prependListener",w="."+d+":",Z=function(k,h,H){if(k.isRemoved)return;const V=k.callback;let Y;"object"==typeof V&&V.handleEvent&&(k.callback=g=>V.handleEvent(g),k.originalDelegate=V);try{k.invoke(k,h,[H])}catch(g){Y=g}const G=k.options;return G&&"object"==typeof G&&G.once&&h[u].call(h,H.type,k.originalDelegate?k.originalDelegate:k.callback,G),Y};function x(k,h,H){if(!(h=h||e.event))return;const V=k||h.target||e,Y=V[ne[h.type][H?ae:le]];if(Y){const G=[];if(1===Y.length){const g=Z(Y[0],V,h);g&&G.push(g)}else{const g=Y.slice();for(let z=0;z{throw z})}}}const U=function(k){return x(this,k,!1)},K=function(k){return x(this,k,!0)};function J(k,h){if(!k)return!1;let H=!0;h&&void 0!==h.useG&&(H=h.useG);const V=h&&h.vh;let Y=!0;h&&void 0!==h.chkDup&&(Y=h.chkDup);let G=!1;h&&void 0!==h.rt&&(G=h.rt);let g=k;for(;g&&!g.hasOwnProperty(i);)g=Ie(g);if(!g&&k[i]&&(g=k),!g||g[y])return!1;const z=h&&h.eventNameToString,O={},R=g[y]=g[i],b=g[j(u)]=g[u],S=g[j(E)]=g[E],ee=g[j(T)]=g[T];let W;h&&h.prepend&&(W=g[j(h.prepend)]=g[h.prepend]);const q=H?function(s){if(!O.isExisting)return R.call(O.target,O.eventName,O.capture?K:U,O.options)}:function(s){return R.call(O.target,O.eventName,s.invoke,O.options)},A=H?function(s){if(!s.isRemoved){const l=ne[s.eventName];let v;l&&(v=l[s.capture?ae:le]);const C=v&&s.target[v];if(C)for(let p=0;pse.zone.cancelTask(se);s.call(me,"abort",ce,{once:!0}),se.removeAbortListener=()=>me.removeEventListener("abort",ce)}return O.target=null,Re&&(Re.taskData=null),lt&&(O.options.once=!0),!pe&&"boolean"==typeof se.options||(se.options=ie),se.target=I,se.capture=Ue,se.eventName=M,F&&(se.originalDelegate=B),L?ke.unshift(se):ke.push(se),p?I:void 0}};return g[i]=a(R,D,q,A,G),W&&(g[d]=a(W,w,function(s){return W.call(O.target,O.eventName,s.invoke,O.options)},A,G,!0)),g[u]=function(){const s=this||e;let l=arguments[0];h&&h.transferEventName&&(l=h.transferEventName(l));const v=arguments[2],C=!!v&&("boolean"==typeof v||v.capture),p=arguments[1];if(!p)return b.apply(this,arguments);if(V&&!V(b,p,s,arguments))return;const L=ne[l];let I;L&&(I=L[C?ae:le]);const M=I&&s[I];if(M)for(let B=0;Bfunction(i,u){i[rt]=!0,t&&t.apply(i,u)})}const Oe=j("zoneTask");function ye(e,r,c,t){let i=null,u=null;c+=t;const E={};function T(D){const d=D.data;d.args[0]=function(){return D.invoke.apply(this,arguments)};const w=i.apply(e,d.args);return et(w)?d.handleId=w:(d.handle=w,d.isRefreshable=Qe(w.refresh)),D}function y(D){const{handle:d,handleId:w}=D.data;return u.call(e,d??w)}i=ue(e,r+=t,D=>function(d,w){if(Qe(w[0])){const Z={isRefreshable:!1,isPeriodic:"Interval"===t,delay:"Timeout"===t||"Interval"===t?w[1]||0:void 0,args:w},x=w[0];w[0]=function(){try{return x.apply(this,arguments)}finally{const{handle:H,handleId:V,isPeriodic:Y,isRefreshable:G}=Z;!Y&&!G&&(V?delete E[V]:H&&(H[Oe]=null))}};const U=xe(r,w[0],Z,T,y);if(!U)return U;const{handleId:K,handle:J,isRefreshable:X,isPeriodic:k}=U.data;if(K)E[K]=U;else if(J&&(J[Oe]=U,X&&!k)){const h=J.refresh;J.refresh=function(){const{zone:H,state:V}=U;return"notScheduled"===V?(U._state="scheduled",H._updateTaskCount(U,1)):"running"===V&&(U._state="scheduling"),h.call(this)}}return J??K??U}return D.apply(e,w)}),u=ue(e,c,D=>function(d,w){const Z=w[0];let x;et(Z)?(x=E[Z],delete E[Z]):(x=Z?.[Oe],x?Z[Oe]=null:x=Z),x?.type?x.cancelFn&&x.zone.cancelTask(x):D.apply(e,w)})}function it(e,r,c){if(!c||0===c.length)return r;const t=c.filter(u=>u.target===e);if(!t||0===t.length)return r;const i=t[0].ignoreProperties;return r.filter(u=>-1===i.indexOf(u))}function ct(e,r,c,t){e&&Ke(e,it(e,r,c),t)}function Fe(e){return Object.getOwnPropertyNames(e).filter(r=>r.startsWith("on")&&r.length>2).map(r=>r.substring(2))}function It(e,r,c,t,i){const u=Zone.__symbol__(t);if(r[u])return;const E=r[u]=r[t];r[t]=function(T,y,D){return y&&y.prototype&&i.forEach(function(d){const w=`${c}.${t}::`+d,Z=y.prototype;try{if(Z.hasOwnProperty(d)){const x=e.ObjectGetOwnPropertyDescriptor(Z,d);x&&x.value?(x.value=e.wrapWithCurrentZone(x.value,w),e._redefineProperty(y.prototype,d,x)):Z[d]&&(Z[d]=e.wrapWithCurrentZone(Z[d],w))}else Z[d]&&(Z[d]=e.wrapWithCurrentZone(Z[d],w))}catch{}}),E.call(r,T,y,D)},e.attachOriginToPatched(r[t],E)}const at=function be(){const e=globalThis,r=!0===e[Q("forceDuplicateZoneCheck")];if(e.Zone&&(r||"function"!=typeof e.Zone.__symbol__))throw new Error("Zone already loaded.");return e.Zone??=function ve(){const e=te.performance;function r(N){e&&e.mark&&e.mark(N)}function c(N,_){e&&e.measure&&e.measure(N,_)}r("Zone");let t=(()=>{class N{static{this.__symbol__=Q}static assertZonePatched(){if(te.Promise!==O.ZoneAwarePromise)throw new Error("Zone.js has detected that ZoneAwarePromise `(window|global).Promise` has been overwritten.\nMost likely cause is that a Promise polyfill has been loaded after Zone.js (Polyfilling Promise api is not necessary when zone.js is loaded. If you must load one, do so before loading zone.js.)")}static get root(){let n=N.current;for(;n.parent;)n=n.parent;return n}static get current(){return b.zone}static get currentTask(){return S}static __load_patch(n,o,m=!1){if(O.hasOwnProperty(n)){const P=!0===te[Q("forceDuplicateZoneCheck")];if(!m&&P)throw Error("Already loaded patch: "+n)}else if(!te["__Zone_disable_"+n]){const P="Zone:"+n;r(P),O[n]=o(te,N,R),c(P,P)}}get parent(){return this._parent}get name(){return this._name}constructor(n,o){this._parent=n,this._name=o?o.name||"unnamed":"",this._properties=o&&o.properties||{},this._zoneDelegate=new u(this,this._parent&&this._parent._zoneDelegate,o)}get(n){const o=this.getZoneWith(n);if(o)return o._properties[n]}getZoneWith(n){let o=this;for(;o;){if(o._properties.hasOwnProperty(n))return o;o=o._parent}return null}fork(n){if(!n)throw new Error("ZoneSpec required!");return this._zoneDelegate.fork(this,n)}wrap(n,o){if("function"!=typeof n)throw new Error("Expecting function got: "+n);const m=this._zoneDelegate.intercept(this,n,o),P=this;return function(){return P.runGuarded(m,this,arguments,o)}}run(n,o,m,P){b={parent:b,zone:this};try{return this._zoneDelegate.invoke(this,n,o,m,P)}finally{b=b.parent}}runGuarded(n,o=null,m,P){b={parent:b,zone:this};try{try{return this._zoneDelegate.invoke(this,n,o,m,P)}catch(q){if(this._zoneDelegate.handleError(this,q))throw q}}finally{b=b.parent}}runTask(n,o,m){if(n.zone!=this)throw new Error("A task can only be run in the zone of creation! (Creation: "+(n.zone||J).name+"; Execution: "+this.name+")");const P=n,{type:q,data:{isPeriodic:A=!1,isRefreshable:_e=!1}={}}=n;if(n.state===X&&(q===z||q===g))return;const he=n.state!=H;he&&P._transitionTo(H,h);const de=S;S=P,b={parent:b,zone:this};try{q==g&&n.data&&!A&&!_e&&(n.cancelFn=void 0);try{return this._zoneDelegate.invokeTask(this,P,o,m)}catch(oe){if(this._zoneDelegate.handleError(this,oe))throw oe}}finally{const oe=n.state;if(oe!==X&&oe!==Y)if(q==z||A||_e&&oe===k)he&&P._transitionTo(h,H,k);else{const f=P._zoneDelegates;this._updateTaskCount(P,-1),he&&P._transitionTo(X,H,X),_e&&(P._zoneDelegates=f)}b=b.parent,S=de}}scheduleTask(n){if(n.zone&&n.zone!==this){let m=this;for(;m;){if(m===n.zone)throw Error(`can not reschedule task to ${this.name} which is descendants of the original zone ${n.zone.name}`);m=m.parent}}n._transitionTo(k,X);const o=[];n._zoneDelegates=o,n._zone=this;try{n=this._zoneDelegate.scheduleTask(this,n)}catch(m){throw n._transitionTo(Y,k,X),this._zoneDelegate.handleError(this,m),m}return n._zoneDelegates===o&&this._updateTaskCount(n,1),n.state==k&&n._transitionTo(h,k),n}scheduleMicroTask(n,o,m,P){return this.scheduleTask(new E(G,n,o,m,P,void 0))}scheduleMacroTask(n,o,m,P,q){return this.scheduleTask(new E(g,n,o,m,P,q))}scheduleEventTask(n,o,m,P,q){return this.scheduleTask(new E(z,n,o,m,P,q))}cancelTask(n){if(n.zone!=this)throw new Error("A task can only be cancelled in the zone of creation! (Creation: "+(n.zone||J).name+"; Execution: "+this.name+")");if(n.state===h||n.state===H){n._transitionTo(V,h,H);try{this._zoneDelegate.cancelTask(this,n)}catch(o){throw n._transitionTo(Y,V),this._zoneDelegate.handleError(this,o),o}return this._updateTaskCount(n,-1),n._transitionTo(X,V),n.runCount=-1,n}}_updateTaskCount(n,o){const m=n._zoneDelegates;-1==o&&(n._zoneDelegates=null);for(let P=0;PN.hasTask(n,o),onScheduleTask:(N,_,n,o)=>N.scheduleTask(n,o),onInvokeTask:(N,_,n,o,m,P)=>N.invokeTask(n,o,m,P),onCancelTask:(N,_,n,o)=>N.cancelTask(n,o)};class u{get zone(){return this._zone}constructor(_,n,o){this._taskCounts={microTask:0,macroTask:0,eventTask:0},this._zone=_,this._parentDelegate=n,this._forkZS=o&&(o&&o.onFork?o:n._forkZS),this._forkDlgt=o&&(o.onFork?n:n._forkDlgt),this._forkCurrZone=o&&(o.onFork?this._zone:n._forkCurrZone),this._interceptZS=o&&(o.onIntercept?o:n._interceptZS),this._interceptDlgt=o&&(o.onIntercept?n:n._interceptDlgt),this._interceptCurrZone=o&&(o.onIntercept?this._zone:n._interceptCurrZone),this._invokeZS=o&&(o.onInvoke?o:n._invokeZS),this._invokeDlgt=o&&(o.onInvoke?n:n._invokeDlgt),this._invokeCurrZone=o&&(o.onInvoke?this._zone:n._invokeCurrZone),this._handleErrorZS=o&&(o.onHandleError?o:n._handleErrorZS),this._handleErrorDlgt=o&&(o.onHandleError?n:n._handleErrorDlgt),this._handleErrorCurrZone=o&&(o.onHandleError?this._zone:n._handleErrorCurrZone),this._scheduleTaskZS=o&&(o.onScheduleTask?o:n._scheduleTaskZS),this._scheduleTaskDlgt=o&&(o.onScheduleTask?n:n._scheduleTaskDlgt),this._scheduleTaskCurrZone=o&&(o.onScheduleTask?this._zone:n._scheduleTaskCurrZone),this._invokeTaskZS=o&&(o.onInvokeTask?o:n._invokeTaskZS),this._invokeTaskDlgt=o&&(o.onInvokeTask?n:n._invokeTaskDlgt),this._invokeTaskCurrZone=o&&(o.onInvokeTask?this._zone:n._invokeTaskCurrZone),this._cancelTaskZS=o&&(o.onCancelTask?o:n._cancelTaskZS),this._cancelTaskDlgt=o&&(o.onCancelTask?n:n._cancelTaskDlgt),this._cancelTaskCurrZone=o&&(o.onCancelTask?this._zone:n._cancelTaskCurrZone),this._hasTaskZS=null,this._hasTaskDlgt=null,this._hasTaskDlgtOwner=null,this._hasTaskCurrZone=null;const m=o&&o.onHasTask;(m||n&&n._hasTaskZS)&&(this._hasTaskZS=m?o:i,this._hasTaskDlgt=n,this._hasTaskDlgtOwner=this,this._hasTaskCurrZone=this._zone,o.onScheduleTask||(this._scheduleTaskZS=i,this._scheduleTaskDlgt=n,this._scheduleTaskCurrZone=this._zone),o.onInvokeTask||(this._invokeTaskZS=i,this._invokeTaskDlgt=n,this._invokeTaskCurrZone=this._zone),o.onCancelTask||(this._cancelTaskZS=i,this._cancelTaskDlgt=n,this._cancelTaskCurrZone=this._zone))}fork(_,n){return this._forkZS?this._forkZS.onFork(this._forkDlgt,this.zone,_,n):new t(_,n)}intercept(_,n,o){return this._interceptZS?this._interceptZS.onIntercept(this._interceptDlgt,this._interceptCurrZone,_,n,o):n}invoke(_,n,o,m,P){return this._invokeZS?this._invokeZS.onInvoke(this._invokeDlgt,this._invokeCurrZone,_,n,o,m,P):n.apply(o,m)}handleError(_,n){return!this._handleErrorZS||this._handleErrorZS.onHandleError(this._handleErrorDlgt,this._handleErrorCurrZone,_,n)}scheduleTask(_,n){let o=n;if(this._scheduleTaskZS)this._hasTaskZS&&o._zoneDelegates.push(this._hasTaskDlgtOwner),o=this._scheduleTaskZS.onScheduleTask(this._scheduleTaskDlgt,this._scheduleTaskCurrZone,_,n),o||(o=n);else if(n.scheduleFn)n.scheduleFn(n);else{if(n.type!=G)throw new Error("Task is missing scheduleFn.");U(n)}return o}invokeTask(_,n,o,m){return this._invokeTaskZS?this._invokeTaskZS.onInvokeTask(this._invokeTaskDlgt,this._invokeTaskCurrZone,_,n,o,m):n.callback.apply(o,m)}cancelTask(_,n){let o;if(this._cancelTaskZS)o=this._cancelTaskZS.onCancelTask(this._cancelTaskDlgt,this._cancelTaskCurrZone,_,n);else{if(!n.cancelFn)throw Error("Task is not cancelable");o=n.cancelFn(n)}return o}hasTask(_,n){try{this._hasTaskZS&&this._hasTaskZS.onHasTask(this._hasTaskDlgt,this._hasTaskCurrZone,_,n)}catch(o){this.handleError(_,o)}}_updateTaskCount(_,n){const o=this._taskCounts,m=o[_],P=o[_]=m+n;if(P<0)throw new Error("More tasks executed then were scheduled.");0!=m&&0!=P||this.hasTask(this._zone,{microTask:o.microTask>0,macroTask:o.macroTask>0,eventTask:o.eventTask>0,change:_})}}class E{constructor(_,n,o,m,P,q){if(this._zone=null,this.runCount=0,this._zoneDelegates=null,this._state="notScheduled",this.type=_,this.source=n,this.data=m,this.scheduleFn=P,this.cancelFn=q,!o)throw new Error("callback is not defined");this.callback=o;const A=this;this.invoke=_===z&&m&&m.useG?E.invokeTask:function(){return E.invokeTask.call(te,A,this,arguments)}}static invokeTask(_,n,o){_||(_=this),ee++;try{return _.runCount++,_.zone.runTask(_,n,o)}finally{1==ee&&K(),ee--}}get zone(){return this._zone}get state(){return this._state}cancelScheduleRequest(){this._transitionTo(X,k)}_transitionTo(_,n,o){if(this._state!==n&&this._state!==o)throw new Error(`${this.type} '${this.source}': can not transition to '${_}', expecting state '${n}'${o?" or '"+o+"'":""}, was '${this._state}'.`);this._state=_,_==X&&(this._zoneDelegates=null)}toString(){return this.data&&typeof this.data.handleId<"u"?this.data.handleId.toString():Object.prototype.toString.call(this)}toJSON(){return{type:this.type,state:this.state,source:this.source,zone:this.zone.name,runCount:this.runCount}}}const T=Q("setTimeout"),y=Q("Promise"),D=Q("then");let Z,d=[],w=!1;function x(N){if(Z||te[y]&&(Z=te[y].resolve(0)),Z){let _=Z[D];_||(_=Z.then),_.call(Z,N)}else te[T](N,0)}function U(N){0===ee&&0===d.length&&x(K),N&&d.push(N)}function K(){if(!w){for(w=!0;d.length;){const N=d;d=[];for(let _=0;_b,onUnhandledError:W,microtaskDrainDone:W,scheduleMicroTask:U,showUncaughtError:()=>!t[Q("ignoreConsoleErrorUncaughtError")],patchEventTarget:()=>[],patchOnProperties:W,patchMethod:()=>W,bindArguments:()=>[],patchThen:()=>W,patchMacroTask:()=>W,patchEventPrototype:()=>W,isIEOrEdge:()=>!1,getGlobalObjects:()=>{},ObjectDefineProperty:()=>W,ObjectGetOwnPropertyDescriptor:()=>{},ObjectCreate:()=>{},ArraySlice:()=>[],patchClass:()=>W,wrapWithCurrentZone:()=>W,filterProperties:()=>[],attachOriginToPatched:()=>W,_redefineProperty:()=>W,patchCallbacks:()=>W,nativeScheduleMicroTask:x};let b={parent:null,zone:new t(null,null)},S=null,ee=0;function W(){}return c("Zone","Zone"),t}(),e.Zone}();(function Zt(e){(function Nt(e){e.__load_patch("ZoneAwarePromise",(r,c,t)=>{const i=Object.getOwnPropertyDescriptor,u=Object.defineProperty,T=t.symbol,y=[],D=!1!==r[T("DISABLE_WRAPPING_UNCAUGHT_PROMISE_REJECTION")],d=T("Promise"),w=T("then");t.onUnhandledError=f=>{if(t.showUncaughtError()){const a=f&&f.rejection;a?console.error("Unhandled Promise rejection:",a instanceof Error?a.message:a,"; Zone:",f.zone.name,"; Task:",f.task&&f.task.source,"; Value:",a,a instanceof Error?a.stack:void 0):console.error(f)}},t.microtaskDrainDone=()=>{for(;y.length;){const f=y.shift();try{f.zone.runGuarded(()=>{throw f.throwOriginal?f.rejection:f})}catch(a){U(a)}}};const x=T("unhandledPromiseRejectionHandler");function U(f){t.onUnhandledError(f);try{const a=c[x];"function"==typeof a&&a.call(this,f)}catch{}}function K(f){return f&&f.then}function J(f){return f}function X(f){return A.reject(f)}const k=T("state"),h=T("value"),H=T("finally"),V=T("parentPromiseValue"),Y=T("parentPromiseState"),g=null,z=!0,O=!1;function b(f,a){return s=>{try{N(f,a,s)}catch(l){N(f,!1,l)}}}const S=function(){let f=!1;return function(s){return function(){f||(f=!0,s.apply(null,arguments))}}},ee="Promise resolved with itself",W=T("currentTaskTrace");function N(f,a,s){const l=S();if(f===s)throw new TypeError(ee);if(f[k]===g){let v=null;try{("object"==typeof s||"function"==typeof s)&&(v=s&&s.then)}catch(C){return l(()=>{N(f,!1,C)})(),f}if(a!==O&&s instanceof A&&s.hasOwnProperty(k)&&s.hasOwnProperty(h)&&s[k]!==g)n(s),N(f,s[k],s[h]);else if(a!==O&&"function"==typeof v)try{v.call(s,l(b(f,a)),l(b(f,!1)))}catch(C){l(()=>{N(f,!1,C)})()}else{f[k]=a;const C=f[h];if(f[h]=s,f[H]===H&&a===z&&(f[k]=f[Y],f[h]=f[V]),a===O&&s instanceof Error){const p=c.currentTask&&c.currentTask.data&&c.currentTask.data.__creationTrace__;p&&u(s,W,{configurable:!0,enumerable:!1,writable:!0,value:p})}for(let p=0;p{try{const L=f[h],I=!!s&&H===s[H];I&&(s[V]=L,s[Y]=C);const M=a.run(p,void 0,I&&p!==X&&p!==J?[]:[L]);N(s,!0,M)}catch(L){N(s,!1,L)}},s)}const P=function(){},q=r.AggregateError;class A{static toString(){return"function ZoneAwarePromise() { [native code] }"}static resolve(a){return a instanceof A?a:N(new this(null),z,a)}static reject(a){return N(new this(null),O,a)}static withResolvers(){const a={};return a.promise=new A((s,l)=>{a.resolve=s,a.reject=l}),a}static any(a){if(!a||"function"!=typeof a[Symbol.iterator])return Promise.reject(new q([],"All promises were rejected"));const s=[];let l=0;try{for(let p of a)l++,s.push(A.resolve(p))}catch{return Promise.reject(new q([],"All promises were rejected"))}if(0===l)return Promise.reject(new q([],"All promises were rejected"));let v=!1;const C=[];return new A((p,L)=>{for(let I=0;I{v||(v=!0,p(M))},M=>{C.push(M),l--,0===l&&(v=!0,L(new q(C,"All promises were rejected")))})})}static race(a){let s,l,v=new this((L,I)=>{s=L,l=I});function C(L){s(L)}function p(L){l(L)}for(let L of a)K(L)||(L=this.resolve(L)),L.then(C,p);return v}static all(a){return A.allWithCallback(a)}static allSettled(a){return(this&&this.prototype instanceof A?this:A).allWithCallback(a,{thenCallback:l=>({status:"fulfilled",value:l}),errorCallback:l=>({status:"rejected",reason:l})})}static allWithCallback(a,s){let l,v,C=new this((M,B)=>{l=M,v=B}),p=2,L=0;const I=[];for(let M of a){K(M)||(M=this.resolve(M));const B=L;try{M.then(F=>{I[B]=s?s.thenCallback(F):F,p--,0===p&&l(I)},F=>{s?(I[B]=s.errorCallback(F),p--,0===p&&l(I)):v(F)})}catch(F){v(F)}p++,L++}return p-=2,0===p&&l(I),C}constructor(a){const s=this;if(!(s instanceof A))throw new Error("Must be an instanceof Promise.");s[k]=g,s[h]=[];try{const l=S();a&&a(l(b(s,z)),l(b(s,O)))}catch(l){N(s,!1,l)}}get[Symbol.toStringTag](){return"Promise"}get[Symbol.species](){return A}then(a,s){let l=this.constructor?.[Symbol.species];(!l||"function"!=typeof l)&&(l=this.constructor||A);const v=new l(P),C=c.current;return this[k]==g?this[h].push(C,v,a,s):o(this,C,v,a,s),v}catch(a){return this.then(null,a)}finally(a){let s=this.constructor?.[Symbol.species];(!s||"function"!=typeof s)&&(s=A);const l=new s(P);l[H]=H;const v=c.current;return this[k]==g?this[h].push(v,l,a,a):o(this,v,l,a,a),l}}A.resolve=A.resolve,A.reject=A.reject,A.race=A.race,A.all=A.all;const _e=r[d]=r.Promise;r.Promise=A;const he=T("thenPatched");function de(f){const a=f.prototype,s=i(a,"then");if(s&&(!1===s.writable||!s.configurable))return;const l=a.then;a[w]=l,f.prototype.then=function(v,C){return new A((L,I)=>{l.call(this,L,I)}).then(v,C)},f[he]=!0}return t.patchThen=de,_e&&(de(_e),ue(r,"fetch",f=>function oe(f){return function(a,s){let l=f.apply(a,s);if(l instanceof A)return l;let v=l.constructor;return v[he]||de(v),l}}(f))),Promise[c.__symbol__("uncaughtPromiseErrors")]=y,A})})(e),function Lt(e){e.__load_patch("toString",r=>{const c=Function.prototype.toString,t=j("OriginalDelegate"),i=j("Promise"),u=j("Error"),E=function(){if("function"==typeof this){const d=this[t];if(d)return"function"==typeof d?c.call(d):Object.prototype.toString.call(d);if(this===Promise){const w=r[i];if(w)return c.call(w)}if(this===Error){const w=r[u];if(w)return c.call(w)}}return c.call(this)};E[t]=c,Function.prototype.toString=E;const T=Object.prototype.toString;Object.prototype.toString=function(){return"function"==typeof Promise&&this instanceof Promise?"[object Promise]":T.call(this)}})}(e),function Mt(e){e.__load_patch("util",(r,c,t)=>{const i=Fe(r);t.patchOnProperties=Ke,t.patchMethod=ue,t.bindArguments=Ve,t.patchMacroTask=yt;const u=c.__symbol__("BLACK_LISTED_EVENTS"),E=c.__symbol__("UNPATCHED_EVENTS");r[E]&&(r[u]=r[E]),r[u]&&(c[u]=c[E]=r[u]),t.patchEventPrototype=Pt,t.patchEventTarget=bt,t.isIEOrEdge=kt,t.ObjectDefineProperty=Le,t.ObjectGetOwnPropertyDescriptor=Te,t.ObjectCreate=_t,t.ArraySlice=Et,t.patchClass=we,t.wrapWithCurrentZone=He,t.filterProperties=it,t.attachOriginToPatched=fe,t._redefineProperty=Object.defineProperty,t.patchCallbacks=It,t.getGlobalObjects=()=>({globalSources:tt,zoneSymbolEventNames:ne,eventNames:i,isBrowser:Ge,isMix:Xe,isNode:De,TRUE_STR:ae,FALSE_STR:le,ZONE_SYMBOL_PREFIX:Pe,ADD_EVENT_LISTENER_STR:Me,REMOVE_EVENT_LISTENER_STR:Ze})})}(e)})(at),function Ot(e){e.__load_patch("legacy",r=>{const c=r[e.__symbol__("legacyPatch")];c&&c()}),e.__load_patch("timers",r=>{const c="set",t="clear";ye(r,c,t,"Timeout"),ye(r,c,t,"Interval"),ye(r,c,t,"Immediate")}),e.__load_patch("requestAnimationFrame",r=>{ye(r,"request","cancel","AnimationFrame"),ye(r,"mozRequest","mozCancel","AnimationFrame"),ye(r,"webkitRequest","webkitCancel","AnimationFrame")}),e.__load_patch("blocking",(r,c)=>{const t=["alert","prompt","confirm"];for(let i=0;ifunction(D,d){return c.current.run(E,r,d,y)})}),e.__load_patch("EventTarget",(r,c,t)=>{(function Dt(e,r){r.patchEventPrototype(e,r)})(r,t),function Ct(e,r){if(Zone[r.symbol("patchEventTarget")])return;const{eventNames:c,zoneSymbolEventNames:t,TRUE_STR:i,FALSE_STR:u,ZONE_SYMBOL_PREFIX:E}=r.getGlobalObjects();for(let y=0;y{we("MutationObserver"),we("WebKitMutationObserver")}),e.__load_patch("IntersectionObserver",(r,c,t)=>{we("IntersectionObserver")}),e.__load_patch("FileReader",(r,c,t)=>{we("FileReader")}),e.__load_patch("on_property",(r,c,t)=>{!function St(e,r){if(De&&!Xe||Zone[e.symbol("patchEvents")])return;const c=r.__Zone_ignore_on_properties;let t=[];if(Ge){const i=window;t=t.concat(["Document","SVGElement","Element","HTMLElement","HTMLBodyElement","HTMLMediaElement","HTMLFrameSetElement","HTMLFrameElement","HTMLIFrameElement","HTMLMarqueeElement","Worker"]);const u=function mt(){try{const e=ge.navigator.userAgent;if(-1!==e.indexOf("MSIE ")||-1!==e.indexOf("Trident/"))return!0}catch{}return!1}()?[{target:i,ignoreProperties:["error"]}]:[];ct(i,Fe(i),c&&c.concat(u),Ie(i))}t=t.concat(["XMLHttpRequest","XMLHttpRequestEventTarget","IDBIndex","IDBRequest","IDBOpenDBRequest","IDBDatabase","IDBTransaction","IDBCursor","WebSocket"]);for(let i=0;i{!function Rt(e,r){const{isBrowser:c,isMix:t}=r.getGlobalObjects();(c||t)&&e.customElements&&"customElements"in e&&r.patchCallbacks(r,e.customElements,"customElements","define",["connectedCallback","disconnectedCallback","adoptedCallback","attributeChangedCallback","formAssociatedCallback","formDisabledCallback","formResetCallback","formStateRestoreCallback"])}(r,t)}),e.__load_patch("XHR",(r,c)=>{!function D(d){const w=d.XMLHttpRequest;if(!w)return;const Z=w.prototype;let U=Z[Ae],K=Z[je];if(!U){const R=d.XMLHttpRequestEventTarget;if(R){const b=R.prototype;U=b[Ae],K=b[je]}}const J="readystatechange",X="scheduled";function k(R){const b=R.data,S=b.target;S[E]=!1,S[y]=!1;const ee=S[u];U||(U=S[Ae],K=S[je]),ee&&K.call(S,J,ee);const W=S[u]=()=>{if(S.readyState===S.DONE)if(!b.aborted&&S[E]&&R.state===X){const _=S[c.__symbol__("loadfalse")];if(0!==S.status&&_&&_.length>0){const n=R.invoke;R.invoke=function(){const o=S[c.__symbol__("loadfalse")];for(let m=0;mfunction(R,b){return R[i]=0==b[2],R[T]=b[1],V.apply(R,b)}),G=j("fetchTaskAborting"),g=j("fetchTaskScheduling"),z=ue(Z,"send",()=>function(R,b){if(!0===c.current[g]||R[i])return z.apply(R,b);{const S={target:R,url:R[T],isPeriodic:!1,args:b,aborted:!1},ee=xe("XMLHttpRequest.send",h,S,k,H);R&&!0===R[y]&&!S.aborted&&ee.state===X&&ee.invoke()}}),O=ue(Z,"abort",()=>function(R,b){const S=function x(R){return R[t]}(R);if(S&&"string"==typeof S.type){if(null==S.cancelFn||S.data&&S.data.aborted)return;S.zone.cancelTask(S)}else if(!0===c.current[G])return O.apply(R,b)})}(r);const t=j("xhrTask"),i=j("xhrSync"),u=j("xhrListener"),E=j("xhrScheduled"),T=j("xhrURL"),y=j("xhrErrorBeforeScheduled")}),e.__load_patch("geolocation",r=>{r.navigator&&r.navigator.geolocation&&function gt(e,r){const c=e.constructor.name;for(let t=0;t{const y=function(){return T.apply(this,Ve(arguments,c+"."+i))};return fe(y,T),y})(u)}}}(r.navigator.geolocation,["getCurrentPosition","watchPosition"])}),e.__load_patch("PromiseRejectionEvent",(r,c)=>{function t(i){return function(u){st(r,i).forEach(T=>{const y=r.PromiseRejectionEvent;if(y){const D=new y(i,{promise:u.promise,reason:u.rejection});T.invoke(D)}})}}r.PromiseRejectionEvent&&(c[j("unhandledPromiseRejectionHandler")]=t("unhandledrejection"),c[j("rejectionHandledHandler")]=t("rejectionhandled"))}),e.__load_patch("queueMicrotask",(r,c,t)=>{!function wt(e,r){r.patchMethod(e,"queueMicrotask",c=>function(t,i){Zone.current.scheduleMicroTask("queueMicrotask",i[0])})}(r,t)})}(at)}},te=>{te(te.s=50)}]); + +"use strict";(self.webpackChunkcoverage_app=self.webpackChunkcoverage_app||[]).push([[792],{332:()=>{function ua(e,n){return Object.is(e,n)}let Le=null,xo=!1,ru=1;const Ke=Symbol("SIGNAL");function te(e){const n=Le;return Le=e,n}const Er={version:0,lastCleanEpoch:0,dirty:!1,producerNode:void 0,producerLastReadVersion:void 0,producerIndexOfThis:void 0,nextProducerIndex:0,liveConsumerNode:void 0,liveConsumerIndexOfThis:void 0,consumerAllowSignalWrites:!1,consumerIsAlwaysLive:!1,kind:"unknown",producerMustRecompute:()=>!1,producerRecomputeValue:()=>{},consumerMarkedDirty:()=>{},consumerOnSignalRead:()=>{}};function Oo(e){if(xo)throw new Error("");if(null===Le)return;Le.consumerOnSignalRead(e);const n=Le.nextProducerIndex++;ha(Le),ne.nextProducerIndex;)e.producerNode.pop(),e.producerLastReadVersion.pop(),e.producerIndexOfThis.pop()}}function Ro(e){ha(e);for(let n=0;n0}function ha(e){e.producerNode??=[],e.producerIndexOfThis??=[],e.producerLastReadVersion??=[]}function ip(e){e.liveConsumerNode??=[],e.liveConsumerIndexOfThis??=[]}function op(e){return void 0!==e.producerNode}const Mr=Symbol("UNSET"),pi=Symbol("COMPUTING"),Gn=Symbol("ERRORED"),vM={...Er,value:Mr,dirty:!0,error:null,equal:ua,kind:"computed",producerMustRecompute:e=>e.value===Mr||e.value===pi,producerRecomputeValue(e){if(e.value===pi)throw new Error("Detected cycle in computations.");const n=e.value;e.value=pi;const t=Ir(e);let r,i=!1;try{r=e.computation(),te(null),i=n!==Mr&&n!==Gn&&r!==Gn&&e.equal(n,r)}catch(o){r=Gn,e.error=o}finally{gi(e,t)}i?e.value=n:(e.value=r,e.version++)}};let sp=function _M(){throw new Error};function ap(){sp()}function ou(e,n){tp()||ap(),e.equal(e.value,n)||(e.value=n,function wM(e){e.version++,function pM(){ru++}(),ep(e)}(e))}const cp={...Er,equal:ua,value:void 0,kind:"signal"};function Be(e){return"function"==typeof e}function dp(e){const t=e(r=>{Error.call(r),r.stack=(new Error).stack});return t.prototype=Object.create(Error.prototype),t.prototype.constructor=t,t}const au=dp(e=>function(t){e(this),this.message=t?`${t.length} errors occurred during unsubscription:\n${t.map((r,i)=>`${i+1}) ${r.toString()}`).join("\n ")}`:"",this.name="UnsubscriptionError",this.errors=t});function pa(e,n){if(e){const t=e.indexOf(n);0<=t&&e.splice(t,1)}}class Rt{constructor(n){this.initialTeardown=n,this.closed=!1,this._parentage=null,this._finalizers=null}unsubscribe(){let n;if(!this.closed){this.closed=!0;const{_parentage:t}=this;if(t)if(this._parentage=null,Array.isArray(t))for(const o of t)o.remove(this);else t.remove(this);const{initialTeardown:r}=this;if(Be(r))try{r()}catch(o){n=o instanceof au?o.errors:[o]}const{_finalizers:i}=this;if(i){this._finalizers=null;for(const o of i)try{gp(o)}catch(s){n=n??[],s instanceof au?n=[...n,...s.errors]:n.push(s)}}if(n)throw new au(n)}}add(n){var t;if(n&&n!==this)if(this.closed)gp(n);else{if(n instanceof Rt){if(n.closed||n._hasParent(this))return;n._addParent(this)}(this._finalizers=null!==(t=this._finalizers)&&void 0!==t?t:[]).push(n)}}_hasParent(n){const{_parentage:t}=this;return t===n||Array.isArray(t)&&t.includes(n)}_addParent(n){const{_parentage:t}=this;this._parentage=Array.isArray(t)?(t.push(n),t):t?[t,n]:n}_removeParent(n){const{_parentage:t}=this;t===n?this._parentage=null:Array.isArray(t)&&pa(t,n)}remove(n){const{_finalizers:t}=this;t&&pa(t,n),n instanceof Rt&&n._removeParent(this)}}Rt.EMPTY=(()=>{const e=new Rt;return e.closed=!0,e})();const fp=Rt.EMPTY;function hp(e){return e instanceof Rt||e&&"closed"in e&&Be(e.remove)&&Be(e.add)&&Be(e.unsubscribe)}function gp(e){Be(e)?e():e.unsubscribe()}const Tr={onUnhandledError:null,onStoppedNotification:null,Promise:void 0,useDeprecatedSynchronousErrorHandling:!1,useDeprecatedNextContext:!1},ma={setTimeout(e,n,...t){const{delegate:r}=ma;return r?.setTimeout?r.setTimeout(e,n,...t):setTimeout(e,n,...t)},clearTimeout(e){const{delegate:n}=ma;return(n?.clearTimeout||clearTimeout)(e)},delegate:void 0};function pp(e){ma.setTimeout(()=>{const{onUnhandledError:n}=Tr;if(!n)throw e;n(e)})}function mp(){}const TM=lu("C",void 0,void 0);function lu(e,n,t){return{kind:e,value:n,error:t}}let Sr=null;function va(e){if(Tr.useDeprecatedSynchronousErrorHandling){const n=!Sr;if(n&&(Sr={errorThrown:!1,error:null}),e(),n){const{errorThrown:t,error:r}=Sr;if(Sr=null,t)throw r}}else e()}class cu extends Rt{constructor(n){super(),this.isStopped=!1,n?(this.destination=n,hp(n)&&n.add(this)):this.destination=kM}static create(n,t,r){return new du(n,t,r)}next(n){this.isStopped?fu(function NM(e){return lu("N",e,void 0)}(n),this):this._next(n)}error(n){this.isStopped?fu(function SM(e){return lu("E",void 0,e)}(n),this):(this.isStopped=!0,this._error(n))}complete(){this.isStopped?fu(TM,this):(this.isStopped=!0,this._complete())}unsubscribe(){this.closed||(this.isStopped=!0,super.unsubscribe(),this.destination=null)}_next(n){this.destination.next(n)}_error(n){try{this.destination.error(n)}finally{this.unsubscribe()}}_complete(){try{this.destination.complete()}finally{this.unsubscribe()}}}const OM=Function.prototype.bind;function uu(e,n){return OM.call(e,n)}class AM{constructor(n){this.partialObserver=n}next(n){const{partialObserver:t}=this;if(t.next)try{t.next(n)}catch(r){_a(r)}}error(n){const{partialObserver:t}=this;if(t.error)try{t.error(n)}catch(r){_a(r)}else _a(n)}complete(){const{partialObserver:n}=this;if(n.complete)try{n.complete()}catch(t){_a(t)}}}class du extends cu{constructor(n,t,r){let i;if(super(),Be(n)||!n)i={next:n??void 0,error:t??void 0,complete:r??void 0};else{let o;this&&Tr.useDeprecatedNextContext?(o=Object.create(n),o.unsubscribe=()=>this.unsubscribe(),i={next:n.next&&uu(n.next,o),error:n.error&&uu(n.error,o),complete:n.complete&&uu(n.complete,o)}):i=n}this.destination=new AM(i)}}function _a(e){Tr.useDeprecatedSynchronousErrorHandling?function xM(e){Tr.useDeprecatedSynchronousErrorHandling&&Sr&&(Sr.errorThrown=!0,Sr.error=e)}(e):pp(e)}function fu(e,n){const{onStoppedNotification:t}=Tr;t&&ma.setTimeout(()=>t(e,n))}const kM={closed:!0,next:mp,error:function RM(e){throw e},complete:mp},hu="function"==typeof Symbol&&Symbol.observable||"@@observable";function gu(e){return e}let kt=(()=>{class e{constructor(t){t&&(this._subscribe=t)}lift(t){const r=new e;return r.source=this,r.operator=t,r}subscribe(t,r,i){const o=function LM(e){return e&&e instanceof cu||function FM(e){return e&&Be(e.next)&&Be(e.error)&&Be(e.complete)}(e)&&hp(e)}(t)?t:new du(t,r,i);return va(()=>{const{operator:s,source:a}=this;o.add(s?s.call(o,a):a?this._subscribe(o):this._trySubscribe(o))}),o}_trySubscribe(t){try{return this._subscribe(t)}catch(r){t.error(r)}}forEach(t,r){return new(r=_p(r))((i,o)=>{const s=new du({next:a=>{try{t(a)}catch(l){o(l),s.unsubscribe()}},error:o,complete:i});this.subscribe(s)})}_subscribe(t){var r;return null===(r=this.source)||void 0===r?void 0:r.subscribe(t)}[hu](){return this}pipe(...t){return function vp(e){return 0===e.length?gu:1===e.length?e[0]:function(t){return e.reduce((r,i)=>i(r),t)}}(t)(this)}toPromise(t){return new(t=_p(t))((r,i)=>{let o;this.subscribe(s=>o=s,s=>i(s),()=>r(o))})}}return e.create=n=>new e(n),e})();function _p(e){var n;return null!==(n=e??Tr.Promise)&&void 0!==n?n:Promise}const PM=dp(e=>function(){e(this),this.name="ObjectUnsubscribedError",this.message="object unsubscribed"});let fn=(()=>{class e extends kt{constructor(){super(),this.closed=!1,this.currentObservers=null,this.observers=[],this.isStopped=!1,this.hasError=!1,this.thrownError=null}lift(t){const r=new yp(this,this);return r.operator=t,r}_throwIfClosed(){if(this.closed)throw new PM}next(t){va(()=>{if(this._throwIfClosed(),!this.isStopped){this.currentObservers||(this.currentObservers=Array.from(this.observers));for(const r of this.currentObservers)r.next(t)}})}error(t){va(()=>{if(this._throwIfClosed(),!this.isStopped){this.hasError=this.isStopped=!0,this.thrownError=t;const{observers:r}=this;for(;r.length;)r.shift().error(t)}})}complete(){va(()=>{if(this._throwIfClosed(),!this.isStopped){this.isStopped=!0;const{observers:t}=this;for(;t.length;)t.shift().complete()}})}unsubscribe(){this.isStopped=this.closed=!0,this.observers=this.currentObservers=null}get observed(){var t;return(null===(t=this.observers)||void 0===t?void 0:t.length)>0}_trySubscribe(t){return this._throwIfClosed(),super._trySubscribe(t)}_subscribe(t){return this._throwIfClosed(),this._checkFinalizedStatuses(t),this._innerSubscribe(t)}_innerSubscribe(t){const{hasError:r,isStopped:i,observers:o}=this;return r||i?fp:(this.currentObservers=null,o.push(t),new Rt(()=>{this.currentObservers=null,pa(o,t)}))}_checkFinalizedStatuses(t){const{hasError:r,thrownError:i,isStopped:o}=this;r?t.error(i):o&&t.complete()}asObservable(){const t=new kt;return t.source=this,t}}return e.create=(n,t)=>new yp(n,t),e})();class yp extends fn{constructor(n,t){super(),this.destination=n,this.source=t}next(n){var t,r;null===(r=null===(t=this.destination)||void 0===t?void 0:t.next)||void 0===r||r.call(t,n)}error(n){var t,r;null===(r=null===(t=this.destination)||void 0===t?void 0:t.error)||void 0===r||r.call(t,n)}complete(){var n,t;null===(t=null===(n=this.destination)||void 0===n?void 0:n.complete)||void 0===t||t.call(n)}_subscribe(n){var t,r;return null!==(r=null===(t=this.source)||void 0===t?void 0:t.subscribe(n))&&void 0!==r?r:fp}}class VM extends fn{constructor(n){super(),this._value=n}get value(){return this.getValue()}_subscribe(n){const t=super._subscribe(n);return!t.closed&&n.next(this._value),t}getValue(){const{hasError:n,thrownError:t,_value:r}=this;if(n)throw t;return this._throwIfClosed(),r}next(n){super.next(this._value=n)}}function Nr(e){return n=>{if(function HM(e){return Be(e?.lift)}(n))return n.lift(function(t){try{return e(t,this)}catch(r){this.error(r)}});throw new TypeError("Unable to lift unknown Observable type")}}function qn(e,n,t,r,i){return new BM(e,n,t,r,i)}class BM extends cu{constructor(n,t,r,i,o,s){super(n),this.onFinalize=o,this.shouldUnsubscribe=s,this._next=t?function(a){try{t(a)}catch(l){n.error(l)}}:super._next,this._error=i?function(a){try{i(a)}catch(l){n.error(l)}finally{this.unsubscribe()}}:super._error,this._complete=r?function(){try{r()}catch(a){n.error(a)}finally{this.unsubscribe()}}:super._complete}unsubscribe(){var n;if(!this.shouldUnsubscribe||this.shouldUnsubscribe()){const{closed:t}=this;super.unsubscribe(),!t&&(null===(n=this.onFinalize)||void 0===n||n.call(this))}}}function pu(e,n){return Nr((t,r)=>{let i=0;t.subscribe(qn(r,o=>{r.next(e.call(n,o,i++))}))})}const Cp="https://g.co/ng/security#xss";class N extends Error{code;constructor(n,t){super(function xr(e,n){return`NG0${Math.abs(e)}${n?": "+n:""}`}(n,t)),this.code=n}}function Sn(e){return{toString:e}.toString()}const vi="__parameters__";function yi(e,n,t){return Sn(()=>{const r=function mu(e){return function(...t){if(e){const r=e(...t);for(const i in r)this[i]=r[i]}}}(n);function i(...o){if(this instanceof i)return r.apply(this,o),this;const s=new i(...o);return a.annotation=s,a;function a(l,c,u){const d=l.hasOwnProperty(vi)?l[vi]:Object.defineProperty(l,vi,{value:[]})[vi];for(;d.length<=u;)d.push(null);return(d[u]=d[u]||[]).push(s),l}}return t&&(i.prototype=Object.create(t.prototype)),i.prototype.ngMetadataName=e,i.annotationCls=i,i})}const Ie=globalThis;function fe(e){for(let n in e)if(e[n]===fe)return n;throw Error("Could not find renamed property on target object.")}function jM(e,n){for(const t in n)n.hasOwnProperty(t)&&!e.hasOwnProperty(t)&&(e[t]=n[t])}function $e(e){if("string"==typeof e)return e;if(Array.isArray(e))return"["+e.map($e).join(", ")+"]";if(null==e)return""+e;if(e.overriddenName)return`${e.overriddenName}`;if(e.name)return`${e.name}`;const n=e.toString();if(null==n)return""+n;const t=n.indexOf("\n");return-1===t?n:n.substring(0,t)}function vu(e,n){return null==e||""===e?null===n?"":n:null==n||""===n?e:e+" "+n}const UM=fe({__forward_ref__:fe});function ve(e){return e.__forward_ref__=ve,e.toString=function(){return $e(this())},e}function W(e){return Ca(e)?e():e}function Ca(e){return"function"==typeof e&&e.hasOwnProperty(UM)&&e.__forward_ref__===ve}function re(e){return{token:e.token,providedIn:e.providedIn||null,factory:e.factory,value:void 0}}function Nn(e){return{providers:e.providers||[],imports:e.imports||[]}}function wa(e){return Ep(e,ba)||Ep(e,Ip)}function Ep(e,n){return e.hasOwnProperty(n)?e[n]:null}function Da(e){return e&&(e.hasOwnProperty(_u)||e.hasOwnProperty(WM))?e[_u]:null}const ba=fe({\u0275prov:fe}),_u=fe({\u0275inj:fe}),Ip=fe({ngInjectableDef:fe}),WM=fe({ngInjectorDef:fe});class R{_desc;ngMetadataName="InjectionToken";\u0275prov;constructor(n,t){this._desc=n,this.\u0275prov=void 0,"number"==typeof t?this.__NG_ELEMENT_ID__=t:void 0!==t&&(this.\u0275prov=re({token:this,providedIn:t.providedIn||"root",factory:t.factory}))}get multi(){return this}toString(){return`InjectionToken ${this._desc}`}}function wu(e){return e&&!!e.\u0275providers}const Ci=fe({\u0275cmp:fe}),Du=fe({\u0275dir:fe}),bu=fe({\u0275pipe:fe}),Tp=fe({\u0275mod:fe}),xn=fe({\u0275fac:fe}),Lo=fe({__NG_ELEMENT_ID__:fe}),Sp=fe({__NG_ENV_ID__:fe});function K(e){return"string"==typeof e?e:null==e?"":String(e)}function Eu(e,n){throw new N(-201,!1)}var oe=function(e){return e[e.Default=0]="Default",e[e.Host=1]="Host",e[e.Self=2]="Self",e[e.SkipSelf=4]="SkipSelf",e[e.Optional=8]="Optional",e}(oe||{});let Iu;function Np(){return Iu}function Et(e){const n=Iu;return Iu=e,n}function xp(e,n,t){const r=wa(e);return r&&"root"==r.providedIn?void 0===r.value?r.value=r.factory():r.value:t&oe.Optional?null:void 0!==n?n:void Eu()}const Po={},Mu="__NG_DI_FLAG__",Ma="ngTempTokenPath",XM=/\n/gm,Op="__source";let wi;function Zn(e){const n=wi;return wi=e,n}function n0(e,n=oe.Default){if(void 0===wi)throw new N(-203,!1);return null===wi?xp(e,void 0,n):wi.get(e,n&oe.Optional?null:void 0,n)}function se(e,n=oe.Default){return(Np()||n0)(W(e),n)}function A(e,n=oe.Default){return se(e,Ta(n))}function Ta(e){return typeof e>"u"||"number"==typeof e?e:(e.optional&&8)|(e.host&&1)|(e.self&&2)|(e.skipSelf&&4)}function Tu(e){const n=[];for(let t=0;tArray.isArray(t)?Di(t,n):n(t))}function Rp(e,n,t){n>=e.length?e.push(t):e.splice(n,0,t)}function Sa(e,n){return n>=e.length-1?e.pop():e.splice(n,1)[0]}function Lt(e,n,t){let r=bi(e,n);return r>=0?e[1|r]=t:(r=~r,function kp(e,n,t,r){let i=e.length;if(i==n)e.push(t,r);else if(1===i)e.push(r,e[0]),e[0]=t;else{for(i--,e.push(e[i-1],e[i]);i>n;)e[i]=e[i-2],i--;e[n]=t,e[n+1]=r}}(e,r,n,t)),r}function Ou(e,n){const t=bi(e,n);if(t>=0)return e[1|t]}function bi(e,n){return function Fp(e,n,t){let r=0,i=e.length>>t;for(;i!==r;){const o=r+(i-r>>1),s=e[o<n?i=o:r=o+1}return~(i<{t.push(s)};return Di(n,s=>{const a=s;Oa(a,o,[],r)&&(i||=[],i.push(a))}),void 0!==i&&Pp(i,o),t}function Pp(e,n){for(let t=0;t{n(o,r)})}}function Oa(e,n,t,r){if(!(e=W(e)))return!1;let i=null,o=Da(e);const s=!o&&ne(e);if(o||s){if(s&&!s.standalone)return!1;i=e}else{const l=e.ngModule;if(o=Da(l),!o)return!1;i=l}const a=r.has(i);if(s){if(a)return!1;if(r.add(i),s.dependencies){const l="function"==typeof s.dependencies?s.dependencies():s.dependencies;for(const c of l)Oa(c,n,t,r)}}else{if(!o)return!1;{if(null!=o.imports&&!a){let c;r.add(i);try{Di(o.imports,u=>{Oa(u,n,t,r)&&(c||=[],c.push(u))})}finally{}void 0!==c&&Pp(c,n)}if(!a){const c=Or(i)||(()=>new i);n({provide:i,useFactory:c,deps:le},i),n({provide:Au,useValue:i,multi:!0},i),n({provide:en,useValue:()=>se(i),multi:!0},i)}const l=o.providers;if(null!=l&&!a){const c=e;ku(l,u=>{n(u,c)})}}}return i!==e&&void 0!==e.providers}function ku(e,n){for(let t of e)wu(t)&&(t=t.\u0275providers),Array.isArray(t)?ku(t,n):n(t)}const f0=fe({provide:String,useValue:fe});function Fu(e){return null!==e&&"object"==typeof e&&f0 in e}function kr(e){return"function"==typeof e}const Lu=new R(""),Aa={},g0={};let Pu;function Ra(){return void 0===Pu&&(Pu=new xa),Pu}class tn{}class Fr extends tn{parent;source;scopes;records=new Map;_ngOnDestroyHooks=new Set;_onDestroyHooks=[];get destroyed(){return this._destroyed}_destroyed=!1;injectorDefTypes;constructor(n,t,r,i){super(),this.parent=t,this.source=r,this.scopes=i,Hu(n,s=>this.processProvider(s)),this.records.set(Lp,Ei(void 0,this)),i.has("environment")&&this.records.set(tn,Ei(void 0,this));const o=this.records.get(Lu);null!=o&&"string"==typeof o.value&&this.scopes.add(o.value),this.injectorDefTypes=new Set(this.get(Au,le,oe.Self))}destroy(){Ho(this),this._destroyed=!0;const n=te(null);try{for(const r of this._ngOnDestroyHooks)r.ngOnDestroy();const t=this._onDestroyHooks;this._onDestroyHooks=[];for(const r of t)r()}finally{this.records.clear(),this._ngOnDestroyHooks.clear(),this.injectorDefTypes.clear(),te(n)}}onDestroy(n){return Ho(this),this._onDestroyHooks.push(n),()=>this.removeOnDestroy(n)}runInContext(n){Ho(this);const t=Zn(this),r=Et(void 0);try{return n()}finally{Zn(t),Et(r)}}get(n,t=Po,r=oe.Default){if(Ho(this),n.hasOwnProperty(Sp))return n[Sp](this);r=Ta(r);const o=Zn(this),s=Et(void 0);try{if(!(r&oe.SkipSelf)){let l=this.records.get(n);if(void 0===l){const c=function y0(e){return"function"==typeof e||"object"==typeof e&&e instanceof R}(n)&&wa(n);l=c&&this.injectableDefInScope(c)?Ei(Vu(n),Aa):null,this.records.set(n,l)}if(null!=l)return this.hydrate(n,l)}return(r&oe.Self?Ra():this.parent).get(n,t=r&oe.Optional&&t===Po?null:t)}catch(a){if("NullInjectorError"===a.name){if((a[Ma]=a[Ma]||[]).unshift($e(n)),o)throw a;return function o0(e,n,t,r){const i=e[Ma];throw n[Op]&&i.unshift(n[Op]),e.message=function s0(e,n,t,r=null){e=e&&"\n"===e.charAt(0)&&"\u0275"==e.charAt(1)?e.slice(2):e;let i=$e(n);if(Array.isArray(n))i=n.map($e).join(" -> ");else if("object"==typeof n){let o=[];for(let s in n)if(n.hasOwnProperty(s)){let a=n[s];o.push(s+":"+("string"==typeof a?JSON.stringify(a):$e(a)))}i=`{${o.join(", ")}}`}return`${t}${r?"("+r+")":""}[${i}]: ${e.replace(XM,"\n ")}`}("\n"+e.message,i,t,r),e.ngTokenPath=i,e[Ma]=null,e}(a,n,"R3InjectorError",this.source)}throw a}finally{Et(s),Zn(o)}}resolveInjectorInitializers(){const n=te(null),t=Zn(this),r=Et(void 0);try{const o=this.get(en,le,oe.Self);for(const s of o)s()}finally{Zn(t),Et(r),te(n)}}toString(){const n=[],t=this.records;for(const r of t.keys())n.push($e(r));return`R3Injector[${n.join(", ")}]`}processProvider(n){let t=kr(n=W(n))?n:W(n&&n.provide);const r=function m0(e){return Fu(e)?Ei(void 0,e.useValue):Ei(Bp(e),Aa)}(n);if(!kr(n)&&!0===n.multi){let i=this.records.get(t);i||(i=Ei(void 0,Aa,!0),i.factory=()=>Tu(i.multi),this.records.set(t,i)),t=n,i.multi.push(n)}this.records.set(t,r)}hydrate(n,t){const r=te(null);try{return t.value===Aa&&(t.value=g0,t.value=t.factory()),"object"==typeof t.value&&t.value&&function _0(e){return null!==e&&"object"==typeof e&&"function"==typeof e.ngOnDestroy}(t.value)&&this._ngOnDestroyHooks.add(t.value),t.value}finally{te(r)}}injectableDefInScope(n){if(!n.providedIn)return!1;const t=W(n.providedIn);return"string"==typeof t?"any"===t||this.scopes.has(t):this.injectorDefTypes.has(t)}removeOnDestroy(n){const t=this._onDestroyHooks.indexOf(n);-1!==t&&this._onDestroyHooks.splice(t,1)}}function Vu(e){const n=wa(e),t=null!==n?n.factory:Or(e);if(null!==t)return t;if(e instanceof R)throw new N(204,!1);if(e instanceof Function)return function p0(e){if(e.length>0)throw new N(204,!1);const t=function qM(e){return e&&(e[ba]||e[Ip])||null}(e);return null!==t?()=>t.factory(e):()=>new e}(e);throw new N(204,!1)}function Bp(e,n,t){let r;if(kr(e)){const i=W(e);return Or(i)||Vu(i)}if(Fu(e))r=()=>W(e.useValue);else if(function Hp(e){return!(!e||!e.useFactory)}(e))r=()=>e.useFactory(...Tu(e.deps||[]));else if(function Vp(e){return!(!e||!e.useExisting)}(e))r=()=>se(W(e.useExisting));else{const i=W(e&&(e.useClass||e.provide));if(!function v0(e){return!!e.deps}(e))return Or(i)||Vu(i);r=()=>new i(...Tu(e.deps))}return r}function Ho(e){if(e.destroyed)throw new N(205,!1)}function Ei(e,n,t=!1){return{factory:e,value:n,multi:t?[]:void 0}}function Hu(e,n){for(const t of e)Array.isArray(t)?Hu(t,n):t&&wu(t)?Hu(t.\u0275providers,n):n(t)}function jp(e,n){e instanceof Fr&&Ho(e);const r=Zn(e),i=Et(void 0);try{return n()}finally{Zn(r),Et(i)}}const G=11,k=25;function Ne(e){return Array.isArray(e)&&"object"==typeof e[1]}function qe(e){return Array.isArray(e)&&!0===e[1]}function Uu(e){return!!(4&e.flags)}function $t(e){return e.componentOffset>-1}function Va(e){return!(1&~e.flags)}function zt(e){return!!e.template}function Rn(e){return!!(512&e[2])}function Yn(e){return!(256&~e[2])}class O0{previousValue;currentValue;firstChange;constructor(n,t,r){this.previousValue=n,this.currentValue=t,this.firstChange=r}isFirstChange(){return this.firstChange}}function Yp(e,n,t,r){null!==n?n.applyValueToInputSignal(n,r):e[t]=r}const kn=(()=>{const e=()=>Kp;return e.ngInherit=!0,e})();function Kp(e){return e.type.prototype.ngOnChanges&&(e.setInput=R0),A0}function A0(){const e=Xp(this),n=e?.current;if(n){const t=e.previous;if(t===hn)e.previous=n;else for(let r in n)t[r]=n[r];e.current=null,this.ngOnChanges(n)}}function R0(e,n,t,r,i){const o=this.declaredInputs[r],s=Xp(e)||function k0(e,n){return e[Jp]=n}(e,{previous:hn,current:null}),a=s.current||(s.current={}),l=s.previous,c=l[o];a[o]=new O0(c&&c.currentValue,t,l===hn),Yp(e,n,i,t)}const Jp="__ngSimpleChanges__";function Xp(e){return e[Jp]||null}function ae(e){for(;Array.isArray(e);)e=e[0];return e}function Ai(e,n){return ae(n[e])}function ft(e,n){return ae(n[e.index])}function Hr(e,n){return e.data[n]}function ht(e,n){const t=n[e];return Ne(t)?t:t[0]}function Gu(e){return!(128&~e[2])}function qt(e,n){return null==n?null:e[n]}function nm(e){e[17]=0}function qu(e){1024&e[2]||(e[2]|=1024,Gu(e)&&jo(e))}function Ba(e){return!!(9216&e[2]||e[24]?.dirty)}function Wu(e){e[10].changeDetectionScheduler?.notify(9),64&e[2]&&(e[2]|=1024),Ba(e)&&jo(e)}function jo(e){e[10].changeDetectionScheduler?.notify(0);let n=Fn(e);for(;null!==n&&!(8192&n[2])&&(n[2]|=8192,Gu(n));)n=Fn(n)}function ja(e,n){if(Yn(e))throw new N(911,!1);null===e[21]&&(e[21]=[]),e[21].push(n)}function Fn(e){const n=e[3];return qe(n)?n[3]:n}function im(e){return e[7]??=[]}function om(e){return e.cleanup??=[]}const Q={lFrame:pm(null),bindingsEnabled:!0,skipHydrationRootTNode:null};let Yu=!1;function sm(){return Q.bindingsEnabled}function D(){return Q.lFrame.lView}function Z(){return Q.lFrame.tView}function B(e){return Q.lFrame.contextLView=e,e[8]}function j(e){return Q.lFrame.contextLView=null,e}function ie(){let e=am();for(;null!==e&&64===e.type;)e=e.parent;return e}function am(){return Q.lFrame.currentTNode}function nn(e,n){const t=Q.lFrame;t.currentTNode=e,t.isParent=n}function Ku(){return Q.lFrame.isParent}function Ju(){Q.lFrame.isParent=!1}function um(){return Yu}function $a(e){const n=Yu;return Yu=e,n}function gt(){const e=Q.lFrame;let n=e.bindingRootIndex;return-1===n&&(n=e.bindingRootIndex=e.tView.bindingStartIndex),n}function Wt(){return Q.lFrame.bindingIndex++}function Pn(e){const n=Q.lFrame,t=n.bindingIndex;return n.bindingIndex=n.bindingIndex+e,t}function Q0(e,n){const t=Q.lFrame;t.bindingIndex=t.bindingRootIndex=e,Xu(n)}function Xu(e){Q.lFrame.currentDirectiveIndex=e}function td(){return Q.lFrame.currentQueryIndex}function za(e){Q.lFrame.currentQueryIndex=e}function K0(e){const n=e[1];return 2===n.type?n.declTNode:1===n.type?e[5]:null}function hm(e,n,t){if(t&oe.SkipSelf){let i=n,o=e;for(;!(i=i.parent,null!==i||t&oe.Host||(i=K0(o),null===i||(o=o[14],10&i.type))););if(null===i)return!1;n=i,e=o}const r=Q.lFrame=gm();return r.currentTNode=n,r.lView=e,!0}function nd(e){const n=gm(),t=e[1];Q.lFrame=n,n.currentTNode=t.firstChild,n.lView=e,n.tView=t,n.contextLView=e,n.bindingIndex=t.bindingStartIndex,n.inI18n=!1}function gm(){const e=Q.lFrame,n=null===e?null:e.child;return null===n?pm(e):n}function pm(e){const n={currentTNode:null,isParent:!0,lView:null,tView:null,selectedIndex:-1,contextLView:null,elementDepthCount:0,currentNamespace:null,currentDirectiveIndex:-1,bindingRootIndex:-1,bindingIndex:-1,currentQueryIndex:0,parent:e,child:null,inI18n:!1};return null!==e&&(e.child=n),n}function mm(){const e=Q.lFrame;return Q.lFrame=e.parent,e.currentTNode=null,e.lView=null,e}const vm=mm;function rd(){const e=mm();e.isParent=!0,e.tView=null,e.selectedIndex=-1,e.contextLView=null,e.elementDepthCount=0,e.currentDirectiveIndex=-1,e.currentNamespace=null,e.bindingRootIndex=-1,e.bindingIndex=-1,e.currentQueryIndex=0}function rt(){return Q.lFrame.selectedIndex}function Ur(e){Q.lFrame.selectedIndex=e}function me(){const e=Q.lFrame;return Hr(e.tView,e.selectedIndex)}let Cm=!0;function $o(){return Cm}function mn(e){Cm=e}function Ga(e,n){for(let t=n.directiveStart,r=n.directiveEnd;t=r)break}else n[l]<0&&(e[17]+=65536),(a>14>16&&(3&e[2])===n&&(e[2]+=16384,Dm(a,o)):Dm(a,o)}class zo{factory;injectImpl;resolving=!1;canSeeViewProviders;multi;componentProviders;index;providerFactory;constructor(n,t,r){this.factory=n,this.canSeeViewProviders=t,this.injectImpl=r}}function bm(e){return 3===e||4===e||6===e}function Em(e){return 64===e.charCodeAt(0)}function ki(e,n){if(null!==n&&0!==n.length)if(null===e||0===e.length)e=n.slice();else{let t=-1;for(let r=0;rn){s=o-1;break}}}for(;o>16}(e),r=n;for(;t>0;)r=r[14],t--;return r}let cd=!0;function Za(e){const n=cd;return cd=e,n}let dT=0;const vn={};function Qa(e,n){const t=Sm(e,n);if(-1!==t)return t;const r=n[1];r.firstCreatePass&&(e.injectorIndex=n.length,ud(r.data,e),ud(n,null),ud(r.blueprint,null));const i=Ya(e,n),o=e.injectorIndex;if(ld(i)){const s=Go(i),a=qo(i,n),l=a[1].data;for(let c=0;c<8;c++)n[o+c]=a[s+c]|l[s+c]}return n[o+8]=i,o}function ud(e,n){e.push(0,0,0,0,0,0,0,0,n)}function Sm(e,n){return-1===e.injectorIndex||e.parent&&e.parent.injectorIndex===e.injectorIndex||null===n[e.injectorIndex+8]?-1:e.injectorIndex}function Ya(e,n){if(e.parent&&-1!==e.parent.injectorIndex)return e.parent.injectorIndex;let t=0,r=null,i=n;for(;null!==i;){if(r=Fm(i),null===r)return-1;if(t++,i=i[14],-1!==r.injectorIndex)return r.injectorIndex|t<<16}return-1}function dd(e,n,t){!function fT(e,n,t){let r;"string"==typeof t?r=t.charCodeAt(0)||0:t.hasOwnProperty(Lo)&&(r=t[Lo]),null==r&&(r=t[Lo]=dT++);const i=255&r;n.data[e+(i>>5)]|=1<=0?255&n:mT:n}(t);if("function"==typeof o){if(!hm(n,e,r))return r&oe.Host?Nm(i,0,r):xm(n,t,r,i);try{let s;if(s=o(r),null!=s||r&oe.Optional)return s;Eu()}finally{vm()}}else if("number"==typeof o){let s=null,a=Sm(e,n),l=-1,c=r&oe.Host?n[15][5]:null;for((-1===a||r&oe.SkipSelf)&&(l=-1===a?Ya(e,n):n[a+8],-1!==l&&km(r,!1)?(s=n[1],a=Go(l),n=qo(l,n)):a=-1);-1!==a;){const u=n[1];if(Rm(o,a,u.data)){const d=gT(a,n,t,s,r,c);if(d!==vn)return d}l=n[a+8],-1!==l&&km(r,n[1].data[a+8]===c)&&Rm(o,a,n)?(s=u,a=Go(l),n=qo(l,n)):a=-1}}return i}function gT(e,n,t,r,i,o){const s=n[1],a=s.data[e+8],u=Ka(a,s,t,null==r?$t(a)&&cd:r!=s&&!!(3&a.type),i&oe.Host&&o===a);return null!==u?Wo(n,s,u,a):vn}function Ka(e,n,t,r,i){const o=e.providerIndexes,s=n.data,a=1048575&o,l=e.directiveStart,u=o>>20,g=i?a+u:e.directiveEnd;for(let h=r?a:a+u;h=l&&m.type===t)return h}if(i){const h=s[l];if(h&&zt(h)&&h.type===t)return l}return null}function Wo(e,n,t,r){let i=e[t];const o=n.data;if(function iT(e){return e instanceof zo}(i)){const s=i;s.resolving&&function YM(e,n){throw n&&n.join(" > "),new N(-200,e)}(function ce(e){return"function"==typeof e?e.name||e.toString():"object"==typeof e&&null!=e&&"function"==typeof e.type?e.type.name||e.type.toString():K(e)}(o[t]));const a=Za(s.canSeeViewProviders);s.resolving=!0;const c=s.injectImpl?Et(s.injectImpl):null;hm(e,r,oe.Default);try{i=e[t]=s.factory(void 0,o,e,r),n.firstCreatePass&&t>=r.directiveStart&&function nT(e,n,t){const{ngOnChanges:r,ngOnInit:i,ngDoCheck:o}=n.type.prototype;if(r){const s=Kp(n);(t.preOrderHooks??=[]).push(e,s),(t.preOrderCheckHooks??=[]).push(e,s)}i&&(t.preOrderHooks??=[]).push(0-e,i),o&&((t.preOrderHooks??=[]).push(e,o),(t.preOrderCheckHooks??=[]).push(e,o))}(t,o[t],n)}finally{null!==c&&Et(c),Za(a),s.resolving=!1,vm()}}return i}function Rm(e,n,t){return!!(t[n+(e>>5)]&1<{const n=e.prototype.constructor,t=n[xn]||fd(n),r=Object.prototype;let i=Object.getPrototypeOf(e.prototype).constructor;for(;i&&i!==r;){const o=i[xn]||fd(i);if(o&&o!==t)return o;i=Object.getPrototypeOf(i)}return o=>new o})}function fd(e){return Ca(e)?()=>{const n=fd(W(e));return n&&n()}:Or(e)}function Fm(e){const n=e[1],t=n.type;return 2===t?n.declTNode:1===t?e[5]:null}function Bm(e,n=null,t=null,r){const i=jm(e,n,t,r);return i.resolveInjectorInitializers(),i}function jm(e,n=null,t=null,r,i=new Set){const o=[t||le,d0(e)];return r=r||("object"==typeof e?void 0:$e(e)),new Fr(o,n||Ra(),r||null,i)}class We{static THROW_IF_NOT_FOUND=Po;static NULL=new xa;static create(n,t){if(Array.isArray(n))return Bm({name:""},t,n,"");{const r=n.name??"";return Bm({name:r},n.parent,n.providers,r)}}static \u0275prov=re({token:We,providedIn:"any",factory:()=>se(Lp)});static __NG_ELEMENT_ID__=-1}new R("").__NG_ELEMENT_ID__=e=>{const n=ie();if(null===n)throw new N(204,!1);if(2&n.type)return n.value;if(e&oe.Optional)return null;throw new N(204,!1)};const Um=!1;let Jn=(()=>class e{static __NG_ELEMENT_ID__=MT;static __NG_ENV_ID__=t=>t})();class $m extends Jn{_lView;constructor(n){super(),this._lView=n}onDestroy(n){return ja(this._lView,n),()=>function Zu(e,n){if(null===e[21])return;const t=e[21].indexOf(n);-1!==t&&e[21].splice(t,1)}(this._lView,n)}}function MT(){return new $m(D())}class Vn{}const Zo=new R("",{providedIn:"root",factory:()=>!1}),zm=new R(""),gd=new R("");let Xn=(()=>{class e{taskId=0;pendingTasks=new Set;get _hasPendingTasks(){return this.hasPendingTasks.value}hasPendingTasks=new VM(!1);add(){this._hasPendingTasks||this.hasPendingTasks.next(!0);const t=this.taskId++;return this.pendingTasks.add(t),t}has(t){return this.pendingTasks.has(t)}remove(t){this.pendingTasks.delete(t),0===this.pendingTasks.size&&this._hasPendingTasks&&this.hasPendingTasks.next(!1)}ngOnDestroy(){this.pendingTasks.clear(),this._hasPendingTasks&&this.hasPendingTasks.next(!1)}static \u0275prov=re({token:e,providedIn:"root",factory:()=>new e})}return e})();const we=class ST extends fn{__isAsync;destroyRef=void 0;pendingTasks=void 0;constructor(n=!1){super(),this.__isAsync=n,function Up(){return void 0!==Np()||null!=function t0(){return wi}()}()&&(this.destroyRef=A(Jn,{optional:!0})??void 0,this.pendingTasks=A(Xn,{optional:!0})??void 0)}emit(n){const t=te(null);try{super.next(n)}finally{te(t)}}subscribe(n,t,r){let i=n,o=t||(()=>null),s=r;if(n&&"object"==typeof n){const l=n;i=l.next?.bind(l),o=l.error?.bind(l),s=l.complete?.bind(l)}this.__isAsync&&(o=this.wrapInTimeout(o),i&&(i=this.wrapInTimeout(i)),s&&(s=this.wrapInTimeout(s)));const a=super.subscribe({next:i,error:o,complete:s});return n instanceof Rt&&n.add(a),a}wrapInTimeout(n){return t=>{const r=this.pendingTasks?.add();setTimeout(()=>{n(t),void 0!==r&&this.pendingTasks?.remove(r)})}}};function Qo(...e){}function Gm(e){let n,t;function r(){e=Qo;try{void 0!==t&&"function"==typeof cancelAnimationFrame&&cancelAnimationFrame(t),void 0!==n&&clearTimeout(n)}catch{}}return n=setTimeout(()=>{e(),r()}),"function"==typeof requestAnimationFrame&&(t=requestAnimationFrame(()=>{e(),r()})),()=>r()}function qm(e){return queueMicrotask(()=>e()),()=>{e=Qo}}const pd="isAngularZone",el=pd+"_ID";let NT=0;class de{hasPendingMacrotasks=!1;hasPendingMicrotasks=!1;isStable=!0;onUnstable=new we(!1);onMicrotaskEmpty=new we(!1);onStable=new we(!1);onError=new we(!1);constructor(n){const{enableLongStackTrace:t=!1,shouldCoalesceEventChangeDetection:r=!1,shouldCoalesceRunChangeDetection:i=!1,scheduleInRootZone:o=Um}=n;if(typeof Zone>"u")throw new N(908,!1);Zone.assertZonePatched();const s=this;s._nesting=0,s._outer=s._inner=Zone.current,Zone.TaskTrackingZoneSpec&&(s._inner=s._inner.fork(new Zone.TaskTrackingZoneSpec)),t&&Zone.longStackTraceZoneSpec&&(s._inner=s._inner.fork(Zone.longStackTraceZoneSpec)),s.shouldCoalesceEventChangeDetection=!i&&r,s.shouldCoalesceRunChangeDetection=i,s.callbackScheduled=!1,s.scheduleInRootZone=o,function AT(e){const n=()=>{!function OT(e){function n(){Gm(()=>{e.callbackScheduled=!1,vd(e),e.isCheckStableRunning=!0,md(e),e.isCheckStableRunning=!1})}e.isCheckStableRunning||e.callbackScheduled||(e.callbackScheduled=!0,e.scheduleInRootZone?Zone.root.run(()=>{n()}):e._outer.run(()=>{n()}),vd(e))}(e)},t=NT++;e._inner=e._inner.fork({name:"angular",properties:{[pd]:!0,[el]:t,[el+t]:!0},onInvokeTask:(r,i,o,s,a,l)=>{if(function RT(e){return Qm(e,"__ignore_ng_zone__")}(l))return r.invokeTask(o,s,a,l);try{return Wm(e),r.invokeTask(o,s,a,l)}finally{(e.shouldCoalesceEventChangeDetection&&"eventTask"===s.type||e.shouldCoalesceRunChangeDetection)&&n(),Zm(e)}},onInvoke:(r,i,o,s,a,l,c)=>{try{return Wm(e),r.invoke(o,s,a,l,c)}finally{e.shouldCoalesceRunChangeDetection&&!e.callbackScheduled&&!function kT(e){return Qm(e,"__scheduler_tick__")}(l)&&n(),Zm(e)}},onHasTask:(r,i,o,s)=>{r.hasTask(o,s),i===o&&("microTask"==s.change?(e._hasPendingMicrotasks=s.microTask,vd(e),md(e)):"macroTask"==s.change&&(e.hasPendingMacrotasks=s.macroTask))},onHandleError:(r,i,o,s)=>(r.handleError(o,s),e.runOutsideAngular(()=>e.onError.emit(s)),!1)})}(s)}static isInAngularZone(){return typeof Zone<"u"&&!0===Zone.current.get(pd)}static assertInAngularZone(){if(!de.isInAngularZone())throw new N(909,!1)}static assertNotInAngularZone(){if(de.isInAngularZone())throw new N(909,!1)}run(n,t,r){return this._inner.run(n,t,r)}runTask(n,t,r,i){const o=this._inner,s=o.scheduleEventTask("NgZoneEvent: "+i,n,xT,Qo,Qo);try{return o.runTask(s,t,r)}finally{o.cancelTask(s)}}runGuarded(n,t,r){return this._inner.runGuarded(n,t,r)}runOutsideAngular(n){return this._outer.run(n)}}const xT={};function md(e){if(0==e._nesting&&!e.hasPendingMicrotasks&&!e.isStable)try{e._nesting++,e.onMicrotaskEmpty.emit(null)}finally{if(e._nesting--,!e.hasPendingMicrotasks)try{e.runOutsideAngular(()=>e.onStable.emit(null))}finally{e.isStable=!0}}}function vd(e){e.hasPendingMicrotasks=!!(e._hasPendingMicrotasks||(e.shouldCoalesceEventChangeDetection||e.shouldCoalesceRunChangeDetection)&&!0===e.callbackScheduled)}function Wm(e){e._nesting++,e.isStable&&(e.isStable=!1,e.onUnstable.emit(null))}function Zm(e){e._nesting--,md(e)}class _d{hasPendingMicrotasks=!1;hasPendingMacrotasks=!1;isStable=!0;onUnstable=new we;onMicrotaskEmpty=new we;onStable=new we;onError=new we;run(n,t,r){return n.apply(t,r)}runGuarded(n,t,r){return n.apply(t,r)}runOutsideAngular(n){return n()}runTask(n,t,r,i){return n.apply(t,r)}}function Qm(e,n){return!(!Array.isArray(e)||1!==e.length)&&!0===e[0]?.data?.[n]}class _n{_console=console;handleError(n){this._console.error("ERROR",n)}}const LT=new R("",{providedIn:"root",factory:()=>{const e=A(de),n=A(_n);return t=>e.runOutsideAngular(()=>n.handleError(t))}});function PT(){return Fi(ie(),D())}function Fi(e,n){return new pt(ft(e,n))}let pt=(()=>class e{nativeElement;constructor(t){this.nativeElement=t}static __NG_ELEMENT_ID__=PT})();function Km(e){return e instanceof pt?e.nativeElement:e}const Jm=new Set;function Xe(e){Jm.has(e)||(Jm.add(e),performance?.mark?.("mark_feature_usage",{detail:{feature:e}}))}function Gr(e,n){Xe("NgSignals");const t=function CM(e){const n=Object.create(cp);n.value=e;const t=()=>(Oo(n),n.value);return t[Ke]=n,t}(e),r=t[Ke];return n?.equal&&(r.equal=n.equal),t.set=i=>ou(r,i),t.update=i=>function lp(e,n){tp()||ap(),ou(e,n(e.value))}(r,i),t.asReadonly=tl.bind(t),t}function tl(){const e=this[Ke];if(void 0===e.readonlyFn){const n=()=>this();n[Ke]=e,e.readonlyFn=n}return e.readonlyFn}function ev(e){return function Xm(e){return"function"==typeof e&&void 0!==e[Ke]}(e)&&"function"==typeof e.set}function VT(){return this._results[Symbol.iterator]()}class HT{_emitDistinctChangesOnly;dirty=!0;_onDirty=void 0;_results=[];_changesDetected=!1;_changes=void 0;length=0;first=void 0;last=void 0;get changes(){return this._changes??=new fn}constructor(n=!1){this._emitDistinctChangesOnly=n}get(n){return this._results[n]}map(n){return this._results.map(n)}filter(n){return this._results.filter(n)}find(n){return this._results.find(n)}reduce(n,t){return this._results.reduce(n,t)}forEach(n){this._results.forEach(n)}some(n){return this._results.some(n)}toArray(){return this._results.slice()}toString(){return this._results.toString()}reset(n,t){this.dirty=!1;const r=function It(e){return e.flat(Number.POSITIVE_INFINITY)}(n);(this._changesDetected=!function u0(e,n,t){if(e.length!==n.length)return!1;for(let r=0;raS}),aS="ng",Ed=new R(""),Pi=new R("",{providedIn:"platform",factory:()=>"unknown"}),yv=new R("",{providedIn:"root",factory:()=>yn().body?.querySelector("[ngCspNonce]")?.getAttribute("ngCspNonce")||null}),bv=new R("",{providedIn:"root",factory:()=>!1});var Fd=function(e){return e[e.CHANGE_DETECTION=0]="CHANGE_DETECTION",e[e.AFTER_NEXT_RENDER=1]="AFTER_NEXT_RENDER",e}(Fd||{});const Hi=new R("");let Ld=(()=>{class e{impl=null;execute(){this.impl?.execute()}static \u0275prov=re({token:e,providedIn:"root",factory:()=>new e})}return e})();function Xv(e,n){const t=e.contentQueries;if(null!==t){const r=te(null);try{for(let i=0;ie,createScript:e=>e,createScriptURL:e=>e})}catch{}return yl}()?.createHTML(e)||e}function e_(e){return function Kd(){if(void 0===Cl&&(Cl=null,Ie.trustedTypes))try{Cl=Ie.trustedTypes.createPolicy("angular#unsafe-bypass",{createHTML:e=>e,createScript:e=>e,createScriptURL:e=>e})}catch{}return Cl}()?.createHTML(e)||e}class r_{changingThisBreaksApplicationSecurity;constructor(n){this.changingThisBreaksApplicationSecurity=n}toString(){return`SafeValue must use [property]=binding: ${this.changingThisBreaksApplicationSecurity} (see ${Cp})`}}function rr(e){return e instanceof r_?e.changingThisBreaksApplicationSecurity:e}function cs(e,n){const t=function eN(e){return e instanceof r_&&e.getTypeName()||null}(e);if(null!=t&&t!==n){if("ResourceURL"===t&&"URL"===n)return!0;throw new Error(`Required a safe ${n}, got a ${t} (see ${Cp})`)}return t===n}class tN{inertDocumentHelper;constructor(n){this.inertDocumentHelper=n}getInertBodyElement(n){n=""+n;try{const t=(new window.DOMParser).parseFromString(Zi(n),"text/html").body;return null===t?this.inertDocumentHelper.getInertBodyElement(n):(t.firstChild?.remove(),t)}catch{return null}}}class nN{defaultDoc;inertDocument;constructor(n){this.defaultDoc=n,this.inertDocument=this.defaultDoc.implementation.createHTMLDocument("sanitization-inert")}getInertBodyElement(n){const t=this.inertDocument.createElement("template");return t.innerHTML=Zi(n),t}}const iN=/^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:\/?#]*(?:[\/?#]|$))/i;function Jd(e){return(e=String(e)).match(iN)?e:"unsafe:"+e}function Hn(e){const n={};for(const t of e.split(","))n[t]=!0;return n}function us(...e){const n={};for(const t of e)for(const r in t)t.hasOwnProperty(r)&&(n[r]=!0);return n}const o_=Hn("area,br,col,hr,img,wbr"),s_=Hn("colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr"),a_=Hn("rp,rt"),Xd=us(o_,us(s_,Hn("address,article,aside,blockquote,caption,center,del,details,dialog,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5,h6,header,hgroup,hr,ins,main,map,menu,nav,ol,pre,section,summary,table,ul")),us(a_,Hn("a,abbr,acronym,audio,b,bdi,bdo,big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,picture,q,ruby,rp,rt,s,samp,small,source,span,strike,strong,sub,sup,time,track,tt,u,var,video")),us(a_,s_)),ef=Hn("background,cite,href,itemtype,longdesc,poster,src,xlink:href"),l_=us(ef,Hn("abbr,accesskey,align,alt,autoplay,axis,bgcolor,border,cellpadding,cellspacing,class,clear,color,cols,colspan,compact,controls,coords,datetime,default,dir,download,face,headers,height,hidden,hreflang,hspace,ismap,itemscope,itemprop,kind,label,lang,language,loop,media,muted,nohref,nowrap,open,preload,rel,rev,role,rows,rowspan,rules,scope,scrolling,shape,size,sizes,span,srclang,srcset,start,summary,tabindex,target,title,translate,type,usemap,valign,value,vspace,width"),Hn("aria-activedescendant,aria-atomic,aria-autocomplete,aria-busy,aria-checked,aria-colcount,aria-colindex,aria-colspan,aria-controls,aria-current,aria-describedby,aria-details,aria-disabled,aria-dropeffect,aria-errormessage,aria-expanded,aria-flowto,aria-grabbed,aria-haspopup,aria-hidden,aria-invalid,aria-keyshortcuts,aria-label,aria-labelledby,aria-level,aria-live,aria-modal,aria-multiline,aria-multiselectable,aria-orientation,aria-owns,aria-placeholder,aria-posinset,aria-pressed,aria-readonly,aria-relevant,aria-required,aria-roledescription,aria-rowcount,aria-rowindex,aria-rowspan,aria-selected,aria-setsize,aria-sort,aria-valuemax,aria-valuemin,aria-valuenow,aria-valuetext")),oN=Hn("script,style,template");class sN{sanitizedSomething=!1;buf=[];sanitizeChildren(n){let t=n.firstChild,r=!0,i=[];for(;t;)if(t.nodeType===Node.ELEMENT_NODE?r=this.startElement(t):t.nodeType===Node.TEXT_NODE?this.chars(t.nodeValue):this.sanitizedSomething=!0,r&&t.firstChild)i.push(t),t=cN(t);else for(;t;){t.nodeType===Node.ELEMENT_NODE&&this.endElement(t);let o=lN(t);if(o){t=o;break}t=i.pop()}return this.buf.join("")}startElement(n){const t=c_(n).toLowerCase();if(!Xd.hasOwnProperty(t))return this.sanitizedSomething=!0,!oN.hasOwnProperty(t);this.buf.push("<"),this.buf.push(t);const r=n.attributes;for(let i=0;i"),!0}endElement(n){const t=c_(n).toLowerCase();Xd.hasOwnProperty(t)&&!o_.hasOwnProperty(t)&&(this.buf.push(""))}chars(n){this.buf.push(d_(n))}}function lN(e){const n=e.nextSibling;if(n&&e!==n.previousSibling)throw u_(n);return n}function cN(e){const n=e.firstChild;if(n&&function aN(e,n){return(e.compareDocumentPosition(n)&Node.DOCUMENT_POSITION_CONTAINED_BY)!==Node.DOCUMENT_POSITION_CONTAINED_BY}(e,n))throw u_(n);return n}function c_(e){const n=e.nodeName;return"string"==typeof n?n:"FORM"}function u_(e){return new Error(`Failed to sanitize html because the element is clobbered: ${e.outerHTML}`)}const uN=/[\uD800-\uDBFF][\uDC00-\uDFFF]/g,dN=/([^\#-~ |!])/g;function d_(e){return e.replace(/&/g,"&").replace(uN,function(n){return"&#"+(1024*(n.charCodeAt(0)-55296)+(n.charCodeAt(1)-56320)+65536)+";"}).replace(dN,function(n){return"&#"+n.charCodeAt(0)+";"}).replace(//g,">")}let wl;function tf(e){return"content"in e&&function hN(e){return e.nodeType===Node.ELEMENT_NODE&&"TEMPLATE"===e.nodeName}(e)?e.content:null}var Qi=function(e){return e[e.NONE=0]="NONE",e[e.HTML=1]="HTML",e[e.STYLE=2]="STYLE",e[e.SCRIPT=3]="SCRIPT",e[e.URL=4]="URL",e[e.RESOURCE_URL=5]="RESOURCE_URL",e}(Qi||{});function f_(e){const n=ds();return n?e_(n.sanitize(Qi.HTML,e)||""):cs(e,"HTML")?e_(rr(e)):function fN(e,n){let t=null;try{wl=wl||function i_(e){const n=new nN(e);return function rN(){try{return!!(new window.DOMParser).parseFromString(Zi(""),"text/html")}catch{return!1}}()?new tN(n):n}(e);let r=n?String(n):"";t=wl.getInertBodyElement(r);let i=5,o=r;do{if(0===i)throw new Error("Failed to sanitize html because the input is unstable");i--,r=o,o=t.innerHTML,t=wl.getInertBodyElement(r)}while(r!==o);return Zi((new sN).sanitizeChildren(tf(t)||t))}finally{if(t){const r=tf(t)||t;for(;r.firstChild;)r.firstChild.remove()}}}(yn(),K(e))}function ir(e){const n=ds();return n?n.sanitize(Qi.URL,e)||"":cs(e,"URL")?rr(e):Jd(K(e))}function ds(){const e=D();return e&&e[10].sanitizer}const CN=/^>|^->||--!>|)/g;function El(e){return e.ownerDocument.defaultView}var or=function(e){return e[e.None=0]="None",e[e.SignalBased=1]="SignalBased",e[e.HasDecoratorInputTransform=2]="HasDecoratorInputTransform",e}(or||{});function AN(e,n,t){let r=e.length;for(;;){const i=e.indexOf(n,t);if(-1===i)return i;if(0===i||e.charCodeAt(i-1)<=32){const o=n.length;if(i+o===r||e.charCodeAt(i+o)<=32)return i}t=i+1}}const D_="ng-template";function RN(e,n,t,r){let i=0;if(r){for(;i-1){let o;for(;++io?"":i[u+1].toLowerCase(),2&r&&c!==d){if(rn(r))return!1;s=!0}}}}else{if(!s&&!rn(r)&&!rn(l))return!1;if(s&&rn(l))continue;s=!1,r=l|1&r}}return rn(r)||s}function rn(e){return!(1&e)}function LN(e,n,t,r){if(null===n)return-1;let i=0;if(r||!t){let o=!1;for(;i-1)for(t++;t0?'="'+a+'"':"")+"]"}else 8&r?i+="."+s:4&r&&(i+=" "+s);else""!==i&&!rn(s)&&(n+=E_(o,i),i=""),r=s,o=o||!rn(r);t++}return""!==i&&(n+=E_(o,i)),n}const J={};function af(e,n){return e.createComment(function g_(e){return e.replace(CN,n=>n.replace(wN,"\u200b$1\u200b"))}(n))}function Il(e,n,t){return e.createElement(n,t)}function Qr(e,n,t,r,i){e.insertBefore(n,t,r,i)}function M_(e,n,t){e.appendChild(n,t)}function T_(e,n,t,r,i){null!==r?Qr(e,n,t,r,i):M_(e,n,t)}function N_(e,n,t){const{mergedAttrs:r,classes:i,styles:o}=t;null!==r&&function lT(e,n,t){let r=0;for(;rk&&x_(e,n,k,!1),t(r,i)}finally{Ur(o)}}function lf(e,n,t){sm()&&(vt(ft(t,n),n),R_(e,n,t))}function R_(e,n,t){(function ix(e,n,t){const r=t.directiveStart,i=t.directiveEnd;$t(t)&&function hx(e,n,t){const r=ft(n,e),i=function k_(e){const n=e.tView;return null===n||n.incompleteFirstPass?e.tView=uf(1,null,e.template,e.decls,e.vars,e.directiveDefs,e.pipeDefs,e.viewQuery,e.schemas,e.consts,e.id):n}(t),o=e[10].rendererFactory,s=hf(e,Ml(e,i,null,function B_(e){let n=16;return e.signals?n=4096:e.onPush&&(n=64),n}(t),r,n,null,o.createRenderer(r,t),null,null,null));e[n.index]=s}(n,t,e.data[r+t.componentOffset]),e.firstCreatePass||Qa(t,n);const o=t.initialInputs;for(let s=r;snull;function L_(e,n,t,r,i){for(let o in n){if(!n.hasOwnProperty(o))continue;const s=n[o];if(void 0===s)continue;r??={};let a,l=or.None;Array.isArray(s)?(a=s[0],l=s[1]):a=s;let c=o;if(null!==i){if(!i.hasOwnProperty(o))continue;c=i[o]}0===e?P_(r,t,c,a,l):P_(r,t,c,a)}return r}function P_(e,n,t,r,i){let o;e.hasOwnProperty(t)?(o=e[t]).push(n,r):o=e[t]=[n,r],void 0!==i&&o.push(i)}function St(e,n,t,r,i,o,s,a){const l=ft(n,t);let u,c=n.inputs;!a&&null!=c&&(u=c[r])?(gf(e,t,u,r,i),$t(n)&&function ex(e,n){const t=ht(n,e);16&t[2]||(t[2]|=64)}(t,n.index)):3&n.type&&(r=function XN(e){return"class"===e?"className":"for"===e?"htmlFor":"formaction"===e?"formAction":"innerHtml"===e?"innerHTML":"readonly"===e?"readOnly":"tabindex"===e?"tabIndex":e}(r),i=null!=s?s(i,n.value||"",r):i,o.setProperty(l,r,i))}function df(e,n,t,r){if(sm()){const i=null===r?null:{"":-1},o=function ax(e,n){const t=e.directiveRegistry;let r=null;if(t)for(let i=0;i0;){const t=e[--n];if("number"==typeof t&&t<0)return t}return 0})(s)!=a&&s.push(a),s.push(t,r,o)}}(e,n,r,hs(e,t,i.hostVars,J),i)}function Cn(e,n,t,r,i,o){const s=ft(e,n);!function ff(e,n,t,r,i,o,s){if(null==o)e.removeAttribute(n,i,t);else{const a=null==s?K(o):s(o,r||"",i);e.setAttribute(n,i,a,t)}}(n[G],s,o,e.value,t,r,i)}function gx(e,n,t,r,i,o){const s=o[n];if(null!==s)for(let a=0;a0&&(e[t-1][4]=r[4]);const o=Sa(e,10+n);!function $_(e,n){z_(e,n),n[0]=null,n[5]=null}(r[1],r);const s=o[18];null!==s&&s.detachView(o[1]),r[3]=null,r[4]=null,r[2]&=-129}return r}function ps(e,n){if(Yn(n))return;const t=n[G];t.destroyNode&&xl(e,n,t,3,null,null),function wx(e){let n=e[12];if(!n)return _f(e[1],e);for(;n;){let t=null;if(Ne(n))t=n[12];else{const r=n[10];r&&(t=r)}if(!t){for(;n&&!n[4]&&n!==e;)Ne(n)&&_f(n[1],n),n=n[3];null===n&&(n=e),Ne(n)&&_f(n[1],n),t=n&&n[4]}n=t}}(n)}function _f(e,n){if(Yn(n))return;const t=te(null);try{n[2]&=-129,n[2]|=256,n[24]&&ko(n[24]),function Ex(e,n){let t;if(null!=e&&null!=(t=e.destroyHooks))for(let r=0;r=0?r[a]():r[-a].unsubscribe(),s+=2}else t[s].call(r[t[s+1]]);null!==r&&(n[7]=null);const i=n[21];if(null!==i){n[21]=null;for(let s=0;s{jo(e.lView)},consumerOnSignalRead(){this.lView[24]=this}},Rx={...Er,consumerIsAlwaysLive:!0,kind:"template",consumerMarkedDirty:e=>{let n=Fn(e.lView);for(;n&&!ty(n[1]);)n=Fn(n);n&&qu(n)},consumerOnSignalRead(){this.lView[24]=this}};function ty(e){return 2!==e.type}function ny(e){if(null===e[23])return;let n=!0;for(;n;){let t=!1;for(const r of e[23])r.dirty&&(t=!0,null===r.zone||Zone.current===r.zone?r.run():r.zone.run(()=>r.run()));n=t&&!!(8192&e[2])}}function Ol(e,n=!0,t=0){const i=e[10].rendererFactory;i.begin?.();try{!function Fx(e,n){const t=um();try{$a(!0),If(e,n);let r=0;for(;Ba(e);){if(100===r)throw new N(103,!1);r++,If(e,1)}}finally{$a(t)}}(e,t)}catch(s){throw n&&Tl(e,s),s}finally{i.end?.()}}function iy(e,n,t,r){if(Yn(n))return;const i=n[2];nd(n);let a=!0,l=null,c=null;ty(e)?(c=function Sx(e){return e[24]??function Nx(e){const n=ey.pop()??Object.create(Ox);return n.lView=e,n}(e)}(n),l=Ir(c)):null===function iu(){return Le}()?(a=!1,c=function Ax(e){const n=e[24]??Object.create(Rx);return n.lView=e,n}(n),l=Ir(c)):n[24]&&(ko(n[24]),n[24]=null);try{nm(n),function dm(e){return Q.lFrame.bindingIndex=e}(e.bindingStartIndex),null!==t&&A_(e,n,t,2,r);const u=!(3&~i);if(u){const h=e.preOrderCheckHooks;null!==h&&qa(n,h,null)}else{const h=e.preOrderHooks;null!==h&&Wa(n,h,0,null),id(n,0)}if(function Lx(e){for(let n=cv(e);null!==n;n=uv(n)){if(!(2&n[2]))continue;const t=n[9];for(let r=0;r-1&&(gs(n,r),Sa(t,r))}this._attachedToViewContainer=!1}ps(this._lView[1],this._lView)}onDestroy(n){ja(this._lView,n)}markForCheck(){ms(this._cdRefInjectingView||this._lView,4)}markForRefresh(){qu(this._cdRefInjectingView||this._lView)}detach(){this._lView[2]&=-129}reattach(){Wu(this._lView),this._lView[2]|=128}detectChanges(){this._lView[2]|=1024,Ol(this._lView,this.notifyErrorHandler)}checkNoChanges(){}attachToViewContainerRef(){if(this._appRef)throw new N(902,!1);this._attachedToViewContainer=!0}detachFromAppRef(){this._appRef=null;const n=Rn(this._lView),t=this._lView[16];null!==t&&!n&&vf(t,this._lView),z_(this._lView[1],this._lView)}attachToAppRef(n){if(this._attachedToViewContainer)throw new N(902,!1);this._appRef=n;const t=Rn(this._lView),r=this._lView[16];null!==r&&!t&&G_(r,this._lView),Wu(this._lView)}}let Bn=(()=>class e{static __NG_ELEMENT_ID__=jx})();const Hx=Bn,Bx=class extends Hx{_declarationLView;_declarationTContainer;elementRef;constructor(n,t,r){super(),this._declarationLView=n,this._declarationTContainer=t,this.elementRef=r}get ssrId(){return this._declarationTContainer.tView?.ssrId||null}createEmbeddedView(n,t){return this.createEmbeddedViewImpl(n,t)}createEmbeddedViewImpl(n,t,r){const i=function Ji(e,n,t,r){const i=te(null);try{const o=n.tView,l=Ml(e,o,t,4096&e[2]?4096:16,null,n,null,null,r?.injector??null,r?.embeddedViewInjector??null,r?.dehydratedView??null);l[16]=e[n.index];const u=e[18];return null!==u&&(l[18]=u.createEmbeddedView(o)),Sl(o,l,t),l}finally{te(i)}}(this._declarationLView,this._declarationTContainer,n,{embeddedViewInjector:t,dehydratedView:r});return new vs(i)}};function jx(){return Al(ie(),D())}function Al(e,n){return 4&e.type?new Bx(n,e,Fi(e,n)):null}function Jr(e,n,t,r,i){let o=e.data[n];if(null===o)o=function Nf(e,n,t,r,i){const o=am(),s=Ku(),l=e.data[n]=function Kx(e,n,t,r,i,o){let s=n?n.injectorIndex:-1,a=0;return function jr(){return null!==Q.skipHydrationRootTNode}()&&(a|=128),{type:t,index:r,insertBeforeIndex:null,injectorIndex:s,directiveStart:-1,directiveEnd:-1,directiveStylingLast:-1,componentOffset:-1,propertyBindings:null,flags:a,providerIndexes:0,value:i,attrs:o,mergedAttrs:null,localNames:null,initialInputs:void 0,inputs:null,outputs:null,tView:null,next:null,prev:null,projectionNext:null,child:null,parent:n,projection:null,styles:null,stylesWithoutHost:null,residualStyles:void 0,classes:null,classesWithoutHost:null,residualClasses:void 0,classBindings:0,styleBindings:0}}(0,s?o:o&&o.parent,t,n,r,i);return function Yx(e,n,t,r){null===e.firstChild&&(e.firstChild=n),null!==t&&(r?null==t.child&&null!==n.parent&&(t.child=n):null===t.next&&(t.next=n,n.prev=t))}(e,l,o,s),l}(e,n,t,r,i),function Z0(){return Q.lFrame.inI18n}()&&(o.flags|=32);else if(64&o.type){o.type=t,o.value=r,o.attrs=i;const s=function Uo(){const e=Q.lFrame,n=e.currentTNode;return e.isParent?n:n.parent}();o.injectorIndex=null===s?-1:s.injectorIndex}return nn(o,!0),o}class P1{}class Ny{}class V1{resolveComponentFactory(n){throw Error(`No component factory found for ${$e(n)}.`)}}class Vl{static NULL=new V1}class Vf{}let on=(()=>class e{destroyNode=null;static __NG_ELEMENT_ID__=()=>function H1(){const e=D(),t=ht(ie().index,e);return(Ne(t)?t:e)[G]}()})(),B1=(()=>{class e{static \u0275prov=re({token:e,providedIn:"root",factory:()=>null})}return e})();function Bl(e,n,t){let r=t?e.styles:null,i=t?e.classes:null,o=0;if(null!==n)for(let s=0;sclass e{static __NG_ELEMENT_ID__=q1})();function q1(){return Ly(ie(),D())}const W1=wn,ky=class extends W1{_lContainer;_hostTNode;_hostLView;constructor(n,t,r){super(),this._lContainer=n,this._hostTNode=t,this._hostLView=r}get element(){return Fi(this._hostTNode,this._hostLView)}get injector(){return new Ae(this._hostTNode,this._hostLView)}get parentInjector(){const n=Ya(this._hostTNode,this._hostLView);if(ld(n)){const t=qo(n,this._hostLView),r=Go(n);return new Ae(t[1].data[r+8],t)}return new Ae(null,this._hostLView)}clear(){for(;this.length>0;)this.remove(this.length-1)}get(n){const t=Fy(this._lContainer);return null!==t&&t[n]||null}get length(){return this._lContainer.length-10}createEmbeddedView(n,t,r){let i,o;"number"==typeof r?i=r:null!=r&&(i=r.index,o=r.injector);const a=n.createEmbeddedViewImpl(t||{},o,null);return this.insertImpl(a,i,Kr(this._hostTNode,null)),a}createComponent(n,t,r,i,o){const s=n&&!function Bo(e){return"function"==typeof e}(n);let a;if(s)a=t;else{const m=t||{};a=m.index,r=m.injector,i=m.projectableNodes,o=m.environmentInjector||m.ngModuleRef}const l=s?n:new Ts(ne(n)),c=r||this.parentInjector;if(!o&&null==l.ngModule){const C=(s?c:this.parentInjector).get(tn,null);C&&(o=C)}ne(l.componentType??{});const h=l.create(c,i,null,o);return this.insertImpl(h.hostView,a,Kr(this._hostTNode,null)),h}insert(n,t){return this.insertImpl(n,t,!0)}insertImpl(n,t,r){const i=n._lView;if(function V0(e){return qe(e[3])}(i)){const a=this.indexOf(n);if(-1!==a)this.detach(a);else{const l=i[3],c=new ky(l,l[5],l[3]);c.detach(c.indexOf(n))}}const o=this._adjustIndex(t),s=this._lContainer;return function Xi(e,n,t,r=!0){const i=n[1];if(function Dx(e,n,t,r){const i=10+r,o=t.length;r>0&&(t[i-1][4]=n),rn.trim())}(n):n}}class Gf{queries;constructor(n=[]){this.queries=n}elementStart(n,t){for(let r=0;r0)r.push(s[a/2]);else{const c=o[a+1],u=n[-l];for(let d=10;dt()),this.destroyCbs=null}onDestroy(n){this.destroyCbs.push(n)}}class Jf extends hO{moduleType;constructor(n){super(),this.moduleType=n}create(n){return new Kf(this.moduleType,n,[])}}class rC extends ti{injector;componentFactoryResolver=new Ay(this);instance=null;constructor(n){super();const t=new Fr([...n.providers,{provide:ti,useValue:this},{provide:Vl,useValue:this.componentFactoryResolver}],n.parent||Ra(),n.debugName,new Set(["environment"]));this.injector=t,n.runEnvironmentInitializers&&t.resolveInjectorInitializers()}destroy(){this.injector.destroy()}onDestroy(n){this.injector.onDestroy(n)}}let mO=(()=>{class e{_injector;cachedInjectors=new Map;constructor(t){this._injector=t}getOrCreateStandaloneInjector(t){if(!t.standalone)return null;if(!this.cachedInjectors.has(t)){const r=Ru(0,t.type),i=r.length>0?function iC(e,n,t=null){return new rC({providers:e,parent:n,debugName:t,runEnvironmentInitializers:!0}).injector}([r],this._injector,`Standalone[${t.type.name}]`):null;this.cachedInjectors.set(t,i)}return this.cachedInjectors.get(t)}ngOnDestroy(){try{for(const t of this.cachedInjectors.values())null!==t&&t.destroy()}finally{this.cachedInjectors.clear()}}static \u0275prov=re({token:e,providedIn:"environment",factory:()=>new e(se(tn))})}return e})();function sn(e){return Sn(()=>{const n=sC(e),t={...n,decls:e.decls,vars:e.vars,template:e.template,consts:e.consts||null,ngContentSelectors:e.ngContentSelectors,onPush:e.changeDetection===nl.OnPush,directiveDefs:null,pipeDefs:null,dependencies:n.standalone&&e.dependencies||null,getStandaloneInjector:n.standalone?i=>i.get(mO).getOrCreateStandaloneInjector(t):null,getExternalStyles:null,signals:e.signals??!1,data:e.data||{},encapsulation:e.encapsulation||Zt.Emulated,styles:e.styles||le,_:null,schemas:e.schemas||null,tView:null,id:""};n.standalone&&Xe("NgStandalone"),aC(t);const r=e.dependencies;return t.directiveDefs=Ul(r,!1),t.pipeDefs=Ul(r,!0),t.id=function CO(e){let n=0;const r=[e.selectors,e.ngContentSelectors,e.hostVars,e.hostAttrs,"function"==typeof e.consts?"":e.consts,e.vars,e.decls,e.encapsulation,e.standalone,e.signals,e.exportAs,JSON.stringify(e.inputs),JSON.stringify(e.outputs),Object.getOwnPropertyNames(e.type.prototype),!!e.contentQueries,!!e.viewQuery];for(const o of r.join("|"))n=Math.imul(31,n)+o.charCodeAt(0)|0;return n+=2147483648,"c"+n}(t),t})}function vO(e){return ne(e)||ze(e)}function _O(e){return null!==e}function cr(e){return Sn(()=>({type:e.type,bootstrap:e.bootstrap||le,declarations:e.declarations||le,imports:e.imports||le,exports:e.exports||le,transitiveCompileScopes:null,schemas:e.schemas||null,id:e.id||null}))}function oC(e,n){if(null==e)return hn;const t={};for(const r in e)if(e.hasOwnProperty(r)){const i=e[r];let o,s,a=or.None;Array.isArray(i)?(a=i[0],o=i[1],s=i[2]??o):(o=i,s=i),n?(t[o]=a!==or.None?[r,a]:r,n[o]=s):t[o]=r}return t}function Y(e){return Sn(()=>{const n=sC(e);return aC(n),n})}function Nt(e){return{type:e.type,name:e.name,factory:null,pure:!1!==e.pure,standalone:e.standalone??!0,onDestroy:e.type.prototype.ngOnDestroy||null}}function sC(e){const n={};return{type:e.type,providersResolver:null,factory:null,hostBindings:e.hostBindings||null,hostVars:e.hostVars||0,hostAttrs:e.hostAttrs||null,contentQueries:e.contentQueries||null,declaredInputs:n,inputTransforms:null,inputConfig:e.inputs||hn,exportAs:e.exportAs||null,standalone:e.standalone??!0,signals:!0===e.signals,selectors:e.selectors||le,viewQuery:e.viewQuery||null,features:e.features||null,setInput:null,findHostDirectiveDefs:null,hostDirectives:null,inputs:oC(e.inputs,n),outputs:oC(e.outputs),debugInfo:null}}function aC(e){e.features?.forEach(n=>n(e))}function Ul(e,n){if(!e)return null;const t=n?nt:vO;return()=>("function"==typeof e?e():e).map(r=>t(r)).filter(_O)}function ue(e){let n=function lC(e){return Object.getPrototypeOf(e.prototype).constructor}(e.type),t=!0;const r=[e];for(;n;){let i;if(zt(e))i=n.\u0275cmp||n.\u0275dir;else{if(n.\u0275cmp)throw new N(903,!1);i=n.\u0275dir}if(i){if(t){r.push(i);const s=e;s.inputs=$l(e.inputs),s.inputTransforms=$l(e.inputTransforms),s.declaredInputs=$l(e.declaredInputs),s.outputs=$l(e.outputs);const a=i.hostBindings;a&&IO(e,a);const l=i.viewQuery,c=i.contentQueries;if(l&&bO(e,l),c&&EO(e,c),wO(e,i),jM(e.outputs,i.outputs),zt(i)&&i.data.animation){const u=e.data;u.animation=(u.animation||[]).concat(i.data.animation)}}const o=i.features;if(o)for(let s=0;s=0;r--){const i=e[r];i.hostVars=n+=i.hostVars,i.hostAttrs=ki(i.hostAttrs,t=ki(t,i.hostAttrs))}}(r)}function wO(e,n){for(const t in n.inputs){if(!n.inputs.hasOwnProperty(t)||e.inputs.hasOwnProperty(t))continue;const r=n.inputs[t];if(void 0!==r&&(e.inputs[t]=r,e.declaredInputs[t]=n.declaredInputs[t],null!==n.inputTransforms)){const i=Array.isArray(r)?r[0]:r;if(!n.inputTransforms.hasOwnProperty(i))continue;e.inputTransforms??={},e.inputTransforms[i]=n.inputTransforms[i]}}}function $l(e){return e===hn?{}:e===le?[]:e}function bO(e,n){const t=e.viewQuery;e.viewQuery=t?(r,i)=>{n(r,i),t(r,i)}:n}function EO(e,n){const t=e.contentQueries;e.contentQueries=t?(r,i,o)=>{n(r,i,o),t(r,i,o)}:n}function IO(e,n){const t=e.hostBindings;e.hostBindings=t?(r,i)=>{n(r,i),t(r,i)}:n}function zl(e){return!!eh(e)&&(Array.isArray(e)||!(e instanceof Map)&&Symbol.iterator in e)}function eh(e){return null!==e&&("function"==typeof e||"object"==typeof e)}function Dn(e,n,t){return e[n]=t}function Re(e,n,t){return!Object.is(e[n],t)&&(e[n]=t,!0)}function ni(e,n,t,r){const i=Re(e,n,t);return Re(e,n+1,r)||i}function V(e,n,t,r,i,o,s,a){const l=D(),c=Z();return function xs(e,n,t,r,i,o,s,a,l,c){const u=t+k,d=n.firstCreatePass?function FO(e,n,t,r,i,o,s,a,l){const c=n.consts,u=Jr(n,e,4,s||null,a||null);df(n,t,u,qt(c,l)),Ga(n,u);const d=u.tView=uf(2,u,r,i,o,n.directiveRegistry,n.pipeRegistry,null,n.schemas,c,null);return null!==n.queries&&(n.queries.template(n,u),d.queries=n.queries.embeddedTView(u)),u}(u,n,e,r,i,o,s,a,l):n.data[u];nn(d,!1);const g=hC(n,e,d,t);$o()&&Nl(n,e,g,d),vt(g,e);const h=j_(g,e,g,d);return e[u]=h,hf(e,h),Va(d)&&lf(n,e,d),null!=l&&cf(e,d,c),d}(l,c,e,n,t,r,i,qt(c.consts,o),s,a),V}let hC=function gC(e,n,t,r){return mn(!0),n[G].createComment("")};const TC=new R(""),Ql=new R("");let lh,sh=(()=>{class e{_ngZone;registry;_isZoneStable=!0;_callbacks=[];taskTrackingZone=null;constructor(t,r,i){this._ngZone=t,this.registry=r,lh||(function kA(e){lh=e}(i),i.addToWindow(r)),this._watchAngularEvents(),t.run(()=>{this.taskTrackingZone=typeof Zone>"u"?null:Zone.current.get("TaskTrackingZone")})}_watchAngularEvents(){this._ngZone.onUnstable.subscribe({next:()=>{this._isZoneStable=!1}}),this._ngZone.runOutsideAngular(()=>{this._ngZone.onStable.subscribe({next:()=>{de.assertNotInAngularZone(),queueMicrotask(()=>{this._isZoneStable=!0,this._runCallbacksIfReady()})}})})}isStable(){return this._isZoneStable&&!this._ngZone.hasPendingMacrotasks}_runCallbacksIfReady(){if(this.isStable())queueMicrotask(()=>{for(;0!==this._callbacks.length;){let t=this._callbacks.pop();clearTimeout(t.timeoutId),t.doneCb()}});else{let t=this.getPendingTasks();this._callbacks=this._callbacks.filter(r=>!r.updateCb||!r.updateCb(t)||(clearTimeout(r.timeoutId),!1))}}getPendingTasks(){return this.taskTrackingZone?this.taskTrackingZone.macroTasks.map(t=>({source:t.source,creationLocation:t.creationLocation,data:t.data})):[]}addCallback(t,r,i){let o=-1;r&&r>0&&(o=setTimeout(()=>{this._callbacks=this._callbacks.filter(s=>s.timeoutId!==o),t()},r)),this._callbacks.push({doneCb:t,timeoutId:o,updateCb:i})}whenStable(t,r,i){if(i&&!this.taskTrackingZone)throw new Error('Task tracking zone is required when passing an update callback to whenStable(). Is "zone.js/plugins/task-tracking" loaded?');this.addCallback(t,r,i),this._runCallbacksIfReady()}registerApplication(t){this.registry.registerApplication(t,this)}unregisterApplication(t){this.registry.unregisterApplication(t)}findProviders(t,r,i){return[]}static \u0275fac=function(r){return new(r||e)(se(de),se(ah),se(Ql))};static \u0275prov=re({token:e,factory:e.\u0275fac})}return e})(),ah=(()=>{class e{_applications=new Map;registerApplication(t,r){this._applications.set(t,r)}unregisterApplication(t){this._applications.delete(t)}unregisterAllApplications(){this._applications.clear()}getTestability(t){return this._applications.get(t)||null}getAllTestabilities(){return Array.from(this._applications.values())}getAllRootElements(){return Array.from(this._applications.keys())}findTestabilityInTree(t,r=!0){return lh?.findTestabilityInTree(this,t,r)??null}static \u0275fac=function(r){return new(r||e)};static \u0275prov=re({token:e,factory:e.\u0275fac,providedIn:"platform"})}return e})();function Yl(e){return!!e&&"function"==typeof e.then}function SC(e){return!!e&&"function"==typeof e.subscribe}const NC=new R("");let xC=(()=>{class e{resolve;reject;initialized=!1;done=!1;donePromise=new Promise((t,r)=>{this.resolve=t,this.reject=r});appInits=A(NC,{optional:!0})??[];injector=A(We);constructor(){}runInitializers(){if(this.initialized)return;const t=[];for(const i of this.appInits){const o=jp(this.injector,i);if(Yl(o))t.push(o);else if(SC(o)){const s=new Promise((a,l)=>{o.subscribe({complete:a,error:l})});t.push(s)}}const r=()=>{this.done=!0,this.resolve()};Promise.all(t).then(()=>{r()}).catch(i=>{this.reject(i)}),0===t.length&&r(),this.initialized=!0}static \u0275fac=function(r){return new(r||e)};static \u0275prov=re({token:e,factory:e.\u0275fac,providedIn:"root"})}return e})(),ch=(()=>{class e{static \u0275prov=re({token:e,providedIn:"root",factory:()=>new OC})}return e})();class OC{queuedEffectCount=0;queues=new Map;schedule(n){this.enqueue(n)}remove(n){const r=this.queues.get(n.zone);r.has(n)&&(r.delete(n),this.queuedEffectCount--)}enqueue(n){const t=n.zone;this.queues.has(t)||this.queues.set(t,new Set);const r=this.queues.get(t);r.has(n)||(this.queuedEffectCount++,r.add(n))}flush(){for(;this.queuedEffectCount>0;)for(const[n,t]of this.queues)null===n?this.flushQueue(t):n.run(()=>this.flushQueue(t))}flushQueue(n){for(const t of n)n.delete(t),this.queuedEffectCount--,t.run()}}const Kl=new R("");function RC(e,n){return Array.isArray(n)?n.reduce(RC,e):{...e,...n}}let Yt=(()=>{class e{_runningTick=!1;_destroyed=!1;_destroyListeners=[];_views=[];internalErrorHandler=A(LT);afterRenderManager=A(Ld);zonelessEnabled=A(Zo);rootEffectScheduler=A(ch);dirtyFlags=0;deferredDirtyFlags=0;tracingSnapshot=null;externalTestViews=new Set;afterTick=new fn;get allViews(){return[...this.externalTestViews.keys(),...this._views]}get destroyed(){return this._destroyed}componentTypes=[];components=[];isStable=A(Xn).hasPendingTasks.pipe(pu(t=>!t));constructor(){A(Hi,{optional:!0})}whenStable(){let t;return new Promise(r=>{t=this.isStable.subscribe({next:i=>{i&&r()}})}).finally(()=>{t.unsubscribe()})}_injector=A(tn);_rendererFactory=null;get injector(){return this._injector}bootstrap(t,r){const i=t instanceof Ny;if(!this._injector.get(xC).done)throw!i&&function Ar(e){const n=ne(e)||ze(e)||nt(e);return null!==n&&n.standalone}(t),new N(405,!1);let s;s=i?t:this._injector.get(Vl).resolveComponentFactory(t),this.componentTypes.push(s.componentType);const a=function FA(e){return e.isBoundToModule}(s)?void 0:this._injector.get(ti),c=s.create(We.NULL,[],r||s.selector,a),u=c.location.nativeElement,d=c.injector.get(TC,null);return d?.registerApplication(u),c.onDestroy(()=>{this.detachView(c.hostView),Jl(this.components,c),d?.unregisterApplication(u)}),this._loadComponent(c),c}tick(){this.zonelessEnabled||(this.dirtyFlags|=1),this._tick()}_tick=()=>{if(null!==this.tracingSnapshot){const r=this.tracingSnapshot;return this.tracingSnapshot=null,r.run(Fd.CHANGE_DETECTION,this._tick),void r.dispose()}if(this._runningTick)throw new N(101,!1);const t=te(null);try{this._runningTick=!0,this.synchronize()}catch(r){this.internalErrorHandler(r)}finally{this._runningTick=!1,te(t),this.afterTick.next()}};synchronize(){null===this._rendererFactory&&!this._injector.destroyed&&(this._rendererFactory=this._injector.get(Vf,null,{optional:!0})),this.dirtyFlags|=this.deferredDirtyFlags,this.deferredDirtyFlags=0;let t=0;for(;0!==this.dirtyFlags&&t++<10;)this.synchronizeOnce()}synchronizeOnce(){if(this.dirtyFlags|=this.deferredDirtyFlags,this.deferredDirtyFlags=0,16&this.dirtyFlags&&(this.dirtyFlags&=-17,this.rootEffectScheduler.flush()),7&this.dirtyFlags){const t=!!(1&this.dirtyFlags);this.dirtyFlags&=-8,this.dirtyFlags|=8;for(let{_lView:r,notifyErrorHandler:i}of this.allViews)VA(r,i,t,this.zonelessEnabled);if(this.dirtyFlags&=-5,this.syncDirtyFlagsWithViews(),23&this.dirtyFlags)return}else this._rendererFactory?.begin?.(),this._rendererFactory?.end?.();8&this.dirtyFlags&&(this.dirtyFlags&=-9,this.afterRenderManager.execute()),this.syncDirtyFlagsWithViews()}syncDirtyFlagsWithViews(){this.allViews.some(({_lView:t})=>Ba(t))?this.dirtyFlags|=2:this.dirtyFlags&=-8}attachView(t){const r=t;this._views.push(r),r.attachToAppRef(this)}detachView(t){const r=t;Jl(this._views,r),r.detachFromAppRef()}_loadComponent(t){this.attachView(t.hostView),this.tick(),this.components.push(t),this._injector.get(Kl,[]).forEach(i=>i(t))}ngOnDestroy(){if(!this._destroyed)try{this._destroyListeners.forEach(t=>t()),this._views.slice().forEach(t=>t.destroy())}finally{this._destroyed=!0,this._views=[],this._destroyListeners=[]}}onDestroy(t){return this._destroyListeners.push(t),()=>Jl(this._destroyListeners,t)}destroy(){if(this._destroyed)throw new N(406,!1);const t=this._injector;t.destroy&&!t.destroyed&&t.destroy()}get viewCount(){return this._views.length}static \u0275fac=function(r){return new(r||e)};static \u0275prov=re({token:e,factory:e.\u0275fac,providedIn:"root"})}return e})();function Jl(e,n){const t=e.indexOf(n);t>-1&&e.splice(t,1)}function VA(e,n,t,r){(t||Ba(e))&&Ol(e,n,t&&!r?0:1)}function _t(e,n,t,r){const i=D();return Re(i,Wt(),n)&&(Z(),Cn(me(),i,e,n,t,r)),_t}function ao(e,n,t,r){return Re(e,Wt(),t)?n+K(t)+r:J}function Xl(e,n){return e<<17|n<<2}function hr(e){return e>>17&32767}function hh(e){return 2|e}function ii(e){return(131068&e)>>2}function gh(e,n){return-131069&e|n<<2}function ph(e){return 1|e}function ZC(e,n,t,r){const i=e[t+1],o=null===n;let s=r?hr(i):ii(i),a=!1;for(;0!==s&&(!1===a||o);){const c=e[s+1];DR(e[s],n)&&(a=!0,e[s+1]=r?ph(c):hh(c)),s=r?hr(c):ii(c)}a&&(e[t+1]=r?hh(i):ph(i))}function DR(e,n){return null===e||null==n||(Array.isArray(e)?e[1]:e)===n||!(!Array.isArray(e)||"string"!=typeof n)&&bi(e,n)>=0}const Ze={textEnd:0,key:0,keyEnd:0,value:0,valueEnd:0};function QC(e){return e.substring(Ze.key,Ze.keyEnd)}function YC(e,n){const t=Ze.textEnd;return t===n?-1:(n=Ze.keyEnd=function MR(e,n,t){for(;n32;)n++;return n}(e,Ze.key=n,t),mo(e,n,t))}function mo(e,n,t){for(;n=0;t=YC(n,t))Lt(e,QC(n),!0)}function an(e,n,t,r){const i=D(),o=Z(),s=Pn(2);o.firstUpdatePass&&nw(o,e,s,r),n!==J&&Re(i,s,n)&&iw(o,o.data[rt()],i,i[G],e,i[s+1]=function VR(e,n){return null==e||""===e||("string"==typeof n?e+=n:"object"==typeof e&&(e=$e(rr(e)))),e}(n,t),r,s)}function tw(e,n){return n>=e.expandoStartIndex}function nw(e,n,t,r){const i=e.data;if(null===i[t+1]){const o=i[rt()],s=tw(e,t);sw(o,r)&&null===n&&!s&&(n=!1),n=function OR(e,n,t,r){const i=function ed(e){const n=Q.lFrame.currentDirectiveIndex;return-1===n?null:e[n]}(e);let o=r?n.residualClasses:n.residualStyles;if(null===i)0===(r?n.classBindings:n.styleBindings)&&(t=Rs(t=vh(null,e,n,t,r),n.attrs,r),o=null);else{const s=n.directiveStylingLast;if(-1===s||e[s]!==i)if(t=vh(i,e,n,t,r),null===o){let l=function AR(e,n,t){const r=t?n.classBindings:n.styleBindings;if(0!==ii(r))return e[hr(r)]}(e,n,r);void 0!==l&&Array.isArray(l)&&(l=vh(null,e,n,l[1],r),l=Rs(l,n.attrs,r),function RR(e,n,t,r){e[hr(t?n.classBindings:n.styleBindings)]=r}(e,n,r,l))}else o=function kR(e,n,t){let r;const i=n.directiveEnd;for(let o=1+n.directiveStylingLast;o0)&&(c=!0)):u=t,i)if(0!==l){const g=hr(e[a+1]);e[r+1]=Xl(g,a),0!==g&&(e[g+1]=gh(e[g+1],r)),e[a+1]=function _R(e,n){return 131071&e|n<<17}(e[a+1],r)}else e[r+1]=Xl(a,0),0!==a&&(e[a+1]=gh(e[a+1],r)),a=r;else e[r+1]=Xl(l,0),0===a?a=r:e[l+1]=gh(e[l+1],r),l=r;c&&(e[r+1]=hh(e[r+1])),ZC(e,u,r,!0),ZC(e,u,r,!1),function wR(e,n,t,r,i){const o=i?e.residualClasses:e.residualStyles;null!=o&&"string"==typeof n&&bi(o,n)>=0&&(t[r+1]=ph(t[r+1]))}(n,u,e,r,o),s=Xl(a,l),o?n.classBindings=s:n.styleBindings=s}(i,o,n,t,s,r)}}function vh(e,n,t,r,i){let o=null;const s=t.directiveEnd;let a=t.directiveStylingLast;for(-1===a?a=t.directiveStart:a++;a0;){const l=e[i],c=Array.isArray(l),u=c?l[1]:l,d=null===u;let g=t[i+1];g===J&&(g=d?le:void 0);let h=d?Ou(g,r):u===r?g:void 0;if(c&&!tc(h)&&(h=Ou(l,r)),tc(h)&&(a=h,s))return a;const m=e[i+1];i=s?hr(m):ii(m)}if(null!==n){let l=o?n.residualClasses:n.residualStyles;null!=l&&(a=Ou(l,r))}return a}function tc(e){return void 0!==e}function sw(e,n){return!!(e.flags&(n?8:16))}function Kt(e,n,t){!function ln(e,n,t,r){const i=Z(),o=Pn(2);i.firstUpdatePass&&nw(i,null,o,r);const s=D();if(t!==J&&Re(s,o,t)){const a=i.data[rt()];if(sw(a,r)&&!tw(i,o)){let l=r?a.classesWithoutHost:a.stylesWithoutHost;null!==l&&(t=vu(l,t||"")),mh(i,a,s,t,r)}else!function PR(e,n,t,r,i,o,s,a){i===J&&(i=le);let l=0,c=0,u=0(mn(!0),Il(r,i,function ym(){return Q.lFrame.currentNamespace}()));function X(e,n,t){const r=D(),i=Z(),o=e+k,s=i.firstCreatePass?function ck(e,n,t,r,i){const o=n.consts,s=qt(o,r),a=Jr(n,e,8,"ng-container",s);return null!==s&&Bl(a,s,!0),df(n,t,a,qt(o,i)),null!==n.queries&&n.queries.elementStart(n,a),a}(o,i,r,n,t):i.data[o];nn(s,!0);const a=fw(i,r,s,e);return r[o]=a,$o()&&Nl(i,r,a,s),vt(a,r),Va(s)&&(lf(i,r,s),Qd(i,s,r)),null!=t&&cf(r,s),X}function ee(){let e=ie();const n=Z();return Ku()?Ju():(e=e.parent,nn(e,!1)),n.firstCreatePass&&(Ga(n,e),Uu(e)&&n.queries.elementEnd(e)),ee}let fw=(e,n,t,r)=>(mn(!0),af(n[G],""));function ge(){return D()}const rc="en-US";let vw=rc;function q(e,n,t,r){const i=D(),o=Z(),s=ie();return bh(o,i,i[G],s,e,n,r),q}function bh(e,n,t,r,i,o,s){const a=Va(r),c=e.firstCreatePass&&om(e),u=n[8],d=im(n);let g=!0;if(3&r.type||s){const C=ft(r,n),E=s?s(C):C,I=d.length,w=s?z=>s(ae(z[r.index])):r.index;let L=null;if(!s&&a&&(L=function nF(e,n,t,r){const i=e.cleanup;if(null!=i)for(let o=0;ol?a[l]:null}"string"==typeof s&&(o+=2)}return null}(e,n,i,r.index)),null!==L)(L.__ngLastListenerFn__||L).__ngNextListenerFn__=o,L.__ngLastListenerFn__=o,g=!1;else{o=Hw(r,n,u,o);const z=t.listen(E,i,o);d.push(o,z),c&&c.push(i,w,I,I+1)}}else o=Hw(r,n,u,o);const h=r.outputs;let m;if(g&&null!==h&&(m=h[i])){const C=m.length;if(C)for(let E=0;E0;)n=n[14],e--;return n}(e,Q.lFrame.contextLView))[8]}(e)}function In(e,n,t){return Eh(e,"",n,"",t),In}function Eh(e,n,t,r,i){const o=D(),s=ao(o,n,t,r);return s!==J&&St(Z(),me(),o,e,s,o[G],i,!1),Eh}function Zw(e,n,t,r){!function zy(e,n,t,r){const i=Z();if(i.firstCreatePass){const o=ie();Gy(i,new By(n,t,r),o.index),function rO(e,n){const t=e.contentQueries||(e.contentQueries=[]);n!==(t.length?t[t.length-1]:-1)&&t.push(e.queries.length-1,n)}(i,e),!(2&~t)&&(i.staticContentQueries=!0)}return Uy(i,D(),t)}(e,n,t,r)}function Vt(e,n,t){!function $y(e,n,t){const r=Z();return r.firstCreatePass&&(Gy(r,new By(e,n,t),-1),!(2&~n)&&(r.staticViewQueries=!0)),Uy(r,D(),n)}(e,n,t)}function Ot(e){const n=D(),t=Z(),r=td();za(r+1);const i=Qf(t,r);if(e.dirty&&function P0(e){return!(4&~e[2])}(n)===!(2&~i.metadata.flags)){if(null===i.matches)e.reset([]);else{const o=qy(n,r);e.reset(o,Km),e.notifyOnChanges()}return!0}return!1}function At(){return function Zf(e,n){return e[18].queries[n].queryList}(D(),td())}function b(e,n=""){const t=D(),r=Z(),i=e+k,o=r.firstCreatePass?Jr(r,i,1,n,null):r.data[i],s=iD(r,t,o,n,e);t[i]=s,$o()&&Nl(r,t,s,o),nn(o,!1)}let iD=(e,n,t,r,i)=>(mn(!0),function sf(e,n){return e.createText(n)}(n[G],r));function O(e){return U("",e,""),O}function U(e,n,t){const r=D(),i=ao(r,e,n,t);return i!==J&&function Un(e,n,t){const r=Ai(n,e);!function I_(e,n,t){e.setValue(n,t)}(e[G],r,t)}(r,rt(),i),U}function Qe(e,n,t){ev(n)&&(n=n());const r=D();return Re(r,Wt(),n)&&St(Z(),me(),r,e,n,r[G],t,!1),Qe}function be(e,n){const t=ev(e);return t&&e.set(n),t}function tt(e,n){const t=D(),r=Z(),i=ie();return bh(r,t,t[G],i,e,n),tt}function Mh(e,n,t,r,i){if(e=W(e),Array.isArray(e))for(let o=0;o>20;if(kr(e)||!e.multi){const h=new zo(c,i,T),m=Sh(l,n,i?u:u+g,d);-1===m?(dd(Qa(a,s),o,l),Th(o,e,n.length),n.push(l),a.directiveStart++,a.directiveEnd++,i&&(a.providerIndexes+=1048576),t.push(h),s.push(h)):(t[m]=h,s[m]=h)}else{const h=Sh(l,n,u+g,d),m=Sh(l,n,u,u+g),E=m>=0&&t[m];if(i&&!E||!i&&!(h>=0&&t[h])){dd(Qa(a,s),o,l);const I=function SF(e,n,t,r,i){const o=new zo(e,t,T);return o.multi=[],o.index=n,o.componentProviders=0,pD(o,i,r&&!t),o}(i?TF:MF,t.length,i,r,c);!i&&E&&(t[m].providerFactory=I),Th(o,e,n.length,0),n.push(l),a.directiveStart++,a.directiveEnd++,i&&(a.providerIndexes+=1048576),t.push(I),s.push(I)}else Th(o,e,h>-1?h:m,pD(t[i?m:h],c,!i&&r));!i&&r&&E&&t[m].componentProviders++}}}function Th(e,n,t,r){const i=kr(n),o=function h0(e){return!!e.useClass}(n);if(i||o){const l=(o?W(n.useClass):n).prototype.ngOnDestroy;if(l){const c=e.destroyHooks||(e.destroyHooks=[]);if(!i&&n.multi){const u=c.indexOf(t);-1===u?c.push(t,[r,l]):c[u+1].push(r,l)}else c.push(t,l)}}}function pD(e,n,t){return t&&e.componentProviders++,e.multi.push(n)-1}function Sh(e,n,t,r){for(let i=t;i{t.providersResolver=(r,i)=>function IF(e,n,t){const r=Z();if(r.firstCreatePass){const i=zt(e);Mh(t,r.data,r.blueprint,i,!0),Mh(n,r.data,r.blueprint,i,!1)}}(r,i?i(e):e,n)}}function _o(e,n,t,r){return function vD(e,n,t,r,i,o){const s=n+t;return Re(e,s,i)?Dn(e,s+1,o?r.call(o,i):r(i)):Hs(e,s+1)}(D(),gt(),e,n,t,r)}function xh(e,n,t,r,i){return function _D(e,n,t,r,i,o,s){const a=n+t;return ni(e,a,i,o)?Dn(e,a+2,s?r.call(s,i,o):r(i,o)):Hs(e,a+2)}(D(),gt(),e,n,t,r,i)}function Fe(e,n,t,r,i,o){return yD(D(),gt(),e,n,t,r,i,o)}function Hs(e,n){const t=e[n];return t===J?void 0:t}function yD(e,n,t,r,i,o,s,a){const l=n+t;return function Gl(e,n,t,r,i){const o=ni(e,n,t,r);return Re(e,n+2,i)||o}(e,l,i,o,s)?Dn(e,l+3,a?r.call(a,i,o,s):r(i,o,s)):Hs(e,l+3)}let wL=(()=>{class e{zone=A(de);changeDetectionScheduler=A(Vn);applicationRef=A(Yt);_onMicrotaskEmptySubscription;initialize(){this._onMicrotaskEmptySubscription||(this._onMicrotaskEmptySubscription=this.zone.onMicrotaskEmpty.subscribe({next:()=>{this.changeDetectionScheduler.runningTick||this.zone.run(()=>{this.applicationRef.tick()})}}))}ngOnDestroy(){this._onMicrotaskEmptySubscription?.unsubscribe()}static \u0275fac=function(r){return new(r||e)};static \u0275prov=re({token:e,factory:e.\u0275fac,providedIn:"root"})}return e})();function Fh({ngZoneFactory:e,ignoreChangesOutsideZone:n,scheduleInRootZone:t}){return e??=()=>new de({...Lh(),scheduleInRootZone:t}),[{provide:de,useFactory:e},{provide:en,multi:!0,useFactory:()=>{const r=A(wL,{optional:!0});return()=>r.initialize()}},{provide:en,multi:!0,useFactory:()=>{const r=A(bL);return()=>{r.initialize()}}},!0===n?{provide:zm,useValue:!0}:[],{provide:gd,useValue:t??Um}]}function Lh(e){return{enableLongStackTrace:!1,shouldCoalesceEventChangeDetection:e?.eventCoalescing??!1,shouldCoalesceRunChangeDetection:e?.runCoalescing??!1}}let bL=(()=>{class e{subscription=new Rt;initialized=!1;zone=A(de);pendingTasks=A(Xn);initialize(){if(this.initialized)return;this.initialized=!0;let t=null;!this.zone.isStable&&!this.zone.hasPendingMacrotasks&&!this.zone.hasPendingMicrotasks&&(t=this.pendingTasks.add()),this.zone.runOutsideAngular(()=>{this.subscription.add(this.zone.onStable.subscribe(()=>{de.assertNotInAngularZone(),queueMicrotask(()=>{null!==t&&!this.zone.hasPendingMacrotasks&&!this.zone.hasPendingMicrotasks&&(this.pendingTasks.remove(t),t=null)})}))}),this.subscription.add(this.zone.onUnstable.subscribe(()=>{de.assertInAngularZone(),t??=this.pendingTasks.add()}))}ngOnDestroy(){this.subscription.unsubscribe()}static \u0275fac=function(r){return new(r||e)};static \u0275prov=re({token:e,factory:e.\u0275fac,providedIn:"root"})}return e})(),Us=(()=>{class e{appRef=A(Yt);taskService=A(Xn);ngZone=A(de);zonelessEnabled=A(Zo);tracing=A(Hi,{optional:!0});disableScheduling=A(zm,{optional:!0})??!1;zoneIsDefined=typeof Zone<"u"&&!!Zone.root.run;schedulerTickApplyArgs=[{data:{__scheduler_tick__:!0}}];subscriptions=new Rt;angularZoneId=this.zoneIsDefined?this.ngZone._inner?.get(el):null;scheduleInRootZone=!this.zonelessEnabled&&this.zoneIsDefined&&(A(gd,{optional:!0})??!1);cancelScheduledCallback=null;useMicrotaskScheduler=!1;runningTick=!1;pendingRenderTaskId=null;constructor(){this.subscriptions.add(this.appRef.afterTick.subscribe(()=>{this.runningTick||this.cleanup()})),this.subscriptions.add(this.ngZone.onUnstable.subscribe(()=>{this.runningTick||this.cleanup()})),this.disableScheduling||=!this.zonelessEnabled&&(this.ngZone instanceof _d||!this.zoneIsDefined)}notify(t){if(!this.zonelessEnabled&&5===t)return;let r=!1;switch(t){case 0:this.appRef.dirtyFlags|=2;break;case 3:case 2:case 4:case 5:case 1:this.appRef.dirtyFlags|=4;break;case 8:this.appRef.deferredDirtyFlags|=8;break;case 6:case 14:this.appRef.dirtyFlags|=2,r=!0;break;case 13:this.appRef.dirtyFlags|=16,r=!0;break;case 12:r=!0;break;default:this.appRef.dirtyFlags|=8}if(this.appRef.tracingSnapshot=this.tracing?.snapshot(this.appRef.tracingSnapshot)??null,!this.shouldScheduleTick(r))return;const i=this.useMicrotaskScheduler?qm:Gm;this.pendingRenderTaskId=this.taskService.add(),this.cancelScheduledCallback=this.scheduleInRootZone?Zone.root.run(()=>i(()=>this.tick())):this.ngZone.runOutsideAngular(()=>i(()=>this.tick()))}shouldScheduleTick(t){return!(this.disableScheduling&&!t||this.appRef.destroyed||null!==this.pendingRenderTaskId||this.runningTick||this.appRef._runningTick||!this.zonelessEnabled&&this.zoneIsDefined&&Zone.current.get(el+this.angularZoneId))}tick(){if(this.runningTick||this.appRef.destroyed)return;if(0===this.appRef.dirtyFlags)return void this.cleanup();!this.zonelessEnabled&&7&this.appRef.dirtyFlags&&(this.appRef.dirtyFlags|=1);const t=this.taskService.add();try{this.ngZone.run(()=>{this.runningTick=!0,this.appRef._tick()},void 0,this.schedulerTickApplyArgs)}catch(r){throw this.taskService.remove(t),r}finally{this.cleanup()}this.useMicrotaskScheduler=!0,qm(()=>{this.useMicrotaskScheduler=!1,this.taskService.remove(t)})}ngOnDestroy(){this.subscriptions.unsubscribe(),this.cleanup()}cleanup(){if(this.runningTick=!1,this.cancelScheduledCallback?.(),this.cancelScheduledCallback=null,null!==this.pendingRenderTaskId){const t=this.pendingRenderTaskId;this.pendingRenderTaskId=null,this.taskService.remove(t)}}static \u0275fac=function(r){return new(r||e)};static \u0275prov=re({token:e,factory:e.\u0275fac,providedIn:"root"})}return e})();const gr=new R("",{providedIn:"root",factory:()=>A(gr,oe.Optional|oe.SkipSelf)||function EL(){return typeof $localize<"u"&&$localize.locale||rc}()}),dc=new R(""),xL=new R("");function $s(e){return!e.moduleRef}let zD=(()=>{class e{_injector;_modules=[];_destroyListeners=[];_destroyed=!1;constructor(t){this._injector=t}bootstrapModuleFactory(t,r){const i=r?.scheduleInRootZone,s=r?.ignoreChangesOutsideZone,a=[Fh({ngZoneFactory:()=>function FT(e="zone.js",n){return"noop"===e?new _d:"zone.js"===e?new de(n):e}(r?.ngZone,{...Lh({eventCoalescing:r?.ngZoneEventCoalescing,runCoalescing:r?.ngZoneRunCoalescing}),scheduleInRootZone:i}),ignoreChangesOutsideZone:s}),{provide:Vn,useExisting:Us}],l=function pO(e,n,t){return new Kf(e,n,t,!1)}(t.moduleType,this.injector,a);return function $D(e){const n=$s(e)?e.r3Injector:e.moduleRef.injector,t=n.get(de);return t.run(()=>{$s(e)?e.r3Injector.resolveInjectorInitializers():e.moduleRef.resolveInjectorInitializers();const r=n.get(_n,null);let i;if(t.runOutsideAngular(()=>{i=t.onError.subscribe({next:o=>{r.handleError(o)}})}),$s(e)){const o=()=>n.destroy(),s=e.platformInjector.get(dc);s.add(o),n.onDestroy(()=>{i.unsubscribe(),s.delete(o)})}else{const o=()=>e.moduleRef.destroy(),s=e.platformInjector.get(dc);s.add(o),e.moduleRef.onDestroy(()=>{Jl(e.allPlatformModules,e.moduleRef),i.unsubscribe(),s.delete(o)})}return function PA(e,n,t){try{const r=t();return Yl(r)?r.catch(i=>{throw n.runOutsideAngular(()=>e.handleError(i)),i}):r}catch(r){throw n.runOutsideAngular(()=>e.handleError(r)),r}}(r,t,()=>{const o=n.get(xC);return o.runInitializers(),o.donePromise.then(()=>{if(function _k(e){"string"==typeof e&&(vw=e.toLowerCase().replace(/_/g,"-"))}(n.get(gr,rc)||rc),!n.get(xL,!0))return $s(e)?n.get(Yt):(e.allPlatformModules.push(e.moduleRef),e.moduleRef);if($s(e)){const l=n.get(Yt);return void 0!==e.rootComponent&&l.bootstrap(e.rootComponent),l}return function OL(e,n){const t=e.injector.get(Yt);if(e._bootstrapComponents.length>0)e._bootstrapComponents.forEach(r=>t.bootstrap(r));else{if(!e.instance.ngDoBootstrap)throw new N(-403,!1);e.instance.ngDoBootstrap(t)}n.push(e)}(e.moduleRef,e.allPlatformModules),e.moduleRef})})})}({moduleRef:l,allPlatformModules:this._modules,platformInjector:this.injector})}bootstrapModule(t,r=[]){const i=RC({},r);return function CL(e,n,t){const r=new Jf(t);return Promise.resolve(r)}(0,0,t).then(o=>this.bootstrapModuleFactory(o,i))}onDestroy(t){this._destroyListeners.push(t)}get injector(){return this._injector}destroy(){if(this._destroyed)throw new N(404,!1);this._modules.slice().forEach(r=>r.destroy()),this._destroyListeners.forEach(r=>r());const t=this._injector.get(dc,null);t&&(t.forEach(r=>r()),t.clear()),this._destroyed=!0}get destroyed(){return this._destroyed}static \u0275fac=function(r){return new(r||e)(se(We))};static \u0275prov=re({token:e,factory:e.\u0275fac,providedIn:"platform"})}return e})(),pr=null;const GD=new R("");function qD(e,n,t=[]){const r=`Platform: ${n}`,i=new R(r);return(o=[])=>{let s=Vh();if(!s||s.injector.get(GD,!1)){const a=[...t,...o,{provide:i,useValue:!0}];e?e(a):function AL(e){if(pr&&!pr.get(GD,!1))throw new N(400,!1);(function AC(){!function yM(e){sp=e}(()=>{throw new N(600,!1)})})(),pr=e;const n=e.get(zD);(function ZD(e){const n=e.get(Ed,null);jp(e,()=>{n?.forEach(t=>t())})})(e)}(function WD(e=[],n){return We.create({name:n,providers:[{provide:Lu,useValue:"platform"},{provide:dc,useValue:new Set([()=>pr=null])},...e]})}(a,r))}return function RL(){const n=Vh();if(!n)throw new N(401,!1);return n}()}}function Vh(){return pr?.get(zD)??null}let si=(()=>class e{static __NG_ELEMENT_ID__=FL})();function FL(e){return function LL(e,n,t){if($t(e)&&!t){const r=ht(e.index,n);return new vs(r,r)}return 175&e.type?new vs(n[15],n):null}(ie(),D(),!(16&~e))}class XD{constructor(){}supports(n){return zl(n)}create(n){return new jL(n)}}const BL=(e,n)=>n;class jL{length=0;collection;_linkedRecords=null;_unlinkedRecords=null;_previousItHead=null;_itHead=null;_itTail=null;_additionsHead=null;_additionsTail=null;_movesHead=null;_movesTail=null;_removalsHead=null;_removalsTail=null;_identityChangesHead=null;_identityChangesTail=null;_trackByFn;constructor(n){this._trackByFn=n||BL}forEachItem(n){let t;for(t=this._itHead;null!==t;t=t._next)n(t)}forEachOperation(n){let t=this._itHead,r=this._removalsHead,i=0,o=null;for(;t||r;){const s=!r||t&&t.currentIndex{s=this._trackByFn(i,a),null!==t&&Object.is(t.trackById,s)?(r&&(t=this._verifyReinsertion(t,a,s,i)),Object.is(t.item,a)||this._addIdentityChange(t,a)):(t=this._mismatch(t,a,s,i),r=!0),t=t._next,i++}),this.length=i;return this._truncate(t),this.collection=n,this.isDirty}get isDirty(){return null!==this._additionsHead||null!==this._movesHead||null!==this._removalsHead||null!==this._identityChangesHead}_reset(){if(this.isDirty){let n;for(n=this._previousItHead=this._itHead;null!==n;n=n._next)n._nextPrevious=n._next;for(n=this._additionsHead;null!==n;n=n._nextAdded)n.previousIndex=n.currentIndex;for(this._additionsHead=this._additionsTail=null,n=this._movesHead;null!==n;n=n._nextMoved)n.previousIndex=n.currentIndex;this._movesHead=this._movesTail=null,this._removalsHead=this._removalsTail=null,this._identityChangesHead=this._identityChangesTail=null}}_mismatch(n,t,r,i){let o;return null===n?o=this._itTail:(o=n._prev,this._remove(n)),null!==(n=null===this._unlinkedRecords?null:this._unlinkedRecords.get(r,null))?(Object.is(n.item,t)||this._addIdentityChange(n,t),this._reinsertAfter(n,o,i)):null!==(n=null===this._linkedRecords?null:this._linkedRecords.get(r,i))?(Object.is(n.item,t)||this._addIdentityChange(n,t),this._moveAfter(n,o,i)):n=this._addAfter(new UL(t,r),o,i),n}_verifyReinsertion(n,t,r,i){let o=null===this._unlinkedRecords?null:this._unlinkedRecords.get(r,null);return null!==o?n=this._reinsertAfter(o,n._prev,i):n.currentIndex!=i&&(n.currentIndex=i,this._addToMoves(n,i)),n}_truncate(n){for(;null!==n;){const t=n._next;this._addToRemovals(this._unlink(n)),n=t}null!==this._unlinkedRecords&&this._unlinkedRecords.clear(),null!==this._additionsTail&&(this._additionsTail._nextAdded=null),null!==this._movesTail&&(this._movesTail._nextMoved=null),null!==this._itTail&&(this._itTail._next=null),null!==this._removalsTail&&(this._removalsTail._nextRemoved=null),null!==this._identityChangesTail&&(this._identityChangesTail._nextIdentityChange=null)}_reinsertAfter(n,t,r){null!==this._unlinkedRecords&&this._unlinkedRecords.remove(n);const i=n._prevRemoved,o=n._nextRemoved;return null===i?this._removalsHead=o:i._nextRemoved=o,null===o?this._removalsTail=i:o._prevRemoved=i,this._insertAfter(n,t,r),this._addToMoves(n,r),n}_moveAfter(n,t,r){return this._unlink(n),this._insertAfter(n,t,r),this._addToMoves(n,r),n}_addAfter(n,t,r){return this._insertAfter(n,t,r),this._additionsTail=null===this._additionsTail?this._additionsHead=n:this._additionsTail._nextAdded=n,n}_insertAfter(n,t,r){const i=null===t?this._itHead:t._next;return n._next=i,n._prev=t,null===i?this._itTail=n:i._prev=n,null===t?this._itHead=n:t._next=n,null===this._linkedRecords&&(this._linkedRecords=new eb),this._linkedRecords.put(n),n.currentIndex=r,n}_remove(n){return this._addToRemovals(this._unlink(n))}_unlink(n){null!==this._linkedRecords&&this._linkedRecords.remove(n);const t=n._prev,r=n._next;return null===t?this._itHead=r:t._next=r,null===r?this._itTail=t:r._prev=t,n}_addToMoves(n,t){return n.previousIndex===t||(this._movesTail=null===this._movesTail?this._movesHead=n:this._movesTail._nextMoved=n),n}_addToRemovals(n){return null===this._unlinkedRecords&&(this._unlinkedRecords=new eb),this._unlinkedRecords.put(n),n.currentIndex=null,n._nextRemoved=null,null===this._removalsTail?(this._removalsTail=this._removalsHead=n,n._prevRemoved=null):(n._prevRemoved=this._removalsTail,this._removalsTail=this._removalsTail._nextRemoved=n),n}_addIdentityChange(n,t){return n.item=t,this._identityChangesTail=null===this._identityChangesTail?this._identityChangesHead=n:this._identityChangesTail._nextIdentityChange=n,n}}class UL{item;trackById;currentIndex=null;previousIndex=null;_nextPrevious=null;_prev=null;_next=null;_prevDup=null;_nextDup=null;_prevRemoved=null;_nextRemoved=null;_nextAdded=null;_nextMoved=null;_nextIdentityChange=null;constructor(n,t){this.item=n,this.trackById=t}}class $L{_head=null;_tail=null;add(n){null===this._head?(this._head=this._tail=n,n._nextDup=null,n._prevDup=null):(this._tail._nextDup=n,n._prevDup=this._tail,n._nextDup=null,this._tail=n)}get(n,t){let r;for(r=this._head;null!==r;r=r._nextDup)if((null===t||t<=r.currentIndex)&&Object.is(r.trackById,n))return r;return null}remove(n){const t=n._prevDup,r=n._nextDup;return null===t?this._head=r:t._nextDup=r,null===r?this._tail=t:r._prevDup=t,null===this._head}}class eb{map=new Map;put(n){const t=n.trackById;let r=this.map.get(t);r||(r=new $L,this.map.set(t,r)),r.add(n)}get(n,t){const i=this.map.get(n);return i?i.get(n,t):null}remove(n){const t=n.trackById;return this.map.get(t).remove(n)&&this.map.delete(t),n}get isEmpty(){return 0===this.map.size}clear(){this.map.clear()}}function tb(e,n,t){const r=e.previousIndex;if(null===r)return r;let i=0;return t&&r{if(t&&t.key===i)this._maybeAddToChanges(t,r),this._appendAfter=t,t=t._next;else{const o=this._getOrCreateRecordForKey(i,r);t=this._insertBeforeOrAppend(t,o)}}),t){t._prev&&(t._prev._next=null),this._removalsHead=t;for(let r=t;null!==r;r=r._nextRemoved)r===this._mapHead&&(this._mapHead=null),this._records.delete(r.key),r._nextRemoved=r._next,r.previousValue=r.currentValue,r.currentValue=null,r._prev=null,r._next=null}return this._changesTail&&(this._changesTail._nextChanged=null),this._additionsTail&&(this._additionsTail._nextAdded=null),this.isDirty}_insertBeforeOrAppend(n,t){if(n){const r=n._prev;return t._next=n,t._prev=r,n._prev=t,r&&(r._next=t),n===this._mapHead&&(this._mapHead=t),this._appendAfter=n,n}return this._appendAfter?(this._appendAfter._next=t,t._prev=this._appendAfter):this._mapHead=t,this._appendAfter=t,null}_getOrCreateRecordForKey(n,t){if(this._records.has(n)){const i=this._records.get(n);this._maybeAddToChanges(i,t);const o=i._prev,s=i._next;return o&&(o._next=s),s&&(s._prev=o),i._next=null,i._prev=null,i}const r=new GL(n);return this._records.set(n,r),r.currentValue=t,this._addToAdditions(r),r}_reset(){if(this.isDirty){let n;for(this._previousMapHead=this._mapHead,n=this._previousMapHead;null!==n;n=n._next)n._nextPrevious=n._next;for(n=this._changesHead;null!==n;n=n._nextChanged)n.previousValue=n.currentValue;for(n=this._additionsHead;null!=n;n=n._nextAdded)n.previousValue=n.currentValue;this._changesHead=this._changesTail=null,this._additionsHead=this._additionsTail=null,this._removalsHead=null}}_maybeAddToChanges(n,t){Object.is(t,n.currentValue)||(n.previousValue=n.currentValue,n.currentValue=t,this._addToChanges(n))}_addToAdditions(n){null===this._additionsHead?this._additionsHead=this._additionsTail=n:(this._additionsTail._nextAdded=n,this._additionsTail=n)}_addToChanges(n){null===this._changesHead?this._changesHead=this._changesTail=n:(this._changesTail._nextChanged=n,this._changesTail=n)}_forEach(n,t){n instanceof Map?n.forEach(t):Object.keys(n).forEach(r=>t(n[r],r))}}class GL{key;previousValue=null;currentValue=null;_nextPrevious=null;_next=null;_prev=null;_nextAdded=null;_nextRemoved=null;_nextChanged=null;constructor(n){this.key=n}}function rb(){return new $h([new XD])}let $h=(()=>{class e{factories;static \u0275prov=re({token:e,providedIn:"root",factory:rb});constructor(t){this.factories=t}static create(t,r){if(null!=r){const i=r.factories.slice();t=t.concat(i)}return new e(t)}static extend(t){return{provide:e,useFactory:r=>e.create(t,r||rb()),deps:[[e,new Nu,new Su]]}}find(t){const r=this.factories.find(i=>i.supports(t));if(null!=r)return r;throw new N(901,!1)}}return e})();function ib(){return new gc([new nb])}let gc=(()=>{class e{static \u0275prov=re({token:e,providedIn:"root",factory:ib});factories;constructor(t){this.factories=t}static create(t,r){if(r){const i=r.factories.slice();t=t.concat(i)}return new e(t)}static extend(t){return{provide:e,useFactory:r=>e.create(t,r||ib()),deps:[[e,new Nu,new Su]]}}find(t){const r=this.factories.find(i=>i.supports(t));if(r)return r;throw new N(901,!1)}}return e})();const ZL=qD(null,"core",[]);let QL=(()=>{class e{constructor(t){}static \u0275fac=function(r){return new(r||e)(se(Yt))};static \u0275mod=cr({type:e});static \u0275inj=Nn({})}return e})();function Mn(e,n){Xe("NgSignals");const t=function mM(e){const n=Object.create(vM);n.computation=e;const t=()=>{if(Ao(n),Oo(n),n.value===Gn)throw n.error;return n.value};return t[Ke]=n,t}(e);return n?.equal&&(t[Ke].equal=n.equal),t}function it(e){const n=te(null);try{return e()}finally{te(n)}}let Lb=null;function Qs(){return Lb}class JP{}const li=new R(""),ig=/\s+/,Gb=[];let Do=(()=>{class e{_ngEl;_renderer;initialClasses=Gb;rawClass;stateMap=new Map;constructor(t,r){this._ngEl=t,this._renderer=r}set klass(t){this.initialClasses=null!=t?t.trim().split(ig):Gb}set ngClass(t){this.rawClass="string"==typeof t?t.trim().split(ig):t}ngDoCheck(){for(const r of this.initialClasses)this._updateState(r,!0);const t=this.rawClass;if(Array.isArray(t)||t instanceof Set)for(const r of t)this._updateState(r,!0);else if(null!=t)for(const r of Object.keys(t))this._updateState(r,!!t[r]);this._applyStateDiff()}_updateState(t,r){const i=this.stateMap.get(t);void 0!==i?(i.enabled!==r&&(i.changed=!0,i.enabled=r),i.touched=!0):this.stateMap.set(t,{enabled:r,changed:!0,touched:!0})}_applyStateDiff(){for(const t of this.stateMap){const r=t[0],i=t[1];i.changed?(this._toggleClass(r,i.enabled),i.changed=!1):i.touched||(i.enabled&&this._toggleClass(r,!1),this.stateMap.delete(r)),i.touched=!1}}_toggleClass(t,r){(t=t.trim()).length>0&&t.split(ig).forEach(i=>{r?this._renderer.addClass(this._ngEl.nativeElement,i):this._renderer.removeClass(this._ngEl.nativeElement,i)})}static \u0275fac=function(r){return new(r||e)(T(pt),T(on))};static \u0275dir=Y({type:e,selectors:[["","ngClass",""]],inputs:{klass:[0,"class","klass"],ngClass:"ngClass"}})}return e})();class BV{$implicit;ngForOf;index;count;constructor(n,t,r,i){this.$implicit=n,this.ngForOf=t,this.index=r,this.count=i}get first(){return 0===this.index}get last(){return this.index===this.count-1}get even(){return this.index%2==0}get odd(){return!this.even}}let ci=(()=>{class e{_viewContainer;_template;_differs;set ngForOf(t){this._ngForOf=t,this._ngForOfDirty=!0}set ngForTrackBy(t){this._trackByFn=t}get ngForTrackBy(){return this._trackByFn}_ngForOf=null;_ngForOfDirty=!0;_differ=null;_trackByFn;constructor(t,r,i){this._viewContainer=t,this._template=r,this._differs=i}set ngForTemplate(t){t&&(this._template=t)}ngDoCheck(){if(this._ngForOfDirty){this._ngForOfDirty=!1;const t=this._ngForOf;!this._differ&&t&&(this._differ=this._differs.find(t).create(this.ngForTrackBy))}if(this._differ){const t=this._differ.diff(this._ngForOf);t&&this._applyChanges(t)}}_applyChanges(t){const r=this._viewContainer;t.forEachOperation((i,o,s)=>{if(null==i.previousIndex)r.createEmbeddedView(this._template,new BV(i.item,this._ngForOf,-1,-1),null===s?void 0:s);else if(null==s)r.remove(null===o?void 0:o);else if(null!==o){const a=r.get(o);r.move(a,s),Wb(a,i)}});for(let i=0,o=r.length;i{Wb(r.get(i.currentIndex),i)})}static ngTemplateContextGuard(t,r){return!0}static \u0275fac=function(r){return new(r||e)(T(wn),T(Bn),T($h))};static \u0275dir=Y({type:e,selectors:[["","ngFor","","ngForOf",""]],inputs:{ngForOf:"ngForOf",ngForTrackBy:"ngForTrackBy",ngForTemplate:"ngForTemplate"}})}return e})();function Wb(e,n){e.context.$implicit=n.item}let zn=(()=>{class e{_viewContainer;_context=new jV;_thenTemplateRef=null;_elseTemplateRef=null;_thenViewRef=null;_elseViewRef=null;constructor(t,r){this._viewContainer=t,this._thenTemplateRef=r}set ngIf(t){this._context.$implicit=this._context.ngIf=t,this._updateView()}set ngIfThen(t){Zb("ngIfThen",t),this._thenTemplateRef=t,this._thenViewRef=null,this._updateView()}set ngIfElse(t){Zb("ngIfElse",t),this._elseTemplateRef=t,this._elseViewRef=null,this._updateView()}_updateView(){this._context.$implicit?this._thenViewRef||(this._viewContainer.clear(),this._elseViewRef=null,this._thenTemplateRef&&(this._thenViewRef=this._viewContainer.createEmbeddedView(this._thenTemplateRef,this._context))):this._elseViewRef||(this._viewContainer.clear(),this._thenViewRef=null,this._elseTemplateRef&&(this._elseViewRef=this._viewContainer.createEmbeddedView(this._elseTemplateRef,this._context)))}static ngIfUseIfTypeGuard;static ngTemplateGuard_ngIf;static ngTemplateContextGuard(t,r){return!0}static \u0275fac=function(r){return new(r||e)(T(wn),T(Bn))};static \u0275dir=Y({type:e,selectors:[["","ngIf",""]],inputs:{ngIf:"ngIf",ngIfThen:"ngIfThen",ngIfElse:"ngIfElse"}})}return e})();class jV{$implicit=null;ngIf=null}function Zb(e,n){if(n&&!n.createEmbeddedView)throw new Error(`${e} must be a TemplateRef, but received '${$e(n)}'.`)}let Yb=(()=>{class e{_ngEl;_differs;_renderer;_ngStyle=null;_differ=null;constructor(t,r,i){this._ngEl=t,this._differs=r,this._renderer=i}set ngStyle(t){this._ngStyle=t,!this._differ&&t&&(this._differ=this._differs.find(t).create())}ngDoCheck(){if(this._differ){const t=this._differ.diff(this._ngStyle);t&&this._applyChanges(t)}}_setStyle(t,r){const[i,o]=t.split("."),s=-1===i.indexOf("-")?void 0:sr.DashCase;null!=r?this._renderer.setStyle(this._ngEl.nativeElement,i,o?`${r}${o}`:r,s):this._renderer.removeStyle(this._ngEl.nativeElement,i,s)}_applyChanges(t){t.forEachRemovedItem(r=>this._setStyle(r.key,null)),t.forEachAddedItem(r=>this._setStyle(r.key,r.currentValue)),t.forEachChangedItem(r=>this._setStyle(r.key,r.currentValue))}static \u0275fac=function(r){return new(r||e)(T(pt),T(gc),T(on))};static \u0275dir=Y({type:e,selectors:[["","ngStyle",""]],inputs:{ngStyle:"ngStyle"}})}return e})(),Kb=(()=>{class e{_viewContainerRef;_viewRef=null;ngTemplateOutletContext=null;ngTemplateOutlet=null;ngTemplateOutletInjector=null;constructor(t){this._viewContainerRef=t}ngOnChanges(t){if(this._shouldRecreateView(t)){const r=this._viewContainerRef;if(this._viewRef&&r.remove(r.indexOf(this._viewRef)),!this.ngTemplateOutlet)return void(this._viewRef=null);const i=this._createContextForwardProxy();this._viewRef=r.createEmbeddedView(this.ngTemplateOutlet,i,{injector:this.ngTemplateOutletInjector??void 0})}}_shouldRecreateView(t){return!!t.ngTemplateOutlet||!!t.ngTemplateOutletInjector}_createContextForwardProxy(){return new Proxy({},{set:(t,r,i)=>!!this.ngTemplateOutletContext&&Reflect.set(this.ngTemplateOutletContext,r,i),get:(t,r,i)=>{if(this.ngTemplateOutletContext)return Reflect.get(this.ngTemplateOutletContext,r,i)}})}static \u0275fac=function(r){return new(r||e)(T(wn))};static \u0275dir=Y({type:e,selectors:[["","ngTemplateOutlet",""]],inputs:{ngTemplateOutletContext:"ngTemplateOutletContext",ngTemplateOutlet:"ngTemplateOutlet",ngTemplateOutletInjector:"ngTemplateOutletInjector"},features:[kn]})}return e})();let Xb=(()=>{class e{transform(t,r,i){if(null==t)return null;if(!this.supports(t))throw function un(e,n){return new N(2100,!1)}();return t.slice(r,i)}supports(t){return"string"==typeof t||Array.isArray(t)}static \u0275fac=function(r){return new(r||e)};static \u0275pipe=Nt({name:"slice",type:e,pure:!1})}return e})(),eE=(()=>{class e{static \u0275fac=function(r){return new(r||e)};static \u0275mod=cr({type:e});static \u0275inj=Nn({})}return e})();function nE(e){return"server"===e}class $2 extends JP{supportsDOMEvents=!0}class fg extends $2{static makeCurrent(){!function KP(e){Lb??=e}(new fg)}onAndCancel(n,t,r,i){return n.addEventListener(t,r,i),()=>{n.removeEventListener(t,r,i)}}dispatchEvent(n,t){n.dispatchEvent(t)}remove(n){n.remove()}createElement(n,t){return(t=t||this.getDefaultDocument()).createElement(n)}createHtmlDocument(){return document.implementation.createHTMLDocument("fakeTitle")}getDefaultDocument(){return document}isElementNode(n){return n.nodeType===Node.ELEMENT_NODE}isShadowRoot(n){return n instanceof DocumentFragment}getGlobalEventTarget(n,t){return"window"===t?window:"document"===t?n:"body"===t?n.body:null}getBaseHref(n){const t=function z2(){return Xs=Xs||document.querySelector("base"),Xs?Xs.getAttribute("href"):null}();return null==t?null:function G2(e){return new URL(e,document.baseURI).pathname}(t)}resetBaseElement(){Xs=null}getUserAgent(){return window.navigator.userAgent}getCookie(n){return function VV(e,n){n=encodeURIComponent(n);for(const t of e.split(";")){const r=t.indexOf("="),[i,o]=-1==r?[t,""]:[t.slice(0,r),t.slice(r+1)];if(i.trim()===n)return decodeURIComponent(o)}return null}(document.cookie,n)}}let Xs=null,W2=(()=>{class e{build(){return new XMLHttpRequest}static \u0275fac=function(r){return new(r||e)};static \u0275prov=re({token:e,factory:e.\u0275fac})}return e})();const hg=new R("");let hE=(()=>{class e{_zone;_plugins;_eventNameToPlugin=new Map;constructor(t,r){this._zone=r,t.forEach(i=>{i.manager=this}),this._plugins=t.slice().reverse()}addEventListener(t,r,i,o){return this._findPluginFor(r).addEventListener(t,r,i,o)}getZone(){return this._zone}_findPluginFor(t){let r=this._eventNameToPlugin.get(t);if(r)return r;if(r=this._plugins.find(o=>o.supports(t)),!r)throw new N(5101,!1);return this._eventNameToPlugin.set(t,r),r}static \u0275fac=function(r){return new(r||e)(se(hg),se(de))};static \u0275prov=re({token:e,factory:e.\u0275fac})}return e})();class gE{_doc;constructor(n){this._doc=n}manager}const Vc="ng-app-id";function pE(e){for(const n of e)n.remove()}function mE(e,n){const t=n.createElement("style");return t.textContent=e,t}function gg(e,n){const t=n.createElement("link");return t.setAttribute("rel","stylesheet"),t.setAttribute("href",e),t}let vE=(()=>{class e{doc;appId;nonce;inline=new Map;external=new Map;hosts=new Set;isServer;constructor(t,r,i,o={}){this.doc=t,this.appId=r,this.nonce=i,this.isServer=nE(o),function Z2(e,n,t,r){const i=e.head?.querySelectorAll(`style[${Vc}="${n}"],link[${Vc}="${n}"]`);if(i)for(const o of i)o.removeAttribute(Vc),o instanceof HTMLLinkElement?r.set(o.href.slice(o.href.lastIndexOf("/")+1),{usage:0,elements:[o]}):o.textContent&&t.set(o.textContent,{usage:0,elements:[o]})}(t,r,this.inline,this.external),this.hosts.add(t.head)}addStyles(t,r){for(const i of t)this.addUsage(i,this.inline,mE);r?.forEach(i=>this.addUsage(i,this.external,gg))}removeStyles(t,r){for(const i of t)this.removeUsage(i,this.inline);r?.forEach(i=>this.removeUsage(i,this.external))}addUsage(t,r,i){const o=r.get(t);o?o.usage++:r.set(t,{usage:1,elements:[...this.hosts].map(s=>this.addElement(s,i(t,this.doc)))})}removeUsage(t,r){const i=r.get(t);i&&(i.usage--,i.usage<=0&&(pE(i.elements),r.delete(t)))}ngOnDestroy(){for(const[,{elements:t}]of[...this.inline,...this.external])pE(t);this.hosts.clear()}addHost(t){this.hosts.add(t);for(const[r,{elements:i}]of this.inline)i.push(this.addElement(t,mE(r,this.doc)));for(const[r,{elements:i}]of this.external)i.push(this.addElement(t,gg(r,this.doc)))}removeHost(t){this.hosts.delete(t)}addElement(t,r){return this.nonce&&r.setAttribute("nonce",this.nonce),this.isServer&&r.setAttribute(Vc,this.appId),t.appendChild(r)}static \u0275fac=function(r){return new(r||e)(se(li),se(qr),se(yv,8),se(Pi))};static \u0275prov=re({token:e,factory:e.\u0275fac})}return e})();const pg={svg:"http://www.w3.org/2000/svg",xhtml:"http://www.w3.org/1999/xhtml",xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/",math:"http://www.w3.org/1998/Math/MathML"},mg=/%COMP%/g,eH=new R("",{providedIn:"root",factory:()=>!0});function yE(e,n){return n.map(t=>t.replace(mg,e))}let CE=(()=>{class e{eventManager;sharedStylesHost;appId;removeStylesOnCompDestroy;doc;platformId;ngZone;nonce;tracingService;rendererByCompId=new Map;defaultRenderer;platformIsServer;constructor(t,r,i,o,s,a,l,c=null,u=null){this.eventManager=t,this.sharedStylesHost=r,this.appId=i,this.removeStylesOnCompDestroy=o,this.doc=s,this.platformId=a,this.ngZone=l,this.nonce=c,this.tracingService=u,this.platformIsServer=nE(a),this.defaultRenderer=new vg(t,s,l,this.platformIsServer,this.tracingService)}createRenderer(t,r){if(!t||!r)return this.defaultRenderer;this.platformIsServer&&r.encapsulation===Zt.ShadowDom&&(r={...r,encapsulation:Zt.Emulated});const i=this.getOrCreateRenderer(t,r);return i instanceof DE?i.applyToHost(t):i instanceof _g&&i.applyStyles(),i}getOrCreateRenderer(t,r){const i=this.rendererByCompId;let o=i.get(r.id);if(!o){const s=this.doc,a=this.ngZone,l=this.eventManager,c=this.sharedStylesHost,u=this.removeStylesOnCompDestroy,d=this.platformIsServer,g=this.tracingService;switch(r.encapsulation){case Zt.Emulated:o=new DE(l,c,r,this.appId,u,s,a,d,g);break;case Zt.ShadowDom:return new iH(l,c,t,r,s,a,this.nonce,d,g);default:o=new _g(l,c,r,u,s,a,d,g)}i.set(r.id,o)}return o}ngOnDestroy(){this.rendererByCompId.clear()}componentReplaced(t){this.rendererByCompId.delete(t)}static \u0275fac=function(r){return new(r||e)(se(hE),se(vE),se(qr),se(eH),se(li),se(Pi),se(de),se(yv),se(Hi,8))};static \u0275prov=re({token:e,factory:e.\u0275fac})}return e})();class vg{eventManager;doc;ngZone;platformIsServer;tracingService;data=Object.create(null);throwOnSyntheticProps=!0;constructor(n,t,r,i,o){this.eventManager=n,this.doc=t,this.ngZone=r,this.platformIsServer=i,this.tracingService=o}destroy(){}destroyNode=null;createElement(n,t){return t?this.doc.createElementNS(pg[t]||t,n):this.doc.createElement(n)}createComment(n){return this.doc.createComment(n)}createText(n){return this.doc.createTextNode(n)}appendChild(n,t){(wE(n)?n.content:n).appendChild(t)}insertBefore(n,t,r){n&&(wE(n)?n.content:n).insertBefore(t,r)}removeChild(n,t){t.remove()}selectRootElement(n,t){let r="string"==typeof n?this.doc.querySelector(n):n;if(!r)throw new N(-5104,!1);return t||(r.textContent=""),r}parentNode(n){return n.parentNode}nextSibling(n){return n.nextSibling}setAttribute(n,t,r,i){if(i){t=i+":"+t;const o=pg[i];o?n.setAttributeNS(o,t,r):n.setAttribute(t,r)}else n.setAttribute(t,r)}removeAttribute(n,t,r){if(r){const i=pg[r];i?n.removeAttributeNS(i,t):n.removeAttribute(`${r}:${t}`)}else n.removeAttribute(t)}addClass(n,t){n.classList.add(t)}removeClass(n,t){n.classList.remove(t)}setStyle(n,t,r,i){i&(sr.DashCase|sr.Important)?n.style.setProperty(t,r,i&sr.Important?"important":""):n.style[t]=r}removeStyle(n,t,r){r&sr.DashCase?n.style.removeProperty(t):n.style[t]=""}setProperty(n,t,r){null!=n&&(n[t]=r)}setValue(n,t){n.nodeValue=t}listen(n,t,r,i){if("string"==typeof n&&!(n=Qs().getGlobalEventTarget(this.doc,n)))throw new Error(`Unsupported event target ${n} for event ${t}`);let o=this.decoratePreventDefault(r);return null!==this.tracingService&&this.tracingService.wrapEventListener&&(o=this.tracingService.wrapEventListener(n,t,o)),this.eventManager.addEventListener(n,t,o,i)}decoratePreventDefault(n){return t=>{if("__ngUnwrap__"===t)return n;!1===(this.platformIsServer?this.ngZone.runGuarded(()=>n(t)):n(t))&&t.preventDefault()}}}function wE(e){return"TEMPLATE"===e.tagName&&void 0!==e.content}class iH extends vg{sharedStylesHost;hostEl;shadowRoot;constructor(n,t,r,i,o,s,a,l,c){super(n,o,s,l,c),this.sharedStylesHost=t,this.hostEl=r,this.shadowRoot=r.attachShadow({mode:"open"}),this.sharedStylesHost.addHost(this.shadowRoot);let u=i.styles;u=yE(i.id,u);for(const g of u){const h=document.createElement("style");a&&h.setAttribute("nonce",a),h.textContent=g,this.shadowRoot.appendChild(h)}const d=i.getExternalStyles?.();if(d)for(const g of d){const h=gg(g,o);a&&h.setAttribute("nonce",a),this.shadowRoot.appendChild(h)}}nodeOrShadowRoot(n){return n===this.hostEl?this.shadowRoot:n}appendChild(n,t){return super.appendChild(this.nodeOrShadowRoot(n),t)}insertBefore(n,t,r){return super.insertBefore(this.nodeOrShadowRoot(n),t,r)}removeChild(n,t){return super.removeChild(null,t)}parentNode(n){return this.nodeOrShadowRoot(super.parentNode(this.nodeOrShadowRoot(n)))}destroy(){this.sharedStylesHost.removeHost(this.shadowRoot)}}class _g extends vg{sharedStylesHost;removeStylesOnCompDestroy;styles;styleUrls;constructor(n,t,r,i,o,s,a,l,c){super(n,o,s,a,l),this.sharedStylesHost=t,this.removeStylesOnCompDestroy=i;let u=r.styles;this.styles=c?yE(c,u):u,this.styleUrls=r.getExternalStyles?.(c)}applyStyles(){this.sharedStylesHost.addStyles(this.styles,this.styleUrls)}destroy(){this.removeStylesOnCompDestroy&&this.sharedStylesHost.removeStyles(this.styles,this.styleUrls)}}class DE extends _g{contentAttr;hostAttr;constructor(n,t,r,i,o,s,a,l,c){const u=i+"-"+r.id;super(n,t,r,o,s,a,l,c,u),this.contentAttr=function tH(e){return"_ngcontent-%COMP%".replace(mg,e)}(u),this.hostAttr=function nH(e){return"_nghost-%COMP%".replace(mg,e)}(u)}applyToHost(n){this.applyStyles(),this.setAttribute(n,this.hostAttr,"")}createElement(n,t){const r=super.createElement(n,t);return super.setAttribute(r,this.contentAttr,""),r}}let oH=(()=>{class e extends gE{constructor(t){super(t)}supports(t){return!0}addEventListener(t,r,i,o){return t.addEventListener(r,i,o),()=>this.removeEventListener(t,r,i,o)}removeEventListener(t,r,i,o){return t.removeEventListener(r,i,o)}static \u0275fac=function(r){return new(r||e)(se(li))};static \u0275prov=re({token:e,factory:e.\u0275fac})}return e})();const bE=["alt","control","meta","shift"],sH={"\b":"Backspace","\t":"Tab","\x7f":"Delete","\x1b":"Escape",Del:"Delete",Esc:"Escape",Left:"ArrowLeft",Right:"ArrowRight",Up:"ArrowUp",Down:"ArrowDown",Menu:"ContextMenu",Scroll:"ScrollLock",Win:"OS"},aH={alt:e=>e.altKey,control:e=>e.ctrlKey,meta:e=>e.metaKey,shift:e=>e.shiftKey};let lH=(()=>{class e extends gE{constructor(t){super(t)}supports(t){return null!=e.parseEventName(t)}addEventListener(t,r,i,o){const s=e.parseEventName(r),a=e.eventCallback(s.fullKey,i,this.manager.getZone());return this.manager.getZone().runOutsideAngular(()=>Qs().onAndCancel(t,s.domEventName,a,o))}static parseEventName(t){const r=t.toLowerCase().split("."),i=r.shift();if(0===r.length||"keydown"!==i&&"keyup"!==i)return null;const o=e._normalizeKey(r.pop());let s="",a=r.indexOf("code");if(a>-1&&(r.splice(a,1),s="code."),bE.forEach(c=>{const u=r.indexOf(c);u>-1&&(r.splice(u,1),s+=c+".")}),s+=o,0!=r.length||0===o.length)return null;const l={};return l.domEventName=i,l.fullKey=s,l}static matchEventFullKeyCode(t,r){let i=sH[t.key]||t.key,o="";return r.indexOf("code.")>-1&&(i=t.code,o="code."),!(null==i||!i)&&(i=i.toLowerCase()," "===i?i="space":"."===i&&(i="dot"),bE.forEach(s=>{s!==i&&(0,aH[s])(t)&&(o+=s+".")}),o+=i,o===r)}static eventCallback(t,r,i){return o=>{e.matchEventFullKeyCode(o,t)&&i.runGuarded(()=>r(o))}}static _normalizeKey(t){return"esc"===t?"escape":t}static \u0275fac=function(r){return new(r||e)(se(li))};static \u0275prov=re({token:e,factory:e.\u0275fac})}return e})();const fH=qD(ZL,"browser",[{provide:Pi,useValue:"browser"},{provide:Ed,useValue:function cH(){fg.makeCurrent()},multi:!0},{provide:li,useFactory:function dH(){return function sS(e){bd=e}(document),document},deps:[]}]),ME=[{provide:Ql,useClass:class q2{addToWindow(n){Ie.getAngularTestability=(r,i=!0)=>{const o=n.findTestabilityInTree(r,i);if(null==o)throw new N(5103,!1);return o},Ie.getAllAngularTestabilities=()=>n.getAllTestabilities(),Ie.getAllAngularRootElements=()=>n.getAllRootElements(),Ie.frameworkStabilizers||(Ie.frameworkStabilizers=[]),Ie.frameworkStabilizers.push(r=>{const i=Ie.getAllAngularTestabilities();let o=i.length;const s=function(){o--,0==o&&r()};i.forEach(a=>{a.whenStable(s)})})}findTestabilityInTree(n,t,r){return null==t?null:n.getTestability(t)??(r?Qs().isShadowRoot(t)?this.findTestabilityInTree(n,t.host,!0):this.findTestabilityInTree(n,t.parentElement,!0):null)}},deps:[]},{provide:TC,useClass:sh,deps:[de,ah,Ql]},{provide:sh,useClass:sh,deps:[de,ah,Ql]}],TE=[{provide:Lu,useValue:"root"},{provide:_n,useFactory:function uH(){return new _n},deps:[]},{provide:hg,useClass:oH,multi:!0,deps:[li,de,Pi]},{provide:hg,useClass:lH,multi:!0,deps:[li]},CE,vE,hE,{provide:Vf,useExisting:CE},{provide:class p2{},useClass:W2,deps:[]},[]];let hH=(()=>{class e{constructor(){}static \u0275fac=function(r){return new(r||e)};static \u0275mod=cr({type:e});static \u0275inj=Nn({providers:[...TE,...ME],imports:[eE,QL]})}return e})();function vr(e){return this instanceof vr?(this.v=e,this):new vr(e)}function RE(e){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var t,n=e[Symbol.asyncIterator];return n?n.call(e):(e=function Dg(e){var n="function"==typeof Symbol&&Symbol.iterator,t=n&&e[n],r=0;if(t)return t.call(e);if(e&&"number"==typeof e.length)return{next:function(){return e&&r>=e.length&&(e=void 0),{value:e&&e[r++],done:!e}}};throw new TypeError(n?"Object is not iterable.":"Symbol.iterator is not defined.")}(e),t={},r("next"),r("throw"),r("return"),t[Symbol.asyncIterator]=function(){return this},t);function r(o){t[o]=e[o]&&function(s){return new Promise(function(a,l){!function i(o,s,a,l){Promise.resolve(l).then(function(c){o({value:c,done:a})},s)}(a,l,(s=e[o](s)).done,s.value)})}}}"function"==typeof SuppressedError&&SuppressedError;const kE=e=>e&&"number"==typeof e.length&&"function"!=typeof e;function FE(e){return Be(e?.then)}function LE(e){return Be(e[hu])}function PE(e){return Symbol.asyncIterator&&Be(e?.[Symbol.asyncIterator])}function VE(e){return new TypeError(`You provided ${null!==e&&"object"==typeof e?"an invalid object":`'${e}'`} where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.`)}const HE=function $H(){return"function"==typeof Symbol&&Symbol.iterator?Symbol.iterator:"@@iterator"}();function BE(e){return Be(e?.[HE])}function jE(e){return function AE(e,n,t){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var i,r=t.apply(e,n||[]),o=[];return i=Object.create(("function"==typeof AsyncIterator?AsyncIterator:Object).prototype),a("next"),a("throw"),a("return",function s(h){return function(m){return Promise.resolve(m).then(h,d)}}),i[Symbol.asyncIterator]=function(){return this},i;function a(h,m){r[h]&&(i[h]=function(C){return new Promise(function(E,I){o.push([h,C,E,I])>1||l(h,C)})},m&&(i[h]=m(i[h])))}function l(h,m){try{!function c(h){h.value instanceof vr?Promise.resolve(h.value.v).then(u,d):g(o[0][2],h)}(r[h](m))}catch(C){g(o[0][3],C)}}function u(h){l("next",h)}function d(h){l("throw",h)}function g(h,m){h(m),o.shift(),o.length&&l(o[0][0],o[0][1])}}(this,arguments,function*(){const t=e.getReader();try{for(;;){const{value:r,done:i}=yield vr(t.read());if(i)return yield vr(void 0);yield yield vr(r)}}finally{t.releaseLock()}})}function UE(e){return Be(e?.getReader)}function ta(e){if(e instanceof kt)return e;if(null!=e){if(LE(e))return function zH(e){return new kt(n=>{const t=e[hu]();if(Be(t.subscribe))return t.subscribe(n);throw new TypeError("Provided object does not correctly implement Symbol.observable")})}(e);if(kE(e))return function GH(e){return new kt(n=>{for(let t=0;t{e.then(t=>{n.closed||(n.next(t),n.complete())},t=>n.error(t)).then(null,pp)})}(e);if(PE(e))return $E(e);if(BE(e))return function WH(e){return new kt(n=>{for(const t of e)if(n.next(t),n.closed)return;n.complete()})}(e);if(UE(e))return function ZH(e){return $E(jE(e))}(e)}throw VE(e)}function $E(e){return new kt(n=>{(function QH(e,n){var t,r,i,o;return function xE(e,n,t,r){return new(t||(t=Promise))(function(o,s){function a(u){try{c(r.next(u))}catch(d){s(d)}}function l(u){try{c(r.throw(u))}catch(d){s(d)}}function c(u){u.done?o(u.value):function i(o){return o instanceof t?o:new t(function(s){s(o)})}(u.value).then(a,l)}c((r=r.apply(e,n||[])).next())})}(this,void 0,void 0,function*(){try{for(t=RE(e);!(r=yield t.next()).done;)if(n.next(r.value),n.closed)return}catch(s){i={error:s}}finally{try{r&&!r.done&&(o=t.return)&&(yield o.call(t))}finally{if(i)throw i.error}}n.complete()})})(e,n).catch(t=>n.error(t))})}function ui(e,n,t,r=0,i=!1){const o=n.schedule(function(){t(),i?e.add(this.schedule(null,r)):this.unsubscribe()},r);if(e.add(o),!i)return o}function zE(e,n=0){return Nr((t,r)=>{t.subscribe(qn(r,i=>ui(r,e,()=>r.next(i),n),()=>ui(r,e,()=>r.complete(),n),i=>ui(r,e,()=>r.error(i),n)))})}function GE(e,n=0){return Nr((t,r)=>{r.add(e.schedule(()=>t.subscribe(r),n))})}function qE(e,n){if(!e)throw new Error("Iterable cannot be null");return new kt(t=>{ui(t,n,()=>{const r=e[Symbol.asyncIterator]();ui(t,n,()=>{r.next().then(i=>{i.done?t.complete():t.next(i.value)})},0,!0)})})}const{isArray:rB}=Array,{getPrototypeOf:iB,prototype:oB,keys:sB}=Object;const{isArray:uB}=Array;function hB(e,n){return e.reduce((t,r,i)=>(t[r]=n[i],t),{})}function gB(...e){const n=function cB(e){return Be(function Eg(e){return e[e.length-1]}(e))?e.pop():void 0}(e),{args:t,keys:r}=function aB(e){if(1===e.length){const n=e[0];if(rB(n))return{args:n,keys:null};if(function lB(e){return e&&"object"==typeof e&&iB(e)===oB}(n)){const t=sB(n);return{args:t.map(r=>n[r]),keys:t}}}return{args:e,keys:null}}(e),i=new kt(o=>{const{length:s}=t;if(!s)return void o.complete();const a=new Array(s);let l=s,c=s;for(let u=0;u{d||(d=!0,c--),a[u]=g},()=>l--,void 0,()=>{(!l||!d)&&(c||o.next(r?hB(r,a):a),o.complete())}))}});return n?i.pipe(function fB(e){return pu(n=>function dB(e,n){return uB(n)?e(...n):e(n)}(e,n))}(n)):i}let WE=(()=>{class e{_renderer;_elementRef;onChange=t=>{};onTouched=()=>{};constructor(t,r){this._renderer=t,this._elementRef=r}setProperty(t,r){this._renderer.setProperty(this._elementRef.nativeElement,t,r)}registerOnTouched(t){this.onTouched=t}registerOnChange(t){this.onChange=t}setDisabledState(t){this.setProperty("disabled",t)}static \u0275fac=function(r){return new(r||e)(T(on),T(pt))};static \u0275dir=Y({type:e})}return e})(),di=(()=>{class e extends WE{static \u0275fac=(()=>{let t;return function(i){return(t||(t=lt(e)))(i||e)}})();static \u0275dir=Y({type:e,features:[ue]})}return e})();const dn=new R(""),pB={provide:dn,useExisting:ve(()=>Ig),multi:!0};let Ig=(()=>{class e extends di{writeValue(t){this.setProperty("checked",t)}static \u0275fac=(()=>{let t;return function(i){return(t||(t=lt(e)))(i||e)}})();static \u0275dir=Y({type:e,selectors:[["input","type","checkbox","formControlName",""],["input","type","checkbox","formControl",""],["input","type","checkbox","ngModel",""]],hostBindings:function(r,i){1&r&&q("change",function(s){return i.onChange(s.target.checked)})("blur",function(){return i.onTouched()})},standalone:!1,features:[Me([pB]),ue]})}return e})();const mB={provide:dn,useExisting:ve(()=>na),multi:!0},_B=new R("");let na=(()=>{class e extends WE{_compositionMode;_composing=!1;constructor(t,r,i){super(t,r),this._compositionMode=i,null==this._compositionMode&&(this._compositionMode=!function vB(){const e=Qs()?Qs().getUserAgent():"";return/android (\d+)/.test(e.toLowerCase())}())}writeValue(t){this.setProperty("value",t??"")}_handleInput(t){(!this._compositionMode||this._compositionMode&&!this._composing)&&this.onChange(t)}_compositionStart(){this._composing=!0}_compositionEnd(t){this._composing=!1,this._compositionMode&&this.onChange(t)}static \u0275fac=function(r){return new(r||e)(T(on),T(pt),T(_B,8))};static \u0275dir=Y({type:e,selectors:[["input","formControlName","",3,"type","checkbox"],["textarea","formControlName",""],["input","formControl","",3,"type","checkbox"],["textarea","formControl",""],["input","ngModel","",3,"type","checkbox"],["textarea","ngModel",""],["","ngDefaultControl",""]],hostBindings:function(r,i){1&r&&q("input",function(s){return i._handleInput(s.target.value)})("blur",function(){return i.onTouched()})("compositionstart",function(){return i._compositionStart()})("compositionend",function(s){return i._compositionEnd(s.target.value)})},standalone:!1,features:[Me([mB]),ue]})}return e})();const ct=new R(""),yr=new R("");function rI(e){return null!=e}function iI(e){return Yl(e)?function nB(e,n){return n?function tB(e,n){if(null!=e){if(LE(e))return function YH(e,n){return ta(e).pipe(GE(n),zE(n))}(e,n);if(kE(e))return function JH(e,n){return new kt(t=>{let r=0;return n.schedule(function(){r===e.length?t.complete():(t.next(e[r++]),t.closed||this.schedule())})})}(e,n);if(FE(e))return function KH(e,n){return ta(e).pipe(GE(n),zE(n))}(e,n);if(PE(e))return qE(e,n);if(BE(e))return function XH(e,n){return new kt(t=>{let r;return ui(t,n,()=>{r=e[HE](),ui(t,n,()=>{let i,o;try{({value:i,done:o}=r.next())}catch(s){return void t.error(s)}o?t.complete():t.next(i)},0,!0)}),()=>Be(r?.return)&&r.return()})}(e,n);if(UE(e))return function eB(e,n){return qE(jE(e),n)}(e,n)}throw VE(e)}(e,n):ta(e)}(e):e}function oI(e){let n={};return e.forEach(t=>{n=null!=t?{...n,...t}:n}),0===Object.keys(n).length?null:n}function sI(e,n){return n.map(t=>t(e))}function aI(e){return e.map(n=>function CB(e){return!e.validate}(n)?n:t=>n.validate(t))}function Mg(e){return null!=e?function lI(e){if(!e)return null;const n=e.filter(rI);return 0==n.length?null:function(t){return oI(sI(t,n))}}(aI(e)):null}function Tg(e){return null!=e?function cI(e){if(!e)return null;const n=e.filter(rI);return 0==n.length?null:function(t){return gB(sI(t,n).map(iI)).pipe(pu(oI))}}(aI(e)):null}function uI(e,n){return null===e?[n]:Array.isArray(e)?[...e,n]:[e,n]}function Sg(e){return e?Array.isArray(e)?e:[e]:[]}function Bc(e,n){return Array.isArray(e)?e.includes(n):e===n}function hI(e,n){const t=Sg(n);return Sg(e).forEach(i=>{Bc(t,i)||t.push(i)}),t}function gI(e,n){return Sg(n).filter(t=>!Bc(e,t))}class pI{get value(){return this.control?this.control.value:null}get valid(){return this.control?this.control.valid:null}get invalid(){return this.control?this.control.invalid:null}get pending(){return this.control?this.control.pending:null}get disabled(){return this.control?this.control.disabled:null}get enabled(){return this.control?this.control.enabled:null}get errors(){return this.control?this.control.errors:null}get pristine(){return this.control?this.control.pristine:null}get dirty(){return this.control?this.control.dirty:null}get touched(){return this.control?this.control.touched:null}get status(){return this.control?this.control.status:null}get untouched(){return this.control?this.control.untouched:null}get statusChanges(){return this.control?this.control.statusChanges:null}get valueChanges(){return this.control?this.control.valueChanges:null}get path(){return null}_composedValidatorFn;_composedAsyncValidatorFn;_rawValidators=[];_rawAsyncValidators=[];_setValidators(n){this._rawValidators=n||[],this._composedValidatorFn=Mg(this._rawValidators)}_setAsyncValidators(n){this._rawAsyncValidators=n||[],this._composedAsyncValidatorFn=Tg(this._rawAsyncValidators)}get validator(){return this._composedValidatorFn||null}get asyncValidator(){return this._composedAsyncValidatorFn||null}_onDestroyCallbacks=[];_registerOnDestroy(n){this._onDestroyCallbacks.push(n)}_invokeOnDestroyCallbacks(){this._onDestroyCallbacks.forEach(n=>n()),this._onDestroyCallbacks=[]}reset(n=void 0){this.control&&this.control.reset(n)}hasError(n,t){return!!this.control&&this.control.hasError(n,t)}getError(n,t){return this.control?this.control.getError(n,t):null}}class Dt extends pI{name;get formDirective(){return null}get path(){return null}}class Cr extends pI{_parent=null;name=null;valueAccessor=null}class mI{_cd;constructor(n){this._cd=n}get isTouched(){return this._cd?.control?._touched?.(),!!this._cd?.control?.touched}get isUntouched(){return!!this._cd?.control?.untouched}get isPristine(){return this._cd?.control?._pristine?.(),!!this._cd?.control?.pristine}get isDirty(){return!!this._cd?.control?.dirty}get isValid(){return this._cd?.control?._status?.(),!!this._cd?.control?.valid}get isInvalid(){return!!this._cd?.control?.invalid}get isPending(){return!!this._cd?.control?.pending}get isSubmitted(){return this._cd?._submitted?.(),!!this._cd?.submitted}}let jc=(()=>{class e extends mI{constructor(t){super(t)}static \u0275fac=function(r){return new(r||e)(T(Cr,2))};static \u0275dir=Y({type:e,selectors:[["","formControlName",""],["","ngModel",""],["","formControl",""]],hostVars:14,hostBindings:function(r,i){2&r&&jn("ng-untouched",i.isUntouched)("ng-touched",i.isTouched)("ng-pristine",i.isPristine)("ng-dirty",i.isDirty)("ng-valid",i.isValid)("ng-invalid",i.isInvalid)("ng-pending",i.isPending)},standalone:!1,features:[ue]})}return e})();const ra="VALID",$c="INVALID",Eo="PENDING",ia="DISABLED";class Io{}class _I extends Io{value;source;constructor(n,t){super(),this.value=n,this.source=t}}class Og extends Io{pristine;source;constructor(n,t){super(),this.pristine=n,this.source=t}}class Ag extends Io{touched;source;constructor(n,t){super(),this.touched=n,this.source=t}}class zc extends Io{status;source;constructor(n,t){super(),this.status=n,this.source=t}}function Gc(e){return null!=e&&!Array.isArray(e)&&"object"==typeof e}class Fg{_pendingDirty=!1;_hasOwnPendingAsyncValidator=null;_pendingTouched=!1;_onCollectionChange=()=>{};_updateOn;_parent=null;_asyncValidationSubscription;_composedValidatorFn;_composedAsyncValidatorFn;_rawValidators;_rawAsyncValidators;value;constructor(n,t){this._assignValidators(n),this._assignAsyncValidators(t)}get validator(){return this._composedValidatorFn}set validator(n){this._rawValidators=this._composedValidatorFn=n}get asyncValidator(){return this._composedAsyncValidatorFn}set asyncValidator(n){this._rawAsyncValidators=this._composedAsyncValidatorFn=n}get parent(){return this._parent}get status(){return it(this.statusReactive)}set status(n){it(()=>this.statusReactive.set(n))}_status=Mn(()=>this.statusReactive());statusReactive=Gr(void 0);get valid(){return this.status===ra}get invalid(){return this.status===$c}get pending(){return this.status==Eo}get disabled(){return this.status===ia}get enabled(){return this.status!==ia}errors;get pristine(){return it(this.pristineReactive)}set pristine(n){it(()=>this.pristineReactive.set(n))}_pristine=Mn(()=>this.pristineReactive());pristineReactive=Gr(!0);get dirty(){return!this.pristine}get touched(){return it(this.touchedReactive)}set touched(n){it(()=>this.touchedReactive.set(n))}_touched=Mn(()=>this.touchedReactive());touchedReactive=Gr(!1);get untouched(){return!this.touched}_events=new fn;events=this._events.asObservable();valueChanges;statusChanges;get updateOn(){return this._updateOn?this._updateOn:this.parent?this.parent.updateOn:"change"}setValidators(n){this._assignValidators(n)}setAsyncValidators(n){this._assignAsyncValidators(n)}addValidators(n){this.setValidators(hI(n,this._rawValidators))}addAsyncValidators(n){this.setAsyncValidators(hI(n,this._rawAsyncValidators))}removeValidators(n){this.setValidators(gI(n,this._rawValidators))}removeAsyncValidators(n){this.setAsyncValidators(gI(n,this._rawAsyncValidators))}hasValidator(n){return Bc(this._rawValidators,n)}hasAsyncValidator(n){return Bc(this._rawAsyncValidators,n)}clearValidators(){this.validator=null}clearAsyncValidators(){this.asyncValidator=null}markAsTouched(n={}){const t=!1===this.touched;this.touched=!0;const r=n.sourceControl??this;this._parent&&!n.onlySelf&&this._parent.markAsTouched({...n,sourceControl:r}),t&&!1!==n.emitEvent&&this._events.next(new Ag(!0,r))}markAllAsTouched(n={}){this.markAsTouched({onlySelf:!0,emitEvent:n.emitEvent,sourceControl:this}),this._forEachChild(t=>t.markAllAsTouched(n))}markAsUntouched(n={}){const t=!0===this.touched;this.touched=!1,this._pendingTouched=!1;const r=n.sourceControl??this;this._forEachChild(i=>{i.markAsUntouched({onlySelf:!0,emitEvent:n.emitEvent,sourceControl:r})}),this._parent&&!n.onlySelf&&this._parent._updateTouched(n,r),t&&!1!==n.emitEvent&&this._events.next(new Ag(!1,r))}markAsDirty(n={}){const t=!0===this.pristine;this.pristine=!1;const r=n.sourceControl??this;this._parent&&!n.onlySelf&&this._parent.markAsDirty({...n,sourceControl:r}),t&&!1!==n.emitEvent&&this._events.next(new Og(!1,r))}markAsPristine(n={}){const t=!1===this.pristine;this.pristine=!0,this._pendingDirty=!1;const r=n.sourceControl??this;this._forEachChild(i=>{i.markAsPristine({onlySelf:!0,emitEvent:n.emitEvent})}),this._parent&&!n.onlySelf&&this._parent._updatePristine(n,r),t&&!1!==n.emitEvent&&this._events.next(new Og(!0,r))}markAsPending(n={}){this.status=Eo;const t=n.sourceControl??this;!1!==n.emitEvent&&(this._events.next(new zc(this.status,t)),this.statusChanges.emit(this.status)),this._parent&&!n.onlySelf&&this._parent.markAsPending({...n,sourceControl:t})}disable(n={}){const t=this._parentMarkedDirty(n.onlySelf);this.status=ia,this.errors=null,this._forEachChild(i=>{i.disable({...n,onlySelf:!0})}),this._updateValue();const r=n.sourceControl??this;!1!==n.emitEvent&&(this._events.next(new _I(this.value,r)),this._events.next(new zc(this.status,r)),this.valueChanges.emit(this.value),this.statusChanges.emit(this.status)),this._updateAncestors({...n,skipPristineCheck:t},this),this._onDisabledChange.forEach(i=>i(!0))}enable(n={}){const t=this._parentMarkedDirty(n.onlySelf);this.status=ra,this._forEachChild(r=>{r.enable({...n,onlySelf:!0})}),this.updateValueAndValidity({onlySelf:!0,emitEvent:n.emitEvent}),this._updateAncestors({...n,skipPristineCheck:t},this),this._onDisabledChange.forEach(r=>r(!1))}_updateAncestors(n,t){this._parent&&!n.onlySelf&&(this._parent.updateValueAndValidity(n),n.skipPristineCheck||this._parent._updatePristine({},t),this._parent._updateTouched({},t))}setParent(n){this._parent=n}getRawValue(){return this.value}updateValueAndValidity(n={}){if(this._setInitialStatus(),this._updateValue(),this.enabled){const r=this._cancelExistingSubscription();this.errors=this._runValidator(),this.status=this._calculateStatus(),(this.status===ra||this.status===Eo)&&this._runAsyncValidator(r,n.emitEvent)}const t=n.sourceControl??this;!1!==n.emitEvent&&(this._events.next(new _I(this.value,t)),this._events.next(new zc(this.status,t)),this.valueChanges.emit(this.value),this.statusChanges.emit(this.status)),this._parent&&!n.onlySelf&&this._parent.updateValueAndValidity({...n,sourceControl:t})}_updateTreeValidity(n={emitEvent:!0}){this._forEachChild(t=>t._updateTreeValidity(n)),this.updateValueAndValidity({onlySelf:!0,emitEvent:n.emitEvent})}_setInitialStatus(){this.status=this._allControlsDisabled()?ia:ra}_runValidator(){return this.validator?this.validator(this):null}_runAsyncValidator(n,t){if(this.asyncValidator){this.status=Eo,this._hasOwnPendingAsyncValidator={emitEvent:!1!==t};const r=iI(this.asyncValidator(this));this._asyncValidationSubscription=r.subscribe(i=>{this._hasOwnPendingAsyncValidator=null,this.setErrors(i,{emitEvent:t,shouldHaveEmitted:n})})}}_cancelExistingSubscription(){if(this._asyncValidationSubscription){this._asyncValidationSubscription.unsubscribe();const n=this._hasOwnPendingAsyncValidator?.emitEvent??!1;return this._hasOwnPendingAsyncValidator=null,n}return!1}setErrors(n,t={}){this.errors=n,this._updateControlsErrors(!1!==t.emitEvent,this,t.shouldHaveEmitted)}get(n){let t=n;return null==t||(Array.isArray(t)||(t=t.split(".")),0===t.length)?null:t.reduce((r,i)=>r&&r._find(i),this)}getError(n,t){const r=t?this.get(t):this;return r&&r.errors?r.errors[n]:null}hasError(n,t){return!!this.getError(n,t)}get root(){let n=this;for(;n._parent;)n=n._parent;return n}_updateControlsErrors(n,t,r){this.status=this._calculateStatus(),n&&this.statusChanges.emit(this.status),(n||r)&&this._events.next(new zc(this.status,t)),this._parent&&this._parent._updateControlsErrors(n,t,r)}_initObservables(){this.valueChanges=new we,this.statusChanges=new we}_calculateStatus(){return this._allControlsDisabled()?ia:this.errors?$c:this._hasOwnPendingAsyncValidator||this._anyControlsHaveStatus(Eo)?Eo:this._anyControlsHaveStatus($c)?$c:ra}_anyControlsHaveStatus(n){return this._anyControls(t=>t.status===n)}_anyControlsDirty(){return this._anyControls(n=>n.dirty)}_anyControlsTouched(){return this._anyControls(n=>n.touched)}_updatePristine(n,t){const r=!this._anyControlsDirty(),i=this.pristine!==r;this.pristine=r,this._parent&&!n.onlySelf&&this._parent._updatePristine(n,t),i&&this._events.next(new Og(this.pristine,t))}_updateTouched(n={},t){this.touched=this._anyControlsTouched(),this._events.next(new Ag(this.touched,t)),this._parent&&!n.onlySelf&&this._parent._updateTouched(n,t)}_onDisabledChange=[];_registerOnCollectionChange(n){this._onCollectionChange=n}_setUpdateStrategy(n){Gc(n)&&null!=n.updateOn&&(this._updateOn=n.updateOn)}_parentMarkedDirty(n){return!n&&!(!this._parent||!this._parent.dirty)&&!this._parent._anyControlsDirty()}_find(n){return null}_assignValidators(n){this._rawValidators=Array.isArray(n)?n.slice():n,this._composedValidatorFn=function SB(e){return Array.isArray(e)?Mg(e):e||null}(this._rawValidators)}_assignAsyncValidators(n){this._rawAsyncValidators=Array.isArray(n)?n.slice():n,this._composedAsyncValidatorFn=function NB(e){return Array.isArray(e)?Tg(e):e||null}(this._rawAsyncValidators)}}const Mo=new R("",{providedIn:"root",factory:()=>qc}),qc="always";function oa(e,n,t=qc){(function Pg(e,n){const t=function dI(e){return e._rawValidators}(e);null!==n.validator?e.setValidators(uI(t,n.validator)):"function"==typeof t&&e.setValidators([t]);const r=function fI(e){return e._rawAsyncValidators}(e);null!==n.asyncValidator?e.setAsyncValidators(uI(r,n.asyncValidator)):"function"==typeof r&&e.setAsyncValidators([r]);const i=()=>e.updateValueAndValidity();Qc(n._rawValidators,i),Qc(n._rawAsyncValidators,i)})(e,n),n.valueAccessor.writeValue(e.value),(e.disabled||"always"===t)&&n.valueAccessor.setDisabledState?.(e.disabled),function AB(e,n){n.valueAccessor.registerOnChange(t=>{e._pendingValue=t,e._pendingChange=!0,e._pendingDirty=!0,"change"===e.updateOn&&wI(e,n)})}(e,n),function kB(e,n){const t=(r,i)=>{n.valueAccessor.writeValue(r),i&&n.viewToModelUpdate(r)};e.registerOnChange(t),n._registerOnDestroy(()=>{e._unregisterOnChange(t)})}(e,n),function RB(e,n){n.valueAccessor.registerOnTouched(()=>{e._pendingTouched=!0,"blur"===e.updateOn&&e._pendingChange&&wI(e,n),"submit"!==e.updateOn&&e.markAsTouched()})}(e,n),function OB(e,n){if(n.valueAccessor.setDisabledState){const t=r=>{n.valueAccessor.setDisabledState(r)};e.registerOnDisabledChange(t),n._registerOnDestroy(()=>{e._unregisterOnDisabledChange(t)})}}(e,n)}function Qc(e,n){e.forEach(t=>{t.registerOnValidatorChange&&t.registerOnValidatorChange(n)})}function wI(e,n){e._pendingDirty&&e.markAsDirty(),e.setValue(e._pendingValue,{emitModelToViewChange:!1}),n.viewToModelUpdate(e._pendingValue),e._pendingChange=!1}function EI(e,n){const t=e.indexOf(n);t>-1&&e.splice(t,1)}function II(e){return"object"==typeof e&&null!==e&&2===Object.keys(e).length&&"value"in e&&"disabled"in e}Promise.resolve();const MI=class extends Fg{defaultValue=null;_onChange=[];_pendingValue;_pendingChange=!1;constructor(n=null,t,r){super(function Rg(e){return(Gc(e)?e.validators:e)||null}(t),function kg(e,n){return(Gc(n)?n.asyncValidators:e)||null}(r,t)),this._applyFormState(n),this._setUpdateStrategy(t),this._initObservables(),this.updateValueAndValidity({onlySelf:!0,emitEvent:!!this.asyncValidator}),Gc(t)&&(t.nonNullable||t.initialValueIsDefault)&&(this.defaultValue=II(n)?n.value:n)}setValue(n,t={}){this.value=this._pendingValue=n,this._onChange.length&&!1!==t.emitModelToViewChange&&this._onChange.forEach(r=>r(this.value,!1!==t.emitViewToModelChange)),this.updateValueAndValidity(t)}patchValue(n,t={}){this.setValue(n,t)}reset(n=this.defaultValue,t={}){this._applyFormState(n),this.markAsPristine(t),this.markAsUntouched(t),this.setValue(this.value,t),this._pendingChange=!1}_updateValue(){}_anyControls(n){return!1}_allControlsDisabled(){return this.disabled}registerOnChange(n){this._onChange.push(n)}_unregisterOnChange(n){EI(this._onChange,n)}registerOnDisabledChange(n){this._onDisabledChange.push(n)}_unregisterOnDisabledChange(n){EI(this._onDisabledChange,n)}_forEachChild(n){}_syncPendingControls(){return!("submit"!==this.updateOn||(this._pendingDirty&&this.markAsDirty(),this._pendingTouched&&this.markAsTouched(),!this._pendingChange)||(this.setValue(this._pendingValue,{onlySelf:!0,emitModelToViewChange:!1}),0))}_applyFormState(n){II(n)?(this.value=this._pendingValue=n.value,n.disabled?this.disable({onlySelf:!0,emitEvent:!1}):this.enable({onlySelf:!0,emitEvent:!1})):this.value=this._pendingValue=n}},UB={provide:Cr,useExisting:ve(()=>aa)},NI=Promise.resolve();let aa=(()=>{class e extends Cr{_changeDetectorRef;callSetDisabledState;control=new MI;static ngAcceptInputType_isDisabled;_registered=!1;viewModel;name="";isDisabled;model;options;update=new we;constructor(t,r,i,o,s,a){super(),this._changeDetectorRef=s,this.callSetDisabledState=a,this._parent=t,this._setValidators(r),this._setAsyncValidators(i),this.valueAccessor=function Bg(e,n){if(!n)return null;let t,r,i;return Array.isArray(n),n.forEach(o=>{o.constructor===na?t=o:function PB(e){return Object.getPrototypeOf(e.constructor)===di}(o)?r=o:i=o}),i||r||t||null}(0,o)}ngOnChanges(t){if(this._checkForErrors(),!this._registered||"name"in t){if(this._registered&&(this._checkName(),this.formDirective)){const r=t.name.previousValue;this.formDirective.removeControl({name:r,path:this._getPath(r)})}this._setUpControl()}"isDisabled"in t&&this._updateDisabled(t),function Hg(e,n){if(!e.hasOwnProperty("model"))return!1;const t=e.model;return!!t.isFirstChange()||!Object.is(n,t.currentValue)}(t,this.viewModel)&&(this._updateValue(this.model),this.viewModel=this.model)}ngOnDestroy(){this.formDirective&&this.formDirective.removeControl(this)}get path(){return this._getPath(this.name)}get formDirective(){return this._parent?this._parent.formDirective:null}viewToModelUpdate(t){this.viewModel=t,this.update.emit(t)}_setUpControl(){this._setUpdateStrategy(),this._isStandalone()?this._setUpStandalone():this.formDirective.addControl(this),this._registered=!0}_setUpdateStrategy(){this.options&&null!=this.options.updateOn&&(this.control._updateOn=this.options.updateOn)}_isStandalone(){return!this._parent||!(!this.options||!this.options.standalone)}_setUpStandalone(){oa(this.control,this,this.callSetDisabledState),this.control.updateValueAndValidity({emitEvent:!1})}_checkForErrors(){this._checkName()}_checkParentType(){}_checkName(){this.options&&this.options.name&&(this.name=this.options.name),this._isStandalone()}_updateValue(t){NI.then(()=>{this.control.setValue(t,{emitViewToModelChange:!1}),this._changeDetectorRef?.markForCheck()})}_updateDisabled(t){const r=t.isDisabled.currentValue,i=0!==r&&function qh(e){return"boolean"==typeof e?e:null!=e&&"false"!==e}(r);NI.then(()=>{i&&!this.control.disabled?this.control.disable():!i&&this.control.disabled&&this.control.enable(),this._changeDetectorRef?.markForCheck()})}_getPath(t){return this._parent?function Wc(e,n){return[...n.path,e]}(t,this._parent):[t]}static \u0275fac=function(r){return new(r||e)(T(Dt,9),T(ct,10),T(yr,10),T(dn,10),T(si,8),T(Mo,8))};static \u0275dir=Y({type:e,selectors:[["","ngModel","",3,"formControlName","",3,"formControl",""]],inputs:{name:"name",isDisabled:[0,"disabled","isDisabled"],model:[0,"ngModel","model"],options:[0,"ngModelOptions","options"]},outputs:{update:"ngModelChange"},exportAs:["ngModel"],standalone:!1,features:[Me([UB]),ue,kn]})}return e})();const WB={provide:dn,useExisting:ve(()=>Ug),multi:!0};let Ug=(()=>{class e extends di{writeValue(t){this.setProperty("value",parseFloat(t))}registerOnChange(t){this.onChange=r=>{t(""==r?null:parseFloat(r))}}static \u0275fac=(()=>{let t;return function(i){return(t||(t=lt(e)))(i||e)}})();static \u0275dir=Y({type:e,selectors:[["input","type","range","formControlName",""],["input","type","range","formControl",""],["input","type","range","ngModel",""]],hostBindings:function(r,i){1&r&&q("change",function(s){return i.onChange(s.target.value)})("input",function(s){return i.onChange(s.target.value)})("blur",function(){return i.onTouched()})},standalone:!1,features:[Me([WB]),ue]})}return e})();const XB={provide:dn,useExisting:ve(()=>la),multi:!0};function LI(e,n){return null==e?`${n}`:(n&&"object"==typeof n&&(n="Object"),`${e}: ${n}`.slice(0,50))}let la=(()=>{class e extends di{value;_optionMap=new Map;_idCounter=0;set compareWith(t){this._compareWith=t}_compareWith=Object.is;writeValue(t){this.value=t;const i=LI(this._getOptionId(t),t);this.setProperty("value",i)}registerOnChange(t){this.onChange=r=>{this.value=this._getOptionValue(r),t(this.value)}}_registerOption(){return(this._idCounter++).toString()}_getOptionId(t){for(const r of this._optionMap.keys())if(this._compareWith(this._optionMap.get(r),t))return r;return null}_getOptionValue(t){const r=function ej(e){return e.split(":")[0]}(t);return this._optionMap.has(r)?this._optionMap.get(r):t}static \u0275fac=(()=>{let t;return function(i){return(t||(t=lt(e)))(i||e)}})();static \u0275dir=Y({type:e,selectors:[["select","formControlName","",3,"multiple",""],["select","formControl","",3,"multiple",""],["select","ngModel","",3,"multiple",""]],hostBindings:function(r,i){1&r&&q("change",function(s){return i.onChange(s.target.value)})("blur",function(){return i.onTouched()})},inputs:{compareWith:"compareWith"},standalone:!1,features:[Me([XB]),ue]})}return e})(),qg=(()=>{class e{_element;_renderer;_select;id;constructor(t,r,i){this._element=t,this._renderer=r,this._select=i,this._select&&(this.id=this._select._registerOption())}set ngValue(t){null!=this._select&&(this._select._optionMap.set(this.id,t),this._setElementValue(LI(this.id,t)),this._select.writeValue(this._select.value))}set value(t){this._setElementValue(t),this._select&&this._select.writeValue(this._select.value)}_setElementValue(t){this._renderer.setProperty(this._element.nativeElement,"value",t)}ngOnDestroy(){this._select&&(this._select._optionMap.delete(this.id),this._select.writeValue(this._select.value))}static \u0275fac=function(r){return new(r||e)(T(pt),T(on),T(la,9))};static \u0275dir=Y({type:e,selectors:[["option"]],inputs:{ngValue:"ngValue",value:"value"},standalone:!1})}return e})();const tj={provide:dn,useExisting:ve(()=>Wg),multi:!0};function PI(e,n){return null==e?`${n}`:("string"==typeof n&&(n=`'${n}'`),n&&"object"==typeof n&&(n="Object"),`${e}: ${n}`.slice(0,50))}let Wg=(()=>{class e extends di{value;_optionMap=new Map;_idCounter=0;set compareWith(t){this._compareWith=t}_compareWith=Object.is;writeValue(t){let r;if(this.value=t,Array.isArray(t)){const i=t.map(o=>this._getOptionId(o));r=(o,s)=>{o._setSelected(i.indexOf(s.toString())>-1)}}else r=(i,o)=>{i._setSelected(!1)};this._optionMap.forEach(r)}registerOnChange(t){this.onChange=r=>{const i=[],o=r.selectedOptions;if(void 0!==o){const s=o;for(let a=0;a{let t;return function(i){return(t||(t=lt(e)))(i||e)}})();static \u0275dir=Y({type:e,selectors:[["select","multiple","","formControlName",""],["select","multiple","","formControl",""],["select","multiple","","ngModel",""]],hostBindings:function(r,i){1&r&&q("change",function(s){return i.onChange(s.target)})("blur",function(){return i.onTouched()})},inputs:{compareWith:"compareWith"},standalone:!1,features:[Me([tj]),ue]})}return e})(),Zg=(()=>{class e{_element;_renderer;_select;id;_value;constructor(t,r,i){this._element=t,this._renderer=r,this._select=i,this._select&&(this.id=this._select._registerOption(this))}set ngValue(t){null!=this._select&&(this._value=t,this._setElementValue(PI(this.id,t)),this._select.writeValue(this._select.value))}set value(t){this._select?(this._value=t,this._setElementValue(PI(this.id,t)),this._select.writeValue(this._select.value)):this._setElementValue(t)}_setElementValue(t){this._renderer.setProperty(this._element.nativeElement,"value",t)}_setSelected(t){this._renderer.setProperty(this._element.nativeElement,"selected",t)}ngOnDestroy(){this._select&&(this._select._optionMap.delete(this.id),this._select.writeValue(this._select.value))}static \u0275fac=function(r){return new(r||e)(T(pt),T(on),T(Wg,9))};static \u0275dir=Y({type:e,selectors:[["option"]],inputs:{ngValue:"ngValue",value:"value"},standalone:!1})}return e})(),dj=(()=>{class e{static \u0275fac=function(r){return new(r||e)};static \u0275mod=cr({type:e});static \u0275inj=Nn({})}return e})(),hj=(()=>{class e{static withConfig(t){return{ngModule:e,providers:[{provide:Mo,useValue:t.callSetDisabledState??qc}]}}static \u0275fac=function(r){return new(r||e)};static \u0275mod=cr({type:e});static \u0275inj=Nn({imports:[dj]})}return e})();class gj extends Rt{constructor(n,t){super()}schedule(n,t=0){return this}}const Kc={setInterval(e,n,...t){const{delegate:r}=Kc;return r?.setInterval?r.setInterval(e,n,...t):setInterval(e,n,...t)},clearInterval(e){const{delegate:n}=Kc;return(n?.clearInterval||clearInterval)(e)},delegate:void 0},WI={now:()=>(WI.delegate||Date).now(),delegate:void 0};class ca{constructor(n,t=ca.now){this.schedulerActionCtor=n,this.now=t}schedule(n,t=0,r){return new this.schedulerActionCtor(this,n).schedule(r,t)}}ca.now=WI.now;const ZI=new class mj extends ca{constructor(n,t=ca.now){super(n,t),this.actions=[],this._active=!1}flush(n){const{actions:t}=this;if(this._active)return void t.push(n);let r;this._active=!0;do{if(r=n.execute(n.state,n.delay))break}while(n=t.shift());if(this._active=!1,r){for(;n=t.shift();)n.unsubscribe();throw r}}}(class pj extends gj{constructor(n,t){super(n,t),this.scheduler=n,this.work=t,this.pending=!1}schedule(n,t=0){var r;if(this.closed)return this;this.state=n;const i=this.id,o=this.scheduler;return null!=i&&(this.id=this.recycleAsyncId(o,i,t)),this.pending=!0,this.delay=t,this.id=null!==(r=this.id)&&void 0!==r?r:this.requestAsyncId(o,this.id,t),this}requestAsyncId(n,t,r=0){return Kc.setInterval(n.flush.bind(n,this),r)}recycleAsyncId(n,t,r=0){if(null!=r&&this.delay===r&&!1===this.pending)return t;null!=t&&Kc.clearInterval(t)}execute(n,t){if(this.closed)return new Error("executing a cancelled action");this.pending=!1;const r=this._execute(n,t);if(r)return r;!1===this.pending&&null!=this.id&&(this.id=this.recycleAsyncId(this.scheduler,this.id,null))}_execute(n,t){let i,r=!1;try{this.work(n)}catch(o){r=!0,i=o||new Error("Scheduled action threw falsy error")}if(r)return this.unsubscribe(),i}unsubscribe(){if(!this.closed){const{id:n,scheduler:t}=this,{actions:r}=t;this.work=this.state=this.scheduler=null,this.pending=!1,pa(r,this),null!=n&&(this.id=this.recycleAsyncId(t,n,null)),this.delay=null,super.unsubscribe()}}}),vj=ZI;function QI(e,n=ZI,t){const r=function wj(e=0,n,t=vj){let r=-1;return null!=n&&(function yj(e){return e&&Be(e.schedule)}(n)?t=n:r=n),new kt(i=>{let o=function Cj(e){return e instanceof Date&&!isNaN(e)}(e)?+e-t.now():e;o<0&&(o=0);let s=0;return t.schedule(function(){i.closed||(i.next(s++),0<=r?this.schedule(void 0,r):i.complete())},o)})}(e,n);return function _j(e,n){return Nr((t,r)=>{const{leading:i=!0,trailing:o=!1}=n??{};let s=!1,a=null,l=null,c=!1;const u=()=>{l?.unsubscribe(),l=null,o&&(h(),c&&r.complete())},d=()=>{l=null,c&&r.complete()},g=m=>l=ta(e(m)).subscribe(qn(r,u,d)),h=()=>{if(s){s=!1;const m=a;a=null,r.next(m),!c&&g(m)}};t.subscribe(qn(r,m=>{s=!0,a=m,(!l||l.closed)&&(i?h():g(m))},()=>{c=!0,(!(o&&s&&l)||l.closed)&&r.complete()}))})}(()=>r,t)}function YI(e,n,t){const r=Be(e)||n||t?{next:e,error:n,complete:t}:e;return r?Nr((i,o)=>{var s;null===(s=r.subscribe)||void 0===s||s.call(r);let a=!0;i.subscribe(qn(o,l=>{var c;null===(c=r.next)||void 0===c||c.call(r,l),o.next(l)},()=>{var l;a=!1,null===(l=r.complete)||void 0===l||l.call(r),o.complete()},l=>{var c;a=!1,null===(c=r.error)||void 0===c||c.call(r,l),o.error(l)},()=>{var l,c;a&&(null===(l=r.unsubscribe)||void 0===l||l.call(r)),null===(c=r.finalize)||void 0===c||c.call(r)}))}):gu}function KI(e,n=gu){return e=e??Dj,Nr((t,r)=>{let i,o=!0;t.subscribe(qn(r,s=>{const a=n(s);(o||!e(i,a))&&(o=!1,i=a,r.next(s))}))})}function Dj(e,n){return e===n}var Bt=typeof window<"u"?window:{screen:{},navigator:{}},To=(Bt.matchMedia||function(){return{matches:!1}}).bind(Bt),JI=!1,XI=function(){};Bt.addEventListener&&Bt.addEventListener("p",XI,{get passive(){return JI=!0}}),Bt.removeEventListener&&Bt.removeEventListener("p",XI,!1);var eM=JI,Yg="ontouchstart"in Bt,nM=(Yg||"TouchEvent"in Bt&&To("(any-pointer: coarse)"),Bt.navigator.userAgent||"");To("(pointer: coarse)").matches&&/iPad|Macintosh/.test(nM)&&Math.min(Bt.screen.width||0,Bt.screen.height||0);(To("(pointer: coarse)").matches||!To("(pointer: fine)").matches&&Yg)&&/Windows.*Firefox/.test(nM),To("(any-pointer: fine)").matches||To("(any-hover: hover)");const Nj=(e,n,t)=>({tooltip:e,placement:n,content:t});function xj(e,n){}function Oj(e,n){1&e&&V(0,xj,0,0,"ng-template")}function Aj(e,n){if(1&e&&(X(0),V(1,Oj,1,0,null,1),ee()),2&e){const t=v();f(),p("ngTemplateOutlet",t.template)("ngTemplateOutletContext",Fe(2,Nj,t.tooltip,t.placement,t.content))}}function Rj(e,n){if(1&e&&(X(0),y(1,"div",2),b(2),_(),ee()),2&e){const t=v();f(),_t("title",t.tooltip)("data-tooltip-placement",t.placement),f(),U(" ",t.content," ")}}const kj=["tooltipTemplate"],Fj=["leftOuterSelectionBar"],Lj=["rightOuterSelectionBar"],Pj=["fullBar"],Vj=["selectionBar"],Hj=["minHandle"],Bj=["maxHandle"],jj=["floorLabel"],Uj=["ceilLabel"],$j=["minHandleLabel"],zj=["maxHandleLabel"],Gj=["combinedLabel"],qj=["ticksElement"],Wj=e=>({"ngx-slider-selected":e});function Zj(e,n){if(1&e&&x(0,"ngx-slider-tooltip-wrapper",32),2&e){const t=v().$implicit;p("template",v().tooltipTemplate)("tooltip",t.valueTooltip)("placement",t.valueTooltipPlacement)("content",t.value)}}function Qj(e,n){1&e&&x(0,"span",33),2&e&&p("innerText",v().$implicit.legend)}function Yj(e,n){1&e&&x(0,"span",34),2&e&&p("innerHTML",v().$implicit.legend,f_)}function Kj(e,n){if(1&e&&(y(0,"span",27),x(1,"ngx-slider-tooltip-wrapper",28),V(2,Zj,1,4,"ngx-slider-tooltip-wrapper",29)(3,Qj,1,1,"span",30)(4,Yj,1,1,"span",31),_()),2&e){const t=n.$implicit,r=v();p("ngClass",_o(8,Wj,t.selected))("ngStyle",t.style),f(),p("template",r.tooltipTemplate)("tooltip",t.tooltip)("placement",t.tooltipPlacement),f(),p("ngIf",null!=t.value),f(),p("ngIf",null!=t.legend&&!1===r.allowUnsafeHtmlInSlider),f(),p("ngIf",null!=t.legend&&(null==r.allowUnsafeHtmlInSlider||r.allowUnsafeHtmlInSlider))}}var Tn=function(e){return e[e.Low=0]="Low",e[e.High=1]="High",e[e.Floor=2]="Floor",e[e.Ceil=3]="Ceil",e[e.TickValue=4]="TickValue",e}(Tn||{});class Jc{floor=0;ceil=null;step=1;minRange=null;maxRange=null;pushRange=!1;minLimit=null;maxLimit=null;translate=null;combineLabels=null;getLegend=null;getStepLegend=null;stepsArray=null;bindIndexForStepsArray=!1;draggableRange=!1;draggableRangeOnly=!1;showSelectionBar=!1;showSelectionBarEnd=!1;showSelectionBarFromValue=null;showOuterSelectionBars=!1;hidePointerLabels=!1;hideLimitLabels=!1;autoHideLimitLabels=!0;readOnly=!1;disabled=!1;showTicks=!1;showTicksValues=!1;tickStep=null;tickValueStep=null;ticksArray=null;ticksTooltip=null;ticksValuesTooltip=null;vertical=!1;getSelectionBarColor=null;getTickColor=null;getPointerColor=null;keyboardSupport=!0;scale=1;rotate=0;enforceStep=!0;enforceRange=!0;enforceStepsArray=!0;noSwitching=!1;onlyBindHandles=!1;rightToLeft=!1;reversedControls=!1;boundPointerLabels=!0;logScale=!1;customValueToPosition=null;customPositionToValue=null;precisionLimit=12;selectionBarGradient=null;ariaLabel="ngx-slider";ariaLabelledBy=null;ariaLabelHigh="ngx-slider-max";ariaLabelledByHigh=null;handleDimension=null;barDimension=null;animate=!0;animateOnMove=!1}const oM=new R("AllowUnsafeHtmlInSlider");var F=function(e){return e[e.Min=0]="Min",e[e.Max=1]="Max",e}(F||{});class Jj{value;highValue;pointerType}class M{static isNullOrUndefined(n){return null==n}static areArraysEqual(n,t){if(n.length!==t.length)return!1;for(let r=0;rMath.abs(n-o.value));let i=0;for(let o=0;o{o.events.next(a)};return n.addEventListener(t,s,{passive:!0,capture:!1}),o.teardownCallback=()=>{n.removeEventListener(t,s,{passive:!0,capture:!1})},o.eventsSubscription=o.events.pipe(M.isNullOrUndefined(i)?YI(()=>{}):QI(i,void 0,{leading:!0,trailing:!0})).subscribe(a=>{r(a)}),o}detachEventListener(n){M.isNullOrUndefined(n.eventsSubscription)||(n.eventsSubscription.unsubscribe(),n.eventsSubscription=null),M.isNullOrUndefined(n.events)||(n.events.complete(),n.events=null),M.isNullOrUndefined(n.teardownCallback)||(n.teardownCallback(),n.teardownCallback=null)}attachEventListener(n,t,r,i){const o=new sM;return o.eventName=t,o.events=new fn,o.teardownCallback=this.renderer.listen(n,t,a=>{o.events.next(a)}),o.eventsSubscription=o.events.pipe(M.isNullOrUndefined(i)?YI(()=>{}):QI(i,void 0,{leading:!0,trailing:!0})).subscribe(a=>{r(a)}),o}}let Dr=(()=>{class e{elemRef;renderer;changeDetectionRef;_position=0;get position(){return this._position}_dimension=0;get dimension(){return this._dimension}_alwaysHide=!1;get alwaysHide(){return this._alwaysHide}_vertical=!1;get vertical(){return this._vertical}_scale=1;get scale(){return this._scale}_rotate=0;get rotate(){return this._rotate}opacity=1;visibility="visible";left="";bottom="";height="";width="";transform="";eventListenerHelper;eventListeners=[];constructor(t,r,i){this.elemRef=t,this.renderer=r,this.changeDetectionRef=i,this.eventListenerHelper=new aM(this.renderer)}setAlwaysHide(t){this._alwaysHide=t,this.visibility=t?"hidden":"visible"}hide(){this.opacity=0}show(){this.alwaysHide||(this.opacity=1)}isVisible(){return!this.alwaysHide&&0!==this.opacity}setVertical(t){this._vertical=t,this._vertical?(this.left="",this.width=""):(this.bottom="",this.height="")}setScale(t){this._scale=t}setRotate(t){this._rotate=t,this.transform="rotate("+t+"deg)"}getRotate(){return this._rotate}setPosition(t){this._position!==t&&!this.isRefDestroyed()&&this.changeDetectionRef.markForCheck(),this._position=t,this._vertical?this.bottom=Math.round(t)+"px":this.left=Math.round(t)+"px"}calculateDimension(){const t=this.getBoundingClientRect();this._dimension=this.vertical?(t.bottom-t.top)*this.scale:(t.right-t.left)*this.scale}setDimension(t){this._dimension!==t&&!this.isRefDestroyed()&&this.changeDetectionRef.markForCheck(),this._dimension=t,this._vertical?this.height=Math.round(t)+"px":this.width=Math.round(t)+"px"}getBoundingClientRect(){return this.elemRef.nativeElement.getBoundingClientRect()}on(t,r,i){const o=this.eventListenerHelper.attachEventListener(this.elemRef.nativeElement,t,r,i);this.eventListeners.push(o)}onPassive(t,r,i){const o=this.eventListenerHelper.attachPassiveEventListener(this.elemRef.nativeElement,t,r,i);this.eventListeners.push(o)}off(t){let r,i;M.isNullOrUndefined(t)?(r=[],i=this.eventListeners):(r=this.eventListeners.filter(o=>o.eventName!==t),i=this.eventListeners.filter(o=>o.eventName===t));for(const o of i)this.eventListenerHelper.detachEventListener(o);this.eventListeners=r}isRefDestroyed(){return M.isNullOrUndefined(this.changeDetectionRef)||this.changeDetectionRef.destroyed}static \u0275fac=function(r){return new(r||e)(T(pt),T(on),T(si))};static \u0275dir=Y({type:e,selectors:[["","ngxSliderElement",""]],hostVars:14,hostBindings:function(r,i){2&r&&ec("opacity",i.opacity)("visibility",i.visibility)("left",i.left)("bottom",i.bottom)("height",i.height)("width",i.width)("transform",i.transform)},standalone:!1})}return e})(),Kg=(()=>{class e extends Dr{active=!1;role="";tabindex="";ariaOrientation="";ariaLabel="";ariaLabelledBy="";ariaValueNow="";ariaValueText="";ariaValueMin="";ariaValueMax="";focus(){this.elemRef.nativeElement.focus()}focusIfNeeded(){document.activeElement!==this.elemRef.nativeElement&&this.elemRef.nativeElement.focus()}constructor(t,r,i){super(t,r,i)}static \u0275fac=function(r){return new(r||e)(T(pt),T(on),T(si))};static \u0275dir=Y({type:e,selectors:[["","ngxSliderHandle",""]],hostVars:11,hostBindings:function(r,i){2&r&&(_t("role",i.role)("tabindex",i.tabindex)("aria-orientation",i.ariaOrientation)("aria-label",i.ariaLabel)("aria-labelledby",i.ariaLabelledBy)("aria-valuenow",i.ariaValueNow)("aria-valuetext",i.ariaValueText)("aria-valuemin",i.ariaValueMin)("aria-valuemax",i.ariaValueMax),jn("ngx-slider-active",i.active))},standalone:!1,features:[ue]})}return e})(),So=(()=>{class e extends Dr{allowUnsafeHtmlInSlider;_value=null;get value(){return this._value}constructor(t,r,i,o){super(t,r,i),this.allowUnsafeHtmlInSlider=o}setValue(t){let r=!1;!this.alwaysHide&&(M.isNullOrUndefined(this.value)||this.value.length!==t.length||this.value.length>0&&0===this.dimension)&&(r=!0),this._value=t,!1===this.allowUnsafeHtmlInSlider?this.elemRef.nativeElement.innerText=t:this.elemRef.nativeElement.innerHTML=t,r&&this.calculateDimension()}static \u0275fac=function(r){return new(r||e)(T(pt),T(on),T(si),T(oM,8))};static \u0275dir=Y({type:e,selectors:[["","ngxSliderLabel",""]],standalone:!1,features:[ue]})}return e})(),Xj=(()=>{class e{template;tooltip;placement;content;static \u0275fac=function(r){return new(r||e)};static \u0275cmp=sn({type:e,selectors:[["ngx-slider-tooltip-wrapper"]],inputs:{template:"template",tooltip:"tooltip",placement:"placement",content:"content"},standalone:!1,decls:2,vars:2,consts:[[4,"ngIf"],[4,"ngTemplateOutlet","ngTemplateOutletContext"],[1,"ngx-slider-inner-tooltip"]],template:function(r,i){1&r&&V(0,Aj,2,6,"ng-container",0)(1,Rj,3,3,"ng-container",0),2&r&&(p("ngIf",i.template),f(),p("ngIf",!i.template))},dependencies:[zn,Kb],styles:[".ngx-slider-inner-tooltip[_ngcontent-%COMP%]{height:100%}"]})}return e})();class e3{selected=!1;style={};tooltip=null;tooltipPlacement=null;value=null;valueTooltip=null;valueTooltipPlacement=null;legend=null}class lM{active=!1;value=0;difference=0;position=0;lowLimit=0;highLimit=0}class Xc{value;highValue;static compare(n,t){return!(M.isNullOrUndefined(n)&&M.isNullOrUndefined(t)||M.isNullOrUndefined(n)!==M.isNullOrUndefined(t))&&n.value===t.value&&n.highValue===t.highValue}}class cM extends Xc{forceChange;static compare(n,t){return!(M.isNullOrUndefined(n)&&M.isNullOrUndefined(t)||M.isNullOrUndefined(n)!==M.isNullOrUndefined(t))&&n.value===t.value&&n.highValue===t.highValue&&n.forceChange===t.forceChange}}const t3={provide:dn,useExisting:ve(()=>uM),multi:!0};let uM=(()=>{class e{renderer;elementRef;changeDetectionRef;zone;allowUnsafeHtmlInSlider;sliderElementNgxSliderClass=!0;value=null;valueChange=new we;highValue=null;highValueChange=new we;options=new Jc;userChangeStart=new we;userChange=new we;userChangeEnd=new we;manualRefreshSubscription;set manualRefresh(t){this.unsubscribeManualRefresh(),this.manualRefreshSubscription=t.subscribe(()=>{setTimeout(()=>this.calculateViewDimensionsAndDetectChanges())})}triggerFocusSubscription;set triggerFocus(t){this.unsubscribeTriggerFocus(),this.triggerFocusSubscription=t.subscribe(r=>{this.focusPointer(r)})}cancelUserChangeSubscription;set cancelUserChange(t){this.unsubscribeCancelUserChange(),this.cancelUserChangeSubscription=t.subscribe(()=>{this.moving&&(this.positionTrackingHandle(this.preStartHandleValue),this.forceEnd(!0))})}get range(){return!M.isNullOrUndefined(this.value)&&!M.isNullOrUndefined(this.highValue)}initHasRun=!1;inputModelChangeSubject=new fn;inputModelChangeSubscription=null;outputModelChangeSubject=new fn;outputModelChangeSubscription=null;viewLowValue=null;viewHighValue=null;viewOptions=new Jc;handleHalfDimension=0;maxHandlePosition=0;currentTrackingPointer=null;currentFocusPointer=null;firstKeyDown=!1;touchId=null;dragging=new lM;preStartHandleValue=null;leftOuterSelectionBarElement;rightOuterSelectionBarElement;fullBarElement;selectionBarElement;minHandleElement;maxHandleElement;floorLabelElement;ceilLabelElement;minHandleLabelElement;maxHandleLabelElement;combinedLabelElement;ticksElement;tooltipTemplate;sliderElementVerticalClass=!1;sliderElementAnimateClass=!1;sliderElementWithLegendClass=!1;sliderElementDisabledAttr=null;sliderElementAriaLabel="ngx-slider";barStyle={};minPointerStyle={};maxPointerStyle={};fullBarTransparentClass=!1;selectionBarDraggableClass=!1;ticksUnderValuesClass=!1;get showTicks(){return this.viewOptions.showTicks}intermediateTicks=!1;ticks=[];eventListenerHelper=null;onMoveEventListener=null;onEndEventListener=null;moving=!1;resizeObserver=null;onTouchedCallback=null;onChangeCallback=null;constructor(t,r,i,o,s){this.renderer=t,this.elementRef=r,this.changeDetectionRef=i,this.zone=o,this.allowUnsafeHtmlInSlider=s,this.eventListenerHelper=new aM(this.renderer)}ngOnInit(){this.viewOptions=new Jc,Object.assign(this.viewOptions,this.options),this.updateDisabledState(),this.updateVerticalState(),this.updateAriaLabel()}ngAfterViewInit(){this.applyOptions(),this.subscribeInputModelChangeSubject(),this.subscribeOutputModelChangeSubject(),this.renormaliseModelValues(),this.viewLowValue=this.modelValueToViewValue(this.value),this.viewHighValue=this.range?this.modelValueToViewValue(this.highValue):null,this.updateVerticalState(),this.manageElementsStyle(),this.updateDisabledState(),this.calculateViewDimensions(),this.addAccessibility(),this.updateCeilLabel(),this.updateFloorLabel(),this.initHandles(),this.manageEventsBindings(),this.updateAriaLabel(),this.subscribeResizeObserver(),this.initHasRun=!0,this.isRefDestroyed()||this.changeDetectionRef.detectChanges()}ngOnChanges(t){!M.isNullOrUndefined(t.options)&&JSON.stringify(t.options.previousValue)!==JSON.stringify(t.options.currentValue)&&this.onChangeOptions(),(!M.isNullOrUndefined(t.value)||!M.isNullOrUndefined(t.highValue))&&this.inputModelChangeSubject.next({value:this.value,highValue:this.highValue,controlAccessorChange:!1,forceChange:!1,internalChange:!1})}ngOnDestroy(){this.unbindEvents(),this.unsubscribeResizeObserver(),this.unsubscribeInputModelChangeSubject(),this.unsubscribeOutputModelChangeSubject(),this.unsubscribeManualRefresh(),this.unsubscribeTriggerFocus()}writeValue(t){t instanceof Array?(this.value=t[0],this.highValue=t[1]):this.value=t,this.inputModelChangeSubject.next({value:this.value,highValue:this.highValue,forceChange:!1,internalChange:!1,controlAccessorChange:!0})}registerOnChange(t){this.onChangeCallback=t}registerOnTouched(t){this.onTouchedCallback=t}setDisabledState(t){this.viewOptions.disabled=t,this.updateDisabledState(),this.initHasRun&&this.manageEventsBindings()}setAriaLabel(t){this.viewOptions.ariaLabel=t,this.updateAriaLabel()}onResize(t){this.calculateViewDimensionsAndDetectChanges()}subscribeInputModelChangeSubject(){this.inputModelChangeSubscription=this.inputModelChangeSubject.pipe(KI(cM.compare),function bj(e,n){return Nr((t,r)=>{let i=0;t.subscribe(qn(r,o=>e.call(n,o,i++)&&r.next(o)))})}(t=>!t.forceChange&&!t.internalChange)).subscribe(t=>this.applyInputModelChange(t))}subscribeOutputModelChangeSubject(){this.outputModelChangeSubscription=this.outputModelChangeSubject.pipe(KI(cM.compare)).subscribe(t=>this.publishOutputModelChange(t))}subscribeResizeObserver(){wr.isResizeObserverAvailable()&&(this.resizeObserver=new ResizeObserver(()=>this.calculateViewDimensionsAndDetectChanges()),this.resizeObserver.observe(this.elementRef.nativeElement))}unsubscribeResizeObserver(){wr.isResizeObserverAvailable()&&null!==this.resizeObserver&&(this.resizeObserver.disconnect(),this.resizeObserver=null)}unsubscribeOnMove(){M.isNullOrUndefined(this.onMoveEventListener)||(this.eventListenerHelper.detachEventListener(this.onMoveEventListener),this.onMoveEventListener=null)}unsubscribeOnEnd(){M.isNullOrUndefined(this.onEndEventListener)||(this.eventListenerHelper.detachEventListener(this.onEndEventListener),this.onEndEventListener=null)}unsubscribeInputModelChangeSubject(){M.isNullOrUndefined(this.inputModelChangeSubscription)||(this.inputModelChangeSubscription.unsubscribe(),this.inputModelChangeSubscription=null)}unsubscribeOutputModelChangeSubject(){M.isNullOrUndefined(this.outputModelChangeSubscription)||(this.outputModelChangeSubscription.unsubscribe(),this.outputModelChangeSubscription=null)}unsubscribeManualRefresh(){M.isNullOrUndefined(this.manualRefreshSubscription)||(this.manualRefreshSubscription.unsubscribe(),this.manualRefreshSubscription=null)}unsubscribeTriggerFocus(){M.isNullOrUndefined(this.triggerFocusSubscription)||(this.triggerFocusSubscription.unsubscribe(),this.triggerFocusSubscription=null)}unsubscribeCancelUserChange(){M.isNullOrUndefined(this.cancelUserChangeSubscription)||(this.cancelUserChangeSubscription.unsubscribe(),this.cancelUserChangeSubscription=null)}getPointerElement(t){return t===F.Min?this.minHandleElement:t===F.Max?this.maxHandleElement:null}getCurrentTrackingValue(){return this.currentTrackingPointer===F.Min?this.viewLowValue:this.currentTrackingPointer===F.Max?this.viewHighValue:null}modelValueToViewValue(t){return M.isNullOrUndefined(t)?NaN:M.isNullOrUndefined(this.viewOptions.stepsArray)||this.viewOptions.bindIndexForStepsArray?+t:M.findStepIndex(+t,this.viewOptions.stepsArray)}viewValueToModelValue(t){return M.isNullOrUndefined(this.viewOptions.stepsArray)||this.viewOptions.bindIndexForStepsArray?t:this.getStepValue(t)}getStepValue(t){const r=this.viewOptions.stepsArray[t];return M.isNullOrUndefined(r)?NaN:r.value}applyViewChange(){this.value=this.viewValueToModelValue(this.viewLowValue),this.range&&(this.highValue=this.viewValueToModelValue(this.viewHighValue)),this.outputModelChangeSubject.next({value:this.value,highValue:this.highValue,controlAccessorChange:!1,userEventInitiated:!0,forceChange:!1}),this.inputModelChangeSubject.next({value:this.value,highValue:this.highValue,controlAccessorChange:!1,forceChange:!1,internalChange:!0})}applyInputModelChange(t){const r=this.normaliseModelValues(t),i=!Xc.compare(t,r);i&&(this.value=r.value,this.highValue=r.highValue),this.viewLowValue=this.modelValueToViewValue(r.value),this.viewHighValue=this.range?this.modelValueToViewValue(r.highValue):null,this.updateLowHandle(this.valueToPosition(this.viewLowValue)),this.range&&this.updateHighHandle(this.valueToPosition(this.viewHighValue)),this.updateSelectionBar(),this.updateTicksScale(),this.updateAriaAttributes(),this.range&&this.updateCombinedLabel(),this.outputModelChangeSubject.next({value:r.value,highValue:r.highValue,controlAccessorChange:t.controlAccessorChange,forceChange:i,userEventInitiated:!1})}publishOutputModelChange(t){const r=()=>{this.valueChange.emit(t.value),this.range&&this.highValueChange.emit(t.highValue),!t.controlAccessorChange&&(M.isNullOrUndefined(this.onChangeCallback)||this.onChangeCallback(this.range?[t.value,t.highValue]:t.value),M.isNullOrUndefined(this.onTouchedCallback)||this.onTouchedCallback(this.range?[t.value,t.highValue]:t.value))};t.userEventInitiated?(r(),this.userChange.emit(this.getChangeContext())):setTimeout(()=>{r()})}normaliseModelValues(t){const r=new Xc;if(r.value=t.value,r.highValue=t.highValue,!M.isNullOrUndefined(this.viewOptions.stepsArray)){if(this.viewOptions.enforceStepsArray){const i=M.findStepIndex(r.value,this.viewOptions.stepsArray);if(r.value=this.viewOptions.stepsArray[i].value,this.range){const o=M.findStepIndex(r.highValue,this.viewOptions.stepsArray);r.highValue=this.viewOptions.stepsArray[o].value}}return r}if(this.viewOptions.enforceStep&&(r.value=this.roundStep(r.value),this.range&&(r.highValue=this.roundStep(r.highValue))),this.viewOptions.enforceRange&&(r.value=He.clampToRange(r.value,this.viewOptions.floor,this.viewOptions.ceil),this.range&&(r.highValue=He.clampToRange(r.highValue,this.viewOptions.floor,this.viewOptions.ceil)),this.range&&t.value>t.highValue))if(this.viewOptions.noSwitching)r.value=r.highValue;else{const i=t.value;r.value=t.highValue,r.highValue=i}return r}renormaliseModelValues(){const t={value:this.value,highValue:this.highValue},r=this.normaliseModelValues(t);Xc.compare(r,t)||(this.value=r.value,this.highValue=r.highValue,this.outputModelChangeSubject.next({value:this.value,highValue:this.highValue,controlAccessorChange:!1,forceChange:!0,userEventInitiated:!1}))}onChangeOptions(){if(!this.initHasRun)return;const t=this.getOptionsInfluencingEventBindings(this.viewOptions);this.applyOptions();const r=this.getOptionsInfluencingEventBindings(this.viewOptions),i=!M.areArraysEqual(t,r);this.renormaliseModelValues(),this.viewLowValue=this.modelValueToViewValue(this.value),this.viewHighValue=this.range?this.modelValueToViewValue(this.highValue):null,this.resetSlider(i)}applyOptions(){if(this.viewOptions=new Jc,Object.assign(this.viewOptions,this.options),this.viewOptions.draggableRange=this.range&&this.viewOptions.draggableRange,this.viewOptions.draggableRangeOnly=this.range&&this.viewOptions.draggableRangeOnly,this.viewOptions.draggableRangeOnly&&(this.viewOptions.draggableRange=!0),this.viewOptions.showTicks=this.viewOptions.showTicks||this.viewOptions.showTicksValues||!M.isNullOrUndefined(this.viewOptions.ticksArray),this.viewOptions.showTicks&&(!M.isNullOrUndefined(this.viewOptions.tickStep)||!M.isNullOrUndefined(this.viewOptions.ticksArray))&&(this.intermediateTicks=!0),this.viewOptions.showSelectionBar=this.viewOptions.showSelectionBar||this.viewOptions.showSelectionBarEnd||!M.isNullOrUndefined(this.viewOptions.showSelectionBarFromValue),M.isNullOrUndefined(this.viewOptions.stepsArray)?this.applyFloorCeilOptions():this.applyStepsArrayOptions(),M.isNullOrUndefined(this.viewOptions.combineLabels)&&(this.viewOptions.combineLabels=(t,r)=>t+" - "+r),this.viewOptions.logScale&&0===this.viewOptions.floor)throw Error("Can't use floor=0 with logarithmic scale")}applyStepsArrayOptions(){this.viewOptions.floor=0,this.viewOptions.ceil=this.viewOptions.stepsArray.length-1,this.viewOptions.step=1,M.isNullOrUndefined(this.viewOptions.translate)&&(this.viewOptions.translate=t=>String(this.viewOptions.bindIndexForStepsArray?this.getStepValue(t):t))}applyFloorCeilOptions(){if(M.isNullOrUndefined(this.viewOptions.step)?this.viewOptions.step=1:(this.viewOptions.step=+this.viewOptions.step,this.viewOptions.step<=0&&(this.viewOptions.step=1)),M.isNullOrUndefined(this.viewOptions.ceil)||M.isNullOrUndefined(this.viewOptions.floor))throw Error("floor and ceil options must be supplied");this.viewOptions.ceil=+this.viewOptions.ceil,this.viewOptions.floor=+this.viewOptions.floor,M.isNullOrUndefined(this.viewOptions.translate)&&(this.viewOptions.translate=t=>String(t))}resetSlider(t=!0){this.manageElementsStyle(),this.addAccessibility(),this.updateCeilLabel(),this.updateFloorLabel(),t&&(this.unbindEvents(),this.manageEventsBindings()),this.updateDisabledState(),this.updateAriaLabel(),this.calculateViewDimensions(),this.refocusPointerIfNeeded()}focusPointer(t){t!==F.Min&&t!==F.Max&&(t=F.Min),t===F.Min?this.minHandleElement.focus():this.range&&t===F.Max&&this.maxHandleElement.focus()}refocusPointerIfNeeded(){M.isNullOrUndefined(this.currentFocusPointer)||this.getPointerElement(this.currentFocusPointer).focusIfNeeded()}manageElementsStyle(){this.updateScale(),this.floorLabelElement.setAlwaysHide(this.viewOptions.showTicksValues||this.viewOptions.hideLimitLabels),this.ceilLabelElement.setAlwaysHide(this.viewOptions.showTicksValues||this.viewOptions.hideLimitLabels);const t=this.viewOptions.showTicksValues&&!this.intermediateTicks;this.minHandleLabelElement.setAlwaysHide(t||this.viewOptions.hidePointerLabels),this.maxHandleLabelElement.setAlwaysHide(t||!this.range||this.viewOptions.hidePointerLabels),this.combinedLabelElement.setAlwaysHide(t||!this.range||this.viewOptions.hidePointerLabels),this.selectionBarElement.setAlwaysHide(!this.range&&!this.viewOptions.showSelectionBar),this.leftOuterSelectionBarElement.setAlwaysHide(!this.range||!this.viewOptions.showOuterSelectionBars),this.rightOuterSelectionBarElement.setAlwaysHide(!this.range||!this.viewOptions.showOuterSelectionBars),this.fullBarTransparentClass=this.range&&this.viewOptions.showOuterSelectionBars,this.selectionBarDraggableClass=this.viewOptions.draggableRange&&!this.viewOptions.onlyBindHandles,this.ticksUnderValuesClass=this.intermediateTicks&&this.options.showTicksValues,this.sliderElementVerticalClass!==this.viewOptions.vertical&&(this.updateVerticalState(),setTimeout(()=>{this.resetSlider()})),this.sliderElementAnimateClass!==this.viewOptions.animate&&setTimeout(()=>{this.sliderElementAnimateClass=this.viewOptions.animate}),this.updateRotate()}manageEventsBindings(){this.viewOptions.disabled||this.viewOptions.readOnly?this.unbindEvents():this.bindEvents()}updateDisabledState(){this.sliderElementDisabledAttr=this.viewOptions.disabled?"disabled":null}updateAriaLabel(){this.sliderElementAriaLabel=this.viewOptions.ariaLabel||"nxg-slider"}updateVerticalState(){this.sliderElementVerticalClass=this.viewOptions.vertical;for(const t of this.getAllSliderElements())M.isNullOrUndefined(t)||t.setVertical(this.viewOptions.vertical)}updateScale(){for(const t of this.getAllSliderElements())t.setScale(this.viewOptions.scale)}updateRotate(){for(const t of this.getAllSliderElements())t.setRotate(this.viewOptions.rotate)}getAllSliderElements(){return[this.leftOuterSelectionBarElement,this.rightOuterSelectionBarElement,this.fullBarElement,this.selectionBarElement,this.minHandleElement,this.maxHandleElement,this.floorLabelElement,this.ceilLabelElement,this.minHandleLabelElement,this.maxHandleLabelElement,this.combinedLabelElement,this.ticksElement]}initHandles(){this.updateLowHandle(this.valueToPosition(this.viewLowValue)),this.range&&this.updateHighHandle(this.valueToPosition(this.viewHighValue)),this.updateSelectionBar(),this.range&&this.updateCombinedLabel(),this.updateTicksScale()}addAccessibility(){this.updateAriaAttributes(),this.minHandleElement.role="slider",this.minHandleElement.tabindex=!this.viewOptions.keyboardSupport||this.viewOptions.readOnly||this.viewOptions.disabled?"":"0",this.minHandleElement.ariaOrientation=this.viewOptions.vertical||0!==this.viewOptions.rotate?"vertical":"horizontal",M.isNullOrUndefined(this.viewOptions.ariaLabel)?M.isNullOrUndefined(this.viewOptions.ariaLabelledBy)||(this.minHandleElement.ariaLabelledBy=this.viewOptions.ariaLabelledBy):this.minHandleElement.ariaLabel=this.viewOptions.ariaLabel,this.range&&(this.maxHandleElement.role="slider",this.maxHandleElement.tabindex=!this.viewOptions.keyboardSupport||this.viewOptions.readOnly||this.viewOptions.disabled?"":"0",this.maxHandleElement.ariaOrientation=this.viewOptions.vertical||0!==this.viewOptions.rotate?"vertical":"horizontal",M.isNullOrUndefined(this.viewOptions.ariaLabelHigh)?M.isNullOrUndefined(this.viewOptions.ariaLabelledByHigh)||(this.maxHandleElement.ariaLabelledBy=this.viewOptions.ariaLabelledByHigh):this.maxHandleElement.ariaLabel=this.viewOptions.ariaLabelHigh)}updateAriaAttributes(){this.minHandleElement.ariaValueNow=(+this.value).toString(),this.minHandleElement.ariaValueText=this.viewOptions.translate(+this.value,Tn.Low),this.minHandleElement.ariaValueMin=this.viewOptions.floor.toString(),this.minHandleElement.ariaValueMax=this.viewOptions.ceil.toString(),this.range&&(this.maxHandleElement.ariaValueNow=(+this.highValue).toString(),this.maxHandleElement.ariaValueText=this.viewOptions.translate(+this.highValue,Tn.High),this.maxHandleElement.ariaValueMin=this.viewOptions.floor.toString(),this.maxHandleElement.ariaValueMax=this.viewOptions.ceil.toString())}calculateViewDimensions(){M.isNullOrUndefined(this.viewOptions.handleDimension)?this.minHandleElement.calculateDimension():this.minHandleElement.setDimension(this.viewOptions.handleDimension);const t=this.minHandleElement.dimension;this.handleHalfDimension=t/2,M.isNullOrUndefined(this.viewOptions.barDimension)?this.fullBarElement.calculateDimension():this.fullBarElement.setDimension(this.viewOptions.barDimension),this.maxHandlePosition=this.fullBarElement.dimension-t,this.initHasRun&&(this.updateFloorLabel(),this.updateCeilLabel(),this.initHandles())}calculateViewDimensionsAndDetectChanges(){this.calculateViewDimensions(),this.isRefDestroyed()||this.changeDetectionRef.detectChanges()}isRefDestroyed(){return this.changeDetectionRef.destroyed}updateTicksScale(){if(!this.viewOptions.showTicks&&this.sliderElementWithLegendClass)return void setTimeout(()=>{this.sliderElementWithLegendClass=!1});const t=M.isNullOrUndefined(this.viewOptions.ticksArray)?this.getTicksArray():this.viewOptions.ticksArray,r=this.viewOptions.vertical?"translateY":"translateX";this.viewOptions.rightToLeft&&t.reverse();const i=M.isNullOrUndefined(this.viewOptions.tickValueStep)?M.isNullOrUndefined(this.viewOptions.tickStep)?this.viewOptions.step:this.viewOptions.tickStep:this.viewOptions.tickValueStep;let o=!1;const s=t.map(a=>{let l=this.valueToPosition(a);this.viewOptions.vertical&&(l=this.maxHandlePosition-l);const c=r+"("+Math.round(l)+"px)",u=new e3;u.selected=this.isTickSelected(a),u.style={"-webkit-transform":c,"-moz-transform":c,"-o-transform":c,"-ms-transform":c,transform:c},u.selected&&!M.isNullOrUndefined(this.viewOptions.getSelectionBarColor)&&(u.style["background-color"]=this.getSelectionBarColor()),!u.selected&&!M.isNullOrUndefined(this.viewOptions.getTickColor)&&(u.style["background-color"]=this.getTickColor(a)),M.isNullOrUndefined(this.viewOptions.ticksTooltip)||(u.tooltip=this.viewOptions.ticksTooltip(a),u.tooltipPlacement=this.viewOptions.vertical?"right":"top"),this.viewOptions.showTicksValues&&!M.isNullOrUndefined(i)&&He.isModuloWithinPrecisionLimit(a,i,this.viewOptions.precisionLimit)&&(u.value=this.getDisplayValue(a,Tn.TickValue),M.isNullOrUndefined(this.viewOptions.ticksValuesTooltip)||(u.valueTooltip=this.viewOptions.ticksValuesTooltip(a),u.valueTooltipPlacement=this.viewOptions.vertical?"right":"top"));let d=null;if(M.isNullOrUndefined(this.viewOptions.stepsArray))M.isNullOrUndefined(this.viewOptions.getLegend)||(d=this.viewOptions.getLegend(a));else{const g=this.viewOptions.stepsArray[a];M.isNullOrUndefined(this.viewOptions.getStepLegend)?M.isNullOrUndefined(g)||(d=g.legend):d=this.viewOptions.getStepLegend(g)}return M.isNullOrUndefined(d)||(u.legend=d,o=!0),u});if(this.sliderElementWithLegendClass!==o&&setTimeout(()=>{this.sliderElementWithLegendClass=o}),M.isNullOrUndefined(this.ticks)||this.ticks.length!==s.length)this.ticks=s,this.isRefDestroyed()||this.changeDetectionRef.detectChanges();else for(let a=0;a=this.viewLowValue)return!0}else if(this.viewOptions.showSelectionBar&&t<=this.viewLowValue)return!0}else{const r=this.viewOptions.showSelectionBarFromValue;if(this.viewLowValue>r&&t>=r&&t<=this.viewLowValue)return!0;if(this.viewLowValue=this.viewLowValue)return!0}return!!(this.range&&t>=this.viewLowValue&&t<=this.viewHighValue)}updateFloorLabel(){this.floorLabelElement.alwaysHide||(this.floorLabelElement.setValue(this.getDisplayValue(this.viewOptions.floor,Tn.Floor)),this.floorLabelElement.calculateDimension(),this.floorLabelElement.setPosition(this.viewOptions.rightToLeft?this.fullBarElement.dimension-this.floorLabelElement.dimension:0))}updateCeilLabel(){this.ceilLabelElement.alwaysHide||(this.ceilLabelElement.setValue(this.getDisplayValue(this.viewOptions.ceil,Tn.Ceil)),this.ceilLabelElement.calculateDimension(),this.ceilLabelElement.setPosition(this.viewOptions.rightToLeft?0:this.fullBarElement.dimension-this.ceilLabelElement.dimension))}updateHandles(t,r){t===F.Min?this.updateLowHandle(r):t===F.Max&&this.updateHighHandle(r),this.updateSelectionBar(),this.updateTicksScale(),this.range&&this.updateCombinedLabel()}getHandleLabelPos(t,r){const i=t===F.Min?this.minHandleLabelElement.dimension:this.maxHandleLabelElement.dimension,o=r-i/2+this.handleHalfDimension,s=this.fullBarElement.dimension-i;return this.viewOptions.boundPointerLabels?this.viewOptions.rightToLeft&&t===F.Min||!this.viewOptions.rightToLeft&&t===F.Max?Math.min(o,s):Math.min(Math.max(o,0),s):o}updateLowHandle(t){this.minHandleElement.setPosition(t),this.minHandleLabelElement.setValue(this.getDisplayValue(this.viewLowValue,Tn.Low)),this.minHandleLabelElement.setPosition(this.getHandleLabelPos(F.Min,t)),M.isNullOrUndefined(this.viewOptions.getPointerColor)||(this.minPointerStyle={backgroundColor:this.getPointerColor(F.Min)}),this.viewOptions.autoHideLimitLabels&&this.updateFloorAndCeilLabelsVisibility()}updateHighHandle(t){this.maxHandleElement.setPosition(t),this.maxHandleLabelElement.setValue(this.getDisplayValue(this.viewHighValue,Tn.High)),this.maxHandleLabelElement.setPosition(this.getHandleLabelPos(F.Max,t)),M.isNullOrUndefined(this.viewOptions.getPointerColor)||(this.maxPointerStyle={backgroundColor:this.getPointerColor(F.Max)}),this.viewOptions.autoHideLimitLabels&&this.updateFloorAndCeilLabelsVisibility()}updateFloorAndCeilLabelsVisibility(){if(this.viewOptions.hidePointerLabels)return;let t=!1,r=!1;const i=this.isLabelBelowFloorLabel(this.minHandleLabelElement),o=this.isLabelAboveCeilLabel(this.minHandleLabelElement),s=this.isLabelAboveCeilLabel(this.maxHandleLabelElement),a=this.isLabelBelowFloorLabel(this.combinedLabelElement),l=this.isLabelAboveCeilLabel(this.combinedLabelElement);if(i?(t=!0,this.floorLabelElement.hide()):(t=!1,this.floorLabelElement.show()),o?(r=!0,this.ceilLabelElement.hide()):(r=!1,this.ceilLabelElement.show()),this.range){const c=this.combinedLabelElement.isVisible()?l:s,u=this.combinedLabelElement.isVisible()?a:i;c?this.ceilLabelElement.hide():r||this.ceilLabelElement.show(),u?this.floorLabelElement.hide():t||this.floorLabelElement.show()}}isLabelBelowFloorLabel(t){const r=t.position,o=this.floorLabelElement.position;return this.viewOptions.rightToLeft?r+t.dimension>=o-2:r<=o+this.floorLabelElement.dimension+2}isLabelAboveCeilLabel(t){const r=t.position,o=this.ceilLabelElement.position;return this.viewOptions.rightToLeft?r<=o+this.ceilLabelElement.dimension+2:r+t.dimension>=o-2}updateSelectionBar(){let t=0,r=0;const i=this.viewOptions.rightToLeft?!this.viewOptions.showSelectionBarEnd:this.viewOptions.showSelectionBarEnd,o=this.viewOptions.rightToLeft?this.maxHandleElement.position+this.handleHalfDimension:this.minHandleElement.position+this.handleHalfDimension;if(this.range)r=Math.abs(this.maxHandleElement.position-this.minHandleElement.position),t=o;else if(M.isNullOrUndefined(this.viewOptions.showSelectionBarFromValue))i?(r=Math.ceil(Math.abs(this.maxHandlePosition-this.minHandleElement.position)+this.handleHalfDimension),t=Math.floor(this.minHandleElement.position+this.handleHalfDimension)):(r=this.minHandleElement.position+this.handleHalfDimension,t=0);else{const s=this.viewOptions.showSelectionBarFromValue,a=this.valueToPosition(s);(this.viewOptions.rightToLeft?this.viewLowValue<=s:this.viewLowValue>s)?(r=this.minHandleElement.position-a,t=a+this.handleHalfDimension):(r=a-this.minHandleElement.position,t=this.minHandleElement.position+this.handleHalfDimension)}if(this.selectionBarElement.setDimension(r),this.selectionBarElement.setPosition(t),this.range&&this.viewOptions.showOuterSelectionBars&&(this.viewOptions.rightToLeft?(this.rightOuterSelectionBarElement.setDimension(t),this.rightOuterSelectionBarElement.setPosition(0),this.fullBarElement.calculateDimension(),this.leftOuterSelectionBarElement.setDimension(this.fullBarElement.dimension-(t+r)),this.leftOuterSelectionBarElement.setPosition(t+r)):(this.leftOuterSelectionBarElement.setDimension(t),this.leftOuterSelectionBarElement.setPosition(0),this.fullBarElement.calculateDimension(),this.rightOuterSelectionBarElement.setDimension(this.fullBarElement.dimension-(t+r)),this.rightOuterSelectionBarElement.setPosition(t+r))),M.isNullOrUndefined(this.viewOptions.getSelectionBarColor)){if(!M.isNullOrUndefined(this.viewOptions.selectionBarGradient)){const s=M.isNullOrUndefined(this.viewOptions.showSelectionBarFromValue)?0:this.valueToPosition(this.viewOptions.showSelectionBarFromValue),a=s-t>0&&!i||s-t<=0&&i;this.barStyle={backgroundImage:"linear-gradient(to "+(this.viewOptions.vertical?a?"bottom":"top":a?"left":"right")+", "+this.viewOptions.selectionBarGradient.from+" 0%,"+this.viewOptions.selectionBarGradient.to+" 100%)"},this.viewOptions.vertical?(this.barStyle.backgroundPosition="center "+(s+r+t+(a?-this.handleHalfDimension:0))+"px",this.barStyle.backgroundSize="100% "+(this.fullBarElement.dimension-this.handleHalfDimension)+"px"):(this.barStyle.backgroundPosition=s-t+(a?this.handleHalfDimension:0)+"px center",this.barStyle.backgroundSize=this.fullBarElement.dimension-this.handleHalfDimension+"px 100%")}}else{const s=this.getSelectionBarColor();this.barStyle={backgroundColor:s}}}getSelectionBarColor(){return this.range?this.viewOptions.getSelectionBarColor(this.value,this.highValue):this.viewOptions.getSelectionBarColor(this.value)}getPointerColor(t){return this.viewOptions.getPointerColor(t===F.Max?this.highValue:this.value,t)}getTickColor(t){return this.viewOptions.getTickColor(t)}updateCombinedLabel(){let t=null;if(t=this.viewOptions.rightToLeft?this.minHandleLabelElement.position-this.minHandleLabelElement.dimension-10<=this.maxHandleLabelElement.position:this.minHandleLabelElement.position+this.minHandleLabelElement.dimension+10>=this.maxHandleLabelElement.position,t){const r=this.getDisplayValue(this.viewLowValue,Tn.Low),i=this.getDisplayValue(this.viewHighValue,Tn.High),o=this.viewOptions.rightToLeft?this.viewOptions.combineLabels(i,r):this.viewOptions.combineLabels(r,i);this.combinedLabelElement.setValue(o);const s=this.viewOptions.boundPointerLabels?Math.min(Math.max(this.selectionBarElement.position+this.selectionBarElement.dimension/2-this.combinedLabelElement.dimension/2,0),this.fullBarElement.dimension-this.combinedLabelElement.dimension):this.selectionBarElement.position+this.selectionBarElement.dimension/2-this.combinedLabelElement.dimension/2;this.combinedLabelElement.setPosition(s),this.minHandleLabelElement.hide(),this.maxHandleLabelElement.hide(),this.combinedLabelElement.show()}else this.updateHighHandle(this.valueToPosition(this.viewHighValue)),this.updateLowHandle(this.valueToPosition(this.viewLowValue)),this.maxHandleLabelElement.show(),this.minHandleLabelElement.show(),this.combinedLabelElement.hide();this.viewOptions.autoHideLimitLabels&&this.updateFloorAndCeilLabelsVisibility()}getDisplayValue(t,r){return!M.isNullOrUndefined(this.viewOptions.stepsArray)&&!this.viewOptions.bindIndexForStepsArray&&(t=this.getStepValue(t)),this.viewOptions.translate(t,r)}roundStep(t,r){const i=M.isNullOrUndefined(r)?this.viewOptions.step:r;let o=He.roundToPrecisionLimit((t-this.viewOptions.floor)/i,this.viewOptions.precisionLimit);return o=Math.round(o)*i,He.roundToPrecisionLimit(this.viewOptions.floor+o,this.viewOptions.precisionLimit)}valueToPosition(t){let r=M.linearValueToPosition;M.isNullOrUndefined(this.viewOptions.customValueToPosition)?this.viewOptions.logScale&&(r=M.logValueToPosition):r=this.viewOptions.customValueToPosition;let i=r(t=He.clampToRange(t,this.viewOptions.floor,this.viewOptions.ceil),this.viewOptions.floor,this.viewOptions.ceil);return M.isNullOrUndefined(i)&&(i=0),this.viewOptions.rightToLeft&&(i=1-i),i*this.maxHandlePosition}positionToValue(t){let r=t/this.maxHandlePosition;this.viewOptions.rightToLeft&&(r=1-r);let i=M.linearPositionToValue;M.isNullOrUndefined(this.viewOptions.customPositionToValue)?this.viewOptions.logScale&&(i=M.logPositionToValue):i=this.viewOptions.customPositionToValue;const o=i(r,this.viewOptions.floor,this.viewOptions.ceil);return M.isNullOrUndefined(o)?0:o}getEventXY(t,r){if(t instanceof MouseEvent)return this.viewOptions.vertical||0!==this.viewOptions.rotate?t.clientY:t.clientX;let i=0;const o=t.touches;if(!M.isNullOrUndefined(r))for(let s=0;so?F.Max:this.viewOptions.rightToLeft?r>this.minHandleElement.position?F.Min:F.Max:rthis.onBarStart(null,t,r,!0,!0,!0)),this.viewOptions.draggableRangeOnly?(this.minHandleElement.on("mousedown",r=>this.onBarStart(F.Min,t,r,!0,!0)),this.maxHandleElement.on("mousedown",r=>this.onBarStart(F.Max,t,r,!0,!0))):(this.minHandleElement.on("mousedown",r=>this.onStart(F.Min,r,!0,!0)),this.range&&this.maxHandleElement.on("mousedown",r=>this.onStart(F.Max,r,!0,!0)),this.viewOptions.onlyBindHandles||(this.fullBarElement.on("mousedown",r=>this.onStart(null,r,!0,!0,!0)),this.ticksElement.on("mousedown",r=>this.onStart(null,r,!0,!0,!0,!0)))),this.viewOptions.onlyBindHandles||this.selectionBarElement.onPassive("touchstart",r=>this.onBarStart(null,t,r,!0,!0,!0)),this.viewOptions.draggableRangeOnly?(this.minHandleElement.onPassive("touchstart",r=>this.onBarStart(F.Min,t,r,!0,!0)),this.maxHandleElement.onPassive("touchstart",r=>this.onBarStart(F.Max,t,r,!0,!0))):(this.minHandleElement.onPassive("touchstart",r=>this.onStart(F.Min,r,!0,!0)),this.range&&this.maxHandleElement.onPassive("touchstart",r=>this.onStart(F.Max,r,!0,!0)),this.viewOptions.onlyBindHandles||(this.fullBarElement.onPassive("touchstart",r=>this.onStart(null,r,!0,!0,!0)),this.ticksElement.onPassive("touchstart",r=>this.onStart(null,r,!1,!1,!0,!0)))),this.viewOptions.keyboardSupport&&(this.minHandleElement.on("focus",()=>this.onPointerFocus(F.Min)),this.range&&this.maxHandleElement.on("focus",()=>this.onPointerFocus(F.Max)))}getOptionsInfluencingEventBindings(t){return[t.disabled,t.readOnly,t.draggableRange,t.draggableRangeOnly,t.onlyBindHandles,t.keyboardSupport]}unbindEvents(){this.unsubscribeOnMove(),this.unsubscribeOnEnd();for(const t of this.getAllSliderElements())M.isNullOrUndefined(t)||t.off()}onBarStart(t,r,i,o,s,a,l){r?this.onDragStart(t,i,o,s):this.onStart(t,i,o,s,a,l)}onStart(t,r,i,o,s,a){r.stopPropagation(),!wr.isTouchEvent(r)&&!eM&&r.preventDefault(),this.moving=!1,this.calculateViewDimensions(),M.isNullOrUndefined(t)&&(t=this.getNearestHandle(r)),this.currentTrackingPointer=t;const l=this.getPointerElement(t);if(l.active=!0,this.preStartHandleValue=this.getCurrentTrackingValue(),this.viewOptions.keyboardSupport&&l.focus(),i){this.unsubscribeOnMove();const c=u=>this.dragging.active?this.onDragMove(u):this.onMove(u);this.onMoveEventListener=wr.isTouchEvent(r)?this.eventListenerHelper.attachPassiveEventListener(document,"touchmove",c):this.eventListenerHelper.attachEventListener(document,"mousemove",c)}if(o){this.unsubscribeOnEnd();const c=u=>this.onEnd(u);this.onEndEventListener=wr.isTouchEvent(r)?this.eventListenerHelper.attachPassiveEventListener(document,"touchend",c):this.eventListenerHelper.attachEventListener(document,"mouseup",c)}this.userChangeStart.emit(this.getChangeContext()),wr.isTouchEvent(r)&&!M.isNullOrUndefined(r.changedTouches)&&M.isNullOrUndefined(this.touchId)&&(this.touchId=r.changedTouches[0].identifier),s&&this.onMove(r,!0),a&&this.onEnd(r)}onMove(t,r){let i=null;if(wr.isTouchEvent(t)){const c=t.changedTouches;for(let u=0;u=this.maxHandlePosition?s=this.viewOptions.rightToLeft?this.viewOptions.floor:this.viewOptions.ceil:(s=this.positionToValue(o),s=r&&!M.isNullOrUndefined(this.viewOptions.tickStep)?this.roundStep(s,this.viewOptions.tickStep):this.roundStep(s)),this.positionTrackingHandle(s)}forceEnd(t=!1){this.moving=!1,this.viewOptions.animate&&(this.sliderElementAnimateClass=!0),t&&(this.sliderElementAnimateClass=!1,setTimeout(()=>{this.sliderElementAnimateClass=this.viewOptions.animate})),this.touchId=null,this.viewOptions.keyboardSupport||(this.minHandleElement.active=!1,this.maxHandleElement.active=!1,this.currentTrackingPointer=null),this.dragging.active=!1,this.unsubscribeOnMove(),this.unsubscribeOnEnd(),this.userChangeEnd.emit(this.getChangeContext())}onEnd(t){wr.isTouchEvent(t)&&t.changedTouches[0].identifier!==this.touchId||this.forceEnd()}onPointerFocus(t){const r=this.getPointerElement(t);r.on("blur",()=>this.onPointerBlur(r)),r.on("keydown",i=>this.onKeyboardEvent(i)),r.on("keyup",()=>this.onKeyUp()),r.active=!0,this.currentTrackingPointer=t,this.currentFocusPointer=t,this.firstKeyDown=!0}onKeyUp(){this.firstKeyDown=!0,this.userChangeEnd.emit(this.getChangeContext())}onPointerBlur(t){t.off("blur"),t.off("keydown"),t.off("keyup"),t.active=!1,M.isNullOrUndefined(this.touchId)&&(this.currentTrackingPointer=null,this.currentFocusPointer=null)}getKeyActions(t){const r=this.viewOptions.ceil-this.viewOptions.floor;let i=t+this.viewOptions.step,o=t-this.viewOptions.step,s=t+r/10,a=t-r/10;this.viewOptions.reversedControls&&(i=t-this.viewOptions.step,o=t+this.viewOptions.step,s=t-r/10,a=t+r/10);const l={UP:i,DOWN:o,LEFT:o,RIGHT:i,PAGEUP:s,PAGEDOWN:a,HOME:this.viewOptions.reversedControls?this.viewOptions.ceil:this.viewOptions.floor,END:this.viewOptions.reversedControls?this.viewOptions.floor:this.viewOptions.ceil};return this.viewOptions.rightToLeft&&(l.LEFT=i,l.RIGHT=o,(this.viewOptions.vertical||0!==this.viewOptions.rotate)&&(l.UP=o,l.DOWN=i)),l}onKeyboardEvent(t){const r=this.getCurrentTrackingValue(),i=M.isNullOrUndefined(t.keyCode)?t.which:t.keyCode,l=this.getKeyActions(r)[{38:"UP",40:"DOWN",37:"LEFT",39:"RIGHT",33:"PAGEUP",34:"PAGEDOWN",36:"HOME",35:"END"}[i]];if(M.isNullOrUndefined(l)||M.isNullOrUndefined(this.currentTrackingPointer))return;t.preventDefault(),this.firstKeyDown&&(this.firstKeyDown=!1,this.userChangeStart.emit(this.getChangeContext()));const c=He.clampToRange(l,this.viewOptions.floor,this.viewOptions.ceil),u=this.roundStep(c);if(this.viewOptions.draggableRangeOnly){const d=this.viewHighValue-this.viewLowValue;let g,h;this.currentTrackingPointer===F.Min?(g=u,h=u+d,h>this.viewOptions.ceil&&(h=this.viewOptions.ceil,g=h-d)):this.currentTrackingPointer===F.Max&&(h=u,g=u-d,g=this.maxHandlePosition-i;let u,d;if(r<=o){if(0===s.position)return;u=this.getMinValue(r,!0,!1),d=this.getMaxValue(r,!0,!1)}else if(c){if(a.position===this.maxHandlePosition)return;d=this.getMaxValue(r,!0,!0),u=this.getMinValue(r,!0,!0)}else u=this.getMinValue(r,!1,!1),d=this.getMaxValue(r,!1,!1);this.positionTrackingBar(u,d)}positionTrackingBar(t,r){!M.isNullOrUndefined(this.viewOptions.minLimit)&&tthis.viewOptions.maxLimit&&(t=He.roundToPrecisionLimit((r=this.viewOptions.maxLimit)-this.dragging.difference,this.viewOptions.precisionLimit)),this.viewLowValue=t,this.viewHighValue=r,this.applyViewChange(),this.updateHandles(F.Min,this.valueToPosition(t)),this.updateHandles(F.Max,this.valueToPosition(r))}positionTrackingHandle(t){t=this.applyMinMaxLimit(t),this.range&&(this.viewOptions.pushRange?t=this.applyPushRange(t):(this.viewOptions.noSwitching&&(this.currentTrackingPointer===F.Min&&t>this.viewHighValue?t=this.applyMinMaxRange(this.viewHighValue):this.currentTrackingPointer===F.Max&&tthis.viewHighValue?(this.viewLowValue=this.viewHighValue,this.applyViewChange(),this.updateHandles(F.Min,this.maxHandleElement.position),this.updateAriaAttributes(),this.currentTrackingPointer=F.Max,this.minHandleElement.active=!1,this.maxHandleElement.active=!0,this.viewOptions.keyboardSupport&&this.maxHandleElement.focus()):this.currentTrackingPointer===F.Max&&tthis.viewOptions.maxLimit?this.viewOptions.maxLimit:t}applyMinMaxRange(t){const i=Math.abs(t-(this.currentTrackingPointer===F.Min?this.viewHighValue:this.viewLowValue));if(!M.isNullOrUndefined(this.viewOptions.minRange)&&ithis.viewOptions.maxRange){if(this.currentTrackingPointer===F.Min)return He.roundToPrecisionLimit(this.viewHighValue-this.viewOptions.maxRange,this.viewOptions.precisionLimit);if(this.currentTrackingPointer===F.Max)return He.roundToPrecisionLimit(this.viewLowValue+this.viewOptions.maxRange,this.viewOptions.precisionLimit)}return t}applyPushRange(t){const r=this.currentTrackingPointer===F.Min?this.viewHighValue-t:t-this.viewLowValue,i=M.isNullOrUndefined(this.viewOptions.minRange)?this.viewOptions.step:this.viewOptions.minRange,o=this.viewOptions.maxRange;return ro&&(this.currentTrackingPointer===F.Min?(this.viewHighValue=He.roundToPrecisionLimit(t+o,this.viewOptions.precisionLimit),this.applyViewChange(),this.updateHandles(F.Max,this.valueToPosition(this.viewHighValue))):this.currentTrackingPointer===F.Max&&(this.viewLowValue=He.roundToPrecisionLimit(t-o,this.viewOptions.precisionLimit),this.applyViewChange(),this.updateHandles(F.Min,this.valueToPosition(this.viewLowValue))),this.updateAriaAttributes()),t}getChangeContext(){const t=new Jj;return t.pointerType=this.currentTrackingPointer,t.value=+this.value,this.range&&(t.highValue=+this.highValue),t}static \u0275fac=function(r){return new(r||e)(T(on),T(pt),T(si),T(de),T(oM,8))};static \u0275cmp=sn({type:e,selectors:[["ngx-slider"]],contentQueries:function(r,i,o){if(1&r&&Zw(o,kj,5),2&r){let s;Ot(s=At())&&(i.tooltipTemplate=s.first)}},viewQuery:function(r,i){if(1&r&&(Vt(Fj,5,Dr),Vt(Lj,5,Dr),Vt(Pj,5,Dr),Vt(Vj,5,Dr),Vt(Hj,5,Kg),Vt(Bj,5,Kg),Vt(jj,5,So),Vt(Uj,5,So),Vt($j,5,So),Vt(zj,5,So),Vt(Gj,5,So),Vt(qj,5,Dr)),2&r){let o;Ot(o=At())&&(i.leftOuterSelectionBarElement=o.first),Ot(o=At())&&(i.rightOuterSelectionBarElement=o.first),Ot(o=At())&&(i.fullBarElement=o.first),Ot(o=At())&&(i.selectionBarElement=o.first),Ot(o=At())&&(i.minHandleElement=o.first),Ot(o=At())&&(i.maxHandleElement=o.first),Ot(o=At())&&(i.floorLabelElement=o.first),Ot(o=At())&&(i.ceilLabelElement=o.first),Ot(o=At())&&(i.minHandleLabelElement=o.first),Ot(o=At())&&(i.maxHandleLabelElement=o.first),Ot(o=At())&&(i.combinedLabelElement=o.first),Ot(o=At())&&(i.ticksElement=o.first)}},hostVars:10,hostBindings:function(r,i){1&r&&q("resize",function(s){return i.onResize(s)},0,El),2&r&&(_t("disabled",i.sliderElementDisabledAttr)("aria-label",i.sliderElementAriaLabel),jn("ngx-slider",i.sliderElementNgxSliderClass)("vertical",i.sliderElementVerticalClass)("animate",i.sliderElementAnimateClass)("with-legend",i.sliderElementWithLegendClass))},inputs:{value:"value",highValue:"highValue",options:"options",manualRefresh:"manualRefresh",triggerFocus:"triggerFocus",cancelUserChange:"cancelUserChange"},outputs:{valueChange:"valueChange",highValueChange:"highValueChange",userChangeStart:"userChangeStart",userChange:"userChange",userChangeEnd:"userChangeEnd"},standalone:!1,features:[Me([t3]),kn],decls:29,vars:13,consts:[["leftOuterSelectionBar",""],["rightOuterSelectionBar",""],["fullBar",""],["selectionBar",""],["minHandle",""],["maxHandle",""],["floorLabel",""],["ceilLabel",""],["minHandleLabel",""],["maxHandleLabel",""],["combinedLabel",""],["ticksElement",""],["ngxSliderElement","",1,"ngx-slider-span","ngx-slider-bar-wrapper","ngx-slider-left-out-selection"],[1,"ngx-slider-span","ngx-slider-bar"],["ngxSliderElement","",1,"ngx-slider-span","ngx-slider-bar-wrapper","ngx-slider-right-out-selection"],["ngxSliderElement","",1,"ngx-slider-span","ngx-slider-bar-wrapper","ngx-slider-full-bar"],["ngxSliderElement","",1,"ngx-slider-span","ngx-slider-bar-wrapper","ngx-slider-selection-bar"],[1,"ngx-slider-span","ngx-slider-bar","ngx-slider-selection",3,"ngStyle"],["ngxSliderHandle","",1,"ngx-slider-span","ngx-slider-pointer","ngx-slider-pointer-min",3,"ngStyle"],["ngxSliderHandle","",1,"ngx-slider-span","ngx-slider-pointer","ngx-slider-pointer-max",3,"ngStyle"],["ngxSliderLabel","",1,"ngx-slider-span","ngx-slider-bubble","ngx-slider-limit","ngx-slider-floor"],["ngxSliderLabel","",1,"ngx-slider-span","ngx-slider-bubble","ngx-slider-limit","ngx-slider-ceil"],["ngxSliderLabel","",1,"ngx-slider-span","ngx-slider-bubble","ngx-slider-model-value"],["ngxSliderLabel","",1,"ngx-slider-span","ngx-slider-bubble","ngx-slider-model-high"],["ngxSliderLabel","",1,"ngx-slider-span","ngx-slider-bubble","ngx-slider-combined"],["ngxSliderElement","",1,"ngx-slider-ticks",3,"hidden"],["class","ngx-slider-tick",3,"ngClass","ngStyle",4,"ngFor","ngForOf"],[1,"ngx-slider-tick",3,"ngClass","ngStyle"],[3,"template","tooltip","placement"],["class","ngx-slider-span ngx-slider-tick-value",3,"template","tooltip","placement","content",4,"ngIf"],["class","ngx-slider-span ngx-slider-tick-legend",3,"innerText",4,"ngIf"],["class","ngx-slider-span ngx-slider-tick-legend",3,"innerHTML",4,"ngIf"],[1,"ngx-slider-span","ngx-slider-tick-value",3,"template","tooltip","placement","content"],[1,"ngx-slider-span","ngx-slider-tick-legend",3,"innerText"],[1,"ngx-slider-span","ngx-slider-tick-legend",3,"innerHTML"]],template:function(r,i){1&r&&(y(0,"span",12,0),x(2,"span",13),_(),y(3,"span",14,1),x(5,"span",13),_(),y(6,"span",15,2),x(8,"span",13),_(),y(9,"span",16,3),x(11,"span",17),_(),x(12,"span",18,4)(14,"span",19,5)(16,"span",20,6)(18,"span",21,7)(20,"span",22,8)(22,"span",23,9)(24,"span",24,10),y(26,"span",25,11),V(28,Kj,5,10,"span",26),_()),2&r&&(f(6),jn("ngx-slider-transparent",i.fullBarTransparentClass),f(3),jn("ngx-slider-draggable",i.selectionBarDraggableClass),f(2),p("ngStyle",i.barStyle),f(),p("ngStyle",i.minPointerStyle),f(2),ec("display",i.range?"inherit":"none"),p("ngStyle",i.maxPointerStyle),f(12),jn("ngx-slider-ticks-values-under",i.ticksUnderValuesClass),p("hidden",!i.showTicks),f(2),p("ngForOf",i.ticks))},dependencies:[Do,ci,zn,Yb,Dr,Kg,So,Xj],styles:['.ngx-slider{display:inline-block;position:relative;height:4px;width:100%;margin:35px 0 15px;vertical-align:middle;-webkit-user-select:none;user-select:none;touch-action:pan-y} .ngx-slider.with-legend{margin-bottom:40px} .ngx-slider[disabled]{cursor:not-allowed} .ngx-slider[disabled] .ngx-slider-pointer{cursor:not-allowed;background-color:#d8e0f3} .ngx-slider[disabled] .ngx-slider-draggable{cursor:not-allowed} .ngx-slider[disabled] .ngx-slider-selection{background:#8b91a2} .ngx-slider[disabled] .ngx-slider-tick{cursor:not-allowed} .ngx-slider[disabled] .ngx-slider-tick.ngx-slider-selected{background:#8b91a2} .ngx-slider .ngx-slider-span{white-space:nowrap;position:absolute;display:inline-block} .ngx-slider .ngx-slider-base{width:100%;height:100%;padding:0} .ngx-slider .ngx-slider-bar-wrapper{left:0;box-sizing:border-box;margin-top:-16px;padding-top:16px;width:100%;height:32px;z-index:1} .ngx-slider .ngx-slider-draggable{cursor:move} .ngx-slider .ngx-slider-bar{left:0;width:100%;height:4px;z-index:1;background:#d8e0f3;-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px} .ngx-slider .ngx-slider-bar-wrapper.ngx-slider-transparent .ngx-slider-bar{background:transparent} .ngx-slider .ngx-slider-bar-wrapper.ngx-slider-left-out-selection .ngx-slider-bar{background:#df002d} .ngx-slider .ngx-slider-bar-wrapper.ngx-slider-right-out-selection .ngx-slider-bar{background:#03a688} .ngx-slider .ngx-slider-selection{z-index:2;background:#0db9f0;-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px} .ngx-slider .ngx-slider-pointer{cursor:pointer;width:32px;height:32px;top:-14px;background-color:#0db9f0;z-index:3;-webkit-border-radius:16px;-moz-border-radius:16px;border-radius:16px} .ngx-slider .ngx-slider-pointer:after{content:"";width:8px;height:8px;position:absolute;top:12px;left:12px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;background:#fff} .ngx-slider .ngx-slider-pointer:hover:after{background-color:#fff} .ngx-slider .ngx-slider-pointer.ngx-slider-active{z-index:4} .ngx-slider .ngx-slider-pointer.ngx-slider-active:after{background-color:#451aff} .ngx-slider .ngx-slider-bubble{cursor:default;bottom:16px;padding:1px 3px;color:#55637d;font-size:16px} .ngx-slider .ngx-slider-bubble.ngx-slider-limit{color:#55637d} .ngx-slider .ngx-slider-ticks{box-sizing:border-box;width:100%;height:0;position:absolute;left:0;top:-3px;margin:0;z-index:1;list-style:none} .ngx-slider .ngx-slider-ticks-values-under .ngx-slider-tick-value{top:auto;bottom:-36px} .ngx-slider .ngx-slider-tick{text-align:center;cursor:pointer;width:10px;height:10px;background:#d8e0f3;border-radius:50%;position:absolute;top:0;left:0;margin-left:11px} .ngx-slider .ngx-slider-tick.ngx-slider-selected{background:#0db9f0} .ngx-slider .ngx-slider-tick-value{position:absolute;top:-34px;transform:translate(-50%)} .ngx-slider .ngx-slider-tick-legend{position:absolute;top:24px;transform:translate(-50%);max-width:50px;white-space:normal} .ngx-slider.vertical{position:relative;width:4px;height:100%;margin:0 20px;padding:0;vertical-align:baseline;touch-action:pan-x} .ngx-slider.vertical .ngx-slider-base{width:100%;height:100%;padding:0} .ngx-slider.vertical .ngx-slider-bar-wrapper{top:auto;left:0;margin:0 0 0 -16px;padding:0 0 0 16px;height:100%;width:32px} .ngx-slider.vertical .ngx-slider-bar{bottom:0;left:auto;width:4px;height:100%} .ngx-slider.vertical .ngx-slider-pointer{left:-14px!important;top:auto;bottom:0} .ngx-slider.vertical .ngx-slider-bubble{left:16px!important;bottom:0} .ngx-slider.vertical .ngx-slider-ticks{height:100%;width:0;left:-3px;top:0;z-index:1} .ngx-slider.vertical .ngx-slider-tick{vertical-align:middle;margin-left:auto;margin-top:11px} .ngx-slider.vertical .ngx-slider-tick-value{left:24px;top:auto;transform:translateY(-28%)} .ngx-slider.vertical .ngx-slider-tick-legend{top:auto;right:24px;transform:translateY(-28%);max-width:none;white-space:nowrap} .ngx-slider.vertical .ngx-slider-ticks-values-under .ngx-slider-tick-value{bottom:auto;left:auto;right:24px} .ngx-slider *{transition:none} .ngx-slider.animate .ngx-slider-bar-wrapper{transition:all linear .3s} .ngx-slider.animate .ngx-slider-selection{transition:background-color linear .3s} .ngx-slider.animate .ngx-slider-pointer{transition:all linear .3s} .ngx-slider.animate .ngx-slider-pointer:after{transition:all linear .3s} .ngx-slider.animate .ngx-slider-bubble{transition:all linear .3s} .ngx-slider.animate .ngx-slider-bubble.ngx-slider-limit{transition:opacity linear .3s} .ngx-slider.animate .ngx-slider-bubble.ngx-slider-combined{transition:opacity linear .3s} .ngx-slider.animate .ngx-slider-tick{transition:background-color linear .3s}']})}return e})(),n3=(()=>{class e{static \u0275fac=function(r){return new(r||e)};static \u0275mod=cr({type:e});static \u0275inj=Nn({imports:[eE]})}return e})();class dM{constructor(){this.riskHotspotsSettings=null,this.coverageInfoSettings=null}}class r3{constructor(){this.showLineCoverage=!0,this.showBranchCoverage=!0,this.showMethodCoverage=!0,this.showFullMethodCoverage=!0,this.visibleMetrics=[],this.groupingMaximum=0,this.grouping=0,this.historyComparisionDate="",this.historyComparisionType="",this.filter="",this.lineCoverageMin=0,this.lineCoverageMax=100,this.branchCoverageMin=0,this.branchCoverageMax=100,this.methodCoverageMin=0,this.methodCoverageMax=100,this.methodFullCoverageMin=0,this.methodFullCoverageMax=100,this.sortBy="name",this.sortOrder="asc",this.collapseStates=[]}}class i3{constructor(n){this.et="",this.et=n.et,this.cl=n.cl,this.ucl=n.ucl,this.cal=n.cal,this.tl=n.tl,this.lcq=n.lcq,this.cb=n.cb,this.tb=n.tb,this.bcq=n.bcq,this.cm=n.cm,this.fcm=n.fcm,this.tm=n.tm,this.mcq=n.mcq,this.mfcq=n.mfcq}get coverageRatioText(){return 0===this.tl?"-":this.cl+"/"+this.cal}get branchCoverageRatioText(){return 0===this.tb?"-":this.cb+"/"+this.tb}get methodCoverageRatioText(){return 0===this.tm?"-":this.cm+"/"+this.tm}get methodFullCoverageRatioText(){return 0===this.tm?"-":this.fcm+"/"+this.tm}}class jt{static roundNumber(n){return Math.floor(n*Math.pow(10,jt.maximumDecimalPlacesForCoverageQuotas))/Math.pow(10,jt.maximumDecimalPlacesForCoverageQuotas)}static getNthOrLastIndexOf(n,t,r){let i=0,o=-1,s=-1;for(;i{this.historicCoverages.push(new i3(r))}),this.metrics=n.metrics}get coverage(){return 0===this.coverableLines?NaN:jt.roundNumber(100*this.coveredLines/this.coverableLines)}visible(n){if(""!==n.filter&&-1===this.name.toLowerCase().indexOf(n.filter.toLowerCase()))return!1;let t=this.coverage,r=t;if(t=Number.isNaN(t)?0:t,r=Number.isNaN(r)?100:r,n.lineCoverageMin>t||n.lineCoverageMaxi||n.branchCoverageMaxs||n.methodCoverageMaxl||n.methodFullCoverageMax=this.currentHistoricCoverage.lcq)return!1}else if("branchCoverageIncreaseOnly"===n.historyComparisionType){let u=this.branchCoverage;if(isNaN(u)||u<=this.currentHistoricCoverage.bcq)return!1}else if("branchCoverageDecreaseOnly"===n.historyComparisionType){let u=this.branchCoverage;if(isNaN(u)||u>=this.currentHistoricCoverage.bcq)return!1}else if("methodCoverageIncreaseOnly"===n.historyComparisionType){let u=this.methodCoverage;if(isNaN(u)||u<=this.currentHistoricCoverage.mcq)return!1}else if("methodCoverageDecreaseOnly"===n.historyComparisionType){let u=this.methodCoverage;if(isNaN(u)||u>=this.currentHistoricCoverage.mcq)return!1}else if("fullMethodCoverageIncreaseOnly"===n.historyComparisionType){let u=this.methodFullCoverage;if(isNaN(u)||u<=this.currentHistoricCoverage.mfcq)return!1}else if("fullMethodCoverageDecreaseOnly"===n.historyComparisionType){let u=this.methodFullCoverage;if(isNaN(u)||u>=this.currentHistoricCoverage.mfcq)return!1}return!0}updateCurrentHistoricCoverage(n){if(this.currentHistoricCoverage=null,""!==n)for(let t=0;t-1&&null===t}visible(n){if(""!==n.filter&&this.name.toLowerCase().indexOf(n.filter.toLowerCase())>-1)return!0;for(let t=0;t{class e{get nativeWindow(){return function o3(){return window}()}static{this.\u0275fac=function(r){return new(r||e)}}static{this.\u0275prov=re({token:e,factory:e.\u0275fac})}}return e})(),s3=(()=>{class e{constructor(){this.translations={}}static{this.\u0275fac=function(r){return new(r||e)}}static{this.\u0275cmp=sn({type:e,selectors:[["pro-button"]],inputs:{translations:"translations"},standalone:!1,decls:3,vars:1,consts:[["href","https://reportgenerator.io/pro","target","_blank",1,"pro-button","pro-button-tiny",3,"title"]],template:function(r,i){1&r&&(b(0,"\xa0"),y(1,"a",0),b(2,"PRO"),_()),2&r&&(f(),In("title",i.translations.methodCoverageProVersion))},encapsulation:2})}}return e})();function a3(e,n){if(1&e){const t=ge();y(0,"div",3)(1,"label")(2,"input",4),tt("ngModelChange",function(i){B(t);const o=v();return be(o.showBranchCoverage,i)||(o.showBranchCoverage=i),j(i)}),q("change",function(){B(t);const i=v();return j(i.showBranchCoverageChange.emit(i.showBranchCoverage))}),_(),b(3),_()()}if(2&e){const t=v();f(2),Qe("ngModel",t.showBranchCoverage),f(),U(" ",t.translations.branchCoverage,"")}}function l3(e,n){1&e&&x(0,"pro-button",9),2&e&&p("translations",v().translations)}function c3(e,n){1&e&&x(0,"pro-button",9),2&e&&p("translations",v().translations)}function u3(e,n){1&e&&x(0,"pro-button",9),2&e&&p("translations",v(2).translations)}function d3(e,n){1&e&&(y(0,"a",13),x(1,"i",14),_()),2&e&&p("href",v().$implicit.explanationUrl,ir)}function f3(e,n){if(1&e){const t=ge();y(0,"div",3)(1,"label")(2,"input",11),q("change",function(){const i=B(t).$implicit;return j(v(2).toggleMetric(i))}),_(),b(3),_(),b(4,"\xa0"),V(5,d3,2,1,"a",12),_()}if(2&e){const t=n.$implicit,r=v(2);f(2),p("checked",r.isMetricSelected(t))("disabled",!r.methodCoverageAvailable),f(),U(" ",t.name,""),f(2),p("ngIf",t.explanationUrl)}}function h3(e,n){if(1&e&&(X(0),x(1,"br")(2,"br"),y(3,"b"),b(4),_(),V(5,u3,1,1,"pro-button",7)(6,f3,6,4,"div",10),ee()),2&e){const t=v();f(4),O(t.translations.metrics),f(),p("ngIf",!t.methodCoverageAvailable),f(),p("ngForOf",t.metrics)}}let g3=(()=>{class e{constructor(){this.visible=!1,this.visibleChange=new we,this.translations={},this.branchCoverageAvailable=!1,this.methodCoverageAvailable=!1,this.metrics=[],this.showLineCoverage=!1,this.showLineCoverageChange=new we,this.showBranchCoverage=!1,this.showBranchCoverageChange=new we,this.showMethodCoverage=!1,this.showMethodCoverageChange=new we,this.showMethodFullCoverage=!1,this.showMethodFullCoverageChange=new we,this.visibleMetrics=[],this.visibleMetricsChange=new we}isMetricSelected(t){return void 0!==this.visibleMetrics.find(r=>r.name===t.name)}toggleMetric(t){let r=this.visibleMetrics.find(i=>i.name===t.name);r?this.visibleMetrics.splice(this.visibleMetrics.indexOf(r),1):this.visibleMetrics.push(t),this.visibleMetrics=[...this.visibleMetrics],this.visibleMetricsChange.emit(this.visibleMetrics)}close(){this.visible=!1,this.visibleChange.emit(this.visible)}cancelEvent(t){t.stopPropagation()}static{this.\u0275fac=function(r){return new(r||e)}}static{this.\u0275cmp=sn({type:e,selectors:[["popup"]],inputs:{visible:"visible",translations:"translations",branchCoverageAvailable:"branchCoverageAvailable",methodCoverageAvailable:"methodCoverageAvailable",metrics:"metrics",showLineCoverage:"showLineCoverage",showBranchCoverage:"showBranchCoverage",showMethodCoverage:"showMethodCoverage",showMethodFullCoverage:"showMethodFullCoverage",visibleMetrics:"visibleMetrics"},outputs:{visibleChange:"visibleChange",showLineCoverageChange:"showLineCoverageChange",showBranchCoverageChange:"showBranchCoverageChange",showMethodCoverageChange:"showMethodCoverageChange",showMethodFullCoverageChange:"showMethodFullCoverageChange",visibleMetricsChange:"visibleMetricsChange"},standalone:!1,decls:22,vars:13,consts:[[1,"popup-container",3,"click"],[1,"popup",3,"click"],[1,"close",3,"click"],[1,"mt-1"],["type","checkbox",3,"ngModelChange","change","ngModel"],["class","mt-1",4,"ngIf"],["type","checkbox",3,"ngModelChange","change","ngModel","disabled"],[3,"translations",4,"ngIf"],[4,"ngIf"],[3,"translations"],["class","mt-1",4,"ngFor","ngForOf"],["type","checkbox",3,"change","checked","disabled"],["target","_blank",3,"href",4,"ngIf"],["target","_blank",3,"href"],[1,"icon-info-circled"]],template:function(r,i){1&r&&(y(0,"div",0),q("click",function(){return i.close()}),y(1,"div",1),q("click",function(s){return i.cancelEvent(s)}),y(2,"div",2),q("click",function(){return i.close()}),b(3,"X"),_(),y(4,"b"),b(5),_(),y(6,"div",3)(7,"label")(8,"input",4),tt("ngModelChange",function(s){return be(i.showLineCoverage,s)||(i.showLineCoverage=s),s}),q("change",function(){return i.showLineCoverageChange.emit(i.showLineCoverage)}),_(),b(9),_()(),V(10,a3,4,2,"div",5),y(11,"div",3)(12,"label")(13,"input",6),tt("ngModelChange",function(s){return be(i.showMethodCoverage,s)||(i.showMethodCoverage=s),s}),q("change",function(){return i.showMethodCoverageChange.emit(i.showMethodCoverage)}),_(),b(14),_(),V(15,l3,1,1,"pro-button",7),_(),y(16,"div",3)(17,"label")(18,"input",6),tt("ngModelChange",function(s){return be(i.showMethodFullCoverage,s)||(i.showMethodFullCoverage=s),s}),q("change",function(){return i.showMethodFullCoverageChange.emit(i.showMethodFullCoverage)}),_(),b(19),_(),V(20,c3,1,1,"pro-button",7),_(),V(21,h3,7,3,"ng-container",8),_()()),2&r&&(f(5),O(i.translations.coverageTypes),f(3),Qe("ngModel",i.showLineCoverage),f(),U(" ",i.translations.coverage,""),f(),p("ngIf",i.branchCoverageAvailable),f(3),Qe("ngModel",i.showMethodCoverage),p("disabled",!i.methodCoverageAvailable),f(),U(" ",i.translations.methodCoverage,""),f(),p("ngIf",!i.methodCoverageAvailable),f(3),Qe("ngModel",i.showMethodFullCoverage),p("disabled",!i.methodCoverageAvailable),f(),U(" ",i.translations.fullMethodCoverage,""),f(),p("ngIf",!i.methodCoverageAvailable),f(),p("ngIf",i.metrics.length>0))},dependencies:[ci,zn,Ig,jc,aa,s3],encapsulation:2})}}return e})();function p3(e,n){1&e&&x(0,"td",3)}function m3(e,n){1&e&&x(0,"td"),2&e&&Kt("green ",v().greenClass,"")}function v3(e,n){1&e&&x(0,"td"),2&e&&Kt("red ",v().redClass,"")}let hM=(()=>{class e{constructor(){this.grayVisible=!0,this.greenVisible=!1,this.redVisible=!1,this.greenClass="",this.redClass="",this._percentage=NaN}get percentage(){return this._percentage}set percentage(t){this._percentage=t,this.grayVisible=isNaN(t),this.greenVisible=!isNaN(t)&&Math.round(t)>0,this.redVisible=!isNaN(t)&&100-Math.round(t)>0,this.greenClass="covered"+Math.round(t),this.redClass="covered"+(100-Math.round(t))}static{this.\u0275fac=function(r){return new(r||e)}}static{this.\u0275cmp=sn({type:e,selectors:[["coverage-bar"]],inputs:{percentage:"percentage"},standalone:!1,decls:4,vars:3,consts:[[1,"coverage"],["class","gray covered100",4,"ngIf"],[3,"class",4,"ngIf"],[1,"gray","covered100"]],template:function(r,i){1&r&&(y(0,"table",0),V(1,p3,1,0,"td",1)(2,m3,1,3,"td",2)(3,v3,1,3,"td",2),_()),2&r&&(f(),p("ngIf",i.grayVisible),f(),p("ngIf",i.greenVisible),f(),p("ngIf",i.redVisible))},dependencies:[zn],encapsulation:2,changeDetection:0})}}return e})();const _3=["codeelement-row",""],y3=(e,n)=>({"icon-plus":e,"icon-minus":n});function C3(e,n){if(1&e&&(y(0,"th",5),b(1),_()),2&e){const t=v();f(),O(t.element.coveredLines)}}function w3(e,n){if(1&e&&(y(0,"th",5),b(1),_()),2&e){const t=v();f(),O(t.element.uncoveredLines)}}function D3(e,n){if(1&e&&(y(0,"th",5),b(1),_()),2&e){const t=v();f(),O(t.element.coverableLines)}}function b3(e,n){if(1&e&&(y(0,"th",5),b(1),_()),2&e){const t=v();f(),O(t.element.totalLines)}}function E3(e,n){if(1&e&&(y(0,"th",6),b(1),_()),2&e){const t=v();p("title",t.element.coverageRatioText),f(),O(t.element.coveragePercentage)}}function I3(e,n){if(1&e&&(y(0,"th",5),x(1,"coverage-bar",7),_()),2&e){const t=v();f(),p("percentage",t.element.coverage)}}function M3(e,n){if(1&e&&(y(0,"th",5),b(1),_()),2&e){const t=v();f(),O(t.element.coveredBranches)}}function T3(e,n){if(1&e&&(y(0,"th",5),b(1),_()),2&e){const t=v();f(),O(t.element.totalBranches)}}function S3(e,n){if(1&e&&(y(0,"th",6),b(1),_()),2&e){const t=v();p("title",t.element.branchCoverageRatioText),f(),O(t.element.branchCoveragePercentage)}}function N3(e,n){if(1&e&&(y(0,"th",5),x(1,"coverage-bar",7),_()),2&e){const t=v();f(),p("percentage",t.element.branchCoverage)}}function x3(e,n){if(1&e&&(y(0,"th",5),b(1),_()),2&e){const t=v();f(),O(t.element.coveredMethods)}}function O3(e,n){if(1&e&&(y(0,"th",5),b(1),_()),2&e){const t=v();f(),O(t.element.totalMethods)}}function A3(e,n){if(1&e&&(y(0,"th",6),b(1),_()),2&e){const t=v();p("title",t.element.methodCoverageRatioText),f(),O(t.element.methodCoveragePercentage)}}function R3(e,n){if(1&e&&(y(0,"th",5),x(1,"coverage-bar",7),_()),2&e){const t=v();f(),p("percentage",t.element.methodCoverage)}}function k3(e,n){if(1&e&&(y(0,"th",5),b(1),_()),2&e){const t=v();f(),O(t.element.fullyCoveredMethods)}}function F3(e,n){if(1&e&&(y(0,"th",5),b(1),_()),2&e){const t=v();f(),O(t.element.totalMethods)}}function L3(e,n){if(1&e&&(y(0,"th",6),b(1),_()),2&e){const t=v();p("title",t.element.methodFullCoverageRatioText),f(),O(t.element.methodFullCoveragePercentage)}}function P3(e,n){if(1&e&&(y(0,"th",5),x(1,"coverage-bar",7),_()),2&e){const t=v();f(),p("percentage",t.element.methodFullCoverage)}}function V3(e,n){1&e&&x(0,"th",5)}let H3=(()=>{class e{constructor(){this.collapsed=!1,this.lineCoverageAvailable=!1,this.branchCoverageAvailable=!1,this.methodCoverageAvailable=!1,this.methodFullCoverageAvailable=!1,this.visibleMetrics=[]}static{this.\u0275fac=function(r){return new(r||e)}}static{this.\u0275cmp=sn({type:e,selectors:[["","codeelement-row",""]],inputs:{element:"element",collapsed:"collapsed",lineCoverageAvailable:"lineCoverageAvailable",branchCoverageAvailable:"branchCoverageAvailable",methodCoverageAvailable:"methodCoverageAvailable",methodFullCoverageAvailable:"methodFullCoverageAvailable",visibleMetrics:"visibleMetrics"},standalone:!1,attrs:_3,decls:23,vars:24,consts:[["href","#",3,"click"],[3,"ngClass"],["class","right",4,"ngIf"],["class","right",3,"title",4,"ngIf"],["class","right",4,"ngFor","ngForOf"],[1,"right"],[1,"right",3,"title"],[3,"percentage"]],template:function(r,i){1&r&&(y(0,"th")(1,"a",0),q("click",function(s){return i.element.toggleCollapse(s)}),x(2,"i",1),b(3),_()(),V(4,C3,2,1,"th",2)(5,w3,2,1,"th",2)(6,D3,2,1,"th",2)(7,b3,2,1,"th",2)(8,E3,2,2,"th",3)(9,I3,2,1,"th",2)(10,M3,2,1,"th",2)(11,T3,2,1,"th",2)(12,S3,2,2,"th",3)(13,N3,2,1,"th",2)(14,x3,2,1,"th",2)(15,O3,2,1,"th",2)(16,A3,2,2,"th",3)(17,R3,2,1,"th",2)(18,k3,2,1,"th",2)(19,F3,2,1,"th",2)(20,L3,2,2,"th",3)(21,P3,2,1,"th",2)(22,V3,1,0,"th",4)),2&r&&(f(2),p("ngClass",xh(21,y3,i.element.collapsed,!i.element.collapsed)),f(),U(" ",i.element.name,""),f(),p("ngIf",i.lineCoverageAvailable),f(),p("ngIf",i.lineCoverageAvailable),f(),p("ngIf",i.lineCoverageAvailable),f(),p("ngIf",i.lineCoverageAvailable),f(),p("ngIf",i.lineCoverageAvailable),f(),p("ngIf",i.lineCoverageAvailable),f(),p("ngIf",i.branchCoverageAvailable),f(),p("ngIf",i.branchCoverageAvailable),f(),p("ngIf",i.branchCoverageAvailable),f(),p("ngIf",i.branchCoverageAvailable),f(),p("ngIf",i.methodCoverageAvailable),f(),p("ngIf",i.methodCoverageAvailable),f(),p("ngIf",i.methodCoverageAvailable),f(),p("ngIf",i.methodCoverageAvailable),f(),p("ngIf",i.methodFullCoverageAvailable),f(),p("ngIf",i.methodFullCoverageAvailable),f(),p("ngIf",i.methodFullCoverageAvailable),f(),p("ngIf",i.methodFullCoverageAvailable),f(),p("ngForOf",i.visibleMetrics))},dependencies:[Do,ci,zn,hM],encapsulation:2,changeDetection:0})}}return e})();const B3=["coverage-history-chart",""];let j3=(()=>{class e{constructor(){this.path=null,this._historicCoverages=[]}get historicCoverages(){return this._historicCoverages}set historicCoverages(t){if(this._historicCoverages=t,t.length>1){let r="";for(let i=0;i({historiccoverageoffset:e});function $3(e,n){if(1&e&&(y(0,"a",5),b(1),_()),2&e){const t=v();p("href",t.clazz.reportPath,ir),f(),O(t.clazz.name)}}function z3(e,n){if(1&e&&(X(0),b(1),ee()),2&e){const t=v();f(),O(t.clazz.name)}}function G3(e,n){if(1&e&&(X(0),y(1,"div"),b(2),_(),y(3,"div",7),b(4),_(),ee()),2&e){const t=v(2);f(),Kt("currenthistory ",t.getClassName(t.clazz.coveredLines,t.clazz.currentHistoricCoverage.cl),""),f(),U(" ",t.clazz.coveredLines," "),f(),p("title",t.clazz.currentHistoricCoverage.et),f(),U(" ",t.clazz.currentHistoricCoverage.cl," ")}}function q3(e,n){if(1&e&&(X(0),b(1),ee()),2&e){const t=v(2);f(),U(" ",t.clazz.coveredLines," ")}}function W3(e,n){if(1&e&&(y(0,"td",6),V(1,G3,5,6,"ng-container",1)(2,q3,2,1,"ng-container",1),_()),2&e){const t=v();f(),p("ngIf",null!==t.clazz.currentHistoricCoverage),f(),p("ngIf",null===t.clazz.currentHistoricCoverage)}}function Z3(e,n){if(1&e&&(X(0),y(1,"div"),b(2),_(),y(3,"div",7),b(4),_(),ee()),2&e){const t=v(2);f(),Kt("currenthistory ",t.getClassName(t.clazz.currentHistoricCoverage.ucl,t.clazz.uncoveredLines),""),f(),U(" ",t.clazz.uncoveredLines," "),f(),p("title",t.clazz.currentHistoricCoverage.et),f(),U(" ",t.clazz.currentHistoricCoverage.ucl," ")}}function Q3(e,n){if(1&e&&(X(0),b(1),ee()),2&e){const t=v(2);f(),U(" ",t.clazz.uncoveredLines," ")}}function Y3(e,n){if(1&e&&(y(0,"td",6),V(1,Z3,5,6,"ng-container",1)(2,Q3,2,1,"ng-container",1),_()),2&e){const t=v();f(),p("ngIf",null!==t.clazz.currentHistoricCoverage),f(),p("ngIf",null===t.clazz.currentHistoricCoverage)}}function K3(e,n){if(1&e&&(X(0),y(1,"div",8),b(2),_(),y(3,"div",7),b(4),_(),ee()),2&e){const t=v(2);f(2),O(t.clazz.coverableLines),f(),p("title",t.clazz.currentHistoricCoverage.et),f(),O(t.clazz.currentHistoricCoverage.cal)}}function J3(e,n){if(1&e&&(X(0),b(1),ee()),2&e){const t=v(2);f(),U(" ",t.clazz.coverableLines," ")}}function X3(e,n){if(1&e&&(y(0,"td",6),V(1,K3,5,3,"ng-container",1)(2,J3,2,1,"ng-container",1),_()),2&e){const t=v();f(),p("ngIf",null!==t.clazz.currentHistoricCoverage),f(),p("ngIf",null===t.clazz.currentHistoricCoverage)}}function eU(e,n){if(1&e&&(X(0),y(1,"div",8),b(2),_(),y(3,"div",7),b(4),_(),ee()),2&e){const t=v(2);f(2),O(t.clazz.totalLines),f(),p("title",t.clazz.currentHistoricCoverage.et),f(),O(t.clazz.currentHistoricCoverage.tl)}}function tU(e,n){if(1&e&&(X(0),b(1),ee()),2&e){const t=v(2);f(),U(" ",t.clazz.totalLines," ")}}function nU(e,n){if(1&e&&(y(0,"td",6),V(1,eU,5,3,"ng-container",1)(2,tU,2,1,"ng-container",1),_()),2&e){const t=v();f(),p("ngIf",null!==t.clazz.currentHistoricCoverage),f(),p("ngIf",null===t.clazz.currentHistoricCoverage)}}function rU(e,n){if(1&e&&x(0,"div",11),2&e){const t=v(2);In("title",t.translations.history+": "+t.translations.coverage),p("historicCoverages",t.clazz.lineCoverageHistory)("ngClass",_o(3,eu,null!==t.clazz.currentHistoricCoverage))}}function iU(e,n){if(1&e&&(X(0),y(1,"div"),b(2),_(),y(3,"div",7),b(4),_(),ee()),2&e){const t=v(2);f(),Kt("currenthistory ",t.getClassName(t.clazz.coverage,t.clazz.currentHistoricCoverage.lcq),""),f(),U(" ",t.clazz.coveragePercentage," "),f(),p("title",t.clazz.currentHistoricCoverage.et+": "+t.clazz.currentHistoricCoverage.coverageRatioText),f(),U("",t.clazz.currentHistoricCoverage.lcq,"%")}}function oU(e,n){if(1&e&&(X(0),b(1),ee()),2&e){const t=v(2);f(),U(" ",t.clazz.coveragePercentage," ")}}function sU(e,n){if(1&e&&(y(0,"td",9),V(1,rU,1,5,"div",10)(2,iU,5,6,"ng-container",1)(3,oU,2,1,"ng-container",1),_()),2&e){const t=v();p("title",t.clazz.coverageRatioText),f(),p("ngIf",t.clazz.lineCoverageHistory.length>1),f(),p("ngIf",null!==t.clazz.currentHistoricCoverage),f(),p("ngIf",null===t.clazz.currentHistoricCoverage)}}function aU(e,n){if(1&e&&(y(0,"td",6),x(1,"coverage-bar",12),_()),2&e){const t=v();f(),p("percentage",t.clazz.coverage)}}function lU(e,n){if(1&e&&(X(0),y(1,"div"),b(2),_(),y(3,"div",7),b(4),_(),ee()),2&e){const t=v(2);f(),Kt("currenthistory ",t.getClassName(t.clazz.coveredBranches,t.clazz.currentHistoricCoverage.cb),""),f(),U(" ",t.clazz.coveredBranches," "),f(),p("title",t.clazz.currentHistoricCoverage.et),f(),U(" ",t.clazz.currentHistoricCoverage.cb," ")}}function cU(e,n){if(1&e&&(X(0),b(1),ee()),2&e){const t=v(2);f(),U(" ",t.clazz.coveredBranches," ")}}function uU(e,n){if(1&e&&(y(0,"td",6),V(1,lU,5,6,"ng-container",1)(2,cU,2,1,"ng-container",1),_()),2&e){const t=v();f(),p("ngIf",null!==t.clazz.currentHistoricCoverage),f(),p("ngIf",null===t.clazz.currentHistoricCoverage)}}function dU(e,n){if(1&e&&(X(0),y(1,"div",8),b(2),_(),y(3,"div",7),b(4),_(),ee()),2&e){const t=v(2);f(2),O(t.clazz.totalBranches),f(),p("title",t.clazz.currentHistoricCoverage.et),f(),O(t.clazz.currentHistoricCoverage.tb)}}function fU(e,n){if(1&e&&(X(0),b(1),ee()),2&e){const t=v(2);f(),U(" ",t.clazz.totalBranches," ")}}function hU(e,n){if(1&e&&(y(0,"td",6),V(1,dU,5,3,"ng-container",1)(2,fU,2,1,"ng-container",1),_()),2&e){const t=v();f(),p("ngIf",null!==t.clazz.currentHistoricCoverage),f(),p("ngIf",null===t.clazz.currentHistoricCoverage)}}function gU(e,n){if(1&e&&x(0,"div",14),2&e){const t=v(2);In("title",t.translations.history+": "+t.translations.branchCoverage),p("historicCoverages",t.clazz.branchCoverageHistory)("ngClass",_o(3,eu,null!==t.clazz.currentHistoricCoverage))}}function pU(e,n){if(1&e&&(X(0),y(1,"div"),b(2),_(),y(3,"div",7),b(4),_(),ee()),2&e){const t=v(2);f(),Kt("currenthistory ",t.getClassName(t.clazz.branchCoverage,t.clazz.currentHistoricCoverage.bcq),""),f(),U(" ",t.clazz.branchCoveragePercentage," "),f(),p("title",t.clazz.currentHistoricCoverage.et+": "+t.clazz.currentHistoricCoverage.branchCoverageRatioText),f(),U("",t.clazz.currentHistoricCoverage.bcq,"%")}}function mU(e,n){if(1&e&&(X(0),b(1),ee()),2&e){const t=v(2);f(),U(" ",t.clazz.branchCoveragePercentage," ")}}function vU(e,n){if(1&e&&(y(0,"td",9),V(1,gU,1,5,"div",13)(2,pU,5,6,"ng-container",1)(3,mU,2,1,"ng-container",1),_()),2&e){const t=v();p("title",t.clazz.branchCoverageRatioText),f(),p("ngIf",t.clazz.branchCoverageHistory.length>1),f(),p("ngIf",null!==t.clazz.currentHistoricCoverage),f(),p("ngIf",null===t.clazz.currentHistoricCoverage)}}function _U(e,n){if(1&e&&(y(0,"td",6),x(1,"coverage-bar",12),_()),2&e){const t=v();f(),p("percentage",t.clazz.branchCoverage)}}function yU(e,n){if(1&e&&(X(0),y(1,"div"),b(2),_(),y(3,"div",7),b(4),_(),ee()),2&e){const t=v(2);f(),Kt("currenthistory ",t.getClassName(t.clazz.coveredMethods,t.clazz.currentHistoricCoverage.cm),""),f(),U(" ",t.clazz.coveredMethods," "),f(),p("title",t.clazz.currentHistoricCoverage.et),f(),U(" ",t.clazz.currentHistoricCoverage.cm," ")}}function CU(e,n){if(1&e&&(X(0),b(1),ee()),2&e){const t=v(2);f(),U(" ",t.clazz.coveredMethods," ")}}function wU(e,n){if(1&e&&(y(0,"td",6),V(1,yU,5,6,"ng-container",1)(2,CU,2,1,"ng-container",1),_()),2&e){const t=v();f(),p("ngIf",null!==t.clazz.currentHistoricCoverage),f(),p("ngIf",null===t.clazz.currentHistoricCoverage)}}function DU(e,n){if(1&e&&(X(0),y(1,"div",8),b(2),_(),y(3,"div",7),b(4),_(),ee()),2&e){const t=v(2);f(2),O(t.clazz.totalMethods),f(),p("title",t.clazz.currentHistoricCoverage.et),f(),O(t.clazz.currentHistoricCoverage.tm)}}function bU(e,n){if(1&e&&(X(0),b(1),ee()),2&e){const t=v(2);f(),U(" ",t.clazz.totalMethods," ")}}function EU(e,n){if(1&e&&(y(0,"td",6),V(1,DU,5,3,"ng-container",1)(2,bU,2,1,"ng-container",1),_()),2&e){const t=v();f(),p("ngIf",null!==t.clazz.currentHistoricCoverage),f(),p("ngIf",null===t.clazz.currentHistoricCoverage)}}function IU(e,n){if(1&e&&x(0,"div",16),2&e){const t=v(2);In("title",t.translations.history+": "+t.translations.methodCoverage),p("historicCoverages",t.clazz.methodCoverageHistory)("ngClass",_o(3,eu,null!==t.clazz.currentHistoricCoverage))}}function MU(e,n){if(1&e&&(X(0),y(1,"div"),b(2),_(),y(3,"div",7),b(4),_(),ee()),2&e){const t=v(2);f(),Kt("currenthistory ",t.getClassName(t.clazz.methodCoverage,t.clazz.currentHistoricCoverage.mcq),""),f(),U(" ",t.clazz.methodCoveragePercentage," "),f(),p("title",t.clazz.currentHistoricCoverage.et+": "+t.clazz.currentHistoricCoverage.methodCoverageRatioText),f(),U("",t.clazz.currentHistoricCoverage.mcq,"%")}}function TU(e,n){if(1&e&&(X(0),b(1),ee()),2&e){const t=v(2);f(),U(" ",t.clazz.methodCoveragePercentage," ")}}function SU(e,n){if(1&e&&(y(0,"td",9),V(1,IU,1,5,"div",15)(2,MU,5,6,"ng-container",1)(3,TU,2,1,"ng-container",1),_()),2&e){const t=v();p("title",t.clazz.methodCoverageRatioText),f(),p("ngIf",t.clazz.methodCoverageHistory.length>1),f(),p("ngIf",null!==t.clazz.currentHistoricCoverage),f(),p("ngIf",null===t.clazz.currentHistoricCoverage)}}function NU(e,n){if(1&e&&(y(0,"td",6),x(1,"coverage-bar",12),_()),2&e){const t=v();f(),p("percentage",t.clazz.methodCoverage)}}function xU(e,n){if(1&e&&(X(0),y(1,"div"),b(2),_(),y(3,"div",7),b(4),_(),ee()),2&e){const t=v(2);f(),Kt("currenthistory ",t.getClassName(t.clazz.fullyCoveredMethods,t.clazz.currentHistoricCoverage.fcm),""),f(),U(" ",t.clazz.fullyCoveredMethods," "),f(),p("title",t.clazz.currentHistoricCoverage.et),f(),U(" ",t.clazz.currentHistoricCoverage.fcm," ")}}function OU(e,n){if(1&e&&(X(0),b(1),ee()),2&e){const t=v(2);f(),U(" ",t.clazz.fullyCoveredMethods," ")}}function AU(e,n){if(1&e&&(y(0,"td",6),V(1,xU,5,6,"ng-container",1)(2,OU,2,1,"ng-container",1),_()),2&e){const t=v();f(),p("ngIf",null!==t.clazz.currentHistoricCoverage),f(),p("ngIf",null===t.clazz.currentHistoricCoverage)}}function RU(e,n){if(1&e&&(X(0),y(1,"div",8),b(2),_(),y(3,"div",7),b(4),_(),ee()),2&e){const t=v(2);f(2),O(t.clazz.totalMethods),f(),p("title",t.clazz.currentHistoricCoverage.et),f(),O(t.clazz.currentHistoricCoverage.tm)}}function kU(e,n){if(1&e&&(X(0),b(1),ee()),2&e){const t=v(2);f(),U(" ",t.clazz.totalMethods," ")}}function FU(e,n){if(1&e&&(y(0,"td",6),V(1,RU,5,3,"ng-container",1)(2,kU,2,1,"ng-container",1),_()),2&e){const t=v();f(),p("ngIf",null!==t.clazz.currentHistoricCoverage),f(),p("ngIf",null===t.clazz.currentHistoricCoverage)}}function LU(e,n){if(1&e&&x(0,"div",18),2&e){const t=v(2);In("title",t.translations.history+": "+t.translations.fullMethodCoverage),p("historicCoverages",t.clazz.methodFullCoverageHistory)("ngClass",_o(3,eu,null!==t.clazz.currentHistoricCoverage))}}function PU(e,n){if(1&e&&(X(0),y(1,"div"),b(2),_(),y(3,"div",7),b(4),_(),ee()),2&e){const t=v(2);f(),Kt("currenthistory ",t.getClassName(t.clazz.methodFullCoverage,t.clazz.currentHistoricCoverage.mfcq),""),f(),U(" ",t.clazz.methodFullCoveragePercentage," "),f(),p("title",t.clazz.currentHistoricCoverage.et+": "+t.clazz.currentHistoricCoverage.methodFullCoverageRatioText),f(),U("",t.clazz.currentHistoricCoverage.mfcq,"%")}}function VU(e,n){if(1&e&&(X(0),b(1),ee()),2&e){const t=v(2);f(),U(" ",t.clazz.methodFullCoveragePercentage," ")}}function HU(e,n){if(1&e&&(y(0,"td",9),V(1,LU,1,5,"div",17)(2,PU,5,6,"ng-container",1)(3,VU,2,1,"ng-container",1),_()),2&e){const t=v();p("title",t.clazz.methodFullCoverageRatioText),f(),p("ngIf",t.clazz.methodFullCoverageHistory.length>1),f(),p("ngIf",null!==t.clazz.currentHistoricCoverage),f(),p("ngIf",null===t.clazz.currentHistoricCoverage)}}function BU(e,n){if(1&e&&(y(0,"td",6),x(1,"coverage-bar",12),_()),2&e){const t=v();f(),p("percentage",t.clazz.methodFullCoverage)}}function jU(e,n){if(1&e&&(y(0,"td",6),b(1),_()),2&e){const t=n.$implicit,r=v();f(),O(r.clazz.metrics[t.abbreviation])}}let UU=(()=>{class e{constructor(){this.translations={},this.lineCoverageAvailable=!1,this.branchCoverageAvailable=!1,this.methodCoverageAvailable=!1,this.methodFullCoverageAvailable=!1,this.visibleMetrics=[],this.historyComparisionDate=""}getClassName(t,r){return t>r?"lightgreen":t({"icon-up-dir_active":e,"icon-down-dir_active":n,"icon-up-down-dir":t});function $U(e,n){if(1&e){const t=ge();y(0,"popup",30),tt("visibleChange",function(i){B(t);const o=v(2);return be(o.popupVisible,i)||(o.popupVisible=i),j(i)})("showLineCoverageChange",function(i){B(t);const o=v(2);return be(o.settings.showLineCoverage,i)||(o.settings.showLineCoverage=i),j(i)})("showBranchCoverageChange",function(i){B(t);const o=v(2);return be(o.settings.showBranchCoverage,i)||(o.settings.showBranchCoverage=i),j(i)})("showMethodCoverageChange",function(i){B(t);const o=v(2);return be(o.settings.showMethodCoverage,i)||(o.settings.showMethodCoverage=i),j(i)})("showMethodFullCoverageChange",function(i){B(t);const o=v(2);return be(o.settings.showFullMethodCoverage,i)||(o.settings.showFullMethodCoverage=i),j(i)})("visibleMetricsChange",function(i){B(t);const o=v(2);return be(o.settings.visibleMetrics,i)||(o.settings.visibleMetrics=i),j(i)}),_()}if(2&e){const t=v(2);Qe("visible",t.popupVisible),p("translations",t.translations)("branchCoverageAvailable",t.branchCoverageAvailable)("methodCoverageAvailable",t.methodCoverageAvailable)("metrics",t.metrics),Qe("showLineCoverage",t.settings.showLineCoverage)("showBranchCoverage",t.settings.showBranchCoverage)("showMethodCoverage",t.settings.showMethodCoverage)("showMethodFullCoverage",t.settings.showFullMethodCoverage)("visibleMetrics",t.settings.visibleMetrics)}}function zU(e,n){if(1&e&&(X(0),b(1),ee()),2&e){const t=v(2);f(),O(t.translations.noGrouping)}}function GU(e,n){if(1&e&&(X(0),b(1),ee()),2&e){const t=v(2);f(),O(t.translations.byAssembly)}}function qU(e,n){if(1&e&&(X(0),b(1),ee()),2&e){const t=v(2);f(),O(t.translations.byNamespace+" "+t.settings.grouping)}}function WU(e,n){if(1&e&&(y(0,"option",34),b(1),_()),2&e){const t=n.$implicit;p("value",t),f(),O(t)}}function ZU(e,n){1&e&&x(0,"br")}function QU(e,n){if(1&e&&(y(0,"option",44),b(1),_()),2&e){const t=v(4);f(),U(" ",t.translations.branchCoverageIncreaseOnly," ")}}function YU(e,n){if(1&e&&(y(0,"option",45),b(1),_()),2&e){const t=v(4);f(),U(" ",t.translations.branchCoverageDecreaseOnly," ")}}function KU(e,n){if(1&e&&(y(0,"option",46),b(1),_()),2&e){const t=v(4);f(),U(" ",t.translations.methodCoverageIncreaseOnly," ")}}function JU(e,n){if(1&e&&(y(0,"option",47),b(1),_()),2&e){const t=v(4);f(),U(" ",t.translations.methodCoverageDecreaseOnly," ")}}function XU(e,n){if(1&e&&(y(0,"option",48),b(1),_()),2&e){const t=v(4);f(),U(" ",t.translations.fullMethodCoverageIncreaseOnly," ")}}function e$(e,n){if(1&e&&(y(0,"option",49),b(1),_()),2&e){const t=v(4);f(),U(" ",t.translations.fullMethodCoverageDecreaseOnly," ")}}function t$(e,n){if(1&e){const t=ge();y(0,"div")(1,"select",31),tt("ngModelChange",function(i){B(t);const o=v(3);return be(o.settings.historyComparisionType,i)||(o.settings.historyComparisionType=i),j(i)}),y(2,"option",32),b(3),_(),y(4,"option",35),b(5),_(),y(6,"option",36),b(7),_(),y(8,"option",37),b(9),_(),V(10,QU,2,1,"option",38)(11,YU,2,1,"option",39)(12,KU,2,1,"option",40)(13,JU,2,1,"option",41)(14,XU,2,1,"option",42)(15,e$,2,1,"option",43),_()()}if(2&e){const t=v(3);f(),Qe("ngModel",t.settings.historyComparisionType),f(2),O(t.translations.filter),f(2),O(t.translations.allChanges),f(2),O(t.translations.lineCoverageIncreaseOnly),f(2),O(t.translations.lineCoverageDecreaseOnly),f(),p("ngIf",t.branchCoverageAvailable),f(),p("ngIf",t.branchCoverageAvailable),f(),p("ngIf",t.methodCoverageAvailable),f(),p("ngIf",t.methodCoverageAvailable),f(),p("ngIf",t.methodCoverageAvailable),f(),p("ngIf",t.methodCoverageAvailable)}}function n$(e,n){if(1&e){const t=ge();X(0),y(1,"div"),b(2),y(3,"select",31),tt("ngModelChange",function(i){B(t);const o=v(2);return be(o.settings.historyComparisionDate,i)||(o.settings.historyComparisionDate=i),j(i)}),q("ngModelChange",function(){return B(t),j(v(2).updateCurrentHistoricCoverage())}),y(4,"option",32),b(5),_(),V(6,WU,2,2,"option",33),_()(),V(7,ZU,1,0,"br",0)(8,t$,16,11,"div",0),ee()}if(2&e){const t=v(2);f(2),U(" ",t.translations.compareHistory," "),f(),Qe("ngModel",t.settings.historyComparisionDate),f(2),O(t.translations.date),f(),p("ngForOf",t.historicCoverageExecutionTimes),f(),p("ngIf",""!==t.settings.historyComparisionDate),f(),p("ngIf",""!==t.settings.historyComparisionDate)}}function r$(e,n){1&e&&x(0,"col",50)}function i$(e,n){1&e&&x(0,"col",51)}function o$(e,n){1&e&&x(0,"col",52)}function s$(e,n){1&e&&x(0,"col",53)}function a$(e,n){1&e&&x(0,"col",54)}function l$(e,n){1&e&&x(0,"col",55)}function c$(e,n){1&e&&x(0,"col",50)}function u$(e,n){1&e&&x(0,"col",53)}function d$(e,n){1&e&&x(0,"col",54)}function f$(e,n){1&e&&x(0,"col",55)}function h$(e,n){1&e&&x(0,"col",50)}function g$(e,n){1&e&&x(0,"col",53)}function p$(e,n){1&e&&x(0,"col",54)}function m$(e,n){1&e&&x(0,"col",55)}function v$(e,n){1&e&&x(0,"col",50)}function _$(e,n){1&e&&x(0,"col",53)}function y$(e,n){1&e&&x(0,"col",54)}function C$(e,n){1&e&&x(0,"col",55)}function w$(e,n){1&e&&x(0,"col",55)}function D$(e,n){if(1&e&&(y(0,"th",56),b(1),_()),2&e){const t=v(2);f(),O(t.translations.coverage)}}function b$(e,n){if(1&e&&(y(0,"th",57),b(1),_()),2&e){const t=v(2);f(),O(t.translations.branchCoverage)}}function E$(e,n){if(1&e&&(y(0,"th",57),b(1),_()),2&e){const t=v(2);f(),O(t.translations.methodCoverage)}}function I$(e,n){if(1&e&&(y(0,"th",57),b(1),_()),2&e){const t=v(2);f(),O(t.translations.fullMethodCoverage)}}function M$(e,n){if(1&e&&(y(0,"th",58),b(1),_()),2&e){const t=v(2);_t("colspan",t.settings.visibleMetrics.length),f(),O(t.translations.metrics)}}function T$(e,n){if(1&e){const t=ge();y(0,"td",56)(1,"ngx-slider",59),tt("valueChange",function(i){B(t);const o=v(2);return be(o.settings.lineCoverageMin,i)||(o.settings.lineCoverageMin=i),j(i)})("highValueChange",function(i){B(t);const o=v(2);return be(o.settings.lineCoverageMax,i)||(o.settings.lineCoverageMax=i),j(i)}),_()()}if(2&e){const t=v(2);f(),Qe("value",t.settings.lineCoverageMin)("highValue",t.settings.lineCoverageMax),p("options",t.sliderOptions)}}function S$(e,n){if(1&e){const t=ge();y(0,"td",57)(1,"ngx-slider",59),tt("valueChange",function(i){B(t);const o=v(2);return be(o.settings.branchCoverageMin,i)||(o.settings.branchCoverageMin=i),j(i)})("highValueChange",function(i){B(t);const o=v(2);return be(o.settings.branchCoverageMax,i)||(o.settings.branchCoverageMax=i),j(i)}),_()()}if(2&e){const t=v(2);f(),Qe("value",t.settings.branchCoverageMin)("highValue",t.settings.branchCoverageMax),p("options",t.sliderOptions)}}function N$(e,n){if(1&e){const t=ge();y(0,"td",57)(1,"ngx-slider",59),tt("valueChange",function(i){B(t);const o=v(2);return be(o.settings.methodCoverageMin,i)||(o.settings.methodCoverageMin=i),j(i)})("highValueChange",function(i){B(t);const o=v(2);return be(o.settings.methodCoverageMax,i)||(o.settings.methodCoverageMax=i),j(i)}),_()()}if(2&e){const t=v(2);f(),Qe("value",t.settings.methodCoverageMin)("highValue",t.settings.methodCoverageMax),p("options",t.sliderOptions)}}function x$(e,n){if(1&e){const t=ge();y(0,"td",57)(1,"ngx-slider",59),tt("valueChange",function(i){B(t);const o=v(2);return be(o.settings.methodFullCoverageMin,i)||(o.settings.methodFullCoverageMin=i),j(i)})("highValueChange",function(i){B(t);const o=v(2);return be(o.settings.methodFullCoverageMax,i)||(o.settings.methodFullCoverageMax=i),j(i)}),_()()}if(2&e){const t=v(2);f(),Qe("value",t.settings.methodFullCoverageMin)("highValue",t.settings.methodFullCoverageMax),p("options",t.sliderOptions)}}function O$(e,n){1&e&&x(0,"td",58),2&e&&_t("colspan",v(2).settings.visibleMetrics.length)}function A$(e,n){if(1&e){const t=ge();y(0,"th",60)(1,"a",3),q("click",function(i){return B(t),j(v(2).updateSorting("covered",i))}),x(2,"i",26),b(3),_()()}if(2&e){const t=v(2);f(2),p("ngClass",Fe(2,ut,"covered"===t.settings.sortBy&&"asc"===t.settings.sortOrder,"covered"===t.settings.sortBy&&"desc"===t.settings.sortOrder,"covered"!==t.settings.sortBy)),f(),O(t.translations.covered)}}function R$(e,n){if(1&e){const t=ge();y(0,"th",60)(1,"a",3),q("click",function(i){return B(t),j(v(2).updateSorting("uncovered",i))}),x(2,"i",26),b(3),_()()}if(2&e){const t=v(2);f(2),p("ngClass",Fe(2,ut,"uncovered"===t.settings.sortBy&&"asc"===t.settings.sortOrder,"uncovered"===t.settings.sortBy&&"desc"===t.settings.sortOrder,"uncovered"!==t.settings.sortBy)),f(),O(t.translations.uncovered)}}function k$(e,n){if(1&e){const t=ge();y(0,"th",60)(1,"a",3),q("click",function(i){return B(t),j(v(2).updateSorting("coverable",i))}),x(2,"i",26),b(3),_()()}if(2&e){const t=v(2);f(2),p("ngClass",Fe(2,ut,"coverable"===t.settings.sortBy&&"asc"===t.settings.sortOrder,"coverable"===t.settings.sortBy&&"desc"===t.settings.sortOrder,"coverable"!==t.settings.sortBy)),f(),O(t.translations.coverable)}}function F$(e,n){if(1&e){const t=ge();y(0,"th",60)(1,"a",3),q("click",function(i){return B(t),j(v(2).updateSorting("total",i))}),x(2,"i",26),b(3),_()()}if(2&e){const t=v(2);f(2),p("ngClass",Fe(2,ut,"total"===t.settings.sortBy&&"asc"===t.settings.sortOrder,"total"===t.settings.sortBy&&"desc"===t.settings.sortOrder,"total"!==t.settings.sortBy)),f(),O(t.translations.total)}}function L$(e,n){if(1&e){const t=ge();y(0,"th",61)(1,"a",3),q("click",function(i){return B(t),j(v(2).updateSorting("coverage",i))}),x(2,"i",26),b(3),_()()}if(2&e){const t=v(2);f(2),p("ngClass",Fe(2,ut,"coverage"===t.settings.sortBy&&"asc"===t.settings.sortOrder,"coverage"===t.settings.sortBy&&"desc"===t.settings.sortOrder,"coverage"!==t.settings.sortBy)),f(),O(t.translations.percentage)}}function P$(e,n){if(1&e){const t=ge();y(0,"th",60)(1,"a",3),q("click",function(i){return B(t),j(v(2).updateSorting("covered_branches",i))}),x(2,"i",26),b(3),_()()}if(2&e){const t=v(2);f(2),p("ngClass",Fe(2,ut,"covered_branches"===t.settings.sortBy&&"asc"===t.settings.sortOrder,"covered_branches"===t.settings.sortBy&&"desc"===t.settings.sortOrder,"covered_branches"!==t.settings.sortBy)),f(),O(t.translations.covered)}}function V$(e,n){if(1&e){const t=ge();y(0,"th",60)(1,"a",3),q("click",function(i){return B(t),j(v(2).updateSorting("total_branches",i))}),x(2,"i",26),b(3),_()()}if(2&e){const t=v(2);f(2),p("ngClass",Fe(2,ut,"total_branches"===t.settings.sortBy&&"asc"===t.settings.sortOrder,"total_branches"===t.settings.sortBy&&"desc"===t.settings.sortOrder,"total_branches"!==t.settings.sortBy)),f(),O(t.translations.total)}}function H$(e,n){if(1&e){const t=ge();y(0,"th",61)(1,"a",3),q("click",function(i){return B(t),j(v(2).updateSorting("branchcoverage",i))}),x(2,"i",26),b(3),_()()}if(2&e){const t=v(2);f(2),p("ngClass",Fe(2,ut,"branchcoverage"===t.settings.sortBy&&"asc"===t.settings.sortOrder,"branchcoverage"===t.settings.sortBy&&"desc"===t.settings.sortOrder,"branchcoverage"!==t.settings.sortBy)),f(),O(t.translations.percentage)}}function B$(e,n){if(1&e){const t=ge();y(0,"th",60)(1,"a",3),q("click",function(i){return B(t),j(v(2).updateSorting("covered_methods",i))}),x(2,"i",26),b(3),_()()}if(2&e){const t=v(2);f(2),p("ngClass",Fe(2,ut,"covered_methods"===t.settings.sortBy&&"asc"===t.settings.sortOrder,"covered_methods"===t.settings.sortBy&&"desc"===t.settings.sortOrder,"covered_methods"!==t.settings.sortBy)),f(),O(t.translations.covered)}}function j$(e,n){if(1&e){const t=ge();y(0,"th",60)(1,"a",3),q("click",function(i){return B(t),j(v(2).updateSorting("total_methods",i))}),x(2,"i",26),b(3),_()()}if(2&e){const t=v(2);f(2),p("ngClass",Fe(2,ut,"total_methods"===t.settings.sortBy&&"asc"===t.settings.sortOrder,"total_methods"===t.settings.sortBy&&"desc"===t.settings.sortOrder,"total_methods"!==t.settings.sortBy)),f(),O(t.translations.total)}}function U$(e,n){if(1&e){const t=ge();y(0,"th",61)(1,"a",3),q("click",function(i){return B(t),j(v(2).updateSorting("methodcoverage",i))}),x(2,"i",26),b(3),_()()}if(2&e){const t=v(2);f(2),p("ngClass",Fe(2,ut,"methodcoverage"===t.settings.sortBy&&"asc"===t.settings.sortOrder,"methodcoverage"===t.settings.sortBy&&"desc"===t.settings.sortOrder,"methodcoverage"!==t.settings.sortBy)),f(),O(t.translations.percentage)}}function $$(e,n){if(1&e){const t=ge();y(0,"th",60)(1,"a",3),q("click",function(i){return B(t),j(v(2).updateSorting("fullycovered_methods",i))}),x(2,"i",26),b(3),_()()}if(2&e){const t=v(2);f(2),p("ngClass",Fe(2,ut,"fullycovered_methods"===t.settings.sortBy&&"asc"===t.settings.sortOrder,"fullycovered_methods"===t.settings.sortBy&&"desc"===t.settings.sortOrder,"fullycovered_methods"!==t.settings.sortBy)),f(),O(t.translations.covered)}}function z$(e,n){if(1&e){const t=ge();y(0,"th",60)(1,"a",3),q("click",function(i){return B(t),j(v(2).updateSorting("total_methods",i))}),x(2,"i",26),b(3),_()()}if(2&e){const t=v(2);f(2),p("ngClass",Fe(2,ut,"total_methods"===t.settings.sortBy&&"asc"===t.settings.sortOrder,"total_methods"===t.settings.sortBy&&"desc"===t.settings.sortOrder,"total_methods"!==t.settings.sortBy)),f(),O(t.translations.total)}}function G$(e,n){if(1&e){const t=ge();y(0,"th",61)(1,"a",3),q("click",function(i){return B(t),j(v(2).updateSorting("methodfullcoverage",i))}),x(2,"i",26),b(3),_()()}if(2&e){const t=v(2);f(2),p("ngClass",Fe(2,ut,"methodfullcoverage"===t.settings.sortBy&&"asc"===t.settings.sortOrder,"methodfullcoverage"===t.settings.sortBy&&"desc"===t.settings.sortOrder,"methodfullcoverage"!==t.settings.sortBy)),f(),O(t.translations.percentage)}}function q$(e,n){if(1&e){const t=ge();y(0,"th")(1,"a",3),q("click",function(i){const o=B(t).$implicit;return j(v(2).updateSorting(o.abbreviation,i))}),x(2,"i",26),b(3),_(),y(4,"a",62),x(5,"i",63),_()()}if(2&e){const t=n.$implicit,r=v(2);f(2),p("ngClass",Fe(3,ut,r.settings.sortBy===t.abbreviation&&"asc"===r.settings.sortOrder,r.settings.sortBy===t.abbreviation&&"desc"===r.settings.sortOrder,r.settings.sortBy!==t.abbreviation)),f(),O(t.name),f(),In("href",t.explanationUrl,ir)}}function W$(e,n){if(1&e&&x(0,"tr",65),2&e){const t=v().$implicit,r=v(2);p("element",t)("collapsed",t.collapsed)("lineCoverageAvailable",r.settings.showLineCoverage)("branchCoverageAvailable",r.branchCoverageAvailable&&r.settings.showBranchCoverage)("methodCoverageAvailable",r.methodCoverageAvailable&&r.settings.showMethodCoverage)("methodFullCoverageAvailable",r.methodCoverageAvailable&&r.settings.showFullMethodCoverage)("visibleMetrics",r.settings.visibleMetrics)}}function Z$(e,n){if(1&e&&x(0,"tr",67),2&e){const t=v().$implicit,r=v(3);p("clazz",t)("translations",r.translations)("lineCoverageAvailable",r.settings.showLineCoverage)("branchCoverageAvailable",r.branchCoverageAvailable&&r.settings.showBranchCoverage)("methodCoverageAvailable",r.methodCoverageAvailable&&r.settings.showMethodCoverage)("methodFullCoverageAvailable",r.methodCoverageAvailable&&r.settings.showFullMethodCoverage)("visibleMetrics",r.settings.visibleMetrics)("historyComparisionDate",r.settings.historyComparisionDate)}}function Q$(e,n){if(1&e&&(X(0),V(1,Z$,1,8,"tr",66),ee()),2&e){const t=n.$implicit,r=v().$implicit,i=v(2);f(),p("ngIf",!r.collapsed&&t.visible(i.settings))}}function Y$(e,n){if(1&e&&x(0,"tr",70),2&e){const t=v().$implicit,r=v(5);p("clazz",t)("translations",r.translations)("lineCoverageAvailable",r.settings.showLineCoverage)("branchCoverageAvailable",r.branchCoverageAvailable&&r.settings.showBranchCoverage)("methodCoverageAvailable",r.methodCoverageAvailable&&r.settings.showMethodCoverage)("methodFullCoverageAvailable",r.methodCoverageAvailable&&r.settings.showFullMethodCoverage)("visibleMetrics",r.settings.visibleMetrics)("historyComparisionDate",r.settings.historyComparisionDate)}}function K$(e,n){if(1&e&&(X(0),V(1,Y$,1,8,"tr",69),ee()),2&e){const t=n.$implicit,r=v(2).$implicit,i=v(3);f(),p("ngIf",!r.collapsed&&t.visible(i.settings))}}function J$(e,n){if(1&e&&(X(0),x(1,"tr",68),V(2,K$,2,1,"ng-container",29),ee()),2&e){const t=v().$implicit,r=v(3);f(),p("element",t)("collapsed",t.collapsed)("lineCoverageAvailable",r.settings.showLineCoverage)("branchCoverageAvailable",r.branchCoverageAvailable&&r.settings.showBranchCoverage)("methodCoverageAvailable",r.methodCoverageAvailable&&r.settings.showMethodCoverage)("methodFullCoverageAvailable",r.methodCoverageAvailable&&r.settings.showFullMethodCoverage)("visibleMetrics",r.settings.visibleMetrics),f(),p("ngForOf",t.classes)}}function X$(e,n){if(1&e&&(X(0),V(1,J$,3,8,"ng-container",0),ee()),2&e){const t=n.$implicit,r=v().$implicit,i=v(2);f(),p("ngIf",!r.collapsed&&t.visible(i.settings))}}function ez(e,n){if(1&e&&(X(0),V(1,W$,1,7,"tr",64)(2,Q$,2,1,"ng-container",29)(3,X$,2,1,"ng-container",29),ee()),2&e){const t=n.$implicit,r=v(2);f(),p("ngIf",t.visible(r.settings)),f(),p("ngForOf",t.classes),f(),p("ngForOf",t.subElements)}}function tz(e,n){if(1&e){const t=ge();y(0,"div"),V(1,$U,1,10,"popup",1),y(2,"div",2)(3,"div")(4,"a",3),q("click",function(i){return B(t),j(v().collapseAll(i))}),b(5),_(),b(6," | "),y(7,"a",3),q("click",function(i){return B(t),j(v().expandAll(i))}),b(8),_()(),y(9,"div",4)(10,"span",5),V(11,zU,2,1,"ng-container",0)(12,GU,2,1,"ng-container",0)(13,qU,2,1,"ng-container",0),_(),x(14,"br"),b(15),y(16,"input",6),tt("ngModelChange",function(i){B(t);const o=v();return be(o.settings.grouping,i)||(o.settings.grouping=i),j(i)}),q("ngModelChange",function(){return B(t),j(v().updateCoverageInfo())}),_()(),y(17,"div",4),V(18,n$,9,6,"ng-container",0),_(),y(19,"div",7)(20,"button",8),q("click",function(){return B(t),j(v().popupVisible=!0)}),x(21,"i",9),b(22),_()()(),y(23,"div",10)(24,"table",11)(25,"colgroup"),x(26,"col",12),V(27,r$,1,0,"col",13)(28,i$,1,0,"col",14)(29,o$,1,0,"col",15)(30,s$,1,0,"col",16)(31,a$,1,0,"col",17)(32,l$,1,0,"col",18)(33,c$,1,0,"col",13)(34,u$,1,0,"col",16)(35,d$,1,0,"col",17)(36,f$,1,0,"col",18)(37,h$,1,0,"col",13)(38,g$,1,0,"col",16)(39,p$,1,0,"col",17)(40,m$,1,0,"col",18)(41,v$,1,0,"col",13)(42,_$,1,0,"col",16)(43,y$,1,0,"col",17)(44,C$,1,0,"col",18)(45,w$,1,0,"col",19),_(),y(46,"thead")(47,"tr",20),x(48,"th"),V(49,D$,2,1,"th",21)(50,b$,2,1,"th",22)(51,E$,2,1,"th",22)(52,I$,2,1,"th",22)(53,M$,2,2,"th",23),_(),y(54,"tr",24)(55,"td")(56,"input",25),tt("ngModelChange",function(i){B(t);const o=v();return be(o.settings.filter,i)||(o.settings.filter=i),j(i)}),_()(),V(57,T$,2,3,"td",21)(58,S$,2,3,"td",22)(59,N$,2,3,"td",22)(60,x$,2,3,"td",22)(61,O$,1,1,"td",23),_(),y(62,"tr")(63,"th")(64,"a",3),q("click",function(i){return B(t),j(v().updateSorting("name",i))}),x(65,"i",26),b(66),_()(),V(67,A$,4,6,"th",27)(68,R$,4,6,"th",27)(69,k$,4,6,"th",27)(70,F$,4,6,"th",27)(71,L$,4,6,"th",28)(72,P$,4,6,"th",27)(73,V$,4,6,"th",27)(74,H$,4,6,"th",28)(75,B$,4,6,"th",27)(76,j$,4,6,"th",27)(77,U$,4,6,"th",28)(78,$$,4,6,"th",27)(79,z$,4,6,"th",27)(80,G$,4,6,"th",28)(81,q$,6,7,"th",29),_()(),y(82,"tbody"),V(83,ez,4,3,"ng-container",29),_()()()()}if(2&e){const t=v();f(),p("ngIf",t.popupVisible),f(4),O(t.translations.collapseAll),f(3),O(t.translations.expandAll),f(3),p("ngIf",-1===t.settings.grouping),f(),p("ngIf",0===t.settings.grouping),f(),p("ngIf",t.settings.grouping>0),f(2),U(" ",t.translations.grouping," "),f(),p("max",t.settings.groupingMaximum),Qe("ngModel",t.settings.grouping),f(2),p("ngIf",t.historicCoverageExecutionTimes.length>0),f(4),O(t.metrics.length>0?t.translations.selectCoverageTypesAndMetrics:t.translations.selectCoverageTypes),f(5),p("ngIf",t.settings.showLineCoverage),f(),p("ngIf",t.settings.showLineCoverage),f(),p("ngIf",t.settings.showLineCoverage),f(),p("ngIf",t.settings.showLineCoverage),f(),p("ngIf",t.settings.showLineCoverage),f(),p("ngIf",t.settings.showLineCoverage),f(),p("ngIf",t.branchCoverageAvailable&&t.settings.showBranchCoverage),f(),p("ngIf",t.branchCoverageAvailable&&t.settings.showBranchCoverage),f(),p("ngIf",t.branchCoverageAvailable&&t.settings.showBranchCoverage),f(),p("ngIf",t.branchCoverageAvailable&&t.settings.showBranchCoverage),f(),p("ngIf",t.methodCoverageAvailable&&t.settings.showMethodCoverage),f(),p("ngIf",t.methodCoverageAvailable&&t.settings.showMethodCoverage),f(),p("ngIf",t.methodCoverageAvailable&&t.settings.showMethodCoverage),f(),p("ngIf",t.methodCoverageAvailable&&t.settings.showMethodCoverage),f(),p("ngIf",t.methodCoverageAvailable&&t.settings.showFullMethodCoverage),f(),p("ngIf",t.methodCoverageAvailable&&t.settings.showFullMethodCoverage),f(),p("ngIf",t.methodCoverageAvailable&&t.settings.showFullMethodCoverage),f(),p("ngIf",t.methodCoverageAvailable&&t.settings.showFullMethodCoverage),f(),p("ngForOf",t.settings.visibleMetrics),f(4),p("ngIf",t.settings.showLineCoverage),f(),p("ngIf",t.branchCoverageAvailable&&t.settings.showBranchCoverage),f(),p("ngIf",t.methodCoverageAvailable&&t.settings.showMethodCoverage),f(),p("ngIf",t.methodCoverageAvailable&&t.settings.showFullMethodCoverage),f(),p("ngIf",t.settings.visibleMetrics.length>0),f(3),In("placeholder",t.translations.filter),Qe("ngModel",t.settings.filter),f(),p("ngIf",t.settings.showLineCoverage),f(),p("ngIf",t.branchCoverageAvailable&&t.settings.showBranchCoverage),f(),p("ngIf",t.methodCoverageAvailable&&t.settings.showMethodCoverage),f(),p("ngIf",t.methodCoverageAvailable&&t.settings.showFullMethodCoverage),f(),p("ngIf",t.settings.visibleMetrics.length>0),f(4),p("ngClass",Fe(60,ut,"name"===t.settings.sortBy&&"asc"===t.settings.sortOrder,"name"===t.settings.sortBy&&"desc"===t.settings.sortOrder,"name"!==t.settings.sortBy)),f(),O(t.translations.name),f(),p("ngIf",t.settings.showLineCoverage),f(),p("ngIf",t.settings.showLineCoverage),f(),p("ngIf",t.settings.showLineCoverage),f(),p("ngIf",t.settings.showLineCoverage),f(),p("ngIf",t.settings.showLineCoverage),f(),p("ngIf",t.branchCoverageAvailable&&t.settings.showBranchCoverage),f(),p("ngIf",t.branchCoverageAvailable&&t.settings.showBranchCoverage),f(),p("ngIf",t.branchCoverageAvailable&&t.settings.showBranchCoverage),f(),p("ngIf",t.methodCoverageAvailable&&t.settings.showMethodCoverage),f(),p("ngIf",t.methodCoverageAvailable&&t.settings.showMethodCoverage),f(),p("ngIf",t.methodCoverageAvailable&&t.settings.showMethodCoverage),f(),p("ngIf",t.methodCoverageAvailable&&t.settings.showFullMethodCoverage),f(),p("ngIf",t.methodCoverageAvailable&&t.settings.showFullMethodCoverage),f(),p("ngIf",t.methodCoverageAvailable&&t.settings.showFullMethodCoverage),f(),p("ngForOf",t.settings.visibleMetrics),f(2),p("ngForOf",t.codeElements)}}let nz=(()=>{class e{constructor(t){this.queryString="",this.historicCoverageExecutionTimes=[],this.branchCoverageAvailable=!1,this.methodCoverageAvailable=!1,this.metrics=[],this.codeElements=[],this.translations={},this.popupVisible=!1,this.settings=new r3,this.sliderOptions={floor:0,ceil:100,step:1,ticksArray:[0,10,20,30,40,50,60,70,80,90,100],showTicks:!0},this.window=t.nativeWindow}ngOnInit(){this.historicCoverageExecutionTimes=this.window.historicCoverageExecutionTimes,this.branchCoverageAvailable=this.window.branchCoverageAvailable,this.methodCoverageAvailable=this.window.methodCoverageAvailable,this.metrics=this.window.metrics,this.translations=this.window.translations,jt.maximumDecimalPlacesForCoverageQuotas=this.window.maximumDecimalPlacesForCoverageQuotas;let t=!1;if(void 0!==this.window.history&&void 0!==this.window.history.replaceState&&null!==this.window.history.state&&null!=this.window.history.state.coverageInfoSettings)console.log("Coverage info: Restoring from history",this.window.history.state.coverageInfoSettings),t=!0,this.settings=JSON.parse(JSON.stringify(this.window.history.state.coverageInfoSettings));else{let i=0,o=this.window.assemblies;for(let s=0;s-1&&(this.queryString=window.location.href.substring(r)),this.updateCoverageInfo(),t&&this.restoreCollapseState()}onBeforeUnload(){if(this.saveCollapseState(),void 0!==this.window.history&&void 0!==this.window.history.replaceState){console.log("Coverage info: Updating history",this.settings);let t=new dM;null!==window.history.state&&(t=JSON.parse(JSON.stringify(this.window.history.state))),t.coverageInfoSettings=JSON.parse(JSON.stringify(this.settings)),window.history.replaceState(t,"")}}updateCoverageInfo(){let t=(new Date).getTime(),r=this.window.assemblies,i=[],o=0;if(0===this.settings.grouping)for(let l=0;l{for(let i=0;i{for(let o=0;ot&&(i[o].collapsed=this.settings.collapseStates[t]),t++,r(i[o].subElements)};r(this.codeElements)}static{this.\u0275fac=function(r){return new(r||e)(T(Xg))}}static{this.\u0275cmp=sn({type:e,selectors:[["coverage-info"]],hostBindings:function(r,i){1&r&&q("beforeunload",function(){return i.onBeforeUnload()},0,El)},standalone:!1,decls:1,vars:1,consts:[[4,"ngIf"],[3,"visible","translations","branchCoverageAvailable","methodCoverageAvailable","metrics","showLineCoverage","showBranchCoverage","showMethodCoverage","showMethodFullCoverage","visibleMetrics","visibleChange","showLineCoverageChange","showBranchCoverageChange","showMethodCoverageChange","showMethodFullCoverageChange","visibleMetricsChange",4,"ngIf"],[1,"customizebox"],["href","#",3,"click"],[1,"col-center"],[1,"slider-label"],["type","range","step","1","min","-1",3,"ngModelChange","max","ngModel"],[1,"col-right","right"],["type","button",3,"click"],[1,"icon-cog"],[1,"table-responsive"],[1,"overview","table-fixed","stripped"],[1,"column-min-200"],["class","column90",4,"ngIf"],["class","column105",4,"ngIf"],["class","column100",4,"ngIf"],["class","column70",4,"ngIf"],["class","column98",4,"ngIf"],["class","column112",4,"ngIf"],["class","column112",4,"ngFor","ngForOf"],[1,"header"],["class","center","colspan","6",4,"ngIf"],["class","center","colspan","4",4,"ngIf"],["class","center",4,"ngIf"],[1,"filterbar"],["type","text",3,"ngModelChange","ngModel","placeholder"],[3,"ngClass"],["class","right",4,"ngIf"],["class","center","colspan","2",4,"ngIf"],[4,"ngFor","ngForOf"],[3,"visibleChange","showLineCoverageChange","showBranchCoverageChange","showMethodCoverageChange","showMethodFullCoverageChange","visibleMetricsChange","visible","translations","branchCoverageAvailable","methodCoverageAvailable","metrics","showLineCoverage","showBranchCoverage","showMethodCoverage","showMethodFullCoverage","visibleMetrics"],[3,"ngModelChange","ngModel"],["value",""],[3,"value",4,"ngFor","ngForOf"],[3,"value"],["value","allChanges"],["value","lineCoverageIncreaseOnly"],["value","lineCoverageDecreaseOnly"],["value","branchCoverageIncreaseOnly",4,"ngIf"],["value","branchCoverageDecreaseOnly",4,"ngIf"],["value","methodCoverageIncreaseOnly",4,"ngIf"],["value","methodCoverageDecreaseOnly",4,"ngIf"],["value","fullMethodCoverageIncreaseOnly",4,"ngIf"],["value","fullMethodCoverageDecreaseOnly",4,"ngIf"],["value","branchCoverageIncreaseOnly"],["value","branchCoverageDecreaseOnly"],["value","methodCoverageIncreaseOnly"],["value","methodCoverageDecreaseOnly"],["value","fullMethodCoverageIncreaseOnly"],["value","fullMethodCoverageDecreaseOnly"],[1,"column90"],[1,"column105"],[1,"column100"],[1,"column70"],[1,"column98"],[1,"column112"],["colspan","6",1,"center"],["colspan","4",1,"center"],[1,"center"],[3,"valueChange","highValueChange","value","highValue","options"],[1,"right"],["colspan","2",1,"center"],["target","_blank",3,"href"],[1,"icon-info-circled"],["codeelement-row","",3,"element","collapsed","lineCoverageAvailable","branchCoverageAvailable","methodCoverageAvailable","methodFullCoverageAvailable","visibleMetrics",4,"ngIf"],["codeelement-row","",3,"element","collapsed","lineCoverageAvailable","branchCoverageAvailable","methodCoverageAvailable","methodFullCoverageAvailable","visibleMetrics"],["class-row","",3,"clazz","translations","lineCoverageAvailable","branchCoverageAvailable","methodCoverageAvailable","methodFullCoverageAvailable","visibleMetrics","historyComparisionDate",4,"ngIf"],["class-row","",3,"clazz","translations","lineCoverageAvailable","branchCoverageAvailable","methodCoverageAvailable","methodFullCoverageAvailable","visibleMetrics","historyComparisionDate"],["codeelement-row","",1,"namespace",3,"element","collapsed","lineCoverageAvailable","branchCoverageAvailable","methodCoverageAvailable","methodFullCoverageAvailable","visibleMetrics"],["class","namespace","class-row","",3,"clazz","translations","lineCoverageAvailable","branchCoverageAvailable","methodCoverageAvailable","methodFullCoverageAvailable","visibleMetrics","historyComparisionDate",4,"ngIf"],["class-row","",1,"namespace",3,"clazz","translations","lineCoverageAvailable","branchCoverageAvailable","methodCoverageAvailable","methodFullCoverageAvailable","visibleMetrics","historyComparisionDate"]],template:function(r,i){1&r&&V(0,tz,84,64,"div",0),2&r&&p("ngIf",i.codeElements.length>0)},dependencies:[Do,ci,zn,qg,Zg,na,Ug,la,jc,aa,uM,g3,H3,UU],encapsulation:2})}}return e})();class rz{constructor(){this.assembly="",this.numberOfRiskHotspots=10,this.filter="",this.sortBy="",this.sortOrder="asc"}}const tu=(e,n,t)=>({"icon-up-dir_active":e,"icon-down-dir_active":n,"icon-up-down-dir":t}),iz=(e,n)=>({lightred:e,lightgreen:n});function oz(e,n){if(1&e&&(y(0,"option",16),b(1),_()),2&e){const t=n.$implicit;p("value",t),f(),O(t)}}function sz(e,n){if(1&e&&(y(0,"span"),b(1),_()),2&e){const t=v(2);f(),O(t.translations.top)}}function az(e,n){1&e&&(y(0,"option",23),b(1,"20"),_())}function lz(e,n){1&e&&(y(0,"option",24),b(1,"50"),_())}function cz(e,n){1&e&&(y(0,"option",25),b(1,"100"),_())}function uz(e,n){if(1&e&&(y(0,"option",16),b(1),_()),2&e){const t=v(3);p("value",t.totalNumberOfRiskHotspots),f(),O(t.translations.all)}}function dz(e,n){if(1&e){const t=ge();y(0,"select",17),tt("ngModelChange",function(i){B(t);const o=v(2);return be(o.settings.numberOfRiskHotspots,i)||(o.settings.numberOfRiskHotspots=i),j(i)}),y(1,"option",18),b(2,"10"),_(),V(3,az,2,0,"option",19)(4,lz,2,0,"option",20)(5,cz,2,0,"option",21)(6,uz,2,2,"option",22),_()}if(2&e){const t=v(2);Qe("ngModel",t.settings.numberOfRiskHotspots),f(3),p("ngIf",t.totalNumberOfRiskHotspots>10),f(),p("ngIf",t.totalNumberOfRiskHotspots>20),f(),p("ngIf",t.totalNumberOfRiskHotspots>50),f(),p("ngIf",t.totalNumberOfRiskHotspots>100)}}function fz(e,n){1&e&&x(0,"col",26)}function hz(e,n){if(1&e){const t=ge();y(0,"th")(1,"a",13),q("click",function(i){const o=B(t).index;return j(v(2).updateSorting(""+o,i))}),x(2,"i",14),b(3),_(),y(4,"a",27),x(5,"i",28),_()()}if(2&e){const t=n.$implicit,r=n.index,i=v(2);f(2),p("ngClass",Fe(3,tu,i.settings.sortBy===""+r&&"asc"===i.settings.sortOrder,i.settings.sortBy===""+r&&"desc"===i.settings.sortOrder,i.settings.sortBy!==""+r)),f(),O(t.name),f(),In("href",t.explanationUrl,ir)}}function gz(e,n){if(1&e&&(y(0,"td",32),b(1),_()),2&e){const t=n.$implicit;p("ngClass",xh(2,iz,t.exceeded,!t.exceeded)),f(),O(t.value)}}function pz(e,n){if(1&e&&(y(0,"tr")(1,"td"),b(2),_(),y(3,"td")(4,"a",29),b(5),_()(),y(6,"td",30)(7,"a",29),b(8),_()(),V(9,gz,2,5,"td",31),_()),2&e){const t=n.$implicit,r=v(2);f(2),O(t.assembly),f(2),p("href",t.reportPath+r.queryString,ir),f(),O(t.class),f(),p("title",t.methodName),f(),p("href",t.reportPath+r.queryString+"#file"+t.fileIndex+"_line"+t.line,ir),f(),U(" ",t.methodShortName," "),f(),p("ngForOf",t.metrics)}}function mz(e,n){if(1&e){const t=ge();y(0,"div")(1,"div",1)(2,"div")(3,"select",2),tt("ngModelChange",function(i){B(t);const o=v();return be(o.settings.assembly,i)||(o.settings.assembly=i),j(i)}),q("ngModelChange",function(){return B(t),j(v().updateRiskHotpots())}),y(4,"option",3),b(5),_(),V(6,oz,2,2,"option",4),_()(),y(7,"div",5),V(8,sz,2,1,"span",0)(9,dz,7,5,"select",6),_(),x(10,"div",5),y(11,"div",7)(12,"span"),b(13),_(),y(14,"input",8),tt("ngModelChange",function(i){B(t);const o=v();return be(o.settings.filter,i)||(o.settings.filter=i),j(i)}),q("ngModelChange",function(){return B(t),j(v().updateRiskHotpots())}),_()()(),y(15,"div",9)(16,"table",10)(17,"colgroup"),x(18,"col",11)(19,"col",11)(20,"col",11),V(21,fz,1,0,"col",12),_(),y(22,"thead")(23,"tr")(24,"th")(25,"a",13),q("click",function(i){return B(t),j(v().updateSorting("assembly",i))}),x(26,"i",14),b(27),_()(),y(28,"th")(29,"a",13),q("click",function(i){return B(t),j(v().updateSorting("class",i))}),x(30,"i",14),b(31),_()(),y(32,"th")(33,"a",13),q("click",function(i){return B(t),j(v().updateSorting("method",i))}),x(34,"i",14),b(35),_()(),V(36,hz,6,7,"th",15),_()(),y(37,"tbody"),V(38,pz,10,7,"tr",15),function DD(e,n){const t=Z();let r;const i=e+k;t.firstCreatePass?(r=function HF(e,n){if(n)for(let t=n.length-1;t>=0;t--){const r=n[t];if(e===r.name)return r}}(n,t.pipeRegistry),t.data[i]=r,r.onDestroy&&(t.destroyHooks??=[]).push(i,r.onDestroy)):r=t.data[i];const o=r.factory||(r.factory=Or(r.type)),a=Et(T);try{const l=Za(!1),c=o();return Za(l),function Ih(e,n,t,r){t>=e.data.length&&(e.data[t]=null,e.blueprint[t]=null),n[t]=r}(t,D(),i,c),c}finally{Et(a)}}(39,"slice"),_()()()()}if(2&e){const t=v();f(3),Qe("ngModel",t.settings.assembly),f(2),O(t.translations.assembly),f(),p("ngForOf",t.assemblies),f(2),p("ngIf",t.totalNumberOfRiskHotspots>10),f(),p("ngIf",t.totalNumberOfRiskHotspots>10),f(4),U("",t.translations.filter," "),f(),Qe("ngModel",t.settings.filter),f(7),p("ngForOf",t.riskHotspotMetrics),f(5),p("ngClass",Fe(20,tu,"assembly"===t.settings.sortBy&&"asc"===t.settings.sortOrder,"assembly"===t.settings.sortBy&&"desc"===t.settings.sortOrder,"assembly"!==t.settings.sortBy)),f(),O(t.translations.assembly),f(3),p("ngClass",Fe(24,tu,"class"===t.settings.sortBy&&"asc"===t.settings.sortOrder,"class"===t.settings.sortBy&&"desc"===t.settings.sortOrder,"class"!==t.settings.sortBy)),f(),O(t.translations.class),f(3),p("ngClass",Fe(28,tu,"method"===t.settings.sortBy&&"asc"===t.settings.sortOrder,"method"===t.settings.sortBy&&"desc"===t.settings.sortOrder,"method"!==t.settings.sortBy)),f(),O(t.translations.method),f(),p("ngForOf",t.riskHotspotMetrics),f(2),p("ngForOf",function bD(e,n,t,r,i){const o=e+k,s=D(),a=function Br(e,n){return e[n]}(s,o);return function Bs(e,n){return e[1].data[n].pure}(s,o)?yD(s,gt(),n,a.transform,t,r,i,a):a.transform(t,r,i)}(39,16,t.riskHotspots,0,t.settings.numberOfRiskHotspots))}}let vz=(()=>{class e{constructor(t){this.queryString="",this.riskHotspotMetrics=[],this.riskHotspots=[],this.totalNumberOfRiskHotspots=0,this.assemblies=[],this.translations={},this.settings=new rz,this.window=t.nativeWindow}ngOnInit(){this.riskHotspotMetrics=this.window.riskHotspotMetrics,this.translations=this.window.translations,void 0!==this.window.history&&void 0!==this.window.history.replaceState&&null!==this.window.history.state&&null!=this.window.history.state.riskHotspotsSettings&&(console.log("Risk hotspots: Restoring from history",this.window.history.state.riskHotspotsSettings),this.settings=JSON.parse(JSON.stringify(this.window.history.state.riskHotspotsSettings)));const t=window.location.href.indexOf("?");t>-1&&(this.queryString=window.location.href.substring(t)),this.updateRiskHotpots()}onDonBeforeUnlodad(){if(void 0!==this.window.history&&void 0!==this.window.history.replaceState){console.log("Risk hotspots: Updating history",this.settings);let t=new dM;null!==window.history.state&&(t=JSON.parse(JSON.stringify(this.window.history.state))),t.riskHotspotsSettings=JSON.parse(JSON.stringify(this.settings)),window.history.replaceState(t,"")}}updateRiskHotpots(){const t=this.window.riskHotspots;if(this.totalNumberOfRiskHotspots=t.length,0===this.assemblies.length){let s=[];for(let a=0;a0)},dependencies:[Do,ci,zn,qg,Zg,na,la,jc,aa,Xb],encapsulation:2})}}return e})(),_z=(()=>{class e{static{this.\u0275fac=function(r){return new(r||e)}}static{this.\u0275mod=cr({type:e,bootstrap:[vz,nz]})}static{this.\u0275inj=Nn({providers:[Xg],imports:[hH,hj,n3]})}}return e})();fH().bootstrapModule(_z).catch(e=>console.error(e))}},No=>{No(No.s=332)}]); \ No newline at end of file diff --git a/source/coverage/report.css b/source/coverage/report.css new file mode 100644 index 0000000..42a58f6 --- /dev/null +++ b/source/coverage/report.css @@ -0,0 +1,834 @@ +:root { + --green: #0aad0a; + --lightgreen: #dcf4dc; +} + +html { font-family: sans-serif; margin: 0; padding: 0; font-size: 0.9em; background-color: #d6d6d6; height: 100%; } +body { margin: 0; padding: 0; height: 100%; color: #000; } +h1 { font-family: 'Century Gothic', sans-serif; font-size: 1.2em; font-weight: normal; color: #fff; background-color: #6f6f6f; padding: 10px; margin: 20px -20px 20px -20px; } +h1:first-of-type { margin-top: 0; } +h2 { font-size: 1.0em; font-weight: bold; margin: 10px 0 15px 0; padding: 0; } +h3 { font-size: 1.0em; font-weight: bold; margin: 0 0 10px 0; padding: 0; display: inline-block; } +input, select, button { border: 1px solid #767676; border-radius: 0; } +button { background-color: #ddd; cursor: pointer; } +a { color: #c00; text-decoration: none; } +a:hover { color: #000; text-decoration: none; } +h1 a.back { color: #fff; background-color: #949494; display: inline-block; margin: -12px 5px -10px -10px; padding: 10px; border-right: 1px solid #fff; } +h1 a.back:hover { background-color: #ccc; } +h1 a.button { color: #000; background-color: #bebebe; margin: -5px 0 0 10px; padding: 5px 8px 5px 8px; border: 1px solid #fff; font-size: 0.9em; border-radius: 3px; float:right; } +h1 a.button:hover { background-color: #ccc; } +h1 a.button i { position: relative; top: 1px; } + +.container { margin: auto; max-width: 1650px; width: 90%; background-color: #fff; display: flex; box-shadow: 0 0 60px #7d7d7d; min-height: 100%; } +.containerleft { padding: 0 20px 20px 20px; flex: 1; min-width: 1%; } +.containerright { width: 340px; min-width: 340px; background-color: #e5e5e5; height: 100%; } +.containerrightfixed { position: fixed; padding: 0 20px 20px 20px; border-left: 1px solid #6f6f6f; width: 300px; overflow-y: auto; height: 100%; top: 0; bottom: 0; } +.containerrightfixed h1 { background-color: #c00; } +.containerrightfixed label, .containerright a { white-space: nowrap; overflow: hidden; display: inline-block; width: 100%; max-width: 300px; text-overflow: ellipsis; } +.containerright a { margin-bottom: 3px; } + +@media screen and (max-width:1200px){ + .container { box-shadow: none; width: 100%; } + .containerright { display: none; } +} + +.popup-container { position: fixed; left: 0; right: 0; top: 0; bottom: 0; background-color: rgb(0, 0, 0, 0.6); z-index: 100; } +.popup { position: absolute; top: 50%; right: 50%; transform: translate(50%,-50%); background-color: #fff; padding: 25px; border-radius: 15px; min-width: 300px; } +.popup .close { text-align: right; color: #979797; font-size: 25px;position: relative; left: 10px; bottom: 10px; cursor: pointer; } + +.footer { font-size: 0.7em; text-align: center; margin-top: 35px; } + +.card-group { display: flex; flex-wrap: wrap; margin-top: -15px; margin-left: -15px; } +.card-group + .card-group { margin-top: 0; } +.card-group .card { margin-top: 15px; margin-left: 15px; display: flex; flex-direction: column; background-color: #e4e4e4; background: radial-gradient(circle, #fefefe 0%, #f6f6f6 100%); border: 1px solid #c1c1c1; padding: 15px; color: #6f6f6f; max-width: 100% } +.card-group .card .card-header { font-size: 1.5rem; font-family: 'Century Gothic', sans-serif; margin-bottom: 15px; flex-grow: 1; } +.card-group .card .card-body { display: flex; flex-direction: row; gap: 15px; flex-grow: 1; } +.card-group .card .card-body div.table { display: flex; flex-direction: column; } +.card-group .card .large { font-size: 5rem; line-height: 5rem; font-weight: bold; align-self: flex-end; border-left-width: 4px; padding-left: 10px; } +.card-group .card table { align-self: flex-end; border-collapse: collapse; } +.card-group .card table tr { border-bottom: 1px solid #c1c1c1; } +.card-group .card table tr:hover { background-color: #c1c1c1; } +.card-group .card table tr:last-child { border-bottom: none; } +.card-group .card table th, .card-group .card table td { padding: 2px; } +.card-group td.limit-width { max-width: 200px; text-overflow: ellipsis; overflow: hidden; } +.card-group td.overflow-wrap { overflow-wrap: anywhere; } + +.pro-button { color: #fff; background-color: #20A0D2; background-image: linear-gradient(50deg, #1c7ed6 0%, #23b8cf 100%); padding: 10px; border-radius: 3px; font-weight: bold; display: inline-block; } +.pro-button:hover { color: #fff; background-color: #1C8EB7; background-image: linear-gradient(50deg, #1A6FBA 0%, #1EA1B5 100%); } +.pro-button-tiny { border-radius: 10px; padding: 3px 8px; } + +th { text-align: left; } +.table-fixed { table-layout: fixed; } +.table-responsive { overflow-x: auto; } +.table-responsive::-webkit-scrollbar { height: 20px; } +.table-responsive::-webkit-scrollbar-thumb { background-color: #6f6f6f; border-radius: 20px; border: 5px solid #fff; } +.overview { border: 1px solid #c1c1c1; border-collapse: collapse; width: 100%; word-wrap: break-word; } +.overview th { border: 1px solid #c1c1c1; border-collapse: collapse; padding: 2px 4px 2px 4px; background-color: #ddd; } +.overview tr.namespace th { background-color: #dcdcdc; } +.overview thead th { background-color: #d1d1d1; } +.overview th a { color: #000; } +.overview tr.namespace a { margin-left: 15px; display: block; } +.overview td { border: 1px solid #c1c1c1; border-collapse: collapse; padding: 2px 5px 2px 5px; } +.overview tr.filterbar td { height: 60px; } +.overview tr.header th { background-color: #d1d1d1; } +.overview tr.header th:nth-child(2n+1) { background-color: #ddd; } +.overview tr.header th:first-child { border-left: 1px solid #fff; border-top: 1px solid #fff; background-color: #fff; } +.overview tbody tr:hover>td { background-color: #b0b0b0; } + +div.currenthistory { margin: -2px -5px 0 -5px; padding: 2px 5px 2px 5px; height: 16px; } +.coverage { border-collapse: collapse; font-size: 5px; height: 10px; } +.coverage td { padding: 0; border: none; } +.stripped tr:nth-child(2n+1) { background-color: #F3F3F3; } + +.customizebox { font-size: 0.75em; margin-bottom: 7px; display: grid; grid-template-columns: 1fr; grid-template-rows: auto auto auto auto; grid-column-gap: 10px; grid-row-gap: 10px; } +.customizebox>div { align-self: end; } +.customizebox div.col-right input { width: 150px; } + +@media screen and (min-width: 1000px) { + .customizebox { grid-template-columns: repeat(4, 1fr); grid-template-rows: 1fr; } + .customizebox div.col-center { justify-self: center; } + .customizebox div.col-right { justify-self: end; } +} +.slider-label { position: relative; left: 85px; } + +.percentagebar { + padding-left: 3px; +} +a.percentagebar { + padding-left: 6px; +} +.percentagebarundefined { + border-left: 2px solid #fff; +} +.percentagebar0 { + border-left: 2px solid #c10909; +} +.percentagebar10 { + border-left: 2px solid; + border-image: linear-gradient(to bottom, #c10909 90%, var(--green) 90%, var(--green) 100%) 1; +} +.percentagebar20 { + border-left: 2px solid; + border-image: linear-gradient(to bottom, #c10909 80%, var(--green) 80%, var(--green) 100%) 1; +} +.percentagebar30 { + border-left: 2px solid; + border-image: linear-gradient(to bottom, #c10909 70%, var(--green) 70%, var(--green) 100%) 1; +} +.percentagebar40 { + border-left: 2px solid; + border-image: linear-gradient(to bottom, #c10909 60%, var(--green) 60%, var(--green) 100%) 1; +} +.percentagebar50 { + border-left: 2px solid; + border-image: linear-gradient(to bottom, #c10909 50%, var(--green) 50%, var(--green) 100%) 1; +} +.percentagebar60 { + border-left: 2px solid; + border-image: linear-gradient(to bottom, #c10909 40%, var(--green) 40%, var(--green) 100%) 1; +} +.percentagebar70 { + border-left: 2px solid; + border-image: linear-gradient(to bottom, #c10909 30%, var(--green) 30%, var(--green) 100%) 1; +} +.percentagebar80 { + border-left: 2px solid; + border-image: linear-gradient(to bottom, #c10909 20%, var(--green) 20%, var(--green) 100%) 1; +} +.percentagebar90 { + border-left: 2px solid; + border-image: linear-gradient(to bottom, #c10909 10%, var(--green) 10%, var(--green) 100%) 1; +} +.percentagebar100 { + border-left: 2px solid var(--green); +} + +.mt-1 { margin-top: 4px; } +.hidden, .ng-hide { display: none; } +.right { text-align: right; } +.center { text-align: center; } +.rightmargin { padding-right: 8px; } +.leftmargin { padding-left: 5px; } +.green { background-color: var(--green); } +.lightgreen { background-color: var(--lightgreen); } +.red { background-color: #c10909; } +.lightred { background-color: #f7dede; } +.orange { background-color: #FFA500; } +.lightorange { background-color: #FFEFD5; } +.gray { background-color: #dcdcdc; } +.lightgray { color: #888888; } +.lightgraybg { background-color: #dadada; } + +code { font-family: Consolas, monospace; font-size: 0.9em; } + +.toggleZoom { text-align:right; } + +.historychart svg { max-width: 100%; } +.ct-chart { position: relative; } +.ct-chart .ct-line { stroke-width: 2px !important; } +.ct-chart .ct-point { stroke-width: 6px !important; transition: stroke-width .2s; } +.ct-chart .ct-point:hover { stroke-width: 10px !important; } +.ct-chart .ct-series.ct-series-a .ct-line, .ct-chart .ct-series.ct-series-a .ct-point { stroke: #c00 !important;} +.ct-chart .ct-series.ct-series-b .ct-line, .ct-chart .ct-series.ct-series-b .ct-point { stroke: #1c2298 !important;} +.ct-chart .ct-series.ct-series-c .ct-line, .ct-chart .ct-series.ct-series-c .ct-point { stroke: #0aad0a !important;} +.ct-chart .ct-series.ct-series-d .ct-line, .ct-chart .ct-series.ct-series-d .ct-point { stroke: #FF6A00 !important;} + +.tinylinecoveragechart, .tinybranchcoveragechart, .tinymethodcoveragechart, .tinyfullmethodcoveragechart { background-color: #fff; margin-left: -3px; float: left; border: 1px solid #c1c1c1; width: 30px; height: 18px; } +.historiccoverageoffset { margin-top: 7px; } + +.tinylinecoveragechart .ct-line, .tinybranchcoveragechart .ct-line, .tinymethodcoveragechart .ct-line, .tinyfullmethodcoveragechart .ct-line { stroke-width: 1px !important; } +.tinybranchcoveragechart .ct-series.ct-series-a .ct-line { stroke: #1c2298 !important; } +.tinymethodcoveragechart .ct-series.ct-series-a .ct-line { stroke: #0aad0a !important; } +.tinyfullmethodcoveragechart .ct-series.ct-series-a .ct-line { stroke: #FF6A00 !important; } + +.linecoverage { background-color: #c00; width: 10px; height: 8px; border: 1px solid #000; display: inline-block; } +.branchcoverage { background-color: #1c2298; width: 10px; height: 8px; border: 1px solid #000; display: inline-block; } +.codeelementcoverage { background-color: #0aad0a; width: 10px; height: 8px; border: 1px solid #000; display: inline-block; } +.fullcodeelementcoverage { background-color: #FF6A00; width: 10px; height: 8px; border: 1px solid #000; display: inline-block; } + +.tooltip { position: absolute; display: none; padding: 5px; background: #F4C63D; color: #453D3F; pointer-events: none; z-index: 1; min-width: 250px; } + +.column-min-200 { min-width: 200px; } +.column60 { width: 60px; } +.column70 { width: 70px; } +.column90 { width: 90px; } +.column98 { width: 98px; } +.column100 { width: 100px; } +.column105 { width: 105px; } +.column112 { width: 112px; } + +.cardpercentagebar { border-left-style: solid; } +.cardpercentagebar0 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 0%, var(--green) 0%) 1; } +.cardpercentagebar1 { border-image: linear-gradient(to bottom, #c10909 1%, #c10909 1%, var(--green) 1%) 1; } +.cardpercentagebar2 { border-image: linear-gradient(to bottom, #c10909 2%, #c10909 2%, var(--green) 2%) 1; } +.cardpercentagebar3 { border-image: linear-gradient(to bottom, #c10909 3%, #c10909 3%, var(--green) 3%) 1; } +.cardpercentagebar4 { border-image: linear-gradient(to bottom, #c10909 4%, #c10909 4%, var(--green) 4%) 1; } +.cardpercentagebar5 { border-image: linear-gradient(to bottom, #c10909 5%, #c10909 5%, var(--green) 5%) 1; } +.cardpercentagebar6 { border-image: linear-gradient(to bottom, #c10909 6%, #c10909 6%, var(--green) 6%) 1; } +.cardpercentagebar7 { border-image: linear-gradient(to bottom, #c10909 7%, #c10909 7%, var(--green) 7%) 1; } +.cardpercentagebar8 { border-image: linear-gradient(to bottom, #c10909 8%, #c10909 8%, var(--green) 8%) 1; } +.cardpercentagebar9 { border-image: linear-gradient(to bottom, #c10909 9%, #c10909 9%, var(--green) 9%) 1; } +.cardpercentagebar10 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 10%, var(--green) 10%) 1; } +.cardpercentagebar11 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 11%, var(--green) 11%) 1; } +.cardpercentagebar12 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 12%, var(--green) 12%) 1; } +.cardpercentagebar13 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 13%, var(--green) 13%) 1; } +.cardpercentagebar14 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 14%, var(--green) 14%) 1; } +.cardpercentagebar15 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 15%, var(--green) 15%) 1; } +.cardpercentagebar16 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 16%, var(--green) 16%) 1; } +.cardpercentagebar17 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 17%, var(--green) 17%) 1; } +.cardpercentagebar18 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 18%, var(--green) 18%) 1; } +.cardpercentagebar19 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 19%, var(--green) 19%) 1; } +.cardpercentagebar20 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 20%, var(--green) 20%) 1; } +.cardpercentagebar21 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 21%, var(--green) 21%) 1; } +.cardpercentagebar22 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 22%, var(--green) 22%) 1; } +.cardpercentagebar23 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 23%, var(--green) 23%) 1; } +.cardpercentagebar24 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 24%, var(--green) 24%) 1; } +.cardpercentagebar25 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 25%, var(--green) 25%) 1; } +.cardpercentagebar26 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 26%, var(--green) 26%) 1; } +.cardpercentagebar27 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 27%, var(--green) 27%) 1; } +.cardpercentagebar28 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 28%, var(--green) 28%) 1; } +.cardpercentagebar29 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 29%, var(--green) 29%) 1; } +.cardpercentagebar30 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 30%, var(--green) 30%) 1; } +.cardpercentagebar31 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 31%, var(--green) 31%) 1; } +.cardpercentagebar32 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 32%, var(--green) 32%) 1; } +.cardpercentagebar33 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 33%, var(--green) 33%) 1; } +.cardpercentagebar34 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 34%, var(--green) 34%) 1; } +.cardpercentagebar35 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 35%, var(--green) 35%) 1; } +.cardpercentagebar36 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 36%, var(--green) 36%) 1; } +.cardpercentagebar37 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 37%, var(--green) 37%) 1; } +.cardpercentagebar38 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 38%, var(--green) 38%) 1; } +.cardpercentagebar39 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 39%, var(--green) 39%) 1; } +.cardpercentagebar40 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 40%, var(--green) 40%) 1; } +.cardpercentagebar41 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 41%, var(--green) 41%) 1; } +.cardpercentagebar42 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 42%, var(--green) 42%) 1; } +.cardpercentagebar43 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 43%, var(--green) 43%) 1; } +.cardpercentagebar44 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 44%, var(--green) 44%) 1; } +.cardpercentagebar45 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 45%, var(--green) 45%) 1; } +.cardpercentagebar46 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 46%, var(--green) 46%) 1; } +.cardpercentagebar47 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 47%, var(--green) 47%) 1; } +.cardpercentagebar48 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 48%, var(--green) 48%) 1; } +.cardpercentagebar49 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 49%, var(--green) 49%) 1; } +.cardpercentagebar50 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 50%, var(--green) 50%) 1; } +.cardpercentagebar51 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 51%, var(--green) 51%) 1; } +.cardpercentagebar52 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 52%, var(--green) 52%) 1; } +.cardpercentagebar53 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 53%, var(--green) 53%) 1; } +.cardpercentagebar54 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 54%, var(--green) 54%) 1; } +.cardpercentagebar55 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 55%, var(--green) 55%) 1; } +.cardpercentagebar56 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 56%, var(--green) 56%) 1; } +.cardpercentagebar57 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 57%, var(--green) 57%) 1; } +.cardpercentagebar58 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 58%, var(--green) 58%) 1; } +.cardpercentagebar59 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 59%, var(--green) 59%) 1; } +.cardpercentagebar60 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 60%, var(--green) 60%) 1; } +.cardpercentagebar61 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 61%, var(--green) 61%) 1; } +.cardpercentagebar62 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 62%, var(--green) 62%) 1; } +.cardpercentagebar63 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 63%, var(--green) 63%) 1; } +.cardpercentagebar64 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 64%, var(--green) 64%) 1; } +.cardpercentagebar65 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 65%, var(--green) 65%) 1; } +.cardpercentagebar66 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 66%, var(--green) 66%) 1; } +.cardpercentagebar67 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 67%, var(--green) 67%) 1; } +.cardpercentagebar68 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 68%, var(--green) 68%) 1; } +.cardpercentagebar69 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 69%, var(--green) 69%) 1; } +.cardpercentagebar70 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 70%, var(--green) 70%) 1; } +.cardpercentagebar71 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 71%, var(--green) 71%) 1; } +.cardpercentagebar72 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 72%, var(--green) 72%) 1; } +.cardpercentagebar73 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 73%, var(--green) 73%) 1; } +.cardpercentagebar74 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 74%, var(--green) 74%) 1; } +.cardpercentagebar75 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 75%, var(--green) 75%) 1; } +.cardpercentagebar76 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 76%, var(--green) 76%) 1; } +.cardpercentagebar77 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 77%, var(--green) 77%) 1; } +.cardpercentagebar78 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 78%, var(--green) 78%) 1; } +.cardpercentagebar79 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 79%, var(--green) 79%) 1; } +.cardpercentagebar80 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 80%, var(--green) 80%) 1; } +.cardpercentagebar81 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 81%, var(--green) 81%) 1; } +.cardpercentagebar82 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 82%, var(--green) 82%) 1; } +.cardpercentagebar83 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 83%, var(--green) 83%) 1; } +.cardpercentagebar84 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 84%, var(--green) 84%) 1; } +.cardpercentagebar85 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 85%, var(--green) 85%) 1; } +.cardpercentagebar86 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 86%, var(--green) 86%) 1; } +.cardpercentagebar87 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 87%, var(--green) 87%) 1; } +.cardpercentagebar88 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 88%, var(--green) 88%) 1; } +.cardpercentagebar89 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 89%, var(--green) 89%) 1; } +.cardpercentagebar90 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 90%, var(--green) 90%) 1; } +.cardpercentagebar91 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 91%, var(--green) 91%) 1; } +.cardpercentagebar92 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 92%, var(--green) 92%) 1; } +.cardpercentagebar93 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 93%, var(--green) 93%) 1; } +.cardpercentagebar94 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 94%, var(--green) 94%) 1; } +.cardpercentagebar95 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 95%, var(--green) 95%) 1; } +.cardpercentagebar96 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 96%, var(--green) 96%) 1; } +.cardpercentagebar97 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 97%, var(--green) 97%) 1; } +.cardpercentagebar98 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 98%, var(--green) 98%) 1; } +.cardpercentagebar99 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 99%, var(--green) 99%) 1; } +.cardpercentagebar100 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 100%, var(--green) 100%) 1; } + +.covered0 { width: 0px; } +.covered1 { width: 1px; } +.covered2 { width: 2px; } +.covered3 { width: 3px; } +.covered4 { width: 4px; } +.covered5 { width: 5px; } +.covered6 { width: 6px; } +.covered7 { width: 7px; } +.covered8 { width: 8px; } +.covered9 { width: 9px; } +.covered10 { width: 10px; } +.covered11 { width: 11px; } +.covered12 { width: 12px; } +.covered13 { width: 13px; } +.covered14 { width: 14px; } +.covered15 { width: 15px; } +.covered16 { width: 16px; } +.covered17 { width: 17px; } +.covered18 { width: 18px; } +.covered19 { width: 19px; } +.covered20 { width: 20px; } +.covered21 { width: 21px; } +.covered22 { width: 22px; } +.covered23 { width: 23px; } +.covered24 { width: 24px; } +.covered25 { width: 25px; } +.covered26 { width: 26px; } +.covered27 { width: 27px; } +.covered28 { width: 28px; } +.covered29 { width: 29px; } +.covered30 { width: 30px; } +.covered31 { width: 31px; } +.covered32 { width: 32px; } +.covered33 { width: 33px; } +.covered34 { width: 34px; } +.covered35 { width: 35px; } +.covered36 { width: 36px; } +.covered37 { width: 37px; } +.covered38 { width: 38px; } +.covered39 { width: 39px; } +.covered40 { width: 40px; } +.covered41 { width: 41px; } +.covered42 { width: 42px; } +.covered43 { width: 43px; } +.covered44 { width: 44px; } +.covered45 { width: 45px; } +.covered46 { width: 46px; } +.covered47 { width: 47px; } +.covered48 { width: 48px; } +.covered49 { width: 49px; } +.covered50 { width: 50px; } +.covered51 { width: 51px; } +.covered52 { width: 52px; } +.covered53 { width: 53px; } +.covered54 { width: 54px; } +.covered55 { width: 55px; } +.covered56 { width: 56px; } +.covered57 { width: 57px; } +.covered58 { width: 58px; } +.covered59 { width: 59px; } +.covered60 { width: 60px; } +.covered61 { width: 61px; } +.covered62 { width: 62px; } +.covered63 { width: 63px; } +.covered64 { width: 64px; } +.covered65 { width: 65px; } +.covered66 { width: 66px; } +.covered67 { width: 67px; } +.covered68 { width: 68px; } +.covered69 { width: 69px; } +.covered70 { width: 70px; } +.covered71 { width: 71px; } +.covered72 { width: 72px; } +.covered73 { width: 73px; } +.covered74 { width: 74px; } +.covered75 { width: 75px; } +.covered76 { width: 76px; } +.covered77 { width: 77px; } +.covered78 { width: 78px; } +.covered79 { width: 79px; } +.covered80 { width: 80px; } +.covered81 { width: 81px; } +.covered82 { width: 82px; } +.covered83 { width: 83px; } +.covered84 { width: 84px; } +.covered85 { width: 85px; } +.covered86 { width: 86px; } +.covered87 { width: 87px; } +.covered88 { width: 88px; } +.covered89 { width: 89px; } +.covered90 { width: 90px; } +.covered91 { width: 91px; } +.covered92 { width: 92px; } +.covered93 { width: 93px; } +.covered94 { width: 94px; } +.covered95 { width: 95px; } +.covered96 { width: 96px; } +.covered97 { width: 97px; } +.covered98 { width: 98px; } +.covered99 { width: 99px; } +.covered100 { width: 100px; } + + @media print { + html, body { background-color: #fff; } + .container { max-width: 100%; width: 100%; padding: 0; } + .overview colgroup col:first-child { width: 300px; } +} + +.icon-up-down-dir { + background-image: url(icon_up-down-dir.svg), url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB3aWR0aD0iMTc5MiIgaGVpZ2h0PSIxNzkyIiB2aWV3Qm94PSIwIDAgMTc5MiAxNzkyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Im0gMTQwOCw3NDIgcSAwLDI2IC0xOSw0NSAtMTksMTkgLTQ1LDE5IEggNDQ4IHEgLTI2LDAgLTQ1LC0xOSAtMTksLTE5IC0xOSwtNDUgMCwtMjYgMTksLTQ1IEwgODUxLDI0OSBxIDE5LC0xOSA0NSwtMTkgMjYsMCA0NSwxOSBsIDQ0OCw0NDggcSAxOSwxOSAxOSw0NSB6IiAvPjxwYXRoIGQ9Im0gMTQwOCwxMDUwIHEgMCwyNiAtMTksNDUgbCAtNDQ4LDQ0OCBxIC0xOSwxOSAtNDUsMTkgLTI2LDAgLTQ1LC0xOSBMIDQwMywxMDk1IHEgLTE5LC0xOSAtMTksLTQ1IDAsLTI2IDE5LC00NSAxOSwtMTkgNDUsLTE5IGggODk2IHEgMjYsMCA0NSwxOSAxOSwxOSAxOSw0NSB6IiAvPjwvc3ZnPg==); + background-repeat: no-repeat; + background-size: contain; + padding-left: 15px; + height: 0.9em; + display: inline-block; + position: relative; + top: 3px; +} +.icon-up-dir_active { + background-image: url(icon_up-dir.svg), url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB3aWR0aD0iMTc5MiIgaGVpZ2h0PSIxNzkyIiB2aWV3Qm94PSIwIDAgMTc5MiAxNzkyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGZpbGw9IiNjMDAiIGQ9Ik0xNDA4IDEyMTZxMCAyNi0xOSA0NXQtNDUgMTloLTg5NnEtMjYgMC00NS0xOXQtMTktNDUgMTktNDVsNDQ4LTQ0OHExOS0xOSA0NS0xOXQ0NSAxOWw0NDggNDQ4cTE5IDE5IDE5IDQ1eiIvPjwvc3ZnPg==); + background-repeat: no-repeat; + background-size: contain; + padding-left: 15px; + height: 0.9em; + display: inline-block; + position: relative; + top: 3px; +} +.icon-down-dir_active { + background-image: url(icon_up-dir_active.svg), url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB3aWR0aD0iMTc5MiIgaGVpZ2h0PSIxNzkyIiB2aWV3Qm94PSIwIDAgMTc5MiAxNzkyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGZpbGw9IiNjMDAiIGQ9Ik0xNDA4IDcwNHEwIDI2LTE5IDQ1bC00NDggNDQ4cS0xOSAxOS00NSAxOXQtNDUtMTlsLTQ0OC00NDhxLTE5LTE5LTE5LTQ1dDE5LTQ1IDQ1LTE5aDg5NnEyNiAwIDQ1IDE5dDE5IDQ1eiIvPjwvc3ZnPg==); + background-repeat: no-repeat; + background-size: contain; + padding-left: 15px; + height: 0.9em; + display: inline-block; + position: relative; + top: 3px; +} +.icon-info-circled { + background-image: url(icon_info-circled.svg), url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB3aWR0aD0iMTc5MiIgaGVpZ2h0PSIxNzkyIiB2aWV3Qm94PSIwIDAgMTc5MiAxNzkyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxjaXJjbGUgY3g9Ijg5NiIgY3k9Ijg5NiIgcj0iNzUwIiBmaWxsPSIjZmZmIiAvPjxwYXRoIGZpbGw9IiMyOEE1RkYiIGQ9Ik0xMTUyIDEzNzZ2LTE2MHEwLTE0LTktMjN0LTIzLTloLTk2di01MTJxMC0xNC05LTIzdC0yMy05aC0zMjBxLTE0IDAtMjMgOXQtOSAyM3YxNjBxMCAxNCA5IDIzdDIzIDloOTZ2MzIwaC05NnEtMTQgMC0yMyA5dC05IDIzdjE2MHEwIDE0IDkgMjN0MjMgOWg0NDhxMTQgMCAyMy05dDktMjN6bS0xMjgtODk2di0xNjBxMC0xNC05LTIzdC0yMy05aC0xOTJxLTE0IDAtMjMgOXQtOSAyM3YxNjBxMCAxNCA5IDIzdDIzIDloMTkycTE0IDAgMjMtOXQ5LTIzem02NDAgNDE2cTAgMjA5LTEwMyAzODUuNXQtMjc5LjUgMjc5LjUtMzg1LjUgMTAzLTM4NS41LTEwMy0yNzkuNS0yNzkuNS0xMDMtMzg1LjUgMTAzLTM4NS41IDI3OS41LTI3OS41IDM4NS41LTEwMyAzODUuNSAxMDMgMjc5LjUgMjc5LjUgMTAzIDM4NS41eiIvPjwvc3ZnPg==); + background-repeat: no-repeat; + background-size: contain; + padding-left: 15px; + height: 0.9em; + display: inline-block; +} +.icon-plus { + background-image: url(icon_plus.svg), url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB3aWR0aD0iMTc5MiIgaGVpZ2h0PSIxNzkyIiB2aWV3Qm94PSIwIDAgMTc5MiAxNzkyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Ik0xNjAwIDczNnYxOTJxMCA0MC0yOCA2OHQtNjggMjhoLTQxNnY0MTZxMCA0MC0yOCA2OHQtNjggMjhoLTE5MnEtNDAgMC02OC0yOHQtMjgtNjh2LTQxNmgtNDE2cS00MCAwLTY4LTI4dC0yOC02OHYtMTkycTAtNDAgMjgtNjh0NjgtMjhoNDE2di00MTZxMC00MCAyOC02OHQ2OC0yOGgxOTJxNDAgMCA2OCAyOHQyOCA2OHY0MTZoNDE2cTQwIDAgNjggMjh0MjggNjh6Ii8+PC9zdmc+); + background-repeat: no-repeat; + background-size: contain; + padding-left: 15px; + height: 0.9em; + display: inline-block; + position: relative; + top: 3px; +} +.icon-minus { + background-image: url(icon_minus.svg), url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB3aWR0aD0iMTc5MiIgaGVpZ2h0PSIxNzkyIiB2aWV3Qm94PSIwIDAgMTc5MiAxNzkyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGZpbGw9IiNjMDAiIGQ9Ik0xNjAwIDczNnYxOTJxMCA0MC0yOCA2OHQtNjggMjhoLTEyMTZxLTQwIDAtNjgtMjh0LTI4LTY4di0xOTJxMC00MCAyOC02OHQ2OC0yOGgxMjE2cTQwIDAgNjggMjh0MjggNjh6Ii8+PC9zdmc+); + background-repeat: no-repeat; + background-size: contain; + padding-left: 15px; + height: 0.9em; + display: inline-block; + position: relative; + top: 3px; +} +.icon-wrench { + background-image: url(icon_wrench.svg), url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB3aWR0aD0iMTc5MiIgaGVpZ2h0PSIxNzkyIiB2aWV3Qm94PSIwIDAgMTc5MiAxNzkyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Ik00NDggMTQ3MnEwLTI2LTE5LTQ1dC00NS0xOS00NSAxOS0xOSA0NSAxOSA0NSA0NSAxOSA0NS0xOSAxOS00NXptNjQ0LTQyMGwtNjgyIDY4MnEtMzcgMzctOTAgMzctNTIgMC05MS0zN2wtMTA2LTEwOHEtMzgtMzYtMzgtOTAgMC01MyAzOC05MWw2ODEtNjgxcTM5IDk4IDExNC41IDE3My41dDE3My41IDExNC41em02MzQtNDM1cTAgMzktMjMgMTA2LTQ3IDEzNC0xNjQuNSAyMTcuNXQtMjU4LjUgODMuNXEtMTg1IDAtMzE2LjUtMTMxLjV0LTEzMS41LTMxNi41IDEzMS41LTMxNi41IDMxNi41LTEzMS41cTU4IDAgMTIxLjUgMTYuNXQxMDcuNSA0Ni41cTE2IDExIDE2IDI4dC0xNiAyOGwtMjkzIDE2OXYyMjRsMTkzIDEwN3E1LTMgNzktNDguNXQxMzUuNS04MSA3MC41LTM1LjVxMTUgMCAyMy41IDEwdDguNSAyNXoiLz48L3N2Zz4=); + background-repeat: no-repeat; + background-size: contain; + padding-left: 20px; + height: 0.9em; + display: inline-block; +} +.icon-cog { + background-image: url(icon_cog.svg), url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHdpZHRoPSI1MTIiIGhlaWdodD0iNTEyIiB2aWV3Qm94PSIwIDAgNTEyIDUxMiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNNDQ0Ljc4OCAyOTEuMWw0Mi42MTYgMjQuNTk5YzQuODY3IDIuODA5IDcuMTI2IDguNjE4IDUuNDU5IDEzLjk4NS0xMS4wNyAzNS42NDItMjkuOTcgNjcuODQyLTU0LjY4OSA5NC41ODZhMTIuMDE2IDEyLjAxNiAwIDAgMS0xNC44MzIgMi4yNTRsLTQyLjU4NC0yNC41OTVhMTkxLjU3NyAxOTEuNTc3IDAgMCAxLTYwLjc1OSAzNS4xM3Y0OS4xODJhMTIuMDEgMTIuMDEgMCAwIDEtOS4zNzcgMTEuNzE4Yy0zNC45NTYgNy44NS03Mi40OTkgOC4yNTYtMTA5LjIxOS4wMDctNS40OS0xLjIzMy05LjQwMy02LjA5Ni05LjQwMy0xMS43MjN2LTQ5LjE4NGExOTEuNTU1IDE5MS41NTUgMCAwIDEtNjAuNzU5LTM1LjEzbC00Mi41ODQgMjQuNTk1YTEyLjAxNiAxMi4wMTYgMCAwIDEtMTQuODMyLTIuMjU0Yy0yNC43MTgtMjYuNzQ0LTQzLjYxOS01OC45NDQtNTQuNjg5LTk0LjU4Ni0xLjY2Ny01LjM2Ni41OTItMTEuMTc1IDUuNDU5LTEzLjk4NUw2Ny4yMTIgMjkxLjFhMTkzLjQ4IDE5My40OCAwIDAgMSAwLTcwLjE5OWwtNDIuNjE2LTI0LjU5OWMtNC44NjctMi44MDktNy4xMjYtOC42MTgtNS40NTktMTMuOTg1IDExLjA3LTM1LjY0MiAyOS45Ny02Ny44NDIgNTQuNjg5LTk0LjU4NmExMi4wMTYgMTIuMDE2IDAgMCAxIDE0LjgzMi0yLjI1NGw0Mi41ODQgMjQuNTk1YTE5MS41NzcgMTkxLjU3NyAwIDAgMSA2MC43NTktMzUuMTNWMjUuNzU5YTEyLjAxIDEyLjAxIDAgMCAxIDkuMzc3LTExLjcxOGMzNC45NTYtNy44NSA3Mi40OTktOC4yNTYgMTA5LjIxOS0uMDA3IDUuNDkgMS4yMzMgOS40MDMgNi4wOTYgOS40MDMgMTEuNzIzdjQ5LjE4NGExOTEuNTU1IDE5MS41NTUgMCAwIDEgNjAuNzU5IDM1LjEzbDQyLjU4NC0yNC41OTVhMTIuMDE2IDEyLjAxNiAwIDAgMSAxNC44MzIgMi4yNTRjMjQuNzE4IDI2Ljc0NCA0My42MTkgNTguOTQ0IDU0LjY4OSA5NC41ODYgMS42NjcgNS4zNjYtLjU5MiAxMS4xNzUtNS40NTkgMTMuOTg1TDQ0NC43ODggMjIwLjlhMTkzLjQ4NSAxOTMuNDg1IDAgMCAxIDAgNzAuMnpNMzM2IDI1NmMwLTQ0LjExMi0zNS44ODgtODAtODAtODBzLTgwIDM1Ljg4OC04MCA4MCAzNS44ODggODAgODAgODAgODAtMzUuODg4IDgwLTgweiIvPjwvc3ZnPg==); + background-repeat: no-repeat; + background-size: contain; + padding-left: 16px; + height: 0.8em; + display: inline-block; +} +.icon-fork { + background-image: url(icon_fork.svg), url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB3aWR0aD0iMTc5MiIgaGVpZ2h0PSIxNzkyIiB2aWV3Qm94PSIwIDAgMTc5MiAxNzkyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxyZWN0IHdpZHRoPSIxNzkyIiBoZWlnaHQ9IjE3OTIiIHN0eWxlPSJmaWxsOiNmZmYiIC8+PHBhdGggZD0iTTY3MiAxNDcycTAtNDAtMjgtNjh0LTY4LTI4LTY4IDI4LTI4IDY4IDI4IDY4IDY4IDI4IDY4LTI4IDI4LTY4em0wLTExNTJxMC00MC0yOC02OHQtNjgtMjgtNjggMjgtMjggNjggMjggNjggNjggMjggNjgtMjggMjgtNjh6bTY0MCAxMjhxMC00MC0yOC02OHQtNjgtMjgtNjggMjgtMjggNjggMjggNjggNjggMjggNjgtMjggMjgtNjh6bTk2IDBxMCA1Mi0yNiA5Ni41dC03MCA2OS41cS0yIDI4Ny0yMjYgNDE0LTY3IDM4LTIwMyA4MS0xMjggNDAtMTY5LjUgNzF0LTQxLjUgMTAwdjI2cTQ0IDI1IDcwIDY5LjV0MjYgOTYuNXEwIDgwLTU2IDEzNnQtMTM2IDU2LTEzNi01Ni01Ni0xMzZxMC01MiAyNi05Ni41dDcwLTY5LjV2LTgyMHEtNDQtMjUtNzAtNjkuNXQtMjYtOTYuNXEwLTgwIDU2LTEzNnQxMzYtNTYgMTM2IDU2IDU2IDEzNnEwIDUyLTI2IDk2LjV0LTcwIDY5LjV2NDk3cTU0LTI2IDE1NC01NyA1NS0xNyA4Ny41LTI5LjV0NzAuNS0zMSA1OS0zOS41IDQwLjUtNTEgMjgtNjkuNSA4LjUtOTEuNXEtNDQtMjUtNzAtNjkuNXQtMjYtOTYuNXEwLTgwIDU2LTEzNnQxMzYtNTYgMTM2IDU2IDU2IDEzNnoiLz48L3N2Zz4=); + background-repeat: no-repeat; + background-size: contain; + padding-left: 20px; + height: 0.9em; + display: inline-block; +} +.icon-cube { + background-image: url(icon_cube.svg), url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB3aWR0aD0iMTc5MiIgaGVpZ2h0PSIxNzkyIiB2aWV3Qm94PSIwIDAgMTc5MiAxNzkyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Ik04OTYgMTYyOWw2NDAtMzQ5di02MzZsLTY0MCAyMzN2NzUyem0tNjQtODY1bDY5OC0yNTQtNjk4LTI1NC02OTggMjU0em04MzItMjUydjc2OHEwIDM1LTE4IDY1dC00OSA0N2wtNzA0IDM4NHEtMjggMTYtNjEgMTZ0LTYxLTE2bC03MDQtMzg0cS0zMS0xNy00OS00N3QtMTgtNjV2LTc2OHEwLTQwIDIzLTczdDYxLTQ3bDcwNC0yNTZxMjItOCA0NC04dDQ0IDhsNzA0IDI1NnEzOCAxNCA2MSA0N3QyMyA3M3oiLz48L3N2Zz4=); + background-repeat: no-repeat; + background-size: contain; + padding-left: 20px; + height: 0.9em; + display: inline-block; +} +.icon-search-plus { + background-image: url(icon_search-plus.svg), url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB3aWR0aD0iMTc5MiIgaGVpZ2h0PSIxNzkyIiB2aWV3Qm94PSIwIDAgMTc5MiAxNzkyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGZpbGw9IiM2ZjZmNmYiIGQ9Ik0xMDg4IDgwMHY2NHEwIDEzLTkuNSAyMi41dC0yMi41IDkuNWgtMjI0djIyNHEwIDEzLTkuNSAyMi41dC0yMi41IDkuNWgtNjRxLTEzIDAtMjIuNS05LjV0LTkuNS0yMi41di0yMjRoLTIyNHEtMTMgMC0yMi41LTkuNXQtOS41LTIyLjV2LTY0cTAtMTMgOS41LTIyLjV0MjIuNS05LjVoMjI0di0yMjRxMC0xMyA5LjUtMjIuNXQyMi41LTkuNWg2NHExMyAwIDIyLjUgOS41dDkuNSAyMi41djIyNGgyMjRxMTMgMCAyMi41IDkuNXQ5LjUgMjIuNXptMTI4IDMycTAtMTg1LTEzMS41LTMxNi41dC0zMTYuNS0xMzEuNS0zMTYuNSAxMzEuNS0xMzEuNSAzMTYuNSAxMzEuNSAzMTYuNSAzMTYuNSAxMzEuNSAzMTYuNS0xMzEuNSAxMzEuNS0zMTYuNXptNTEyIDgzMnEwIDUzLTM3LjUgOTAuNXQtOTAuNSAzNy41cS01NCAwLTkwLTM4bC0zNDMtMzQycS0xNzkgMTI0LTM5OSAxMjQtMTQzIDAtMjczLjUtNTUuNXQtMjI1LTE1MC0xNTAtMjI1LTU1LjUtMjczLjUgNTUuNS0yNzMuNSAxNTAtMjI1IDIyNS0xNTAgMjczLjUtNTUuNSAyNzMuNSA1NS41IDIyNSAxNTAgMTUwIDIyNSA1NS41IDI3My41cTAgMjIwLTEyNCAzOTlsMzQzIDM0M3EzNyAzNyAzNyA5MHoiLz48L3N2Zz4=); + background-repeat: no-repeat; + background-size: contain; + padding-left: 20px; + height: 0.9em; + display: inline-block; +} +.icon-search-minus { + background-image: url(icon_search-minus.svg), url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB3aWR0aD0iMTc5MiIgaGVpZ2h0PSIxNzkyIiB2aWV3Qm94PSIwIDAgMTc5MiAxNzkyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGZpbGw9IiM2ZjZmNmYiIGQ9Ik0xMDg4IDgwMHY2NHEwIDEzLTkuNSAyMi41dC0yMi41IDkuNWgtNTc2cS0xMyAwLTIyLjUtOS41dC05LjUtMjIuNXYtNjRxMC0xMyA5LjUtMjIuNXQyMi41LTkuNWg1NzZxMTMgMCAyMi41IDkuNXQ5LjUgMjIuNXptMTI4IDMycTAtMTg1LTEzMS41LTMxNi41dC0zMTYuNS0xMzEuNS0zMTYuNSAxMzEuNS0xMzEuNSAzMTYuNSAxMzEuNSAzMTYuNSAzMTYuNSAxMzEuNSAzMTYuNS0xMzEuNSAxMzEuNS0zMTYuNXptNTEyIDgzMnEwIDUzLTM3LjUgOTAuNXQtOTAuNSAzNy41cS01NCAwLTkwLTM4bC0zNDMtMzQycS0xNzkgMTI0LTM5OSAxMjQtMTQzIDAtMjczLjUtNTUuNXQtMjI1LTE1MC0xNTAtMjI1LTU1LjUtMjczLjUgNTUuNS0yNzMuNSAxNTAtMjI1IDIyNS0xNTAgMjczLjUtNTUuNSAyNzMuNSA1NS41IDIyNSAxNTAgMTUwIDIyNSA1NS41IDI3My41cTAgMjIwLTEyNCAzOTlsMzQzIDM0M3EzNyAzNyAzNyA5MHoiLz48L3N2Zz4=); + background-repeat: no-repeat; + background-size: contain; + padding-left: 20px; + height: 0.9em; + display: inline-block; +} +.icon-star { + background-image: url(icon_star.svg), url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB3aWR0aD0iMTc5MiIgaGVpZ2h0PSIxNzkyIiB2aWV3Qm94PSIwIDAgMTc5MiAxNzkyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Ik0xNzI4IDY0N3EwIDIyLTI2IDQ4bC0zNjMgMzU0IDg2IDUwMHExIDcgMSAyMCAwIDIxLTEwLjUgMzUuNXQtMzAuNSAxNC41cS0xOSAwLTQwLTEybC00NDktMjM2LTQ0OSAyMzZxLTIyIDEyLTQwIDEyLTIxIDAtMzEuNS0xNC41dC0xMC41LTM1LjVxMC02IDItMjBsODYtNTAwLTM2NC0zNTRxLTI1LTI3LTI1LTQ4IDAtMzcgNTYtNDZsNTAyLTczIDIyNS00NTVxMTktNDEgNDktNDF0NDkgNDFsMjI1IDQ1NSA1MDIgNzNxNTYgOSA1NiA0NnoiIGZpbGw9IiMwMDAiLz48L3N2Zz4=); + background-repeat: no-repeat; + background-size: contain; + padding-left: 20px; + height: 0.9em; + display: inline-block; +} +.icon-sponsor { + background-image: url(icon_sponsor.svg), url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB3aWR0aD0iMTc5MiIgaGVpZ2h0PSIxNzkyIiB2aWV3Qm94PSIwIDAgMTc5MiAxNzkyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Ik04OTYgMTY2NHEtMjYgMC00NC0xOGwtNjI0LTYwMnEtMTAtOC0yNy41LTI2dC01NS41LTY1LjUtNjgtOTcuNS01My41LTEyMS0yMy41LTEzOHEwLTIyMCAxMjctMzQ0dDM1MS0xMjRxNjIgMCAxMjYuNSAyMS41dDEyMCA1OCA5NS41IDY4LjUgNzYgNjhxMzYtMzYgNzYtNjh0OTUuNS02OC41IDEyMC01OCAxMjYuNS0yMS41cTIyNCAwIDM1MSAxMjR0MTI3IDM0NHEwIDIyMS0yMjkgNDUwbC02MjMgNjAwcS0xOCAxOC00NCAxOHoiIGZpbGw9IiNlYTRhYWEiLz48L3N2Zz4=); + background-repeat: no-repeat; + background-size: contain; + padding-left: 20px; + height: 0.9em; + display: inline-block; +} + +.ngx-slider .ngx-slider-bar { + background: #a9a9a9 !important; +} + +.ngx-slider .ngx-slider-selection { + background: #818181 !important; +} + +.ngx-slider .ngx-slider-bubble { + padding: 3px 4px !important; + font-size: 12px !important; +} + +.ngx-slider .ngx-slider-pointer { + width: 20px !important; + height: 20px !important; + top: -8px !important; + background-color: #0075FF !important; + -webkit-border-radius: 10px !important; + -moz-border-radius: 10px !important; + border-radius: 10px !important; +} + + .ngx-slider .ngx-slider-pointer:after { + content: none !important; + } + +.ngx-slider .ngx-slider-tick.ngx-slider-selected { + background-color: #62a5f4 !important; + width: 8px !important; + height: 8px !important; + top: 1px !important; +} + + + +@media (prefers-color-scheme: dark) { + @media screen { + html { + background-color: #333; + color: #fff; + } + + body { + color: #fff; + } + + h1 { + background-color: #555453; + color: #fff; + } + + .container { + background-color: #333; + box-shadow: 0 0 60px #0c0c0c; + } + + .containerrightfixed { + background-color: #3D3C3C; + border-left: 1px solid #515050; + } + + .containerrightfixed h1 { + background-color: #484747; + } + + .popup-container { + background-color: rgb(80, 80, 80, 0.6); + } + + .popup { + background-color: #333; + } + + .card-group .card { + background-color: #333; + background: radial-gradient(circle, #444 0%, #333 100%); + border: 1px solid #545454; + color: #fff; + } + + .card-group .card table tr { + border-bottom: 1px solid #545454; + } + + .card-group .card table tr:hover { + background-color: #2E2D2C; + } + + .table-responsive::-webkit-scrollbar-thumb { + background-color: #555453; + border: 5px solid #333; + } + + .overview tr:hover > td { + background-color: #2E2D2C; + } + + .overview th { + background-color: #444; + border: 1px solid #3B3A39; + } + + .overview tr.namespace th { + background-color: #444; + } + + .overview thead th { + background-color: #444; + } + + .overview th a { + color: #fff; + color: rgba(255, 255, 255, 0.95); + } + + .overview th a:hover { + color: #0078d4; + } + + .overview td { + border: 1px solid #3B3A39; + } + + .overview .coverage td { + border: none; + } + + .overview tr.header th { + background-color: #444; + } + + .overview tr.header th:nth-child(2n+1) { + background-color: #3a3a3a; + } + + .overview tr.header th:first-child { + border-left: 1px solid #333; + border-top: 1px solid #333; + background-color: #333; + } + + .stripped tr:nth-child(2n+1) { + background-color: #3c3c3c; + } + + input, select, button { + background-color: #333; + color: #fff; + border: 1px solid #A19F9D; + } + + a { + color: #fff; + color: rgba(255, 255, 255, 0.95); + } + + a:hover { + color: #0078d4; + } + + h1 a.back { + background-color: #4a4846; + } + + h1 a.button { + color: #fff; + background-color: #565656; + border-color: #c1c1c1; + } + + h1 a.button:hover { + background-color: #8d8d8d; + } + + .gray { + background-color: #484747; + } + + .lightgray { + color: #ebebeb; + } + + .lightgraybg { + background-color: #474747; + } + + .lightgreen { + background-color: #406540; + } + + .lightorange { + background-color: #ab7f36; + } + + .lightred { + background-color: #954848; + } + + .ct-label { + color: #fff !important; + fill: #fff !important; + } + + .ct-grid { + stroke: #fff !important; + } + + .ct-chart .ct-series.ct-series-a .ct-line, .ct-chart .ct-series.ct-series-a .ct-point { + stroke: #0078D4 !important; + } + + .ct-chart .ct-series.ct-series-b .ct-line, .ct-chart .ct-series.ct-series-b .ct-point { + stroke: #6dc428 !important; + } + + .ct-chart .ct-series.ct-series-c .ct-line, .ct-chart .ct-series.ct-series-c .ct-point { + stroke: #e58f1d !important; + } + + .ct-chart .ct-series.ct-series-d .ct-line, .ct-chart .ct-series.ct-series-d .ct-point { + stroke: #c71bca !important; + } + + .linecoverage { + background-color: #0078D4; + } + + .branchcoverage { + background-color: #6dc428; + } + .codeelementcoverage { + background-color: #e58f1d; + } + + .fullcodeelementcoverage { + background-color: #c71bca; + } + + .tinylinecoveragechart, .tinybranchcoveragechart, .tinymethodcoveragechart, .tinyfullmethodcoveragechart { + background-color: #333; + } + + .tinybranchcoveragechart .ct-series.ct-series-a .ct-line { + stroke: #6dc428 !important; + } + + .tinymethodcoveragechart .ct-series.ct-series-a .ct-line { + stroke: #e58f1d !important; + } + + .tinyfullmethodcoveragechart .ct-series.ct-series-a .ct-line { + stroke: #c71bca !important; + } + + .icon-up-down-dir { + background-image: url(icon_up-down-dir_dark.svg), url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB3aWR0aD0iMTc5MiIgaGVpZ2h0PSIxNzkyIiB2aWV3Qm94PSIwIDAgMTc5MiAxNzkyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGZpbGw9IiNCRkJGQzAiIGQ9Im0gMTQwOCw3NDIgcSAwLDI2IC0xOSw0NSAtMTksMTkgLTQ1LDE5IEggNDQ4IHEgLTI2LDAgLTQ1LC0xOSAtMTksLTE5IC0xOSwtNDUgMCwtMjYgMTksLTQ1IEwgODUxLDI0OSBxIDE5LC0xOSA0NSwtMTkgMjYsMCA0NSwxOSBsIDQ0OCw0NDggcSAxOSwxOSAxOSw0NSB6IiAvPjxwYXRoIGZpbGw9IiNCRkJGQzAiIGQ9Im0gMTQwOCwxMDUwIHEgMCwyNiAtMTksNDUgbCAtNDQ4LDQ0OCBxIC0xOSwxOSAtNDUsMTkgLTI2LDAgLTQ1LC0xOSBMIDQwMywxMDk1IHEgLTE5LC0xOSAtMTksLTQ1IDAsLTI2IDE5LC00NSAxOSwtMTkgNDUsLTE5IGggODk2IHEgMjYsMCA0NSwxOSAxOSwxOSAxOSw0NSB6IiAvPjwvc3ZnPg==); + } + .icon-info-circled { + background-image: url(icon_info-circled_dark.svg), url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB3aWR0aD0iMTc5MiIgaGVpZ2h0PSIxNzkyIiB2aWV3Qm94PSIwIDAgMTc5MiAxNzkyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxjaXJjbGUgY3g9Ijg5NiIgY3k9Ijg5NiIgcj0iNzUwIiBmaWxsPSIjZmZmIiAvPjxwYXRoIGZpbGw9IiMyOEE1RkYiIGQ9Ik0xMTUyIDEzNzZ2LTE2MHEwLTE0LTktMjN0LTIzLTloLTk2di01MTJxMC0xNC05LTIzdC0yMy05aC0zMjBxLTE0IDAtMjMgOXQtOSAyM3YxNjBxMCAxNCA5IDIzdDIzIDloOTZ2MzIwaC05NnEtMTQgMC0yMyA5dC05IDIzdjE2MHEwIDE0IDkgMjN0MjMgOWg0NDhxMTQgMCAyMy05dDktMjN6bS0xMjgtODk2di0xNjBxMC0xNC05LTIzdC0yMy05aC0xOTJxLTE0IDAtMjMgOXQtOSAyM3YxNjBxMCAxNCA5IDIzdDIzIDloMTkycTE0IDAgMjMtOXQ5LTIzem02NDAgNDE2cTAgMjA5LTEwMyAzODUuNXQtMjc5LjUgMjc5LjUtMzg1LjUgMTAzLTM4NS41LTEwMy0yNzkuNS0yNzkuNS0xMDMtMzg1LjUgMTAzLTM4NS41IDI3OS41LTI3OS41IDM4NS41LTEwMyAzODUuNSAxMDMgMjc5LjUgMjc5LjUgMTAzIDM4NS41eiIvPjwvc3ZnPg==); + } + + .icon-plus { + background-image: url(icon_plus_dark.svg), url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHdpZHRoPSIxNzkyIiBoZWlnaHQ9IjE3OTIiIHZpZXdCb3g9IjAgMCAxNzkyIDE3OTIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZmlsbD0iI0JGQkZDMCIgZD0iTTE2MDAgNzM2djE5MnEwIDQwLTI4IDY4dC02OCAyOGgtNDE2djQxNnEwIDQwLTI4IDY4dC02OCAyOGgtMTkycS00MCAwLTY4LTI4dC0yOC02OHYtNDE2aC00MTZxLTQwIDAtNjgtMjh0LTI4LTY4di0xOTJxMC00MCAyOC02OHQ2OC0yOGg0MTZ2LTQxNnEwLTQwIDI4LTY4dDY4LTI4aDE5MnE0MCAwIDY4IDI4dDI4IDY4djQxNmg0MTZxNDAgMCA2OCAyOHQyOCA2OHoiLz48L3N2Zz4=); + } + + .icon-minus { + background-image: url(icon_minus_dark.svg), url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHdpZHRoPSIxNzkyIiBoZWlnaHQ9IjE3OTIiIHZpZXdCb3g9IjAgMCAxNzkyIDE3OTIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZmlsbD0iI0JGQkZDMCIgZD0iTTE2MDAgNzM2djE5MnEwIDQwLTI4IDY4dC02OCAyOGgtMTIxNnEtNDAgMC02OC0yOHQtMjgtNjh2LTE5MnEwLTQwIDI4LTY4dDY4LTI4aDEyMTZxNDAgMCA2OCAyOHQyOCA2OHoiLz48L3N2Zz4=); + } + + .icon-wrench { + background-image: url(icon_wrench_dark.svg), url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHdpZHRoPSIxNzkyIiBoZWlnaHQ9IjE3OTIiIHZpZXdCb3g9IjAgMCAxNzkyIDE3OTIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZmlsbD0iI0JEQkRCRiIgZD0iTTQ0OCAxNDcycTAtMjYtMTktNDV0LTQ1LTE5LTQ1IDE5LTE5IDQ1IDE5IDQ1IDQ1IDE5IDQ1LTE5IDE5LTQ1em02NDQtNDIwbC02ODIgNjgycS0zNyAzNy05MCAzNy01MiAwLTkxLTM3bC0xMDYtMTA4cS0zOC0zNi0zOC05MCAwLTUzIDM4LTkxbDY4MS02ODFxMzkgOTggMTE0LjUgMTczLjV0MTczLjUgMTE0LjV6bTYzNC00MzVxMCAzOS0yMyAxMDYtNDcgMTM0LTE2NC41IDIxNy41dC0yNTguNSA4My41cS0xODUgMC0zMTYuNS0xMzEuNXQtMTMxLjUtMzE2LjUgMTMxLjUtMzE2LjUgMzE2LjUtMTMxLjVxNTggMCAxMjEuNSAxNi41dDEwNy41IDQ2LjVxMTYgMTEgMTYgMjh0LTE2IDI4bC0yOTMgMTY5djIyNGwxOTMgMTA3cTUtMyA3OS00OC41dDEzNS41LTgxIDcwLjUtMzUuNXExNSAwIDIzLjUgMTB0OC41IDI1eiIvPjwvc3ZnPg==); + } + + .icon-cog { + background-image: url(icon_cog_dark.svg), url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHdpZHRoPSI1MTIiIGhlaWdodD0iNTEyIiB2aWV3Qm94PSIwIDAgNTEyIDUxMiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBmaWxsPSIjQkRCREJGIiBkPSJNNDQ0Ljc4OCAyOTEuMWw0Mi42MTYgMjQuNTk5YzQuODY3IDIuODA5IDcuMTI2IDguNjE4IDUuNDU5IDEzLjk4NS0xMS4wNyAzNS42NDItMjkuOTcgNjcuODQyLTU0LjY4OSA5NC41ODZhMTIuMDE2IDEyLjAxNiAwIDAgMS0xNC44MzIgMi4yNTRsLTQyLjU4NC0yNC41OTVhMTkxLjU3NyAxOTEuNTc3IDAgMCAxLTYwLjc1OSAzNS4xM3Y0OS4xODJhMTIuMDEgMTIuMDEgMCAwIDEtOS4zNzcgMTEuNzE4Yy0zNC45NTYgNy44NS03Mi40OTkgOC4yNTYtMTA5LjIxOS4wMDctNS40OS0xLjIzMy05LjQwMy02LjA5Ni05LjQwMy0xMS43MjN2LTQ5LjE4NGExOTEuNTU1IDE5MS41NTUgMCAwIDEtNjAuNzU5LTM1LjEzbC00Mi41ODQgMjQuNTk1YTEyLjAxNiAxMi4wMTYgMCAwIDEtMTQuODMyLTIuMjU0Yy0yNC43MTgtMjYuNzQ0LTQzLjYxOS01OC45NDQtNTQuNjg5LTk0LjU4Ni0xLjY2Ny01LjM2Ni41OTItMTEuMTc1IDUuNDU5LTEzLjk4NUw2Ny4yMTIgMjkxLjFhMTkzLjQ4IDE5My40OCAwIDAgMSAwLTcwLjE5OWwtNDIuNjE2LTI0LjU5OWMtNC44NjctMi44MDktNy4xMjYtOC42MTgtNS40NTktMTMuOTg1IDExLjA3LTM1LjY0MiAyOS45Ny02Ny44NDIgNTQuNjg5LTk0LjU4NmExMi4wMTYgMTIuMDE2IDAgMCAxIDE0LjgzMi0yLjI1NGw0Mi41ODQgMjQuNTk1YTE5MS41NzcgMTkxLjU3NyAwIDAgMSA2MC43NTktMzUuMTNWMjUuNzU5YTEyLjAxIDEyLjAxIDAgMCAxIDkuMzc3LTExLjcxOGMzNC45NTYtNy44NSA3Mi40OTktOC4yNTYgMTA5LjIxOS0uMDA3IDUuNDkgMS4yMzMgOS40MDMgNi4wOTYgOS40MDMgMTEuNzIzdjQ5LjE4NGExOTEuNTU1IDE5MS41NTUgMCAwIDEgNjAuNzU5IDM1LjEzbDQyLjU4NC0yNC41OTVhMTIuMDE2IDEyLjAxNiAwIDAgMSAxNC44MzIgMi4yNTRjMjQuNzE4IDI2Ljc0NCA0My42MTkgNTguOTQ0IDU0LjY4OSA5NC41ODYgMS42NjcgNS4zNjYtLjU5MiAxMS4xNzUtNS40NTkgMTMuOTg1TDQ0NC43ODggMjIwLjlhMTkzLjQ4NSAxOTMuNDg1IDAgMCAxIDAgNzAuMnpNMzM2IDI1NmMwLTQ0LjExMi0zNS44ODgtODAtODAtODBzLTgwIDM1Ljg4OC04MCA4MCAzNS44ODggODAgODAgODAgODAtMzUuODg4IDgwLTgweiIvPjwvc3ZnPg==); + } + + .icon-fork { + background-image: url(icon_fork_dark.svg), url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHdpZHRoPSIxNzkyIiBoZWlnaHQ9IjE3OTIiIHZpZXdCb3g9IjAgMCAxNzkyIDE3OTIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZmlsbD0iI0JGQkZDMCIgZD0iTTY3MiAxNDcycTAtNDAtMjgtNjh0LTY4LTI4LTY4IDI4LTI4IDY4IDI4IDY4IDY4IDI4IDY4LTI4IDI4LTY4em0wLTExNTJxMC00MC0yOC02OHQtNjgtMjgtNjggMjgtMjggNjggMjggNjggNjggMjggNjgtMjggMjgtNjh6bTY0MCAxMjhxMC00MC0yOC02OHQtNjgtMjgtNjggMjgtMjggNjggMjggNjggNjggMjggNjgtMjggMjgtNjh6bTk2IDBxMCA1Mi0yNiA5Ni41dC03MCA2OS41cS0yIDI4Ny0yMjYgNDE0LTY3IDM4LTIwMyA4MS0xMjggNDAtMTY5LjUgNzF0LTQxLjUgMTAwdjI2cTQ0IDI1IDcwIDY5LjV0MjYgOTYuNXEwIDgwLTU2IDEzNnQtMTM2IDU2LTEzNi01Ni01Ni0xMzZxMC01MiAyNi05Ni41dDcwLTY5LjV2LTgyMHEtNDQtMjUtNzAtNjkuNXQtMjYtOTYuNXEwLTgwIDU2LTEzNnQxMzYtNTYgMTM2IDU2IDU2IDEzNnEwIDUyLTI2IDk2LjV0LTcwIDY5LjV2NDk3cTU0LTI2IDE1NC01NyA1NS0xNyA4Ny41LTI5LjV0NzAuNS0zMSA1OS0zOS41IDQwLjUtNTEgMjgtNjkuNSA4LjUtOTEuNXEtNDQtMjUtNzAtNjkuNXQtMjYtOTYuNXEwLTgwIDU2LTEzNnQxMzYtNTYgMTM2IDU2IDU2IDEzNnoiLz48L3N2Zz4=); + } + + .icon-cube { + background-image: url(icon_cube_dark.svg), url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHdpZHRoPSIxNzkyIiBoZWlnaHQ9IjE3OTIiIHZpZXdCb3g9IjAgMCAxNzkyIDE3OTIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZmlsbD0iI0JGQkZDMCIgZD0iTTg5NiAxNjI5bDY0MC0zNDl2LTYzNmwtNjQwIDIzM3Y3NTJ6bS02NC04NjVsNjk4LTI1NC02OTgtMjU0LTY5OCAyNTR6bTgzMi0yNTJ2NzY4cTAgMzUtMTggNjV0LTQ5IDQ3bC03MDQgMzg0cS0yOCAxNi02MSAxNnQtNjEtMTZsLTcwNC0zODRxLTMxLTE3LTQ5LTQ3dC0xOC02NXYtNzY4cTAtNDAgMjMtNzN0NjEtNDdsNzA0LTI1NnEyMi04IDQ0LTh0NDQgOGw3MDQgMjU2cTM4IDE0IDYxIDQ3dDIzIDczeiIvPjwvc3ZnPg==); + } + + .icon-search-plus { + background-image: url(icon_search-plus_dark.svg), url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHdpZHRoPSIxNzkyIiBoZWlnaHQ9IjE3OTIiIHZpZXdCb3g9IjAgMCAxNzkyIDE3OTIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZmlsbD0iI0JGQkZDMCIgZD0iTTEwODggODAwdjY0cTAgMTMtOS41IDIyLjV0LTIyLjUgOS41aC0yMjR2MjI0cTAgMTMtOS41IDIyLjV0LTIyLjUgOS41aC02NHEtMTMgMC0yMi41LTkuNXQtOS41LTIyLjV2LTIyNGgtMjI0cS0xMyAwLTIyLjUtOS41dC05LjUtMjIuNXYtNjRxMC0xMyA5LjUtMjIuNXQyMi41LTkuNWgyMjR2LTIyNHEwLTEzIDkuNS0yMi41dDIyLjUtOS41aDY0cTEzIDAgMjIuNSA5LjV0OS41IDIyLjV2MjI0aDIyNHExMyAwIDIyLjUgOS41dDkuNSAyMi41em0xMjggMzJxMC0xODUtMTMxLjUtMzE2LjV0LTMxNi41LTEzMS41LTMxNi41IDEzMS41LTEzMS41IDMxNi41IDEzMS41IDMxNi41IDMxNi41IDEzMS41IDMxNi41LTEzMS41IDEzMS41LTMxNi41em01MTIgODMycTAgNTMtMzcuNSA5MC41dC05MC41IDM3LjVxLTU0IDAtOTAtMzhsLTM0My0zNDJxLTE3OSAxMjQtMzk5IDEyNC0xNDMgMC0yNzMuNS01NS41dC0yMjUtMTUwLTE1MC0yMjUtNTUuNS0yNzMuNSA1NS41LTI3My41IDE1MC0yMjUgMjI1LTE1MCAyNzMuNS01NS41IDI3My41IDU1LjUgMjI1IDE1MCAxNTAgMjI1IDU1LjUgMjczLjVxMCAyMjAtMTI0IDM5OWwzNDMgMzQzcTM3IDM3IDM3IDkweiIvPjwvc3ZnPg==); + } + + .icon-search-minus { + background-image: url(icon_search-minus_dark.svg), url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHdpZHRoPSIxNzkyIiBoZWlnaHQ9IjE3OTIiIHZpZXdCb3g9IjAgMCAxNzkyIDE3OTIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZmlsbD0iI0JGQkZDMCIgZD0iTTEwODggODAwdjY0cTAgMTMtOS41IDIyLjV0LTIyLjUgOS41aC01NzZxLTEzIDAtMjIuNS05LjV0LTkuNS0yMi41di02NHEwLTEzIDkuNS0yMi41dDIyLjUtOS41aDU3NnExMyAwIDIyLjUgOS41dDkuNSAyMi41em0xMjggMzJxMC0xODUtMTMxLjUtMzE2LjV0LTMxNi41LTEzMS41LTMxNi41IDEzMS41LTEzMS41IDMxNi41IDEzMS41IDMxNi41IDMxNi41IDEzMS41IDMxNi41LTEzMS41IDEzMS41LTMxNi41em01MTIgODMycTAgNTMtMzcuNSA5MC41dC05MC41IDM3LjVxLTU0IDAtOTAtMzhsLTM0My0zNDJxLTE3OSAxMjQtMzk5IDEyNC0xNDMgMC0yNzMuNS01NS41dC0yMjUtMTUwLTE1MC0yMjUtNTUuNS0yNzMuNSA1NS41LTI3My41IDE1MC0yMjUgMjI1LTE1MCAyNzMuNS01NS41IDI3My41IDU1LjUgMjI1IDE1MCAxNTAgMjI1IDU1LjUgMjczLjVxMCAyMjAtMTI0IDM5OWwzNDMgMzQzcTM3IDM3IDM3IDkweiIvPjwvc3ZnPg==); + } + + .icon-star { + background-image: url(icon_star_dark.svg), url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB3aWR0aD0iMTc5MiIgaGVpZ2h0PSIxNzkyIiB2aWV3Qm94PSIwIDAgMTc5MiAxNzkyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Ik0xNzI4IDY0N3EwIDIyLTI2IDQ4bC0zNjMgMzU0IDg2IDUwMHExIDcgMSAyMCAwIDIxLTEwLjUgMzUuNXQtMzAuNSAxNC41cS0xOSAwLTQwLTEybC00NDktMjM2LTQ0OSAyMzZxLTIyIDEyLTQwIDEyLTIxIDAtMzEuNS0xNC41dC0xMC41LTM1LjVxMC02IDItMjBsODYtNTAwLTM2NC0zNTRxLTI1LTI3LTI1LTQ4IDAtMzcgNTYtNDZsNTAyLTczIDIyNS00NTVxMTktNDEgNDktNDF0NDkgNDFsMjI1IDQ1NSA1MDIgNzNxNTYgOSA1NiA0NnoiIGZpbGw9IiNmZmYiLz48L3N2Zz4=); + } + } +} + +.ct-double-octave:after,.ct-golden-section:after,.ct-major-eleventh:after,.ct-major-second:after,.ct-major-seventh:after,.ct-major-sixth:after,.ct-major-tenth:after,.ct-major-third:after,.ct-major-twelfth:after,.ct-minor-second:after,.ct-minor-seventh:after,.ct-minor-sixth:after,.ct-minor-third:after,.ct-octave:after,.ct-perfect-fifth:after,.ct-perfect-fourth:after,.ct-square:after{content:"";clear:both}.ct-label{fill:rgba(0,0,0,.4);color:rgba(0,0,0,.4);font-size:.75rem;line-height:1}.ct-chart-bar .ct-label,.ct-chart-line .ct-label{display:block;display:-webkit-box;display:-moz-box;display:-ms-flexbox;display:-webkit-flex;display:flex}.ct-chart-donut .ct-label,.ct-chart-pie .ct-label{dominant-baseline:central}.ct-label.ct-horizontal.ct-start{-webkit-box-align:flex-end;-webkit-align-items:flex-end;-ms-flex-align:flex-end;align-items:flex-end;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:start}.ct-label.ct-horizontal.ct-end{-webkit-box-align:flex-start;-webkit-align-items:flex-start;-ms-flex-align:flex-start;align-items:flex-start;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:start}.ct-label.ct-vertical.ct-start{-webkit-box-align:flex-end;-webkit-align-items:flex-end;-ms-flex-align:flex-end;align-items:flex-end;-webkit-box-pack:flex-end;-webkit-justify-content:flex-end;-ms-flex-pack:flex-end;justify-content:flex-end;text-align:right;text-anchor:end}.ct-label.ct-vertical.ct-end{-webkit-box-align:flex-end;-webkit-align-items:flex-end;-ms-flex-align:flex-end;align-items:flex-end;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:start}.ct-chart-bar .ct-label.ct-horizontal.ct-start{-webkit-box-align:flex-end;-webkit-align-items:flex-end;-ms-flex-align:flex-end;align-items:flex-end;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;text-align:center;text-anchor:start}.ct-chart-bar .ct-label.ct-horizontal.ct-end{-webkit-box-align:flex-start;-webkit-align-items:flex-start;-ms-flex-align:flex-start;align-items:flex-start;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;text-align:center;text-anchor:start}.ct-chart-bar.ct-horizontal-bars .ct-label.ct-horizontal.ct-start{-webkit-box-align:flex-end;-webkit-align-items:flex-end;-ms-flex-align:flex-end;align-items:flex-end;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:start}.ct-chart-bar.ct-horizontal-bars .ct-label.ct-horizontal.ct-end{-webkit-box-align:flex-start;-webkit-align-items:flex-start;-ms-flex-align:flex-start;align-items:flex-start;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:start}.ct-chart-bar.ct-horizontal-bars .ct-label.ct-vertical.ct-start{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:flex-end;-webkit-justify-content:flex-end;-ms-flex-pack:flex-end;justify-content:flex-end;text-align:right;text-anchor:end}.ct-chart-bar.ct-horizontal-bars .ct-label.ct-vertical.ct-end{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:end}.ct-grid{stroke:rgba(0,0,0,.2);stroke-width:1px;stroke-dasharray:2px}.ct-grid-background{fill:none}.ct-point{stroke-width:10px;stroke-linecap:round}.ct-line{fill:none;stroke-width:4px}.ct-area{stroke:none;fill-opacity:.1}.ct-bar{fill:none;stroke-width:10px}.ct-slice-donut{fill:none;stroke-width:60px}.ct-series-a .ct-bar,.ct-series-a .ct-line,.ct-series-a .ct-point,.ct-series-a .ct-slice-donut{stroke:#d70206}.ct-series-a .ct-area,.ct-series-a .ct-slice-donut-solid,.ct-series-a .ct-slice-pie{fill:#d70206}.ct-series-b .ct-bar,.ct-series-b .ct-line,.ct-series-b .ct-point,.ct-series-b .ct-slice-donut{stroke:#f05b4f}.ct-series-b .ct-area,.ct-series-b .ct-slice-donut-solid,.ct-series-b .ct-slice-pie{fill:#f05b4f}.ct-series-c .ct-bar,.ct-series-c .ct-line,.ct-series-c .ct-point,.ct-series-c .ct-slice-donut{stroke:#f4c63d}.ct-series-c .ct-area,.ct-series-c .ct-slice-donut-solid,.ct-series-c .ct-slice-pie{fill:#f4c63d}.ct-series-d .ct-bar,.ct-series-d .ct-line,.ct-series-d .ct-point,.ct-series-d .ct-slice-donut{stroke:#d17905}.ct-series-d .ct-area,.ct-series-d .ct-slice-donut-solid,.ct-series-d .ct-slice-pie{fill:#d17905}.ct-series-e .ct-bar,.ct-series-e .ct-line,.ct-series-e .ct-point,.ct-series-e .ct-slice-donut{stroke:#453d3f}.ct-series-e .ct-area,.ct-series-e .ct-slice-donut-solid,.ct-series-e .ct-slice-pie{fill:#453d3f}.ct-series-f .ct-bar,.ct-series-f .ct-line,.ct-series-f .ct-point,.ct-series-f .ct-slice-donut{stroke:#59922b}.ct-series-f .ct-area,.ct-series-f .ct-slice-donut-solid,.ct-series-f .ct-slice-pie{fill:#59922b}.ct-series-g .ct-bar,.ct-series-g .ct-line,.ct-series-g .ct-point,.ct-series-g .ct-slice-donut{stroke:#0544d3}.ct-series-g .ct-area,.ct-series-g .ct-slice-donut-solid,.ct-series-g .ct-slice-pie{fill:#0544d3}.ct-series-h .ct-bar,.ct-series-h .ct-line,.ct-series-h .ct-point,.ct-series-h .ct-slice-donut{stroke:#6b0392}.ct-series-h .ct-area,.ct-series-h .ct-slice-donut-solid,.ct-series-h .ct-slice-pie{fill:#6b0392}.ct-series-i .ct-bar,.ct-series-i .ct-line,.ct-series-i .ct-point,.ct-series-i .ct-slice-donut{stroke:#f05b4f}.ct-series-i .ct-area,.ct-series-i .ct-slice-donut-solid,.ct-series-i .ct-slice-pie{fill:#f05b4f}.ct-series-j .ct-bar,.ct-series-j .ct-line,.ct-series-j .ct-point,.ct-series-j .ct-slice-donut{stroke:#dda458}.ct-series-j .ct-area,.ct-series-j .ct-slice-donut-solid,.ct-series-j .ct-slice-pie{fill:#dda458}.ct-series-k .ct-bar,.ct-series-k .ct-line,.ct-series-k .ct-point,.ct-series-k .ct-slice-donut{stroke:#eacf7d}.ct-series-k .ct-area,.ct-series-k .ct-slice-donut-solid,.ct-series-k .ct-slice-pie{fill:#eacf7d}.ct-series-l .ct-bar,.ct-series-l .ct-line,.ct-series-l .ct-point,.ct-series-l .ct-slice-donut{stroke:#86797d}.ct-series-l .ct-area,.ct-series-l .ct-slice-donut-solid,.ct-series-l .ct-slice-pie{fill:#86797d}.ct-series-m .ct-bar,.ct-series-m .ct-line,.ct-series-m .ct-point,.ct-series-m .ct-slice-donut{stroke:#b2c326}.ct-series-m .ct-area,.ct-series-m .ct-slice-donut-solid,.ct-series-m .ct-slice-pie{fill:#b2c326}.ct-series-n .ct-bar,.ct-series-n .ct-line,.ct-series-n .ct-point,.ct-series-n .ct-slice-donut{stroke:#6188e2}.ct-series-n .ct-area,.ct-series-n .ct-slice-donut-solid,.ct-series-n .ct-slice-pie{fill:#6188e2}.ct-series-o .ct-bar,.ct-series-o .ct-line,.ct-series-o .ct-point,.ct-series-o .ct-slice-donut{stroke:#a748ca}.ct-series-o .ct-area,.ct-series-o .ct-slice-donut-solid,.ct-series-o .ct-slice-pie{fill:#a748ca}.ct-square{display:block;position:relative;width:100%}.ct-square:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:100%}.ct-square:after{display:table}.ct-square>svg{display:block;position:absolute;top:0;left:0}.ct-minor-second{display:block;position:relative;width:100%}.ct-minor-second:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:93.75%}.ct-minor-second:after{display:table}.ct-minor-second>svg{display:block;position:absolute;top:0;left:0}.ct-major-second{display:block;position:relative;width:100%}.ct-major-second:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:88.8888888889%}.ct-major-second:after{display:table}.ct-major-second>svg{display:block;position:absolute;top:0;left:0}.ct-minor-third{display:block;position:relative;width:100%}.ct-minor-third:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:83.3333333333%}.ct-minor-third:after{display:table}.ct-minor-third>svg{display:block;position:absolute;top:0;left:0}.ct-major-third{display:block;position:relative;width:100%}.ct-major-third:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:80%}.ct-major-third:after{display:table}.ct-major-third>svg{display:block;position:absolute;top:0;left:0}.ct-perfect-fourth{display:block;position:relative;width:100%}.ct-perfect-fourth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:75%}.ct-perfect-fourth:after{display:table}.ct-perfect-fourth>svg{display:block;position:absolute;top:0;left:0}.ct-perfect-fifth{display:block;position:relative;width:100%}.ct-perfect-fifth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:66.6666666667%}.ct-perfect-fifth:after{display:table}.ct-perfect-fifth>svg{display:block;position:absolute;top:0;left:0}.ct-minor-sixth{display:block;position:relative;width:100%}.ct-minor-sixth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:62.5%}.ct-minor-sixth:after{display:table}.ct-minor-sixth>svg{display:block;position:absolute;top:0;left:0}.ct-golden-section{display:block;position:relative;width:100%}.ct-golden-section:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:61.804697157%}.ct-golden-section:after{display:table}.ct-golden-section>svg{display:block;position:absolute;top:0;left:0}.ct-major-sixth{display:block;position:relative;width:100%}.ct-major-sixth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:60%}.ct-major-sixth:after{display:table}.ct-major-sixth>svg{display:block;position:absolute;top:0;left:0}.ct-minor-seventh{display:block;position:relative;width:100%}.ct-minor-seventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:56.25%}.ct-minor-seventh:after{display:table}.ct-minor-seventh>svg{display:block;position:absolute;top:0;left:0}.ct-major-seventh{display:block;position:relative;width:100%}.ct-major-seventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:53.3333333333%}.ct-major-seventh:after{display:table}.ct-major-seventh>svg{display:block;position:absolute;top:0;left:0}.ct-octave{display:block;position:relative;width:100%}.ct-octave:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:50%}.ct-octave:after{display:table}.ct-octave>svg{display:block;position:absolute;top:0;left:0}.ct-major-tenth{display:block;position:relative;width:100%}.ct-major-tenth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:40%}.ct-major-tenth:after{display:table}.ct-major-tenth>svg{display:block;position:absolute;top:0;left:0}.ct-major-eleventh{display:block;position:relative;width:100%}.ct-major-eleventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:37.5%}.ct-major-eleventh:after{display:table}.ct-major-eleventh>svg{display:block;position:absolute;top:0;left:0}.ct-major-twelfth{display:block;position:relative;width:100%}.ct-major-twelfth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:33.3333333333%}.ct-major-twelfth:after{display:table}.ct-major-twelfth>svg{display:block;position:absolute;top:0;left:0}.ct-double-octave{display:block;position:relative;width:100%}.ct-double-octave:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:25%}.ct-double-octave:after{display:table}.ct-double-octave>svg{display:block;position:absolute;top:0;left:0} \ No newline at end of file diff --git a/source/global.json b/source/global.json new file mode 100644 index 0000000..30823ad --- /dev/null +++ b/source/global.json @@ -0,0 +1,5 @@ +{ + "sdk": { + "version": "8.0.203" + } +} \ No newline at end of file diff --git a/source/gpconnect-analytics.DAL/BatchService.cs b/source/gpconnect-analytics.DAL/BatchService.cs deleted file mode 100644 index d6787f5..0000000 --- a/source/gpconnect-analytics.DAL/BatchService.cs +++ /dev/null @@ -1,161 +0,0 @@ -using Dapper; -using gpconnect_analytics.DAL.Interfaces; -using gpconnect_analytics.DTO.Request; -using gpconnect_analytics.DTO.Response.Configuration; -using gpconnect_analytics.Helpers; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Logging; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using System.Web; - -namespace gpconnect_analytics.DAL -{ - public class BatchService : IBatchService - { - private readonly IConfigurationService _configurationService; - private readonly ILogger _logger; - private SplunkClient _splunkClient; - private readonly IDataService _dataService; - private readonly ISplunkService _splunkService; - private readonly IImportService _importService; - - public BatchService(IConfigurationService configurationService, IImportService importService, ISplunkService splunkService, ILogger logger, IDataService dataService) - { - _configurationService = configurationService; - _logger = logger; - _dataService = dataService; - _splunkService = splunkService; - _importService = importService; - } - - public async Task StartBatchDownloadForTodayAsync(FileTypes fileTypes) - { - var dateInScope = DateTime.Today.AddDays(1); - var fileType = await _configurationService.GetFileType(fileTypes); - var uriList = await GetBatchDownloadUriList(fileType, DateTimeHelper.EachDay(dateInScope, dateInScope).ToList()); - - await RemovePreviousDownloads(fileType, dateInScope, dateInScope); - return await ProcessUrls(fileType, uriList, true); - } - - public async Task StartBatchDownloadAsync(HttpRequest req, FileTypes fileTypes) - { - if (req != null) - { - var startDate = DateTime.TryParse(req.Query["StartDate"].ToString(), out DateTime start) ? start : DateTime.Today; - var endDate = DateTime.TryParse(req.Query["EndDate"].ToString(), out DateTime end) ? end : DateTime.Today; - - if (endDate >= startDate) - { - var fileType = await _configurationService.GetFileType(fileTypes); - var uriList = await GetBatchDownloadUriList(fileType, DateTimeHelper.EachDay(startDate, endDate).ToList()); - - await RemovePreviousDownloads(fileType, startDate, endDate); - - return await ProcessUrls(fileType, uriList, false); - } - } - return new BadRequestObjectResult("Bad request"); - } - - private async Task ProcessUrls(FileType fileType, List uriList, bool isToday) - { - for (var i = 0; i < uriList.Count; i++) - { - var downloadTasksQuery = - from requestUri in uriList.Skip(i).Take(1) - select ExecuteBatchDownloadFromSplunk(fileType, requestUri, isToday); - - var downloadTasks = downloadTasksQuery.ToList(); - - while (downloadTasks.Any()) - { - Task finishedTask = await Task.WhenAny(downloadTasks); - downloadTasks.Remove(finishedTask); - } - await Task.Delay(TimeSpan.FromSeconds(10)); - } - return new OkObjectResult($"Batch download complete: {uriList.Count} requests processed"); - } - - private async Task ExecuteBatchDownloadFromSplunk(FileType fileType, UriRequest uriRequest, bool isToday) - { - try - { - if (FileTypeEnabled(fileType)) - { - var extractResponse = await _splunkService.DownloadCSVDateRangeAsync(fileType, uriRequest, isToday); - await _importService.AddObjectFileMessage(fileType, extractResponse); - } - else - { - _logger?.LogWarning($"Filetype {fileType.FileTypeFilePrefix} is not enabled. Please check if this is correct"); - } - } - catch (Exception exc) - { - _logger?.LogError(exc, $"An error has occurred while attempting to execute an Azure function"); - throw; - } - } - - public async Task> GetBatchDownloadUriList(FileType fileType, List dateTimeList) - { - var uriList = new List(); - _splunkClient = await _configurationService.GetSplunkClientConfiguration(); - - foreach (var dateTime in dateTimeList) - { - var earliestDate = dateTime.AddDays(-2); - var latestDate = dateTime.AddDays(-1); - - for (var i = 0; i < 24; i++) - { - var splunkQuery = fileType.SplunkQuery; - var hour = TimeSpan.Zero.Add(TimeSpan.FromHours(i)); - - splunkQuery = splunkQuery.Replace("{earliest}", earliestDate.ToString(Helpers.DateFormatConstants.SplunkQueryDate)); - splunkQuery = splunkQuery.Replace("{latest}", latestDate.ToString(Helpers.DateFormatConstants.SplunkQueryDate)); - splunkQuery = splunkQuery.Replace("{hour}", hour.ToString(Helpers.DateFormatConstants.SplunkQueryHour)); - - var uriBuilder = new UriBuilder - { - Scheme = Uri.UriSchemeHttps, - Host = _splunkClient.HostName, - Port = _splunkClient.HostPort, - Path = _splunkClient.BaseUrl, - Query = string.Format(_splunkClient.QueryParameters, HttpUtility.UrlEncode(splunkQuery)) - }; - - uriList.Add(new UriRequest() - { - Request = uriBuilder.Uri, - EarliestDate = earliestDate, - LatestDate = latestDate, - Hour = hour - }); - } - } - return uriList; - } - - public async Task RemovePreviousDownloads(FileType fileType, DateTime startDate, DateTime endDate) - { - var procedureName = "Import.RemovePreviousDownload"; - var parameters = new DynamicParameters(); - parameters.Add("@FileTypeId", fileType.FileTypeId); - parameters.Add("@StartDate", startDate.AddDays(-2)); - parameters.Add("@EndDate", endDate.AddDays(-1)); - await _dataService.ExecuteStoredProcedure(procedureName, parameters); - } - - private bool FileTypeEnabled(FileType fileType) - { - return (fileType != null && fileType.Enabled); - } - } -} diff --git a/source/gpconnect-analytics.DAL/ConfigurationService.cs b/source/gpconnect-analytics.DAL/ConfigurationService.cs deleted file mode 100644 index b4cc928..0000000 --- a/source/gpconnect-analytics.DAL/ConfigurationService.cs +++ /dev/null @@ -1,63 +0,0 @@ -using gpconnect_analytics.DAL.Interfaces; -using gpconnect_analytics.DTO.Response.Configuration; -using gpconnect_analytics.Helpers; -using Microsoft.Extensions.Logging; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace gpconnect_analytics.DAL -{ - public class ConfigurationService : IConfigurationService - { - private readonly ILogger _logger; - private readonly IDataService _dataService; - - public ConfigurationService(IDataService dataService, ILogger logger) - { - _logger = logger; - _dataService = dataService; - } - - public async Task GetBlobStorageConfiguration() - { - var result = await _dataService.ExecuteStoredProcedure("[Configuration].[GetBlobStorageConfiguration]"); - _logger.LogInformation($"Loading blob storage configuration", result.FirstOrDefault()); - return result.FirstOrDefault(); - } - - public async Task GetFilePathConstants() - { - var result = await _dataService.ExecuteStoredProcedure("[Configuration].[GetFilePathConstants]"); - _logger.LogInformation($"Loading file path constants", result.FirstOrDefault()); - return result.FirstOrDefault(); - } - - public async Task> GetFileTypes() - { - var result = await _dataService.ExecuteStoredProcedure("[Configuration].[GetFileTypes]"); - _logger.LogInformation($"Loading file types", result); - return result; - } - - public async Task GetFileType(FileTypes fileTypes) - { - var result = await _dataService.ExecuteStoredProcedure("[Configuration].[GetFileTypes]"); - return result.FirstOrDefault(ft => ft.FileTypeFilePrefix == fileTypes.ToString()); - } - - public async Task GetSplunkClientConfiguration() - { - var result = await _dataService.ExecuteStoredProcedure("[Configuration].[GetSplunkClientConfiguration]"); - _logger.LogInformation($"Loading splunk client configuration", result.FirstOrDefault()); - return result.FirstOrDefault(); - } - - public async Task GetSplunkInstance(Helpers.SplunkInstances splunkInstance) - { - var result = await _dataService.ExecuteStoredProcedure("[Configuration].[GetSplunkInstances]"); - _logger.LogInformation($"Loading splunk instance", result); - return result.FirstOrDefault(x => x.Source == splunkInstance.ToString()); - } - } -} diff --git a/source/gpconnect-analytics.DAL/DataService.cs b/source/gpconnect-analytics.DAL/DataService.cs deleted file mode 100644 index c01af79..0000000 --- a/source/gpconnect-analytics.DAL/DataService.cs +++ /dev/null @@ -1,88 +0,0 @@ -using Dapper; -using gpconnect_analytics.DAL.Interfaces; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Logging; -using System; -using System.Collections.Generic; -using System.Data.SqlClient; -using System.Threading.Tasks; - -namespace gpconnect_analytics.DAL -{ - public class DataService : IDataService - { - private readonly ILogger _logger; - private readonly IConfiguration _configuration; - private readonly string _connectionString; - - public DataService(ILogger logger, IConfiguration configuration) - { - _logger = logger; - _configuration = configuration; - _connectionString = _configuration.GetConnectionString(ConnectionStrings.GpConnectAnalytics); - } - - public async Task> ExecuteStoredProcedure(string procedureName, DynamicParameters parameters) where T : class - { - using (var sqlConnection = new SqlConnection(_connectionString)) - { - try - { - sqlConnection.InfoMessage += SqlConnection_InfoMessage; - _logger.LogInformation($"Executing stored procedure {procedureName}", parameters); - var results = await sqlConnection.QueryAsync(procedureName, parameters, commandType: System.Data.CommandType.StoredProcedure, commandTimeout: 0); - return results.AsList(); - } - catch (Exception exc) - { - _logger?.LogError(exc, $"An error has occurred while attempting to execute the function {procedureName}"); - throw; - } - } - } - - public async Task ExecuteStoredProcedureWithOutputParameters(string procedureName, DynamicParameters parameters) - { - using (var sqlConnection = new SqlConnection(_connectionString)) - { - try - { - sqlConnection.InfoMessage += SqlConnection_InfoMessage; - _logger.LogInformation($"Executing stored procedure {procedureName}", parameters); - await SqlMapper.ExecuteAsync(sqlConnection, procedureName, parameters, commandType: System.Data.CommandType.StoredProcedure, commandTimeout: 0); - return parameters; - } - catch (Exception exc) - { - _logger?.LogError(exc, $"An error has occurred while attempting to execute the function {procedureName}"); - throw; - } - } - } - - public async Task ExecuteStoredProcedure(string procedureName, DynamicParameters parameters) - { - - using (var sqlConnection = new SqlConnection(_connectionString)) - { - try - { - sqlConnection.InfoMessage += SqlConnection_InfoMessage; - _logger.LogInformation($"Executing stored procedure {procedureName}", parameters); - var result = await sqlConnection.ExecuteAsync(procedureName, parameters, commandType: System.Data.CommandType.StoredProcedure, commandTimeout: 0); - return result; - } - catch (Exception exc) - { - _logger?.LogError(exc, $"An error has occurred while attempting to execute the function {procedureName}"); - throw; - } - } - } - - private void SqlConnection_InfoMessage(object sender, SqlInfoMessageEventArgs e) - { - _logger?.LogInformation(e.Message); - } - } -} diff --git a/source/gpconnect-analytics.DAL/ImportService.cs b/source/gpconnect-analytics.DAL/ImportService.cs deleted file mode 100644 index c0c3ad7..0000000 --- a/source/gpconnect-analytics.DAL/ImportService.cs +++ /dev/null @@ -1,101 +0,0 @@ -using Dapper; -using gpconnect_analytics.DAL.Interfaces; -using gpconnect_analytics.DTO.Response.Configuration; -using gpconnect_analytics.DTO.Response.Queue; -using gpconnect_analytics.DTO.Response.Splunk; -using gpconnect_analytics.Helpers; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Logging; -using System; -using System.Data; -using System.Threading.Tasks; - -namespace gpconnect_analytics.DAL -{ - public class ImportService : IImportService - { - private readonly ILogger _logger; - private readonly IDataService _dataService; - private readonly IBlobService _blobService; - private readonly IConfigurationService _configurationService; - - public ImportService(IConfigurationService configurationService, IDataService dataService, IBlobService blobService, ILogger logger) - { - _logger = logger; - _configurationService = configurationService; - _dataService = dataService; - _blobService = blobService; - } - - public async Task AddDownloadedFileManually(HttpRequest req) - { - var filePath = req.Query["FilePath"].ToString(); - var fileTypeFromPath = filePath.GetFileType(); - - if (fileTypeFromPath != null) - { - var fileType = await _configurationService.GetFileType((FileTypes)fileTypeFromPath); - await AddFileMessage(fileType, new ExtractResponse() { FilePath = filePath }); - return new OkObjectResult($"Import of {filePath} complete"); - } - return new BadRequestObjectResult("Bad request"); - } - - public async Task AddObjectFileMessage(FileType fileType, ExtractResponse extractResponse) - { - switch (extractResponse?.ExtractResponseMessage.StatusCode) - { - case System.Net.HttpStatusCode.OK: - var uploadedBlob = await _blobService.AddObjectToBlob(extractResponse); - if (uploadedBlob != null) - { - await AddFileMessage(fileType, extractResponse); - } - break; - default: - _logger?.LogWarning(extractResponse?.ExtractResponseMessage.ToString()); - break; - throw new Exception($"Splunk has returned the following HTTP status code {extractResponse?.ExtractResponseMessage.StatusCode}"); - } - } - - public async Task AddFileMessage(FileType fileType, ExtractResponse extractResponse) - { - var fileAddedCount = await AddFile(fileType.FileTypeId, extractResponse.FilePath, true); - await _blobService.AddMessageToBlobQueue(fileAddedCount, fileType.FileTypeId, extractResponse.FilePath, true); - } - - public async Task AddFile(int fileTypeId, string filePath, bool overrideFile) - { - var procedureName = "ApiReader.AddFile"; - var parameters = new DynamicParameters(); - parameters.Add("@FileTypeId", fileTypeId); - parameters.Add("@FilePath", filePath); - parameters.Add("@Override", overrideFile); - var result = await _dataService.ExecuteStoredProcedure(procedureName, parameters); - return result; - } - - public async Task InstallData(Message queueItem) - { - bool moreFilesToInstall = true; - var procedureName = "Import.InstallNextFile"; - var parameters = new DynamicParameters(); - parameters.Add("@FileTypeId", queueItem.FileTypeId); - if(queueItem.Override) - { - parameters.Add("@Override", queueItem.Override, dbType: DbType.Boolean, direction: ParameterDirection.Input); - } - parameters.Add("@MoreFilesToInstall", dbType: DbType.Boolean, direction: ParameterDirection.Output); - - while (moreFilesToInstall) - { - _logger.LogInformation($"Installing file into database", parameters); - var result = await _dataService.ExecuteStoredProcedureWithOutputParameters(procedureName, parameters); - moreFilesToInstall = result.Get("@MoreFilesToInstall"); - _logger.LogInformation($"More files to install? {moreFilesToInstall}"); - }; - } - } -} diff --git a/source/gpconnect-analytics.DAL/Interfaces/IBatchService.cs b/source/gpconnect-analytics.DAL/Interfaces/IBatchService.cs deleted file mode 100644 index 2e279ce..0000000 --- a/source/gpconnect-analytics.DAL/Interfaces/IBatchService.cs +++ /dev/null @@ -1,19 +0,0 @@ -using gpconnect_analytics.DTO.Request; -using gpconnect_analytics.DTO.Response.Configuration; -using gpconnect_analytics.Helpers; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; -using System; -using System.Collections.Generic; -using System.Threading.Tasks; - -namespace gpconnect_analytics.DAL.Interfaces -{ - public interface IBatchService - { - Task> GetBatchDownloadUriList(FileType fileType, List dateTimeList); - Task RemovePreviousDownloads(FileType fileType, DateTime startDate, DateTime endDate); - Task StartBatchDownloadForTodayAsync(FileTypes fileTypes); - Task StartBatchDownloadAsync(HttpRequest req, FileTypes fileTypes); - } -} diff --git a/source/gpconnect-analytics.DAL/Interfaces/IBlobService.cs b/source/gpconnect-analytics.DAL/Interfaces/IBlobService.cs deleted file mode 100644 index 8264c8b..0000000 --- a/source/gpconnect-analytics.DAL/Interfaces/IBlobService.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Azure.Storage.Blobs.Models; -using gpconnect_analytics.DTO.Response.Splunk; -using System.Threading.Tasks; - -namespace gpconnect_analytics.DAL.Interfaces -{ - public interface IBlobService - { - Task AddMessageToBlobQueue(int fileAddedCount, int fileTypeId, string blobName, bool overrideEntry = false); - Task AddObjectToBlob(ExtractResponse extractResponse); - } -} diff --git a/source/gpconnect-analytics.DAL/Interfaces/IDataService.cs b/source/gpconnect-analytics.DAL/Interfaces/IDataService.cs deleted file mode 100644 index a5068b7..0000000 --- a/source/gpconnect-analytics.DAL/Interfaces/IDataService.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Dapper; -using System.Collections.Generic; -using System.Threading.Tasks; - -namespace gpconnect_analytics.DAL.Interfaces -{ - public interface IDataService - { - Task> ExecuteStoredProcedure(string procedureName, DynamicParameters parameters = null) where T : class; - Task ExecuteStoredProcedureWithOutputParameters(string procedureName, DynamicParameters parameters); - Task ExecuteStoredProcedure(string procedureName, DynamicParameters parameters = null); - } -} diff --git a/source/gpconnect-analytics.DAL/Interfaces/IImportService.cs b/source/gpconnect-analytics.DAL/Interfaces/IImportService.cs deleted file mode 100644 index 3b0c163..0000000 --- a/source/gpconnect-analytics.DAL/Interfaces/IImportService.cs +++ /dev/null @@ -1,17 +0,0 @@ -using gpconnect_analytics.DTO.Response.Configuration; -using gpconnect_analytics.DTO.Response.Queue; -using gpconnect_analytics.DTO.Response.Splunk; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; -using System.Threading.Tasks; - -namespace gpconnect_analytics.DAL.Interfaces -{ - public interface IImportService - { - Task InstallData(Message message); - Task AddFile(int fileTypeId, string filePath, bool overrideFile); - Task AddDownloadedFileManually(HttpRequest req); - Task AddObjectFileMessage(FileType fileType, ExtractResponse extractResponse); - } -} diff --git a/source/gpconnect-analytics.DAL/Interfaces/ISplunkService.cs b/source/gpconnect-analytics.DAL/Interfaces/ISplunkService.cs deleted file mode 100644 index dd25a4e..0000000 --- a/source/gpconnect-analytics.DAL/Interfaces/ISplunkService.cs +++ /dev/null @@ -1,12 +0,0 @@ -using gpconnect_analytics.DTO.Request; -using gpconnect_analytics.DTO.Response.Configuration; -using gpconnect_analytics.DTO.Response.Splunk; -using System.Threading.Tasks; - -namespace gpconnect_analytics.DAL.Interfaces -{ - public interface ISplunkService - { - Task DownloadCSVDateRangeAsync(FileType fileType, UriRequest uriRequest, bool isToday); - } -} diff --git a/source/gpconnect-analytics.DAL/gpconnect-analytics.DAL.csproj b/source/gpconnect-analytics.DAL/gpconnect-analytics.DAL.csproj deleted file mode 100644 index eaf6218..0000000 --- a/source/gpconnect-analytics.DAL/gpconnect-analytics.DAL.csproj +++ /dev/null @@ -1,29 +0,0 @@ - - - - netcoreapp3.1 - gpconnect_analytics.DAL - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/source/gpconnect-analytics.DTO/Request/AsidLookupRun.cs b/source/gpconnect-analytics.DTO/Request/AsidLookupRun.cs deleted file mode 100644 index 8f4875b..0000000 --- a/source/gpconnect-analytics.DTO/Request/AsidLookupRun.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace gpconnect_analytics.DTO.Request -{ - public class AsidLookupRun : BaseRun - { - } -} diff --git a/source/gpconnect-analytics.DTO/Response/Import/NextFile.cs b/source/gpconnect-analytics.DTO/Response/Import/NextFile.cs deleted file mode 100644 index 5d5b209..0000000 --- a/source/gpconnect-analytics.DTO/Response/Import/NextFile.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace gpconnect_analytics.DTO.Response.Import -{ - public class NextFile - { - public bool MoreFilesToInstall { get; set; } - } -} diff --git a/source/gpconnect-analytics.DTO/gpconnect-analytics.DTO.csproj b/source/gpconnect-analytics.DTO/gpconnect-analytics.DTO.csproj deleted file mode 100644 index 0edb15e..0000000 --- a/source/gpconnect-analytics.DTO/gpconnect-analytics.DTO.csproj +++ /dev/null @@ -1,13 +0,0 @@ - - - - netcoreapp3.1 - gpconnect_analytics.DTO - - - - - - - - diff --git a/source/gpconnect-analytics.Functions/Configuration/Infrastructure/HttpClient/HttpClientExtensions.cs b/source/gpconnect-analytics.Functions/Configuration/Infrastructure/HttpClient/HttpClientExtensions.cs deleted file mode 100644 index 8c001ea..0000000 --- a/source/gpconnect-analytics.Functions/Configuration/Infrastructure/HttpClient/HttpClientExtensions.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Security.Authentication; - -namespace gpconnect_analytics.Configuration.Infrastructure.HttpClient -{ - public static class HttpClientExtensions - { - public static System.Net.Http.HttpClient ConfigureHttpClient(System.Net.Http.HttpClient options) - { - options.Timeout = new TimeSpan(0, 0, 1, 0); - options.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/csv")); - options.DefaultRequestHeaders.CacheControl = new CacheControlHeaderValue { NoCache = true }; - return options; - } - - public static HttpMessageHandler CreateHttpMessageHandler() - { - var httpClientHandler = new HttpClientHandler - { - SslProtocols = SslProtocols.Tls13 | SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls - }; - return httpClientHandler; - } - } -} diff --git a/source/gpconnect-analytics.Functions/Configuration/Infrastructure/Mapping/MappingExtensions.cs b/source/gpconnect-analytics.Functions/Configuration/Infrastructure/Mapping/MappingExtensions.cs deleted file mode 100644 index baa1fea..0000000 --- a/source/gpconnect-analytics.Functions/Configuration/Infrastructure/Mapping/MappingExtensions.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Dapper.FluentMap; -using gpconnect_analytics.DAL.Mapping; - -namespace gpconnect_analytics.Configuration.Infrastructure -{ - public static class MappingExtensions - { - public static void ConfigureMappingServices() - { - FluentMapper.Initialize(config => - { - config.AddMap(new SplunkInstanceMap()); - }); - } - } -} diff --git a/source/gpconnect-analytics.Functions/ExecuteImportByTrigger.cs b/source/gpconnect-analytics.Functions/ExecuteImportByTrigger.cs deleted file mode 100644 index 99675cd..0000000 --- a/source/gpconnect-analytics.Functions/ExecuteImportByTrigger.cs +++ /dev/null @@ -1,24 +0,0 @@ -using gpconnect_analytics.DAL.Interfaces; -using gpconnect_analytics.DTO.Response.Queue; -using Microsoft.Azure.WebJobs; -using Microsoft.Extensions.Logging; -using System.Threading.Tasks; - -namespace gpconnect_analytics.Functions -{ - public class ExecuteImportByTrigger - { - private readonly IImportService _importService; - - public ExecuteImportByTrigger(IImportService importService) - { - _importService = importService; - } - - [FunctionName("ExecuteImportByTrigger")] - public async Task Run([QueueTrigger("%QueueName%")] Message queueItem, ILogger log) - { - await _importService.InstallData(queueItem); - } - } -} diff --git a/source/gpconnect-analytics.Functions/GetDataFromApiByDateRange.cs b/source/gpconnect-analytics.Functions/GetDataFromApiByDateRange.cs deleted file mode 100644 index f7f91ce..0000000 --- a/source/gpconnect-analytics.Functions/GetDataFromApiByDateRange.cs +++ /dev/null @@ -1,39 +0,0 @@ -using gpconnect_analytics.DAL.Interfaces; -using gpconnect_analytics.Helpers; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; -using Microsoft.Azure.WebJobs; -using Microsoft.Azure.WebJobs.Extensions.Http; -using Microsoft.Extensions.Logging; -using System.Threading.Tasks; - -namespace gpconnect_analytics.Functions -{ - public class GetDataFromApiByDateRange - { - private readonly IBatchService _batchService; - - public GetDataFromApiByDateRange(IBatchService batchService) - { - _batchService = batchService; - } - - [FunctionName("GetDataFromApiByDateRangeSspTrans")] - public async Task GetDataFromSspTransByDateRange([HttpTrigger(AuthorizationLevel.Function, "GET", Route = null)] HttpRequest req, ILogger log) - { - return await _batchService.StartBatchDownloadAsync(req, FileTypes.ssptrans); - } - - [FunctionName("GetDataFromApiByDateRangeMeshTrans")] - public async Task GetDataFromMeshTransByDateRange([HttpTrigger(AuthorizationLevel.Function, "GET", Route = null)] HttpRequest req, ILogger log) - { - return await _batchService.StartBatchDownloadAsync(req, FileTypes.meshtrans); - } - - [FunctionName("GetDataFromApiByDateRangeAsidLookup")] - public async Task GetDataFromAsidLookupByDateRange([HttpTrigger(AuthorizationLevel.Function, "GET", Route = null)] HttpRequest req, ILogger log) - { - return await _batchService.StartBatchDownloadAsync(req, FileTypes.asidlookup); - } - } -} diff --git a/source/gpconnect-analytics.Functions/GetDataFromApiByTrigger.cs b/source/gpconnect-analytics.Functions/GetDataFromApiByTrigger.cs deleted file mode 100644 index 5741505..0000000 --- a/source/gpconnect-analytics.Functions/GetDataFromApiByTrigger.cs +++ /dev/null @@ -1,36 +0,0 @@ -using gpconnect_analytics.DAL.Interfaces; -using gpconnect_analytics.Helpers; -using Microsoft.Azure.WebJobs; -using Microsoft.Extensions.Logging; -using System.Threading.Tasks; - -namespace gpconnect_analytics.Functions -{ - public class GetDataFromApiByTrigger - { - private readonly IBatchService _batchService; - - public GetDataFromApiByTrigger(IBatchService batchService) - { - _batchService = batchService; - } - - [FunctionName("GetDataFromApiByTriggerAsidLookup")] - public async Task GetDataFromAsidLookup([TimerTrigger("%GetDataFromApiByTriggerAsidLookupSchedule%", RunOnStartup = false)] TimerInfo myTimer, ILogger log) - { - await _batchService.StartBatchDownloadForTodayAsync(FileTypes.asidlookup); - } - - [FunctionName("GetDataFromApiByTriggerSspTrans")] - public async Task GetDataFromSspTrans([TimerTrigger("%GetDataFromApiByTriggerSspTransSchedule%", RunOnStartup = false)] TimerInfo myTimer, ILogger log) - { - await _batchService.StartBatchDownloadForTodayAsync(FileTypes.ssptrans); - } - - [FunctionName("GetDataFromApiByTriggerMeshTrans")] - public async Task GetDataFromMeshTrans([TimerTrigger("%GetDataFromApiByTriggerMeshTransSchedule%", RunOnStartup = false)] TimerInfo myTimer, ILogger log) - { - await _batchService.StartBatchDownloadForTodayAsync(FileTypes.meshtrans); - } - } -} diff --git a/source/gpconnect-analytics.Functions/GetDataFromApiManual.cs b/source/gpconnect-analytics.Functions/GetDataFromApiManual.cs deleted file mode 100644 index a474b5f..0000000 --- a/source/gpconnect-analytics.Functions/GetDataFromApiManual.cs +++ /dev/null @@ -1,26 +0,0 @@ -using gpconnect_analytics.DAL.Interfaces; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; -using Microsoft.Azure.WebJobs; -using Microsoft.Azure.WebJobs.Extensions.Http; -using Microsoft.Extensions.Logging; -using System.Threading.Tasks; - -namespace gpconnect_analytics.Functions -{ - public class GetDataFromApiManual - { - private readonly IImportService _importService; - - public GetDataFromApiManual(IImportService importService) - { - _importService = importService; - } - - [FunctionName("GetDataFromApiManual")] - public async Task AddDownloadedFile([HttpTrigger(AuthorizationLevel.Function, "GET", Route = null)] HttpRequest req, ILogger log) - { - return await _importService.AddDownloadedFileManually(req); - } - } -} diff --git a/source/gpconnect-analytics.Functions/GetDataFromApiToday.cs b/source/gpconnect-analytics.Functions/GetDataFromApiToday.cs deleted file mode 100644 index 03fe9be..0000000 --- a/source/gpconnect-analytics.Functions/GetDataFromApiToday.cs +++ /dev/null @@ -1,39 +0,0 @@ -using gpconnect_analytics.DAL.Interfaces; -using gpconnect_analytics.Helpers; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; -using Microsoft.Azure.WebJobs; -using Microsoft.Azure.WebJobs.Extensions.Http; -using Microsoft.Extensions.Logging; -using System.Threading.Tasks; - -namespace gpconnect_analytics.Functions -{ - public class GetDataFromApiToday - { - private readonly IBatchService _batchService; - - public GetDataFromApiToday(IBatchService batchService) - { - _batchService = batchService; - } - - [FunctionName("GetDataFromApiTodaySspTrans")] - public async Task GetDataFromSspTransByDateRange([HttpTrigger(AuthorizationLevel.Function, "GET", Route = null)] HttpRequest req, ILogger log) - { - return await _batchService.StartBatchDownloadForTodayAsync(FileTypes.ssptrans); - } - - [FunctionName("GetDataFromApiTodayMeshTrans")] - public async Task GetDataFromMeshTransByDateRange([HttpTrigger(AuthorizationLevel.Function, "GET", Route = null)] HttpRequest req, ILogger log) - { - return await _batchService.StartBatchDownloadForTodayAsync(FileTypes.meshtrans); - } - - [FunctionName("GetDataFromApiTodayAsidLookup")] - public async Task GetDataFromAsidLookupByDateRange([HttpTrigger(AuthorizationLevel.Function, "GET", Route = null)] HttpRequest req, ILogger log) - { - return await _batchService.StartBatchDownloadForTodayAsync(FileTypes.asidlookup); - } - } -} diff --git a/source/gpconnect-analytics.Functions/PurgeErrorLogByTrigger.cs b/source/gpconnect-analytics.Functions/PurgeErrorLogByTrigger.cs deleted file mode 100644 index 8761068..0000000 --- a/source/gpconnect-analytics.Functions/PurgeErrorLogByTrigger.cs +++ /dev/null @@ -1,23 +0,0 @@ -using gpconnect_analytics.DAL.Interfaces; -using Microsoft.Azure.WebJobs; -using Microsoft.Extensions.Logging; -using System.Threading.Tasks; - -namespace gpconnect_analytics.Functions -{ - public class PurgeErrorLogByTrigger - { - private readonly ILoggingService _loggingService; - - public PurgeErrorLogByTrigger(ILoggingService loggingService) - { - _loggingService = loggingService; - } - - [FunctionName("PurgeErrorLogByTrigger")] - public async Task PurgeErrorLog([TimerTrigger("%PurgeErrorLogByTriggerSchedule%", RunOnStartup = false)] TimerInfo myTimer, ILogger log) - { - await _loggingService.PurgeErrorLog(); - } - } -} diff --git a/source/gpconnect-analytics.Functions/Startup.cs b/source/gpconnect-analytics.Functions/Startup.cs deleted file mode 100644 index f3fa4dd..0000000 --- a/source/gpconnect-analytics.Functions/Startup.cs +++ /dev/null @@ -1,31 +0,0 @@ -using gpconnect_analytics.Configuration.Infrastructure; -using gpconnect_analytics.Configuration.Infrastructure.Logging; -using gpconnect_analytics.DAL; -using gpconnect_analytics.DAL.Interfaces; -using gpconnect_analytics.Functions; -using Microsoft.Azure.Functions.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection; - -[assembly: FunctionsStartup(typeof(Startup))] -namespace gpconnect_analytics.Functions -{ - public class Startup : FunctionsStartup - { - public override void Configure(IFunctionsHostBuilder builder) - { - MappingExtensions.ConfigureMappingServices(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - - var configuration = builder.GetContext().Configuration; - builder.Services.AddLogging(loggingBuilder => LoggingExtensions.ConfigureLoggingServices(loggingBuilder, configuration)); - builder.Services.AddHttpClient("SplunkApiClient", options => Configuration.Infrastructure.HttpClient.HttpClientExtensions.ConfigureHttpClient(options)) - .ConfigurePrimaryHttpMessageHandler(() => Configuration.Infrastructure.HttpClient.HttpClientExtensions.CreateHttpMessageHandler()); - } - } -} diff --git a/source/gpconnect-analytics.Functions/gpconnect-analytics.Functions.csproj b/source/gpconnect-analytics.Functions/gpconnect-analytics.Functions.csproj deleted file mode 100644 index d2c95d7..0000000 --- a/source/gpconnect-analytics.Functions/gpconnect-analytics.Functions.csproj +++ /dev/null @@ -1,32 +0,0 @@ - - - netcoreapp3.1 - v4 - gpconnect_analytics.Functions - /home/site/wwwroot - Linux - - - - - - - - - - - - - - - - - - PreserveNewest - - - PreserveNewest - Never - - - diff --git a/source/gpconnect-analytics.Helpers/ApplicationHelper.cs b/source/gpconnect-analytics.Helpers/ApplicationHelper.cs deleted file mode 100644 index c214dca..0000000 --- a/source/gpconnect-analytics.Helpers/ApplicationHelper.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.Reflection; - -namespace gpconnect_analytics.Helpers -{ - public class ApplicationHelper - { - public static class ApplicationVersion - { - public static string GetAssemblyVersion() - { - string buildTag = System.Environment.GetEnvironmentVariable("BUILD_TAG"); - - if (string.IsNullOrWhiteSpace(buildTag)) - return Assembly.GetCallingAssembly()?.GetName().FullName; - - return buildTag; - } - } - } -} diff --git a/source/gpconnect-analytics.Helpers/AttributeExtensions.cs b/source/gpconnect-analytics.Helpers/AttributeExtensions.cs deleted file mode 100644 index a3412c4..0000000 --- a/source/gpconnect-analytics.Helpers/AttributeExtensions.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using System.Linq; - -namespace gpconnect_analytics.Helpers -{ - public static class AttributeExtensions - { - public static FileTypes? GetFileType(this string filePath) - { - return GetValueFromPath(filePath); - } - - public static FileTypes? GetValueFromPath(string filePath) - { - var fileType = typeof(FilePath).GetFields() - .Where(x => Attribute.GetCustomAttribute(x, typeof(FilePathAttribute)) is FilePathAttribute filePathAttribute && filePath.Contains(filePathAttribute?.FilePath)) - .FirstOrDefault(); - return fileType != null ? (FileTypes)fileType.GetValue(filePath) : (FileTypes?)null; - } - } -} \ No newline at end of file diff --git a/source/gpconnect-analytics.Helpers/ConfigurationHelper.cs b/source/gpconnect-analytics.Helpers/ConfigurationHelper.cs deleted file mode 100644 index e23b2f6..0000000 --- a/source/gpconnect-analytics.Helpers/ConfigurationHelper.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Microsoft.Extensions.Configuration; -using System; - -namespace gpconnect_analytics.Helpers -{ - public static class ConfigurationHelper - { - public static string GetConfigurationString(this IConfigurationSection configurationSetting, string defaultValue = "", bool throwExceptionIfEmpty = false) - { - var keyValueExists = configurationSetting.Exists() && !string.IsNullOrEmpty(configurationSetting.Value); - if (!keyValueExists && throwExceptionIfEmpty) throw new ArgumentNullException(configurationSetting.Key); - return keyValueExists ? configurationSetting.Value : defaultValue; - } - } -} diff --git a/source/gpconnect-analytics.Helpers/FileTypes.cs b/source/gpconnect-analytics.Helpers/FileTypes.cs deleted file mode 100644 index 9ca38ea..0000000 --- a/source/gpconnect-analytics.Helpers/FileTypes.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace gpconnect_analytics.Helpers -{ - public enum FileTypes - { - [FilePath("asid-lookup-data")] - asidlookup, - [FilePath("ssp-transactions")] - ssptrans, - [FilePath("mesh-transactions")] - meshtrans - } -} \ No newline at end of file diff --git a/source/gpconnect-analytics.Helpers/NumberExtensions.cs b/source/gpconnect-analytics.Helpers/NumberExtensions.cs deleted file mode 100644 index de32983..0000000 --- a/source/gpconnect-analytics.Helpers/NumberExtensions.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; - -namespace gpconnect_analytics.Helpers -{ - public static class NumberExtensions - { - public static int StringToInteger(this string valueIn, int defaultValue) - { - return int.TryParse(valueIn, out _) ? Convert.ToInt32(valueIn) : defaultValue; - } - - public static int StringToInteger(this string valueIn) - { - return int.Parse(valueIn); - } - - public static string UnitsFormatter(this double valueIn, string units) - { - return $"{valueIn} {units}"; - } - } - -} diff --git a/source/gpconnect-analytics.Helpers/StringExtensions.cs b/source/gpconnect-analytics.Helpers/StringExtensions.cs deleted file mode 100644 index ce4e5fb..0000000 --- a/source/gpconnect-analytics.Helpers/StringExtensions.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.Text; - -namespace gpconnect_analytics.Helpers -{ - public static class StringExtensions - { - public static string StringToBase64(this string valueIn) - { - return Convert.ToBase64String(Encoding.UTF8.GetBytes(valueIn)); - } - } -} diff --git a/source/gpconnect-analytics.Helpers/gpconnect-analytics.Helpers.csproj b/source/gpconnect-analytics.Helpers/gpconnect-analytics.Helpers.csproj deleted file mode 100644 index 8627406..0000000 --- a/source/gpconnect-analytics.Helpers/gpconnect-analytics.Helpers.csproj +++ /dev/null @@ -1,12 +0,0 @@ - - - - netcoreapp3.1 - - - - - - - - diff --git a/source/gpconnect-analytics.sln b/source/gpconnect-analytics.sln index cf3937b..cf75d48 100644 --- a/source/gpconnect-analytics.sln +++ b/source/gpconnect-analytics.sln @@ -3,13 +3,15 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.30804.86 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "gpconnect-analytics.Functions", "gpconnect-analytics.Functions\gpconnect-analytics.Functions.csproj", "{7EBDF22C-0A85-4151-A8D7-8D81E456276E}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Functions", "Functions\Functions.csproj", "{7EBDF22C-0A85-4151-A8D7-8D81E456276E}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "gpconnect-analytics.DAL", "gpconnect-analytics.DAL\gpconnect-analytics.DAL.csproj", "{3B1FB921-0C56-47D6-A716-A4DE679F6EBF}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Core", "Core\Core.csproj", "{66EFAC7B-6BD6-421A-B70D-126FC4D0EE3F}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "gpconnect-analytics.DTO", "gpconnect-analytics.DTO\gpconnect-analytics.DTO.csproj", "{18DE5071-433E-49D2-B168-136730EDB158}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Core.Tests", "Core.Tests\Core.Tests.csproj", "{5841302E-4C82-473D-9579-308FCBA85E50}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "gpconnect-analytics.Helpers", "gpconnect-analytics.Helpers\gpconnect-analytics.Helpers.csproj", "{D8523638-EE9F-4551-8F22-7FD91BD327FC}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IntegrationTests", "IntegrationTests\IntegrationTests.csproj", "{00CE1CEE-7D58-4689-8EB6-0F86E6DF8729}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Functions.Tests", "Functions.Tests\Functions.Tests.csproj", "{3A964393-AD74-49C0-891B-140B5C197661}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -21,18 +23,22 @@ Global {7EBDF22C-0A85-4151-A8D7-8D81E456276E}.Debug|Any CPU.Build.0 = Debug|Any CPU {7EBDF22C-0A85-4151-A8D7-8D81E456276E}.Release|Any CPU.ActiveCfg = Release|Any CPU {7EBDF22C-0A85-4151-A8D7-8D81E456276E}.Release|Any CPU.Build.0 = Release|Any CPU - {3B1FB921-0C56-47D6-A716-A4DE679F6EBF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3B1FB921-0C56-47D6-A716-A4DE679F6EBF}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3B1FB921-0C56-47D6-A716-A4DE679F6EBF}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3B1FB921-0C56-47D6-A716-A4DE679F6EBF}.Release|Any CPU.Build.0 = Release|Any CPU - {18DE5071-433E-49D2-B168-136730EDB158}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {18DE5071-433E-49D2-B168-136730EDB158}.Debug|Any CPU.Build.0 = Debug|Any CPU - {18DE5071-433E-49D2-B168-136730EDB158}.Release|Any CPU.ActiveCfg = Release|Any CPU - {18DE5071-433E-49D2-B168-136730EDB158}.Release|Any CPU.Build.0 = Release|Any CPU - {D8523638-EE9F-4551-8F22-7FD91BD327FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D8523638-EE9F-4551-8F22-7FD91BD327FC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D8523638-EE9F-4551-8F22-7FD91BD327FC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D8523638-EE9F-4551-8F22-7FD91BD327FC}.Release|Any CPU.Build.0 = Release|Any CPU + {66EFAC7B-6BD6-421A-B70D-126FC4D0EE3F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {66EFAC7B-6BD6-421A-B70D-126FC4D0EE3F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {66EFAC7B-6BD6-421A-B70D-126FC4D0EE3F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {66EFAC7B-6BD6-421A-B70D-126FC4D0EE3F}.Release|Any CPU.Build.0 = Release|Any CPU + {5841302E-4C82-473D-9579-308FCBA85E50}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5841302E-4C82-473D-9579-308FCBA85E50}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5841302E-4C82-473D-9579-308FCBA85E50}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5841302E-4C82-473D-9579-308FCBA85E50}.Release|Any CPU.Build.0 = Release|Any CPU + {00CE1CEE-7D58-4689-8EB6-0F86E6DF8729}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {00CE1CEE-7D58-4689-8EB6-0F86E6DF8729}.Debug|Any CPU.Build.0 = Debug|Any CPU + {00CE1CEE-7D58-4689-8EB6-0F86E6DF8729}.Release|Any CPU.ActiveCfg = Release|Any CPU + {00CE1CEE-7D58-4689-8EB6-0F86E6DF8729}.Release|Any CPU.Build.0 = Release|Any CPU + {3A964393-AD74-49C0-891B-140B5C197661}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3A964393-AD74-49C0-891B-140B5C197661}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3A964393-AD74-49C0-891B-140B5C197661}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3A964393-AD74-49C0-891B-140B5C197661}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/source/gpconnect-analytics.sln.DotSettings b/source/gpconnect-analytics.sln.DotSettings new file mode 100644 index 0000000..3ba9dd0 --- /dev/null +++ b/source/gpconnect-analytics.sln.DotSettings @@ -0,0 +1,16 @@ + + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True \ No newline at end of file From 108b7f147b4ad924eb59068bb36b67179f5f496b Mon Sep 17 00:00:00 2001 From: grant-dot-dev <12433404+grant-dot-dev@users.noreply.github.com> Date: Tue, 18 Feb 2025 11:10:21 +0000 Subject: [PATCH 2/3] removed coverage folders --- source/coverage/Core_ApplicationHelper.html | 198 ----- source/coverage/Core_AttributeExtensions.html | 202 ----- source/coverage/Core_ConnectionStrings.html | 180 ---- source/coverage/Core_DapperWrapper.html | 247 ------ source/coverage/Core_DateTimeHelper.html | 184 ---- source/coverage/Core_FilePathAttribute.html | 185 ---- .../Core_HierarchyProviderConsumerRepo.html | 235 ----- .../Core_OrganisationHierarchyProvider.html | 192 ---- source/coverage/Core_SplunkInstanceMap.html | 187 ---- source/coverage/Core_TimeProvider.html | 187 ---- source/coverage/Functions_BatchService.html | 327 ------- source/coverage/Functions_BlobService.html | 270 ------ .../Functions_ConfigurationService.html | 244 ----- .../Functions_CoreConfigurationService.html | 187 ---- source/coverage/Functions_DataService.html | 296 ------- .../Functions_DirectFunctionExecutor.html | 169 ---- .../Functions_EmailConfigurationProvider.html | 202 ----- .../Functions_ExecuteImportByTrigger.html | 189 ---- source/coverage/Functions_FileService.html | 192 ---- ...Functions_FunctionExecutorAutoStartup.html | 167 ---- ...FunctionExecutorHostBuilderExtensions.html | 167 ---- ...s_FunctionMetadataProviderAutoStartup.html | 167 ---- ...ons_GeneratedFunctionMetadataProvider.html | 167 ---- .../Functions_GetDataFromApiByDateRange.html | 262 ------ .../Functions_GetDataFromApiByTrigger.html | 211 ----- .../Functions_GetDataFromApiManual.html | 215 ----- .../Functions_GetDataFromApiToday.html | 275 ------ .../Functions_HttpClientExtensions.html | 198 ----- source/coverage/Functions_ImportService.html | 261 ------ .../coverage/Functions_LoggingExtensions.html | 368 -------- source/coverage/Functions_LoggingService.html | 196 ---- .../coverage/Functions_MappingExtensions.html | 186 ---- source/coverage/Functions_Program.html | 227 ----- .../Functions_PurgeErrorLogByTrigger.html | 189 ---- source/coverage/Functions_SplunkService.html | 366 -------- .../Functions_SqlConnectionFactory.html | 186 ---- .../Functions_StoreProviderConsumerData.html | 242 ----- ...ns_WorkerExtensionStartupCodeExecutor.html | 167 ---- ...lderFunctionMetadataProviderExtension.html | 167 ---- source/coverage/class.js | 218 ----- source/coverage/icon_cog.svg | 1 - source/coverage/icon_cog_dark.svg | 1 - source/coverage/icon_cube.svg | 2 - source/coverage/icon_cube_dark.svg | 1 - source/coverage/icon_fork.svg | 2 - source/coverage/icon_fork_dark.svg | 1 - source/coverage/icon_info-circled.svg | 2 - source/coverage/icon_info-circled_dark.svg | 2 - source/coverage/icon_minus.svg | 2 - source/coverage/icon_minus_dark.svg | 1 - source/coverage/icon_plus.svg | 2 - source/coverage/icon_plus_dark.svg | 1 - source/coverage/icon_search-minus.svg | 2 - source/coverage/icon_search-minus_dark.svg | 1 - source/coverage/icon_search-plus.svg | 2 - source/coverage/icon_search-plus_dark.svg | 1 - source/coverage/icon_sponsor.svg | 2 - source/coverage/icon_star.svg | 2 - source/coverage/icon_star_dark.svg | 2 - source/coverage/icon_up-dir.svg | 2 - source/coverage/icon_up-dir_active.svg | 2 - source/coverage/icon_up-down-dir.svg | 2 - source/coverage/icon_up-down-dir_dark.svg | 2 - source/coverage/icon_wrench.svg | 2 - source/coverage/icon_wrench_dark.svg | 1 - source/coverage/index.htm | 234 ----- source/coverage/index.html | 234 ----- source/coverage/main.js | 334 ------- source/coverage/report.css | 834 ------------------ 69 files changed, 10352 deletions(-) delete mode 100644 source/coverage/Core_ApplicationHelper.html delete mode 100644 source/coverage/Core_AttributeExtensions.html delete mode 100644 source/coverage/Core_ConnectionStrings.html delete mode 100644 source/coverage/Core_DapperWrapper.html delete mode 100644 source/coverage/Core_DateTimeHelper.html delete mode 100644 source/coverage/Core_FilePathAttribute.html delete mode 100644 source/coverage/Core_HierarchyProviderConsumerRepo.html delete mode 100644 source/coverage/Core_OrganisationHierarchyProvider.html delete mode 100644 source/coverage/Core_SplunkInstanceMap.html delete mode 100644 source/coverage/Core_TimeProvider.html delete mode 100644 source/coverage/Functions_BatchService.html delete mode 100644 source/coverage/Functions_BlobService.html delete mode 100644 source/coverage/Functions_ConfigurationService.html delete mode 100644 source/coverage/Functions_CoreConfigurationService.html delete mode 100644 source/coverage/Functions_DataService.html delete mode 100644 source/coverage/Functions_DirectFunctionExecutor.html delete mode 100644 source/coverage/Functions_EmailConfigurationProvider.html delete mode 100644 source/coverage/Functions_ExecuteImportByTrigger.html delete mode 100644 source/coverage/Functions_FileService.html delete mode 100644 source/coverage/Functions_FunctionExecutorAutoStartup.html delete mode 100644 source/coverage/Functions_FunctionExecutorHostBuilderExtensions.html delete mode 100644 source/coverage/Functions_FunctionMetadataProviderAutoStartup.html delete mode 100644 source/coverage/Functions_GeneratedFunctionMetadataProvider.html delete mode 100644 source/coverage/Functions_GetDataFromApiByDateRange.html delete mode 100644 source/coverage/Functions_GetDataFromApiByTrigger.html delete mode 100644 source/coverage/Functions_GetDataFromApiManual.html delete mode 100644 source/coverage/Functions_GetDataFromApiToday.html delete mode 100644 source/coverage/Functions_HttpClientExtensions.html delete mode 100644 source/coverage/Functions_ImportService.html delete mode 100644 source/coverage/Functions_LoggingExtensions.html delete mode 100644 source/coverage/Functions_LoggingService.html delete mode 100644 source/coverage/Functions_MappingExtensions.html delete mode 100644 source/coverage/Functions_Program.html delete mode 100644 source/coverage/Functions_PurgeErrorLogByTrigger.html delete mode 100644 source/coverage/Functions_SplunkService.html delete mode 100644 source/coverage/Functions_SqlConnectionFactory.html delete mode 100644 source/coverage/Functions_StoreProviderConsumerData.html delete mode 100644 source/coverage/Functions_WorkerExtensionStartupCodeExecutor.html delete mode 100644 source/coverage/Functions_WorkerHostBuilderFunctionMetadataProviderExtension.html delete mode 100644 source/coverage/class.js delete mode 100644 source/coverage/icon_cog.svg delete mode 100644 source/coverage/icon_cog_dark.svg delete mode 100644 source/coverage/icon_cube.svg delete mode 100644 source/coverage/icon_cube_dark.svg delete mode 100644 source/coverage/icon_fork.svg delete mode 100644 source/coverage/icon_fork_dark.svg delete mode 100644 source/coverage/icon_info-circled.svg delete mode 100644 source/coverage/icon_info-circled_dark.svg delete mode 100644 source/coverage/icon_minus.svg delete mode 100644 source/coverage/icon_minus_dark.svg delete mode 100644 source/coverage/icon_plus.svg delete mode 100644 source/coverage/icon_plus_dark.svg delete mode 100644 source/coverage/icon_search-minus.svg delete mode 100644 source/coverage/icon_search-minus_dark.svg delete mode 100644 source/coverage/icon_search-plus.svg delete mode 100644 source/coverage/icon_search-plus_dark.svg delete mode 100644 source/coverage/icon_sponsor.svg delete mode 100644 source/coverage/icon_star.svg delete mode 100644 source/coverage/icon_star_dark.svg delete mode 100644 source/coverage/icon_up-dir.svg delete mode 100644 source/coverage/icon_up-dir_active.svg delete mode 100644 source/coverage/icon_up-down-dir.svg delete mode 100644 source/coverage/icon_up-down-dir_dark.svg delete mode 100644 source/coverage/icon_wrench.svg delete mode 100644 source/coverage/icon_wrench_dark.svg delete mode 100644 source/coverage/index.htm delete mode 100644 source/coverage/index.html delete mode 100644 source/coverage/main.js delete mode 100644 source/coverage/report.css diff --git a/source/coverage/Core_ApplicationHelper.html b/source/coverage/Core_ApplicationHelper.html deleted file mode 100644 index 9ec4665..0000000 --- a/source/coverage/Core_ApplicationHelper.html +++ /dev/null @@ -1,198 +0,0 @@ - - - - - - - -Core.Helpers.ApplicationHelper - Coverage Report - -
-

< Summary

-
-
-
Information
-
-
- - - - - - - - - - - - - -
Class:Core.Helpers.ApplicationHelper
Assembly:Core
File(s):/Users/griordan/git/gpconnect-analytics/source/Core/Helpers/ApplicationHelper.cs
-
-
-
-
-
-
-
Line coverage
-
-
100%
-
- - - - - - - - - - - - - - - - - - - - - -
Covered lines:7
Uncovered lines:0
Coverable lines:7
Total lines:23
Line coverage:100%
-
-
-
-
-
Branch coverage
-
-
66%
-
- - - - - - - - - - - - - -
Covered branches:4
Total branches:6
Branch coverage:66.6%
-
-
-
-
-
Method coverage
-
-
-

Feature is only available for sponsors

-Upgrade to PRO version -
-
-
-
-

Metrics

-
- ------- - - - - - -
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
GetAssemblyVersion()100%11100%
GetAssemblyVersionInternal(...)100%44100%
-
-

File(s)

-

/Users/griordan/git/gpconnect-analytics/source/Core/Helpers/ApplicationHelper.cs

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - -
#LineLine coverage
 1using System.Reflection;
 2
 3namespace Core.Helpers
 4{
 5    public class ApplicationHelper
 6    {
 7        public static class ApplicationVersion
 8        {
 9            public static string GetAssemblyVersion()
 110            {
 111                return GetAssemblyVersionInternal(Assembly.GetCallingAssembly);
 112            }
 13
 14            // Internal method to allow dependency injection for testing
 15            public static string GetAssemblyVersionInternal(Func<Assembly> getAssembly)
 616            {
 617                var buildTag = System.Environment.GetEnvironmentVariable("BUILD_TAG");
 18
 619                return string.IsNullOrWhiteSpace(buildTag) ? getAssembly()?.GetName().FullName : buildTag;
 620            }
 21        }
 22    }
 23}
-
-
-
- \ No newline at end of file diff --git a/source/coverage/Core_AttributeExtensions.html b/source/coverage/Core_AttributeExtensions.html deleted file mode 100644 index 1b07772..0000000 --- a/source/coverage/Core_AttributeExtensions.html +++ /dev/null @@ -1,202 +0,0 @@ - - - - - - - -Core.Helpers.AttributeExtensions - Coverage Report - -
-

< Summary

-
-
-
Information
-
-
- - - - - - - - - - - - - -
Class:Core.Helpers.AttributeExtensions
Assembly:Core
File(s):/Users/griordan/git/gpconnect-analytics/source/Core/Helpers/AttributeExtensions.cs
-
-
-
-
-
-
-
Line coverage
-
-
100%
-
- - - - - - - - - - - - - - - - - - - - - -
Covered lines:13
Uncovered lines:0
Coverable lines:13
Total lines:27
Line coverage:100%
-
-
-
-
-
Branch coverage
-
-
100%
-
- - - - - - - - - - - - - -
Covered branches:6
Total branches:6
Branch coverage:100%
-
-
-
-
-
Method coverage
-
-
-

Feature is only available for sponsors

-Upgrade to PRO version -
-
-
-
-

Metrics

-
- ------- - - - - - -
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
GetFileType(...)100%11100%
GetValueFromPath(...)100%44100%
-
-

File(s)

-

/Users/griordan/git/gpconnect-analytics/source/Core/Helpers/AttributeExtensions.cs

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#LineLine coverage
 1using System.Reflection;
 2
 3namespace Core.Helpers
 4{
 5    public static class AttributeExtensions
 6    {
 7        public static FileTypes? GetFileType<TFilePath>(this string filePath)
 88        {
 89            return GetValueFromPath<TFilePath>(filePath);
 810        }
 11
 12        private static FileTypes? GetValueFromPath<T>(string filePath)
 813        {
 814            if (string.IsNullOrEmpty(filePath))
 215            {
 216                return null;
 17            }
 18
 619            var fileType = typeof(T).GetFields()
 620                .FirstOrDefault(field =>
 1221                    field.GetCustomAttribute<FilePathAttribute>() is { } attribute &&
 1222                    filePath.Contains(attribute.FilePath));
 23
 624            return fileType?.GetValue(null) as FileTypes?;
 825        }
 26    }
 27}
-
-
-
- \ No newline at end of file diff --git a/source/coverage/Core_ConnectionStrings.html b/source/coverage/Core_ConnectionStrings.html deleted file mode 100644 index 6fec525..0000000 --- a/source/coverage/Core_ConnectionStrings.html +++ /dev/null @@ -1,180 +0,0 @@ - - - - - - - -Core.Helpers.ConnectionStrings - Coverage Report - -
-

< Summary

-
-
-
Information
-
-
- - - - - - - - - - - - - -
Class:Core.Helpers.ConnectionStrings
Assembly:Core
File(s):/Users/griordan/git/gpconnect-analytics/source/Core/Helpers/ConnectionStrings.cs
-
-
-
-
-
-
-
Line coverage
-
-
100%
-
- - - - - - - - - - - - - - - - - - - - - -
Covered lines:1
Uncovered lines:0
Coverable lines:1
Total lines:7
Line coverage:100%
-
-
-
-
-
Branch coverage
-
-
N/A
-
- - - - - - - - - - - - - -
Covered branches:0
Total branches:0
Branch coverage:N/A
-
-
-
-
-
Method coverage
-
-
-

Feature is only available for sponsors

-Upgrade to PRO version -
-
-
-
-

Metrics

-
- ------- - - - - -
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.cctor()100%11100%
-
-

File(s)

-

/Users/griordan/git/gpconnect-analytics/source/Core/Helpers/ConnectionStrings.cs

-
- - - - - - - - - - - -
#LineLine coverage
 1namespace Core.Helpers
 2{
 3    public static class ConnectionStrings
 4    {
 15        public static string GpConnectAnalytics { get; } = "GpConnectAnalytics";
 6    }
 7}
-
-
-
-
-

Methods/Properties

-.cctor()
-
-
- \ No newline at end of file diff --git a/source/coverage/Core_DapperWrapper.html b/source/coverage/Core_DapperWrapper.html deleted file mode 100644 index 60e8176..0000000 --- a/source/coverage/Core_DapperWrapper.html +++ /dev/null @@ -1,247 +0,0 @@ - - - - - - - -Core.Repositories.DapperWrapper - Coverage Report - -
-

< Summary

-
-
-
Information
-
-
- - - - - - - - - - - - - -
Class:Core.Repositories.DapperWrapper
Assembly:Core
File(s):/Users/griordan/git/gpconnect-analytics/source/Core/Repositories/DapperWrapper.cs
-
-
-
-
-
-
-
Line coverage
-
-
96%
-
- - - - - - - - - - - - - - - - - - - - - -
Covered lines:27
Uncovered lines:1
Coverable lines:28
Total lines:68
Line coverage:96.4%
-
-
-
-
-
Branch coverage
-
-
N/A
-
- - - - - - - - - - - - - -
Covered branches:0
Total branches:0
Branch coverage:N/A
-
-
-
-
-
Method coverage
-
-
-

Feature is only available for sponsors

-Upgrade to PRO version -
-
-
-
-

Metrics

-
- ------- - - - - - - - -
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
ExecuteAsync()100%11100%
ExecuteStoredProcedureAsync()100%11100%
QueryStoredProcedureAsync()100%1190.9%
QueryAsync()100%11100%
-
-

File(s)

-

/Users/griordan/git/gpconnect-analytics/source/Core/Repositories/DapperWrapper.cs

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#LineLine coverage
 1using System.Data;
 2using Dapper;
 3
 4namespace Core.Repositories;
 5
 6public interface IDapperWrapper
 7{
 8    Task<int> ExecuteAsync(IDbConnection connection, string sql, object param = null,
 9        IDbTransaction transaction = null);
 10
 11    Task<IEnumerable<T>> QueryAsync<T>(IDbConnection connection, string sql, object param = null,
 12        IDbTransaction transaction = null);
 13
 14    Task<int> ExecuteStoredProcedureAsync<T>(IDbConnection connection, string procedureName,
 15        object parameters, int commandTimeout = 30);
 16
 17    Task<IEnumerable<T>> QueryStoredProcedureAsync<T>(IDbConnection connection, string procedureName,
 18        object parameters, int commandTimeout = 30);
 19}
 20
 21public class DapperWrapper : IDapperWrapper
 22{
 23    public async Task<int> ExecuteAsync(IDbConnection connection, string sql, object param = null,
 24        IDbTransaction transaction = null)
 125    {
 126        return await connection.ExecuteAsync(sql, param, transaction);
 127    }
 28
 29    public async Task<int> ExecuteStoredProcedureAsync<T>(IDbConnection connection, string procedureName,
 30        object parameters, int commandTimeout = 30)
 231    {
 32        try
 233        {
 234            return await connection.ExecuteAsync(
 235                procedureName,
 236                parameters,
 237                commandType: CommandType.StoredProcedure,
 238                commandTimeout: commandTimeout);
 39        }
 140        catch (Exception ex)
 141        {
 142            throw new Exception($"Error executing stored procedure: {procedureName}", ex);
 43        }
 144    }
 45
 46    public async Task<IEnumerable<T>> QueryStoredProcedureAsync<T>(IDbConnection connection, string procedureName,
 47        object parameters, int commandTimeout = 30)
 148    {
 49        try
 150        {
 151            return await connection.QueryAsync<T>(
 152                procedureName,
 153                parameters,
 154                commandType: CommandType.StoredProcedure,
 155                commandTimeout: commandTimeout);
 56        }
 157        catch (Exception ex)
 158        {
 159            throw new Exception($"Error executing stored procedure: {procedureName}", ex);
 60        }
 061    }
 62
 63    public async Task<IEnumerable<T>> QueryAsync<T>(IDbConnection connection, string sql, object param = null,
 64        IDbTransaction transaction = null)
 165    {
 166        return await connection.QueryAsync<T>(sql, param, transaction);
 167    }
 68}
-
-
-
- \ No newline at end of file diff --git a/source/coverage/Core_DateTimeHelper.html b/source/coverage/Core_DateTimeHelper.html deleted file mode 100644 index 7f4b186..0000000 --- a/source/coverage/Core_DateTimeHelper.html +++ /dev/null @@ -1,184 +0,0 @@ - - - - - - - -Core.Helpers.DateTimeHelper - Coverage Report - -
-

< Summary

-
-
-
Information
-
-
- - - - - - - - - - - - - -
Class:Core.Helpers.DateTimeHelper
Assembly:Core
File(s):/Users/griordan/git/gpconnect-analytics/source/Core/Helpers/DateTimeHelper.cs
-
-
-
-
-
-
-
Line coverage
-
-
100%
-
- - - - - - - - - - - - - - - - - - - - - -
Covered lines:4
Uncovered lines:0
Coverable lines:4
Total lines:11
Line coverage:100%
-
-
-
-
-
Branch coverage
-
-
100%
-
- - - - - - - - - - - - - -
Covered branches:2
Total branches:2
Branch coverage:100%
-
-
-
-
-
Method coverage
-
-
-

Feature is only available for sponsors

-Upgrade to PRO version -
-
-
-
-

Metrics

-
- ------- - - - - -
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
EachDay()100%22100%
-
-

File(s)

-

/Users/griordan/git/gpconnect-analytics/source/Core/Helpers/DateTimeHelper.cs

-
- - - - - - - - - - - - - - - -
#LineLine coverage
 1namespace Core.Helpers
 2{
 3    public static class DateTimeHelper
 4    {
 5        public static IEnumerable<DateTime> EachDay(DateTime from, DateTime to)
 46        {
 267            for (var day = from.Date; day.Date <= to.Date; day = day.AddDays(1))
 98                yield return day;
 49        }
 10    }
 11}
-
-
-
-
-

Methods/Properties

-EachDay()
-
-
- \ No newline at end of file diff --git a/source/coverage/Core_FilePathAttribute.html b/source/coverage/Core_FilePathAttribute.html deleted file mode 100644 index d4817b5..0000000 --- a/source/coverage/Core_FilePathAttribute.html +++ /dev/null @@ -1,185 +0,0 @@ - - - - - - - -Core.Helpers.FilePathAttribute - Coverage Report - -
-

< Summary

-
-
-
Information
-
-
- - - - - - - - - - - - - -
Class:Core.Helpers.FilePathAttribute
Assembly:Core
File(s):/Users/griordan/git/gpconnect-analytics/source/Core/Helpers/FilePath.cs
-
-
-
-
-
-
-
Line coverage
-
-
100%
-
- - - - - - - - - - - - - - - - - - - - - -
Covered lines:3
Uncovered lines:0
Coverable lines:3
Total lines:12
Line coverage:100%
-
-
-
-
-
Branch coverage
-
-
N/A
-
- - - - - - - - - - - - - -
Covered branches:0
Total branches:0
Branch coverage:N/A
-
-
-
-
-
Method coverage
-
-
-

Feature is only available for sponsors

-Upgrade to PRO version -
-
-
-
-

Metrics

-
- ------- - - - - -
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
-
-

File(s)

-

/Users/griordan/git/gpconnect-analytics/source/Core/Helpers/FilePath.cs

-
- - - - - - - - - - - - - - - - -
#LineLine coverage
 1namespace Core.Helpers
 2{
 3    public class FilePathAttribute : Attribute
 4    {
 5        public string FilePath { get; } = "";
 6
 167        public FilePathAttribute(string value)
 168        {
 9            FilePath = value;
 1610        }
 11    }
 12}
-
-
-
-
-

Methods/Properties

-.ctor(System.String)
-
-
- \ No newline at end of file diff --git a/source/coverage/Core_HierarchyProviderConsumerRepo.html b/source/coverage/Core_HierarchyProviderConsumerRepo.html deleted file mode 100644 index 7b9eb8d..0000000 --- a/source/coverage/Core_HierarchyProviderConsumerRepo.html +++ /dev/null @@ -1,235 +0,0 @@ - - - - - - - -Core.Repositories.HierarchyProviderConsumerRepo - Coverage Report - -
-

< Summary

-
-
-
Information
-
-
- - - - - - - - - - - - - -
Class:Core.Repositories.HierarchyProviderConsumerRepo
Assembly:Core
File(s):/Users/griordan/git/gpconnect-analytics/source/Core/Repositories/HierarchyProviderConsumerRepo.cs
-
-
-
-
-
-
-
Line coverage
-
-
0%
-
- - - - - - - - - - - - - - - - - - - - - -
Covered lines:0
Uncovered lines:17
Coverable lines:17
Total lines:62
Line coverage:0%
-
-
-
-
-
Branch coverage
-
-
0%
-
- - - - - - - - - - - - - -
Covered branches:0
Total branches:4
Branch coverage:0%
-
-
-
-
-
Method coverage
-
-
-

Feature is only available for sponsors

-Upgrade to PRO version -
-
-
-
-

Metrics

-
- ------- - - - - -
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
InsertHierarchyProviderConsumers()0%2040%
-
-

File(s)

-

/Users/griordan/git/gpconnect-analytics/source/Core/Repositories/HierarchyProviderConsumerRepo.cs

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#LineLine coverage
 1using System.Data;
 2using Core.DTOs.Request;
 3using Core.Helpers;
 4using Core.Services.Interfaces;
 5using Microsoft.Data.SqlClient;
 6
 7namespace Core.Repositories;
 8
 9public class HierarchyProviderConsumerRepo(
 10    ICoreConfigurationService configurationService,
 11    IDapperWrapper dapperWrapper,
 12    IConnectionFactory connectionFactory)
 13    : IHierarchyProviderConsumerRepo
 14{
 15    public async Task InsertHierarchyProviderConsumers(List<OrganisationHierarchyProvider> providers)
 016    {
 017        var connectionString = configurationService.GetConnectionString(ConnectionStrings.GpConnectAnalytics);
 018        await using var connection = connectionFactory.CreateConnection(connectionString);
 19
 20        // Explicitly open the connection
 021        if (connection.State != ConnectionState.Open)
 022        {
 023            await connection.OpenAsync();
 024        }
 25
 026        await using var transaction = await connection.BeginTransactionAsync();
 27
 28        const string sql = """
 29                               INSERT INTO [Data].[HierarchyProviderConsumers] (
 30                                   OdsCode,
 31                                   PracticeName,
 32                                   RegisteredPatientCount,
 33                                   RegionCode,
 34                                   RegionName,
 35                                   Icb22Name,
 36                                   PcnName,
 37                                   Appointments13000
 38                               )
 39                               VALUES (
 40                                   @OdsCode,
 41                                   @PracticeName,
 42                                   @RegisteredPatientCount,
 43                                   @RegionCode,
 44                                   @RegionName,
 45                                   @Icb22Name,
 46                                   @PcnName,
 47                                   @Appointments13000
 48                               );
 49                           """;
 50
 51        try
 052        {
 053            await dapperWrapper.ExecuteAsync(connection, sql, providers, transaction);
 054            await transaction.CommitAsync();
 055        }
 056        catch
 057        {
 058            await transaction.RollbackAsync();
 059            throw;
 60        }
 061    }
 62}
-
-
-
-
-

Methods/Properties

-InsertHierarchyProviderConsumers()
-
-
- \ No newline at end of file diff --git a/source/coverage/Core_OrganisationHierarchyProvider.html b/source/coverage/Core_OrganisationHierarchyProvider.html deleted file mode 100644 index 323010e..0000000 --- a/source/coverage/Core_OrganisationHierarchyProvider.html +++ /dev/null @@ -1,192 +0,0 @@ - - - - - - - -Core.DTOs.Request.OrganisationHierarchyProvider - Coverage Report - -
-

< Summary

-
-
-
Information
-
-
- - - - - - - - - - - - - -
Class:Core.DTOs.Request.OrganisationHierarchyProvider
Assembly:Core
File(s):/Users/griordan/git/gpconnect-analytics/source/Core/DTOs/Request/OrganisationHeirarchyProvider.cs
-
-
-
-
-
-
-
Line coverage
-
-
100%
-
- - - - - - - - - - - - - - - - - - - - - -
Covered lines:2
Uncovered lines:0
Coverable lines:2
Total lines:19
Line coverage:100%
-
-
-
-
-
Branch coverage
-
-
N/A
-
- - - - - - - - - - - - - -
Covered branches:0
Total branches:0
Branch coverage:N/A
-
-
-
-
-
Method coverage
-
-
-

Feature is only available for sponsors

-Upgrade to PRO version -
-
-
-
-

Metrics

-
- ------- - - - - -
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor()100%11100%
-
-

File(s)

-

/Users/griordan/git/gpconnect-analytics/source/Core/DTOs/Request/OrganisationHeirarchyProvider.cs

-
- - - - - - - - - - - - - - - - - - - - - - - -
#LineLine coverage
 1#nullable enable
 2namespace Core.DTOs.Request
 3{
 4    public class OrganisationHierarchyProvider
 5    {
 6        public required string OdsCode { get; set; }
 7        public string? PracticeName { get; set; }
 8        public int RegisteredPatientCount { get; set; }
 9        public string? RegionCode { get; set; }
 10        public string? RegionName { get; set; }
 11        public string? Icb22Name { get; set; }
 12        public string? PcnName { get; set; }
 13        public int Appointments13000 { get; set; }
 14
 15        public OrganisationHierarchyProvider()
 316        {
 317        }
 18    }
 19}
-
-
-
-
-

Methods/Properties

-.ctor()
-
-
- \ No newline at end of file diff --git a/source/coverage/Core_SplunkInstanceMap.html b/source/coverage/Core_SplunkInstanceMap.html deleted file mode 100644 index 1799c42..0000000 --- a/source/coverage/Core_SplunkInstanceMap.html +++ /dev/null @@ -1,187 +0,0 @@ - - - - - - - -Core.Mapping.SplunkInstanceMap - Coverage Report - -
-

< Summary

-
-
-
Information
-
-
- - - - - - - - - - - - - -
Class:Core.Mapping.SplunkInstanceMap
Assembly:Core
File(s):/Users/griordan/git/gpconnect-analytics/source/Core/Mapping/SplunkInstanceMap.cs
-
-
-
-
-
-
-
Line coverage
-
-
0%
-
- - - - - - - - - - - - - - - - - - - - - -
Covered lines:0
Uncovered lines:5
Coverable lines:5
Total lines:14
Line coverage:0%
-
-
-
-
-
Branch coverage
-
-
N/A
-
- - - - - - - - - - - - - -
Covered branches:0
Total branches:0
Branch coverage:N/A
-
-
-
-
-
Method coverage
-
-
-

Feature is only available for sponsors

-Upgrade to PRO version -
-
-
-
-

Metrics

-
- ------- - - - - -
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor()100%210%
-
-

File(s)

-

/Users/griordan/git/gpconnect-analytics/source/Core/Mapping/SplunkInstanceMap.cs

-
- - - - - - - - - - - - - - - - - - -
#LineLine coverage
 1using Core.DTOs.Response.Configuration;
 2using Dapper.FluentMap.Mapping;
 3
 4namespace Core.Mapping
 5{
 6    public class SplunkInstanceMap : EntityMap<SplunkInstance>
 7    {
 08        public SplunkInstanceMap()
 09        {
 010            Map(p => p.Source).ToColumn("SplunkInstance");
 011            Map(p => p.SourceGroup).ToColumn("SplunkInstanceGroup");
 012        }
 13    }
 14}
-
-
-
-
-

Methods/Properties

-.ctor()
-
-
- \ No newline at end of file diff --git a/source/coverage/Core_TimeProvider.html b/source/coverage/Core_TimeProvider.html deleted file mode 100644 index 9187520..0000000 --- a/source/coverage/Core_TimeProvider.html +++ /dev/null @@ -1,187 +0,0 @@ - - - - - - - -TimeProvider - Coverage Report - -
-

< Summary

-
-
-
Information
-
-
- - - - - - - - - - - - - -
Class:TimeProvider
Assembly:Core
File(s):/Users/griordan/git/gpconnect-analytics/source/Core/Helpers/TimeProvider.cs
-
-
-
-
-
-
-
Line coverage
-
-
0%
-
- - - - - - - - - - - - - - - - - - - - - -
Covered lines:0
Uncovered lines:2
Coverable lines:2
Total lines:12
Line coverage:0%
-
-
-
-
-
Branch coverage
-
-
N/A
-
- - - - - - - - - - - - - -
Covered branches:0
Total branches:0
Branch coverage:N/A
-
-
-
-
-
Method coverage
-
-
-

Feature is only available for sponsors

-Upgrade to PRO version -
-
-
-
-

Metrics

-
- ------- - - - - - -
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
UtcDateTime()100%210%
CurrentDate()100%210%
-
-

File(s)

-

/Users/griordan/git/gpconnect-analytics/source/Core/Helpers/TimeProvider.cs

-
- - - - - - - - - - - - - - - - -
#LineLine coverage
 1using Core;
 2
 3public class TimeProvider : ITimeProvider
 4{
 05    public DateTime UtcDateTime() => DateTime.UtcNow;
 6
 7    /// <summary>
 8    /// Gets current Date, time is set at 00:00
 9    /// </summary>
 10    /// <returns>current DateTime</returns>
 011    public DateTime CurrentDate() => DateTime.Today;
 12}
-
-
-
-
-

Methods/Properties

-UtcDateTime()
-CurrentDate()
-
-
- \ No newline at end of file diff --git a/source/coverage/Functions_BatchService.html b/source/coverage/Functions_BatchService.html deleted file mode 100644 index 5fd4098..0000000 --- a/source/coverage/Functions_BatchService.html +++ /dev/null @@ -1,327 +0,0 @@ - - - - - - - -Functions.Services.BatchService - Coverage Report - -
-

< Summary

-
-
-
Information
-
-
- - - - - - - - - - - - - -
Class:Functions.Services.BatchService
Assembly:Functions
File(s):/Users/griordan/git/gpconnect-analytics/source/Functions/Services/BatchService.cs
-
-
-
-
-
-
-
Line coverage
-
-
92%
-
- - - - - - - - - - - - - - - - - - - - - -
Covered lines:86
Uncovered lines:7
Coverable lines:93
Total lines:146
Line coverage:92.4%
-
-
-
-
-
Branch coverage
-
-
77%
-
- - - - - - - - - - - - - -
Covered branches:14
Total branches:18
Branch coverage:77.7%
-
-
-
-
-
Method coverage
-
-
-

Feature is only available for sponsors

-Upgrade to PRO version -
-
-
-
-

Metrics

-
- ------- - - - - - - - - -
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
StartBatchDownloadForTodayAsync()100%11100%
StartBatchDownloadAsync()60%121074.07%
ProcessUrls()100%44100%
GetBatchDownloadUriList()100%44100%
RemovePreviousDownloads()100%11100%
-
-

File(s)

-

/Users/griordan/git/gpconnect-analytics/source/Functions/Services/BatchService.cs

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#LineLine coverage
 1using System.Web;
 2using Core.DTOs.Request;
 3using Core.DTOs.Response.Configuration;
 4using Core.Helpers;
 5using Core.Services.Interfaces;
 6using Dapper;
 7using Functions.Services.Interfaces;
 8using Microsoft.Extensions.Logging;
 9
 10namespace Functions.Services
 11{
 12    public class BatchService(
 13        IConfigurationService configurationService,
 14        ISplunkService splunkService,
 15        ILogger<BatchService> logger,
 16        IDataService dataService)
 17        : IBatchService
 18    {
 19        private SplunkClient _splunkClient;
 20
 21        public async Task<int> StartBatchDownloadForTodayAsync(FileTypes fileTypes)
 222        {
 223            var dateInScope = DateTime.Today.AddDays(1);
 224            var fileType = await configurationService.GetFileType(fileTypes);
 225            var uriList =
 226                await GetBatchDownloadUriList(fileType, DateTimeHelper.EachDay(dateInScope, dateInScope).ToList());
 27
 228            await RemovePreviousDownloads(fileType, dateInScope, dateInScope);
 29
 230            await ProcessUrls(fileType, uriList, true);
 231            return uriList.Count;
 232        }
 33
 34        public async Task<int> StartBatchDownloadAsync(FileTypes fileTypes, string? startDate, string? endDate)
 335        {
 336            if (string.IsNullOrWhiteSpace(startDate) || string.IsNullOrWhiteSpace(endDate))
 037            {
 038                logger.LogError("Start and end dates are required for batch download");
 039                throw new ArgumentException("Start and end dates are required for batch download");
 40            }
 41
 342            var start = DateTime.TryParse(startDate, out DateTime parsedStart)
 343                ? parsedStart
 344                : DateTime.Today;
 345            var end = DateTime.TryParse(endDate, out DateTime parsedEnd)
 346                ? parsedEnd
 347                : DateTime.Today;
 48
 349            if (parsedEnd >= parsedStart)
 250            {
 251                var fileType = await configurationService.GetFileType(fileTypes);
 252                var uriList =
 253                    await GetBatchDownloadUriList(fileType, DateTimeHelper.EachDay(start, end).ToList());
 54
 255                await RemovePreviousDownloads(fileType, start, end);
 56
 57                try
 258                {
 259                    await ProcessUrls(fileType, uriList, false);
 260                    return uriList.Count;
 61                }
 062                catch (Exception ex)
 063                {
 064                    logger.LogError(ex, "An error occurred during batch download when processing urls");
 065                    throw;
 66                }
 67            }
 68
 169            logger.LogError("Start date cannot be later than end date");
 170            throw new ArgumentException("Start date cannot be later than end date");
 271        }
 72
 73        private async Task ProcessUrls(FileType fileType, List<UriRequest> uriList, bool isToday)
 474        {
 475            var downloadTasks = new List<Task>();
 76
 77            // Create and start all download tasks
 44078            for (var i = 0; i < uriList.Count; i++)
 21679            {
 21680                var requestUri = uriList[i];
 21681                downloadTasks.Add(splunkService.ExecuteBatchDownloadFromSplunk(fileType, requestUri, isToday));
 21682            }
 83
 84            // Wait for tasks to complete
 22085            while (downloadTasks.Count > 0)
 21686            {
 21687                var finishedTask = await Task.WhenAny(downloadTasks);
 21688                downloadTasks.Remove(finishedTask);
 21689            }
 490        }
 91
 92        public async Task<List<UriRequest>> GetBatchDownloadUriList(FileType fileType, List<DateTime> dateTimeList)
 593        {
 594            var uriList = new List<UriRequest>();
 595            _splunkClient = await configurationService.GetSplunkClientConfiguration();
 96
 3997            foreach (var dateTime in dateTimeList)
 1298            {
 1299                var earliestDate = dateTime.AddDays(-2);
 12100                var latestDate = dateTime.AddDays(-1);
 101
 600102                for (var i = 0; i < 24; i++)
 288103                {
 288104                    var splunkQuery = fileType.SplunkQuery;
 288105                    var hour = TimeSpan.Zero.Add(TimeSpan.FromHours(i));
 106
 288107                    splunkQuery = splunkQuery.Replace("{earliest}",
 288108                        earliestDate.ToString(DateFormatConstants.SplunkQueryDate));
 288109                    splunkQuery = splunkQuery.Replace("{latest}",
 288110                        latestDate.ToString(DateFormatConstants.SplunkQueryDate));
 288111                    splunkQuery = splunkQuery.Replace("{hour}",
 288112                        hour.ToString(DateFormatConstants.SplunkQueryHour));
 113
 288114                    var uriBuilder = new UriBuilder
 288115                    {
 288116                        Scheme = Uri.UriSchemeHttps,
 288117                        Host = _splunkClient.HostName,
 288118                        Port = _splunkClient.HostPort,
 288119                        Path = _splunkClient.BaseUrl,
 288120                        Query = string.Format(_splunkClient.QueryParameters, HttpUtility.UrlEncode(splunkQuery))
 288121                    };
 122
 288123                    uriList.Add(new UriRequest()
 288124                    {
 288125                        Request = uriBuilder.Uri,
 288126                        EarliestDate = earliestDate,
 288127                        LatestDate = latestDate,
 288128                        Hour = hour
 288129                    });
 288130                }
 12131            }
 132
 5133            return uriList;
 5134        }
 135
 136        public async Task RemovePreviousDownloads(FileType fileType, DateTime startDate, DateTime endDate)
 5137        {
 5138            var procedureName = "Import.RemovePreviousDownload";
 5139            var parameters = new DynamicParameters();
 5140            parameters.Add("@FileTypeId", fileType.FileTypeId);
 5141            parameters.Add("@StartDate", startDate.AddDays(-2));
 5142            parameters.Add("@EndDate", endDate.AddDays(-1));
 5143            await dataService.ExecuteStoredProcedure(procedureName, parameters);
 5144        }
 145    }
 146}
-
-
-
- \ No newline at end of file diff --git a/source/coverage/Functions_BlobService.html b/source/coverage/Functions_BlobService.html deleted file mode 100644 index 5878523..0000000 --- a/source/coverage/Functions_BlobService.html +++ /dev/null @@ -1,270 +0,0 @@ - - - - - - - -Functions.Services.BlobService - Coverage Report - -
-

< Summary

-
-
-
Information
-
-
- - - - - - - - - - - - - -
Class:Functions.Services.BlobService
Assembly:Functions
File(s):/Users/griordan/git/gpconnect-analytics/source/Functions/Services/BlobService.cs
-
-
-
-
-
-
-
Line coverage
-
-
84%
-
- - - - - - - - - - - - - - - - - - - - - -
Covered lines:42
Uncovered lines:8
Coverable lines:50
Total lines:93
Line coverage:84%
-
-
-
-
-
Branch coverage
-
-
75%
-
- - - - - - - - - - - - - -
Covered branches:6
Total branches:8
Branch coverage:75%
-
-
-
-
-
Method coverage
-
-
-

Feature is only available for sponsors

-Upgrade to PRO version -
-
-
-
-

Metrics

-
- ------- - - - - - - -
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)50%22100%
AddObjectToBlob()100%2278.94%
AddMessageToBlobQueue()75%4483.33%
-
-

File(s)

-

/Users/griordan/git/gpconnect-analytics/source/Functions/Services/BlobService.cs

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#LineLine coverage
 1using System.Text;
 2using System.Text.Json;
 3using Azure;
 4using Azure.Storage.Blobs;
 5using Azure.Storage.Blobs.Models;
 6using Azure.Storage.Queues;
 7using Core.DTOs.Response.Configuration;
 8using Core.DTOs.Response.Queue;
 9using Core.DTOs.Response.Splunk;
 10using Core.Services.Interfaces;
 11using Functions.Services.Interfaces;
 12using Microsoft.Extensions.Logging;
 13
 14namespace Functions.Services
 15{
 16    public class BlobService : IBlobService
 17    {
 18        private readonly ILogger<BlobService> _logger;
 19        private readonly BlobStorage _blobStorageConfiguration;
 20        private readonly QueueClient _queueClient;
 21        private readonly BlobServiceClient _blobServiceClient;
 22
 23        public BlobService(IConfigurationService configurationService, ILogger<BlobService> logger,
 24            QueueClient? queueClient)
 625        {
 626            _logger = logger;
 627            _blobStorageConfiguration = configurationService.GetBlobStorageConfiguration().Result;
 628            _blobServiceClient = new BlobServiceClient(_blobStorageConfiguration.ConnectionString);
 629            _queueClient = queueClient ?? new QueueClient(_blobStorageConfiguration.ConnectionString,
 630                _blobStorageConfiguration.QueueName);
 631        }
 32
 33        public async Task<BlobContentInfo?> AddObjectToBlob(ExtractResponse extractResponse)
 334        {
 335            _logger.LogInformation($"Adding object to blob storage", extractResponse);
 36
 37            try
 338            {
 339                var containerClient =
 340                    _blobServiceClient.GetBlobContainerClient(_blobStorageConfiguration.ContainerName);
 41
 442                if (!await containerClient.ExistsAsync()) return null;
 43
 144                var blobClient = containerClient.GetBlobClient(extractResponse.FilePath);
 145                var response =
 146                    await blobClient.UploadAsync(extractResponse.ExtractResponseStream, overwrite: true);
 47
 148                return response;
 49            }
 150            catch (RequestFailedException requestFailedException)
 151            {
 152                _logger.LogError(requestFailedException, "The container does not exist");
 153                throw;
 54            }
 055            catch (Exception exc)
 056            {
 057                _logger.LogError(exc, "An error occurred while trying to add a blob to the storage");
 058                throw;
 59            }
 260        }
 61
 62        public async Task AddMessageToBlobQueue(int fileAddedCount, int fileTypeId, string blobName,
 63            bool overrideEntry = false)
 364        {
 65            try
 366            {
 367                if ((await _queueClient.ExistsAsync()) && fileAddedCount == 1)
 168                {
 169                    var message = new Message
 170                    {
 171                        FileTypeId = fileTypeId,
 172                        BlobName = blobName,
 173                        Override = overrideEntry
 174                    };
 75
 176                    var messageText = JsonSerializer.Serialize(message);
 177                    _logger.LogInformation($"Adding message to blob queue", message);
 178                    await _queueClient.SendMessageAsync(Convert.ToBase64String(Encoding.UTF8.GetBytes(messageText)));
 179                }
 280            }
 181            catch (RequestFailedException requestFailedException)
 182            {
 183                _logger.LogError(requestFailedException, "The queue does not exist");
 184                throw;
 85            }
 086            catch (Exception exc)
 087            {
 088                _logger.LogError(exc, "An error occurred while trying to add a message to the queue");
 089                throw;
 90            }
 291        }
 92    }
 93}
-
-
-
- \ No newline at end of file diff --git a/source/coverage/Functions_ConfigurationService.html b/source/coverage/Functions_ConfigurationService.html deleted file mode 100644 index 17b4c71..0000000 --- a/source/coverage/Functions_ConfigurationService.html +++ /dev/null @@ -1,244 +0,0 @@ - - - - - - - -Functions.Services.ConfigurationService - Coverage Report - -
-

< Summary

-
-
-
Information
-
-
- - - - - - - - - - - - - -
Class:Functions.Services.ConfigurationService
Assembly:Functions
File(s):/Users/griordan/git/gpconnect-analytics/source/Functions/Services/ConfigurationService.cs
-
-
-
-
-
-
-
Line coverage
-
-
88%
-
- - - - - - - - - - - - - - - - - - - - - -
Covered lines:32
Uncovered lines:4
Coverable lines:36
Total lines:61
Line coverage:88.8%
-
-
-
-
-
Branch coverage
-
-
N/A
-
- - - - - - - - - - - - - -
Covered branches:0
Total branches:0
Branch coverage:N/A
-
-
-
-
-
Method coverage
-
-
-

Feature is only available for sponsors

-Upgrade to PRO version -
-
-
-
-

Metrics

-
- ------- - - - - - - - - - -
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
GetBlobStorageConfiguration()100%11100%
GetFilePathConstants()100%11100%
GetFileTypes()100%11100%
GetFileType()100%210%
GetSplunkClientConfiguration()100%11100%
GetSplunkInstance()100%11100%
-
-

File(s)

-

/Users/griordan/git/gpconnect-analytics/source/Functions/Services/ConfigurationService.cs

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#LineLine coverage
 1using Core.DTOs.Response.Configuration;
 2using Core.Helpers;
 3using Core.Services.Interfaces;
 4using Microsoft.Extensions.Logging;
 5
 6namespace Functions.Services
 7{
 8    public class ConfigurationService(
 9        IDataService dataService,
 10        ILogger<ConfigurationService> logger)
 11        : IConfigurationService
 12    {
 13        public async Task<BlobStorage> GetBlobStorageConfiguration()
 214        {
 215            var result =
 216                await dataService.ExecuteQueryStoredProcedure<BlobStorage>(
 217                    "[Configuration].[GetBlobStorageConfiguration]");
 218            logger.LogInformation("Loading blob storage configuration", result.FirstOrDefault());
 219            return result.FirstOrDefault();
 220        }
 21
 22        public async Task<FilePathConstants> GetFilePathConstants()
 223        {
 224            var result =
 225                await dataService.ExecuteQueryStoredProcedure<FilePathConstants>(
 226                    "[Configuration].[GetFilePathConstants]");
 227            logger.LogInformation("Loading file path constants", result.FirstOrDefault());
 228            return result.FirstOrDefault();
 229        }
 30
 31        public async Task<List<FileType>> GetFileTypes()
 232        {
 233            var result = await dataService.ExecuteQueryStoredProcedure<FileType>("[Configuration].[GetFileTypes]");
 234            logger.LogInformation("Loading file types", result);
 235            return result;
 236        }
 37
 38        public async Task<FileType> GetFileType(FileTypes fileTypes)
 039        {
 040            var result = await dataService.ExecuteQueryStoredProcedure<FileType>("[Configuration].[GetFileTypes]");
 041            return result.FirstOrDefault(ft => ft.FileTypeFilePrefix == fileTypes.ToString());
 042        }
 43
 44        public async Task<SplunkClient> GetSplunkClientConfiguration()
 145        {
 146            var result =
 147                await dataService.ExecuteQueryStoredProcedure<SplunkClient>(
 148                    "[Configuration].[GetSplunkClientConfiguration]");
 149            logger.LogInformation("Loading splunk client configuration", result.FirstOrDefault());
 150            return result.FirstOrDefault();
 151        }
 52
 53        public async Task<SplunkInstance> GetSplunkInstance(SplunkInstances splunkInstance)
 154        {
 155            var result =
 156                await dataService.ExecuteQueryStoredProcedure<SplunkInstance>("[Configuration].[GetSplunkInstances]");
 157            logger.LogInformation("Loading splunk instance", result);
 258            return result.FirstOrDefault(x => x.Source == splunkInstance.ToString());
 159        }
 60    }
 61}
-
-
-
- \ No newline at end of file diff --git a/source/coverage/Functions_CoreConfigurationService.html b/source/coverage/Functions_CoreConfigurationService.html deleted file mode 100644 index 9609a3d..0000000 --- a/source/coverage/Functions_CoreConfigurationService.html +++ /dev/null @@ -1,187 +0,0 @@ - - - - - - - -Functions.Services.CoreConfigurationService - Coverage Report - -
-

< Summary

-
-
-
Information
-
-
- - - - - - - - - - - - - -
Class:Functions.Services.CoreConfigurationService
Assembly:Functions
File(s):/Users/griordan/git/gpconnect-analytics/source/Functions/Services/CoreConfigurationService.cs
-
-
-
-
-
-
-
Line coverage
-
-
100%
-
- - - - - - - - - - - - - - - - - - - - - -
Covered lines:4
Uncovered lines:0
Coverable lines:4
Total lines:14
Line coverage:100%
-
-
-
-
-
Branch coverage
-
-
100%
-
- - - - - - - - - - - - - -
Covered branches:2
Total branches:2
Branch coverage:100%
-
-
-
-
-
Method coverage
-
-
-

Feature is only available for sponsors

-Upgrade to PRO version -
-
-
-
-

Metrics

-
- ------- - - - - -
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
GetConnectionString(...)100%22100%
-
-

File(s)

-

/Users/griordan/git/gpconnect-analytics/source/Functions/Services/CoreConfigurationService.cs

-
- - - - - - - - - - - - - - - - - - -
#LineLine coverage
 1using Core.Services.Interfaces;
 2using Microsoft.Extensions.Configuration;
 3
 4namespace Functions.Services
 5{
 6    public class CoreConfigurationService(IConfiguration configuration) : ICoreConfigurationService
 7    {
 8        public string GetConnectionString(string name)
 29        {
 210            var connectionString = configuration.GetConnectionString(name);
 211            return connectionString ?? throw new ArgumentException("No connection string with given name");
 112        }
 13    }
 14}
-
-
-
-
-

Methods/Properties

-GetConnectionString(System.String)
-
-
- \ No newline at end of file diff --git a/source/coverage/Functions_DataService.html b/source/coverage/Functions_DataService.html deleted file mode 100644 index 3e64d4b..0000000 --- a/source/coverage/Functions_DataService.html +++ /dev/null @@ -1,296 +0,0 @@ - - - - - - - -Functions.Services.DataService - Coverage Report - -
-

< Summary

-
-
-
Information
-
-
- - - - - - - - - - - - - -
Class:Functions.Services.DataService
Assembly:Functions
File(s):/Users/griordan/git/gpconnect-analytics/source/Functions/Services/DataService.cs
-
-
-
-
-
-
-
Line coverage
-
-
3%
-
- - - - - - - - - - - - - - - - - - - - - -
Covered lines:2
Uncovered lines:64
Coverable lines:66
Total lines:113
Line coverage:3%
-
-
-
-
-
Branch coverage
-
-
0%
-
- - - - - - - - - - - - - -
Covered branches:0
Total branches:16
Branch coverage:0%
-
-
-
-
-
Method coverage
-
-
-

Feature is only available for sponsors

-Upgrade to PRO version -
-
-
-
-

Metrics

-
- ------- - - - - - - - - - -
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
ExecuteRawUpsertSqlAsync()100%210%
ExecuteQueryStoredProcedure()0%4260%
ExecuteStoredProcedureWithOutputParameters()0%2040%
ExecuteStoredProcedure()0%2040%
SqlConnection_InfoMessage(...)0%620%
-
-

File(s)

-

/Users/griordan/git/gpconnect-analytics/source/Functions/Services/DataService.cs

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#LineLine coverage
 1using Core;
 2using Core.Helpers;
 3using Core.Repositories;
 4using Core.Services.Interfaces;
 5using Dapper;
 6using Microsoft.Data.SqlClient;
 7using Microsoft.Extensions.Logging;
 8
 9namespace Functions.Services
 10{
 11    public class DataService(
 12        ILogger<DataService> logger,
 13        ICoreConfigurationService coreConfigurationService,
 14        IDapperWrapper dapper,
 15        IConnectionFactory connectionFactory)
 16        : IDataService
 17    {
 618        private readonly string _connectionString =
 619            coreConfigurationService.GetConnectionString(ConnectionStrings.GpConnectAnalytics);
 20
 21        public async Task<int> ExecuteRawUpsertSqlAsync(string sqlCommand, object parameters)
 022        {
 23            try
 024            {
 025                await using var sqlConnection = connectionFactory.CreateConnection(_connectionString);
 026                await sqlConnection.OpenAsync();
 027                logger.LogInformation($"Executing raw SQL command");
 028                var rowsAffected = await dapper.ExecuteAsync(sqlConnection, sqlCommand, parameters);
 029                return rowsAffected;
 030            }
 031            catch (Exception ex)
 032            {
 033                logger.LogError(ex, $"An error has occurred while executing the raw SQL command: {sqlCommand}");
 034                throw;
 35            }
 036        }
 37
 38        public async Task<List<T>> ExecuteQueryStoredProcedure<T>(string procedureName, DynamicParameters parameters)
 39            where T : class
 040        {
 041            await using var sqlConnection = connectionFactory.CreateConnection(_connectionString);
 42            try
 043            {
 044                if (sqlConnection is SqlConnection connection)
 045                {
 046                    connection.InfoMessage += SqlConnection_InfoMessage;
 047                }
 48
 049                logger.LogInformation($"Executing stored procedure {procedureName}", parameters);
 50
 051                var results = await dapper.QueryStoredProcedureAsync<T>(sqlConnection, procedureName, parameters, 0);
 052                return results.AsList();
 53            }
 054            catch (Exception exc)
 055            {
 056                logger.LogError(exc, $"An error has occurred while attempting to execute the function {procedureName}");
 057                throw;
 58            }
 059        }
 60
 61
 62        public async Task<DynamicParameters> ExecuteStoredProcedureWithOutputParameters(string procedureName,
 63            DynamicParameters parameters)
 064        {
 065            await using var sqlConnection = connectionFactory.CreateConnection(_connectionString);
 66            try
 067            {
 068                if (sqlConnection is SqlConnection connection)
 069                {
 070                    connection.InfoMessage += SqlConnection_InfoMessage;
 071                }
 72
 073                logger.LogInformation($"Executing stored procedure {procedureName}", parameters);
 074                await dapper.ExecuteStoredProcedureAsync<DynamicParameters>(sqlConnection, procedureName, parameters,
 075                    0);
 076                return parameters;
 77            }
 078            catch (Exception exc)
 079            {
 080                logger?.LogError(exc,
 081                    $"An error has occurred while attempting to execute the function {procedureName}");
 082                throw;
 83            }
 084        }
 85
 86        public async Task<int> ExecuteStoredProcedure(string procedureName, DynamicParameters parameters)
 087        {
 088            await using var sqlConnection = connectionFactory.CreateConnection(_connectionString);
 89            try
 090            {
 091                if (sqlConnection is SqlConnection connection)
 092                {
 093                    connection.InfoMessage += SqlConnection_InfoMessage;
 094                }
 95
 096                logger.LogInformation($"Executing stored procedure {procedureName}", parameters);
 097                var result = await dapper.ExecuteAsync(sqlConnection, procedureName, parameters);
 098                return result;
 99            }
 0100            catch (Exception exc)
 0101            {
 0102                logger?.LogError(exc,
 0103                    $"An error has occurred while attempting to execute the function {procedureName}");
 0104                throw;
 105            }
 0106        }
 107
 108        private void SqlConnection_InfoMessage(object sender, SqlInfoMessageEventArgs e)
 0109        {
 0110            logger?.LogInformation(e.Message);
 0111        }
 112    }
 113}
-
-
-
- \ No newline at end of file diff --git a/source/coverage/Functions_DirectFunctionExecutor.html b/source/coverage/Functions_DirectFunctionExecutor.html deleted file mode 100644 index b2e9ba1..0000000 --- a/source/coverage/Functions_DirectFunctionExecutor.html +++ /dev/null @@ -1,169 +0,0 @@ - - - - - - - -Functions.DirectFunctionExecutor - Coverage Report - -
-

< Summary

- -
-
-
Line coverage
-
-
0%
-
- - - - - - - - - - - - - - - - - - - - - -
Covered lines:0
Uncovered lines:96
Coverable lines:96
Total lines:132
Line coverage:0%
-
-
-
-
-
Branch coverage
-
-
0%
-
- - - - - - - - - - - - - -
Covered branches:0
Total branches:28
Branch coverage:0%
-
-
-
-
-
Method coverage
-
-
-

Feature is only available for sponsors

-Upgrade to PRO version -
-
-
-
-

Metrics

-
- ------- - - - - - -
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)0%620%
ExecuteAsync()0%702260%
-
-

File(s)

-

/Users/griordan/git/gpconnect-analytics/source/Functions/Microsoft.Azure.Functions.Worker.Sdk.Generators/Microsoft.Azure.Functions.Worker.Sdk.Generators.FunctionExecutorGenerator/GeneratedFunctionExecutor.g.cs

-

File '/Users/griordan/git/gpconnect-analytics/source/Functions/Microsoft.Azure.Functions.Worker.Sdk.Generators/Microsoft.Azure.Functions.Worker.Sdk.Generators.FunctionExecutorGenerator/GeneratedFunctionExecutor.g.cs' does not exist (any more).

-
-
- \ No newline at end of file diff --git a/source/coverage/Functions_EmailConfigurationProvider.html b/source/coverage/Functions_EmailConfigurationProvider.html deleted file mode 100644 index 91845a9..0000000 --- a/source/coverage/Functions_EmailConfigurationProvider.html +++ /dev/null @@ -1,202 +0,0 @@ - - - - - - - -Functions.Configuration.EmailConfigurationProvider - Coverage Report - -
-

< Summary

-
-
-
Information
-
-
- - - - - - - - - - - - - -
Class:Functions.Configuration.EmailConfigurationProvider
Assembly:Functions
File(s):/Users/griordan/git/gpconnect-analytics/source/Functions/Configuration/EmailConfigurationProvider.cs
-
-
-
-
-
-
-
Line coverage
-
-
0%
-
- - - - - - - - - - - - - - - - - - - - - -
Covered lines:0
Uncovered lines:8
Coverable lines:8
Total lines:29
Line coverage:0%
-
-
-
-
-
Branch coverage
-
-
0%
-
- - - - - - - - - - - - - -
Covered branches:0
Total branches:2
Branch coverage:0%
-
-
-
-
-
Method coverage
-
-
-

Feature is only available for sponsors

-Upgrade to PRO version -
-
-
-
-

Metrics

-
- ------- - - - - -
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
GetEmailConfiguration(...)0%620%
-
-

File(s)

-

/Users/griordan/git/gpconnect-analytics/source/Functions/Configuration/EmailConfigurationProvider.cs

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#LineLine coverage
 1using System.Data;
 2using Core;
 3using Core.DTOs.Response.Configuration;
 4using Core.Helpers;
 5using Dapper;
 6using Microsoft.Extensions.Configuration;
 7
 8namespace Functions.Configuration;
 9
 10public interface IEmailConfigurationProvider
 11{
 12    Email? GetEmailConfiguration(IConfiguration configuration);
 13}
 14
 15public class EmailConfigurationProvider(IConnectionFactory connectionFactory) : IEmailConfigurationProvider
 16{
 17    public Email? GetEmailConfiguration(IConfiguration configuration)
 018    {
 019        var connectionString = configuration.GetConnectionString(ConnectionStrings.GpConnectAnalytics) ??
 020                               throw new InvalidOperationException("connection string cannot be null at this point.");
 21
 022        using var sqlConnection = connectionFactory.CreateConnection(connectionString);
 23
 024        IEnumerable<Email?> result = sqlConnection.Query<Email>("[Configuration].[GetEmailConfiguration]",
 025            commandType: CommandType.StoredProcedure);
 26
 027        return result.FirstOrDefault();
 028    }
 29}
-
-
-
- \ No newline at end of file diff --git a/source/coverage/Functions_ExecuteImportByTrigger.html b/source/coverage/Functions_ExecuteImportByTrigger.html deleted file mode 100644 index 6476c6f..0000000 --- a/source/coverage/Functions_ExecuteImportByTrigger.html +++ /dev/null @@ -1,189 +0,0 @@ - - - - - - - -Functions.ExecuteImportByTrigger - Coverage Report - -
-

< Summary

-
-
-
Information
-
-
- - - - - - - - - - - - - -
Class:Functions.ExecuteImportByTrigger
Assembly:Functions
File(s):/Users/griordan/git/gpconnect-analytics/source/Functions/ExecuteImportByTrigger.cs
-
-
-
-
-
-
-
Line coverage
-
-
100%
-
- - - - - - - - - - - - - - - - - - - - - -
Covered lines:3
Uncovered lines:0
Coverable lines:3
Total lines:16
Line coverage:100%
-
-
-
-
-
Branch coverage
-
-
N/A
-
- - - - - - - - - - - - - -
Covered branches:0
Total branches:0
Branch coverage:N/A
-
-
-
-
-
Method coverage
-
-
-

Feature is only available for sponsors

-Upgrade to PRO version -
-
-
-
-

Metrics

-
- ------- - - - - -
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
Run()100%11100%
-
-

File(s)

-

/Users/griordan/git/gpconnect-analytics/source/Functions/ExecuteImportByTrigger.cs

-
- - - - - - - - - - - - - - - - - - - - -
#LineLine coverage
 1using Core.DTOs.Response.Queue;
 2using Functions.Services.Interfaces;
 3using Microsoft.Azure.Functions.Worker;
 4using Microsoft.Extensions.Logging;
 5
 6namespace Functions
 7{
 8    public class ExecuteImportByTrigger(IImportService importService)
 9    {
 10        [Function("ExecuteImportByTrigger")]
 11        public async Task Run([QueueTrigger("%QueueName%")] Message queueItem, ILogger log)
 212        {
 213            await importService.InstallData(queueItem);
 214        }
 15    }
 16}
-
-
-
-
-

Methods/Properties

-Run()
-
-
- \ No newline at end of file diff --git a/source/coverage/Functions_FileService.html b/source/coverage/Functions_FileService.html deleted file mode 100644 index 3f1e038..0000000 --- a/source/coverage/Functions_FileService.html +++ /dev/null @@ -1,192 +0,0 @@ - - - - - - - -Functions.Services.FileService - Coverage Report - -
-

< Summary

-
-
-
Information
-
-
- - - - - - - - - - - - - -
Class:Functions.Services.FileService
Assembly:Functions
File(s):/Users/griordan/git/gpconnect-analytics/source/Functions/Services/FileService.cs
-
-
-
-
-
-
-
Line coverage
-
-
100%
-
- - - - - - - - - - - - - - - - - - - - - -
Covered lines:8
Uncovered lines:0
Coverable lines:8
Total lines:19
Line coverage:100%
-
-
-
-
-
Branch coverage
-
-
N/A
-
- - - - - - - - - - - - - -
Covered branches:0
Total branches:0
Branch coverage:N/A
-
-
-
-
-
Method coverage
-
-
-

Feature is only available for sponsors

-Upgrade to PRO version -
-
-
-
-

Metrics

-
- ------- - - - - -
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
ApiReaderAddFile()100%11100%
-
-

File(s)

-

/Users/griordan/git/gpconnect-analytics/source/Functions/Services/FileService.cs

-
- - - - - - - - - - - - - - - - - - - - - - - -
#LineLine coverage
 1using Core.Services.Interfaces;
 2using Dapper;
 3using Functions.Services.Interfaces;
 4
 5namespace Functions.Services;
 6
 7public class FileService(IDataService dataService) : IFileService
 8{
 9    public async Task<int> ApiReaderAddFile(int fileTypeId, string filePath, bool overrideFile)
 110    {
 11        const string procedureName = "ApiReader.AddFile";
 112        var parameters = new DynamicParameters();
 113        parameters.Add("@FileTypeId", fileTypeId);
 114        parameters.Add("@FilePath", filePath);
 115        parameters.Add("@Override", overrideFile);
 116        var result = await dataService.ExecuteStoredProcedure(procedureName, parameters);
 117        return result;
 118    }
 19}
-
-
-
-
-

Methods/Properties

-ApiReaderAddFile()
-
-
- \ No newline at end of file diff --git a/source/coverage/Functions_FunctionExecutorAutoStartup.html b/source/coverage/Functions_FunctionExecutorAutoStartup.html deleted file mode 100644 index e6701d1..0000000 --- a/source/coverage/Functions_FunctionExecutorAutoStartup.html +++ /dev/null @@ -1,167 +0,0 @@ - - - - - - - -Functions.FunctionExecutorAutoStartup - Coverage Report - -
-

< Summary

- -
-
-
Line coverage
-
-
0%
-
- - - - - - - - - - - - - - - - - - - - - -
Covered lines:0
Uncovered lines:3
Coverable lines:3
Total lines:164
Line coverage:0%
-
-
-
-
-
Branch coverage
-
-
N/A
-
- - - - - - - - - - - - - -
Covered branches:0
Total branches:0
Branch coverage:N/A
-
-
-
-
-
Method coverage
-
-
-

Feature is only available for sponsors

-Upgrade to PRO version -
-
-
-
-

Metrics

-
- ------- - - - - -
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
Configure(...)100%210%
-
-

File(s)

-

/Users/griordan/git/gpconnect-analytics/source/Functions/Microsoft.Azure.Functions.Worker.Sdk.Generators/Microsoft.Azure.Functions.Worker.Sdk.Generators.FunctionExecutorGenerator/GeneratedFunctionExecutor.g.cs

-

File '/Users/griordan/git/gpconnect-analytics/source/Functions/Microsoft.Azure.Functions.Worker.Sdk.Generators/Microsoft.Azure.Functions.Worker.Sdk.Generators.FunctionExecutorGenerator/GeneratedFunctionExecutor.g.cs' does not exist (any more).

-
-
- \ No newline at end of file diff --git a/source/coverage/Functions_FunctionExecutorHostBuilderExtensions.html b/source/coverage/Functions_FunctionExecutorHostBuilderExtensions.html deleted file mode 100644 index ed2e3e0..0000000 --- a/source/coverage/Functions_FunctionExecutorHostBuilderExtensions.html +++ /dev/null @@ -1,167 +0,0 @@ - - - - - - - -Functions.FunctionExecutorHostBuilderExtensions - Coverage Report - -
-

< Summary

- -
-
-
Line coverage
-
-
0%
-
- - - - - - - - - - - - - - - - - - - - - -
Covered lines:0
Uncovered lines:6
Coverable lines:6
Total lines:149
Line coverage:0%
-
-
-
-
-
Branch coverage
-
-
N/A
-
- - - - - - - - - - - - - -
Covered branches:0
Total branches:0
Branch coverage:N/A
-
-
-
-
-
Method coverage
-
-
-

Feature is only available for sponsors

-Upgrade to PRO version -
-
-
-
-

Metrics

-
- ------- - - - - -
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
ConfigureGeneratedFunctionExecutor(...)100%210%
-
-

File(s)

-

/Users/griordan/git/gpconnect-analytics/source/Functions/Microsoft.Azure.Functions.Worker.Sdk.Generators/Microsoft.Azure.Functions.Worker.Sdk.Generators.FunctionExecutorGenerator/GeneratedFunctionExecutor.g.cs

-

File '/Users/griordan/git/gpconnect-analytics/source/Functions/Microsoft.Azure.Functions.Worker.Sdk.Generators/Microsoft.Azure.Functions.Worker.Sdk.Generators.FunctionExecutorGenerator/GeneratedFunctionExecutor.g.cs' does not exist (any more).

-
-
- \ No newline at end of file diff --git a/source/coverage/Functions_FunctionMetadataProviderAutoStartup.html b/source/coverage/Functions_FunctionMetadataProviderAutoStartup.html deleted file mode 100644 index 1b59ce5..0000000 --- a/source/coverage/Functions_FunctionMetadataProviderAutoStartup.html +++ /dev/null @@ -1,167 +0,0 @@ - - - - - - - -Functions.FunctionMetadataProviderAutoStartup - Coverage Report - -
-

< Summary

- -
-
-
Line coverage
-
-
0%
-
- - - - - - - - - - - - - - - - - - - - - -
Covered lines:0
Uncovered lines:3
Coverable lines:3
Total lines:226
Line coverage:0%
-
-
-
-
-
Branch coverage
-
-
N/A
-
- - - - - - - - - - - - - -
Covered branches:0
Total branches:0
Branch coverage:N/A
-
-
-
-
-
Method coverage
-
-
-

Feature is only available for sponsors

-Upgrade to PRO version -
-
-
-
-

Metrics

-
- ------- - - - - -
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
Configure(...)100%210%
-
-

File(s)

-

/Users/griordan/git/gpconnect-analytics/source/Functions/Microsoft.Azure.Functions.Worker.Sdk.Generators/Microsoft.Azure.Functions.Worker.Sdk.Generators.FunctionMetadataProviderGenerator/GeneratedFunctionMetadataProvider.g.cs

-

File '/Users/griordan/git/gpconnect-analytics/source/Functions/Microsoft.Azure.Functions.Worker.Sdk.Generators/Microsoft.Azure.Functions.Worker.Sdk.Generators.FunctionMetadataProviderGenerator/GeneratedFunctionMetadataProvider.g.cs' does not exist (any more).

-
-
- \ No newline at end of file diff --git a/source/coverage/Functions_GeneratedFunctionMetadataProvider.html b/source/coverage/Functions_GeneratedFunctionMetadataProvider.html deleted file mode 100644 index 00bd679..0000000 --- a/source/coverage/Functions_GeneratedFunctionMetadataProvider.html +++ /dev/null @@ -1,167 +0,0 @@ - - - - - - - -Functions.GeneratedFunctionMetadataProvider - Coverage Report - -
-

< Summary

- -
-
-
Line coverage
-
-
0%
-
- - - - - - - - - - - - - - - - - - - - - -
Covered lines:0
Uncovered lines:155
Coverable lines:155
Total lines:192
Line coverage:0%
-
-
-
-
-
Branch coverage
-
-
N/A
-
- - - - - - - - - - - - - -
Covered branches:0
Total branches:0
Branch coverage:N/A
-
-
-
-
-
Method coverage
-
-
-

Feature is only available for sponsors

-Upgrade to PRO version -
-
-
-
-

Metrics

-
- ------- - - - - -
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
GetFunctionMetadataAsync(...)100%210%
-
-

File(s)

-

/Users/griordan/git/gpconnect-analytics/source/Functions/Microsoft.Azure.Functions.Worker.Sdk.Generators/Microsoft.Azure.Functions.Worker.Sdk.Generators.FunctionMetadataProviderGenerator/GeneratedFunctionMetadataProvider.g.cs

-

File '/Users/griordan/git/gpconnect-analytics/source/Functions/Microsoft.Azure.Functions.Worker.Sdk.Generators/Microsoft.Azure.Functions.Worker.Sdk.Generators.FunctionMetadataProviderGenerator/GeneratedFunctionMetadataProvider.g.cs' does not exist (any more).

-
-
- -
- \ No newline at end of file diff --git a/source/coverage/Functions_GetDataFromApiByDateRange.html b/source/coverage/Functions_GetDataFromApiByDateRange.html deleted file mode 100644 index 85b9a32..0000000 --- a/source/coverage/Functions_GetDataFromApiByDateRange.html +++ /dev/null @@ -1,262 +0,0 @@ - - - - - - - -Functions.GetDataFromApiByDateRange - Coverage Report - -
-

< Summary

-
-
-
Information
-
-
- - - - - - - - - - - - - -
Class:Functions.GetDataFromApiByDateRange
Assembly:Functions
File(s):/Users/griordan/git/gpconnect-analytics/source/Functions/GetDataFromApiByDateRange.cs
-
-
-
-
-
-
-
Line coverage
-
-
60%
-
- - - - - - - - - - - - - - - - - - - - - -
Covered lines:27
Uncovered lines:18
Coverable lines:45
Total lines:85
Line coverage:60%
-
-
-
-
-
Branch coverage
-
-
N/A
-
- - - - - - - - - - - - - -
Covered branches:0
Total branches:0
Branch coverage:N/A
-
-
-
-
-
Method coverage
-
-
-

Feature is only available for sponsors

-Upgrade to PRO version -
-
-
-
-

Metrics

-
- ------- - - - - - - -
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
GetDataFromSspTransByDateRange()100%1160%
GetDataFromMeshTransByDateRange()100%1160%
GetDataFromAsidLookupByDateRange()100%1160%
-
-

File(s)

-

/Users/griordan/git/gpconnect-analytics/source/Functions/GetDataFromApiByDateRange.cs

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#LineLine coverage
 1using System.Net;
 2using Core.Helpers;
 3using Functions.Services.Interfaces;
 4using Microsoft.Azure.Functions.Worker;
 5using Microsoft.Azure.Functions.Worker.Http;
 6using Microsoft.Extensions.Logging;
 7
 8namespace Functions
 9{
 10    public class GetDataFromApiByDateRange(IBatchService batchService, ILogger log)
 11    {
 12        [Function("GetDataFromApiByDateRangeSspTrans")]
 13        public async Task<HttpResponseData> GetDataFromSspTransByDateRange(
 14            [HttpTrigger(AuthorizationLevel.Function, "GET", Route = null)]
 15            HttpRequestData req)
 116        {
 17            try
 118            {
 119                var startDate = req.Query["StartDate"];
 120                var endDate = req.Query["EndDate"];
 121                var rows = await batchService.StartBatchDownloadAsync(FileTypes.ssptrans, startDate, endDate);
 22
 23
 124                var response = req.CreateResponse(HttpStatusCode.OK);
 125                await response.WriteStringAsync($"Batch Download successful: {rows} requests processed");
 126                return response;
 27            }
 028            catch (Exception ex)
 029            {
 030                log.LogError(ex, "Error starting batch download for SSP Trans");
 031                var response = req.CreateResponse(HttpStatusCode.InternalServerError);
 032                await response.WriteStringAsync("Failed to download - see logs");
 033                return response;
 34            }
 135        }
 36
 37        [Function("GetDataFromApiByDateRangeMeshTrans")]
 38        public async Task<HttpResponseData> GetDataFromMeshTransByDateRange(
 39            [HttpTrigger(AuthorizationLevel.Function, "GET", Route = null)]
 40            HttpRequestData req)
 141        {
 42            try
 143            {
 144                var startDate = req.Query["StartDate"];
 145                var endDate = req.Query["EndDate"];
 146                var processed = await batchService.StartBatchDownloadAsync(FileTypes.meshtrans, startDate, endDate);
 47
 148                var response = req.CreateResponse(HttpStatusCode.OK);
 149                await response.WriteStringAsync($"Batch Download successful: {processed} requests processed");
 150                return response;
 51            }
 052            catch (Exception ex)
 053            {
 054                log.LogError(ex, "Error starting batch download for Mesh Trans");
 055                var response = req.CreateResponse(HttpStatusCode.InternalServerError);
 056                await response.WriteStringAsync("Failed to download - see logs");
 057                return response;
 58            }
 159        }
 60
 61        [Function("GetDataFromApiByDateRangeAsidLookup")]
 62        public async Task<HttpResponseData> GetDataFromAsidLookupByDateRange(
 63            [HttpTrigger(AuthorizationLevel.Function, "GET", Route = null)]
 64            HttpRequestData req)
 165        {
 66            try
 167            {
 168                var startDate = req.Query["StartDate"];
 169                var endDate = req.Query["EndDate"];
 170                var processed = await batchService.StartBatchDownloadAsync(FileTypes.asidlookup, startDate, endDate);
 71
 172                var response = req.CreateResponse(HttpStatusCode.OK);
 173                await response.WriteStringAsync($"Batch Download successful: {processed} requests processed");
 174                return response;
 75            }
 076            catch (Exception ex)
 077            {
 078                log.LogError(ex, "Error starting batch download for Asid Lookup");
 079                var response = req.CreateResponse(HttpStatusCode.InternalServerError);
 080                await response.WriteStringAsync("Failed to download - see logs");
 081                return response;
 82            }
 183        }
 84    }
 85}
-
-
-
- \ No newline at end of file diff --git a/source/coverage/Functions_GetDataFromApiByTrigger.html b/source/coverage/Functions_GetDataFromApiByTrigger.html deleted file mode 100644 index b53eb9a..0000000 --- a/source/coverage/Functions_GetDataFromApiByTrigger.html +++ /dev/null @@ -1,211 +0,0 @@ - - - - - - - -Functions.GetDataFromApiByTrigger - Coverage Report - -
-

< Summary

-
-
-
Information
-
-
- - - - - - - - - - - - - -
Class:Functions.GetDataFromApiByTrigger
Assembly:Functions
File(s):/Users/griordan/git/gpconnect-analytics/source/Functions/GetDataFromApiByTrigger.cs
-
-
-
-
-
-
-
Line coverage
-
-
100%
-
- - - - - - - - - - - - - - - - - - - - - -
Covered lines:9
Uncovered lines:0
Coverable lines:9
Total lines:34
Line coverage:100%
-
-
-
-
-
Branch coverage
-
-
N/A
-
- - - - - - - - - - - - - -
Covered branches:0
Total branches:0
Branch coverage:N/A
-
-
-
-
-
Method coverage
-
-
-

Feature is only available for sponsors

-Upgrade to PRO version -
-
-
-
-

Metrics

-
- ------- - - - - - - -
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
GetDataFromAsidLookup()100%11100%
GetDataFromSspTrans()100%11100%
GetDataFromMeshTrans()100%11100%
-
-

File(s)

-

/Users/griordan/git/gpconnect-analytics/source/Functions/GetDataFromApiByTrigger.cs

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#LineLine coverage
 1using Core.Helpers;
 2using Functions.Services.Interfaces;
 3using Microsoft.Azure.Functions.Worker;
 4using Microsoft.Extensions.Logging;
 5
 6namespace Functions
 7{
 8    public class GetDataFromApiByTrigger(IBatchService batchService, ILogger log)
 9    {
 10        [Function("GetDataFromApiByTriggerAsidLookup")]
 11        public async Task GetDataFromAsidLookup(
 12            [TimerTrigger("%GetDataFromApiByTriggerAsidLookupSchedule%", RunOnStartup = false)]
 13            TimerInfo myTimer)
 114        {
 115            await batchService.StartBatchDownloadForTodayAsync(FileTypes.asidlookup);
 116        }
 17
 18        [Function("GetDataFromApiByTriggerSspTrans")]
 19        public async Task GetDataFromSspTrans(
 20            [TimerTrigger("%GetDataFromApiByTriggerSspTransSchedule%", RunOnStartup = false)]
 21            TimerInfo myTimer)
 122        {
 123            await batchService.StartBatchDownloadForTodayAsync(FileTypes.ssptrans);
 124        }
 25
 26        [Function("GetDataFromApiByTriggerMeshTrans")]
 27        public async Task GetDataFromMeshTrans(
 28            [TimerTrigger("%GetDataFromApiByTriggerMeshTransSchedule%", RunOnStartup = false)]
 29            TimerInfo myTimer)
 130        {
 131            await batchService.StartBatchDownloadForTodayAsync(FileTypes.meshtrans);
 132        }
 33    }
 34}
-
-
-
- \ No newline at end of file diff --git a/source/coverage/Functions_GetDataFromApiManual.html b/source/coverage/Functions_GetDataFromApiManual.html deleted file mode 100644 index 2d4a269..0000000 --- a/source/coverage/Functions_GetDataFromApiManual.html +++ /dev/null @@ -1,215 +0,0 @@ - - - - - - - -Functions.GetDataFromApiManual - Coverage Report - -
-

< Summary

-
-
-
Information
-
-
- - - - - - - - - - - - - -
Class:Functions.GetDataFromApiManual
Assembly:Functions
File(s):/Users/griordan/git/gpconnect-analytics/source/Functions/GetDataFromApiManual.cs
-
-
-
-
-
-
-
Line coverage
-
-
100%
-
- - - - - - - - - - - - - - - - - - - - - -
Covered lines:21
Uncovered lines:0
Coverable lines:21
Total lines:42
Line coverage:100%
-
-
-
-
-
Branch coverage
-
-
100%
-
- - - - - - - - - - - - - -
Covered branches:2
Total branches:2
Branch coverage:100%
-
-
-
-
-
Method coverage
-
-
-

Feature is only available for sponsors

-Upgrade to PRO version -
-
-
-
-

Metrics

-
- ------- - - - - -
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
AddDownloadedFile()100%22100%
-
-

File(s)

-

/Users/griordan/git/gpconnect-analytics/source/Functions/GetDataFromApiManual.cs

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#LineLine coverage
 1using System.Net;
 2using Functions.Services.Interfaces;
 3using Microsoft.Azure.Functions.Worker;
 4using Microsoft.Azure.Functions.Worker.Http;
 5using Microsoft.Extensions.Logging;
 6
 7namespace Functions
 8{
 9    public class GetDataFromApiManual(IImportService importService, ILogger log)
 10    {
 11        [Function("GetDataFromApiManual")]
 12        public async Task<HttpResponseData> AddDownloadedFile(
 13            [HttpTrigger(AuthorizationLevel.Function, "GET", Route = null)]
 14            HttpRequestData req)
 415        {
 416            var response = req.CreateResponse();
 417            response.Headers.Add("Content-Type", "application/text");
 18            try
 419            {
 420                var filePath = req.Query["FilePath"];
 421                if (string.IsNullOrEmpty(filePath))
 122                {
 123                    response.StatusCode = HttpStatusCode.BadRequest;
 124                    await response.WriteStringAsync("Filepath missing");
 125                    return response;
 26                }
 27
 328                await importService.AddDownloadedFileManually(filePath);
 129                response.StatusCode = HttpStatusCode.OK;
 130                await response.WriteStringAsync("Successfully added files");
 131                return response;
 32            }
 233            catch (Exception ex)
 234            {
 235                log.LogError(ex, $"Error adding downloaded file: {ex.Message}");
 236                response.StatusCode = HttpStatusCode.InternalServerError;
 237                await response.WriteStringAsync("Something went wrong - see error logs for more details");
 238                return response;
 39            }
 440        }
 41    }
 42}
-
-
-
-
-

Methods/Properties

-AddDownloadedFile()
-
-
- \ No newline at end of file diff --git a/source/coverage/Functions_GetDataFromApiToday.html b/source/coverage/Functions_GetDataFromApiToday.html deleted file mode 100644 index f1873fa..0000000 --- a/source/coverage/Functions_GetDataFromApiToday.html +++ /dev/null @@ -1,275 +0,0 @@ - - - - - - - -Functions.GetDataFromApiToday - Coverage Report - -
-

< Summary

-
-
-
Information
-
-
- - - - - - - - - - - - - -
Class:Functions.GetDataFromApiToday
Assembly:Functions
File(s):/Users/griordan/git/gpconnect-analytics/source/Functions/GetDataFromApiToday.cs
-
-
-
-
-
-
-
Line coverage
-
-
100%
-
- - - - - - - - - - - - - - - - - - - - - -
Covered lines:54
Uncovered lines:0
Coverable lines:54
Total lines:98
Line coverage:100%
-
-
-
-
-
Branch coverage
-
-
N/A
-
- - - - - - - - - - - - - -
Covered branches:0
Total branches:0
Branch coverage:N/A
-
-
-
-
-
Method coverage
-
-
-

Feature is only available for sponsors

-Upgrade to PRO version -
-
-
-
-

Metrics

-
- ------- - - - - - - -
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
GetDataFromSspTransByDateRange()100%11100%
GetDataFromMeshTransByDateRange()100%11100%
GetDataFromAsidLookupByDateRange()100%11100%
-
-

File(s)

-

/Users/griordan/git/gpconnect-analytics/source/Functions/GetDataFromApiToday.cs

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#LineLine coverage
 1using System.Net;
 2using Core.Helpers;
 3using Functions.Services.Interfaces;
 4using Microsoft.Azure.Functions.Worker;
 5using Microsoft.Azure.Functions.Worker.Http;
 6using Microsoft.Extensions.Logging;
 7
 8namespace Functions
 9{
 10    public class GetDataFromApiToday(IBatchService batchService, ILogger log)
 11    {
 12        [Function("GetDataFromApiTodaySspTrans")]
 13        public async Task<HttpResponseData> GetDataFromSspTransByDateRange(
 14            [HttpTrigger(AuthorizationLevel.Function, "GET", Route = null)]
 15            HttpRequestData req)
 316        {
 317            var response = req.CreateResponse();
 318            response.Headers.Add("Content-Type", "application/text");
 19
 20
 321            var affectedCount = 0;
 22            try
 323            {
 324                affectedCount = await batchService.StartBatchDownloadForTodayAsync(FileTypes.ssptrans);
 125            }
 226            catch (Exception ex)
 227            {
 228                log.LogError(ex, "An error occurred during batch download when processing urls");
 229                response.StatusCode = HttpStatusCode.InternalServerError;
 230                await response.WriteStringAsync(
 231                    $"An error occurred whilst processing batch download - see logs for more details");
 32
 233                return response;
 34            }
 35
 136            response.StatusCode = HttpStatusCode.OK;
 137            await response.WriteStringAsync($"Processed {affectedCount} requests");
 138            return response;
 339        }
 40
 41        [Function("GetDataFromApiTodayMeshTrans")]
 42        public async Task<HttpResponseData> GetDataFromMeshTransByDateRange(
 43            [HttpTrigger(AuthorizationLevel.Function, "GET", Route = null)]
 44            HttpRequestData req)
 345        {
 346            var response = req.CreateResponse();
 347            response.Headers.Add("Content-Type", "application/text");
 48
 49
 350            var affectedCount = 0;
 51            try
 352            {
 353                affectedCount = await batchService.StartBatchDownloadForTodayAsync(FileTypes.meshtrans);
 154            }
 255            catch (Exception ex)
 256            {
 257                log.LogError(ex, "An error occurred during batch download when processing urls");
 258                response.StatusCode = HttpStatusCode.InternalServerError;
 259                await response.WriteStringAsync(
 260                    $"An error occurred whilst processing batch download - see logs for more details");
 61
 262                return response;
 63            }
 64
 165            response.StatusCode = HttpStatusCode.OK;
 166            await response.WriteStringAsync($"Processed {affectedCount} requests");
 167            return response;
 368        }
 69
 70        [Function("GetDataFromApiTodayAsidLookup")]
 71        public async Task<HttpResponseData> GetDataFromAsidLookupByDateRange(
 72            [HttpTrigger(AuthorizationLevel.Function, "GET", Route = null)]
 73            HttpRequestData req)
 374        {
 375            var response = req.CreateResponse();
 376            response.Headers.Add("Content-Type", "application/text");
 377            var affectedCount = 0;
 78            try
 379            {
 380                affectedCount = await batchService.StartBatchDownloadForTodayAsync(FileTypes.asidlookup);
 181            }
 282            catch (Exception ex)
 283            {
 284                log.LogError(ex, "An error occurred during batch download when processing urls");
 285                response.StatusCode = HttpStatusCode.InternalServerError;
 286                await response.WriteStringAsync(
 287                    $"An error occurred whilst processing batch download - see logs for more details");
 88
 89
 290                return response;
 91            }
 92
 193            response.StatusCode = HttpStatusCode.OK;
 194            await response.WriteStringAsync($"Processed {affectedCount} requests");
 195            return response;
 396        }
 97    }
 98}
-
-
-
- \ No newline at end of file diff --git a/source/coverage/Functions_HttpClientExtensions.html b/source/coverage/Functions_HttpClientExtensions.html deleted file mode 100644 index 234c5b9..0000000 --- a/source/coverage/Functions_HttpClientExtensions.html +++ /dev/null @@ -1,198 +0,0 @@ - - - - - - - -Functions.Configuration.Infrastructure.HttpClient.HttpClientExtensions - Coverage Report - -
-

< Summary

-
-
-
Information
-
-
- - - - - - - - - - - - - -
Class:Functions.Configuration.Infrastructure.HttpClient.HttpClientExtensions
Assembly:Functions
File(s):/Users/griordan/git/gpconnect-analytics/source/Functions/Configuration/Infrastructure/HttpClient/HttpClientExtensions.cs
-
-
-
-
-
-
-
Line coverage
-
-
100%
-
- - - - - - - - - - - - - - - - - - - - - -
Covered lines:12
Uncovered lines:0
Coverable lines:12
Total lines:23
Line coverage:100%
-
-
-
-
-
Branch coverage
-
-
N/A
-
- - - - - - - - - - - - - -
Covered branches:0
Total branches:0
Branch coverage:N/A
-
-
-
-
-
Method coverage
-
-
-

Feature is only available for sponsors

-Upgrade to PRO version -
-
-
-
-

Metrics

-
- ------- - - - - - -
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
ConfigureHttpClient(...)100%11100%
CreateHttpMessageHandler()100%11100%
-
-

File(s)

-

/Users/griordan/git/gpconnect-analytics/source/Functions/Configuration/Infrastructure/HttpClient/HttpClientExtensions.cs

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - -
#LineLine coverage
 1using System.Net.Http.Headers;
 2using System.Security.Authentication;
 3
 4namespace Functions.Configuration.Infrastructure.HttpClient;
 5
 6public static class HttpClientExtensions
 7{
 8    public static void ConfigureHttpClient(System.Net.Http.HttpClient options)
 19    {
 110        options.Timeout = new TimeSpan(0, 0, 1, 0);
 111        options.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/csv"));
 112        options.DefaultRequestHeaders.CacheControl = new CacheControlHeaderValue { NoCache = true };
 113    }
 14
 15    public static HttpMessageHandler CreateHttpMessageHandler()
 116    {
 117        var httpClientHandler = new HttpClientHandler
 118        {
 119            SslProtocols = SslProtocols.Tls13 | SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls
 120        };
 121        return httpClientHandler;
 122    }
 23}
-
-
-
- \ No newline at end of file diff --git a/source/coverage/Functions_ImportService.html b/source/coverage/Functions_ImportService.html deleted file mode 100644 index 00b6aa4..0000000 --- a/source/coverage/Functions_ImportService.html +++ /dev/null @@ -1,261 +0,0 @@ - - - - - - - -Functions.Services.ImportService - Coverage Report - -
-

< Summary

-
-
-
Information
-
-
- - - - - - - - - - - - - -
Class:Functions.Services.ImportService
Assembly:Functions
File(s):/Users/griordan/git/gpconnect-analytics/source/Functions/Services/ImportService.cs
-
-
-
-
-
-
-
Line coverage
-
-
100%
-
- - - - - - - - - - - - - - - - - - - - - -
Covered lines:46
Uncovered lines:0
Coverable lines:46
Total lines:84
Line coverage:100%
-
-
-
-
-
Branch coverage
-
-
85%
-
- - - - - - - - - - - - - -
Covered branches:12
Total branches:14
Branch coverage:85.7%
-
-
-
-
-
Method coverage
-
-
-

Feature is only available for sponsors

-Upgrade to PRO version -
-
-
-
-

Metrics

-
- ------- - - - - - - -
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
AddDownloadedFileManually()100%22100%
AddObjectFileMessage()75%88100%
InstallData()100%44100%
-
-

File(s)

-

/Users/griordan/git/gpconnect-analytics/source/Functions/Services/ImportService.cs

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#LineLine coverage
 1using System.Data;
 2using Core.DTOs.Response.Configuration;
 3using Core.DTOs.Response.Queue;
 4using Core.DTOs.Response.Splunk;
 5using Core.Helpers;
 6using Core.Services.Interfaces;
 7using Dapper;
 8using Functions.Services.Interfaces;
 9using Microsoft.Extensions.Logging;
 10
 11namespace Functions.Services
 12{
 13    public class ImportService(
 14        IConfigurationService configurationService,
 15        IDataService dataService,
 16        IBlobService blobService,
 17        ILogger<ImportService> logger,
 18        IFileService fileService)
 19        : IImportService
 20    {
 21        public async Task AddDownloadedFileManually(string filePath)
 222        {
 223            var fileTypeFromPath = filePath.GetFileType<FileTypes>();
 24
 225            if (fileTypeFromPath == null)
 126            {
 127                throw new ArgumentException("Filepath does not contain vailid file type suffix");
 28            }
 29
 130            var fileType = await configurationService.GetFileType((FileTypes)fileTypeFromPath);
 131            var fileAddedCount =
 132                await fileService.ApiReaderAddFile(fileType.FileTypeId, filePath, true);
 33
 134            await blobService.AddMessageToBlobQueue(fileAddedCount, fileType.FileTypeId, filePath,
 135                true);
 136        }
 37
 38        public async Task AddObjectFileMessage(FileType fileType, ExtractResponse extractResponse)
 539        {
 540            if (extractResponse.ExtractResponseMessage.StatusCode == System.Net.HttpStatusCode.OK)
 241            {
 242                var uploadedBlob = await blobService.AddObjectToBlob(extractResponse);
 243                if (uploadedBlob != null)
 144                {
 145                    var fileAddedCount =
 146                        await fileService.ApiReaderAddFile(fileType.FileTypeId, extractResponse.FilePath, true);
 47
 148                    await blobService.AddMessageToBlobQueue(fileAddedCount, fileType.FileTypeId,
 149                        extractResponse.FilePath,
 150                        true);
 151                }
 252            }
 53            else
 354            {
 355                logger?.LogWarning(extractResponse?.ExtractResponseMessage.ToString());
 356            }
 557        }
 58
 59
 60        public async Task InstallData(Message queueItem)
 161        {
 162            var moreFilesToInstall = true;
 63            const string procedureName = "Import.InstallNextFile";
 164            var parameters = new DynamicParameters();
 165            parameters.Add("@FileTypeId", queueItem.FileTypeId);
 166            if (queueItem.Override)
 167            {
 168                parameters.Add("@Override", queueItem.Override, dbType: DbType.Boolean,
 169                    direction: ParameterDirection.Input);
 170            }
 71
 172            parameters.Add("@MoreFilesToInstall", dbType: DbType.Boolean, direction: ParameterDirection.Output);
 73
 374            while (moreFilesToInstall)
 275            {
 276                logger.LogInformation($"Installing file into database", parameters);
 277                var result = await dataService.ExecuteStoredProcedureWithOutputParameters(procedureName, parameters);
 78
 279                moreFilesToInstall = result.Get<bool>("@MoreFilesToInstall");
 280                logger.LogInformation($"More files to install? {moreFilesToInstall}");
 281            }
 182        }
 83    }
 84}
-
-
-
- \ No newline at end of file diff --git a/source/coverage/Functions_LoggingExtensions.html b/source/coverage/Functions_LoggingExtensions.html deleted file mode 100644 index ef39463..0000000 --- a/source/coverage/Functions_LoggingExtensions.html +++ /dev/null @@ -1,368 +0,0 @@ - - - - - - - -Functions.Configuration.Infrastructure.Logging.LoggingExtensions - Coverage Report - -
-

< Summary

-
-
-
Information
-
-
- - - - - - - - - - - - - -
Class:Functions.Configuration.Infrastructure.Logging.LoggingExtensions
Assembly:Functions
File(s):/Users/griordan/git/gpconnect-analytics/source/Functions/Configuration/Infrastructure/Logging/LoggingExtensions.cs
-
-
-
-
-
-
-
Line coverage
-
-
0%
-
- - - - - - - - - - - - - - - - - - - - - -
Covered lines:0
Uncovered lines:130
Coverable lines:130
Total lines:185
Line coverage:0%
-
-
-
-
-
Branch coverage
-
-
0%
-
- - - - - - - - - - - - - -
Covered branches:0
Total branches:4
Branch coverage:0%
-
-
-
-
-
Method coverage
-
-
-

Feature is only available for sponsors

-Upgrade to PRO version -
-
-
-
-

Metrics

-
- ------- - - - - - - - - - -
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
ConfigureLoggingServices(...)100%210%
AddMailTarget(...)0%2040%
GetExceptionLayout()100%210%
GetEmailConfiguration(...)100%210%
AddDatabaseTarget(...)100%210%
AddConsoleTarget()100%210%
-
-

File(s)

-

/Users/griordan/git/gpconnect-analytics/source/Functions/Configuration/Infrastructure/Logging/LoggingExtensions.cs

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#LineLine coverage
 1using System.Data;
 2using Core.DTOs.Response.Configuration;
 3using Core.Helpers;
 4using Dapper;
 5using Microsoft.Data.SqlClient;
 6using Microsoft.Extensions.Configuration;
 7using Microsoft.Extensions.Logging;
 8using NLog;
 9using NLog.Extensions.Logging;
 10using NLog.Layouts;
 11using NLog.Targets;
 12
 13namespace Functions.Configuration.Infrastructure.Logging
 14{
 15    public static class LoggingExtensions
 16    {
 17        public static ILoggingBuilder ConfigureLoggingServices(
 18            ILoggingBuilder loggingBuilder,
 19            IConfiguration configuration,
 20            IEmailConfigurationProvider emailConfigurationProvider)
 021        {
 22            // Set up NLog
 023            LogManager.Setup().LoadConfigurationFromFile("nlog.config");
 24
 25            // Add NLog to the logging pipeline
 026            loggingBuilder.AddNLog();
 27
 28            // Add custom targets manually (optional)
 029            var nLogConfiguration = new NLog.Config.LoggingConfiguration();
 30
 031            var consoleTarget = AddConsoleTarget();
 032            var databaseTarget = AddDatabaseTarget(configuration);
 033            var mailTarget = AddMailTarget(configuration, emailConfigurationProvider);
 34
 035            nLogConfiguration.Variables.Add("applicationVersion",
 036                ApplicationHelper.ApplicationVersion.GetAssemblyVersion());
 37
 038            nLogConfiguration.AddRule(NLog.LogLevel.Trace, NLog.LogLevel.Fatal, consoleTarget);
 039            nLogConfiguration.AddRule(NLog.LogLevel.Trace, NLog.LogLevel.Fatal, databaseTarget);
 040            nLogConfiguration.AddRule(NLog.LogLevel.Error, NLog.LogLevel.Fatal, mailTarget);
 41
 042            nLogConfiguration.AddTarget(consoleTarget);
 043            nLogConfiguration.AddTarget(databaseTarget);
 044            nLogConfiguration.AddTarget(mailTarget);
 45
 046            return loggingBuilder;
 047        }
 48
 49        private static MailTarget AddMailTarget(IConfiguration configuration,
 50            IEmailConfigurationProvider emailConfigurationProvider)
 051        {
 052            var emailConfiguration = emailConfigurationProvider.GetEmailConfiguration(configuration);
 053            if (emailConfiguration == null)
 054            {
 055                throw new InvalidOperationException("EmailConfiguration cannot be null");
 56            }
 57
 058            var mailTarget = new MailTarget
 059            {
 060                Name = "Mail",
 061                Html = false,
 062                SmtpServer = emailConfiguration.Hostname,
 063                SmtpAuthentication = emailConfiguration.AuthenticationRequired
 064                    ? SmtpAuthenticationMode.Basic
 065                    : SmtpAuthenticationMode.None,
 066                SmtpUserName = emailConfiguration.Username,
 067                SmtpPort = emailConfiguration.Port,
 068                SmtpPassword = emailConfiguration.Password,
 069                To = emailConfiguration.RecipientAddress,
 070                From = emailConfiguration.SenderAddress,
 071                Body = GetExceptionLayout(),
 072                Subject = emailConfiguration.DefaultSubject,
 073                EnableSsl = true,
 074                DeliveryMethod = System.Net.Mail.SmtpDeliveryMethod.Network
 075            };
 076            return mailTarget;
 077        }
 78
 79        private static JsonLayout GetExceptionLayout()
 080        {
 081            var exceptionLayout = new JsonLayout();
 082            exceptionLayout.Attributes.Add(new JsonAttribute("type", "${exception:format=Type}"));
 083            exceptionLayout.Attributes.Add(new JsonAttribute("message", "${exception:format=Message}"));
 084            exceptionLayout.Attributes.Add(new JsonAttribute("stacktrace", "${exception:format=StackTrace}"));
 085            exceptionLayout.Attributes.Add(new JsonAttribute("innerException", new JsonLayout
 086            {
 087                Attributes =
 088                {
 089                    new JsonAttribute("type",
 090                        "${exception:format=:innerFormat=Type:MaxInnerExceptionLevel=1:InnerExceptionSeparator=}"),
 091                    new JsonAttribute("message",
 092                        "${exception:format=:innerFormat=Message:MaxInnerExceptionLevel=1:InnerExceptionSeparator=}"),
 093                    new JsonAttribute("stacktrace",
 094                        "${exception:format=:innerFormat=StackTrace:MaxInnerExceptionLevel=1:InnerExceptionSeparator=}")
 095                },
 096                RenderEmptyObject = false
 097            }, false));
 098            return exceptionLayout;
 099        }
 100
 101        private static Email? GetEmailConfiguration(IConfiguration configuration)
 0102        {
 0103            using var sqlConnection =
 0104                new SqlConnection(configuration.GetConnectionString(ConnectionStrings.GpConnectAnalytics));
 105
 0106            IEnumerable<Email?> result = sqlConnection.Query<Email>("[Configuration].[GetEmailConfiguration]",
 0107                commandType: CommandType.StoredProcedure);
 108
 0109            return result.FirstOrDefault();
 0110        }
 111
 112        private static DatabaseTarget AddDatabaseTarget(IConfiguration configuration)
 0113        {
 0114            var databaseTarget = new DatabaseTarget
 0115            {
 0116                Name = "Database",
 0117                ConnectionString = configuration.GetConnectionString(ConnectionStrings.GpConnectAnalytics),
 0118                CommandType = CommandType.StoredProcedure,
 0119                CommandText = "Logging.WriteLog",
 0120                DBProvider = "System.Data.SqlClient"
 0121            };
 122
 0123            databaseTarget.Parameters.Add(new DatabaseParameterInfo
 0124            {
 0125                Name = "@Application",
 0126                Layout = "${var:applicationVersion}",
 0127                DbType = DbType.String.ToString()
 0128            });
 129
 0130            databaseTarget.Parameters.Add(new DatabaseParameterInfo
 0131            {
 0132                Name = "@Logged",
 0133                Layout = "${date}",
 0134                DbType = DbType.DateTime.ToString()
 0135            });
 136
 0137            databaseTarget.Parameters.Add(new DatabaseParameterInfo
 0138            {
 0139                Name = "@Level",
 0140                Layout = "${level:uppercase=true}",
 0141                DbType = DbType.String.ToString()
 0142            });
 143
 0144            databaseTarget.Parameters.Add(new DatabaseParameterInfo
 0145            {
 0146                Name = "@Message",
 0147                Layout = "${message}",
 0148                DbType = DbType.String.ToString()
 0149            });
 150
 0151            databaseTarget.Parameters.Add(new DatabaseParameterInfo
 0152            {
 0153                Name = "@Logger",
 0154                Layout = "${logger}",
 0155                DbType = DbType.String.ToString()
 0156            });
 157
 0158            databaseTarget.Parameters.Add(new DatabaseParameterInfo
 0159            {
 0160                Name = "@Callsite",
 0161                Layout = "${callsite:filename=true}",
 0162                DbType = DbType.String.ToString()
 0163            });
 164
 0165            databaseTarget.Parameters.Add(new DatabaseParameterInfo
 0166            {
 0167                Name = "@Exception",
 0168                Layout = GetExceptionLayout(),
 0169                DbType = DbType.String.ToString()
 0170            });
 171
 0172            return databaseTarget;
 0173        }
 174
 175        private static ConsoleTarget AddConsoleTarget()
 0176        {
 0177            var consoleTarget = new ConsoleTarget
 0178            {
 0179                Name = "Console",
 0180                Layout = "${date}|${message}|${exception:format=stackTrace}"
 0181            };
 0182            return consoleTarget;
 0183        }
 184    }
 185}
-
-
-
- \ No newline at end of file diff --git a/source/coverage/Functions_LoggingService.html b/source/coverage/Functions_LoggingService.html deleted file mode 100644 index 58b08f3..0000000 --- a/source/coverage/Functions_LoggingService.html +++ /dev/null @@ -1,196 +0,0 @@ - - - - - - - -Functions.Services.LoggingService - Coverage Report - -
-

< Summary

-
-
-
Information
-
-
- - - - - - - - - - - - - -
Class:Functions.Services.LoggingService
Assembly:Functions
File(s):/Users/griordan/git/gpconnect-analytics/source/Functions/Services/LoggingService.cs
-
-
-
-
-
-
-
Line coverage
-
-
0%
-
- - - - - - - - - - - - - - - - - - - - - -
Covered lines:0
Uncovered lines:7
Coverable lines:7
Total lines:21
Line coverage:0%
-
-
-
-
-
Branch coverage
-
-
N/A
-
- - - - - - - - - - - - - -
Covered branches:0
Total branches:0
Branch coverage:N/A
-
-
-
-
-
Method coverage
-
-
-

Feature is only available for sponsors

-Upgrade to PRO version -
-
-
-
-

Metrics

-
- ------- - - - - - -
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%210%
PurgeErrorLog()100%210%
-
-

File(s)

-

/Users/griordan/git/gpconnect-analytics/source/Functions/Services/LoggingService.cs

-
- - - - - - - - - - - - - - - - - - - - - - - - - -
#LineLine coverage
 1using Core.Services.Interfaces;
 2using Functions.Services.Interfaces;
 3
 4namespace Functions.Services
 5{
 6    public class LoggingService : ILoggingService
 7    {
 8        private readonly IDataService _dataService;
 9
 10        public LoggingService(IDataService dataService)
 011        {
 012            _dataService = dataService;
 013        }
 14
 15        public async Task PurgeErrorLog()
 016        {
 017            var procedureName = "Logging.PurgeErrorLog";
 018            await _dataService.ExecuteStoredProcedure(procedureName);
 019        }
 20    }
 21}
-
-
-
- \ No newline at end of file diff --git a/source/coverage/Functions_MappingExtensions.html b/source/coverage/Functions_MappingExtensions.html deleted file mode 100644 index 68a5307..0000000 --- a/source/coverage/Functions_MappingExtensions.html +++ /dev/null @@ -1,186 +0,0 @@ - - - - - - - -Functions.Configuration.Infrastructure.Mapping.MappingExtensions - Coverage Report - -
-

< Summary

-
-
-
Information
-
-
- - - - - - - - - - - - - -
Class:Functions.Configuration.Infrastructure.Mapping.MappingExtensions
Assembly:Functions
File(s):/Users/griordan/git/gpconnect-analytics/source/Functions/Configuration/Infrastructure/Mapping/MappingExtensions.cs
-
-
-
-
-
-
-
Line coverage
-
-
0%
-
- - - - - - - - - - - - - - - - - - - - - -
Covered lines:0
Uncovered lines:3
Coverable lines:3
Total lines:13
Line coverage:0%
-
-
-
-
-
Branch coverage
-
-
N/A
-
- - - - - - - - - - - - - -
Covered branches:0
Total branches:0
Branch coverage:N/A
-
-
-
-
-
Method coverage
-
-
-

Feature is only available for sponsors

-Upgrade to PRO version -
-
-
-
-

Metrics

-
- ------- - - - - -
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
ConfigureMappingServices()100%210%
-
-

File(s)

-

/Users/griordan/git/gpconnect-analytics/source/Functions/Configuration/Infrastructure/Mapping/MappingExtensions.cs

-
- - - - - - - - - - - - - - - - - -
#LineLine coverage
 1using Core.Mapping;
 2using Dapper.FluentMap;
 3
 4namespace Functions.Configuration.Infrastructure.Mapping
 5{
 6    public static class MappingExtensions
 7    {
 8        public static void ConfigureMappingServices()
 09        {
 010            FluentMapper.Initialize(config => { config.AddMap(new SplunkInstanceMap()); });
 011        }
 12    }
 13}
-
-
-
-
-

Methods/Properties

-ConfigureMappingServices()
-
-
- \ No newline at end of file diff --git a/source/coverage/Functions_Program.html b/source/coverage/Functions_Program.html deleted file mode 100644 index 002fa9b..0000000 --- a/source/coverage/Functions_Program.html +++ /dev/null @@ -1,227 +0,0 @@ - - - - - - - -Program - Coverage Report - -
-

< Summary

-
-
-
Information
-
-
- - - - - - - - - - - - - -
Class:Program
Assembly:Functions
File(s):/Users/griordan/git/gpconnect-analytics/source/Functions/Program.cs
-
-
-
-
-
-
-
Line coverage
-
-
0%
-
- - - - - - - - - - - - - - - - - - - - - -
Covered lines:0
Uncovered lines:37
Coverable lines:37
Total lines:54
Line coverage:0%
-
-
-
-
-
Branch coverage
-
-
N/A
-
- - - - - - - - - - - - - -
Covered branches:0
Total branches:0
Branch coverage:N/A
-
-
-
-
-
Method coverage
-
-
-

Feature is only available for sponsors

-Upgrade to PRO version -
-
-
-
-

Metrics

-
- ------- - - - - -
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
<Main>$(...)100%210%
-
-

File(s)

-

/Users/griordan/git/gpconnect-analytics/source/Functions/Program.cs

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#LineLine coverage
 1using Core;
 2using Core.Repositories;
 3using Core.Services.Interfaces;
 4using Functions;
 5using Functions.Configuration;
 6using Functions.Configuration.Infrastructure.HttpClient;
 7using Functions.Configuration.Infrastructure.Logging;
 8using Functions.Configuration.Infrastructure.Mapping;
 9using Functions.Services;
 10using Functions.Services.Interfaces;
 11using Microsoft.Data.SqlClient;
 12using Microsoft.Extensions.DependencyInjection;
 13using Microsoft.Extensions.Hosting;
 14
 15
 016var builder = Host.CreateDefaultBuilder(args)
 017    .ConfigureFunctionsWorkerDefaults()
 018    .ConfigureServices((context, services) =>
 019    {
 020        // Configure your services here
 021        MappingExtensions.ConfigureMappingServices();
 022        services.AddSingleton<ICoreConfigurationService, CoreConfigurationService>();
 023        services.AddScoped<IConfigurationService, ConfigurationService>();
 024        services.AddScoped<IBlobService, BlobService>();
 025        services.AddScoped<IImportService, ImportService>();
 026        services.AddScoped<ISplunkService, SplunkService>();
 027        services.AddScoped<IDataService, DataService>();
 028        services.AddScoped<IBatchService, BatchService>();
 029        services.AddScoped<ILoggingService, LoggingService>();
 030        services.AddScoped<IDapperWrapper, DapperWrapper>();
 031        services.AddScoped<IHierarchyProviderConsumerRepo, HierarchyProviderConsumerRepo>();
 032        services.AddSingleton<IConnectionFactory, SqlConnectionFactory>();
 033        services.AddSingleton<IEmailConfigurationProvider, EmailConfigurationProvider>();
 034        services.AddScoped<ITimeProvider, TimeProvider>();
 035
 036        // Configure logging with email configuration provider
 037        services.AddLogging(loggingBuilder =>
 038        {
 039            var emailProvider = services.BuildServiceProvider().GetRequiredService<IEmailConfigurationProvider>();
 040            LoggingExtensions.ConfigureLoggingServices(loggingBuilder, context.Configuration, emailProvider);
 041        });
 042
 043        // Configure HttpClient
 044        services.AddHttpClient("SplunkApiClient", options =>
 045                HttpClientExtensions
 046                    .ConfigureHttpClient(options))
 047            .ConfigurePrimaryHttpMessageHandler(() =>
 048                HttpClientExtensions
 049                    .CreateHttpMessageHandler());
 050    });
 51
 52
 053var host = builder.Build();
 054host.Run();
-
-
-
-
-

Methods/Properties

-<Main>$(System.String[])
-
-
- \ No newline at end of file diff --git a/source/coverage/Functions_PurgeErrorLogByTrigger.html b/source/coverage/Functions_PurgeErrorLogByTrigger.html deleted file mode 100644 index 572ff12..0000000 --- a/source/coverage/Functions_PurgeErrorLogByTrigger.html +++ /dev/null @@ -1,189 +0,0 @@ - - - - - - - -Functions.PurgeErrorLogByTrigger - Coverage Report - -
-

< Summary

-
-
-
Information
-
-
- - - - - - - - - - - - - -
Class:Functions.PurgeErrorLogByTrigger
Assembly:Functions
File(s):/Users/griordan/git/gpconnect-analytics/source/Functions/PurgeErrorLogByTrigger.cs
-
-
-
-
-
-
-
Line coverage
-
-
100%
-
- - - - - - - - - - - - - - - - - - - - - -
Covered lines:3
Uncovered lines:0
Coverable lines:3
Total lines:16
Line coverage:100%
-
-
-
-
-
Branch coverage
-
-
N/A
-
- - - - - - - - - - - - - -
Covered branches:0
Total branches:0
Branch coverage:N/A
-
-
-
-
-
Method coverage
-
-
-

Feature is only available for sponsors

-Upgrade to PRO version -
-
-
-
-

Metrics

-
- ------- - - - - -
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
PurgeErrorLog()100%11100%
-
-

File(s)

-

/Users/griordan/git/gpconnect-analytics/source/Functions/PurgeErrorLogByTrigger.cs

-
- - - - - - - - - - - - - - - - - - - - -
#LineLine coverage
 1using Functions.Services.Interfaces;
 2using Microsoft.Azure.Functions.Worker;
 3
 4namespace Functions
 5{
 6    public class PurgeErrorLogByTrigger(ILoggingService loggingService)
 7    {
 8        [Function("PurgeErrorLogByTrigger")]
 9        public async Task PurgeErrorLog(
 10            [TimerTrigger("%PurgeErrorLogByTriggerSchedule%", RunOnStartup = false)]
 11            TimerInfo myTimer)
 112        {
 113            await loggingService.PurgeErrorLog();
 114        }
 15    }
 16}
-
-
-
-
-

Methods/Properties

-PurgeErrorLog()
-
-
- \ No newline at end of file diff --git a/source/coverage/Functions_SplunkService.html b/source/coverage/Functions_SplunkService.html deleted file mode 100644 index f2f731c..0000000 --- a/source/coverage/Functions_SplunkService.html +++ /dev/null @@ -1,366 +0,0 @@ - - - - - - - -Functions.Services.SplunkService - Coverage Report - -
-

< Summary

-
-
-
Information
-
-
- - - - - - - - - - - - - -
Class:Functions.Services.SplunkService
Assembly:Functions
File(s):/Users/griordan/git/gpconnect-analytics/source/Functions/Services/SplunkService.cs
-
-
-
-
-
-
-
Line coverage
-
-
78%
-
- - - - - - - - - - - - - - - - - - - - - -
Covered lines:96
Uncovered lines:26
Coverable lines:122
Total lines:181
Line coverage:78.6%
-
-
-
-
-
Branch coverage
-
-
57%
-
- - - - - - - - - - - - - -
Covered branches:8
Total branches:14
Branch coverage:57.1%
-
-
-
-
-
Method coverage
-
-
-

Feature is only available for sponsors

-Upgrade to PRO version -
-
-
-
-

Metrics

-
- ------- - - - - - - - - - - -
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
DownloadCSVDateRangeAsync()100%1181.81%
GetSearchResultFromRequestUri()50%2256.09%
ConstructFilePath(...)75%44100%
ExecuteBatchDownloadFromSplunk()50%6676.47%
HasApiTokenExpired(...)100%11100%
FileTypeEnabled(...)50%22100%
-
-

File(s)

-

/Users/griordan/git/gpconnect-analytics/source/Functions/Services/SplunkService.cs

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#LineLine coverage
 1using System.IdentityModel.Tokens.Jwt;
 2using System.Net.Http.Headers;
 3using System.Text;
 4using Core;
 5using Core.DTOs.Request;
 6using Core.DTOs.Response.Configuration;
 7using Core.DTOs.Response.Splunk;
 8using Core.Helpers;
 9using Core.Services.Interfaces;
 10using Functions.Services.Interfaces;
 11using Microsoft.Extensions.Logging;
 12
 13namespace Functions.Services
 14{
 15    public class SplunkService(
 16        IConfigurationService configurationService,
 17        IHttpClientFactory httpClientFactory,
 18        IImportService importService,
 19        ILogger<SplunkService> logger,
 20        ITimeProvider timeProvider)
 21        : ISplunkService
 22    {
 23        private SplunkClient _splunkClient;
 24        private FilePathConstants _filePathConstants;
 725        private Extract _extract = new();
 26
 27        public async Task<ExtractResponse> DownloadCSVDateRangeAsync(FileType fileType, UriRequest uriRequest,
 28            bool isToday)
 629        {
 30            try
 631            {
 632                _filePathConstants = await configurationService.GetFilePathConstants();
 533                var splunkInstance = await configurationService.GetSplunkInstance(SplunkInstances.cloud);
 34
 535                _extract.Override = true;
 536                _extract.QueryFromDate = uriRequest.EarliestDate;
 537                _extract.QueryToDate = uriRequest.LatestDate;
 538                _extract.QueryHour = uriRequest.Hour;
 39
 540                var filePath = ConstructFilePath(splunkInstance, fileType, isToday, true);
 541                var extractResponse = await GetSearchResultFromRequestUri(uriRequest);
 42
 543                extractResponse.FilePath = filePath;
 544                extractResponse.ExtractRequestDetails = _extract;
 45
 546                return extractResponse;
 47            }
 148            catch (TimeoutException timeoutException)
 149            {
 150                logger.LogError(timeoutException, "A timeout error has occurred");
 151                throw;
 52            }
 053            catch (Exception exc)
 054            {
 055                logger.LogError(exc, "An error occurred in trying to execute a GET request");
 056                throw;
 57            }
 558        }
 59
 60        private async Task<ExtractResponse> GetSearchResultFromRequestUri(UriRequest uriRequest)
 561        {
 562            var extractResponseMessage = new ExtractResponse
 563            {
 564                ExtractResponseMessage = new HttpResponseMessage()
 565            };
 66            try
 567            {
 568                _splunkClient = await configurationService.GetSplunkClientConfiguration();
 469                var apiTokenExpiry = HasApiTokenExpired(_splunkClient.ApiToken);
 70
 171                if (!apiTokenExpiry.Item1)
 072                {
 073                    var client = httpClientFactory.CreateClient("SplunkApiClient");
 074                    client.DefaultRequestHeaders.Authorization =
 075                        new AuthenticationHeaderValue("Bearer", _splunkClient.ApiToken);
 076                    client.Timeout = new TimeSpan(0, 0, _splunkClient.QueryTimeout);
 77
 078                    var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, uriRequest.Request);
 079                    var response = await client.SendAsync(httpRequestMessage);
 080                    var responseStream = await response.Content.ReadAsStreamAsync();
 81
 082                    extractResponseMessage.ExtractResponseStream = responseStream;
 083                    extractResponseMessage.ExtractResponseMessage = response;
 084                    extractResponseMessage.ExtractRequestDetails = _extract;
 085                    extractResponseMessage.UriRequest = uriRequest;
 086                }
 87                else
 188                {
 189                    extractResponseMessage.ExtractResponseMessage.ReasonPhrase =
 190                        $"The authentication token has expired because it is valid up to {apiTokenExpiry.Item2}";
 191                    extractResponseMessage.ExtractResponseMessage.StatusCode = System.Net.HttpStatusCode.Unauthorized;
 192                }
 193            }
 094            catch (OperationCanceledException operationCancelledException)
 095            {
 096                extractResponseMessage.ExtractResponseMessage.ReasonPhrase = operationCancelledException.Message;
 097                extractResponseMessage.ExtractResponseMessage.StatusCode = System.Net.HttpStatusCode.RequestTimeout;
 098            }
 499            catch (Exception exc)
 4100            {
 4101                extractResponseMessage.ExtractResponseMessage.ReasonPhrase = exc.Message;
 4102                extractResponseMessage.ExtractResponseMessage.StatusCode =
 4103                    System.Net.HttpStatusCode.InternalServerError;
 4104            }
 105
 5106            return extractResponseMessage;
 5107        }
 108
 109        private string ConstructFilePath(SplunkInstance splunkInstance, FileType fileType, bool isToday,
 110            bool setDateAsMidnight = false)
 5111        {
 5112            var filePathString = new StringBuilder();
 5113            filePathString.Append(fileType.DirectoryName);
 5114            filePathString.Append(_filePathConstants.PathSeparator);
 5115            filePathString.Append(splunkInstance.Source);
 5116            filePathString.Append(_filePathConstants.PathSeparator);
 5117            filePathString.Append(
 5118                _extract.QueryFromDate.ToString(DateFormatConstants.FilePathQueryDateYearMonth));
 5119            filePathString.Append(_filePathConstants.PathSeparator);
 5120            filePathString.Append(_filePathConstants.ProjectNameFilePrefix);
 5121            filePathString.Append(_filePathConstants.ComponentSeparator);
 5122            filePathString.Append(fileType.FileTypeFilePrefix);
 5123            filePathString.Append(_filePathConstants.ComponentSeparator);
 5124            filePathString.Append(
 5125                $"{_extract.QueryFromDate.ToString(DateFormatConstants.FilePathQueryDate)}T{_extract.QueryHour.ToString(
 5126            filePathString.Append(_filePathConstants.ComponentSeparator);
 5127            filePathString.Append(
 5128                $"{_extract.QueryToDate.ToString(DateFormatConstants.FilePathQueryDate)}T{_extract.QueryHour.ToString(Da
 5129            filePathString.Append(_filePathConstants.ComponentSeparator);
 5130            filePathString.Append(splunkInstance.Source);
 5131            filePathString.Append(_filePathConstants.ComponentSeparator);
 5132            if (!isToday)
 1133            {
 1134                filePathString.Append(setDateAsMidnight
 1135                    ? timeProvider.CurrentDate().ToString(DateFormatConstants.FilePathNowDate)
 1136                    : timeProvider.UtcDateTime().ToString(DateFormatConstants.FilePathNowDate));
 1137            }
 138            else
 4139            {
 4140                filePathString.Append(DateTime.Today.AddDays(1).AddSeconds(-1)
 4141                    .ToString(DateFormatConstants.FilePathNowDate));
 4142            }
 143
 5144            filePathString.Append(_filePathConstants.FileExtension);
 5145            return filePathString.ToString();
 5146        }
 147
 148        public async Task ExecuteBatchDownloadFromSplunk(FileType fileType, UriRequest uriRequest, bool isToday)
 2149        {
 150            try
 2151            {
 2152                if (FileTypeEnabled(fileType))
 1153                {
 1154                    var extractResponse = await DownloadCSVDateRangeAsync(fileType, uriRequest, isToday);
 1155                    await importService.AddObjectFileMessage(fileType, extractResponse);
 1156                }
 157                else
 1158                {
 1159                    logger?.LogWarning(
 1160                        $"Filetype {fileType.FileTypeFilePrefix} is not enabled. Please check if this is correct");
 1161                }
 2162            }
 0163            catch (Exception exc)
 0164            {
 0165                logger?.LogError(exc, $"An error has occurred while attempting to execute an Azure function");
 0166                throw;
 167            }
 2168        }
 169
 170        private (bool, DateTime) HasApiTokenExpired(string apiToken)
 1171        {
 1172            var jwtToken = new JwtSecurityToken(apiToken);
 1173            return (DateTime.UtcNow > jwtToken.ValidTo, jwtToken.ValidTo);
 1174        }
 175
 176        private static bool FileTypeEnabled(FileType fileType)
 2177        {
 2178            return fileType is { Enabled: true };
 2179        }
 180    }
 181}
-
-
-
- \ No newline at end of file diff --git a/source/coverage/Functions_SqlConnectionFactory.html b/source/coverage/Functions_SqlConnectionFactory.html deleted file mode 100644 index fd12539..0000000 --- a/source/coverage/Functions_SqlConnectionFactory.html +++ /dev/null @@ -1,186 +0,0 @@ - - - - - - - -Functions.SqlConnectionFactory - Coverage Report - -
-

< Summary

-
-
-
Information
-
-
- - - - - - - - - - - - - -
Class:Functions.SqlConnectionFactory
Assembly:Functions
File(s):/Users/griordan/git/gpconnect-analytics/source/Functions/SqlConnectionFactory.cs
-
-
-
-
-
-
-
Line coverage
-
-
0%
-
- - - - - - - - - - - - - - - - - - - - - -
Covered lines:0
Uncovered lines:3
Coverable lines:3
Total lines:13
Line coverage:0%
-
-
-
-
-
Branch coverage
-
-
N/A
-
- - - - - - - - - - - - - -
Covered branches:0
Total branches:0
Branch coverage:N/A
-
-
-
-
-
Method coverage
-
-
-

Feature is only available for sponsors

-Upgrade to PRO version -
-
-
-
-

Metrics

-
- ------- - - - - -
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
CreateConnection(...)100%210%
-
-

File(s)

-

/Users/griordan/git/gpconnect-analytics/source/Functions/SqlConnectionFactory.cs

-
- - - - - - - - - - - - - - - - - -
#LineLine coverage
 1using System.Data.Common;
 2using Core;
 3using Microsoft.Data.SqlClient;
 4
 5namespace Functions;
 6
 7public class SqlConnectionFactory : IConnectionFactory
 8{
 9    public DbConnection CreateConnection(string connectionString)
 010    {
 011        return new SqlConnection(connectionString);
 012    }
 13}
-
-
-
-
-

Methods/Properties

-CreateConnection(System.String)
-
-
- \ No newline at end of file diff --git a/source/coverage/Functions_StoreProviderConsumerData.html b/source/coverage/Functions_StoreProviderConsumerData.html deleted file mode 100644 index c6b0d47..0000000 --- a/source/coverage/Functions_StoreProviderConsumerData.html +++ /dev/null @@ -1,242 +0,0 @@ - - - - - - - -Functions.StoreProviderConsumerData - Coverage Report - -
-

< Summary

-
-
-
Information
-
-
- - - - - - - - - - - - - -
Class:Functions.StoreProviderConsumerData
Assembly:Functions
File(s):/Users/griordan/git/gpconnect-analytics/source/Functions/StoreProviderConsumerData.cs
-
-
-
-
-
-
-
Line coverage
-
-
61%
-
- - - - - - - - - - - - - - - - - - - - - -
Covered lines:22
Uncovered lines:14
Coverable lines:36
Total lines:69
Line coverage:61.1%
-
-
-
-
-
Branch coverage
-
-
75%
-
- - - - - - - - - - - - - -
Covered branches:3
Total branches:4
Branch coverage:75%
-
-
-
-
-
Method coverage
-
-
-

Feature is only available for sponsors

-Upgrade to PRO version -
-
-
-
-

Metrics

-
- ------- - - - - -
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
Run()75%5461.11%
-
-

File(s)

-

/Users/griordan/git/gpconnect-analytics/source/Functions/StoreProviderConsumerData.cs

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#LineLine coverage
 1using System.Net;
 2using System.Text.Json;
 3using Core.DTOs.Request;
 4using Core.Repositories;
 5using Microsoft.Azure.Functions.Worker;
 6using Microsoft.Azure.Functions.Worker.Http;
 7using Microsoft.Extensions.Logging;
 8
 9namespace Functions
 10{
 11    public class StoreProviderConsumerData(
 12        IHierarchyProviderConsumerRepo repository,
 13        ILogger<StoreProviderConsumerData> logger)
 14    {
 15        [Function("StoreProviderConsumerData")]
 16        public async Task<HttpResponseData> Run(
 17            [HttpTrigger(AuthorizationLevel.Function, "post", Route = "StoreProviderConsumerData")]
 18            HttpRequestData req)
 419        {
 420            logger.LogInformation("Processing HTTP request.");
 21
 422            var requestBody = await new StreamReader(req.Body).ReadToEndAsync();
 23
 424            if (requestBody.Length == 0)
 325            {
 326                var response = req.CreateResponse(HttpStatusCode.BadRequest);
 327                response.Headers.Add("Content-Type", "text/plain; charset=utf-8");
 328                await response.WriteStringAsync("Request body length is 0");
 329                return response;
 30            }
 31
 132            List<OrganisationHierarchyProvider> records = null;
 33            try
 134            {
 135                records = JsonSerializer.Deserialize<List<OrganisationHierarchyProvider>>(requestBody) ?? throw new
 136                    InvalidOperationException("Unable to deserialize input");
 137            }
 038            catch (JsonException ex)
 039            {
 040                logger.LogError($"Failed to deserialize request body: {ex.Message}");
 041                var response = req.CreateResponse(HttpStatusCode.BadRequest);
 042                response.Headers.Add("Content-Type", "text/plain; charset=utf-8");
 043                await response.WriteStringAsync("Invalid json input");
 044                return response;
 45            }
 46
 47
 48            try
 149            {
 150                logger.LogInformation($"Attempting to save {records.Count} items into databases");
 151                await repository.InsertHierarchyProviderConsumers(records);
 52
 153                var response = req.CreateResponse(HttpStatusCode.OK);
 154                response.Headers.Add("Content-Type", "text/plain; charset=utf-8");
 155                await response.WriteStringAsync("Storing of items successful");
 156                return response;
 57            }
 058            catch (Exception ex)
 059            {
 060                logger.LogError($"Failed to save data to databases: {ex.Message}");
 61
 062                var response = req.CreateResponse(HttpStatusCode.BadRequest);
 063                response.Headers.Add("Content-Type", "text/plain; charset=utf-8");
 064                await response.WriteStringAsync("Failed to save to the database - see logs for more information");
 065                return response;
 66            }
 467        }
 68    }
 69}
-
-
-
-
-

Methods/Properties

-Run()
-
-
- \ No newline at end of file diff --git a/source/coverage/Functions_WorkerExtensionStartupCodeExecutor.html b/source/coverage/Functions_WorkerExtensionStartupCodeExecutor.html deleted file mode 100644 index 8ae3d35..0000000 --- a/source/coverage/Functions_WorkerExtensionStartupCodeExecutor.html +++ /dev/null @@ -1,167 +0,0 @@ - - - - - - - -Functions.WorkerExtensionStartupCodeExecutor - Coverage Report - -
-

< Summary

- -
-
-
Line coverage
-
-
0%
-
- - - - - - - - - - - - - - - - - - - - - -
Covered lines:0
Uncovered lines:9
Coverable lines:9
Total lines:29
Line coverage:0%
-
-
-
-
-
Branch coverage
-
-
N/A
-
- - - - - - - - - - - - - -
Covered branches:0
Total branches:0
Branch coverage:N/A
-
-
-
-
-
Method coverage
-
-
-

Feature is only available for sponsors

-Upgrade to PRO version -
-
-
-
-

Metrics

-
- ------- - - - - -
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
Configure(...)100%210%
-
-

File(s)

-

/Users/griordan/git/gpconnect-analytics/source/Functions/Microsoft.Azure.Functions.Worker.Sdk.Generators/Microsoft.Azure.Functions.Worker.Sdk.Generators.ExtensionStartupRunnerGenerator/WorkerExtensionStartupCodeExecutor.g.cs

-

File '/Users/griordan/git/gpconnect-analytics/source/Functions/Microsoft.Azure.Functions.Worker.Sdk.Generators/Microsoft.Azure.Functions.Worker.Sdk.Generators.ExtensionStartupRunnerGenerator/WorkerExtensionStartupCodeExecutor.g.cs' does not exist (any more).

-
-
- \ No newline at end of file diff --git a/source/coverage/Functions_WorkerHostBuilderFunctionMetadataProviderExtension.html b/source/coverage/Functions_WorkerHostBuilderFunctionMetadataProviderExtension.html deleted file mode 100644 index a719f15..0000000 --- a/source/coverage/Functions_WorkerHostBuilderFunctionMetadataProviderExtension.html +++ /dev/null @@ -1,167 +0,0 @@ - - - - - - - -Functions.WorkerHostBuilderFunctionMetadataProviderExtension - Coverage Report - -
-

< Summary

- -
-
-
Line coverage
-
-
0%
-
- - - - - - - - - - - - - - - - - - - - - -
Covered lines:0
Uncovered lines:7
Coverable lines:7
Total lines:211
Line coverage:0%
-
-
-
-
-
Branch coverage
-
-
N/A
-
- - - - - - - - - - - - - -
Covered branches:0
Total branches:0
Branch coverage:N/A
-
-
-
-
-
Method coverage
-
-
-

Feature is only available for sponsors

-Upgrade to PRO version -
-
-
-
-

Metrics

-
- ------- - - - - -
MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
ConfigureGeneratedFunctionMetadataProvider(...)100%210%
-
-

File(s)

-

/Users/griordan/git/gpconnect-analytics/source/Functions/Microsoft.Azure.Functions.Worker.Sdk.Generators/Microsoft.Azure.Functions.Worker.Sdk.Generators.FunctionMetadataProviderGenerator/GeneratedFunctionMetadataProvider.g.cs

-

File '/Users/griordan/git/gpconnect-analytics/source/Functions/Microsoft.Azure.Functions.Worker.Sdk.Generators/Microsoft.Azure.Functions.Worker.Sdk.Generators.FunctionMetadataProviderGenerator/GeneratedFunctionMetadataProvider.g.cs' does not exist (any more).

-
-
- \ No newline at end of file diff --git a/source/coverage/class.js b/source/coverage/class.js deleted file mode 100644 index b7a43b2..0000000 --- a/source/coverage/class.js +++ /dev/null @@ -1,218 +0,0 @@ -/* Chartist.js 0.11.4 - * Copyright © 2019 Gion Kunz - * Free to use under either the WTFPL license or the MIT license. - * https://raw.githubusercontent.com/gionkunz/chartist-js/master/LICENSE-WTFPL - * https://raw.githubusercontent.com/gionkunz/chartist-js/master/LICENSE-MIT - */ - -!function (a, b) { "function" == typeof define && define.amd ? define("Chartist", [], function () { return a.Chartist = b() }) : "object" == typeof module && module.exports ? module.exports = b() : a.Chartist = b() }(this, function () { - var a = { version: "0.11.4" }; return function (a, b) { "use strict"; var c = a.window, d = a.document; b.namespaces = { svg: "http://www.w3.org/2000/svg", xmlns: "http://www.w3.org/2000/xmlns/", xhtml: "http://www.w3.org/1999/xhtml", xlink: "http://www.w3.org/1999/xlink", ct: "http://gionkunz.github.com/chartist-js/ct" }, b.noop = function (a) { return a }, b.alphaNumerate = function (a) { return String.fromCharCode(97 + a % 26) }, b.extend = function (a) { var c, d, e; for (a = a || {}, c = 1; c < arguments.length; c++) { d = arguments[c]; for (var f in d) e = d[f], "object" != typeof e || null === e || e instanceof Array ? a[f] = e : a[f] = b.extend(a[f], e) } return a }, b.replaceAll = function (a, b, c) { return a.replace(new RegExp(b, "g"), c) }, b.ensureUnit = function (a, b) { return "number" == typeof a && (a += b), a }, b.quantity = function (a) { if ("string" == typeof a) { var b = /^(\d+)\s*(.*)$/g.exec(a); return { value: +b[1], unit: b[2] || void 0 } } return { value: a } }, b.querySelector = function (a) { return a instanceof Node ? a : d.querySelector(a) }, b.times = function (a) { return Array.apply(null, new Array(a)) }, b.sum = function (a, b) { return a + (b ? b : 0) }, b.mapMultiply = function (a) { return function (b) { return b * a } }, b.mapAdd = function (a) { return function (b) { return b + a } }, b.serialMap = function (a, c) { var d = [], e = Math.max.apply(null, a.map(function (a) { return a.length })); return b.times(e).forEach(function (b, e) { var f = a.map(function (a) { return a[e] }); d[e] = c.apply(null, f) }), d }, b.roundWithPrecision = function (a, c) { var d = Math.pow(10, c || b.precision); return Math.round(a * d) / d }, b.precision = 8, b.escapingMap = { "&": "&", "<": "<", ">": ">", '"': """, "'": "'" }, b.serialize = function (a) { return null === a || void 0 === a ? a : ("number" == typeof a ? a = "" + a : "object" == typeof a && (a = JSON.stringify({ data: a })), Object.keys(b.escapingMap).reduce(function (a, c) { return b.replaceAll(a, c, b.escapingMap[c]) }, a)) }, b.deserialize = function (a) { if ("string" != typeof a) return a; a = Object.keys(b.escapingMap).reduce(function (a, c) { return b.replaceAll(a, b.escapingMap[c], c) }, a); try { a = JSON.parse(a), a = void 0 !== a.data ? a.data : a } catch (c) { } return a }, b.createSvg = function (a, c, d, e) { var f; return c = c || "100%", d = d || "100%", Array.prototype.slice.call(a.querySelectorAll("svg")).filter(function (a) { return a.getAttributeNS(b.namespaces.xmlns, "ct") }).forEach(function (b) { a.removeChild(b) }), f = new b.Svg("svg").attr({ width: c, height: d }).addClass(e), f._node.style.width = c, f._node.style.height = d, a.appendChild(f._node), f }, b.normalizeData = function (a, c, d) { var e, f = { raw: a, normalized: {} }; return f.normalized.series = b.getDataArray({ series: a.series || [] }, c, d), e = f.normalized.series.every(function (a) { return a instanceof Array }) ? Math.max.apply(null, f.normalized.series.map(function (a) { return a.length })) : f.normalized.series.length, f.normalized.labels = (a.labels || []).slice(), Array.prototype.push.apply(f.normalized.labels, b.times(Math.max(0, e - f.normalized.labels.length)).map(function () { return "" })), c && b.reverseData(f.normalized), f }, b.safeHasProperty = function (a, b) { return null !== a && "object" == typeof a && a.hasOwnProperty(b) }, b.isDataHoleValue = function (a) { return null === a || void 0 === a || "number" == typeof a && isNaN(a) }, b.reverseData = function (a) { a.labels.reverse(), a.series.reverse(); for (var b = 0; b < a.series.length; b++)"object" == typeof a.series[b] && void 0 !== a.series[b].data ? a.series[b].data.reverse() : a.series[b] instanceof Array && a.series[b].reverse() }, b.getDataArray = function (a, c, d) { function e(a) { if (b.safeHasProperty(a, "value")) return e(a.value); if (b.safeHasProperty(a, "data")) return e(a.data); if (a instanceof Array) return a.map(e); if (!b.isDataHoleValue(a)) { if (d) { var c = {}; return "string" == typeof d ? c[d] = b.getNumberOrUndefined(a) : c.y = b.getNumberOrUndefined(a), c.x = a.hasOwnProperty("x") ? b.getNumberOrUndefined(a.x) : c.x, c.y = a.hasOwnProperty("y") ? b.getNumberOrUndefined(a.y) : c.y, c } return b.getNumberOrUndefined(a) } } return a.series.map(e) }, b.normalizePadding = function (a, b) { return b = b || 0, "number" == typeof a ? { top: a, right: a, bottom: a, left: a } : { top: "number" == typeof a.top ? a.top : b, right: "number" == typeof a.right ? a.right : b, bottom: "number" == typeof a.bottom ? a.bottom : b, left: "number" == typeof a.left ? a.left : b } }, b.getMetaData = function (a, b) { var c = a.data ? a.data[b] : a[b]; return c ? c.meta : void 0 }, b.orderOfMagnitude = function (a) { return Math.floor(Math.log(Math.abs(a)) / Math.LN10) }, b.projectLength = function (a, b, c) { return b / c.range * a }, b.getAvailableHeight = function (a, c) { return Math.max((b.quantity(c.height).value || a.height()) - (c.chartPadding.top + c.chartPadding.bottom) - c.axisX.offset, 0) }, b.getHighLow = function (a, c, d) { function e(a) { if (void 0 !== a) if (a instanceof Array) for (var b = 0; b < a.length; b++)e(a[b]); else { var c = d ? +a[d] : +a; g && c > f.high && (f.high = c), h && c < f.low && (f.low = c) } } c = b.extend({}, c, d ? c["axis" + d.toUpperCase()] : {}); var f = { high: void 0 === c.high ? -Number.MAX_VALUE : +c.high, low: void 0 === c.low ? Number.MAX_VALUE : +c.low }, g = void 0 === c.high, h = void 0 === c.low; return (g || h) && e(a), (c.referenceValue || 0 === c.referenceValue) && (f.high = Math.max(c.referenceValue, f.high), f.low = Math.min(c.referenceValue, f.low)), f.high <= f.low && (0 === f.low ? f.high = 1 : f.low < 0 ? f.high = 0 : f.high > 0 ? f.low = 0 : (f.high = 1, f.low = 0)), f }, b.isNumeric = function (a) { return null !== a && isFinite(a) }, b.isFalseyButZero = function (a) { return !a && 0 !== a }, b.getNumberOrUndefined = function (a) { return b.isNumeric(a) ? +a : void 0 }, b.isMultiValue = function (a) { return "object" == typeof a && ("x" in a || "y" in a) }, b.getMultiValue = function (a, c) { return b.isMultiValue(a) ? b.getNumberOrUndefined(a[c || "y"]) : b.getNumberOrUndefined(a) }, b.rho = function (a) { function b(a, c) { return a % c === 0 ? c : b(c, a % c) } function c(a) { return a * a + 1 } if (1 === a) return a; var d, e = 2, f = 2; if (a % 2 === 0) return 2; do e = c(e) % a, f = c(c(f)) % a, d = b(Math.abs(e - f), a); while (1 === d); return d }, b.getBounds = function (a, c, d, e) { function f(a, b) { return a === (a += b) && (a *= 1 + (b > 0 ? o : -o)), a } var g, h, i, j = 0, k = { high: c.high, low: c.low }; k.valueRange = k.high - k.low, k.oom = b.orderOfMagnitude(k.valueRange), k.step = Math.pow(10, k.oom), k.min = Math.floor(k.low / k.step) * k.step, k.max = Math.ceil(k.high / k.step) * k.step, k.range = k.max - k.min, k.numberOfSteps = Math.round(k.range / k.step); var l = b.projectLength(a, k.step, k), m = l < d, n = e ? b.rho(k.range) : 0; if (e && b.projectLength(a, 1, k) >= d) k.step = 1; else if (e && n < k.step && b.projectLength(a, n, k) >= d) k.step = n; else for (; ;) { if (m && b.projectLength(a, k.step, k) <= d) k.step *= 2; else { if (m || !(b.projectLength(a, k.step / 2, k) >= d)) break; if (k.step /= 2, e && k.step % 1 !== 0) { k.step *= 2; break } } if (j++ > 1e3) throw new Error("Exceeded maximum number of iterations while optimizing scale step!") } var o = 2.221e-16; for (k.step = Math.max(k.step, o), h = k.min, i = k.max; h + k.step <= k.low;)h = f(h, k.step); for (; i - k.step >= k.high;)i = f(i, -k.step); k.min = h, k.max = i, k.range = k.max - k.min; var p = []; for (g = k.min; g <= k.max; g = f(g, k.step)) { var q = b.roundWithPrecision(g); q !== p[p.length - 1] && p.push(q) } return k.values = p, k }, b.polarToCartesian = function (a, b, c, d) { var e = (d - 90) * Math.PI / 180; return { x: a + c * Math.cos(e), y: b + c * Math.sin(e) } }, b.createChartRect = function (a, c, d) { var e = !(!c.axisX && !c.axisY), f = e ? c.axisY.offset : 0, g = e ? c.axisX.offset : 0, h = a.width() || b.quantity(c.width).value || 0, i = a.height() || b.quantity(c.height).value || 0, j = b.normalizePadding(c.chartPadding, d); h = Math.max(h, f + j.left + j.right), i = Math.max(i, g + j.top + j.bottom); var k = { padding: j, width: function () { return this.x2 - this.x1 }, height: function () { return this.y1 - this.y2 } }; return e ? ("start" === c.axisX.position ? (k.y2 = j.top + g, k.y1 = Math.max(i - j.bottom, k.y2 + 1)) : (k.y2 = j.top, k.y1 = Math.max(i - j.bottom - g, k.y2 + 1)), "start" === c.axisY.position ? (k.x1 = j.left + f, k.x2 = Math.max(h - j.right, k.x1 + 1)) : (k.x1 = j.left, k.x2 = Math.max(h - j.right - f, k.x1 + 1))) : (k.x1 = j.left, k.x2 = Math.max(h - j.right, k.x1 + 1), k.y2 = j.top, k.y1 = Math.max(i - j.bottom, k.y2 + 1)), k }, b.createGrid = function (a, c, d, e, f, g, h, i) { var j = {}; j[d.units.pos + "1"] = a, j[d.units.pos + "2"] = a, j[d.counterUnits.pos + "1"] = e, j[d.counterUnits.pos + "2"] = e + f; var k = g.elem("line", j, h.join(" ")); i.emit("draw", b.extend({ type: "grid", axis: d, index: c, group: g, element: k }, j)) }, b.createGridBackground = function (a, b, c, d) { var e = a.elem("rect", { x: b.x1, y: b.y2, width: b.width(), height: b.height() }, c, !0); d.emit("draw", { type: "gridBackground", group: a, element: e }) }, b.createLabel = function (a, c, e, f, g, h, i, j, k, l, m) { var n, o = {}; if (o[g.units.pos] = a + i[g.units.pos], o[g.counterUnits.pos] = i[g.counterUnits.pos], o[g.units.len] = c, o[g.counterUnits.len] = Math.max(0, h - 10), l) { var p = d.createElement("span"); p.className = k.join(" "), p.setAttribute("xmlns", b.namespaces.xhtml), p.innerText = f[e], p.style[g.units.len] = Math.round(o[g.units.len]) + "px", p.style[g.counterUnits.len] = Math.round(o[g.counterUnits.len]) + "px", n = j.foreignObject(p, b.extend({ style: "overflow: visible;" }, o)) } else n = j.elem("text", o, k.join(" ")).text(f[e]); m.emit("draw", b.extend({ type: "label", axis: g, index: e, group: j, element: n, text: f[e] }, o)) }, b.getSeriesOption = function (a, b, c) { if (a.name && b.series && b.series[a.name]) { var d = b.series[a.name]; return d.hasOwnProperty(c) ? d[c] : b[c] } return b[c] }, b.optionsProvider = function (a, d, e) { function f(a) { var f = h; if (h = b.extend({}, j), d) for (i = 0; i < d.length; i++) { var g = c.matchMedia(d[i][0]); g.matches && (h = b.extend(h, d[i][1])) } e && a && e.emit("optionsChanged", { previousOptions: f, currentOptions: h }) } function g() { k.forEach(function (a) { a.removeListener(f) }) } var h, i, j = b.extend({}, a), k = []; if (!c.matchMedia) throw "window.matchMedia not found! Make sure you're using a polyfill."; if (d) for (i = 0; i < d.length; i++) { var l = c.matchMedia(d[i][0]); l.addListener(f), k.push(l) } return f(), { removeMediaQueryListeners: g, getCurrentOptions: function () { return b.extend({}, h) } } }, b.splitIntoSegments = function (a, c, d) { var e = { increasingX: !1, fillHoles: !1 }; d = b.extend({}, e, d); for (var f = [], g = !0, h = 0; h < a.length; h += 2)void 0 === b.getMultiValue(c[h / 2].value) ? d.fillHoles || (g = !0) : (d.increasingX && h >= 2 && a[h] <= a[h - 2] && (g = !0), g && (f.push({ pathCoordinates: [], valueData: [] }), g = !1), f[f.length - 1].pathCoordinates.push(a[h], a[h + 1]), f[f.length - 1].valueData.push(c[h / 2])); return f } }(this || global, a), function (a, b) { "use strict"; b.Interpolation = {}, b.Interpolation.none = function (a) { var c = { fillHoles: !1 }; return a = b.extend({}, c, a), function (c, d) { for (var e = new b.Svg.Path, f = !0, g = 0; g < c.length; g += 2) { var h = c[g], i = c[g + 1], j = d[g / 2]; void 0 !== b.getMultiValue(j.value) ? (f ? e.move(h, i, !1, j) : e.line(h, i, !1, j), f = !1) : a.fillHoles || (f = !0) } return e } }, b.Interpolation.simple = function (a) { var c = { divisor: 2, fillHoles: !1 }; a = b.extend({}, c, a); var d = 1 / Math.max(1, a.divisor); return function (c, e) { for (var f, g, h, i = new b.Svg.Path, j = 0; j < c.length; j += 2) { var k = c[j], l = c[j + 1], m = (k - f) * d, n = e[j / 2]; void 0 !== n.value ? (void 0 === h ? i.move(k, l, !1, n) : i.curve(f + m, g, k - m, l, k, l, !1, n), f = k, g = l, h = n) : a.fillHoles || (f = k = h = void 0) } return i } }, b.Interpolation.cardinal = function (a) { var c = { tension: 1, fillHoles: !1 }; a = b.extend({}, c, a); var d = Math.min(1, Math.max(0, a.tension)), e = 1 - d; return function f(c, g) { var h = b.splitIntoSegments(c, g, { fillHoles: a.fillHoles }); if (h.length) { if (h.length > 1) { var i = []; return h.forEach(function (a) { i.push(f(a.pathCoordinates, a.valueData)) }), b.Svg.Path.join(i) } if (c = h[0].pathCoordinates, g = h[0].valueData, c.length <= 4) return b.Interpolation.none()(c, g); for (var j, k = (new b.Svg.Path).move(c[0], c[1], !1, g[0]), l = 0, m = c.length; m - 2 * !j > l; l += 2) { var n = [{ x: +c[l - 2], y: +c[l - 1] }, { x: +c[l], y: +c[l + 1] }, { x: +c[l + 2], y: +c[l + 3] }, { x: +c[l + 4], y: +c[l + 5] }]; j ? l ? m - 4 === l ? n[3] = { x: +c[0], y: +c[1] } : m - 2 === l && (n[2] = { x: +c[0], y: +c[1] }, n[3] = { x: +c[2], y: +c[3] }) : n[0] = { x: +c[m - 2], y: +c[m - 1] } : m - 4 === l ? n[3] = n[2] : l || (n[0] = { x: +c[l], y: +c[l + 1] }), k.curve(d * (-n[0].x + 6 * n[1].x + n[2].x) / 6 + e * n[2].x, d * (-n[0].y + 6 * n[1].y + n[2].y) / 6 + e * n[2].y, d * (n[1].x + 6 * n[2].x - n[3].x) / 6 + e * n[2].x, d * (n[1].y + 6 * n[2].y - n[3].y) / 6 + e * n[2].y, n[2].x, n[2].y, !1, g[(l + 2) / 2]) } return k } return b.Interpolation.none()([]) } }, b.Interpolation.monotoneCubic = function (a) { var c = { fillHoles: !1 }; return a = b.extend({}, c, a), function d(c, e) { var f = b.splitIntoSegments(c, e, { fillHoles: a.fillHoles, increasingX: !0 }); if (f.length) { if (f.length > 1) { var g = []; return f.forEach(function (a) { g.push(d(a.pathCoordinates, a.valueData)) }), b.Svg.Path.join(g) } if (c = f[0].pathCoordinates, e = f[0].valueData, c.length <= 4) return b.Interpolation.none()(c, e); var h, i, j = [], k = [], l = c.length / 2, m = [], n = [], o = [], p = []; for (h = 0; h < l; h++)j[h] = c[2 * h], k[h] = c[2 * h + 1]; for (h = 0; h < l - 1; h++)o[h] = k[h + 1] - k[h], p[h] = j[h + 1] - j[h], n[h] = o[h] / p[h]; for (m[0] = n[0], m[l - 1] = n[l - 2], h = 1; h < l - 1; h++)0 === n[h] || 0 === n[h - 1] || n[h - 1] > 0 != n[h] > 0 ? m[h] = 0 : (m[h] = 3 * (p[h - 1] + p[h]) / ((2 * p[h] + p[h - 1]) / n[h - 1] + (p[h] + 2 * p[h - 1]) / n[h]), isFinite(m[h]) || (m[h] = 0)); for (i = (new b.Svg.Path).move(j[0], k[0], !1, e[0]), h = 0; h < l - 1; h++)i.curve(j[h] + p[h] / 3, k[h] + m[h] * p[h] / 3, j[h + 1] - p[h] / 3, k[h + 1] - m[h + 1] * p[h] / 3, j[h + 1], k[h + 1], !1, e[h + 1]); return i } return b.Interpolation.none()([]) } }, b.Interpolation.step = function (a) { var c = { postpone: !0, fillHoles: !1 }; return a = b.extend({}, c, a), function (c, d) { for (var e, f, g, h = new b.Svg.Path, i = 0; i < c.length; i += 2) { var j = c[i], k = c[i + 1], l = d[i / 2]; void 0 !== l.value ? (void 0 === g ? h.move(j, k, !1, l) : (a.postpone ? h.line(j, f, !1, g) : h.line(e, k, !1, l), h.line(j, k, !1, l)), e = j, f = k, g = l) : a.fillHoles || (e = f = g = void 0) } return h } } }(this || global, a), function (a, b) { "use strict"; b.EventEmitter = function () { function a(a, b) { d[a] = d[a] || [], d[a].push(b) } function b(a, b) { d[a] && (b ? (d[a].splice(d[a].indexOf(b), 1), 0 === d[a].length && delete d[a]) : delete d[a]) } function c(a, b) { d[a] && d[a].forEach(function (a) { a(b) }), d["*"] && d["*"].forEach(function (c) { c(a, b) }) } var d = []; return { addEventHandler: a, removeEventHandler: b, emit: c } } }(this || global, a), function (a, b) { "use strict"; function c(a) { var b = []; if (a.length) for (var c = 0; c < a.length; c++)b.push(a[c]); return b } function d(a, c) { var d = c || this.prototype || b.Class, e = Object.create(d); b.Class.cloneDefinitions(e, a); var f = function () { var a, c = e.constructor || function () { }; return a = this === b ? Object.create(e) : this, c.apply(a, Array.prototype.slice.call(arguments, 0)), a }; return f.prototype = e, f["super"] = d, f.extend = this.extend, f } function e() { var a = c(arguments), b = a[0]; return a.splice(1, a.length - 1).forEach(function (a) { Object.getOwnPropertyNames(a).forEach(function (c) { delete b[c], Object.defineProperty(b, c, Object.getOwnPropertyDescriptor(a, c)) }) }), b } b.Class = { extend: d, cloneDefinitions: e } }(this || global, a), function (a, b) { "use strict"; function c(a, c, d) { return a && (this.data = a || {}, this.data.labels = this.data.labels || [], this.data.series = this.data.series || [], this.eventEmitter.emit("data", { type: "update", data: this.data })), c && (this.options = b.extend({}, d ? this.options : this.defaultOptions, c), this.initializeTimeoutId || (this.optionsProvider.removeMediaQueryListeners(), this.optionsProvider = b.optionsProvider(this.options, this.responsiveOptions, this.eventEmitter))), this.initializeTimeoutId || this.createChart(this.optionsProvider.getCurrentOptions()), this } function d() { return this.initializeTimeoutId ? i.clearTimeout(this.initializeTimeoutId) : (i.removeEventListener("resize", this.resizeListener), this.optionsProvider.removeMediaQueryListeners()), this } function e(a, b) { return this.eventEmitter.addEventHandler(a, b), this } function f(a, b) { return this.eventEmitter.removeEventHandler(a, b), this } function g() { i.addEventListener("resize", this.resizeListener), this.optionsProvider = b.optionsProvider(this.options, this.responsiveOptions, this.eventEmitter), this.eventEmitter.addEventHandler("optionsChanged", function () { this.update() }.bind(this)), this.options.plugins && this.options.plugins.forEach(function (a) { a instanceof Array ? a[0](this, a[1]) : a(this) }.bind(this)), this.eventEmitter.emit("data", { type: "initial", data: this.data }), this.createChart(this.optionsProvider.getCurrentOptions()), this.initializeTimeoutId = void 0 } function h(a, c, d, e, f) { this.container = b.querySelector(a), this.data = c || {}, this.data.labels = this.data.labels || [], this.data.series = this.data.series || [], this.defaultOptions = d, this.options = e, this.responsiveOptions = f, this.eventEmitter = b.EventEmitter(), this.supportsForeignObject = b.Svg.isSupported("Extensibility"), this.supportsAnimations = b.Svg.isSupported("AnimationEventsAttribute"), this.resizeListener = function () { this.update() }.bind(this), this.container && (this.container.__chartist__ && this.container.__chartist__.detach(), this.container.__chartist__ = this), this.initializeTimeoutId = setTimeout(g.bind(this), 0) } var i = a.window; b.Base = b.Class.extend({ constructor: h, optionsProvider: void 0, container: void 0, svg: void 0, eventEmitter: void 0, createChart: function () { throw new Error("Base chart type can't be instantiated!") }, update: c, detach: d, on: e, off: f, version: b.version, supportsForeignObject: !1 }) }(this || global, a), function (a, b) { "use strict"; function c(a, c, d, e, f) { a instanceof Element ? this._node = a : (this._node = y.createElementNS(b.namespaces.svg, a), "svg" === a && this.attr({ "xmlns:ct": b.namespaces.ct })), c && this.attr(c), d && this.addClass(d), e && (f && e._node.firstChild ? e._node.insertBefore(this._node, e._node.firstChild) : e._node.appendChild(this._node)) } function d(a, c) { return "string" == typeof a ? c ? this._node.getAttributeNS(c, a) : this._node.getAttribute(a) : (Object.keys(a).forEach(function (c) { if (void 0 !== a[c]) if (c.indexOf(":") !== -1) { var d = c.split(":"); this._node.setAttributeNS(b.namespaces[d[0]], c, a[c]) } else this._node.setAttribute(c, a[c]) }.bind(this)), this) } function e(a, c, d, e) { return new b.Svg(a, c, d, this, e) } function f() { return this._node.parentNode instanceof SVGElement ? new b.Svg(this._node.parentNode) : null } function g() { for (var a = this._node; "svg" !== a.nodeName;)a = a.parentNode; return new b.Svg(a) } function h(a) { var c = this._node.querySelector(a); return c ? new b.Svg(c) : null } function i(a) { var c = this._node.querySelectorAll(a); return c.length ? new b.Svg.List(c) : null } function j() { return this._node } function k(a, c, d, e) { if ("string" == typeof a) { var f = y.createElement("div"); f.innerHTML = a, a = f.firstChild } a.setAttribute("xmlns", b.namespaces.xmlns); var g = this.elem("foreignObject", c, d, e); return g._node.appendChild(a), g } function l(a) { return this._node.appendChild(y.createTextNode(a)), this } function m() { for (; this._node.firstChild;)this._node.removeChild(this._node.firstChild); return this } function n() { return this._node.parentNode.removeChild(this._node), this.parent() } function o(a) { return this._node.parentNode.replaceChild(a._node, this._node), a } function p(a, b) { return b && this._node.firstChild ? this._node.insertBefore(a._node, this._node.firstChild) : this._node.appendChild(a._node), this } function q() { return this._node.getAttribute("class") ? this._node.getAttribute("class").trim().split(/\s+/) : [] } function r(a) { return this._node.setAttribute("class", this.classes(this._node).concat(a.trim().split(/\s+/)).filter(function (a, b, c) { return c.indexOf(a) === b }).join(" ")), this } function s(a) { var b = a.trim().split(/\s+/); return this._node.setAttribute("class", this.classes(this._node).filter(function (a) { return b.indexOf(a) === -1 }).join(" ")), this } function t() { return this._node.setAttribute("class", ""), this } function u() { return this._node.getBoundingClientRect().height } function v() { return this._node.getBoundingClientRect().width } function w(a, c, d) { return void 0 === c && (c = !0), Object.keys(a).forEach(function (e) { function f(a, c) { var f, g, h, i = {}; a.easing && (h = a.easing instanceof Array ? a.easing : b.Svg.Easing[a.easing], delete a.easing), a.begin = b.ensureUnit(a.begin, "ms"), a.dur = b.ensureUnit(a.dur, "ms"), h && (a.calcMode = "spline", a.keySplines = h.join(" "), a.keyTimes = "0;1"), c && (a.fill = "freeze", i[e] = a.from, this.attr(i), g = b.quantity(a.begin || 0).value, a.begin = "indefinite"), f = this.elem("animate", b.extend({ attributeName: e }, a)), c && setTimeout(function () { try { f._node.beginElement() } catch (b) { i[e] = a.to, this.attr(i), f.remove() } }.bind(this), g), d && f._node.addEventListener("beginEvent", function () { d.emit("animationBegin", { element: this, animate: f._node, params: a }) }.bind(this)), f._node.addEventListener("endEvent", function () { d && d.emit("animationEnd", { element: this, animate: f._node, params: a }), c && (i[e] = a.to, this.attr(i), f.remove()) }.bind(this)) } a[e] instanceof Array ? a[e].forEach(function (a) { f.bind(this)(a, !1) }.bind(this)) : f.bind(this)(a[e], c) }.bind(this)), this } function x(a) { var c = this; this.svgElements = []; for (var d = 0; d < a.length; d++)this.svgElements.push(new b.Svg(a[d])); Object.keys(b.Svg.prototype).filter(function (a) { return ["constructor", "parent", "querySelector", "querySelectorAll", "replace", "append", "classes", "height", "width"].indexOf(a) === -1 }).forEach(function (a) { c[a] = function () { var d = Array.prototype.slice.call(arguments, 0); return c.svgElements.forEach(function (c) { b.Svg.prototype[a].apply(c, d) }), c } }) } var y = a.document; b.Svg = b.Class.extend({ constructor: c, attr: d, elem: e, parent: f, root: g, querySelector: h, querySelectorAll: i, getNode: j, foreignObject: k, text: l, empty: m, remove: n, replace: o, append: p, classes: q, addClass: r, removeClass: s, removeAllClasses: t, height: u, width: v, animate: w }), b.Svg.isSupported = function (a) { return y.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#" + a, "1.1") }; var z = { easeInSine: [.47, 0, .745, .715], easeOutSine: [.39, .575, .565, 1], easeInOutSine: [.445, .05, .55, .95], easeInQuad: [.55, .085, .68, .53], easeOutQuad: [.25, .46, .45, .94], easeInOutQuad: [.455, .03, .515, .955], easeInCubic: [.55, .055, .675, .19], easeOutCubic: [.215, .61, .355, 1], easeInOutCubic: [.645, .045, .355, 1], easeInQuart: [.895, .03, .685, .22], easeOutQuart: [.165, .84, .44, 1], easeInOutQuart: [.77, 0, .175, 1], easeInQuint: [.755, .05, .855, .06], easeOutQuint: [.23, 1, .32, 1], easeInOutQuint: [.86, 0, .07, 1], easeInExpo: [.95, .05, .795, .035], easeOutExpo: [.19, 1, .22, 1], easeInOutExpo: [1, 0, 0, 1], easeInCirc: [.6, .04, .98, .335], easeOutCirc: [.075, .82, .165, 1], easeInOutCirc: [.785, .135, .15, .86], easeInBack: [.6, -.28, .735, .045], easeOutBack: [.175, .885, .32, 1.275], easeInOutBack: [.68, -.55, .265, 1.55] }; b.Svg.Easing = z, b.Svg.List = b.Class.extend({ constructor: x }) }(this || global, a), function (a, b) { "use strict"; function c(a, c, d, e, f, g) { var h = b.extend({ command: f ? a.toLowerCase() : a.toUpperCase() }, c, g ? { data: g } : {}); d.splice(e, 0, h) } function d(a, b) { a.forEach(function (c, d) { t[c.command.toLowerCase()].forEach(function (e, f) { b(c, e, d, f, a) }) }) } function e(a, c) { this.pathElements = [], this.pos = 0, this.close = a, this.options = b.extend({}, u, c) } function f(a) { return void 0 !== a ? (this.pos = Math.max(0, Math.min(this.pathElements.length, a)), this) : this.pos } function g(a) { return this.pathElements.splice(this.pos, a), this } function h(a, b, d, e) { return c("M", { x: +a, y: +b }, this.pathElements, this.pos++, d, e), this } function i(a, b, d, e) { return c("L", { x: +a, y: +b }, this.pathElements, this.pos++, d, e), this } function j(a, b, d, e, f, g, h, i) { return c("C", { x1: +a, y1: +b, x2: +d, y2: +e, x: +f, y: +g }, this.pathElements, this.pos++, h, i), this } function k(a, b, d, e, f, g, h, i, j) { return c("A", { rx: +a, ry: +b, xAr: +d, lAf: +e, sf: +f, x: +g, y: +h }, this.pathElements, this.pos++, i, j), this } function l(a) { var c = a.replace(/([A-Za-z])([0-9])/g, "$1 $2").replace(/([0-9])([A-Za-z])/g, "$1 $2").split(/[\s,]+/).reduce(function (a, b) { return b.match(/[A-Za-z]/) && a.push([]), a[a.length - 1].push(b), a }, []); "Z" === c[c.length - 1][0].toUpperCase() && c.pop(); var d = c.map(function (a) { var c = a.shift(), d = t[c.toLowerCase()]; return b.extend({ command: c }, d.reduce(function (b, c, d) { return b[c] = +a[d], b }, {})) }), e = [this.pos, 0]; return Array.prototype.push.apply(e, d), Array.prototype.splice.apply(this.pathElements, e), this.pos += d.length, this } function m() { var a = Math.pow(10, this.options.accuracy); return this.pathElements.reduce(function (b, c) { var d = t[c.command.toLowerCase()].map(function (b) { return this.options.accuracy ? Math.round(c[b] * a) / a : c[b] }.bind(this)); return b + c.command + d.join(",") }.bind(this), "") + (this.close ? "Z" : "") } function n(a, b) { return d(this.pathElements, function (c, d) { c[d] *= "x" === d[0] ? a : b }), this } function o(a, b) { return d(this.pathElements, function (c, d) { c[d] += "x" === d[0] ? a : b }), this } function p(a) { return d(this.pathElements, function (b, c, d, e, f) { var g = a(b, c, d, e, f); (g || 0 === g) && (b[c] = g) }), this } function q(a) { var c = new b.Svg.Path(a || this.close); return c.pos = this.pos, c.pathElements = this.pathElements.slice().map(function (a) { return b.extend({}, a) }), c.options = b.extend({}, this.options), c } function r(a) { var c = [new b.Svg.Path]; return this.pathElements.forEach(function (d) { d.command === a.toUpperCase() && 0 !== c[c.length - 1].pathElements.length && c.push(new b.Svg.Path), c[c.length - 1].pathElements.push(d) }), c } function s(a, c, d) { for (var e = new b.Svg.Path(c, d), f = 0; f < a.length; f++)for (var g = a[f], h = 0; h < g.pathElements.length; h++)e.pathElements.push(g.pathElements[h]); return e } var t = { m: ["x", "y"], l: ["x", "y"], c: ["x1", "y1", "x2", "y2", "x", "y"], a: ["rx", "ry", "xAr", "lAf", "sf", "x", "y"] }, u = { accuracy: 3 }; b.Svg.Path = b.Class.extend({ constructor: e, position: f, remove: g, move: h, line: i, curve: j, arc: k, scale: n, translate: o, transform: p, parse: l, stringify: m, clone: q, splitByCommand: r }), b.Svg.Path.elementDescriptions = t, b.Svg.Path.join = s }(this || global, a), function (a, b) { "use strict"; function c(a, b, c, d) { this.units = a, this.counterUnits = a === e.x ? e.y : e.x, this.chartRect = b, this.axisLength = b[a.rectEnd] - b[a.rectStart], this.gridOffset = b[a.rectOffset], this.ticks = c, this.options = d } function d(a, c, d, e, f) { var g = e["axis" + this.units.pos.toUpperCase()], h = this.ticks.map(this.projectValue.bind(this)), i = this.ticks.map(g.labelInterpolationFnc); h.forEach(function (j, k) { var l, m = { x: 0, y: 0 }; l = h[k + 1] ? h[k + 1] - j : Math.max(this.axisLength - j, 30), b.isFalseyButZero(i[k]) && "" !== i[k] || ("x" === this.units.pos ? (j = this.chartRect.x1 + j, m.x = e.axisX.labelOffset.x, "start" === e.axisX.position ? m.y = this.chartRect.padding.top + e.axisX.labelOffset.y + (d ? 5 : 20) : m.y = this.chartRect.y1 + e.axisX.labelOffset.y + (d ? 5 : 20)) : (j = this.chartRect.y1 - j, m.y = e.axisY.labelOffset.y - (d ? l : 0), "start" === e.axisY.position ? m.x = d ? this.chartRect.padding.left + e.axisY.labelOffset.x : this.chartRect.x1 - 10 : m.x = this.chartRect.x2 + e.axisY.labelOffset.x + 10), g.showGrid && b.createGrid(j, k, this, this.gridOffset, this.chartRect[this.counterUnits.len](), a, [e.classNames.grid, e.classNames[this.units.dir]], f), g.showLabel && b.createLabel(j, l, k, i, this, g.offset, m, c, [e.classNames.label, e.classNames[this.units.dir], "start" === g.position ? e.classNames[g.position] : e.classNames.end], d, f)) }.bind(this)) } var e = (a.window, a.document, { x: { pos: "x", len: "width", dir: "horizontal", rectStart: "x1", rectEnd: "x2", rectOffset: "y2" }, y: { pos: "y", len: "height", dir: "vertical", rectStart: "y2", rectEnd: "y1", rectOffset: "x1" } }); b.Axis = b.Class.extend({ constructor: c, createGridAndLabels: d, projectValue: function (a, b, c) { throw new Error("Base axis can't be instantiated!") } }), b.Axis.units = e }(this || global, a), function (a, b) { "use strict"; function c(a, c, d, e) { var f = e.highLow || b.getHighLow(c, e, a.pos); this.bounds = b.getBounds(d[a.rectEnd] - d[a.rectStart], f, e.scaleMinSpace || 20, e.onlyInteger), this.range = { min: this.bounds.min, max: this.bounds.max }, b.AutoScaleAxis["super"].constructor.call(this, a, d, this.bounds.values, e) } function d(a) { return this.axisLength * (+b.getMultiValue(a, this.units.pos) - this.bounds.min) / this.bounds.range } a.window, a.document; b.AutoScaleAxis = b.Axis.extend({ constructor: c, projectValue: d }) }(this || global, a), function (a, b) { "use strict"; function c(a, c, d, e) { var f = e.highLow || b.getHighLow(c, e, a.pos); this.divisor = e.divisor || 1, this.ticks = e.ticks || b.times(this.divisor).map(function (a, b) { return f.low + (f.high - f.low) / this.divisor * b }.bind(this)), this.ticks.sort(function (a, b) { return a - b }), this.range = { min: f.low, max: f.high }, b.FixedScaleAxis["super"].constructor.call(this, a, d, this.ticks, e), this.stepLength = this.axisLength / this.divisor } function d(a) { return this.axisLength * (+b.getMultiValue(a, this.units.pos) - this.range.min) / (this.range.max - this.range.min) } a.window, a.document; b.FixedScaleAxis = b.Axis.extend({ constructor: c, projectValue: d }) }(this || global, a), function (a, b) { "use strict"; function c(a, c, d, e) { b.StepAxis["super"].constructor.call(this, a, d, e.ticks, e); var f = Math.max(1, e.ticks.length - (e.stretch ? 1 : 0)); this.stepLength = this.axisLength / f } function d(a, b) { return this.stepLength * b } a.window, a.document; b.StepAxis = b.Axis.extend({ constructor: c, projectValue: d }) }(this || global, a), function (a, b) { "use strict"; function c(a) { var c = b.normalizeData(this.data, a.reverseData, !0); this.svg = b.createSvg(this.container, a.width, a.height, a.classNames.chart); var d, f, g = this.svg.elem("g").addClass(a.classNames.gridGroup), h = this.svg.elem("g"), i = this.svg.elem("g").addClass(a.classNames.labelGroup), j = b.createChartRect(this.svg, a, e.padding); d = void 0 === a.axisX.type ? new b.StepAxis(b.Axis.units.x, c.normalized.series, j, b.extend({}, a.axisX, { ticks: c.normalized.labels, stretch: a.fullWidth })) : a.axisX.type.call(b, b.Axis.units.x, c.normalized.series, j, a.axisX), f = void 0 === a.axisY.type ? new b.AutoScaleAxis(b.Axis.units.y, c.normalized.series, j, b.extend({}, a.axisY, { high: b.isNumeric(a.high) ? a.high : a.axisY.high, low: b.isNumeric(a.low) ? a.low : a.axisY.low })) : a.axisY.type.call(b, b.Axis.units.y, c.normalized.series, j, a.axisY), d.createGridAndLabels(g, i, this.supportsForeignObject, a, this.eventEmitter), f.createGridAndLabels(g, i, this.supportsForeignObject, a, this.eventEmitter), a.showGridBackground && b.createGridBackground(g, j, a.classNames.gridBackground, this.eventEmitter), c.raw.series.forEach(function (e, g) { var i = h.elem("g"); i.attr({ "ct:series-name": e.name, "ct:meta": b.serialize(e.meta) }), i.addClass([a.classNames.series, e.className || a.classNames.series + "-" + b.alphaNumerate(g)].join(" ")); var k = [], l = []; c.normalized.series[g].forEach(function (a, h) { var i = { x: j.x1 + d.projectValue(a, h, c.normalized.series[g]), y: j.y1 - f.projectValue(a, h, c.normalized.series[g]) }; k.push(i.x, i.y), l.push({ value: a, valueIndex: h, meta: b.getMetaData(e, h) }) }.bind(this)); var m = { lineSmooth: b.getSeriesOption(e, a, "lineSmooth"), showPoint: b.getSeriesOption(e, a, "showPoint"), showLine: b.getSeriesOption(e, a, "showLine"), showArea: b.getSeriesOption(e, a, "showArea"), areaBase: b.getSeriesOption(e, a, "areaBase") }, n = "function" == typeof m.lineSmooth ? m.lineSmooth : m.lineSmooth ? b.Interpolation.monotoneCubic() : b.Interpolation.none(), o = n(k, l); if (m.showPoint && o.pathElements.forEach(function (c) { var h = i.elem("line", { x1: c.x, y1: c.y, x2: c.x + .01, y2: c.y }, a.classNames.point).attr({ "ct:value": [c.data.value.x, c.data.value.y].filter(b.isNumeric).join(","), "ct:meta": b.serialize(c.data.meta) }); this.eventEmitter.emit("draw", { type: "point", value: c.data.value, index: c.data.valueIndex, meta: c.data.meta, series: e, seriesIndex: g, axisX: d, axisY: f, group: i, element: h, x: c.x, y: c.y }) }.bind(this)), m.showLine) { var p = i.elem("path", { d: o.stringify() }, a.classNames.line, !0); this.eventEmitter.emit("draw", { type: "line", values: c.normalized.series[g], path: o.clone(), chartRect: j, index: g, series: e, seriesIndex: g, seriesMeta: e.meta, axisX: d, axisY: f, group: i, element: p }) } if (m.showArea && f.range) { var q = Math.max(Math.min(m.areaBase, f.range.max), f.range.min), r = j.y1 - f.projectValue(q); o.splitByCommand("M").filter(function (a) { return a.pathElements.length > 1 }).map(function (a) { var b = a.pathElements[0], c = a.pathElements[a.pathElements.length - 1]; return a.clone(!0).position(0).remove(1).move(b.x, r).line(b.x, b.y).position(a.pathElements.length + 1).line(c.x, r) }).forEach(function (b) { var h = i.elem("path", { d: b.stringify() }, a.classNames.area, !0); this.eventEmitter.emit("draw", { type: "area", values: c.normalized.series[g], path: b.clone(), series: e, seriesIndex: g, axisX: d, axisY: f, chartRect: j, index: g, group: i, element: h }) }.bind(this)) } }.bind(this)), this.eventEmitter.emit("created", { bounds: f.bounds, chartRect: j, axisX: d, axisY: f, svg: this.svg, options: a }) } function d(a, c, d, f) { b.Line["super"].constructor.call(this, a, c, e, b.extend({}, e, d), f) } var e = (a.window, a.document, { axisX: { offset: 30, position: "end", labelOffset: { x: 0, y: 0 }, showLabel: !0, showGrid: !0, labelInterpolationFnc: b.noop, type: void 0 }, axisY: { offset: 40, position: "start", labelOffset: { x: 0, y: 0 }, showLabel: !0, showGrid: !0, labelInterpolationFnc: b.noop, type: void 0, scaleMinSpace: 20, onlyInteger: !1 }, width: void 0, height: void 0, showLine: !0, showPoint: !0, showArea: !1, areaBase: 0, lineSmooth: !0, showGridBackground: !1, low: void 0, high: void 0, chartPadding: { top: 15, right: 15, bottom: 5, left: 10 }, fullWidth: !1, reverseData: !1, classNames: { chart: "ct-chart-line", label: "ct-label", labelGroup: "ct-labels", series: "ct-series", line: "ct-line", point: "ct-point", area: "ct-area", grid: "ct-grid", gridGroup: "ct-grids", gridBackground: "ct-grid-background", vertical: "ct-vertical", horizontal: "ct-horizontal", start: "ct-start", end: "ct-end" } }); b.Line = b.Base.extend({ constructor: d, createChart: c }) }(this || global, a), function (a, b) { - "use strict"; function c(a) { - var c, d; a.distributeSeries ? (c = b.normalizeData(this.data, a.reverseData, a.horizontalBars ? "x" : "y"), c.normalized.series = c.normalized.series.map(function (a) { return [a] })) : c = b.normalizeData(this.data, a.reverseData, a.horizontalBars ? "x" : "y"), this.svg = b.createSvg(this.container, a.width, a.height, a.classNames.chart + (a.horizontalBars ? " " + a.classNames.horizontalBars : "")); var f = this.svg.elem("g").addClass(a.classNames.gridGroup), g = this.svg.elem("g"), h = this.svg.elem("g").addClass(a.classNames.labelGroup); - if (a.stackBars && 0 !== c.normalized.series.length) { var i = b.serialMap(c.normalized.series, function () { return Array.prototype.slice.call(arguments).map(function (a) { return a }).reduce(function (a, b) { return { x: a.x + (b && b.x) || 0, y: a.y + (b && b.y) || 0 } }, { x: 0, y: 0 }) }); d = b.getHighLow([i], a, a.horizontalBars ? "x" : "y") } else d = b.getHighLow(c.normalized.series, a, a.horizontalBars ? "x" : "y"); d.high = +a.high || (0 === a.high ? 0 : d.high), d.low = +a.low || (0 === a.low ? 0 : d.low); var j, k, l, m, n, o = b.createChartRect(this.svg, a, e.padding); k = a.distributeSeries && a.stackBars ? c.normalized.labels.slice(0, 1) : c.normalized.labels, a.horizontalBars ? (j = m = void 0 === a.axisX.type ? new b.AutoScaleAxis(b.Axis.units.x, c.normalized.series, o, b.extend({}, a.axisX, { highLow: d, referenceValue: 0 })) : a.axisX.type.call(b, b.Axis.units.x, c.normalized.series, o, b.extend({}, a.axisX, { highLow: d, referenceValue: 0 })), l = n = void 0 === a.axisY.type ? new b.StepAxis(b.Axis.units.y, c.normalized.series, o, { ticks: k }) : a.axisY.type.call(b, b.Axis.units.y, c.normalized.series, o, a.axisY)) : (l = m = void 0 === a.axisX.type ? new b.StepAxis(b.Axis.units.x, c.normalized.series, o, { ticks: k }) : a.axisX.type.call(b, b.Axis.units.x, c.normalized.series, o, a.axisX), j = n = void 0 === a.axisY.type ? new b.AutoScaleAxis(b.Axis.units.y, c.normalized.series, o, b.extend({}, a.axisY, { highLow: d, referenceValue: 0 })) : a.axisY.type.call(b, b.Axis.units.y, c.normalized.series, o, b.extend({}, a.axisY, { highLow: d, referenceValue: 0 }))); var p = a.horizontalBars ? o.x1 + j.projectValue(0) : o.y1 - j.projectValue(0), q = []; l.createGridAndLabels(f, h, this.supportsForeignObject, a, this.eventEmitter), j.createGridAndLabels(f, h, this.supportsForeignObject, a, this.eventEmitter), a.showGridBackground && b.createGridBackground(f, o, a.classNames.gridBackground, this.eventEmitter), c.raw.series.forEach(function (d, e) { var f, h, i = e - (c.raw.series.length - 1) / 2; f = a.distributeSeries && !a.stackBars ? l.axisLength / c.normalized.series.length / 2 : a.distributeSeries && a.stackBars ? l.axisLength / 2 : l.axisLength / c.normalized.series[e].length / 2, h = g.elem("g"), h.attr({ "ct:series-name": d.name, "ct:meta": b.serialize(d.meta) }), h.addClass([a.classNames.series, d.className || a.classNames.series + "-" + b.alphaNumerate(e)].join(" ")), c.normalized.series[e].forEach(function (g, k) { var r, s, t, u; if (u = a.distributeSeries && !a.stackBars ? e : a.distributeSeries && a.stackBars ? 0 : k, r = a.horizontalBars ? { x: o.x1 + j.projectValue(g && g.x ? g.x : 0, k, c.normalized.series[e]), y: o.y1 - l.projectValue(g && g.y ? g.y : 0, u, c.normalized.series[e]) } : { x: o.x1 + l.projectValue(g && g.x ? g.x : 0, u, c.normalized.series[e]), y: o.y1 - j.projectValue(g && g.y ? g.y : 0, k, c.normalized.series[e]) }, l instanceof b.StepAxis && (l.options.stretch || (r[l.units.pos] += f * (a.horizontalBars ? -1 : 1)), r[l.units.pos] += a.stackBars || a.distributeSeries ? 0 : i * a.seriesBarDistance * (a.horizontalBars ? -1 : 1)), t = q[k] || p, q[k] = t - (p - r[l.counterUnits.pos]), void 0 !== g) { var v = {}; v[l.units.pos + "1"] = r[l.units.pos], v[l.units.pos + "2"] = r[l.units.pos], !a.stackBars || "accumulate" !== a.stackMode && a.stackMode ? (v[l.counterUnits.pos + "1"] = p, v[l.counterUnits.pos + "2"] = r[l.counterUnits.pos]) : (v[l.counterUnits.pos + "1"] = t, v[l.counterUnits.pos + "2"] = q[k]), v.x1 = Math.min(Math.max(v.x1, o.x1), o.x2), v.x2 = Math.min(Math.max(v.x2, o.x1), o.x2), v.y1 = Math.min(Math.max(v.y1, o.y2), o.y1), v.y2 = Math.min(Math.max(v.y2, o.y2), o.y1); var w = b.getMetaData(d, k); s = h.elem("line", v, a.classNames.bar).attr({ "ct:value": [g.x, g.y].filter(b.isNumeric).join(","), "ct:meta": b.serialize(w) }), this.eventEmitter.emit("draw", b.extend({ type: "bar", value: g, index: k, meta: w, series: d, seriesIndex: e, axisX: m, axisY: n, chartRect: o, group: h, element: s }, v)) } }.bind(this)) }.bind(this)), this.eventEmitter.emit("created", { bounds: j.bounds, chartRect: o, axisX: m, axisY: n, svg: this.svg, options: a }) - } function d(a, c, d, f) { b.Bar["super"].constructor.call(this, a, c, e, b.extend({}, e, d), f) } var e = (a.window, a.document, { axisX: { offset: 30, position: "end", labelOffset: { x: 0, y: 0 }, showLabel: !0, showGrid: !0, labelInterpolationFnc: b.noop, scaleMinSpace: 30, onlyInteger: !1 }, axisY: { offset: 40, position: "start", labelOffset: { x: 0, y: 0 }, showLabel: !0, showGrid: !0, labelInterpolationFnc: b.noop, scaleMinSpace: 20, onlyInteger: !1 }, width: void 0, height: void 0, high: void 0, low: void 0, referenceValue: 0, chartPadding: { top: 15, right: 15, bottom: 5, left: 10 }, seriesBarDistance: 15, stackBars: !1, stackMode: "accumulate", horizontalBars: !1, distributeSeries: !1, reverseData: !1, showGridBackground: !1, classNames: { chart: "ct-chart-bar", horizontalBars: "ct-horizontal-bars", label: "ct-label", labelGroup: "ct-labels", series: "ct-series", bar: "ct-bar", grid: "ct-grid", gridGroup: "ct-grids", gridBackground: "ct-grid-background", vertical: "ct-vertical", horizontal: "ct-horizontal", start: "ct-start", end: "ct-end" } }); b.Bar = b.Base.extend({ constructor: d, createChart: c }) - }(this || global, a), function (a, b) { "use strict"; function c(a, b, c) { var d = b.x > a.x; return d && "explode" === c || !d && "implode" === c ? "start" : d && "implode" === c || !d && "explode" === c ? "end" : "middle" } function d(a) { var d, e, g, h, i, j = b.normalizeData(this.data), k = [], l = a.startAngle; this.svg = b.createSvg(this.container, a.width, a.height, a.donut ? a.classNames.chartDonut : a.classNames.chartPie), e = b.createChartRect(this.svg, a, f.padding), g = Math.min(e.width() / 2, e.height() / 2), i = a.total || j.normalized.series.reduce(function (a, b) { return a + b }, 0); var m = b.quantity(a.donutWidth); "%" === m.unit && (m.value *= g / 100), g -= a.donut && !a.donutSolid ? m.value / 2 : 0, h = "outside" === a.labelPosition || a.donut && !a.donutSolid ? g : "center" === a.labelPosition ? 0 : a.donutSolid ? g - m.value / 2 : g / 2, h += a.labelOffset; var n = { x: e.x1 + e.width() / 2, y: e.y2 + e.height() / 2 }, o = 1 === j.raw.series.filter(function (a) { return a.hasOwnProperty("value") ? 0 !== a.value : 0 !== a }).length; j.raw.series.forEach(function (a, b) { k[b] = this.svg.elem("g", null, null) }.bind(this)), a.showLabel && (d = this.svg.elem("g", null, null)), j.raw.series.forEach(function (e, f) { if (0 !== j.normalized.series[f] || !a.ignoreEmptyValues) { k[f].attr({ "ct:series-name": e.name }), k[f].addClass([a.classNames.series, e.className || a.classNames.series + "-" + b.alphaNumerate(f)].join(" ")); var p = i > 0 ? l + j.normalized.series[f] / i * 360 : 0, q = Math.max(0, l - (0 === f || o ? 0 : .2)); p - q >= 359.99 && (p = q + 359.99); var r, s, t, u = b.polarToCartesian(n.x, n.y, g, q), v = b.polarToCartesian(n.x, n.y, g, p), w = new b.Svg.Path(!a.donut || a.donutSolid).move(v.x, v.y).arc(g, g, 0, p - l > 180, 0, u.x, u.y); a.donut ? a.donutSolid && (t = g - m.value, r = b.polarToCartesian(n.x, n.y, t, l - (0 === f || o ? 0 : .2)), s = b.polarToCartesian(n.x, n.y, t, p), w.line(r.x, r.y), w.arc(t, t, 0, p - l > 180, 1, s.x, s.y)) : w.line(n.x, n.y); var x = a.classNames.slicePie; a.donut && (x = a.classNames.sliceDonut, a.donutSolid && (x = a.classNames.sliceDonutSolid)); var y = k[f].elem("path", { d: w.stringify() }, x); if (y.attr({ "ct:value": j.normalized.series[f], "ct:meta": b.serialize(e.meta) }), a.donut && !a.donutSolid && (y._node.style.strokeWidth = m.value + "px"), this.eventEmitter.emit("draw", { type: "slice", value: j.normalized.series[f], totalDataSum: i, index: f, meta: e.meta, series: e, group: k[f], element: y, path: w.clone(), center: n, radius: g, startAngle: l, endAngle: p }), a.showLabel) { var z; z = 1 === j.raw.series.length ? { x: n.x, y: n.y } : b.polarToCartesian(n.x, n.y, h, l + (p - l) / 2); var A; A = j.normalized.labels && !b.isFalseyButZero(j.normalized.labels[f]) ? j.normalized.labels[f] : j.normalized.series[f]; var B = a.labelInterpolationFnc(A, f); if (B || 0 === B) { var C = d.elem("text", { dx: z.x, dy: z.y, "text-anchor": c(n, z, a.labelDirection) }, a.classNames.label).text("" + B); this.eventEmitter.emit("draw", { type: "label", index: f, group: d, element: C, text: "" + B, x: z.x, y: z.y }) } } l = p } }.bind(this)), this.eventEmitter.emit("created", { chartRect: e, svg: this.svg, options: a }) } function e(a, c, d, e) { b.Pie["super"].constructor.call(this, a, c, f, b.extend({}, f, d), e) } var f = (a.window, a.document, { width: void 0, height: void 0, chartPadding: 5, classNames: { chartPie: "ct-chart-pie", chartDonut: "ct-chart-donut", series: "ct-series", slicePie: "ct-slice-pie", sliceDonut: "ct-slice-donut", sliceDonutSolid: "ct-slice-donut-solid", label: "ct-label" }, startAngle: 0, total: void 0, donut: !1, donutSolid: !1, donutWidth: 60, showLabel: !0, labelOffset: 0, labelPosition: "inside", labelInterpolationFnc: b.noop, labelDirection: "neutral", reverseData: !1, ignoreEmptyValues: !1 }); b.Pie = b.Base.extend({ constructor: e, createChart: d, determineAnchorPosition: c }) }(this || global, a), a -}); -//# sourceMappingURL=chartist.min.js.map - -var i, l, selectedLine = null; - -/* Navigate to hash without browser history entry */ -var navigateToHash = function () { - if (window.history !== undefined && window.history.replaceState !== undefined) { - window.history.replaceState(undefined, undefined, this.getAttribute("href")); - } -}; - -var hashLinks = document.getElementsByClassName('navigatetohash'); -for (i = 0, l = hashLinks.length; i < l; i++) { - hashLinks[i].addEventListener('click', navigateToHash); -} - -/* Switch test method */ -var switchTestMethod = function () { - var method = this.getAttribute("value"); - console.log("Selected test method: " + method); - - var lines, i, l, coverageData, lineAnalysis, cells; - - lines = document.querySelectorAll('.lineAnalysis tr'); - - for (i = 1, l = lines.length; i < l; i++) { - coverageData = JSON.parse(lines[i].getAttribute('data-coverage').replace(/'/g, '"')); - lineAnalysis = coverageData[method]; - cells = lines[i].querySelectorAll('td'); - if (lineAnalysis === undefined) { - lineAnalysis = coverageData.AllTestMethods; - if (lineAnalysis.LVS !== 'gray') { - cells[0].setAttribute('class', 'red'); - cells[1].innerText = cells[1].textContent = '0'; - cells[4].setAttribute('class', 'lightred'); - } - } else { - cells[0].setAttribute('class', lineAnalysis.LVS); - cells[1].innerText = cells[1].textContent = lineAnalysis.VC; - cells[4].setAttribute('class', 'light' + lineAnalysis.LVS); - } - } -}; - -var testMethods = document.getElementsByClassName('switchtestmethod'); -for (i = 0, l = testMethods.length; i < l; i++) { - testMethods[i].addEventListener('change', switchTestMethod); -} - -/* Highlight test method by line */ -var toggleLine = function () { - if (selectedLine === this) { - selectedLine = null; - } else { - selectedLine = null; - unhighlightTestMethods(); - highlightTestMethods.call(this); - selectedLine = this; - } - -}; -var highlightTestMethods = function () { - if (selectedLine !== null) { - return; - } - - var lineAnalysis; - var coverageData = JSON.parse(this.getAttribute('data-coverage').replace(/'/g, '"')); - var testMethods = document.getElementsByClassName('testmethod'); - - for (i = 0, l = testMethods.length; i < l; i++) { - lineAnalysis = coverageData[testMethods[i].id]; - if (lineAnalysis === undefined) { - testMethods[i].className = testMethods[i].className.replace(/\s*light.+/g, ""); - } else { - testMethods[i].className += ' light' + lineAnalysis.LVS; - } - } -}; -var unhighlightTestMethods = function () { - if (selectedLine !== null) { - return; - } - - var testMethods = document.getElementsByClassName('testmethod'); - for (i = 0, l = testMethods.length; i < l; i++) { - testMethods[i].className = testMethods[i].className.replace(/\s*light.+/g, ""); - } -}; -var coverableLines = document.getElementsByClassName('coverableline'); -for (i = 0, l = coverableLines.length; i < l; i++) { - coverableLines[i].addEventListener('click', toggleLine); - coverableLines[i].addEventListener('mouseenter', highlightTestMethods); - coverableLines[i].addEventListener('mouseleave', unhighlightTestMethods); -} - -/* History charts */ -var renderChart = function (chart) { - // Remove current children (e.g. PNG placeholder) - while (chart.firstChild) { - chart.firstChild.remove(); - } - - var chartData = window[chart.getAttribute('data-data')]; - var options = { - axisY: { - type: undefined, - onlyInteger: true - }, - lineSmooth: false, - low: 0, - high: 100, - scaleMinSpace: 20, - onlyInteger: true, - fullWidth: true - }; - var lineChart = new Chartist.Line(chart, { - labels: [], - series: chartData.series - }, options); - - /* Zoom */ - var zoomButtonDiv = document.createElement("div"); - zoomButtonDiv.className = "toggleZoom"; - var zoomButtonLink = document.createElement("a"); - zoomButtonLink.setAttribute("href", ""); - var zoomButtonText = document.createElement("i"); - zoomButtonText.className = "icon-search-plus"; - - zoomButtonLink.appendChild(zoomButtonText); - zoomButtonDiv.appendChild(zoomButtonLink); - - chart.appendChild(zoomButtonDiv); - - zoomButtonDiv.addEventListener('click', function (event) { - event.preventDefault(); - - if (options.axisY.type === undefined) { - options.axisY.type = Chartist.AutoScaleAxis; - zoomButtonText.className = "icon-search-minus"; - } else { - options.axisY.type = undefined; - zoomButtonText.className = "icon-search-plus"; - } - - lineChart.update(null, options); - }); - - var tooltip = document.createElement("div"); - tooltip.className = "tooltip"; - - chart.appendChild(tooltip); - - /* Tooltips */ - var showToolTip = function () { - var index = this.getAttribute('ct:meta'); - - tooltip.innerHTML = chartData.tooltips[index]; - tooltip.style.display = 'block'; - }; - - var moveToolTip = function (event) { - var box = chart.getBoundingClientRect(); - var left = event.pageX - box.left - window.pageXOffset; - var top = event.pageY - box.top - window.pageYOffset; - - left = left + 20; - top = top - tooltip.offsetHeight / 2; - - if (left + tooltip.offsetWidth > box.width) { - left -= tooltip.offsetWidth + 40; - } - - if (top < 0) { - top = 0; - } - - if (top + tooltip.offsetHeight > box.height) { - top = box.height - tooltip.offsetHeight; - } - - tooltip.style.left = left + 'px'; - tooltip.style.top = top + 'px'; - }; - - var hideToolTip = function () { - tooltip.style.display = 'none'; - }; - chart.addEventListener('mousemove', moveToolTip); - - lineChart.on('created', function () { - var chartPoints = chart.getElementsByClassName('ct-point'); - for (i = 0, l = chartPoints.length; i < l; i++) { - chartPoints[i].addEventListener('mousemove', showToolTip); - chartPoints[i].addEventListener('mouseout', hideToolTip); - } - }); -}; - -var charts = document.getElementsByClassName('historychart'); -for (i = 0, l = charts.length; i < l; i++) { - renderChart(charts[i]); -} \ No newline at end of file diff --git a/source/coverage/icon_cog.svg b/source/coverage/icon_cog.svg deleted file mode 100644 index d730bf1..0000000 --- a/source/coverage/icon_cog.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/source/coverage/icon_cog_dark.svg b/source/coverage/icon_cog_dark.svg deleted file mode 100644 index ccbcd9b..0000000 --- a/source/coverage/icon_cog_dark.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/source/coverage/icon_cube.svg b/source/coverage/icon_cube.svg deleted file mode 100644 index 3302443..0000000 --- a/source/coverage/icon_cube.svg +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/source/coverage/icon_cube_dark.svg b/source/coverage/icon_cube_dark.svg deleted file mode 100644 index 3e7f0fa..0000000 --- a/source/coverage/icon_cube_dark.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/source/coverage/icon_fork.svg b/source/coverage/icon_fork.svg deleted file mode 100644 index f0148b3..0000000 --- a/source/coverage/icon_fork.svg +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/source/coverage/icon_fork_dark.svg b/source/coverage/icon_fork_dark.svg deleted file mode 100644 index 11930c9..0000000 --- a/source/coverage/icon_fork_dark.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/source/coverage/icon_info-circled.svg b/source/coverage/icon_info-circled.svg deleted file mode 100644 index 252166b..0000000 --- a/source/coverage/icon_info-circled.svg +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/source/coverage/icon_info-circled_dark.svg b/source/coverage/icon_info-circled_dark.svg deleted file mode 100644 index 252166b..0000000 --- a/source/coverage/icon_info-circled_dark.svg +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/source/coverage/icon_minus.svg b/source/coverage/icon_minus.svg deleted file mode 100644 index 3c30c36..0000000 --- a/source/coverage/icon_minus.svg +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/source/coverage/icon_minus_dark.svg b/source/coverage/icon_minus_dark.svg deleted file mode 100644 index 2516b6f..0000000 --- a/source/coverage/icon_minus_dark.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/source/coverage/icon_plus.svg b/source/coverage/icon_plus.svg deleted file mode 100644 index 7932723..0000000 --- a/source/coverage/icon_plus.svg +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/source/coverage/icon_plus_dark.svg b/source/coverage/icon_plus_dark.svg deleted file mode 100644 index 6ed4edd..0000000 --- a/source/coverage/icon_plus_dark.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/source/coverage/icon_search-minus.svg b/source/coverage/icon_search-minus.svg deleted file mode 100644 index c174eb5..0000000 --- a/source/coverage/icon_search-minus.svg +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/source/coverage/icon_search-minus_dark.svg b/source/coverage/icon_search-minus_dark.svg deleted file mode 100644 index 9caaffb..0000000 --- a/source/coverage/icon_search-minus_dark.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/source/coverage/icon_search-plus.svg b/source/coverage/icon_search-plus.svg deleted file mode 100644 index 04b24ec..0000000 --- a/source/coverage/icon_search-plus.svg +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/source/coverage/icon_search-plus_dark.svg b/source/coverage/icon_search-plus_dark.svg deleted file mode 100644 index 5324194..0000000 --- a/source/coverage/icon_search-plus_dark.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/source/coverage/icon_sponsor.svg b/source/coverage/icon_sponsor.svg deleted file mode 100644 index bf6d959..0000000 --- a/source/coverage/icon_sponsor.svg +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/source/coverage/icon_star.svg b/source/coverage/icon_star.svg deleted file mode 100644 index b23c54e..0000000 --- a/source/coverage/icon_star.svg +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/source/coverage/icon_star_dark.svg b/source/coverage/icon_star_dark.svg deleted file mode 100644 index 49c0d03..0000000 --- a/source/coverage/icon_star_dark.svg +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/source/coverage/icon_up-dir.svg b/source/coverage/icon_up-dir.svg deleted file mode 100644 index 567c11f..0000000 --- a/source/coverage/icon_up-dir.svg +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/source/coverage/icon_up-dir_active.svg b/source/coverage/icon_up-dir_active.svg deleted file mode 100644 index bb22554..0000000 --- a/source/coverage/icon_up-dir_active.svg +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/source/coverage/icon_up-down-dir.svg b/source/coverage/icon_up-down-dir.svg deleted file mode 100644 index 62a3f9c..0000000 --- a/source/coverage/icon_up-down-dir.svg +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/source/coverage/icon_up-down-dir_dark.svg b/source/coverage/icon_up-down-dir_dark.svg deleted file mode 100644 index 2820a25..0000000 --- a/source/coverage/icon_up-down-dir_dark.svg +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/source/coverage/icon_wrench.svg b/source/coverage/icon_wrench.svg deleted file mode 100644 index b6aa318..0000000 --- a/source/coverage/icon_wrench.svg +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/source/coverage/icon_wrench_dark.svg b/source/coverage/icon_wrench_dark.svg deleted file mode 100644 index 5c77a9c..0000000 --- a/source/coverage/icon_wrench_dark.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/source/coverage/index.htm b/source/coverage/index.htm deleted file mode 100644 index 0113390..0000000 --- a/source/coverage/index.htm +++ /dev/null @@ -1,234 +0,0 @@ - - - - - - - -Summary - Coverage Report - -
-

SummaryStarSponsor

-
-
-
Information
-
-
- - - - - - - - - - - - - - - - - - - - - -
Parser:MultiReport (3x Cobertura)
Assemblies:2
Classes:31
Files:31
Coverage date:12/02/2025 - 16:32:11 - 12/02/2025 - 16:32:54
-
-
-
-
-
Line coverage
-
-
62%
-
- - - - - - - - - - - - - - - - - - - - - -
Covered lines:524
Uncovered lines:317
Coverable lines:841
Total lines:1610
Line coverage:62.3%
-
-
-
-
-
Branch coverage
-
-
57%
-
- - - - - - - - - - - - - -
Covered branches:59
Total branches:102
Branch coverage:57.8%
-
-
-
-
-
Method coverage
-
-
-

Feature is only available for sponsors

-Upgrade to PRO version -
-
-
-
-

Risk Hotspots

- -
- ------- - - - - - - - - - - - - - - -
AssemblyClassMethodCrap Score Cyclomatic complexity
FunctionsFunctions.Services.DataServiceExecuteQueryStoredProcedure()426
-
-
-

Coverage

- -
- ------------- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Line coverageBranch coverage
NameCoveredUncoveredCoverableTotalPercentageCoveredTotalPercentage
Core57258225569.5%
  
121866.6%
  
Core.DTOs.Request.OrganisationHierarchyProvider20219100%
 
00
 
Core.Helpers.ApplicationHelper70723100%
 
4666.6%
  
Core.Helpers.AttributeExtensions1301327100%
 
66100%
 
Core.Helpers.ConnectionStrings1017100%
 
00
 
Core.Helpers.DateTimeHelper40411100%
 
22100%
 
Core.Helpers.FilePathAttribute30312100%
 
00
 
Core.Mapping.SplunkInstanceMap055140%
 
00
 
Core.Repositories.DapperWrapper271286896.4%
  
00
 
Core.Repositories.HierarchyProviderConsumerRepo01717620%
 
040%
 
TimeProvider022120%
 
00
 
Functions467292759135561.5%
  
478455.9%
  
Functions.Configuration.EmailConfigurationProvider088290%
 
020%
 
Functions.Configuration.Infrastructure.HttpClient.HttpClientExtensions1201223100%
 
00
 
Functions.Configuration.Infrastructure.Logging.LoggingExtensions01301301850%
 
040%
 
Functions.Configuration.Infrastructure.Mapping.MappingExtensions033130%
 
00
 
Functions.ExecuteImportByTrigger30316100%
 
00
 
Functions.GetDataFromApiByDateRange2718458560%
  
00
 
Functions.GetDataFromApiByTrigger90934100%
 
00
 
Functions.GetDataFromApiManual2102142100%
 
22100%
 
Functions.GetDataFromApiToday5405498100%
 
00
 
Functions.PurgeErrorLogByTrigger30316100%
 
00
 
Functions.Services.BatchService8679314692.4%
  
141877.7%
  
Functions.Services.BlobService428509384%
  
6875%
  
Functions.Services.ConfigurationService324366188.8%
  
00
 
Functions.Services.CoreConfigurationService40414100%
 
22100%
 
Functions.Services.DataService264661133%
  
0160%
 
Functions.Services.FileService80819100%
 
00
 
Functions.Services.ImportService4604684100%
 
121485.7%
  
Functions.Services.LoggingService077210%
 
00
 
Functions.Services.SplunkService962612218178.6%
  
81457.1%
  
Functions.SqlConnectionFactory033130%
 
00
 
Functions.StoreProviderConsumerData2214366961.1%
  
3475%
  
-
-
-
- \ No newline at end of file diff --git a/source/coverage/index.html b/source/coverage/index.html deleted file mode 100644 index 0113390..0000000 --- a/source/coverage/index.html +++ /dev/null @@ -1,234 +0,0 @@ - - - - - - - -Summary - Coverage Report - -
-

SummaryStarSponsor

-
-
-
Information
-
-
- - - - - - - - - - - - - - - - - - - - - -
Parser:MultiReport (3x Cobertura)
Assemblies:2
Classes:31
Files:31
Coverage date:12/02/2025 - 16:32:11 - 12/02/2025 - 16:32:54
-
-
-
-
-
Line coverage
-
-
62%
-
- - - - - - - - - - - - - - - - - - - - - -
Covered lines:524
Uncovered lines:317
Coverable lines:841
Total lines:1610
Line coverage:62.3%
-
-
-
-
-
Branch coverage
-
-
57%
-
- - - - - - - - - - - - - -
Covered branches:59
Total branches:102
Branch coverage:57.8%
-
-
-
-
-
Method coverage
-
-
-

Feature is only available for sponsors

-Upgrade to PRO version -
-
-
-
-

Risk Hotspots

- -
- ------- - - - - - - - - - - - - - - -
AssemblyClassMethodCrap Score Cyclomatic complexity
FunctionsFunctions.Services.DataServiceExecuteQueryStoredProcedure()426
-
-
-

Coverage

- -
- ------------- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Line coverageBranch coverage
NameCoveredUncoveredCoverableTotalPercentageCoveredTotalPercentage
Core57258225569.5%
  
121866.6%
  
Core.DTOs.Request.OrganisationHierarchyProvider20219100%
 
00
 
Core.Helpers.ApplicationHelper70723100%
 
4666.6%
  
Core.Helpers.AttributeExtensions1301327100%
 
66100%
 
Core.Helpers.ConnectionStrings1017100%
 
00
 
Core.Helpers.DateTimeHelper40411100%
 
22100%
 
Core.Helpers.FilePathAttribute30312100%
 
00
 
Core.Mapping.SplunkInstanceMap055140%
 
00
 
Core.Repositories.DapperWrapper271286896.4%
  
00
 
Core.Repositories.HierarchyProviderConsumerRepo01717620%
 
040%
 
TimeProvider022120%
 
00
 
Functions467292759135561.5%
  
478455.9%
  
Functions.Configuration.EmailConfigurationProvider088290%
 
020%
 
Functions.Configuration.Infrastructure.HttpClient.HttpClientExtensions1201223100%
 
00
 
Functions.Configuration.Infrastructure.Logging.LoggingExtensions01301301850%
 
040%
 
Functions.Configuration.Infrastructure.Mapping.MappingExtensions033130%
 
00
 
Functions.ExecuteImportByTrigger30316100%
 
00
 
Functions.GetDataFromApiByDateRange2718458560%
  
00
 
Functions.GetDataFromApiByTrigger90934100%
 
00
 
Functions.GetDataFromApiManual2102142100%
 
22100%
 
Functions.GetDataFromApiToday5405498100%
 
00
 
Functions.PurgeErrorLogByTrigger30316100%
 
00
 
Functions.Services.BatchService8679314692.4%
  
141877.7%
  
Functions.Services.BlobService428509384%
  
6875%
  
Functions.Services.ConfigurationService324366188.8%
  
00
 
Functions.Services.CoreConfigurationService40414100%
 
22100%
 
Functions.Services.DataService264661133%
  
0160%
 
Functions.Services.FileService80819100%
 
00
 
Functions.Services.ImportService4604684100%
 
121485.7%
  
Functions.Services.LoggingService077210%
 
00
 
Functions.Services.SplunkService962612218178.6%
  
81457.1%
  
Functions.SqlConnectionFactory033130%
 
00
 
Functions.StoreProviderConsumerData2214366961.1%
  
3475%
  
-
-
-
- \ No newline at end of file diff --git a/source/coverage/main.js b/source/coverage/main.js deleted file mode 100644 index d585298..0000000 --- a/source/coverage/main.js +++ /dev/null @@ -1,334 +0,0 @@ -/* Chartist.js 0.11.4 - * Copyright © 2019 Gion Kunz - * Free to use under either the WTFPL license or the MIT license. - * https://raw.githubusercontent.com/gionkunz/chartist-js/master/LICENSE-WTFPL - * https://raw.githubusercontent.com/gionkunz/chartist-js/master/LICENSE-MIT - */ - -!function (a, b) { "function" == typeof define && define.amd ? define("Chartist", [], function () { return a.Chartist = b() }) : "object" == typeof module && module.exports ? module.exports = b() : a.Chartist = b() }(this, function () { - var a = { version: "0.11.4" }; return function (a, b) { "use strict"; var c = a.window, d = a.document; b.namespaces = { svg: "http://www.w3.org/2000/svg", xmlns: "http://www.w3.org/2000/xmlns/", xhtml: "http://www.w3.org/1999/xhtml", xlink: "http://www.w3.org/1999/xlink", ct: "http://gionkunz.github.com/chartist-js/ct" }, b.noop = function (a) { return a }, b.alphaNumerate = function (a) { return String.fromCharCode(97 + a % 26) }, b.extend = function (a) { var c, d, e; for (a = a || {}, c = 1; c < arguments.length; c++) { d = arguments[c]; for (var f in d) e = d[f], "object" != typeof e || null === e || e instanceof Array ? a[f] = e : a[f] = b.extend(a[f], e) } return a }, b.replaceAll = function (a, b, c) { return a.replace(new RegExp(b, "g"), c) }, b.ensureUnit = function (a, b) { return "number" == typeof a && (a += b), a }, b.quantity = function (a) { if ("string" == typeof a) { var b = /^(\d+)\s*(.*)$/g.exec(a); return { value: +b[1], unit: b[2] || void 0 } } return { value: a } }, b.querySelector = function (a) { return a instanceof Node ? a : d.querySelector(a) }, b.times = function (a) { return Array.apply(null, new Array(a)) }, b.sum = function (a, b) { return a + (b ? b : 0) }, b.mapMultiply = function (a) { return function (b) { return b * a } }, b.mapAdd = function (a) { return function (b) { return b + a } }, b.serialMap = function (a, c) { var d = [], e = Math.max.apply(null, a.map(function (a) { return a.length })); return b.times(e).forEach(function (b, e) { var f = a.map(function (a) { return a[e] }); d[e] = c.apply(null, f) }), d }, b.roundWithPrecision = function (a, c) { var d = Math.pow(10, c || b.precision); return Math.round(a * d) / d }, b.precision = 8, b.escapingMap = { "&": "&", "<": "<", ">": ">", '"': """, "'": "'" }, b.serialize = function (a) { return null === a || void 0 === a ? a : ("number" == typeof a ? a = "" + a : "object" == typeof a && (a = JSON.stringify({ data: a })), Object.keys(b.escapingMap).reduce(function (a, c) { return b.replaceAll(a, c, b.escapingMap[c]) }, a)) }, b.deserialize = function (a) { if ("string" != typeof a) return a; a = Object.keys(b.escapingMap).reduce(function (a, c) { return b.replaceAll(a, b.escapingMap[c], c) }, a); try { a = JSON.parse(a), a = void 0 !== a.data ? a.data : a } catch (c) { } return a }, b.createSvg = function (a, c, d, e) { var f; return c = c || "100%", d = d || "100%", Array.prototype.slice.call(a.querySelectorAll("svg")).filter(function (a) { return a.getAttributeNS(b.namespaces.xmlns, "ct") }).forEach(function (b) { a.removeChild(b) }), f = new b.Svg("svg").attr({ width: c, height: d }).addClass(e), f._node.style.width = c, f._node.style.height = d, a.appendChild(f._node), f }, b.normalizeData = function (a, c, d) { var e, f = { raw: a, normalized: {} }; return f.normalized.series = b.getDataArray({ series: a.series || [] }, c, d), e = f.normalized.series.every(function (a) { return a instanceof Array }) ? Math.max.apply(null, f.normalized.series.map(function (a) { return a.length })) : f.normalized.series.length, f.normalized.labels = (a.labels || []).slice(), Array.prototype.push.apply(f.normalized.labels, b.times(Math.max(0, e - f.normalized.labels.length)).map(function () { return "" })), c && b.reverseData(f.normalized), f }, b.safeHasProperty = function (a, b) { return null !== a && "object" == typeof a && a.hasOwnProperty(b) }, b.isDataHoleValue = function (a) { return null === a || void 0 === a || "number" == typeof a && isNaN(a) }, b.reverseData = function (a) { a.labels.reverse(), a.series.reverse(); for (var b = 0; b < a.series.length; b++)"object" == typeof a.series[b] && void 0 !== a.series[b].data ? a.series[b].data.reverse() : a.series[b] instanceof Array && a.series[b].reverse() }, b.getDataArray = function (a, c, d) { function e(a) { if (b.safeHasProperty(a, "value")) return e(a.value); if (b.safeHasProperty(a, "data")) return e(a.data); if (a instanceof Array) return a.map(e); if (!b.isDataHoleValue(a)) { if (d) { var c = {}; return "string" == typeof d ? c[d] = b.getNumberOrUndefined(a) : c.y = b.getNumberOrUndefined(a), c.x = a.hasOwnProperty("x") ? b.getNumberOrUndefined(a.x) : c.x, c.y = a.hasOwnProperty("y") ? b.getNumberOrUndefined(a.y) : c.y, c } return b.getNumberOrUndefined(a) } } return a.series.map(e) }, b.normalizePadding = function (a, b) { return b = b || 0, "number" == typeof a ? { top: a, right: a, bottom: a, left: a } : { top: "number" == typeof a.top ? a.top : b, right: "number" == typeof a.right ? a.right : b, bottom: "number" == typeof a.bottom ? a.bottom : b, left: "number" == typeof a.left ? a.left : b } }, b.getMetaData = function (a, b) { var c = a.data ? a.data[b] : a[b]; return c ? c.meta : void 0 }, b.orderOfMagnitude = function (a) { return Math.floor(Math.log(Math.abs(a)) / Math.LN10) }, b.projectLength = function (a, b, c) { return b / c.range * a }, b.getAvailableHeight = function (a, c) { return Math.max((b.quantity(c.height).value || a.height()) - (c.chartPadding.top + c.chartPadding.bottom) - c.axisX.offset, 0) }, b.getHighLow = function (a, c, d) { function e(a) { if (void 0 !== a) if (a instanceof Array) for (var b = 0; b < a.length; b++)e(a[b]); else { var c = d ? +a[d] : +a; g && c > f.high && (f.high = c), h && c < f.low && (f.low = c) } } c = b.extend({}, c, d ? c["axis" + d.toUpperCase()] : {}); var f = { high: void 0 === c.high ? -Number.MAX_VALUE : +c.high, low: void 0 === c.low ? Number.MAX_VALUE : +c.low }, g = void 0 === c.high, h = void 0 === c.low; return (g || h) && e(a), (c.referenceValue || 0 === c.referenceValue) && (f.high = Math.max(c.referenceValue, f.high), f.low = Math.min(c.referenceValue, f.low)), f.high <= f.low && (0 === f.low ? f.high = 1 : f.low < 0 ? f.high = 0 : f.high > 0 ? f.low = 0 : (f.high = 1, f.low = 0)), f }, b.isNumeric = function (a) { return null !== a && isFinite(a) }, b.isFalseyButZero = function (a) { return !a && 0 !== a }, b.getNumberOrUndefined = function (a) { return b.isNumeric(a) ? +a : void 0 }, b.isMultiValue = function (a) { return "object" == typeof a && ("x" in a || "y" in a) }, b.getMultiValue = function (a, c) { return b.isMultiValue(a) ? b.getNumberOrUndefined(a[c || "y"]) : b.getNumberOrUndefined(a) }, b.rho = function (a) { function b(a, c) { return a % c === 0 ? c : b(c, a % c) } function c(a) { return a * a + 1 } if (1 === a) return a; var d, e = 2, f = 2; if (a % 2 === 0) return 2; do e = c(e) % a, f = c(c(f)) % a, d = b(Math.abs(e - f), a); while (1 === d); return d }, b.getBounds = function (a, c, d, e) { function f(a, b) { return a === (a += b) && (a *= 1 + (b > 0 ? o : -o)), a } var g, h, i, j = 0, k = { high: c.high, low: c.low }; k.valueRange = k.high - k.low, k.oom = b.orderOfMagnitude(k.valueRange), k.step = Math.pow(10, k.oom), k.min = Math.floor(k.low / k.step) * k.step, k.max = Math.ceil(k.high / k.step) * k.step, k.range = k.max - k.min, k.numberOfSteps = Math.round(k.range / k.step); var l = b.projectLength(a, k.step, k), m = l < d, n = e ? b.rho(k.range) : 0; if (e && b.projectLength(a, 1, k) >= d) k.step = 1; else if (e && n < k.step && b.projectLength(a, n, k) >= d) k.step = n; else for (; ;) { if (m && b.projectLength(a, k.step, k) <= d) k.step *= 2; else { if (m || !(b.projectLength(a, k.step / 2, k) >= d)) break; if (k.step /= 2, e && k.step % 1 !== 0) { k.step *= 2; break } } if (j++ > 1e3) throw new Error("Exceeded maximum number of iterations while optimizing scale step!") } var o = 2.221e-16; for (k.step = Math.max(k.step, o), h = k.min, i = k.max; h + k.step <= k.low;)h = f(h, k.step); for (; i - k.step >= k.high;)i = f(i, -k.step); k.min = h, k.max = i, k.range = k.max - k.min; var p = []; for (g = k.min; g <= k.max; g = f(g, k.step)) { var q = b.roundWithPrecision(g); q !== p[p.length - 1] && p.push(q) } return k.values = p, k }, b.polarToCartesian = function (a, b, c, d) { var e = (d - 90) * Math.PI / 180; return { x: a + c * Math.cos(e), y: b + c * Math.sin(e) } }, b.createChartRect = function (a, c, d) { var e = !(!c.axisX && !c.axisY), f = e ? c.axisY.offset : 0, g = e ? c.axisX.offset : 0, h = a.width() || b.quantity(c.width).value || 0, i = a.height() || b.quantity(c.height).value || 0, j = b.normalizePadding(c.chartPadding, d); h = Math.max(h, f + j.left + j.right), i = Math.max(i, g + j.top + j.bottom); var k = { padding: j, width: function () { return this.x2 - this.x1 }, height: function () { return this.y1 - this.y2 } }; return e ? ("start" === c.axisX.position ? (k.y2 = j.top + g, k.y1 = Math.max(i - j.bottom, k.y2 + 1)) : (k.y2 = j.top, k.y1 = Math.max(i - j.bottom - g, k.y2 + 1)), "start" === c.axisY.position ? (k.x1 = j.left + f, k.x2 = Math.max(h - j.right, k.x1 + 1)) : (k.x1 = j.left, k.x2 = Math.max(h - j.right - f, k.x1 + 1))) : (k.x1 = j.left, k.x2 = Math.max(h - j.right, k.x1 + 1), k.y2 = j.top, k.y1 = Math.max(i - j.bottom, k.y2 + 1)), k }, b.createGrid = function (a, c, d, e, f, g, h, i) { var j = {}; j[d.units.pos + "1"] = a, j[d.units.pos + "2"] = a, j[d.counterUnits.pos + "1"] = e, j[d.counterUnits.pos + "2"] = e + f; var k = g.elem("line", j, h.join(" ")); i.emit("draw", b.extend({ type: "grid", axis: d, index: c, group: g, element: k }, j)) }, b.createGridBackground = function (a, b, c, d) { var e = a.elem("rect", { x: b.x1, y: b.y2, width: b.width(), height: b.height() }, c, !0); d.emit("draw", { type: "gridBackground", group: a, element: e }) }, b.createLabel = function (a, c, e, f, g, h, i, j, k, l, m) { var n, o = {}; if (o[g.units.pos] = a + i[g.units.pos], o[g.counterUnits.pos] = i[g.counterUnits.pos], o[g.units.len] = c, o[g.counterUnits.len] = Math.max(0, h - 10), l) { var p = d.createElement("span"); p.className = k.join(" "), p.setAttribute("xmlns", b.namespaces.xhtml), p.innerText = f[e], p.style[g.units.len] = Math.round(o[g.units.len]) + "px", p.style[g.counterUnits.len] = Math.round(o[g.counterUnits.len]) + "px", n = j.foreignObject(p, b.extend({ style: "overflow: visible;" }, o)) } else n = j.elem("text", o, k.join(" ")).text(f[e]); m.emit("draw", b.extend({ type: "label", axis: g, index: e, group: j, element: n, text: f[e] }, o)) }, b.getSeriesOption = function (a, b, c) { if (a.name && b.series && b.series[a.name]) { var d = b.series[a.name]; return d.hasOwnProperty(c) ? d[c] : b[c] } return b[c] }, b.optionsProvider = function (a, d, e) { function f(a) { var f = h; if (h = b.extend({}, j), d) for (i = 0; i < d.length; i++) { var g = c.matchMedia(d[i][0]); g.matches && (h = b.extend(h, d[i][1])) } e && a && e.emit("optionsChanged", { previousOptions: f, currentOptions: h }) } function g() { k.forEach(function (a) { a.removeListener(f) }) } var h, i, j = b.extend({}, a), k = []; if (!c.matchMedia) throw "window.matchMedia not found! Make sure you're using a polyfill."; if (d) for (i = 0; i < d.length; i++) { var l = c.matchMedia(d[i][0]); l.addListener(f), k.push(l) } return f(), { removeMediaQueryListeners: g, getCurrentOptions: function () { return b.extend({}, h) } } }, b.splitIntoSegments = function (a, c, d) { var e = { increasingX: !1, fillHoles: !1 }; d = b.extend({}, e, d); for (var f = [], g = !0, h = 0; h < a.length; h += 2)void 0 === b.getMultiValue(c[h / 2].value) ? d.fillHoles || (g = !0) : (d.increasingX && h >= 2 && a[h] <= a[h - 2] && (g = !0), g && (f.push({ pathCoordinates: [], valueData: [] }), g = !1), f[f.length - 1].pathCoordinates.push(a[h], a[h + 1]), f[f.length - 1].valueData.push(c[h / 2])); return f } }(this || global, a), function (a, b) { "use strict"; b.Interpolation = {}, b.Interpolation.none = function (a) { var c = { fillHoles: !1 }; return a = b.extend({}, c, a), function (c, d) { for (var e = new b.Svg.Path, f = !0, g = 0; g < c.length; g += 2) { var h = c[g], i = c[g + 1], j = d[g / 2]; void 0 !== b.getMultiValue(j.value) ? (f ? e.move(h, i, !1, j) : e.line(h, i, !1, j), f = !1) : a.fillHoles || (f = !0) } return e } }, b.Interpolation.simple = function (a) { var c = { divisor: 2, fillHoles: !1 }; a = b.extend({}, c, a); var d = 1 / Math.max(1, a.divisor); return function (c, e) { for (var f, g, h, i = new b.Svg.Path, j = 0; j < c.length; j += 2) { var k = c[j], l = c[j + 1], m = (k - f) * d, n = e[j / 2]; void 0 !== n.value ? (void 0 === h ? i.move(k, l, !1, n) : i.curve(f + m, g, k - m, l, k, l, !1, n), f = k, g = l, h = n) : a.fillHoles || (f = k = h = void 0) } return i } }, b.Interpolation.cardinal = function (a) { var c = { tension: 1, fillHoles: !1 }; a = b.extend({}, c, a); var d = Math.min(1, Math.max(0, a.tension)), e = 1 - d; return function f(c, g) { var h = b.splitIntoSegments(c, g, { fillHoles: a.fillHoles }); if (h.length) { if (h.length > 1) { var i = []; return h.forEach(function (a) { i.push(f(a.pathCoordinates, a.valueData)) }), b.Svg.Path.join(i) } if (c = h[0].pathCoordinates, g = h[0].valueData, c.length <= 4) return b.Interpolation.none()(c, g); for (var j, k = (new b.Svg.Path).move(c[0], c[1], !1, g[0]), l = 0, m = c.length; m - 2 * !j > l; l += 2) { var n = [{ x: +c[l - 2], y: +c[l - 1] }, { x: +c[l], y: +c[l + 1] }, { x: +c[l + 2], y: +c[l + 3] }, { x: +c[l + 4], y: +c[l + 5] }]; j ? l ? m - 4 === l ? n[3] = { x: +c[0], y: +c[1] } : m - 2 === l && (n[2] = { x: +c[0], y: +c[1] }, n[3] = { x: +c[2], y: +c[3] }) : n[0] = { x: +c[m - 2], y: +c[m - 1] } : m - 4 === l ? n[3] = n[2] : l || (n[0] = { x: +c[l], y: +c[l + 1] }), k.curve(d * (-n[0].x + 6 * n[1].x + n[2].x) / 6 + e * n[2].x, d * (-n[0].y + 6 * n[1].y + n[2].y) / 6 + e * n[2].y, d * (n[1].x + 6 * n[2].x - n[3].x) / 6 + e * n[2].x, d * (n[1].y + 6 * n[2].y - n[3].y) / 6 + e * n[2].y, n[2].x, n[2].y, !1, g[(l + 2) / 2]) } return k } return b.Interpolation.none()([]) } }, b.Interpolation.monotoneCubic = function (a) { var c = { fillHoles: !1 }; return a = b.extend({}, c, a), function d(c, e) { var f = b.splitIntoSegments(c, e, { fillHoles: a.fillHoles, increasingX: !0 }); if (f.length) { if (f.length > 1) { var g = []; return f.forEach(function (a) { g.push(d(a.pathCoordinates, a.valueData)) }), b.Svg.Path.join(g) } if (c = f[0].pathCoordinates, e = f[0].valueData, c.length <= 4) return b.Interpolation.none()(c, e); var h, i, j = [], k = [], l = c.length / 2, m = [], n = [], o = [], p = []; for (h = 0; h < l; h++)j[h] = c[2 * h], k[h] = c[2 * h + 1]; for (h = 0; h < l - 1; h++)o[h] = k[h + 1] - k[h], p[h] = j[h + 1] - j[h], n[h] = o[h] / p[h]; for (m[0] = n[0], m[l - 1] = n[l - 2], h = 1; h < l - 1; h++)0 === n[h] || 0 === n[h - 1] || n[h - 1] > 0 != n[h] > 0 ? m[h] = 0 : (m[h] = 3 * (p[h - 1] + p[h]) / ((2 * p[h] + p[h - 1]) / n[h - 1] + (p[h] + 2 * p[h - 1]) / n[h]), isFinite(m[h]) || (m[h] = 0)); for (i = (new b.Svg.Path).move(j[0], k[0], !1, e[0]), h = 0; h < l - 1; h++)i.curve(j[h] + p[h] / 3, k[h] + m[h] * p[h] / 3, j[h + 1] - p[h] / 3, k[h + 1] - m[h + 1] * p[h] / 3, j[h + 1], k[h + 1], !1, e[h + 1]); return i } return b.Interpolation.none()([]) } }, b.Interpolation.step = function (a) { var c = { postpone: !0, fillHoles: !1 }; return a = b.extend({}, c, a), function (c, d) { for (var e, f, g, h = new b.Svg.Path, i = 0; i < c.length; i += 2) { var j = c[i], k = c[i + 1], l = d[i / 2]; void 0 !== l.value ? (void 0 === g ? h.move(j, k, !1, l) : (a.postpone ? h.line(j, f, !1, g) : h.line(e, k, !1, l), h.line(j, k, !1, l)), e = j, f = k, g = l) : a.fillHoles || (e = f = g = void 0) } return h } } }(this || global, a), function (a, b) { "use strict"; b.EventEmitter = function () { function a(a, b) { d[a] = d[a] || [], d[a].push(b) } function b(a, b) { d[a] && (b ? (d[a].splice(d[a].indexOf(b), 1), 0 === d[a].length && delete d[a]) : delete d[a]) } function c(a, b) { d[a] && d[a].forEach(function (a) { a(b) }), d["*"] && d["*"].forEach(function (c) { c(a, b) }) } var d = []; return { addEventHandler: a, removeEventHandler: b, emit: c } } }(this || global, a), function (a, b) { "use strict"; function c(a) { var b = []; if (a.length) for (var c = 0; c < a.length; c++)b.push(a[c]); return b } function d(a, c) { var d = c || this.prototype || b.Class, e = Object.create(d); b.Class.cloneDefinitions(e, a); var f = function () { var a, c = e.constructor || function () { }; return a = this === b ? Object.create(e) : this, c.apply(a, Array.prototype.slice.call(arguments, 0)), a }; return f.prototype = e, f["super"] = d, f.extend = this.extend, f } function e() { var a = c(arguments), b = a[0]; return a.splice(1, a.length - 1).forEach(function (a) { Object.getOwnPropertyNames(a).forEach(function (c) { delete b[c], Object.defineProperty(b, c, Object.getOwnPropertyDescriptor(a, c)) }) }), b } b.Class = { extend: d, cloneDefinitions: e } }(this || global, a), function (a, b) { "use strict"; function c(a, c, d) { return a && (this.data = a || {}, this.data.labels = this.data.labels || [], this.data.series = this.data.series || [], this.eventEmitter.emit("data", { type: "update", data: this.data })), c && (this.options = b.extend({}, d ? this.options : this.defaultOptions, c), this.initializeTimeoutId || (this.optionsProvider.removeMediaQueryListeners(), this.optionsProvider = b.optionsProvider(this.options, this.responsiveOptions, this.eventEmitter))), this.initializeTimeoutId || this.createChart(this.optionsProvider.getCurrentOptions()), this } function d() { return this.initializeTimeoutId ? i.clearTimeout(this.initializeTimeoutId) : (i.removeEventListener("resize", this.resizeListener), this.optionsProvider.removeMediaQueryListeners()), this } function e(a, b) { return this.eventEmitter.addEventHandler(a, b), this } function f(a, b) { return this.eventEmitter.removeEventHandler(a, b), this } function g() { i.addEventListener("resize", this.resizeListener), this.optionsProvider = b.optionsProvider(this.options, this.responsiveOptions, this.eventEmitter), this.eventEmitter.addEventHandler("optionsChanged", function () { this.update() }.bind(this)), this.options.plugins && this.options.plugins.forEach(function (a) { a instanceof Array ? a[0](this, a[1]) : a(this) }.bind(this)), this.eventEmitter.emit("data", { type: "initial", data: this.data }), this.createChart(this.optionsProvider.getCurrentOptions()), this.initializeTimeoutId = void 0 } function h(a, c, d, e, f) { this.container = b.querySelector(a), this.data = c || {}, this.data.labels = this.data.labels || [], this.data.series = this.data.series || [], this.defaultOptions = d, this.options = e, this.responsiveOptions = f, this.eventEmitter = b.EventEmitter(), this.supportsForeignObject = b.Svg.isSupported("Extensibility"), this.supportsAnimations = b.Svg.isSupported("AnimationEventsAttribute"), this.resizeListener = function () { this.update() }.bind(this), this.container && (this.container.__chartist__ && this.container.__chartist__.detach(), this.container.__chartist__ = this), this.initializeTimeoutId = setTimeout(g.bind(this), 0) } var i = a.window; b.Base = b.Class.extend({ constructor: h, optionsProvider: void 0, container: void 0, svg: void 0, eventEmitter: void 0, createChart: function () { throw new Error("Base chart type can't be instantiated!") }, update: c, detach: d, on: e, off: f, version: b.version, supportsForeignObject: !1 }) }(this || global, a), function (a, b) { "use strict"; function c(a, c, d, e, f) { a instanceof Element ? this._node = a : (this._node = y.createElementNS(b.namespaces.svg, a), "svg" === a && this.attr({ "xmlns:ct": b.namespaces.ct })), c && this.attr(c), d && this.addClass(d), e && (f && e._node.firstChild ? e._node.insertBefore(this._node, e._node.firstChild) : e._node.appendChild(this._node)) } function d(a, c) { return "string" == typeof a ? c ? this._node.getAttributeNS(c, a) : this._node.getAttribute(a) : (Object.keys(a).forEach(function (c) { if (void 0 !== a[c]) if (c.indexOf(":") !== -1) { var d = c.split(":"); this._node.setAttributeNS(b.namespaces[d[0]], c, a[c]) } else this._node.setAttribute(c, a[c]) }.bind(this)), this) } function e(a, c, d, e) { return new b.Svg(a, c, d, this, e) } function f() { return this._node.parentNode instanceof SVGElement ? new b.Svg(this._node.parentNode) : null } function g() { for (var a = this._node; "svg" !== a.nodeName;)a = a.parentNode; return new b.Svg(a) } function h(a) { var c = this._node.querySelector(a); return c ? new b.Svg(c) : null } function i(a) { var c = this._node.querySelectorAll(a); return c.length ? new b.Svg.List(c) : null } function j() { return this._node } function k(a, c, d, e) { if ("string" == typeof a) { var f = y.createElement("div"); f.innerHTML = a, a = f.firstChild } a.setAttribute("xmlns", b.namespaces.xmlns); var g = this.elem("foreignObject", c, d, e); return g._node.appendChild(a), g } function l(a) { return this._node.appendChild(y.createTextNode(a)), this } function m() { for (; this._node.firstChild;)this._node.removeChild(this._node.firstChild); return this } function n() { return this._node.parentNode.removeChild(this._node), this.parent() } function o(a) { return this._node.parentNode.replaceChild(a._node, this._node), a } function p(a, b) { return b && this._node.firstChild ? this._node.insertBefore(a._node, this._node.firstChild) : this._node.appendChild(a._node), this } function q() { return this._node.getAttribute("class") ? this._node.getAttribute("class").trim().split(/\s+/) : [] } function r(a) { return this._node.setAttribute("class", this.classes(this._node).concat(a.trim().split(/\s+/)).filter(function (a, b, c) { return c.indexOf(a) === b }).join(" ")), this } function s(a) { var b = a.trim().split(/\s+/); return this._node.setAttribute("class", this.classes(this._node).filter(function (a) { return b.indexOf(a) === -1 }).join(" ")), this } function t() { return this._node.setAttribute("class", ""), this } function u() { return this._node.getBoundingClientRect().height } function v() { return this._node.getBoundingClientRect().width } function w(a, c, d) { return void 0 === c && (c = !0), Object.keys(a).forEach(function (e) { function f(a, c) { var f, g, h, i = {}; a.easing && (h = a.easing instanceof Array ? a.easing : b.Svg.Easing[a.easing], delete a.easing), a.begin = b.ensureUnit(a.begin, "ms"), a.dur = b.ensureUnit(a.dur, "ms"), h && (a.calcMode = "spline", a.keySplines = h.join(" "), a.keyTimes = "0;1"), c && (a.fill = "freeze", i[e] = a.from, this.attr(i), g = b.quantity(a.begin || 0).value, a.begin = "indefinite"), f = this.elem("animate", b.extend({ attributeName: e }, a)), c && setTimeout(function () { try { f._node.beginElement() } catch (b) { i[e] = a.to, this.attr(i), f.remove() } }.bind(this), g), d && f._node.addEventListener("beginEvent", function () { d.emit("animationBegin", { element: this, animate: f._node, params: a }) }.bind(this)), f._node.addEventListener("endEvent", function () { d && d.emit("animationEnd", { element: this, animate: f._node, params: a }), c && (i[e] = a.to, this.attr(i), f.remove()) }.bind(this)) } a[e] instanceof Array ? a[e].forEach(function (a) { f.bind(this)(a, !1) }.bind(this)) : f.bind(this)(a[e], c) }.bind(this)), this } function x(a) { var c = this; this.svgElements = []; for (var d = 0; d < a.length; d++)this.svgElements.push(new b.Svg(a[d])); Object.keys(b.Svg.prototype).filter(function (a) { return ["constructor", "parent", "querySelector", "querySelectorAll", "replace", "append", "classes", "height", "width"].indexOf(a) === -1 }).forEach(function (a) { c[a] = function () { var d = Array.prototype.slice.call(arguments, 0); return c.svgElements.forEach(function (c) { b.Svg.prototype[a].apply(c, d) }), c } }) } var y = a.document; b.Svg = b.Class.extend({ constructor: c, attr: d, elem: e, parent: f, root: g, querySelector: h, querySelectorAll: i, getNode: j, foreignObject: k, text: l, empty: m, remove: n, replace: o, append: p, classes: q, addClass: r, removeClass: s, removeAllClasses: t, height: u, width: v, animate: w }), b.Svg.isSupported = function (a) { return y.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#" + a, "1.1") }; var z = { easeInSine: [.47, 0, .745, .715], easeOutSine: [.39, .575, .565, 1], easeInOutSine: [.445, .05, .55, .95], easeInQuad: [.55, .085, .68, .53], easeOutQuad: [.25, .46, .45, .94], easeInOutQuad: [.455, .03, .515, .955], easeInCubic: [.55, .055, .675, .19], easeOutCubic: [.215, .61, .355, 1], easeInOutCubic: [.645, .045, .355, 1], easeInQuart: [.895, .03, .685, .22], easeOutQuart: [.165, .84, .44, 1], easeInOutQuart: [.77, 0, .175, 1], easeInQuint: [.755, .05, .855, .06], easeOutQuint: [.23, 1, .32, 1], easeInOutQuint: [.86, 0, .07, 1], easeInExpo: [.95, .05, .795, .035], easeOutExpo: [.19, 1, .22, 1], easeInOutExpo: [1, 0, 0, 1], easeInCirc: [.6, .04, .98, .335], easeOutCirc: [.075, .82, .165, 1], easeInOutCirc: [.785, .135, .15, .86], easeInBack: [.6, -.28, .735, .045], easeOutBack: [.175, .885, .32, 1.275], easeInOutBack: [.68, -.55, .265, 1.55] }; b.Svg.Easing = z, b.Svg.List = b.Class.extend({ constructor: x }) }(this || global, a), function (a, b) { "use strict"; function c(a, c, d, e, f, g) { var h = b.extend({ command: f ? a.toLowerCase() : a.toUpperCase() }, c, g ? { data: g } : {}); d.splice(e, 0, h) } function d(a, b) { a.forEach(function (c, d) { t[c.command.toLowerCase()].forEach(function (e, f) { b(c, e, d, f, a) }) }) } function e(a, c) { this.pathElements = [], this.pos = 0, this.close = a, this.options = b.extend({}, u, c) } function f(a) { return void 0 !== a ? (this.pos = Math.max(0, Math.min(this.pathElements.length, a)), this) : this.pos } function g(a) { return this.pathElements.splice(this.pos, a), this } function h(a, b, d, e) { return c("M", { x: +a, y: +b }, this.pathElements, this.pos++, d, e), this } function i(a, b, d, e) { return c("L", { x: +a, y: +b }, this.pathElements, this.pos++, d, e), this } function j(a, b, d, e, f, g, h, i) { return c("C", { x1: +a, y1: +b, x2: +d, y2: +e, x: +f, y: +g }, this.pathElements, this.pos++, h, i), this } function k(a, b, d, e, f, g, h, i, j) { return c("A", { rx: +a, ry: +b, xAr: +d, lAf: +e, sf: +f, x: +g, y: +h }, this.pathElements, this.pos++, i, j), this } function l(a) { var c = a.replace(/([A-Za-z])([0-9])/g, "$1 $2").replace(/([0-9])([A-Za-z])/g, "$1 $2").split(/[\s,]+/).reduce(function (a, b) { return b.match(/[A-Za-z]/) && a.push([]), a[a.length - 1].push(b), a }, []); "Z" === c[c.length - 1][0].toUpperCase() && c.pop(); var d = c.map(function (a) { var c = a.shift(), d = t[c.toLowerCase()]; return b.extend({ command: c }, d.reduce(function (b, c, d) { return b[c] = +a[d], b }, {})) }), e = [this.pos, 0]; return Array.prototype.push.apply(e, d), Array.prototype.splice.apply(this.pathElements, e), this.pos += d.length, this } function m() { var a = Math.pow(10, this.options.accuracy); return this.pathElements.reduce(function (b, c) { var d = t[c.command.toLowerCase()].map(function (b) { return this.options.accuracy ? Math.round(c[b] * a) / a : c[b] }.bind(this)); return b + c.command + d.join(",") }.bind(this), "") + (this.close ? "Z" : "") } function n(a, b) { return d(this.pathElements, function (c, d) { c[d] *= "x" === d[0] ? a : b }), this } function o(a, b) { return d(this.pathElements, function (c, d) { c[d] += "x" === d[0] ? a : b }), this } function p(a) { return d(this.pathElements, function (b, c, d, e, f) { var g = a(b, c, d, e, f); (g || 0 === g) && (b[c] = g) }), this } function q(a) { var c = new b.Svg.Path(a || this.close); return c.pos = this.pos, c.pathElements = this.pathElements.slice().map(function (a) { return b.extend({}, a) }), c.options = b.extend({}, this.options), c } function r(a) { var c = [new b.Svg.Path]; return this.pathElements.forEach(function (d) { d.command === a.toUpperCase() && 0 !== c[c.length - 1].pathElements.length && c.push(new b.Svg.Path), c[c.length - 1].pathElements.push(d) }), c } function s(a, c, d) { for (var e = new b.Svg.Path(c, d), f = 0; f < a.length; f++)for (var g = a[f], h = 0; h < g.pathElements.length; h++)e.pathElements.push(g.pathElements[h]); return e } var t = { m: ["x", "y"], l: ["x", "y"], c: ["x1", "y1", "x2", "y2", "x", "y"], a: ["rx", "ry", "xAr", "lAf", "sf", "x", "y"] }, u = { accuracy: 3 }; b.Svg.Path = b.Class.extend({ constructor: e, position: f, remove: g, move: h, line: i, curve: j, arc: k, scale: n, translate: o, transform: p, parse: l, stringify: m, clone: q, splitByCommand: r }), b.Svg.Path.elementDescriptions = t, b.Svg.Path.join = s }(this || global, a), function (a, b) { "use strict"; function c(a, b, c, d) { this.units = a, this.counterUnits = a === e.x ? e.y : e.x, this.chartRect = b, this.axisLength = b[a.rectEnd] - b[a.rectStart], this.gridOffset = b[a.rectOffset], this.ticks = c, this.options = d } function d(a, c, d, e, f) { var g = e["axis" + this.units.pos.toUpperCase()], h = this.ticks.map(this.projectValue.bind(this)), i = this.ticks.map(g.labelInterpolationFnc); h.forEach(function (j, k) { var l, m = { x: 0, y: 0 }; l = h[k + 1] ? h[k + 1] - j : Math.max(this.axisLength - j, 30), b.isFalseyButZero(i[k]) && "" !== i[k] || ("x" === this.units.pos ? (j = this.chartRect.x1 + j, m.x = e.axisX.labelOffset.x, "start" === e.axisX.position ? m.y = this.chartRect.padding.top + e.axisX.labelOffset.y + (d ? 5 : 20) : m.y = this.chartRect.y1 + e.axisX.labelOffset.y + (d ? 5 : 20)) : (j = this.chartRect.y1 - j, m.y = e.axisY.labelOffset.y - (d ? l : 0), "start" === e.axisY.position ? m.x = d ? this.chartRect.padding.left + e.axisY.labelOffset.x : this.chartRect.x1 - 10 : m.x = this.chartRect.x2 + e.axisY.labelOffset.x + 10), g.showGrid && b.createGrid(j, k, this, this.gridOffset, this.chartRect[this.counterUnits.len](), a, [e.classNames.grid, e.classNames[this.units.dir]], f), g.showLabel && b.createLabel(j, l, k, i, this, g.offset, m, c, [e.classNames.label, e.classNames[this.units.dir], "start" === g.position ? e.classNames[g.position] : e.classNames.end], d, f)) }.bind(this)) } var e = (a.window, a.document, { x: { pos: "x", len: "width", dir: "horizontal", rectStart: "x1", rectEnd: "x2", rectOffset: "y2" }, y: { pos: "y", len: "height", dir: "vertical", rectStart: "y2", rectEnd: "y1", rectOffset: "x1" } }); b.Axis = b.Class.extend({ constructor: c, createGridAndLabels: d, projectValue: function (a, b, c) { throw new Error("Base axis can't be instantiated!") } }), b.Axis.units = e }(this || global, a), function (a, b) { "use strict"; function c(a, c, d, e) { var f = e.highLow || b.getHighLow(c, e, a.pos); this.bounds = b.getBounds(d[a.rectEnd] - d[a.rectStart], f, e.scaleMinSpace || 20, e.onlyInteger), this.range = { min: this.bounds.min, max: this.bounds.max }, b.AutoScaleAxis["super"].constructor.call(this, a, d, this.bounds.values, e) } function d(a) { return this.axisLength * (+b.getMultiValue(a, this.units.pos) - this.bounds.min) / this.bounds.range } a.window, a.document; b.AutoScaleAxis = b.Axis.extend({ constructor: c, projectValue: d }) }(this || global, a), function (a, b) { "use strict"; function c(a, c, d, e) { var f = e.highLow || b.getHighLow(c, e, a.pos); this.divisor = e.divisor || 1, this.ticks = e.ticks || b.times(this.divisor).map(function (a, b) { return f.low + (f.high - f.low) / this.divisor * b }.bind(this)), this.ticks.sort(function (a, b) { return a - b }), this.range = { min: f.low, max: f.high }, b.FixedScaleAxis["super"].constructor.call(this, a, d, this.ticks, e), this.stepLength = this.axisLength / this.divisor } function d(a) { return this.axisLength * (+b.getMultiValue(a, this.units.pos) - this.range.min) / (this.range.max - this.range.min) } a.window, a.document; b.FixedScaleAxis = b.Axis.extend({ constructor: c, projectValue: d }) }(this || global, a), function (a, b) { "use strict"; function c(a, c, d, e) { b.StepAxis["super"].constructor.call(this, a, d, e.ticks, e); var f = Math.max(1, e.ticks.length - (e.stretch ? 1 : 0)); this.stepLength = this.axisLength / f } function d(a, b) { return this.stepLength * b } a.window, a.document; b.StepAxis = b.Axis.extend({ constructor: c, projectValue: d }) }(this || global, a), function (a, b) { "use strict"; function c(a) { var c = b.normalizeData(this.data, a.reverseData, !0); this.svg = b.createSvg(this.container, a.width, a.height, a.classNames.chart); var d, f, g = this.svg.elem("g").addClass(a.classNames.gridGroup), h = this.svg.elem("g"), i = this.svg.elem("g").addClass(a.classNames.labelGroup), j = b.createChartRect(this.svg, a, e.padding); d = void 0 === a.axisX.type ? new b.StepAxis(b.Axis.units.x, c.normalized.series, j, b.extend({}, a.axisX, { ticks: c.normalized.labels, stretch: a.fullWidth })) : a.axisX.type.call(b, b.Axis.units.x, c.normalized.series, j, a.axisX), f = void 0 === a.axisY.type ? new b.AutoScaleAxis(b.Axis.units.y, c.normalized.series, j, b.extend({}, a.axisY, { high: b.isNumeric(a.high) ? a.high : a.axisY.high, low: b.isNumeric(a.low) ? a.low : a.axisY.low })) : a.axisY.type.call(b, b.Axis.units.y, c.normalized.series, j, a.axisY), d.createGridAndLabels(g, i, this.supportsForeignObject, a, this.eventEmitter), f.createGridAndLabels(g, i, this.supportsForeignObject, a, this.eventEmitter), a.showGridBackground && b.createGridBackground(g, j, a.classNames.gridBackground, this.eventEmitter), c.raw.series.forEach(function (e, g) { var i = h.elem("g"); i.attr({ "ct:series-name": e.name, "ct:meta": b.serialize(e.meta) }), i.addClass([a.classNames.series, e.className || a.classNames.series + "-" + b.alphaNumerate(g)].join(" ")); var k = [], l = []; c.normalized.series[g].forEach(function (a, h) { var i = { x: j.x1 + d.projectValue(a, h, c.normalized.series[g]), y: j.y1 - f.projectValue(a, h, c.normalized.series[g]) }; k.push(i.x, i.y), l.push({ value: a, valueIndex: h, meta: b.getMetaData(e, h) }) }.bind(this)); var m = { lineSmooth: b.getSeriesOption(e, a, "lineSmooth"), showPoint: b.getSeriesOption(e, a, "showPoint"), showLine: b.getSeriesOption(e, a, "showLine"), showArea: b.getSeriesOption(e, a, "showArea"), areaBase: b.getSeriesOption(e, a, "areaBase") }, n = "function" == typeof m.lineSmooth ? m.lineSmooth : m.lineSmooth ? b.Interpolation.monotoneCubic() : b.Interpolation.none(), o = n(k, l); if (m.showPoint && o.pathElements.forEach(function (c) { var h = i.elem("line", { x1: c.x, y1: c.y, x2: c.x + .01, y2: c.y }, a.classNames.point).attr({ "ct:value": [c.data.value.x, c.data.value.y].filter(b.isNumeric).join(","), "ct:meta": b.serialize(c.data.meta) }); this.eventEmitter.emit("draw", { type: "point", value: c.data.value, index: c.data.valueIndex, meta: c.data.meta, series: e, seriesIndex: g, axisX: d, axisY: f, group: i, element: h, x: c.x, y: c.y }) }.bind(this)), m.showLine) { var p = i.elem("path", { d: o.stringify() }, a.classNames.line, !0); this.eventEmitter.emit("draw", { type: "line", values: c.normalized.series[g], path: o.clone(), chartRect: j, index: g, series: e, seriesIndex: g, seriesMeta: e.meta, axisX: d, axisY: f, group: i, element: p }) } if (m.showArea && f.range) { var q = Math.max(Math.min(m.areaBase, f.range.max), f.range.min), r = j.y1 - f.projectValue(q); o.splitByCommand("M").filter(function (a) { return a.pathElements.length > 1 }).map(function (a) { var b = a.pathElements[0], c = a.pathElements[a.pathElements.length - 1]; return a.clone(!0).position(0).remove(1).move(b.x, r).line(b.x, b.y).position(a.pathElements.length + 1).line(c.x, r) }).forEach(function (b) { var h = i.elem("path", { d: b.stringify() }, a.classNames.area, !0); this.eventEmitter.emit("draw", { type: "area", values: c.normalized.series[g], path: b.clone(), series: e, seriesIndex: g, axisX: d, axisY: f, chartRect: j, index: g, group: i, element: h }) }.bind(this)) } }.bind(this)), this.eventEmitter.emit("created", { bounds: f.bounds, chartRect: j, axisX: d, axisY: f, svg: this.svg, options: a }) } function d(a, c, d, f) { b.Line["super"].constructor.call(this, a, c, e, b.extend({}, e, d), f) } var e = (a.window, a.document, { axisX: { offset: 30, position: "end", labelOffset: { x: 0, y: 0 }, showLabel: !0, showGrid: !0, labelInterpolationFnc: b.noop, type: void 0 }, axisY: { offset: 40, position: "start", labelOffset: { x: 0, y: 0 }, showLabel: !0, showGrid: !0, labelInterpolationFnc: b.noop, type: void 0, scaleMinSpace: 20, onlyInteger: !1 }, width: void 0, height: void 0, showLine: !0, showPoint: !0, showArea: !1, areaBase: 0, lineSmooth: !0, showGridBackground: !1, low: void 0, high: void 0, chartPadding: { top: 15, right: 15, bottom: 5, left: 10 }, fullWidth: !1, reverseData: !1, classNames: { chart: "ct-chart-line", label: "ct-label", labelGroup: "ct-labels", series: "ct-series", line: "ct-line", point: "ct-point", area: "ct-area", grid: "ct-grid", gridGroup: "ct-grids", gridBackground: "ct-grid-background", vertical: "ct-vertical", horizontal: "ct-horizontal", start: "ct-start", end: "ct-end" } }); b.Line = b.Base.extend({ constructor: d, createChart: c }) }(this || global, a), function (a, b) { - "use strict"; function c(a) { - var c, d; a.distributeSeries ? (c = b.normalizeData(this.data, a.reverseData, a.horizontalBars ? "x" : "y"), c.normalized.series = c.normalized.series.map(function (a) { return [a] })) : c = b.normalizeData(this.data, a.reverseData, a.horizontalBars ? "x" : "y"), this.svg = b.createSvg(this.container, a.width, a.height, a.classNames.chart + (a.horizontalBars ? " " + a.classNames.horizontalBars : "")); var f = this.svg.elem("g").addClass(a.classNames.gridGroup), g = this.svg.elem("g"), h = this.svg.elem("g").addClass(a.classNames.labelGroup); - if (a.stackBars && 0 !== c.normalized.series.length) { var i = b.serialMap(c.normalized.series, function () { return Array.prototype.slice.call(arguments).map(function (a) { return a }).reduce(function (a, b) { return { x: a.x + (b && b.x) || 0, y: a.y + (b && b.y) || 0 } }, { x: 0, y: 0 }) }); d = b.getHighLow([i], a, a.horizontalBars ? "x" : "y") } else d = b.getHighLow(c.normalized.series, a, a.horizontalBars ? "x" : "y"); d.high = +a.high || (0 === a.high ? 0 : d.high), d.low = +a.low || (0 === a.low ? 0 : d.low); var j, k, l, m, n, o = b.createChartRect(this.svg, a, e.padding); k = a.distributeSeries && a.stackBars ? c.normalized.labels.slice(0, 1) : c.normalized.labels, a.horizontalBars ? (j = m = void 0 === a.axisX.type ? new b.AutoScaleAxis(b.Axis.units.x, c.normalized.series, o, b.extend({}, a.axisX, { highLow: d, referenceValue: 0 })) : a.axisX.type.call(b, b.Axis.units.x, c.normalized.series, o, b.extend({}, a.axisX, { highLow: d, referenceValue: 0 })), l = n = void 0 === a.axisY.type ? new b.StepAxis(b.Axis.units.y, c.normalized.series, o, { ticks: k }) : a.axisY.type.call(b, b.Axis.units.y, c.normalized.series, o, a.axisY)) : (l = m = void 0 === a.axisX.type ? new b.StepAxis(b.Axis.units.x, c.normalized.series, o, { ticks: k }) : a.axisX.type.call(b, b.Axis.units.x, c.normalized.series, o, a.axisX), j = n = void 0 === a.axisY.type ? new b.AutoScaleAxis(b.Axis.units.y, c.normalized.series, o, b.extend({}, a.axisY, { highLow: d, referenceValue: 0 })) : a.axisY.type.call(b, b.Axis.units.y, c.normalized.series, o, b.extend({}, a.axisY, { highLow: d, referenceValue: 0 }))); var p = a.horizontalBars ? o.x1 + j.projectValue(0) : o.y1 - j.projectValue(0), q = []; l.createGridAndLabels(f, h, this.supportsForeignObject, a, this.eventEmitter), j.createGridAndLabels(f, h, this.supportsForeignObject, a, this.eventEmitter), a.showGridBackground && b.createGridBackground(f, o, a.classNames.gridBackground, this.eventEmitter), c.raw.series.forEach(function (d, e) { var f, h, i = e - (c.raw.series.length - 1) / 2; f = a.distributeSeries && !a.stackBars ? l.axisLength / c.normalized.series.length / 2 : a.distributeSeries && a.stackBars ? l.axisLength / 2 : l.axisLength / c.normalized.series[e].length / 2, h = g.elem("g"), h.attr({ "ct:series-name": d.name, "ct:meta": b.serialize(d.meta) }), h.addClass([a.classNames.series, d.className || a.classNames.series + "-" + b.alphaNumerate(e)].join(" ")), c.normalized.series[e].forEach(function (g, k) { var r, s, t, u; if (u = a.distributeSeries && !a.stackBars ? e : a.distributeSeries && a.stackBars ? 0 : k, r = a.horizontalBars ? { x: o.x1 + j.projectValue(g && g.x ? g.x : 0, k, c.normalized.series[e]), y: o.y1 - l.projectValue(g && g.y ? g.y : 0, u, c.normalized.series[e]) } : { x: o.x1 + l.projectValue(g && g.x ? g.x : 0, u, c.normalized.series[e]), y: o.y1 - j.projectValue(g && g.y ? g.y : 0, k, c.normalized.series[e]) }, l instanceof b.StepAxis && (l.options.stretch || (r[l.units.pos] += f * (a.horizontalBars ? -1 : 1)), r[l.units.pos] += a.stackBars || a.distributeSeries ? 0 : i * a.seriesBarDistance * (a.horizontalBars ? -1 : 1)), t = q[k] || p, q[k] = t - (p - r[l.counterUnits.pos]), void 0 !== g) { var v = {}; v[l.units.pos + "1"] = r[l.units.pos], v[l.units.pos + "2"] = r[l.units.pos], !a.stackBars || "accumulate" !== a.stackMode && a.stackMode ? (v[l.counterUnits.pos + "1"] = p, v[l.counterUnits.pos + "2"] = r[l.counterUnits.pos]) : (v[l.counterUnits.pos + "1"] = t, v[l.counterUnits.pos + "2"] = q[k]), v.x1 = Math.min(Math.max(v.x1, o.x1), o.x2), v.x2 = Math.min(Math.max(v.x2, o.x1), o.x2), v.y1 = Math.min(Math.max(v.y1, o.y2), o.y1), v.y2 = Math.min(Math.max(v.y2, o.y2), o.y1); var w = b.getMetaData(d, k); s = h.elem("line", v, a.classNames.bar).attr({ "ct:value": [g.x, g.y].filter(b.isNumeric).join(","), "ct:meta": b.serialize(w) }), this.eventEmitter.emit("draw", b.extend({ type: "bar", value: g, index: k, meta: w, series: d, seriesIndex: e, axisX: m, axisY: n, chartRect: o, group: h, element: s }, v)) } }.bind(this)) }.bind(this)), this.eventEmitter.emit("created", { bounds: j.bounds, chartRect: o, axisX: m, axisY: n, svg: this.svg, options: a }) - } function d(a, c, d, f) { b.Bar["super"].constructor.call(this, a, c, e, b.extend({}, e, d), f) } var e = (a.window, a.document, { axisX: { offset: 30, position: "end", labelOffset: { x: 0, y: 0 }, showLabel: !0, showGrid: !0, labelInterpolationFnc: b.noop, scaleMinSpace: 30, onlyInteger: !1 }, axisY: { offset: 40, position: "start", labelOffset: { x: 0, y: 0 }, showLabel: !0, showGrid: !0, labelInterpolationFnc: b.noop, scaleMinSpace: 20, onlyInteger: !1 }, width: void 0, height: void 0, high: void 0, low: void 0, referenceValue: 0, chartPadding: { top: 15, right: 15, bottom: 5, left: 10 }, seriesBarDistance: 15, stackBars: !1, stackMode: "accumulate", horizontalBars: !1, distributeSeries: !1, reverseData: !1, showGridBackground: !1, classNames: { chart: "ct-chart-bar", horizontalBars: "ct-horizontal-bars", label: "ct-label", labelGroup: "ct-labels", series: "ct-series", bar: "ct-bar", grid: "ct-grid", gridGroup: "ct-grids", gridBackground: "ct-grid-background", vertical: "ct-vertical", horizontal: "ct-horizontal", start: "ct-start", end: "ct-end" } }); b.Bar = b.Base.extend({ constructor: d, createChart: c }) - }(this || global, a), function (a, b) { "use strict"; function c(a, b, c) { var d = b.x > a.x; return d && "explode" === c || !d && "implode" === c ? "start" : d && "implode" === c || !d && "explode" === c ? "end" : "middle" } function d(a) { var d, e, g, h, i, j = b.normalizeData(this.data), k = [], l = a.startAngle; this.svg = b.createSvg(this.container, a.width, a.height, a.donut ? a.classNames.chartDonut : a.classNames.chartPie), e = b.createChartRect(this.svg, a, f.padding), g = Math.min(e.width() / 2, e.height() / 2), i = a.total || j.normalized.series.reduce(function (a, b) { return a + b }, 0); var m = b.quantity(a.donutWidth); "%" === m.unit && (m.value *= g / 100), g -= a.donut && !a.donutSolid ? m.value / 2 : 0, h = "outside" === a.labelPosition || a.donut && !a.donutSolid ? g : "center" === a.labelPosition ? 0 : a.donutSolid ? g - m.value / 2 : g / 2, h += a.labelOffset; var n = { x: e.x1 + e.width() / 2, y: e.y2 + e.height() / 2 }, o = 1 === j.raw.series.filter(function (a) { return a.hasOwnProperty("value") ? 0 !== a.value : 0 !== a }).length; j.raw.series.forEach(function (a, b) { k[b] = this.svg.elem("g", null, null) }.bind(this)), a.showLabel && (d = this.svg.elem("g", null, null)), j.raw.series.forEach(function (e, f) { if (0 !== j.normalized.series[f] || !a.ignoreEmptyValues) { k[f].attr({ "ct:series-name": e.name }), k[f].addClass([a.classNames.series, e.className || a.classNames.series + "-" + b.alphaNumerate(f)].join(" ")); var p = i > 0 ? l + j.normalized.series[f] / i * 360 : 0, q = Math.max(0, l - (0 === f || o ? 0 : .2)); p - q >= 359.99 && (p = q + 359.99); var r, s, t, u = b.polarToCartesian(n.x, n.y, g, q), v = b.polarToCartesian(n.x, n.y, g, p), w = new b.Svg.Path(!a.donut || a.donutSolid).move(v.x, v.y).arc(g, g, 0, p - l > 180, 0, u.x, u.y); a.donut ? a.donutSolid && (t = g - m.value, r = b.polarToCartesian(n.x, n.y, t, l - (0 === f || o ? 0 : .2)), s = b.polarToCartesian(n.x, n.y, t, p), w.line(r.x, r.y), w.arc(t, t, 0, p - l > 180, 1, s.x, s.y)) : w.line(n.x, n.y); var x = a.classNames.slicePie; a.donut && (x = a.classNames.sliceDonut, a.donutSolid && (x = a.classNames.sliceDonutSolid)); var y = k[f].elem("path", { d: w.stringify() }, x); if (y.attr({ "ct:value": j.normalized.series[f], "ct:meta": b.serialize(e.meta) }), a.donut && !a.donutSolid && (y._node.style.strokeWidth = m.value + "px"), this.eventEmitter.emit("draw", { type: "slice", value: j.normalized.series[f], totalDataSum: i, index: f, meta: e.meta, series: e, group: k[f], element: y, path: w.clone(), center: n, radius: g, startAngle: l, endAngle: p }), a.showLabel) { var z; z = 1 === j.raw.series.length ? { x: n.x, y: n.y } : b.polarToCartesian(n.x, n.y, h, l + (p - l) / 2); var A; A = j.normalized.labels && !b.isFalseyButZero(j.normalized.labels[f]) ? j.normalized.labels[f] : j.normalized.series[f]; var B = a.labelInterpolationFnc(A, f); if (B || 0 === B) { var C = d.elem("text", { dx: z.x, dy: z.y, "text-anchor": c(n, z, a.labelDirection) }, a.classNames.label).text("" + B); this.eventEmitter.emit("draw", { type: "label", index: f, group: d, element: C, text: "" + B, x: z.x, y: z.y }) } } l = p } }.bind(this)), this.eventEmitter.emit("created", { chartRect: e, svg: this.svg, options: a }) } function e(a, c, d, e) { b.Pie["super"].constructor.call(this, a, c, f, b.extend({}, f, d), e) } var f = (a.window, a.document, { width: void 0, height: void 0, chartPadding: 5, classNames: { chartPie: "ct-chart-pie", chartDonut: "ct-chart-donut", series: "ct-series", slicePie: "ct-slice-pie", sliceDonut: "ct-slice-donut", sliceDonutSolid: "ct-slice-donut-solid", label: "ct-label" }, startAngle: 0, total: void 0, donut: !1, donutSolid: !1, donutWidth: 60, showLabel: !0, labelOffset: 0, labelPosition: "inside", labelInterpolationFnc: b.noop, labelDirection: "neutral", reverseData: !1, ignoreEmptyValues: !1 }); b.Pie = b.Base.extend({ constructor: e, createChart: d, determineAnchorPosition: c }) }(this || global, a), a -}); -//# sourceMappingURL=chartist.min.js.map - -var i, l, selectedLine = null; - -/* Navigate to hash without browser history entry */ -var navigateToHash = function () { - if (window.history !== undefined && window.history.replaceState !== undefined) { - window.history.replaceState(undefined, undefined, this.getAttribute("href")); - } -}; - -var hashLinks = document.getElementsByClassName('navigatetohash'); -for (i = 0, l = hashLinks.length; i < l; i++) { - hashLinks[i].addEventListener('click', navigateToHash); -} - -/* Switch test method */ -var switchTestMethod = function () { - var method = this.getAttribute("value"); - console.log("Selected test method: " + method); - - var lines, i, l, coverageData, lineAnalysis, cells; - - lines = document.querySelectorAll('.lineAnalysis tr'); - - for (i = 1, l = lines.length; i < l; i++) { - coverageData = JSON.parse(lines[i].getAttribute('data-coverage').replace(/'/g, '"')); - lineAnalysis = coverageData[method]; - cells = lines[i].querySelectorAll('td'); - if (lineAnalysis === undefined) { - lineAnalysis = coverageData.AllTestMethods; - if (lineAnalysis.LVS !== 'gray') { - cells[0].setAttribute('class', 'red'); - cells[1].innerText = cells[1].textContent = '0'; - cells[4].setAttribute('class', 'lightred'); - } - } else { - cells[0].setAttribute('class', lineAnalysis.LVS); - cells[1].innerText = cells[1].textContent = lineAnalysis.VC; - cells[4].setAttribute('class', 'light' + lineAnalysis.LVS); - } - } -}; - -var testMethods = document.getElementsByClassName('switchtestmethod'); -for (i = 0, l = testMethods.length; i < l; i++) { - testMethods[i].addEventListener('change', switchTestMethod); -} - -/* Highlight test method by line */ -var toggleLine = function () { - if (selectedLine === this) { - selectedLine = null; - } else { - selectedLine = null; - unhighlightTestMethods(); - highlightTestMethods.call(this); - selectedLine = this; - } - -}; -var highlightTestMethods = function () { - if (selectedLine !== null) { - return; - } - - var lineAnalysis; - var coverageData = JSON.parse(this.getAttribute('data-coverage').replace(/'/g, '"')); - var testMethods = document.getElementsByClassName('testmethod'); - - for (i = 0, l = testMethods.length; i < l; i++) { - lineAnalysis = coverageData[testMethods[i].id]; - if (lineAnalysis === undefined) { - testMethods[i].className = testMethods[i].className.replace(/\s*light.+/g, ""); - } else { - testMethods[i].className += ' light' + lineAnalysis.LVS; - } - } -}; -var unhighlightTestMethods = function () { - if (selectedLine !== null) { - return; - } - - var testMethods = document.getElementsByClassName('testmethod'); - for (i = 0, l = testMethods.length; i < l; i++) { - testMethods[i].className = testMethods[i].className.replace(/\s*light.+/g, ""); - } -}; -var coverableLines = document.getElementsByClassName('coverableline'); -for (i = 0, l = coverableLines.length; i < l; i++) { - coverableLines[i].addEventListener('click', toggleLine); - coverableLines[i].addEventListener('mouseenter', highlightTestMethods); - coverableLines[i].addEventListener('mouseleave', unhighlightTestMethods); -} - -/* History charts */ -var renderChart = function (chart) { - // Remove current children (e.g. PNG placeholder) - while (chart.firstChild) { - chart.firstChild.remove(); - } - - var chartData = window[chart.getAttribute('data-data')]; - var options = { - axisY: { - type: undefined, - onlyInteger: true - }, - lineSmooth: false, - low: 0, - high: 100, - scaleMinSpace: 20, - onlyInteger: true, - fullWidth: true - }; - var lineChart = new Chartist.Line(chart, { - labels: [], - series: chartData.series - }, options); - - /* Zoom */ - var zoomButtonDiv = document.createElement("div"); - zoomButtonDiv.className = "toggleZoom"; - var zoomButtonLink = document.createElement("a"); - zoomButtonLink.setAttribute("href", ""); - var zoomButtonText = document.createElement("i"); - zoomButtonText.className = "icon-search-plus"; - - zoomButtonLink.appendChild(zoomButtonText); - zoomButtonDiv.appendChild(zoomButtonLink); - - chart.appendChild(zoomButtonDiv); - - zoomButtonDiv.addEventListener('click', function (event) { - event.preventDefault(); - - if (options.axisY.type === undefined) { - options.axisY.type = Chartist.AutoScaleAxis; - zoomButtonText.className = "icon-search-minus"; - } else { - options.axisY.type = undefined; - zoomButtonText.className = "icon-search-plus"; - } - - lineChart.update(null, options); - }); - - var tooltip = document.createElement("div"); - tooltip.className = "tooltip"; - - chart.appendChild(tooltip); - - /* Tooltips */ - var showToolTip = function () { - var index = this.getAttribute('ct:meta'); - - tooltip.innerHTML = chartData.tooltips[index]; - tooltip.style.display = 'block'; - }; - - var moveToolTip = function (event) { - var box = chart.getBoundingClientRect(); - var left = event.pageX - box.left - window.pageXOffset; - var top = event.pageY - box.top - window.pageYOffset; - - left = left + 20; - top = top - tooltip.offsetHeight / 2; - - if (left + tooltip.offsetWidth > box.width) { - left -= tooltip.offsetWidth + 40; - } - - if (top < 0) { - top = 0; - } - - if (top + tooltip.offsetHeight > box.height) { - top = box.height - tooltip.offsetHeight; - } - - tooltip.style.left = left + 'px'; - tooltip.style.top = top + 'px'; - }; - - var hideToolTip = function () { - tooltip.style.display = 'none'; - }; - chart.addEventListener('mousemove', moveToolTip); - - lineChart.on('created', function () { - var chartPoints = chart.getElementsByClassName('ct-point'); - for (i = 0, l = chartPoints.length; i < l; i++) { - chartPoints[i].addEventListener('mousemove', showToolTip); - chartPoints[i].addEventListener('mouseout', hideToolTip); - } - }); -}; - -var charts = document.getElementsByClassName('historychart'); -for (i = 0, l = charts.length; i < l; i++) { - renderChart(charts[i]); -} - -var assemblies = [ - { - "name": "Core", - "classes": [ - { "name": "Core.DTOs.Request.OrganisationHierarchyProvider", "rp": "Core_OrganisationHierarchyProvider.html", "cl": 2, "ucl": 0, "cal": 2, "tl": 19, "cb": 0, "tb": 0, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, - { "name": "Core.Helpers.ApplicationHelper", "rp": "Core_ApplicationHelper.html", "cl": 7, "ucl": 0, "cal": 7, "tl": 23, "cb": 4, "tb": 6, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, - { "name": "Core.Helpers.AttributeExtensions", "rp": "Core_AttributeExtensions.html", "cl": 13, "ucl": 0, "cal": 13, "tl": 27, "cb": 6, "tb": 6, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, - { "name": "Core.Helpers.ConnectionStrings", "rp": "Core_ConnectionStrings.html", "cl": 1, "ucl": 0, "cal": 1, "tl": 7, "cb": 0, "tb": 0, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, - { "name": "Core.Helpers.DateTimeHelper", "rp": "Core_DateTimeHelper.html", "cl": 4, "ucl": 0, "cal": 4, "tl": 11, "cb": 2, "tb": 2, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, - { "name": "Core.Helpers.FilePathAttribute", "rp": "Core_FilePathAttribute.html", "cl": 3, "ucl": 0, "cal": 3, "tl": 12, "cb": 0, "tb": 0, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, - { "name": "Core.Mapping.SplunkInstanceMap", "rp": "Core_SplunkInstanceMap.html", "cl": 0, "ucl": 5, "cal": 5, "tl": 14, "cb": 0, "tb": 0, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, - { "name": "Core.Repositories.DapperWrapper", "rp": "Core_DapperWrapper.html", "cl": 27, "ucl": 1, "cal": 28, "tl": 68, "cb": 0, "tb": 0, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, - { "name": "Core.Repositories.HierarchyProviderConsumerRepo", "rp": "Core_HierarchyProviderConsumerRepo.html", "cl": 0, "ucl": 17, "cal": 17, "tl": 62, "cb": 0, "tb": 4, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, - { "name": "TimeProvider", "rp": "Core_TimeProvider.html", "cl": 0, "ucl": 2, "cal": 2, "tl": 12, "cb": 0, "tb": 0, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, - ]}, - { - "name": "Functions", - "classes": [ - { "name": "Functions.Configuration.EmailConfigurationProvider", "rp": "Functions_EmailConfigurationProvider.html", "cl": 0, "ucl": 8, "cal": 8, "tl": 29, "cb": 0, "tb": 2, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, - { "name": "Functions.Configuration.Infrastructure.HttpClient.HttpClientExtensions", "rp": "Functions_HttpClientExtensions.html", "cl": 12, "ucl": 0, "cal": 12, "tl": 23, "cb": 0, "tb": 0, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, - { "name": "Functions.Configuration.Infrastructure.Logging.LoggingExtensions", "rp": "Functions_LoggingExtensions.html", "cl": 0, "ucl": 130, "cal": 130, "tl": 185, "cb": 0, "tb": 4, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, - { "name": "Functions.Configuration.Infrastructure.Mapping.MappingExtensions", "rp": "Functions_MappingExtensions.html", "cl": 0, "ucl": 3, "cal": 3, "tl": 13, "cb": 0, "tb": 0, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, - { "name": "Functions.ExecuteImportByTrigger", "rp": "Functions_ExecuteImportByTrigger.html", "cl": 3, "ucl": 0, "cal": 3, "tl": 16, "cb": 0, "tb": 0, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, - { "name": "Functions.GetDataFromApiByDateRange", "rp": "Functions_GetDataFromApiByDateRange.html", "cl": 27, "ucl": 18, "cal": 45, "tl": 85, "cb": 0, "tb": 0, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, - { "name": "Functions.GetDataFromApiByTrigger", "rp": "Functions_GetDataFromApiByTrigger.html", "cl": 9, "ucl": 0, "cal": 9, "tl": 34, "cb": 0, "tb": 0, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, - { "name": "Functions.GetDataFromApiManual", "rp": "Functions_GetDataFromApiManual.html", "cl": 21, "ucl": 0, "cal": 21, "tl": 42, "cb": 2, "tb": 2, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, - { "name": "Functions.GetDataFromApiToday", "rp": "Functions_GetDataFromApiToday.html", "cl": 54, "ucl": 0, "cal": 54, "tl": 98, "cb": 0, "tb": 0, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, - { "name": "Functions.PurgeErrorLogByTrigger", "rp": "Functions_PurgeErrorLogByTrigger.html", "cl": 3, "ucl": 0, "cal": 3, "tl": 16, "cb": 0, "tb": 0, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, - { "name": "Functions.Services.BatchService", "rp": "Functions_BatchService.html", "cl": 86, "ucl": 7, "cal": 93, "tl": 146, "cb": 14, "tb": 18, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, - { "name": "Functions.Services.BlobService", "rp": "Functions_BlobService.html", "cl": 42, "ucl": 8, "cal": 50, "tl": 93, "cb": 6, "tb": 8, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, - { "name": "Functions.Services.ConfigurationService", "rp": "Functions_ConfigurationService.html", "cl": 32, "ucl": 4, "cal": 36, "tl": 61, "cb": 0, "tb": 0, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, - { "name": "Functions.Services.CoreConfigurationService", "rp": "Functions_CoreConfigurationService.html", "cl": 4, "ucl": 0, "cal": 4, "tl": 14, "cb": 2, "tb": 2, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, - { "name": "Functions.Services.DataService", "rp": "Functions_DataService.html", "cl": 2, "ucl": 64, "cal": 66, "tl": 113, "cb": 0, "tb": 16, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, - { "name": "Functions.Services.FileService", "rp": "Functions_FileService.html", "cl": 8, "ucl": 0, "cal": 8, "tl": 19, "cb": 0, "tb": 0, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, - { "name": "Functions.Services.ImportService", "rp": "Functions_ImportService.html", "cl": 46, "ucl": 0, "cal": 46, "tl": 84, "cb": 12, "tb": 14, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, - { "name": "Functions.Services.LoggingService", "rp": "Functions_LoggingService.html", "cl": 0, "ucl": 7, "cal": 7, "tl": 21, "cb": 0, "tb": 0, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, - { "name": "Functions.Services.SplunkService", "rp": "Functions_SplunkService.html", "cl": 96, "ucl": 26, "cal": 122, "tl": 181, "cb": 8, "tb": 14, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, - { "name": "Functions.SqlConnectionFactory", "rp": "Functions_SqlConnectionFactory.html", "cl": 0, "ucl": 3, "cal": 3, "tl": 13, "cb": 0, "tb": 0, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, - { "name": "Functions.StoreProviderConsumerData", "rp": "Functions_StoreProviderConsumerData.html", "cl": 22, "ucl": 14, "cal": 36, "tl": 69, "cb": 3, "tb": 4, "cm": 0, "fcm": 0, "tm": 0, "lch": [], "bch": [], "mch": [], "mfch": [], "hc": [], "metrics": { } }, - ]}, -]; - -var metrics = [{ "name": "Crap Score", "abbreviation": "crp", "explanationUrl": "https://googletesting.blogspot.de/2011/02/this-code-is-crap.html" }, { "name": "Cyclomatic complexity", "abbreviation": "cc", "explanationUrl": "https://en.wikipedia.org/wiki/Cyclomatic_complexity" }, { "name": "Line coverage", "abbreviation": "cov", "explanationUrl": "https://en.wikipedia.org/wiki/Code_coverage" }, { "name": "Branch coverage", "abbreviation": "bcov", "explanationUrl": "https://en.wikipedia.org/wiki/Code_coverage" }]; - -var historicCoverageExecutionTimes = []; - -var riskHotspotMetrics = [ - { "name": "Crap Score", "explanationUrl": "https://googletesting.blogspot.de/2011/02/this-code-is-crap.html" }, - { "name": "Cyclomatic complexity", "explanationUrl": "https://en.wikipedia.org/wiki/Cyclomatic_complexity" }, -]; - -var riskHotspots = [ - { - "assembly": "Functions", "class": "Functions.Services.DataService", "reportPath": "Functions_DataService.html", "methodName": "ExecuteQueryStoredProcedure()", "methodShortName": "ExecuteQueryStoredProcedure()", "fileIndex": 0, "line": 40, - "metrics": [ - { "value": 42, "exceeded": true }, - { "value": 6, "exceeded": false }, - ]}, -]; - -var branchCoverageAvailable = true; -var methodCoverageAvailable = false; -var maximumDecimalPlacesForCoverageQuotas = 1; - - -var translations = { -'top': 'Top:', -'all': 'All', -'assembly': 'Assembly', -'class': 'Class', -'method': 'Method', -'lineCoverage': 'Line coverage', -'noGrouping': 'No grouping', -'byAssembly': 'By assembly', -'byNamespace': 'By namespace, Level:', -'all': 'All', -'collapseAll': 'Collapse all', -'expandAll': 'Expand all', -'grouping': 'Grouping:', -'filter': 'Filter:', -'name': 'Name', -'covered': 'Covered', -'uncovered': 'Uncovered', -'coverable': 'Coverable', -'total': 'Total', -'coverage': 'Line coverage', -'branchCoverage': 'Branch coverage', -'methodCoverage': 'Method coverage', -'fullMethodCoverage': 'Full method coverage', -'percentage': 'Percentage', -'history': 'Coverage history', -'compareHistory': 'Compare with:', -'date': 'Date', -'allChanges': 'All changes', -'selectCoverageTypes': 'Select coverage types', -'selectCoverageTypesAndMetrics': 'Select coverage types & metrics', -'coverageTypes': 'Coverage types', -'metrics': 'Metrics', -'methodCoverageProVersion': 'Feature is only available for sponsors', -'lineCoverageIncreaseOnly': 'Line coverage: Increase only', -'lineCoverageDecreaseOnly': 'Line coverage: Decrease only', -'branchCoverageIncreaseOnly': 'Branch coverage: Increase only', -'branchCoverageDecreaseOnly': 'Branch coverage: Decrease only', -'methodCoverageIncreaseOnly': 'Method coverage: Increase only', -'methodCoverageDecreaseOnly': 'Method coverage: Decrease only', -'fullMethodCoverageIncreaseOnly': 'Full method coverage: Increase only', -'fullMethodCoverageDecreaseOnly': 'Full method coverage: Decrease only' -}; - - -(()=>{"use strict";var e,_={},p={};function n(e){var a=p[e];if(void 0!==a)return a.exports;var r=p[e]={exports:{}};return _[e](r,r.exports,n),r.exports}n.m=_,e=[],n.O=(a,r,u,l)=>{if(!r){var o=1/0;for(f=0;f=l)&&Object.keys(n.O).every(h=>n.O[h](r[t]))?r.splice(t--,1):(v=!1,l0&&e[f-1][2]>l;f--)e[f]=e[f-1];e[f]=[r,u,l]},n.n=e=>{var a=e&&e.__esModule?()=>e.default:()=>e;return n.d(a,{a}),a},n.d=(e,a)=>{for(var r in a)n.o(a,r)&&!n.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:a[r]})},n.o=(e,a)=>Object.prototype.hasOwnProperty.call(e,a),(()=>{var e={121:0};n.O.j=u=>0===e[u];var a=(u,l)=>{var t,c,[f,o,v]=l,s=0;if(f.some(d=>0!==e[d])){for(t in o)n.o(o,t)&&(n.m[t]=o[t]);if(v)var b=v(n)}for(u&&u(l);s{ve(935)},935:()=>{const te=globalThis;function Q(e){return(te.__Zone_symbol_prefix||"__zone_symbol__")+e}const Te=Object.getOwnPropertyDescriptor,Le=Object.defineProperty,Ie=Object.getPrototypeOf,_t=Object.create,Et=Array.prototype.slice,Me="addEventListener",Ze="removeEventListener",Ae=Q(Me),je=Q(Ze),ae="true",le="false",Pe=Q("");function He(e,r){return Zone.current.wrap(e,r)}function xe(e,r,c,t,i){return Zone.current.scheduleMacroTask(e,r,c,t,i)}const j=Q,Ce=typeof window<"u",ge=Ce?window:void 0,$=Ce&&ge||globalThis;function Ve(e,r){for(let c=e.length-1;c>=0;c--)"function"==typeof e[c]&&(e[c]=He(e[c],r+"_"+c));return e}function We(e){return!e||!1!==e.writable&&!("function"==typeof e.get&&typeof e.set>"u")}const qe=typeof WorkerGlobalScope<"u"&&self instanceof WorkerGlobalScope,De=!("nw"in $)&&typeof $.process<"u"&&"[object process]"===$.process.toString(),Ge=!De&&!qe&&!(!Ce||!ge.HTMLElement),Xe=typeof $.process<"u"&&"[object process]"===$.process.toString()&&!qe&&!(!Ce||!ge.HTMLElement),Se={},pt=j("enable_beforeunload"),Ye=function(e){if(!(e=e||$.event))return;let r=Se[e.type];r||(r=Se[e.type]=j("ON_PROPERTY"+e.type));const c=this||e.target||$,t=c[r];let i;return Ge&&c===ge&&"error"===e.type?(i=t&&t.call(this,e.message,e.filename,e.lineno,e.colno,e.error),!0===i&&e.preventDefault()):(i=t&&t.apply(this,arguments),"beforeunload"===e.type&&$[pt]&&"string"==typeof i?e.returnValue=i:null!=i&&!i&&e.preventDefault()),i};function $e(e,r,c){let t=Te(e,r);if(!t&&c&&Te(c,r)&&(t={enumerable:!0,configurable:!0}),!t||!t.configurable)return;const i=j("on"+r+"patched");if(e.hasOwnProperty(i)&&e[i])return;delete t.writable,delete t.value;const u=t.get,E=t.set,T=r.slice(2);let y=Se[T];y||(y=Se[T]=j("ON_PROPERTY"+T)),t.set=function(D){let d=this;!d&&e===$&&(d=$),d&&("function"==typeof d[y]&&d.removeEventListener(T,Ye),E&&E.call(d,null),d[y]=D,"function"==typeof D&&d.addEventListener(T,Ye,!1))},t.get=function(){let D=this;if(!D&&e===$&&(D=$),!D)return null;const d=D[y];if(d)return d;if(u){let w=u.call(this);if(w)return t.set.call(this,w),"function"==typeof D.removeAttribute&&D.removeAttribute(r),w}return null},Le(e,r,t),e[i]=!0}function Ke(e,r,c){if(r)for(let t=0;tfunction(E,T){const y=c(E,T);return y.cbIdx>=0&&"function"==typeof T[y.cbIdx]?xe(y.name,T[y.cbIdx],y,i):u.apply(E,T)})}function fe(e,r){e[j("OriginalDelegate")]=r}let Je=!1,Be=!1;function kt(){if(Je)return Be;Je=!0;try{const e=ge.navigator.userAgent;(-1!==e.indexOf("MSIE ")||-1!==e.indexOf("Trident/")||-1!==e.indexOf("Edge/"))&&(Be=!0)}catch{}return Be}function Qe(e){return"function"==typeof e}function et(e){return"number"==typeof e}let pe=!1;if(typeof window<"u")try{const e=Object.defineProperty({},"passive",{get:function(){pe=!0}});window.addEventListener("test",e,e),window.removeEventListener("test",e,e)}catch{pe=!1}const vt={useG:!0},ne={},tt={},nt=new RegExp("^"+Pe+"(\\w+)(true|false)$"),rt=j("propagationStopped");function ot(e,r){const c=(r?r(e):e)+le,t=(r?r(e):e)+ae,i=Pe+c,u=Pe+t;ne[e]={},ne[e][le]=i,ne[e][ae]=u}function bt(e,r,c,t){const i=t&&t.add||Me,u=t&&t.rm||Ze,E=t&&t.listeners||"eventListeners",T=t&&t.rmAll||"removeAllListeners",y=j(i),D="."+i+":",d="prependListener",w="."+d+":",Z=function(k,h,H){if(k.isRemoved)return;const V=k.callback;let Y;"object"==typeof V&&V.handleEvent&&(k.callback=g=>V.handleEvent(g),k.originalDelegate=V);try{k.invoke(k,h,[H])}catch(g){Y=g}const G=k.options;return G&&"object"==typeof G&&G.once&&h[u].call(h,H.type,k.originalDelegate?k.originalDelegate:k.callback,G),Y};function x(k,h,H){if(!(h=h||e.event))return;const V=k||h.target||e,Y=V[ne[h.type][H?ae:le]];if(Y){const G=[];if(1===Y.length){const g=Z(Y[0],V,h);g&&G.push(g)}else{const g=Y.slice();for(let z=0;z{throw z})}}}const U=function(k){return x(this,k,!1)},K=function(k){return x(this,k,!0)};function J(k,h){if(!k)return!1;let H=!0;h&&void 0!==h.useG&&(H=h.useG);const V=h&&h.vh;let Y=!0;h&&void 0!==h.chkDup&&(Y=h.chkDup);let G=!1;h&&void 0!==h.rt&&(G=h.rt);let g=k;for(;g&&!g.hasOwnProperty(i);)g=Ie(g);if(!g&&k[i]&&(g=k),!g||g[y])return!1;const z=h&&h.eventNameToString,O={},R=g[y]=g[i],b=g[j(u)]=g[u],S=g[j(E)]=g[E],ee=g[j(T)]=g[T];let W;h&&h.prepend&&(W=g[j(h.prepend)]=g[h.prepend]);const q=H?function(s){if(!O.isExisting)return R.call(O.target,O.eventName,O.capture?K:U,O.options)}:function(s){return R.call(O.target,O.eventName,s.invoke,O.options)},A=H?function(s){if(!s.isRemoved){const l=ne[s.eventName];let v;l&&(v=l[s.capture?ae:le]);const C=v&&s.target[v];if(C)for(let p=0;pse.zone.cancelTask(se);s.call(me,"abort",ce,{once:!0}),se.removeAbortListener=()=>me.removeEventListener("abort",ce)}return O.target=null,Re&&(Re.taskData=null),lt&&(O.options.once=!0),!pe&&"boolean"==typeof se.options||(se.options=ie),se.target=I,se.capture=Ue,se.eventName=M,F&&(se.originalDelegate=B),L?ke.unshift(se):ke.push(se),p?I:void 0}};return g[i]=a(R,D,q,A,G),W&&(g[d]=a(W,w,function(s){return W.call(O.target,O.eventName,s.invoke,O.options)},A,G,!0)),g[u]=function(){const s=this||e;let l=arguments[0];h&&h.transferEventName&&(l=h.transferEventName(l));const v=arguments[2],C=!!v&&("boolean"==typeof v||v.capture),p=arguments[1];if(!p)return b.apply(this,arguments);if(V&&!V(b,p,s,arguments))return;const L=ne[l];let I;L&&(I=L[C?ae:le]);const M=I&&s[I];if(M)for(let B=0;Bfunction(i,u){i[rt]=!0,t&&t.apply(i,u)})}const Oe=j("zoneTask");function ye(e,r,c,t){let i=null,u=null;c+=t;const E={};function T(D){const d=D.data;d.args[0]=function(){return D.invoke.apply(this,arguments)};const w=i.apply(e,d.args);return et(w)?d.handleId=w:(d.handle=w,d.isRefreshable=Qe(w.refresh)),D}function y(D){const{handle:d,handleId:w}=D.data;return u.call(e,d??w)}i=ue(e,r+=t,D=>function(d,w){if(Qe(w[0])){const Z={isRefreshable:!1,isPeriodic:"Interval"===t,delay:"Timeout"===t||"Interval"===t?w[1]||0:void 0,args:w},x=w[0];w[0]=function(){try{return x.apply(this,arguments)}finally{const{handle:H,handleId:V,isPeriodic:Y,isRefreshable:G}=Z;!Y&&!G&&(V?delete E[V]:H&&(H[Oe]=null))}};const U=xe(r,w[0],Z,T,y);if(!U)return U;const{handleId:K,handle:J,isRefreshable:X,isPeriodic:k}=U.data;if(K)E[K]=U;else if(J&&(J[Oe]=U,X&&!k)){const h=J.refresh;J.refresh=function(){const{zone:H,state:V}=U;return"notScheduled"===V?(U._state="scheduled",H._updateTaskCount(U,1)):"running"===V&&(U._state="scheduling"),h.call(this)}}return J??K??U}return D.apply(e,w)}),u=ue(e,c,D=>function(d,w){const Z=w[0];let x;et(Z)?(x=E[Z],delete E[Z]):(x=Z?.[Oe],x?Z[Oe]=null:x=Z),x?.type?x.cancelFn&&x.zone.cancelTask(x):D.apply(e,w)})}function it(e,r,c){if(!c||0===c.length)return r;const t=c.filter(u=>u.target===e);if(!t||0===t.length)return r;const i=t[0].ignoreProperties;return r.filter(u=>-1===i.indexOf(u))}function ct(e,r,c,t){e&&Ke(e,it(e,r,c),t)}function Fe(e){return Object.getOwnPropertyNames(e).filter(r=>r.startsWith("on")&&r.length>2).map(r=>r.substring(2))}function It(e,r,c,t,i){const u=Zone.__symbol__(t);if(r[u])return;const E=r[u]=r[t];r[t]=function(T,y,D){return y&&y.prototype&&i.forEach(function(d){const w=`${c}.${t}::`+d,Z=y.prototype;try{if(Z.hasOwnProperty(d)){const x=e.ObjectGetOwnPropertyDescriptor(Z,d);x&&x.value?(x.value=e.wrapWithCurrentZone(x.value,w),e._redefineProperty(y.prototype,d,x)):Z[d]&&(Z[d]=e.wrapWithCurrentZone(Z[d],w))}else Z[d]&&(Z[d]=e.wrapWithCurrentZone(Z[d],w))}catch{}}),E.call(r,T,y,D)},e.attachOriginToPatched(r[t],E)}const at=function be(){const e=globalThis,r=!0===e[Q("forceDuplicateZoneCheck")];if(e.Zone&&(r||"function"!=typeof e.Zone.__symbol__))throw new Error("Zone already loaded.");return e.Zone??=function ve(){const e=te.performance;function r(N){e&&e.mark&&e.mark(N)}function c(N,_){e&&e.measure&&e.measure(N,_)}r("Zone");let t=(()=>{class N{static{this.__symbol__=Q}static assertZonePatched(){if(te.Promise!==O.ZoneAwarePromise)throw new Error("Zone.js has detected that ZoneAwarePromise `(window|global).Promise` has been overwritten.\nMost likely cause is that a Promise polyfill has been loaded after Zone.js (Polyfilling Promise api is not necessary when zone.js is loaded. If you must load one, do so before loading zone.js.)")}static get root(){let n=N.current;for(;n.parent;)n=n.parent;return n}static get current(){return b.zone}static get currentTask(){return S}static __load_patch(n,o,m=!1){if(O.hasOwnProperty(n)){const P=!0===te[Q("forceDuplicateZoneCheck")];if(!m&&P)throw Error("Already loaded patch: "+n)}else if(!te["__Zone_disable_"+n]){const P="Zone:"+n;r(P),O[n]=o(te,N,R),c(P,P)}}get parent(){return this._parent}get name(){return this._name}constructor(n,o){this._parent=n,this._name=o?o.name||"unnamed":"",this._properties=o&&o.properties||{},this._zoneDelegate=new u(this,this._parent&&this._parent._zoneDelegate,o)}get(n){const o=this.getZoneWith(n);if(o)return o._properties[n]}getZoneWith(n){let o=this;for(;o;){if(o._properties.hasOwnProperty(n))return o;o=o._parent}return null}fork(n){if(!n)throw new Error("ZoneSpec required!");return this._zoneDelegate.fork(this,n)}wrap(n,o){if("function"!=typeof n)throw new Error("Expecting function got: "+n);const m=this._zoneDelegate.intercept(this,n,o),P=this;return function(){return P.runGuarded(m,this,arguments,o)}}run(n,o,m,P){b={parent:b,zone:this};try{return this._zoneDelegate.invoke(this,n,o,m,P)}finally{b=b.parent}}runGuarded(n,o=null,m,P){b={parent:b,zone:this};try{try{return this._zoneDelegate.invoke(this,n,o,m,P)}catch(q){if(this._zoneDelegate.handleError(this,q))throw q}}finally{b=b.parent}}runTask(n,o,m){if(n.zone!=this)throw new Error("A task can only be run in the zone of creation! (Creation: "+(n.zone||J).name+"; Execution: "+this.name+")");const P=n,{type:q,data:{isPeriodic:A=!1,isRefreshable:_e=!1}={}}=n;if(n.state===X&&(q===z||q===g))return;const he=n.state!=H;he&&P._transitionTo(H,h);const de=S;S=P,b={parent:b,zone:this};try{q==g&&n.data&&!A&&!_e&&(n.cancelFn=void 0);try{return this._zoneDelegate.invokeTask(this,P,o,m)}catch(oe){if(this._zoneDelegate.handleError(this,oe))throw oe}}finally{const oe=n.state;if(oe!==X&&oe!==Y)if(q==z||A||_e&&oe===k)he&&P._transitionTo(h,H,k);else{const f=P._zoneDelegates;this._updateTaskCount(P,-1),he&&P._transitionTo(X,H,X),_e&&(P._zoneDelegates=f)}b=b.parent,S=de}}scheduleTask(n){if(n.zone&&n.zone!==this){let m=this;for(;m;){if(m===n.zone)throw Error(`can not reschedule task to ${this.name} which is descendants of the original zone ${n.zone.name}`);m=m.parent}}n._transitionTo(k,X);const o=[];n._zoneDelegates=o,n._zone=this;try{n=this._zoneDelegate.scheduleTask(this,n)}catch(m){throw n._transitionTo(Y,k,X),this._zoneDelegate.handleError(this,m),m}return n._zoneDelegates===o&&this._updateTaskCount(n,1),n.state==k&&n._transitionTo(h,k),n}scheduleMicroTask(n,o,m,P){return this.scheduleTask(new E(G,n,o,m,P,void 0))}scheduleMacroTask(n,o,m,P,q){return this.scheduleTask(new E(g,n,o,m,P,q))}scheduleEventTask(n,o,m,P,q){return this.scheduleTask(new E(z,n,o,m,P,q))}cancelTask(n){if(n.zone!=this)throw new Error("A task can only be cancelled in the zone of creation! (Creation: "+(n.zone||J).name+"; Execution: "+this.name+")");if(n.state===h||n.state===H){n._transitionTo(V,h,H);try{this._zoneDelegate.cancelTask(this,n)}catch(o){throw n._transitionTo(Y,V),this._zoneDelegate.handleError(this,o),o}return this._updateTaskCount(n,-1),n._transitionTo(X,V),n.runCount=-1,n}}_updateTaskCount(n,o){const m=n._zoneDelegates;-1==o&&(n._zoneDelegates=null);for(let P=0;PN.hasTask(n,o),onScheduleTask:(N,_,n,o)=>N.scheduleTask(n,o),onInvokeTask:(N,_,n,o,m,P)=>N.invokeTask(n,o,m,P),onCancelTask:(N,_,n,o)=>N.cancelTask(n,o)};class u{get zone(){return this._zone}constructor(_,n,o){this._taskCounts={microTask:0,macroTask:0,eventTask:0},this._zone=_,this._parentDelegate=n,this._forkZS=o&&(o&&o.onFork?o:n._forkZS),this._forkDlgt=o&&(o.onFork?n:n._forkDlgt),this._forkCurrZone=o&&(o.onFork?this._zone:n._forkCurrZone),this._interceptZS=o&&(o.onIntercept?o:n._interceptZS),this._interceptDlgt=o&&(o.onIntercept?n:n._interceptDlgt),this._interceptCurrZone=o&&(o.onIntercept?this._zone:n._interceptCurrZone),this._invokeZS=o&&(o.onInvoke?o:n._invokeZS),this._invokeDlgt=o&&(o.onInvoke?n:n._invokeDlgt),this._invokeCurrZone=o&&(o.onInvoke?this._zone:n._invokeCurrZone),this._handleErrorZS=o&&(o.onHandleError?o:n._handleErrorZS),this._handleErrorDlgt=o&&(o.onHandleError?n:n._handleErrorDlgt),this._handleErrorCurrZone=o&&(o.onHandleError?this._zone:n._handleErrorCurrZone),this._scheduleTaskZS=o&&(o.onScheduleTask?o:n._scheduleTaskZS),this._scheduleTaskDlgt=o&&(o.onScheduleTask?n:n._scheduleTaskDlgt),this._scheduleTaskCurrZone=o&&(o.onScheduleTask?this._zone:n._scheduleTaskCurrZone),this._invokeTaskZS=o&&(o.onInvokeTask?o:n._invokeTaskZS),this._invokeTaskDlgt=o&&(o.onInvokeTask?n:n._invokeTaskDlgt),this._invokeTaskCurrZone=o&&(o.onInvokeTask?this._zone:n._invokeTaskCurrZone),this._cancelTaskZS=o&&(o.onCancelTask?o:n._cancelTaskZS),this._cancelTaskDlgt=o&&(o.onCancelTask?n:n._cancelTaskDlgt),this._cancelTaskCurrZone=o&&(o.onCancelTask?this._zone:n._cancelTaskCurrZone),this._hasTaskZS=null,this._hasTaskDlgt=null,this._hasTaskDlgtOwner=null,this._hasTaskCurrZone=null;const m=o&&o.onHasTask;(m||n&&n._hasTaskZS)&&(this._hasTaskZS=m?o:i,this._hasTaskDlgt=n,this._hasTaskDlgtOwner=this,this._hasTaskCurrZone=this._zone,o.onScheduleTask||(this._scheduleTaskZS=i,this._scheduleTaskDlgt=n,this._scheduleTaskCurrZone=this._zone),o.onInvokeTask||(this._invokeTaskZS=i,this._invokeTaskDlgt=n,this._invokeTaskCurrZone=this._zone),o.onCancelTask||(this._cancelTaskZS=i,this._cancelTaskDlgt=n,this._cancelTaskCurrZone=this._zone))}fork(_,n){return this._forkZS?this._forkZS.onFork(this._forkDlgt,this.zone,_,n):new t(_,n)}intercept(_,n,o){return this._interceptZS?this._interceptZS.onIntercept(this._interceptDlgt,this._interceptCurrZone,_,n,o):n}invoke(_,n,o,m,P){return this._invokeZS?this._invokeZS.onInvoke(this._invokeDlgt,this._invokeCurrZone,_,n,o,m,P):n.apply(o,m)}handleError(_,n){return!this._handleErrorZS||this._handleErrorZS.onHandleError(this._handleErrorDlgt,this._handleErrorCurrZone,_,n)}scheduleTask(_,n){let o=n;if(this._scheduleTaskZS)this._hasTaskZS&&o._zoneDelegates.push(this._hasTaskDlgtOwner),o=this._scheduleTaskZS.onScheduleTask(this._scheduleTaskDlgt,this._scheduleTaskCurrZone,_,n),o||(o=n);else if(n.scheduleFn)n.scheduleFn(n);else{if(n.type!=G)throw new Error("Task is missing scheduleFn.");U(n)}return o}invokeTask(_,n,o,m){return this._invokeTaskZS?this._invokeTaskZS.onInvokeTask(this._invokeTaskDlgt,this._invokeTaskCurrZone,_,n,o,m):n.callback.apply(o,m)}cancelTask(_,n){let o;if(this._cancelTaskZS)o=this._cancelTaskZS.onCancelTask(this._cancelTaskDlgt,this._cancelTaskCurrZone,_,n);else{if(!n.cancelFn)throw Error("Task is not cancelable");o=n.cancelFn(n)}return o}hasTask(_,n){try{this._hasTaskZS&&this._hasTaskZS.onHasTask(this._hasTaskDlgt,this._hasTaskCurrZone,_,n)}catch(o){this.handleError(_,o)}}_updateTaskCount(_,n){const o=this._taskCounts,m=o[_],P=o[_]=m+n;if(P<0)throw new Error("More tasks executed then were scheduled.");0!=m&&0!=P||this.hasTask(this._zone,{microTask:o.microTask>0,macroTask:o.macroTask>0,eventTask:o.eventTask>0,change:_})}}class E{constructor(_,n,o,m,P,q){if(this._zone=null,this.runCount=0,this._zoneDelegates=null,this._state="notScheduled",this.type=_,this.source=n,this.data=m,this.scheduleFn=P,this.cancelFn=q,!o)throw new Error("callback is not defined");this.callback=o;const A=this;this.invoke=_===z&&m&&m.useG?E.invokeTask:function(){return E.invokeTask.call(te,A,this,arguments)}}static invokeTask(_,n,o){_||(_=this),ee++;try{return _.runCount++,_.zone.runTask(_,n,o)}finally{1==ee&&K(),ee--}}get zone(){return this._zone}get state(){return this._state}cancelScheduleRequest(){this._transitionTo(X,k)}_transitionTo(_,n,o){if(this._state!==n&&this._state!==o)throw new Error(`${this.type} '${this.source}': can not transition to '${_}', expecting state '${n}'${o?" or '"+o+"'":""}, was '${this._state}'.`);this._state=_,_==X&&(this._zoneDelegates=null)}toString(){return this.data&&typeof this.data.handleId<"u"?this.data.handleId.toString():Object.prototype.toString.call(this)}toJSON(){return{type:this.type,state:this.state,source:this.source,zone:this.zone.name,runCount:this.runCount}}}const T=Q("setTimeout"),y=Q("Promise"),D=Q("then");let Z,d=[],w=!1;function x(N){if(Z||te[y]&&(Z=te[y].resolve(0)),Z){let _=Z[D];_||(_=Z.then),_.call(Z,N)}else te[T](N,0)}function U(N){0===ee&&0===d.length&&x(K),N&&d.push(N)}function K(){if(!w){for(w=!0;d.length;){const N=d;d=[];for(let _=0;_b,onUnhandledError:W,microtaskDrainDone:W,scheduleMicroTask:U,showUncaughtError:()=>!t[Q("ignoreConsoleErrorUncaughtError")],patchEventTarget:()=>[],patchOnProperties:W,patchMethod:()=>W,bindArguments:()=>[],patchThen:()=>W,patchMacroTask:()=>W,patchEventPrototype:()=>W,isIEOrEdge:()=>!1,getGlobalObjects:()=>{},ObjectDefineProperty:()=>W,ObjectGetOwnPropertyDescriptor:()=>{},ObjectCreate:()=>{},ArraySlice:()=>[],patchClass:()=>W,wrapWithCurrentZone:()=>W,filterProperties:()=>[],attachOriginToPatched:()=>W,_redefineProperty:()=>W,patchCallbacks:()=>W,nativeScheduleMicroTask:x};let b={parent:null,zone:new t(null,null)},S=null,ee=0;function W(){}return c("Zone","Zone"),t}(),e.Zone}();(function Zt(e){(function Nt(e){e.__load_patch("ZoneAwarePromise",(r,c,t)=>{const i=Object.getOwnPropertyDescriptor,u=Object.defineProperty,T=t.symbol,y=[],D=!1!==r[T("DISABLE_WRAPPING_UNCAUGHT_PROMISE_REJECTION")],d=T("Promise"),w=T("then");t.onUnhandledError=f=>{if(t.showUncaughtError()){const a=f&&f.rejection;a?console.error("Unhandled Promise rejection:",a instanceof Error?a.message:a,"; Zone:",f.zone.name,"; Task:",f.task&&f.task.source,"; Value:",a,a instanceof Error?a.stack:void 0):console.error(f)}},t.microtaskDrainDone=()=>{for(;y.length;){const f=y.shift();try{f.zone.runGuarded(()=>{throw f.throwOriginal?f.rejection:f})}catch(a){U(a)}}};const x=T("unhandledPromiseRejectionHandler");function U(f){t.onUnhandledError(f);try{const a=c[x];"function"==typeof a&&a.call(this,f)}catch{}}function K(f){return f&&f.then}function J(f){return f}function X(f){return A.reject(f)}const k=T("state"),h=T("value"),H=T("finally"),V=T("parentPromiseValue"),Y=T("parentPromiseState"),g=null,z=!0,O=!1;function b(f,a){return s=>{try{N(f,a,s)}catch(l){N(f,!1,l)}}}const S=function(){let f=!1;return function(s){return function(){f||(f=!0,s.apply(null,arguments))}}},ee="Promise resolved with itself",W=T("currentTaskTrace");function N(f,a,s){const l=S();if(f===s)throw new TypeError(ee);if(f[k]===g){let v=null;try{("object"==typeof s||"function"==typeof s)&&(v=s&&s.then)}catch(C){return l(()=>{N(f,!1,C)})(),f}if(a!==O&&s instanceof A&&s.hasOwnProperty(k)&&s.hasOwnProperty(h)&&s[k]!==g)n(s),N(f,s[k],s[h]);else if(a!==O&&"function"==typeof v)try{v.call(s,l(b(f,a)),l(b(f,!1)))}catch(C){l(()=>{N(f,!1,C)})()}else{f[k]=a;const C=f[h];if(f[h]=s,f[H]===H&&a===z&&(f[k]=f[Y],f[h]=f[V]),a===O&&s instanceof Error){const p=c.currentTask&&c.currentTask.data&&c.currentTask.data.__creationTrace__;p&&u(s,W,{configurable:!0,enumerable:!1,writable:!0,value:p})}for(let p=0;p{try{const L=f[h],I=!!s&&H===s[H];I&&(s[V]=L,s[Y]=C);const M=a.run(p,void 0,I&&p!==X&&p!==J?[]:[L]);N(s,!0,M)}catch(L){N(s,!1,L)}},s)}const P=function(){},q=r.AggregateError;class A{static toString(){return"function ZoneAwarePromise() { [native code] }"}static resolve(a){return a instanceof A?a:N(new this(null),z,a)}static reject(a){return N(new this(null),O,a)}static withResolvers(){const a={};return a.promise=new A((s,l)=>{a.resolve=s,a.reject=l}),a}static any(a){if(!a||"function"!=typeof a[Symbol.iterator])return Promise.reject(new q([],"All promises were rejected"));const s=[];let l=0;try{for(let p of a)l++,s.push(A.resolve(p))}catch{return Promise.reject(new q([],"All promises were rejected"))}if(0===l)return Promise.reject(new q([],"All promises were rejected"));let v=!1;const C=[];return new A((p,L)=>{for(let I=0;I{v||(v=!0,p(M))},M=>{C.push(M),l--,0===l&&(v=!0,L(new q(C,"All promises were rejected")))})})}static race(a){let s,l,v=new this((L,I)=>{s=L,l=I});function C(L){s(L)}function p(L){l(L)}for(let L of a)K(L)||(L=this.resolve(L)),L.then(C,p);return v}static all(a){return A.allWithCallback(a)}static allSettled(a){return(this&&this.prototype instanceof A?this:A).allWithCallback(a,{thenCallback:l=>({status:"fulfilled",value:l}),errorCallback:l=>({status:"rejected",reason:l})})}static allWithCallback(a,s){let l,v,C=new this((M,B)=>{l=M,v=B}),p=2,L=0;const I=[];for(let M of a){K(M)||(M=this.resolve(M));const B=L;try{M.then(F=>{I[B]=s?s.thenCallback(F):F,p--,0===p&&l(I)},F=>{s?(I[B]=s.errorCallback(F),p--,0===p&&l(I)):v(F)})}catch(F){v(F)}p++,L++}return p-=2,0===p&&l(I),C}constructor(a){const s=this;if(!(s instanceof A))throw new Error("Must be an instanceof Promise.");s[k]=g,s[h]=[];try{const l=S();a&&a(l(b(s,z)),l(b(s,O)))}catch(l){N(s,!1,l)}}get[Symbol.toStringTag](){return"Promise"}get[Symbol.species](){return A}then(a,s){let l=this.constructor?.[Symbol.species];(!l||"function"!=typeof l)&&(l=this.constructor||A);const v=new l(P),C=c.current;return this[k]==g?this[h].push(C,v,a,s):o(this,C,v,a,s),v}catch(a){return this.then(null,a)}finally(a){let s=this.constructor?.[Symbol.species];(!s||"function"!=typeof s)&&(s=A);const l=new s(P);l[H]=H;const v=c.current;return this[k]==g?this[h].push(v,l,a,a):o(this,v,l,a,a),l}}A.resolve=A.resolve,A.reject=A.reject,A.race=A.race,A.all=A.all;const _e=r[d]=r.Promise;r.Promise=A;const he=T("thenPatched");function de(f){const a=f.prototype,s=i(a,"then");if(s&&(!1===s.writable||!s.configurable))return;const l=a.then;a[w]=l,f.prototype.then=function(v,C){return new A((L,I)=>{l.call(this,L,I)}).then(v,C)},f[he]=!0}return t.patchThen=de,_e&&(de(_e),ue(r,"fetch",f=>function oe(f){return function(a,s){let l=f.apply(a,s);if(l instanceof A)return l;let v=l.constructor;return v[he]||de(v),l}}(f))),Promise[c.__symbol__("uncaughtPromiseErrors")]=y,A})})(e),function Lt(e){e.__load_patch("toString",r=>{const c=Function.prototype.toString,t=j("OriginalDelegate"),i=j("Promise"),u=j("Error"),E=function(){if("function"==typeof this){const d=this[t];if(d)return"function"==typeof d?c.call(d):Object.prototype.toString.call(d);if(this===Promise){const w=r[i];if(w)return c.call(w)}if(this===Error){const w=r[u];if(w)return c.call(w)}}return c.call(this)};E[t]=c,Function.prototype.toString=E;const T=Object.prototype.toString;Object.prototype.toString=function(){return"function"==typeof Promise&&this instanceof Promise?"[object Promise]":T.call(this)}})}(e),function Mt(e){e.__load_patch("util",(r,c,t)=>{const i=Fe(r);t.patchOnProperties=Ke,t.patchMethod=ue,t.bindArguments=Ve,t.patchMacroTask=yt;const u=c.__symbol__("BLACK_LISTED_EVENTS"),E=c.__symbol__("UNPATCHED_EVENTS");r[E]&&(r[u]=r[E]),r[u]&&(c[u]=c[E]=r[u]),t.patchEventPrototype=Pt,t.patchEventTarget=bt,t.isIEOrEdge=kt,t.ObjectDefineProperty=Le,t.ObjectGetOwnPropertyDescriptor=Te,t.ObjectCreate=_t,t.ArraySlice=Et,t.patchClass=we,t.wrapWithCurrentZone=He,t.filterProperties=it,t.attachOriginToPatched=fe,t._redefineProperty=Object.defineProperty,t.patchCallbacks=It,t.getGlobalObjects=()=>({globalSources:tt,zoneSymbolEventNames:ne,eventNames:i,isBrowser:Ge,isMix:Xe,isNode:De,TRUE_STR:ae,FALSE_STR:le,ZONE_SYMBOL_PREFIX:Pe,ADD_EVENT_LISTENER_STR:Me,REMOVE_EVENT_LISTENER_STR:Ze})})}(e)})(at),function Ot(e){e.__load_patch("legacy",r=>{const c=r[e.__symbol__("legacyPatch")];c&&c()}),e.__load_patch("timers",r=>{const c="set",t="clear";ye(r,c,t,"Timeout"),ye(r,c,t,"Interval"),ye(r,c,t,"Immediate")}),e.__load_patch("requestAnimationFrame",r=>{ye(r,"request","cancel","AnimationFrame"),ye(r,"mozRequest","mozCancel","AnimationFrame"),ye(r,"webkitRequest","webkitCancel","AnimationFrame")}),e.__load_patch("blocking",(r,c)=>{const t=["alert","prompt","confirm"];for(let i=0;ifunction(D,d){return c.current.run(E,r,d,y)})}),e.__load_patch("EventTarget",(r,c,t)=>{(function Dt(e,r){r.patchEventPrototype(e,r)})(r,t),function Ct(e,r){if(Zone[r.symbol("patchEventTarget")])return;const{eventNames:c,zoneSymbolEventNames:t,TRUE_STR:i,FALSE_STR:u,ZONE_SYMBOL_PREFIX:E}=r.getGlobalObjects();for(let y=0;y{we("MutationObserver"),we("WebKitMutationObserver")}),e.__load_patch("IntersectionObserver",(r,c,t)=>{we("IntersectionObserver")}),e.__load_patch("FileReader",(r,c,t)=>{we("FileReader")}),e.__load_patch("on_property",(r,c,t)=>{!function St(e,r){if(De&&!Xe||Zone[e.symbol("patchEvents")])return;const c=r.__Zone_ignore_on_properties;let t=[];if(Ge){const i=window;t=t.concat(["Document","SVGElement","Element","HTMLElement","HTMLBodyElement","HTMLMediaElement","HTMLFrameSetElement","HTMLFrameElement","HTMLIFrameElement","HTMLMarqueeElement","Worker"]);const u=function mt(){try{const e=ge.navigator.userAgent;if(-1!==e.indexOf("MSIE ")||-1!==e.indexOf("Trident/"))return!0}catch{}return!1}()?[{target:i,ignoreProperties:["error"]}]:[];ct(i,Fe(i),c&&c.concat(u),Ie(i))}t=t.concat(["XMLHttpRequest","XMLHttpRequestEventTarget","IDBIndex","IDBRequest","IDBOpenDBRequest","IDBDatabase","IDBTransaction","IDBCursor","WebSocket"]);for(let i=0;i{!function Rt(e,r){const{isBrowser:c,isMix:t}=r.getGlobalObjects();(c||t)&&e.customElements&&"customElements"in e&&r.patchCallbacks(r,e.customElements,"customElements","define",["connectedCallback","disconnectedCallback","adoptedCallback","attributeChangedCallback","formAssociatedCallback","formDisabledCallback","formResetCallback","formStateRestoreCallback"])}(r,t)}),e.__load_patch("XHR",(r,c)=>{!function D(d){const w=d.XMLHttpRequest;if(!w)return;const Z=w.prototype;let U=Z[Ae],K=Z[je];if(!U){const R=d.XMLHttpRequestEventTarget;if(R){const b=R.prototype;U=b[Ae],K=b[je]}}const J="readystatechange",X="scheduled";function k(R){const b=R.data,S=b.target;S[E]=!1,S[y]=!1;const ee=S[u];U||(U=S[Ae],K=S[je]),ee&&K.call(S,J,ee);const W=S[u]=()=>{if(S.readyState===S.DONE)if(!b.aborted&&S[E]&&R.state===X){const _=S[c.__symbol__("loadfalse")];if(0!==S.status&&_&&_.length>0){const n=R.invoke;R.invoke=function(){const o=S[c.__symbol__("loadfalse")];for(let m=0;mfunction(R,b){return R[i]=0==b[2],R[T]=b[1],V.apply(R,b)}),G=j("fetchTaskAborting"),g=j("fetchTaskScheduling"),z=ue(Z,"send",()=>function(R,b){if(!0===c.current[g]||R[i])return z.apply(R,b);{const S={target:R,url:R[T],isPeriodic:!1,args:b,aborted:!1},ee=xe("XMLHttpRequest.send",h,S,k,H);R&&!0===R[y]&&!S.aborted&&ee.state===X&&ee.invoke()}}),O=ue(Z,"abort",()=>function(R,b){const S=function x(R){return R[t]}(R);if(S&&"string"==typeof S.type){if(null==S.cancelFn||S.data&&S.data.aborted)return;S.zone.cancelTask(S)}else if(!0===c.current[G])return O.apply(R,b)})}(r);const t=j("xhrTask"),i=j("xhrSync"),u=j("xhrListener"),E=j("xhrScheduled"),T=j("xhrURL"),y=j("xhrErrorBeforeScheduled")}),e.__load_patch("geolocation",r=>{r.navigator&&r.navigator.geolocation&&function gt(e,r){const c=e.constructor.name;for(let t=0;t{const y=function(){return T.apply(this,Ve(arguments,c+"."+i))};return fe(y,T),y})(u)}}}(r.navigator.geolocation,["getCurrentPosition","watchPosition"])}),e.__load_patch("PromiseRejectionEvent",(r,c)=>{function t(i){return function(u){st(r,i).forEach(T=>{const y=r.PromiseRejectionEvent;if(y){const D=new y(i,{promise:u.promise,reason:u.rejection});T.invoke(D)}})}}r.PromiseRejectionEvent&&(c[j("unhandledPromiseRejectionHandler")]=t("unhandledrejection"),c[j("rejectionHandledHandler")]=t("rejectionhandled"))}),e.__load_patch("queueMicrotask",(r,c,t)=>{!function wt(e,r){r.patchMethod(e,"queueMicrotask",c=>function(t,i){Zone.current.scheduleMicroTask("queueMicrotask",i[0])})}(r,t)})}(at)}},te=>{te(te.s=50)}]); - -"use strict";(self.webpackChunkcoverage_app=self.webpackChunkcoverage_app||[]).push([[792],{332:()=>{function ua(e,n){return Object.is(e,n)}let Le=null,xo=!1,ru=1;const Ke=Symbol("SIGNAL");function te(e){const n=Le;return Le=e,n}const Er={version:0,lastCleanEpoch:0,dirty:!1,producerNode:void 0,producerLastReadVersion:void 0,producerIndexOfThis:void 0,nextProducerIndex:0,liveConsumerNode:void 0,liveConsumerIndexOfThis:void 0,consumerAllowSignalWrites:!1,consumerIsAlwaysLive:!1,kind:"unknown",producerMustRecompute:()=>!1,producerRecomputeValue:()=>{},consumerMarkedDirty:()=>{},consumerOnSignalRead:()=>{}};function Oo(e){if(xo)throw new Error("");if(null===Le)return;Le.consumerOnSignalRead(e);const n=Le.nextProducerIndex++;ha(Le),ne.nextProducerIndex;)e.producerNode.pop(),e.producerLastReadVersion.pop(),e.producerIndexOfThis.pop()}}function Ro(e){ha(e);for(let n=0;n0}function ha(e){e.producerNode??=[],e.producerIndexOfThis??=[],e.producerLastReadVersion??=[]}function ip(e){e.liveConsumerNode??=[],e.liveConsumerIndexOfThis??=[]}function op(e){return void 0!==e.producerNode}const Mr=Symbol("UNSET"),pi=Symbol("COMPUTING"),Gn=Symbol("ERRORED"),vM={...Er,value:Mr,dirty:!0,error:null,equal:ua,kind:"computed",producerMustRecompute:e=>e.value===Mr||e.value===pi,producerRecomputeValue(e){if(e.value===pi)throw new Error("Detected cycle in computations.");const n=e.value;e.value=pi;const t=Ir(e);let r,i=!1;try{r=e.computation(),te(null),i=n!==Mr&&n!==Gn&&r!==Gn&&e.equal(n,r)}catch(o){r=Gn,e.error=o}finally{gi(e,t)}i?e.value=n:(e.value=r,e.version++)}};let sp=function _M(){throw new Error};function ap(){sp()}function ou(e,n){tp()||ap(),e.equal(e.value,n)||(e.value=n,function wM(e){e.version++,function pM(){ru++}(),ep(e)}(e))}const cp={...Er,equal:ua,value:void 0,kind:"signal"};function Be(e){return"function"==typeof e}function dp(e){const t=e(r=>{Error.call(r),r.stack=(new Error).stack});return t.prototype=Object.create(Error.prototype),t.prototype.constructor=t,t}const au=dp(e=>function(t){e(this),this.message=t?`${t.length} errors occurred during unsubscription:\n${t.map((r,i)=>`${i+1}) ${r.toString()}`).join("\n ")}`:"",this.name="UnsubscriptionError",this.errors=t});function pa(e,n){if(e){const t=e.indexOf(n);0<=t&&e.splice(t,1)}}class Rt{constructor(n){this.initialTeardown=n,this.closed=!1,this._parentage=null,this._finalizers=null}unsubscribe(){let n;if(!this.closed){this.closed=!0;const{_parentage:t}=this;if(t)if(this._parentage=null,Array.isArray(t))for(const o of t)o.remove(this);else t.remove(this);const{initialTeardown:r}=this;if(Be(r))try{r()}catch(o){n=o instanceof au?o.errors:[o]}const{_finalizers:i}=this;if(i){this._finalizers=null;for(const o of i)try{gp(o)}catch(s){n=n??[],s instanceof au?n=[...n,...s.errors]:n.push(s)}}if(n)throw new au(n)}}add(n){var t;if(n&&n!==this)if(this.closed)gp(n);else{if(n instanceof Rt){if(n.closed||n._hasParent(this))return;n._addParent(this)}(this._finalizers=null!==(t=this._finalizers)&&void 0!==t?t:[]).push(n)}}_hasParent(n){const{_parentage:t}=this;return t===n||Array.isArray(t)&&t.includes(n)}_addParent(n){const{_parentage:t}=this;this._parentage=Array.isArray(t)?(t.push(n),t):t?[t,n]:n}_removeParent(n){const{_parentage:t}=this;t===n?this._parentage=null:Array.isArray(t)&&pa(t,n)}remove(n){const{_finalizers:t}=this;t&&pa(t,n),n instanceof Rt&&n._removeParent(this)}}Rt.EMPTY=(()=>{const e=new Rt;return e.closed=!0,e})();const fp=Rt.EMPTY;function hp(e){return e instanceof Rt||e&&"closed"in e&&Be(e.remove)&&Be(e.add)&&Be(e.unsubscribe)}function gp(e){Be(e)?e():e.unsubscribe()}const Tr={onUnhandledError:null,onStoppedNotification:null,Promise:void 0,useDeprecatedSynchronousErrorHandling:!1,useDeprecatedNextContext:!1},ma={setTimeout(e,n,...t){const{delegate:r}=ma;return r?.setTimeout?r.setTimeout(e,n,...t):setTimeout(e,n,...t)},clearTimeout(e){const{delegate:n}=ma;return(n?.clearTimeout||clearTimeout)(e)},delegate:void 0};function pp(e){ma.setTimeout(()=>{const{onUnhandledError:n}=Tr;if(!n)throw e;n(e)})}function mp(){}const TM=lu("C",void 0,void 0);function lu(e,n,t){return{kind:e,value:n,error:t}}let Sr=null;function va(e){if(Tr.useDeprecatedSynchronousErrorHandling){const n=!Sr;if(n&&(Sr={errorThrown:!1,error:null}),e(),n){const{errorThrown:t,error:r}=Sr;if(Sr=null,t)throw r}}else e()}class cu extends Rt{constructor(n){super(),this.isStopped=!1,n?(this.destination=n,hp(n)&&n.add(this)):this.destination=kM}static create(n,t,r){return new du(n,t,r)}next(n){this.isStopped?fu(function NM(e){return lu("N",e,void 0)}(n),this):this._next(n)}error(n){this.isStopped?fu(function SM(e){return lu("E",void 0,e)}(n),this):(this.isStopped=!0,this._error(n))}complete(){this.isStopped?fu(TM,this):(this.isStopped=!0,this._complete())}unsubscribe(){this.closed||(this.isStopped=!0,super.unsubscribe(),this.destination=null)}_next(n){this.destination.next(n)}_error(n){try{this.destination.error(n)}finally{this.unsubscribe()}}_complete(){try{this.destination.complete()}finally{this.unsubscribe()}}}const OM=Function.prototype.bind;function uu(e,n){return OM.call(e,n)}class AM{constructor(n){this.partialObserver=n}next(n){const{partialObserver:t}=this;if(t.next)try{t.next(n)}catch(r){_a(r)}}error(n){const{partialObserver:t}=this;if(t.error)try{t.error(n)}catch(r){_a(r)}else _a(n)}complete(){const{partialObserver:n}=this;if(n.complete)try{n.complete()}catch(t){_a(t)}}}class du extends cu{constructor(n,t,r){let i;if(super(),Be(n)||!n)i={next:n??void 0,error:t??void 0,complete:r??void 0};else{let o;this&&Tr.useDeprecatedNextContext?(o=Object.create(n),o.unsubscribe=()=>this.unsubscribe(),i={next:n.next&&uu(n.next,o),error:n.error&&uu(n.error,o),complete:n.complete&&uu(n.complete,o)}):i=n}this.destination=new AM(i)}}function _a(e){Tr.useDeprecatedSynchronousErrorHandling?function xM(e){Tr.useDeprecatedSynchronousErrorHandling&&Sr&&(Sr.errorThrown=!0,Sr.error=e)}(e):pp(e)}function fu(e,n){const{onStoppedNotification:t}=Tr;t&&ma.setTimeout(()=>t(e,n))}const kM={closed:!0,next:mp,error:function RM(e){throw e},complete:mp},hu="function"==typeof Symbol&&Symbol.observable||"@@observable";function gu(e){return e}let kt=(()=>{class e{constructor(t){t&&(this._subscribe=t)}lift(t){const r=new e;return r.source=this,r.operator=t,r}subscribe(t,r,i){const o=function LM(e){return e&&e instanceof cu||function FM(e){return e&&Be(e.next)&&Be(e.error)&&Be(e.complete)}(e)&&hp(e)}(t)?t:new du(t,r,i);return va(()=>{const{operator:s,source:a}=this;o.add(s?s.call(o,a):a?this._subscribe(o):this._trySubscribe(o))}),o}_trySubscribe(t){try{return this._subscribe(t)}catch(r){t.error(r)}}forEach(t,r){return new(r=_p(r))((i,o)=>{const s=new du({next:a=>{try{t(a)}catch(l){o(l),s.unsubscribe()}},error:o,complete:i});this.subscribe(s)})}_subscribe(t){var r;return null===(r=this.source)||void 0===r?void 0:r.subscribe(t)}[hu](){return this}pipe(...t){return function vp(e){return 0===e.length?gu:1===e.length?e[0]:function(t){return e.reduce((r,i)=>i(r),t)}}(t)(this)}toPromise(t){return new(t=_p(t))((r,i)=>{let o;this.subscribe(s=>o=s,s=>i(s),()=>r(o))})}}return e.create=n=>new e(n),e})();function _p(e){var n;return null!==(n=e??Tr.Promise)&&void 0!==n?n:Promise}const PM=dp(e=>function(){e(this),this.name="ObjectUnsubscribedError",this.message="object unsubscribed"});let fn=(()=>{class e extends kt{constructor(){super(),this.closed=!1,this.currentObservers=null,this.observers=[],this.isStopped=!1,this.hasError=!1,this.thrownError=null}lift(t){const r=new yp(this,this);return r.operator=t,r}_throwIfClosed(){if(this.closed)throw new PM}next(t){va(()=>{if(this._throwIfClosed(),!this.isStopped){this.currentObservers||(this.currentObservers=Array.from(this.observers));for(const r of this.currentObservers)r.next(t)}})}error(t){va(()=>{if(this._throwIfClosed(),!this.isStopped){this.hasError=this.isStopped=!0,this.thrownError=t;const{observers:r}=this;for(;r.length;)r.shift().error(t)}})}complete(){va(()=>{if(this._throwIfClosed(),!this.isStopped){this.isStopped=!0;const{observers:t}=this;for(;t.length;)t.shift().complete()}})}unsubscribe(){this.isStopped=this.closed=!0,this.observers=this.currentObservers=null}get observed(){var t;return(null===(t=this.observers)||void 0===t?void 0:t.length)>0}_trySubscribe(t){return this._throwIfClosed(),super._trySubscribe(t)}_subscribe(t){return this._throwIfClosed(),this._checkFinalizedStatuses(t),this._innerSubscribe(t)}_innerSubscribe(t){const{hasError:r,isStopped:i,observers:o}=this;return r||i?fp:(this.currentObservers=null,o.push(t),new Rt(()=>{this.currentObservers=null,pa(o,t)}))}_checkFinalizedStatuses(t){const{hasError:r,thrownError:i,isStopped:o}=this;r?t.error(i):o&&t.complete()}asObservable(){const t=new kt;return t.source=this,t}}return e.create=(n,t)=>new yp(n,t),e})();class yp extends fn{constructor(n,t){super(),this.destination=n,this.source=t}next(n){var t,r;null===(r=null===(t=this.destination)||void 0===t?void 0:t.next)||void 0===r||r.call(t,n)}error(n){var t,r;null===(r=null===(t=this.destination)||void 0===t?void 0:t.error)||void 0===r||r.call(t,n)}complete(){var n,t;null===(t=null===(n=this.destination)||void 0===n?void 0:n.complete)||void 0===t||t.call(n)}_subscribe(n){var t,r;return null!==(r=null===(t=this.source)||void 0===t?void 0:t.subscribe(n))&&void 0!==r?r:fp}}class VM extends fn{constructor(n){super(),this._value=n}get value(){return this.getValue()}_subscribe(n){const t=super._subscribe(n);return!t.closed&&n.next(this._value),t}getValue(){const{hasError:n,thrownError:t,_value:r}=this;if(n)throw t;return this._throwIfClosed(),r}next(n){super.next(this._value=n)}}function Nr(e){return n=>{if(function HM(e){return Be(e?.lift)}(n))return n.lift(function(t){try{return e(t,this)}catch(r){this.error(r)}});throw new TypeError("Unable to lift unknown Observable type")}}function qn(e,n,t,r,i){return new BM(e,n,t,r,i)}class BM extends cu{constructor(n,t,r,i,o,s){super(n),this.onFinalize=o,this.shouldUnsubscribe=s,this._next=t?function(a){try{t(a)}catch(l){n.error(l)}}:super._next,this._error=i?function(a){try{i(a)}catch(l){n.error(l)}finally{this.unsubscribe()}}:super._error,this._complete=r?function(){try{r()}catch(a){n.error(a)}finally{this.unsubscribe()}}:super._complete}unsubscribe(){var n;if(!this.shouldUnsubscribe||this.shouldUnsubscribe()){const{closed:t}=this;super.unsubscribe(),!t&&(null===(n=this.onFinalize)||void 0===n||n.call(this))}}}function pu(e,n){return Nr((t,r)=>{let i=0;t.subscribe(qn(r,o=>{r.next(e.call(n,o,i++))}))})}const Cp="https://g.co/ng/security#xss";class N extends Error{code;constructor(n,t){super(function xr(e,n){return`NG0${Math.abs(e)}${n?": "+n:""}`}(n,t)),this.code=n}}function Sn(e){return{toString:e}.toString()}const vi="__parameters__";function yi(e,n,t){return Sn(()=>{const r=function mu(e){return function(...t){if(e){const r=e(...t);for(const i in r)this[i]=r[i]}}}(n);function i(...o){if(this instanceof i)return r.apply(this,o),this;const s=new i(...o);return a.annotation=s,a;function a(l,c,u){const d=l.hasOwnProperty(vi)?l[vi]:Object.defineProperty(l,vi,{value:[]})[vi];for(;d.length<=u;)d.push(null);return(d[u]=d[u]||[]).push(s),l}}return t&&(i.prototype=Object.create(t.prototype)),i.prototype.ngMetadataName=e,i.annotationCls=i,i})}const Ie=globalThis;function fe(e){for(let n in e)if(e[n]===fe)return n;throw Error("Could not find renamed property on target object.")}function jM(e,n){for(const t in n)n.hasOwnProperty(t)&&!e.hasOwnProperty(t)&&(e[t]=n[t])}function $e(e){if("string"==typeof e)return e;if(Array.isArray(e))return"["+e.map($e).join(", ")+"]";if(null==e)return""+e;if(e.overriddenName)return`${e.overriddenName}`;if(e.name)return`${e.name}`;const n=e.toString();if(null==n)return""+n;const t=n.indexOf("\n");return-1===t?n:n.substring(0,t)}function vu(e,n){return null==e||""===e?null===n?"":n:null==n||""===n?e:e+" "+n}const UM=fe({__forward_ref__:fe});function ve(e){return e.__forward_ref__=ve,e.toString=function(){return $e(this())},e}function W(e){return Ca(e)?e():e}function Ca(e){return"function"==typeof e&&e.hasOwnProperty(UM)&&e.__forward_ref__===ve}function re(e){return{token:e.token,providedIn:e.providedIn||null,factory:e.factory,value:void 0}}function Nn(e){return{providers:e.providers||[],imports:e.imports||[]}}function wa(e){return Ep(e,ba)||Ep(e,Ip)}function Ep(e,n){return e.hasOwnProperty(n)?e[n]:null}function Da(e){return e&&(e.hasOwnProperty(_u)||e.hasOwnProperty(WM))?e[_u]:null}const ba=fe({\u0275prov:fe}),_u=fe({\u0275inj:fe}),Ip=fe({ngInjectableDef:fe}),WM=fe({ngInjectorDef:fe});class R{_desc;ngMetadataName="InjectionToken";\u0275prov;constructor(n,t){this._desc=n,this.\u0275prov=void 0,"number"==typeof t?this.__NG_ELEMENT_ID__=t:void 0!==t&&(this.\u0275prov=re({token:this,providedIn:t.providedIn||"root",factory:t.factory}))}get multi(){return this}toString(){return`InjectionToken ${this._desc}`}}function wu(e){return e&&!!e.\u0275providers}const Ci=fe({\u0275cmp:fe}),Du=fe({\u0275dir:fe}),bu=fe({\u0275pipe:fe}),Tp=fe({\u0275mod:fe}),xn=fe({\u0275fac:fe}),Lo=fe({__NG_ELEMENT_ID__:fe}),Sp=fe({__NG_ENV_ID__:fe});function K(e){return"string"==typeof e?e:null==e?"":String(e)}function Eu(e,n){throw new N(-201,!1)}var oe=function(e){return e[e.Default=0]="Default",e[e.Host=1]="Host",e[e.Self=2]="Self",e[e.SkipSelf=4]="SkipSelf",e[e.Optional=8]="Optional",e}(oe||{});let Iu;function Np(){return Iu}function Et(e){const n=Iu;return Iu=e,n}function xp(e,n,t){const r=wa(e);return r&&"root"==r.providedIn?void 0===r.value?r.value=r.factory():r.value:t&oe.Optional?null:void 0!==n?n:void Eu()}const Po={},Mu="__NG_DI_FLAG__",Ma="ngTempTokenPath",XM=/\n/gm,Op="__source";let wi;function Zn(e){const n=wi;return wi=e,n}function n0(e,n=oe.Default){if(void 0===wi)throw new N(-203,!1);return null===wi?xp(e,void 0,n):wi.get(e,n&oe.Optional?null:void 0,n)}function se(e,n=oe.Default){return(Np()||n0)(W(e),n)}function A(e,n=oe.Default){return se(e,Ta(n))}function Ta(e){return typeof e>"u"||"number"==typeof e?e:(e.optional&&8)|(e.host&&1)|(e.self&&2)|(e.skipSelf&&4)}function Tu(e){const n=[];for(let t=0;tArray.isArray(t)?Di(t,n):n(t))}function Rp(e,n,t){n>=e.length?e.push(t):e.splice(n,0,t)}function Sa(e,n){return n>=e.length-1?e.pop():e.splice(n,1)[0]}function Lt(e,n,t){let r=bi(e,n);return r>=0?e[1|r]=t:(r=~r,function kp(e,n,t,r){let i=e.length;if(i==n)e.push(t,r);else if(1===i)e.push(r,e[0]),e[0]=t;else{for(i--,e.push(e[i-1],e[i]);i>n;)e[i]=e[i-2],i--;e[n]=t,e[n+1]=r}}(e,r,n,t)),r}function Ou(e,n){const t=bi(e,n);if(t>=0)return e[1|t]}function bi(e,n){return function Fp(e,n,t){let r=0,i=e.length>>t;for(;i!==r;){const o=r+(i-r>>1),s=e[o<n?i=o:r=o+1}return~(i<{t.push(s)};return Di(n,s=>{const a=s;Oa(a,o,[],r)&&(i||=[],i.push(a))}),void 0!==i&&Pp(i,o),t}function Pp(e,n){for(let t=0;t{n(o,r)})}}function Oa(e,n,t,r){if(!(e=W(e)))return!1;let i=null,o=Da(e);const s=!o&&ne(e);if(o||s){if(s&&!s.standalone)return!1;i=e}else{const l=e.ngModule;if(o=Da(l),!o)return!1;i=l}const a=r.has(i);if(s){if(a)return!1;if(r.add(i),s.dependencies){const l="function"==typeof s.dependencies?s.dependencies():s.dependencies;for(const c of l)Oa(c,n,t,r)}}else{if(!o)return!1;{if(null!=o.imports&&!a){let c;r.add(i);try{Di(o.imports,u=>{Oa(u,n,t,r)&&(c||=[],c.push(u))})}finally{}void 0!==c&&Pp(c,n)}if(!a){const c=Or(i)||(()=>new i);n({provide:i,useFactory:c,deps:le},i),n({provide:Au,useValue:i,multi:!0},i),n({provide:en,useValue:()=>se(i),multi:!0},i)}const l=o.providers;if(null!=l&&!a){const c=e;ku(l,u=>{n(u,c)})}}}return i!==e&&void 0!==e.providers}function ku(e,n){for(let t of e)wu(t)&&(t=t.\u0275providers),Array.isArray(t)?ku(t,n):n(t)}const f0=fe({provide:String,useValue:fe});function Fu(e){return null!==e&&"object"==typeof e&&f0 in e}function kr(e){return"function"==typeof e}const Lu=new R(""),Aa={},g0={};let Pu;function Ra(){return void 0===Pu&&(Pu=new xa),Pu}class tn{}class Fr extends tn{parent;source;scopes;records=new Map;_ngOnDestroyHooks=new Set;_onDestroyHooks=[];get destroyed(){return this._destroyed}_destroyed=!1;injectorDefTypes;constructor(n,t,r,i){super(),this.parent=t,this.source=r,this.scopes=i,Hu(n,s=>this.processProvider(s)),this.records.set(Lp,Ei(void 0,this)),i.has("environment")&&this.records.set(tn,Ei(void 0,this));const o=this.records.get(Lu);null!=o&&"string"==typeof o.value&&this.scopes.add(o.value),this.injectorDefTypes=new Set(this.get(Au,le,oe.Self))}destroy(){Ho(this),this._destroyed=!0;const n=te(null);try{for(const r of this._ngOnDestroyHooks)r.ngOnDestroy();const t=this._onDestroyHooks;this._onDestroyHooks=[];for(const r of t)r()}finally{this.records.clear(),this._ngOnDestroyHooks.clear(),this.injectorDefTypes.clear(),te(n)}}onDestroy(n){return Ho(this),this._onDestroyHooks.push(n),()=>this.removeOnDestroy(n)}runInContext(n){Ho(this);const t=Zn(this),r=Et(void 0);try{return n()}finally{Zn(t),Et(r)}}get(n,t=Po,r=oe.Default){if(Ho(this),n.hasOwnProperty(Sp))return n[Sp](this);r=Ta(r);const o=Zn(this),s=Et(void 0);try{if(!(r&oe.SkipSelf)){let l=this.records.get(n);if(void 0===l){const c=function y0(e){return"function"==typeof e||"object"==typeof e&&e instanceof R}(n)&&wa(n);l=c&&this.injectableDefInScope(c)?Ei(Vu(n),Aa):null,this.records.set(n,l)}if(null!=l)return this.hydrate(n,l)}return(r&oe.Self?Ra():this.parent).get(n,t=r&oe.Optional&&t===Po?null:t)}catch(a){if("NullInjectorError"===a.name){if((a[Ma]=a[Ma]||[]).unshift($e(n)),o)throw a;return function o0(e,n,t,r){const i=e[Ma];throw n[Op]&&i.unshift(n[Op]),e.message=function s0(e,n,t,r=null){e=e&&"\n"===e.charAt(0)&&"\u0275"==e.charAt(1)?e.slice(2):e;let i=$e(n);if(Array.isArray(n))i=n.map($e).join(" -> ");else if("object"==typeof n){let o=[];for(let s in n)if(n.hasOwnProperty(s)){let a=n[s];o.push(s+":"+("string"==typeof a?JSON.stringify(a):$e(a)))}i=`{${o.join(", ")}}`}return`${t}${r?"("+r+")":""}[${i}]: ${e.replace(XM,"\n ")}`}("\n"+e.message,i,t,r),e.ngTokenPath=i,e[Ma]=null,e}(a,n,"R3InjectorError",this.source)}throw a}finally{Et(s),Zn(o)}}resolveInjectorInitializers(){const n=te(null),t=Zn(this),r=Et(void 0);try{const o=this.get(en,le,oe.Self);for(const s of o)s()}finally{Zn(t),Et(r),te(n)}}toString(){const n=[],t=this.records;for(const r of t.keys())n.push($e(r));return`R3Injector[${n.join(", ")}]`}processProvider(n){let t=kr(n=W(n))?n:W(n&&n.provide);const r=function m0(e){return Fu(e)?Ei(void 0,e.useValue):Ei(Bp(e),Aa)}(n);if(!kr(n)&&!0===n.multi){let i=this.records.get(t);i||(i=Ei(void 0,Aa,!0),i.factory=()=>Tu(i.multi),this.records.set(t,i)),t=n,i.multi.push(n)}this.records.set(t,r)}hydrate(n,t){const r=te(null);try{return t.value===Aa&&(t.value=g0,t.value=t.factory()),"object"==typeof t.value&&t.value&&function _0(e){return null!==e&&"object"==typeof e&&"function"==typeof e.ngOnDestroy}(t.value)&&this._ngOnDestroyHooks.add(t.value),t.value}finally{te(r)}}injectableDefInScope(n){if(!n.providedIn)return!1;const t=W(n.providedIn);return"string"==typeof t?"any"===t||this.scopes.has(t):this.injectorDefTypes.has(t)}removeOnDestroy(n){const t=this._onDestroyHooks.indexOf(n);-1!==t&&this._onDestroyHooks.splice(t,1)}}function Vu(e){const n=wa(e),t=null!==n?n.factory:Or(e);if(null!==t)return t;if(e instanceof R)throw new N(204,!1);if(e instanceof Function)return function p0(e){if(e.length>0)throw new N(204,!1);const t=function qM(e){return e&&(e[ba]||e[Ip])||null}(e);return null!==t?()=>t.factory(e):()=>new e}(e);throw new N(204,!1)}function Bp(e,n,t){let r;if(kr(e)){const i=W(e);return Or(i)||Vu(i)}if(Fu(e))r=()=>W(e.useValue);else if(function Hp(e){return!(!e||!e.useFactory)}(e))r=()=>e.useFactory(...Tu(e.deps||[]));else if(function Vp(e){return!(!e||!e.useExisting)}(e))r=()=>se(W(e.useExisting));else{const i=W(e&&(e.useClass||e.provide));if(!function v0(e){return!!e.deps}(e))return Or(i)||Vu(i);r=()=>new i(...Tu(e.deps))}return r}function Ho(e){if(e.destroyed)throw new N(205,!1)}function Ei(e,n,t=!1){return{factory:e,value:n,multi:t?[]:void 0}}function Hu(e,n){for(const t of e)Array.isArray(t)?Hu(t,n):t&&wu(t)?Hu(t.\u0275providers,n):n(t)}function jp(e,n){e instanceof Fr&&Ho(e);const r=Zn(e),i=Et(void 0);try{return n()}finally{Zn(r),Et(i)}}const G=11,k=25;function Ne(e){return Array.isArray(e)&&"object"==typeof e[1]}function qe(e){return Array.isArray(e)&&!0===e[1]}function Uu(e){return!!(4&e.flags)}function $t(e){return e.componentOffset>-1}function Va(e){return!(1&~e.flags)}function zt(e){return!!e.template}function Rn(e){return!!(512&e[2])}function Yn(e){return!(256&~e[2])}class O0{previousValue;currentValue;firstChange;constructor(n,t,r){this.previousValue=n,this.currentValue=t,this.firstChange=r}isFirstChange(){return this.firstChange}}function Yp(e,n,t,r){null!==n?n.applyValueToInputSignal(n,r):e[t]=r}const kn=(()=>{const e=()=>Kp;return e.ngInherit=!0,e})();function Kp(e){return e.type.prototype.ngOnChanges&&(e.setInput=R0),A0}function A0(){const e=Xp(this),n=e?.current;if(n){const t=e.previous;if(t===hn)e.previous=n;else for(let r in n)t[r]=n[r];e.current=null,this.ngOnChanges(n)}}function R0(e,n,t,r,i){const o=this.declaredInputs[r],s=Xp(e)||function k0(e,n){return e[Jp]=n}(e,{previous:hn,current:null}),a=s.current||(s.current={}),l=s.previous,c=l[o];a[o]=new O0(c&&c.currentValue,t,l===hn),Yp(e,n,i,t)}const Jp="__ngSimpleChanges__";function Xp(e){return e[Jp]||null}function ae(e){for(;Array.isArray(e);)e=e[0];return e}function Ai(e,n){return ae(n[e])}function ft(e,n){return ae(n[e.index])}function Hr(e,n){return e.data[n]}function ht(e,n){const t=n[e];return Ne(t)?t:t[0]}function Gu(e){return!(128&~e[2])}function qt(e,n){return null==n?null:e[n]}function nm(e){e[17]=0}function qu(e){1024&e[2]||(e[2]|=1024,Gu(e)&&jo(e))}function Ba(e){return!!(9216&e[2]||e[24]?.dirty)}function Wu(e){e[10].changeDetectionScheduler?.notify(9),64&e[2]&&(e[2]|=1024),Ba(e)&&jo(e)}function jo(e){e[10].changeDetectionScheduler?.notify(0);let n=Fn(e);for(;null!==n&&!(8192&n[2])&&(n[2]|=8192,Gu(n));)n=Fn(n)}function ja(e,n){if(Yn(e))throw new N(911,!1);null===e[21]&&(e[21]=[]),e[21].push(n)}function Fn(e){const n=e[3];return qe(n)?n[3]:n}function im(e){return e[7]??=[]}function om(e){return e.cleanup??=[]}const Q={lFrame:pm(null),bindingsEnabled:!0,skipHydrationRootTNode:null};let Yu=!1;function sm(){return Q.bindingsEnabled}function D(){return Q.lFrame.lView}function Z(){return Q.lFrame.tView}function B(e){return Q.lFrame.contextLView=e,e[8]}function j(e){return Q.lFrame.contextLView=null,e}function ie(){let e=am();for(;null!==e&&64===e.type;)e=e.parent;return e}function am(){return Q.lFrame.currentTNode}function nn(e,n){const t=Q.lFrame;t.currentTNode=e,t.isParent=n}function Ku(){return Q.lFrame.isParent}function Ju(){Q.lFrame.isParent=!1}function um(){return Yu}function $a(e){const n=Yu;return Yu=e,n}function gt(){const e=Q.lFrame;let n=e.bindingRootIndex;return-1===n&&(n=e.bindingRootIndex=e.tView.bindingStartIndex),n}function Wt(){return Q.lFrame.bindingIndex++}function Pn(e){const n=Q.lFrame,t=n.bindingIndex;return n.bindingIndex=n.bindingIndex+e,t}function Q0(e,n){const t=Q.lFrame;t.bindingIndex=t.bindingRootIndex=e,Xu(n)}function Xu(e){Q.lFrame.currentDirectiveIndex=e}function td(){return Q.lFrame.currentQueryIndex}function za(e){Q.lFrame.currentQueryIndex=e}function K0(e){const n=e[1];return 2===n.type?n.declTNode:1===n.type?e[5]:null}function hm(e,n,t){if(t&oe.SkipSelf){let i=n,o=e;for(;!(i=i.parent,null!==i||t&oe.Host||(i=K0(o),null===i||(o=o[14],10&i.type))););if(null===i)return!1;n=i,e=o}const r=Q.lFrame=gm();return r.currentTNode=n,r.lView=e,!0}function nd(e){const n=gm(),t=e[1];Q.lFrame=n,n.currentTNode=t.firstChild,n.lView=e,n.tView=t,n.contextLView=e,n.bindingIndex=t.bindingStartIndex,n.inI18n=!1}function gm(){const e=Q.lFrame,n=null===e?null:e.child;return null===n?pm(e):n}function pm(e){const n={currentTNode:null,isParent:!0,lView:null,tView:null,selectedIndex:-1,contextLView:null,elementDepthCount:0,currentNamespace:null,currentDirectiveIndex:-1,bindingRootIndex:-1,bindingIndex:-1,currentQueryIndex:0,parent:e,child:null,inI18n:!1};return null!==e&&(e.child=n),n}function mm(){const e=Q.lFrame;return Q.lFrame=e.parent,e.currentTNode=null,e.lView=null,e}const vm=mm;function rd(){const e=mm();e.isParent=!0,e.tView=null,e.selectedIndex=-1,e.contextLView=null,e.elementDepthCount=0,e.currentDirectiveIndex=-1,e.currentNamespace=null,e.bindingRootIndex=-1,e.bindingIndex=-1,e.currentQueryIndex=0}function rt(){return Q.lFrame.selectedIndex}function Ur(e){Q.lFrame.selectedIndex=e}function me(){const e=Q.lFrame;return Hr(e.tView,e.selectedIndex)}let Cm=!0;function $o(){return Cm}function mn(e){Cm=e}function Ga(e,n){for(let t=n.directiveStart,r=n.directiveEnd;t=r)break}else n[l]<0&&(e[17]+=65536),(a>14>16&&(3&e[2])===n&&(e[2]+=16384,Dm(a,o)):Dm(a,o)}class zo{factory;injectImpl;resolving=!1;canSeeViewProviders;multi;componentProviders;index;providerFactory;constructor(n,t,r){this.factory=n,this.canSeeViewProviders=t,this.injectImpl=r}}function bm(e){return 3===e||4===e||6===e}function Em(e){return 64===e.charCodeAt(0)}function ki(e,n){if(null!==n&&0!==n.length)if(null===e||0===e.length)e=n.slice();else{let t=-1;for(let r=0;rn){s=o-1;break}}}for(;o>16}(e),r=n;for(;t>0;)r=r[14],t--;return r}let cd=!0;function Za(e){const n=cd;return cd=e,n}let dT=0;const vn={};function Qa(e,n){const t=Sm(e,n);if(-1!==t)return t;const r=n[1];r.firstCreatePass&&(e.injectorIndex=n.length,ud(r.data,e),ud(n,null),ud(r.blueprint,null));const i=Ya(e,n),o=e.injectorIndex;if(ld(i)){const s=Go(i),a=qo(i,n),l=a[1].data;for(let c=0;c<8;c++)n[o+c]=a[s+c]|l[s+c]}return n[o+8]=i,o}function ud(e,n){e.push(0,0,0,0,0,0,0,0,n)}function Sm(e,n){return-1===e.injectorIndex||e.parent&&e.parent.injectorIndex===e.injectorIndex||null===n[e.injectorIndex+8]?-1:e.injectorIndex}function Ya(e,n){if(e.parent&&-1!==e.parent.injectorIndex)return e.parent.injectorIndex;let t=0,r=null,i=n;for(;null!==i;){if(r=Fm(i),null===r)return-1;if(t++,i=i[14],-1!==r.injectorIndex)return r.injectorIndex|t<<16}return-1}function dd(e,n,t){!function fT(e,n,t){let r;"string"==typeof t?r=t.charCodeAt(0)||0:t.hasOwnProperty(Lo)&&(r=t[Lo]),null==r&&(r=t[Lo]=dT++);const i=255&r;n.data[e+(i>>5)]|=1<=0?255&n:mT:n}(t);if("function"==typeof o){if(!hm(n,e,r))return r&oe.Host?Nm(i,0,r):xm(n,t,r,i);try{let s;if(s=o(r),null!=s||r&oe.Optional)return s;Eu()}finally{vm()}}else if("number"==typeof o){let s=null,a=Sm(e,n),l=-1,c=r&oe.Host?n[15][5]:null;for((-1===a||r&oe.SkipSelf)&&(l=-1===a?Ya(e,n):n[a+8],-1!==l&&km(r,!1)?(s=n[1],a=Go(l),n=qo(l,n)):a=-1);-1!==a;){const u=n[1];if(Rm(o,a,u.data)){const d=gT(a,n,t,s,r,c);if(d!==vn)return d}l=n[a+8],-1!==l&&km(r,n[1].data[a+8]===c)&&Rm(o,a,n)?(s=u,a=Go(l),n=qo(l,n)):a=-1}}return i}function gT(e,n,t,r,i,o){const s=n[1],a=s.data[e+8],u=Ka(a,s,t,null==r?$t(a)&&cd:r!=s&&!!(3&a.type),i&oe.Host&&o===a);return null!==u?Wo(n,s,u,a):vn}function Ka(e,n,t,r,i){const o=e.providerIndexes,s=n.data,a=1048575&o,l=e.directiveStart,u=o>>20,g=i?a+u:e.directiveEnd;for(let h=r?a:a+u;h=l&&m.type===t)return h}if(i){const h=s[l];if(h&&zt(h)&&h.type===t)return l}return null}function Wo(e,n,t,r){let i=e[t];const o=n.data;if(function iT(e){return e instanceof zo}(i)){const s=i;s.resolving&&function YM(e,n){throw n&&n.join(" > "),new N(-200,e)}(function ce(e){return"function"==typeof e?e.name||e.toString():"object"==typeof e&&null!=e&&"function"==typeof e.type?e.type.name||e.type.toString():K(e)}(o[t]));const a=Za(s.canSeeViewProviders);s.resolving=!0;const c=s.injectImpl?Et(s.injectImpl):null;hm(e,r,oe.Default);try{i=e[t]=s.factory(void 0,o,e,r),n.firstCreatePass&&t>=r.directiveStart&&function nT(e,n,t){const{ngOnChanges:r,ngOnInit:i,ngDoCheck:o}=n.type.prototype;if(r){const s=Kp(n);(t.preOrderHooks??=[]).push(e,s),(t.preOrderCheckHooks??=[]).push(e,s)}i&&(t.preOrderHooks??=[]).push(0-e,i),o&&((t.preOrderHooks??=[]).push(e,o),(t.preOrderCheckHooks??=[]).push(e,o))}(t,o[t],n)}finally{null!==c&&Et(c),Za(a),s.resolving=!1,vm()}}return i}function Rm(e,n,t){return!!(t[n+(e>>5)]&1<{const n=e.prototype.constructor,t=n[xn]||fd(n),r=Object.prototype;let i=Object.getPrototypeOf(e.prototype).constructor;for(;i&&i!==r;){const o=i[xn]||fd(i);if(o&&o!==t)return o;i=Object.getPrototypeOf(i)}return o=>new o})}function fd(e){return Ca(e)?()=>{const n=fd(W(e));return n&&n()}:Or(e)}function Fm(e){const n=e[1],t=n.type;return 2===t?n.declTNode:1===t?e[5]:null}function Bm(e,n=null,t=null,r){const i=jm(e,n,t,r);return i.resolveInjectorInitializers(),i}function jm(e,n=null,t=null,r,i=new Set){const o=[t||le,d0(e)];return r=r||("object"==typeof e?void 0:$e(e)),new Fr(o,n||Ra(),r||null,i)}class We{static THROW_IF_NOT_FOUND=Po;static NULL=new xa;static create(n,t){if(Array.isArray(n))return Bm({name:""},t,n,"");{const r=n.name??"";return Bm({name:r},n.parent,n.providers,r)}}static \u0275prov=re({token:We,providedIn:"any",factory:()=>se(Lp)});static __NG_ELEMENT_ID__=-1}new R("").__NG_ELEMENT_ID__=e=>{const n=ie();if(null===n)throw new N(204,!1);if(2&n.type)return n.value;if(e&oe.Optional)return null;throw new N(204,!1)};const Um=!1;let Jn=(()=>class e{static __NG_ELEMENT_ID__=MT;static __NG_ENV_ID__=t=>t})();class $m extends Jn{_lView;constructor(n){super(),this._lView=n}onDestroy(n){return ja(this._lView,n),()=>function Zu(e,n){if(null===e[21])return;const t=e[21].indexOf(n);-1!==t&&e[21].splice(t,1)}(this._lView,n)}}function MT(){return new $m(D())}class Vn{}const Zo=new R("",{providedIn:"root",factory:()=>!1}),zm=new R(""),gd=new R("");let Xn=(()=>{class e{taskId=0;pendingTasks=new Set;get _hasPendingTasks(){return this.hasPendingTasks.value}hasPendingTasks=new VM(!1);add(){this._hasPendingTasks||this.hasPendingTasks.next(!0);const t=this.taskId++;return this.pendingTasks.add(t),t}has(t){return this.pendingTasks.has(t)}remove(t){this.pendingTasks.delete(t),0===this.pendingTasks.size&&this._hasPendingTasks&&this.hasPendingTasks.next(!1)}ngOnDestroy(){this.pendingTasks.clear(),this._hasPendingTasks&&this.hasPendingTasks.next(!1)}static \u0275prov=re({token:e,providedIn:"root",factory:()=>new e})}return e})();const we=class ST extends fn{__isAsync;destroyRef=void 0;pendingTasks=void 0;constructor(n=!1){super(),this.__isAsync=n,function Up(){return void 0!==Np()||null!=function t0(){return wi}()}()&&(this.destroyRef=A(Jn,{optional:!0})??void 0,this.pendingTasks=A(Xn,{optional:!0})??void 0)}emit(n){const t=te(null);try{super.next(n)}finally{te(t)}}subscribe(n,t,r){let i=n,o=t||(()=>null),s=r;if(n&&"object"==typeof n){const l=n;i=l.next?.bind(l),o=l.error?.bind(l),s=l.complete?.bind(l)}this.__isAsync&&(o=this.wrapInTimeout(o),i&&(i=this.wrapInTimeout(i)),s&&(s=this.wrapInTimeout(s)));const a=super.subscribe({next:i,error:o,complete:s});return n instanceof Rt&&n.add(a),a}wrapInTimeout(n){return t=>{const r=this.pendingTasks?.add();setTimeout(()=>{n(t),void 0!==r&&this.pendingTasks?.remove(r)})}}};function Qo(...e){}function Gm(e){let n,t;function r(){e=Qo;try{void 0!==t&&"function"==typeof cancelAnimationFrame&&cancelAnimationFrame(t),void 0!==n&&clearTimeout(n)}catch{}}return n=setTimeout(()=>{e(),r()}),"function"==typeof requestAnimationFrame&&(t=requestAnimationFrame(()=>{e(),r()})),()=>r()}function qm(e){return queueMicrotask(()=>e()),()=>{e=Qo}}const pd="isAngularZone",el=pd+"_ID";let NT=0;class de{hasPendingMacrotasks=!1;hasPendingMicrotasks=!1;isStable=!0;onUnstable=new we(!1);onMicrotaskEmpty=new we(!1);onStable=new we(!1);onError=new we(!1);constructor(n){const{enableLongStackTrace:t=!1,shouldCoalesceEventChangeDetection:r=!1,shouldCoalesceRunChangeDetection:i=!1,scheduleInRootZone:o=Um}=n;if(typeof Zone>"u")throw new N(908,!1);Zone.assertZonePatched();const s=this;s._nesting=0,s._outer=s._inner=Zone.current,Zone.TaskTrackingZoneSpec&&(s._inner=s._inner.fork(new Zone.TaskTrackingZoneSpec)),t&&Zone.longStackTraceZoneSpec&&(s._inner=s._inner.fork(Zone.longStackTraceZoneSpec)),s.shouldCoalesceEventChangeDetection=!i&&r,s.shouldCoalesceRunChangeDetection=i,s.callbackScheduled=!1,s.scheduleInRootZone=o,function AT(e){const n=()=>{!function OT(e){function n(){Gm(()=>{e.callbackScheduled=!1,vd(e),e.isCheckStableRunning=!0,md(e),e.isCheckStableRunning=!1})}e.isCheckStableRunning||e.callbackScheduled||(e.callbackScheduled=!0,e.scheduleInRootZone?Zone.root.run(()=>{n()}):e._outer.run(()=>{n()}),vd(e))}(e)},t=NT++;e._inner=e._inner.fork({name:"angular",properties:{[pd]:!0,[el]:t,[el+t]:!0},onInvokeTask:(r,i,o,s,a,l)=>{if(function RT(e){return Qm(e,"__ignore_ng_zone__")}(l))return r.invokeTask(o,s,a,l);try{return Wm(e),r.invokeTask(o,s,a,l)}finally{(e.shouldCoalesceEventChangeDetection&&"eventTask"===s.type||e.shouldCoalesceRunChangeDetection)&&n(),Zm(e)}},onInvoke:(r,i,o,s,a,l,c)=>{try{return Wm(e),r.invoke(o,s,a,l,c)}finally{e.shouldCoalesceRunChangeDetection&&!e.callbackScheduled&&!function kT(e){return Qm(e,"__scheduler_tick__")}(l)&&n(),Zm(e)}},onHasTask:(r,i,o,s)=>{r.hasTask(o,s),i===o&&("microTask"==s.change?(e._hasPendingMicrotasks=s.microTask,vd(e),md(e)):"macroTask"==s.change&&(e.hasPendingMacrotasks=s.macroTask))},onHandleError:(r,i,o,s)=>(r.handleError(o,s),e.runOutsideAngular(()=>e.onError.emit(s)),!1)})}(s)}static isInAngularZone(){return typeof Zone<"u"&&!0===Zone.current.get(pd)}static assertInAngularZone(){if(!de.isInAngularZone())throw new N(909,!1)}static assertNotInAngularZone(){if(de.isInAngularZone())throw new N(909,!1)}run(n,t,r){return this._inner.run(n,t,r)}runTask(n,t,r,i){const o=this._inner,s=o.scheduleEventTask("NgZoneEvent: "+i,n,xT,Qo,Qo);try{return o.runTask(s,t,r)}finally{o.cancelTask(s)}}runGuarded(n,t,r){return this._inner.runGuarded(n,t,r)}runOutsideAngular(n){return this._outer.run(n)}}const xT={};function md(e){if(0==e._nesting&&!e.hasPendingMicrotasks&&!e.isStable)try{e._nesting++,e.onMicrotaskEmpty.emit(null)}finally{if(e._nesting--,!e.hasPendingMicrotasks)try{e.runOutsideAngular(()=>e.onStable.emit(null))}finally{e.isStable=!0}}}function vd(e){e.hasPendingMicrotasks=!!(e._hasPendingMicrotasks||(e.shouldCoalesceEventChangeDetection||e.shouldCoalesceRunChangeDetection)&&!0===e.callbackScheduled)}function Wm(e){e._nesting++,e.isStable&&(e.isStable=!1,e.onUnstable.emit(null))}function Zm(e){e._nesting--,md(e)}class _d{hasPendingMicrotasks=!1;hasPendingMacrotasks=!1;isStable=!0;onUnstable=new we;onMicrotaskEmpty=new we;onStable=new we;onError=new we;run(n,t,r){return n.apply(t,r)}runGuarded(n,t,r){return n.apply(t,r)}runOutsideAngular(n){return n()}runTask(n,t,r,i){return n.apply(t,r)}}function Qm(e,n){return!(!Array.isArray(e)||1!==e.length)&&!0===e[0]?.data?.[n]}class _n{_console=console;handleError(n){this._console.error("ERROR",n)}}const LT=new R("",{providedIn:"root",factory:()=>{const e=A(de),n=A(_n);return t=>e.runOutsideAngular(()=>n.handleError(t))}});function PT(){return Fi(ie(),D())}function Fi(e,n){return new pt(ft(e,n))}let pt=(()=>class e{nativeElement;constructor(t){this.nativeElement=t}static __NG_ELEMENT_ID__=PT})();function Km(e){return e instanceof pt?e.nativeElement:e}const Jm=new Set;function Xe(e){Jm.has(e)||(Jm.add(e),performance?.mark?.("mark_feature_usage",{detail:{feature:e}}))}function Gr(e,n){Xe("NgSignals");const t=function CM(e){const n=Object.create(cp);n.value=e;const t=()=>(Oo(n),n.value);return t[Ke]=n,t}(e),r=t[Ke];return n?.equal&&(r.equal=n.equal),t.set=i=>ou(r,i),t.update=i=>function lp(e,n){tp()||ap(),ou(e,n(e.value))}(r,i),t.asReadonly=tl.bind(t),t}function tl(){const e=this[Ke];if(void 0===e.readonlyFn){const n=()=>this();n[Ke]=e,e.readonlyFn=n}return e.readonlyFn}function ev(e){return function Xm(e){return"function"==typeof e&&void 0!==e[Ke]}(e)&&"function"==typeof e.set}function VT(){return this._results[Symbol.iterator]()}class HT{_emitDistinctChangesOnly;dirty=!0;_onDirty=void 0;_results=[];_changesDetected=!1;_changes=void 0;length=0;first=void 0;last=void 0;get changes(){return this._changes??=new fn}constructor(n=!1){this._emitDistinctChangesOnly=n}get(n){return this._results[n]}map(n){return this._results.map(n)}filter(n){return this._results.filter(n)}find(n){return this._results.find(n)}reduce(n,t){return this._results.reduce(n,t)}forEach(n){this._results.forEach(n)}some(n){return this._results.some(n)}toArray(){return this._results.slice()}toString(){return this._results.toString()}reset(n,t){this.dirty=!1;const r=function It(e){return e.flat(Number.POSITIVE_INFINITY)}(n);(this._changesDetected=!function u0(e,n,t){if(e.length!==n.length)return!1;for(let r=0;raS}),aS="ng",Ed=new R(""),Pi=new R("",{providedIn:"platform",factory:()=>"unknown"}),yv=new R("",{providedIn:"root",factory:()=>yn().body?.querySelector("[ngCspNonce]")?.getAttribute("ngCspNonce")||null}),bv=new R("",{providedIn:"root",factory:()=>!1});var Fd=function(e){return e[e.CHANGE_DETECTION=0]="CHANGE_DETECTION",e[e.AFTER_NEXT_RENDER=1]="AFTER_NEXT_RENDER",e}(Fd||{});const Hi=new R("");let Ld=(()=>{class e{impl=null;execute(){this.impl?.execute()}static \u0275prov=re({token:e,providedIn:"root",factory:()=>new e})}return e})();function Xv(e,n){const t=e.contentQueries;if(null!==t){const r=te(null);try{for(let i=0;ie,createScript:e=>e,createScriptURL:e=>e})}catch{}return yl}()?.createHTML(e)||e}function e_(e){return function Kd(){if(void 0===Cl&&(Cl=null,Ie.trustedTypes))try{Cl=Ie.trustedTypes.createPolicy("angular#unsafe-bypass",{createHTML:e=>e,createScript:e=>e,createScriptURL:e=>e})}catch{}return Cl}()?.createHTML(e)||e}class r_{changingThisBreaksApplicationSecurity;constructor(n){this.changingThisBreaksApplicationSecurity=n}toString(){return`SafeValue must use [property]=binding: ${this.changingThisBreaksApplicationSecurity} (see ${Cp})`}}function rr(e){return e instanceof r_?e.changingThisBreaksApplicationSecurity:e}function cs(e,n){const t=function eN(e){return e instanceof r_&&e.getTypeName()||null}(e);if(null!=t&&t!==n){if("ResourceURL"===t&&"URL"===n)return!0;throw new Error(`Required a safe ${n}, got a ${t} (see ${Cp})`)}return t===n}class tN{inertDocumentHelper;constructor(n){this.inertDocumentHelper=n}getInertBodyElement(n){n=""+n;try{const t=(new window.DOMParser).parseFromString(Zi(n),"text/html").body;return null===t?this.inertDocumentHelper.getInertBodyElement(n):(t.firstChild?.remove(),t)}catch{return null}}}class nN{defaultDoc;inertDocument;constructor(n){this.defaultDoc=n,this.inertDocument=this.defaultDoc.implementation.createHTMLDocument("sanitization-inert")}getInertBodyElement(n){const t=this.inertDocument.createElement("template");return t.innerHTML=Zi(n),t}}const iN=/^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:\/?#]*(?:[\/?#]|$))/i;function Jd(e){return(e=String(e)).match(iN)?e:"unsafe:"+e}function Hn(e){const n={};for(const t of e.split(","))n[t]=!0;return n}function us(...e){const n={};for(const t of e)for(const r in t)t.hasOwnProperty(r)&&(n[r]=!0);return n}const o_=Hn("area,br,col,hr,img,wbr"),s_=Hn("colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr"),a_=Hn("rp,rt"),Xd=us(o_,us(s_,Hn("address,article,aside,blockquote,caption,center,del,details,dialog,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5,h6,header,hgroup,hr,ins,main,map,menu,nav,ol,pre,section,summary,table,ul")),us(a_,Hn("a,abbr,acronym,audio,b,bdi,bdo,big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,picture,q,ruby,rp,rt,s,samp,small,source,span,strike,strong,sub,sup,time,track,tt,u,var,video")),us(a_,s_)),ef=Hn("background,cite,href,itemtype,longdesc,poster,src,xlink:href"),l_=us(ef,Hn("abbr,accesskey,align,alt,autoplay,axis,bgcolor,border,cellpadding,cellspacing,class,clear,color,cols,colspan,compact,controls,coords,datetime,default,dir,download,face,headers,height,hidden,hreflang,hspace,ismap,itemscope,itemprop,kind,label,lang,language,loop,media,muted,nohref,nowrap,open,preload,rel,rev,role,rows,rowspan,rules,scope,scrolling,shape,size,sizes,span,srclang,srcset,start,summary,tabindex,target,title,translate,type,usemap,valign,value,vspace,width"),Hn("aria-activedescendant,aria-atomic,aria-autocomplete,aria-busy,aria-checked,aria-colcount,aria-colindex,aria-colspan,aria-controls,aria-current,aria-describedby,aria-details,aria-disabled,aria-dropeffect,aria-errormessage,aria-expanded,aria-flowto,aria-grabbed,aria-haspopup,aria-hidden,aria-invalid,aria-keyshortcuts,aria-label,aria-labelledby,aria-level,aria-live,aria-modal,aria-multiline,aria-multiselectable,aria-orientation,aria-owns,aria-placeholder,aria-posinset,aria-pressed,aria-readonly,aria-relevant,aria-required,aria-roledescription,aria-rowcount,aria-rowindex,aria-rowspan,aria-selected,aria-setsize,aria-sort,aria-valuemax,aria-valuemin,aria-valuenow,aria-valuetext")),oN=Hn("script,style,template");class sN{sanitizedSomething=!1;buf=[];sanitizeChildren(n){let t=n.firstChild,r=!0,i=[];for(;t;)if(t.nodeType===Node.ELEMENT_NODE?r=this.startElement(t):t.nodeType===Node.TEXT_NODE?this.chars(t.nodeValue):this.sanitizedSomething=!0,r&&t.firstChild)i.push(t),t=cN(t);else for(;t;){t.nodeType===Node.ELEMENT_NODE&&this.endElement(t);let o=lN(t);if(o){t=o;break}t=i.pop()}return this.buf.join("")}startElement(n){const t=c_(n).toLowerCase();if(!Xd.hasOwnProperty(t))return this.sanitizedSomething=!0,!oN.hasOwnProperty(t);this.buf.push("<"),this.buf.push(t);const r=n.attributes;for(let i=0;i"),!0}endElement(n){const t=c_(n).toLowerCase();Xd.hasOwnProperty(t)&&!o_.hasOwnProperty(t)&&(this.buf.push(""))}chars(n){this.buf.push(d_(n))}}function lN(e){const n=e.nextSibling;if(n&&e!==n.previousSibling)throw u_(n);return n}function cN(e){const n=e.firstChild;if(n&&function aN(e,n){return(e.compareDocumentPosition(n)&Node.DOCUMENT_POSITION_CONTAINED_BY)!==Node.DOCUMENT_POSITION_CONTAINED_BY}(e,n))throw u_(n);return n}function c_(e){const n=e.nodeName;return"string"==typeof n?n:"FORM"}function u_(e){return new Error(`Failed to sanitize html because the element is clobbered: ${e.outerHTML}`)}const uN=/[\uD800-\uDBFF][\uDC00-\uDFFF]/g,dN=/([^\#-~ |!])/g;function d_(e){return e.replace(/&/g,"&").replace(uN,function(n){return"&#"+(1024*(n.charCodeAt(0)-55296)+(n.charCodeAt(1)-56320)+65536)+";"}).replace(dN,function(n){return"&#"+n.charCodeAt(0)+";"}).replace(//g,">")}let wl;function tf(e){return"content"in e&&function hN(e){return e.nodeType===Node.ELEMENT_NODE&&"TEMPLATE"===e.nodeName}(e)?e.content:null}var Qi=function(e){return e[e.NONE=0]="NONE",e[e.HTML=1]="HTML",e[e.STYLE=2]="STYLE",e[e.SCRIPT=3]="SCRIPT",e[e.URL=4]="URL",e[e.RESOURCE_URL=5]="RESOURCE_URL",e}(Qi||{});function f_(e){const n=ds();return n?e_(n.sanitize(Qi.HTML,e)||""):cs(e,"HTML")?e_(rr(e)):function fN(e,n){let t=null;try{wl=wl||function i_(e){const n=new nN(e);return function rN(){try{return!!(new window.DOMParser).parseFromString(Zi(""),"text/html")}catch{return!1}}()?new tN(n):n}(e);let r=n?String(n):"";t=wl.getInertBodyElement(r);let i=5,o=r;do{if(0===i)throw new Error("Failed to sanitize html because the input is unstable");i--,r=o,o=t.innerHTML,t=wl.getInertBodyElement(r)}while(r!==o);return Zi((new sN).sanitizeChildren(tf(t)||t))}finally{if(t){const r=tf(t)||t;for(;r.firstChild;)r.firstChild.remove()}}}(yn(),K(e))}function ir(e){const n=ds();return n?n.sanitize(Qi.URL,e)||"":cs(e,"URL")?rr(e):Jd(K(e))}function ds(){const e=D();return e&&e[10].sanitizer}const CN=/^>|^->||--!>|)/g;function El(e){return e.ownerDocument.defaultView}var or=function(e){return e[e.None=0]="None",e[e.SignalBased=1]="SignalBased",e[e.HasDecoratorInputTransform=2]="HasDecoratorInputTransform",e}(or||{});function AN(e,n,t){let r=e.length;for(;;){const i=e.indexOf(n,t);if(-1===i)return i;if(0===i||e.charCodeAt(i-1)<=32){const o=n.length;if(i+o===r||e.charCodeAt(i+o)<=32)return i}t=i+1}}const D_="ng-template";function RN(e,n,t,r){let i=0;if(r){for(;i-1){let o;for(;++io?"":i[u+1].toLowerCase(),2&r&&c!==d){if(rn(r))return!1;s=!0}}}}else{if(!s&&!rn(r)&&!rn(l))return!1;if(s&&rn(l))continue;s=!1,r=l|1&r}}return rn(r)||s}function rn(e){return!(1&e)}function LN(e,n,t,r){if(null===n)return-1;let i=0;if(r||!t){let o=!1;for(;i-1)for(t++;t0?'="'+a+'"':"")+"]"}else 8&r?i+="."+s:4&r&&(i+=" "+s);else""!==i&&!rn(s)&&(n+=E_(o,i),i=""),r=s,o=o||!rn(r);t++}return""!==i&&(n+=E_(o,i)),n}const J={};function af(e,n){return e.createComment(function g_(e){return e.replace(CN,n=>n.replace(wN,"\u200b$1\u200b"))}(n))}function Il(e,n,t){return e.createElement(n,t)}function Qr(e,n,t,r,i){e.insertBefore(n,t,r,i)}function M_(e,n,t){e.appendChild(n,t)}function T_(e,n,t,r,i){null!==r?Qr(e,n,t,r,i):M_(e,n,t)}function N_(e,n,t){const{mergedAttrs:r,classes:i,styles:o}=t;null!==r&&function lT(e,n,t){let r=0;for(;rk&&x_(e,n,k,!1),t(r,i)}finally{Ur(o)}}function lf(e,n,t){sm()&&(vt(ft(t,n),n),R_(e,n,t))}function R_(e,n,t){(function ix(e,n,t){const r=t.directiveStart,i=t.directiveEnd;$t(t)&&function hx(e,n,t){const r=ft(n,e),i=function k_(e){const n=e.tView;return null===n||n.incompleteFirstPass?e.tView=uf(1,null,e.template,e.decls,e.vars,e.directiveDefs,e.pipeDefs,e.viewQuery,e.schemas,e.consts,e.id):n}(t),o=e[10].rendererFactory,s=hf(e,Ml(e,i,null,function B_(e){let n=16;return e.signals?n=4096:e.onPush&&(n=64),n}(t),r,n,null,o.createRenderer(r,t),null,null,null));e[n.index]=s}(n,t,e.data[r+t.componentOffset]),e.firstCreatePass||Qa(t,n);const o=t.initialInputs;for(let s=r;snull;function L_(e,n,t,r,i){for(let o in n){if(!n.hasOwnProperty(o))continue;const s=n[o];if(void 0===s)continue;r??={};let a,l=or.None;Array.isArray(s)?(a=s[0],l=s[1]):a=s;let c=o;if(null!==i){if(!i.hasOwnProperty(o))continue;c=i[o]}0===e?P_(r,t,c,a,l):P_(r,t,c,a)}return r}function P_(e,n,t,r,i){let o;e.hasOwnProperty(t)?(o=e[t]).push(n,r):o=e[t]=[n,r],void 0!==i&&o.push(i)}function St(e,n,t,r,i,o,s,a){const l=ft(n,t);let u,c=n.inputs;!a&&null!=c&&(u=c[r])?(gf(e,t,u,r,i),$t(n)&&function ex(e,n){const t=ht(n,e);16&t[2]||(t[2]|=64)}(t,n.index)):3&n.type&&(r=function XN(e){return"class"===e?"className":"for"===e?"htmlFor":"formaction"===e?"formAction":"innerHtml"===e?"innerHTML":"readonly"===e?"readOnly":"tabindex"===e?"tabIndex":e}(r),i=null!=s?s(i,n.value||"",r):i,o.setProperty(l,r,i))}function df(e,n,t,r){if(sm()){const i=null===r?null:{"":-1},o=function ax(e,n){const t=e.directiveRegistry;let r=null;if(t)for(let i=0;i0;){const t=e[--n];if("number"==typeof t&&t<0)return t}return 0})(s)!=a&&s.push(a),s.push(t,r,o)}}(e,n,r,hs(e,t,i.hostVars,J),i)}function Cn(e,n,t,r,i,o){const s=ft(e,n);!function ff(e,n,t,r,i,o,s){if(null==o)e.removeAttribute(n,i,t);else{const a=null==s?K(o):s(o,r||"",i);e.setAttribute(n,i,a,t)}}(n[G],s,o,e.value,t,r,i)}function gx(e,n,t,r,i,o){const s=o[n];if(null!==s)for(let a=0;a0&&(e[t-1][4]=r[4]);const o=Sa(e,10+n);!function $_(e,n){z_(e,n),n[0]=null,n[5]=null}(r[1],r);const s=o[18];null!==s&&s.detachView(o[1]),r[3]=null,r[4]=null,r[2]&=-129}return r}function ps(e,n){if(Yn(n))return;const t=n[G];t.destroyNode&&xl(e,n,t,3,null,null),function wx(e){let n=e[12];if(!n)return _f(e[1],e);for(;n;){let t=null;if(Ne(n))t=n[12];else{const r=n[10];r&&(t=r)}if(!t){for(;n&&!n[4]&&n!==e;)Ne(n)&&_f(n[1],n),n=n[3];null===n&&(n=e),Ne(n)&&_f(n[1],n),t=n&&n[4]}n=t}}(n)}function _f(e,n){if(Yn(n))return;const t=te(null);try{n[2]&=-129,n[2]|=256,n[24]&&ko(n[24]),function Ex(e,n){let t;if(null!=e&&null!=(t=e.destroyHooks))for(let r=0;r=0?r[a]():r[-a].unsubscribe(),s+=2}else t[s].call(r[t[s+1]]);null!==r&&(n[7]=null);const i=n[21];if(null!==i){n[21]=null;for(let s=0;s{jo(e.lView)},consumerOnSignalRead(){this.lView[24]=this}},Rx={...Er,consumerIsAlwaysLive:!0,kind:"template",consumerMarkedDirty:e=>{let n=Fn(e.lView);for(;n&&!ty(n[1]);)n=Fn(n);n&&qu(n)},consumerOnSignalRead(){this.lView[24]=this}};function ty(e){return 2!==e.type}function ny(e){if(null===e[23])return;let n=!0;for(;n;){let t=!1;for(const r of e[23])r.dirty&&(t=!0,null===r.zone||Zone.current===r.zone?r.run():r.zone.run(()=>r.run()));n=t&&!!(8192&e[2])}}function Ol(e,n=!0,t=0){const i=e[10].rendererFactory;i.begin?.();try{!function Fx(e,n){const t=um();try{$a(!0),If(e,n);let r=0;for(;Ba(e);){if(100===r)throw new N(103,!1);r++,If(e,1)}}finally{$a(t)}}(e,t)}catch(s){throw n&&Tl(e,s),s}finally{i.end?.()}}function iy(e,n,t,r){if(Yn(n))return;const i=n[2];nd(n);let a=!0,l=null,c=null;ty(e)?(c=function Sx(e){return e[24]??function Nx(e){const n=ey.pop()??Object.create(Ox);return n.lView=e,n}(e)}(n),l=Ir(c)):null===function iu(){return Le}()?(a=!1,c=function Ax(e){const n=e[24]??Object.create(Rx);return n.lView=e,n}(n),l=Ir(c)):n[24]&&(ko(n[24]),n[24]=null);try{nm(n),function dm(e){return Q.lFrame.bindingIndex=e}(e.bindingStartIndex),null!==t&&A_(e,n,t,2,r);const u=!(3&~i);if(u){const h=e.preOrderCheckHooks;null!==h&&qa(n,h,null)}else{const h=e.preOrderHooks;null!==h&&Wa(n,h,0,null),id(n,0)}if(function Lx(e){for(let n=cv(e);null!==n;n=uv(n)){if(!(2&n[2]))continue;const t=n[9];for(let r=0;r-1&&(gs(n,r),Sa(t,r))}this._attachedToViewContainer=!1}ps(this._lView[1],this._lView)}onDestroy(n){ja(this._lView,n)}markForCheck(){ms(this._cdRefInjectingView||this._lView,4)}markForRefresh(){qu(this._cdRefInjectingView||this._lView)}detach(){this._lView[2]&=-129}reattach(){Wu(this._lView),this._lView[2]|=128}detectChanges(){this._lView[2]|=1024,Ol(this._lView,this.notifyErrorHandler)}checkNoChanges(){}attachToViewContainerRef(){if(this._appRef)throw new N(902,!1);this._attachedToViewContainer=!0}detachFromAppRef(){this._appRef=null;const n=Rn(this._lView),t=this._lView[16];null!==t&&!n&&vf(t,this._lView),z_(this._lView[1],this._lView)}attachToAppRef(n){if(this._attachedToViewContainer)throw new N(902,!1);this._appRef=n;const t=Rn(this._lView),r=this._lView[16];null!==r&&!t&&G_(r,this._lView),Wu(this._lView)}}let Bn=(()=>class e{static __NG_ELEMENT_ID__=jx})();const Hx=Bn,Bx=class extends Hx{_declarationLView;_declarationTContainer;elementRef;constructor(n,t,r){super(),this._declarationLView=n,this._declarationTContainer=t,this.elementRef=r}get ssrId(){return this._declarationTContainer.tView?.ssrId||null}createEmbeddedView(n,t){return this.createEmbeddedViewImpl(n,t)}createEmbeddedViewImpl(n,t,r){const i=function Ji(e,n,t,r){const i=te(null);try{const o=n.tView,l=Ml(e,o,t,4096&e[2]?4096:16,null,n,null,null,r?.injector??null,r?.embeddedViewInjector??null,r?.dehydratedView??null);l[16]=e[n.index];const u=e[18];return null!==u&&(l[18]=u.createEmbeddedView(o)),Sl(o,l,t),l}finally{te(i)}}(this._declarationLView,this._declarationTContainer,n,{embeddedViewInjector:t,dehydratedView:r});return new vs(i)}};function jx(){return Al(ie(),D())}function Al(e,n){return 4&e.type?new Bx(n,e,Fi(e,n)):null}function Jr(e,n,t,r,i){let o=e.data[n];if(null===o)o=function Nf(e,n,t,r,i){const o=am(),s=Ku(),l=e.data[n]=function Kx(e,n,t,r,i,o){let s=n?n.injectorIndex:-1,a=0;return function jr(){return null!==Q.skipHydrationRootTNode}()&&(a|=128),{type:t,index:r,insertBeforeIndex:null,injectorIndex:s,directiveStart:-1,directiveEnd:-1,directiveStylingLast:-1,componentOffset:-1,propertyBindings:null,flags:a,providerIndexes:0,value:i,attrs:o,mergedAttrs:null,localNames:null,initialInputs:void 0,inputs:null,outputs:null,tView:null,next:null,prev:null,projectionNext:null,child:null,parent:n,projection:null,styles:null,stylesWithoutHost:null,residualStyles:void 0,classes:null,classesWithoutHost:null,residualClasses:void 0,classBindings:0,styleBindings:0}}(0,s?o:o&&o.parent,t,n,r,i);return function Yx(e,n,t,r){null===e.firstChild&&(e.firstChild=n),null!==t&&(r?null==t.child&&null!==n.parent&&(t.child=n):null===t.next&&(t.next=n,n.prev=t))}(e,l,o,s),l}(e,n,t,r,i),function Z0(){return Q.lFrame.inI18n}()&&(o.flags|=32);else if(64&o.type){o.type=t,o.value=r,o.attrs=i;const s=function Uo(){const e=Q.lFrame,n=e.currentTNode;return e.isParent?n:n.parent}();o.injectorIndex=null===s?-1:s.injectorIndex}return nn(o,!0),o}class P1{}class Ny{}class V1{resolveComponentFactory(n){throw Error(`No component factory found for ${$e(n)}.`)}}class Vl{static NULL=new V1}class Vf{}let on=(()=>class e{destroyNode=null;static __NG_ELEMENT_ID__=()=>function H1(){const e=D(),t=ht(ie().index,e);return(Ne(t)?t:e)[G]}()})(),B1=(()=>{class e{static \u0275prov=re({token:e,providedIn:"root",factory:()=>null})}return e})();function Bl(e,n,t){let r=t?e.styles:null,i=t?e.classes:null,o=0;if(null!==n)for(let s=0;sclass e{static __NG_ELEMENT_ID__=q1})();function q1(){return Ly(ie(),D())}const W1=wn,ky=class extends W1{_lContainer;_hostTNode;_hostLView;constructor(n,t,r){super(),this._lContainer=n,this._hostTNode=t,this._hostLView=r}get element(){return Fi(this._hostTNode,this._hostLView)}get injector(){return new Ae(this._hostTNode,this._hostLView)}get parentInjector(){const n=Ya(this._hostTNode,this._hostLView);if(ld(n)){const t=qo(n,this._hostLView),r=Go(n);return new Ae(t[1].data[r+8],t)}return new Ae(null,this._hostLView)}clear(){for(;this.length>0;)this.remove(this.length-1)}get(n){const t=Fy(this._lContainer);return null!==t&&t[n]||null}get length(){return this._lContainer.length-10}createEmbeddedView(n,t,r){let i,o;"number"==typeof r?i=r:null!=r&&(i=r.index,o=r.injector);const a=n.createEmbeddedViewImpl(t||{},o,null);return this.insertImpl(a,i,Kr(this._hostTNode,null)),a}createComponent(n,t,r,i,o){const s=n&&!function Bo(e){return"function"==typeof e}(n);let a;if(s)a=t;else{const m=t||{};a=m.index,r=m.injector,i=m.projectableNodes,o=m.environmentInjector||m.ngModuleRef}const l=s?n:new Ts(ne(n)),c=r||this.parentInjector;if(!o&&null==l.ngModule){const C=(s?c:this.parentInjector).get(tn,null);C&&(o=C)}ne(l.componentType??{});const h=l.create(c,i,null,o);return this.insertImpl(h.hostView,a,Kr(this._hostTNode,null)),h}insert(n,t){return this.insertImpl(n,t,!0)}insertImpl(n,t,r){const i=n._lView;if(function V0(e){return qe(e[3])}(i)){const a=this.indexOf(n);if(-1!==a)this.detach(a);else{const l=i[3],c=new ky(l,l[5],l[3]);c.detach(c.indexOf(n))}}const o=this._adjustIndex(t),s=this._lContainer;return function Xi(e,n,t,r=!0){const i=n[1];if(function Dx(e,n,t,r){const i=10+r,o=t.length;r>0&&(t[i-1][4]=n),rn.trim())}(n):n}}class Gf{queries;constructor(n=[]){this.queries=n}elementStart(n,t){for(let r=0;r0)r.push(s[a/2]);else{const c=o[a+1],u=n[-l];for(let d=10;dt()),this.destroyCbs=null}onDestroy(n){this.destroyCbs.push(n)}}class Jf extends hO{moduleType;constructor(n){super(),this.moduleType=n}create(n){return new Kf(this.moduleType,n,[])}}class rC extends ti{injector;componentFactoryResolver=new Ay(this);instance=null;constructor(n){super();const t=new Fr([...n.providers,{provide:ti,useValue:this},{provide:Vl,useValue:this.componentFactoryResolver}],n.parent||Ra(),n.debugName,new Set(["environment"]));this.injector=t,n.runEnvironmentInitializers&&t.resolveInjectorInitializers()}destroy(){this.injector.destroy()}onDestroy(n){this.injector.onDestroy(n)}}let mO=(()=>{class e{_injector;cachedInjectors=new Map;constructor(t){this._injector=t}getOrCreateStandaloneInjector(t){if(!t.standalone)return null;if(!this.cachedInjectors.has(t)){const r=Ru(0,t.type),i=r.length>0?function iC(e,n,t=null){return new rC({providers:e,parent:n,debugName:t,runEnvironmentInitializers:!0}).injector}([r],this._injector,`Standalone[${t.type.name}]`):null;this.cachedInjectors.set(t,i)}return this.cachedInjectors.get(t)}ngOnDestroy(){try{for(const t of this.cachedInjectors.values())null!==t&&t.destroy()}finally{this.cachedInjectors.clear()}}static \u0275prov=re({token:e,providedIn:"environment",factory:()=>new e(se(tn))})}return e})();function sn(e){return Sn(()=>{const n=sC(e),t={...n,decls:e.decls,vars:e.vars,template:e.template,consts:e.consts||null,ngContentSelectors:e.ngContentSelectors,onPush:e.changeDetection===nl.OnPush,directiveDefs:null,pipeDefs:null,dependencies:n.standalone&&e.dependencies||null,getStandaloneInjector:n.standalone?i=>i.get(mO).getOrCreateStandaloneInjector(t):null,getExternalStyles:null,signals:e.signals??!1,data:e.data||{},encapsulation:e.encapsulation||Zt.Emulated,styles:e.styles||le,_:null,schemas:e.schemas||null,tView:null,id:""};n.standalone&&Xe("NgStandalone"),aC(t);const r=e.dependencies;return t.directiveDefs=Ul(r,!1),t.pipeDefs=Ul(r,!0),t.id=function CO(e){let n=0;const r=[e.selectors,e.ngContentSelectors,e.hostVars,e.hostAttrs,"function"==typeof e.consts?"":e.consts,e.vars,e.decls,e.encapsulation,e.standalone,e.signals,e.exportAs,JSON.stringify(e.inputs),JSON.stringify(e.outputs),Object.getOwnPropertyNames(e.type.prototype),!!e.contentQueries,!!e.viewQuery];for(const o of r.join("|"))n=Math.imul(31,n)+o.charCodeAt(0)|0;return n+=2147483648,"c"+n}(t),t})}function vO(e){return ne(e)||ze(e)}function _O(e){return null!==e}function cr(e){return Sn(()=>({type:e.type,bootstrap:e.bootstrap||le,declarations:e.declarations||le,imports:e.imports||le,exports:e.exports||le,transitiveCompileScopes:null,schemas:e.schemas||null,id:e.id||null}))}function oC(e,n){if(null==e)return hn;const t={};for(const r in e)if(e.hasOwnProperty(r)){const i=e[r];let o,s,a=or.None;Array.isArray(i)?(a=i[0],o=i[1],s=i[2]??o):(o=i,s=i),n?(t[o]=a!==or.None?[r,a]:r,n[o]=s):t[o]=r}return t}function Y(e){return Sn(()=>{const n=sC(e);return aC(n),n})}function Nt(e){return{type:e.type,name:e.name,factory:null,pure:!1!==e.pure,standalone:e.standalone??!0,onDestroy:e.type.prototype.ngOnDestroy||null}}function sC(e){const n={};return{type:e.type,providersResolver:null,factory:null,hostBindings:e.hostBindings||null,hostVars:e.hostVars||0,hostAttrs:e.hostAttrs||null,contentQueries:e.contentQueries||null,declaredInputs:n,inputTransforms:null,inputConfig:e.inputs||hn,exportAs:e.exportAs||null,standalone:e.standalone??!0,signals:!0===e.signals,selectors:e.selectors||le,viewQuery:e.viewQuery||null,features:e.features||null,setInput:null,findHostDirectiveDefs:null,hostDirectives:null,inputs:oC(e.inputs,n),outputs:oC(e.outputs),debugInfo:null}}function aC(e){e.features?.forEach(n=>n(e))}function Ul(e,n){if(!e)return null;const t=n?nt:vO;return()=>("function"==typeof e?e():e).map(r=>t(r)).filter(_O)}function ue(e){let n=function lC(e){return Object.getPrototypeOf(e.prototype).constructor}(e.type),t=!0;const r=[e];for(;n;){let i;if(zt(e))i=n.\u0275cmp||n.\u0275dir;else{if(n.\u0275cmp)throw new N(903,!1);i=n.\u0275dir}if(i){if(t){r.push(i);const s=e;s.inputs=$l(e.inputs),s.inputTransforms=$l(e.inputTransforms),s.declaredInputs=$l(e.declaredInputs),s.outputs=$l(e.outputs);const a=i.hostBindings;a&&IO(e,a);const l=i.viewQuery,c=i.contentQueries;if(l&&bO(e,l),c&&EO(e,c),wO(e,i),jM(e.outputs,i.outputs),zt(i)&&i.data.animation){const u=e.data;u.animation=(u.animation||[]).concat(i.data.animation)}}const o=i.features;if(o)for(let s=0;s=0;r--){const i=e[r];i.hostVars=n+=i.hostVars,i.hostAttrs=ki(i.hostAttrs,t=ki(t,i.hostAttrs))}}(r)}function wO(e,n){for(const t in n.inputs){if(!n.inputs.hasOwnProperty(t)||e.inputs.hasOwnProperty(t))continue;const r=n.inputs[t];if(void 0!==r&&(e.inputs[t]=r,e.declaredInputs[t]=n.declaredInputs[t],null!==n.inputTransforms)){const i=Array.isArray(r)?r[0]:r;if(!n.inputTransforms.hasOwnProperty(i))continue;e.inputTransforms??={},e.inputTransforms[i]=n.inputTransforms[i]}}}function $l(e){return e===hn?{}:e===le?[]:e}function bO(e,n){const t=e.viewQuery;e.viewQuery=t?(r,i)=>{n(r,i),t(r,i)}:n}function EO(e,n){const t=e.contentQueries;e.contentQueries=t?(r,i,o)=>{n(r,i,o),t(r,i,o)}:n}function IO(e,n){const t=e.hostBindings;e.hostBindings=t?(r,i)=>{n(r,i),t(r,i)}:n}function zl(e){return!!eh(e)&&(Array.isArray(e)||!(e instanceof Map)&&Symbol.iterator in e)}function eh(e){return null!==e&&("function"==typeof e||"object"==typeof e)}function Dn(e,n,t){return e[n]=t}function Re(e,n,t){return!Object.is(e[n],t)&&(e[n]=t,!0)}function ni(e,n,t,r){const i=Re(e,n,t);return Re(e,n+1,r)||i}function V(e,n,t,r,i,o,s,a){const l=D(),c=Z();return function xs(e,n,t,r,i,o,s,a,l,c){const u=t+k,d=n.firstCreatePass?function FO(e,n,t,r,i,o,s,a,l){const c=n.consts,u=Jr(n,e,4,s||null,a||null);df(n,t,u,qt(c,l)),Ga(n,u);const d=u.tView=uf(2,u,r,i,o,n.directiveRegistry,n.pipeRegistry,null,n.schemas,c,null);return null!==n.queries&&(n.queries.template(n,u),d.queries=n.queries.embeddedTView(u)),u}(u,n,e,r,i,o,s,a,l):n.data[u];nn(d,!1);const g=hC(n,e,d,t);$o()&&Nl(n,e,g,d),vt(g,e);const h=j_(g,e,g,d);return e[u]=h,hf(e,h),Va(d)&&lf(n,e,d),null!=l&&cf(e,d,c),d}(l,c,e,n,t,r,i,qt(c.consts,o),s,a),V}let hC=function gC(e,n,t,r){return mn(!0),n[G].createComment("")};const TC=new R(""),Ql=new R("");let lh,sh=(()=>{class e{_ngZone;registry;_isZoneStable=!0;_callbacks=[];taskTrackingZone=null;constructor(t,r,i){this._ngZone=t,this.registry=r,lh||(function kA(e){lh=e}(i),i.addToWindow(r)),this._watchAngularEvents(),t.run(()=>{this.taskTrackingZone=typeof Zone>"u"?null:Zone.current.get("TaskTrackingZone")})}_watchAngularEvents(){this._ngZone.onUnstable.subscribe({next:()=>{this._isZoneStable=!1}}),this._ngZone.runOutsideAngular(()=>{this._ngZone.onStable.subscribe({next:()=>{de.assertNotInAngularZone(),queueMicrotask(()=>{this._isZoneStable=!0,this._runCallbacksIfReady()})}})})}isStable(){return this._isZoneStable&&!this._ngZone.hasPendingMacrotasks}_runCallbacksIfReady(){if(this.isStable())queueMicrotask(()=>{for(;0!==this._callbacks.length;){let t=this._callbacks.pop();clearTimeout(t.timeoutId),t.doneCb()}});else{let t=this.getPendingTasks();this._callbacks=this._callbacks.filter(r=>!r.updateCb||!r.updateCb(t)||(clearTimeout(r.timeoutId),!1))}}getPendingTasks(){return this.taskTrackingZone?this.taskTrackingZone.macroTasks.map(t=>({source:t.source,creationLocation:t.creationLocation,data:t.data})):[]}addCallback(t,r,i){let o=-1;r&&r>0&&(o=setTimeout(()=>{this._callbacks=this._callbacks.filter(s=>s.timeoutId!==o),t()},r)),this._callbacks.push({doneCb:t,timeoutId:o,updateCb:i})}whenStable(t,r,i){if(i&&!this.taskTrackingZone)throw new Error('Task tracking zone is required when passing an update callback to whenStable(). Is "zone.js/plugins/task-tracking" loaded?');this.addCallback(t,r,i),this._runCallbacksIfReady()}registerApplication(t){this.registry.registerApplication(t,this)}unregisterApplication(t){this.registry.unregisterApplication(t)}findProviders(t,r,i){return[]}static \u0275fac=function(r){return new(r||e)(se(de),se(ah),se(Ql))};static \u0275prov=re({token:e,factory:e.\u0275fac})}return e})(),ah=(()=>{class e{_applications=new Map;registerApplication(t,r){this._applications.set(t,r)}unregisterApplication(t){this._applications.delete(t)}unregisterAllApplications(){this._applications.clear()}getTestability(t){return this._applications.get(t)||null}getAllTestabilities(){return Array.from(this._applications.values())}getAllRootElements(){return Array.from(this._applications.keys())}findTestabilityInTree(t,r=!0){return lh?.findTestabilityInTree(this,t,r)??null}static \u0275fac=function(r){return new(r||e)};static \u0275prov=re({token:e,factory:e.\u0275fac,providedIn:"platform"})}return e})();function Yl(e){return!!e&&"function"==typeof e.then}function SC(e){return!!e&&"function"==typeof e.subscribe}const NC=new R("");let xC=(()=>{class e{resolve;reject;initialized=!1;done=!1;donePromise=new Promise((t,r)=>{this.resolve=t,this.reject=r});appInits=A(NC,{optional:!0})??[];injector=A(We);constructor(){}runInitializers(){if(this.initialized)return;const t=[];for(const i of this.appInits){const o=jp(this.injector,i);if(Yl(o))t.push(o);else if(SC(o)){const s=new Promise((a,l)=>{o.subscribe({complete:a,error:l})});t.push(s)}}const r=()=>{this.done=!0,this.resolve()};Promise.all(t).then(()=>{r()}).catch(i=>{this.reject(i)}),0===t.length&&r(),this.initialized=!0}static \u0275fac=function(r){return new(r||e)};static \u0275prov=re({token:e,factory:e.\u0275fac,providedIn:"root"})}return e})(),ch=(()=>{class e{static \u0275prov=re({token:e,providedIn:"root",factory:()=>new OC})}return e})();class OC{queuedEffectCount=0;queues=new Map;schedule(n){this.enqueue(n)}remove(n){const r=this.queues.get(n.zone);r.has(n)&&(r.delete(n),this.queuedEffectCount--)}enqueue(n){const t=n.zone;this.queues.has(t)||this.queues.set(t,new Set);const r=this.queues.get(t);r.has(n)||(this.queuedEffectCount++,r.add(n))}flush(){for(;this.queuedEffectCount>0;)for(const[n,t]of this.queues)null===n?this.flushQueue(t):n.run(()=>this.flushQueue(t))}flushQueue(n){for(const t of n)n.delete(t),this.queuedEffectCount--,t.run()}}const Kl=new R("");function RC(e,n){return Array.isArray(n)?n.reduce(RC,e):{...e,...n}}let Yt=(()=>{class e{_runningTick=!1;_destroyed=!1;_destroyListeners=[];_views=[];internalErrorHandler=A(LT);afterRenderManager=A(Ld);zonelessEnabled=A(Zo);rootEffectScheduler=A(ch);dirtyFlags=0;deferredDirtyFlags=0;tracingSnapshot=null;externalTestViews=new Set;afterTick=new fn;get allViews(){return[...this.externalTestViews.keys(),...this._views]}get destroyed(){return this._destroyed}componentTypes=[];components=[];isStable=A(Xn).hasPendingTasks.pipe(pu(t=>!t));constructor(){A(Hi,{optional:!0})}whenStable(){let t;return new Promise(r=>{t=this.isStable.subscribe({next:i=>{i&&r()}})}).finally(()=>{t.unsubscribe()})}_injector=A(tn);_rendererFactory=null;get injector(){return this._injector}bootstrap(t,r){const i=t instanceof Ny;if(!this._injector.get(xC).done)throw!i&&function Ar(e){const n=ne(e)||ze(e)||nt(e);return null!==n&&n.standalone}(t),new N(405,!1);let s;s=i?t:this._injector.get(Vl).resolveComponentFactory(t),this.componentTypes.push(s.componentType);const a=function FA(e){return e.isBoundToModule}(s)?void 0:this._injector.get(ti),c=s.create(We.NULL,[],r||s.selector,a),u=c.location.nativeElement,d=c.injector.get(TC,null);return d?.registerApplication(u),c.onDestroy(()=>{this.detachView(c.hostView),Jl(this.components,c),d?.unregisterApplication(u)}),this._loadComponent(c),c}tick(){this.zonelessEnabled||(this.dirtyFlags|=1),this._tick()}_tick=()=>{if(null!==this.tracingSnapshot){const r=this.tracingSnapshot;return this.tracingSnapshot=null,r.run(Fd.CHANGE_DETECTION,this._tick),void r.dispose()}if(this._runningTick)throw new N(101,!1);const t=te(null);try{this._runningTick=!0,this.synchronize()}catch(r){this.internalErrorHandler(r)}finally{this._runningTick=!1,te(t),this.afterTick.next()}};synchronize(){null===this._rendererFactory&&!this._injector.destroyed&&(this._rendererFactory=this._injector.get(Vf,null,{optional:!0})),this.dirtyFlags|=this.deferredDirtyFlags,this.deferredDirtyFlags=0;let t=0;for(;0!==this.dirtyFlags&&t++<10;)this.synchronizeOnce()}synchronizeOnce(){if(this.dirtyFlags|=this.deferredDirtyFlags,this.deferredDirtyFlags=0,16&this.dirtyFlags&&(this.dirtyFlags&=-17,this.rootEffectScheduler.flush()),7&this.dirtyFlags){const t=!!(1&this.dirtyFlags);this.dirtyFlags&=-8,this.dirtyFlags|=8;for(let{_lView:r,notifyErrorHandler:i}of this.allViews)VA(r,i,t,this.zonelessEnabled);if(this.dirtyFlags&=-5,this.syncDirtyFlagsWithViews(),23&this.dirtyFlags)return}else this._rendererFactory?.begin?.(),this._rendererFactory?.end?.();8&this.dirtyFlags&&(this.dirtyFlags&=-9,this.afterRenderManager.execute()),this.syncDirtyFlagsWithViews()}syncDirtyFlagsWithViews(){this.allViews.some(({_lView:t})=>Ba(t))?this.dirtyFlags|=2:this.dirtyFlags&=-8}attachView(t){const r=t;this._views.push(r),r.attachToAppRef(this)}detachView(t){const r=t;Jl(this._views,r),r.detachFromAppRef()}_loadComponent(t){this.attachView(t.hostView),this.tick(),this.components.push(t),this._injector.get(Kl,[]).forEach(i=>i(t))}ngOnDestroy(){if(!this._destroyed)try{this._destroyListeners.forEach(t=>t()),this._views.slice().forEach(t=>t.destroy())}finally{this._destroyed=!0,this._views=[],this._destroyListeners=[]}}onDestroy(t){return this._destroyListeners.push(t),()=>Jl(this._destroyListeners,t)}destroy(){if(this._destroyed)throw new N(406,!1);const t=this._injector;t.destroy&&!t.destroyed&&t.destroy()}get viewCount(){return this._views.length}static \u0275fac=function(r){return new(r||e)};static \u0275prov=re({token:e,factory:e.\u0275fac,providedIn:"root"})}return e})();function Jl(e,n){const t=e.indexOf(n);t>-1&&e.splice(t,1)}function VA(e,n,t,r){(t||Ba(e))&&Ol(e,n,t&&!r?0:1)}function _t(e,n,t,r){const i=D();return Re(i,Wt(),n)&&(Z(),Cn(me(),i,e,n,t,r)),_t}function ao(e,n,t,r){return Re(e,Wt(),t)?n+K(t)+r:J}function Xl(e,n){return e<<17|n<<2}function hr(e){return e>>17&32767}function hh(e){return 2|e}function ii(e){return(131068&e)>>2}function gh(e,n){return-131069&e|n<<2}function ph(e){return 1|e}function ZC(e,n,t,r){const i=e[t+1],o=null===n;let s=r?hr(i):ii(i),a=!1;for(;0!==s&&(!1===a||o);){const c=e[s+1];DR(e[s],n)&&(a=!0,e[s+1]=r?ph(c):hh(c)),s=r?hr(c):ii(c)}a&&(e[t+1]=r?hh(i):ph(i))}function DR(e,n){return null===e||null==n||(Array.isArray(e)?e[1]:e)===n||!(!Array.isArray(e)||"string"!=typeof n)&&bi(e,n)>=0}const Ze={textEnd:0,key:0,keyEnd:0,value:0,valueEnd:0};function QC(e){return e.substring(Ze.key,Ze.keyEnd)}function YC(e,n){const t=Ze.textEnd;return t===n?-1:(n=Ze.keyEnd=function MR(e,n,t){for(;n32;)n++;return n}(e,Ze.key=n,t),mo(e,n,t))}function mo(e,n,t){for(;n=0;t=YC(n,t))Lt(e,QC(n),!0)}function an(e,n,t,r){const i=D(),o=Z(),s=Pn(2);o.firstUpdatePass&&nw(o,e,s,r),n!==J&&Re(i,s,n)&&iw(o,o.data[rt()],i,i[G],e,i[s+1]=function VR(e,n){return null==e||""===e||("string"==typeof n?e+=n:"object"==typeof e&&(e=$e(rr(e)))),e}(n,t),r,s)}function tw(e,n){return n>=e.expandoStartIndex}function nw(e,n,t,r){const i=e.data;if(null===i[t+1]){const o=i[rt()],s=tw(e,t);sw(o,r)&&null===n&&!s&&(n=!1),n=function OR(e,n,t,r){const i=function ed(e){const n=Q.lFrame.currentDirectiveIndex;return-1===n?null:e[n]}(e);let o=r?n.residualClasses:n.residualStyles;if(null===i)0===(r?n.classBindings:n.styleBindings)&&(t=Rs(t=vh(null,e,n,t,r),n.attrs,r),o=null);else{const s=n.directiveStylingLast;if(-1===s||e[s]!==i)if(t=vh(i,e,n,t,r),null===o){let l=function AR(e,n,t){const r=t?n.classBindings:n.styleBindings;if(0!==ii(r))return e[hr(r)]}(e,n,r);void 0!==l&&Array.isArray(l)&&(l=vh(null,e,n,l[1],r),l=Rs(l,n.attrs,r),function RR(e,n,t,r){e[hr(t?n.classBindings:n.styleBindings)]=r}(e,n,r,l))}else o=function kR(e,n,t){let r;const i=n.directiveEnd;for(let o=1+n.directiveStylingLast;o0)&&(c=!0)):u=t,i)if(0!==l){const g=hr(e[a+1]);e[r+1]=Xl(g,a),0!==g&&(e[g+1]=gh(e[g+1],r)),e[a+1]=function _R(e,n){return 131071&e|n<<17}(e[a+1],r)}else e[r+1]=Xl(a,0),0!==a&&(e[a+1]=gh(e[a+1],r)),a=r;else e[r+1]=Xl(l,0),0===a?a=r:e[l+1]=gh(e[l+1],r),l=r;c&&(e[r+1]=hh(e[r+1])),ZC(e,u,r,!0),ZC(e,u,r,!1),function wR(e,n,t,r,i){const o=i?e.residualClasses:e.residualStyles;null!=o&&"string"==typeof n&&bi(o,n)>=0&&(t[r+1]=ph(t[r+1]))}(n,u,e,r,o),s=Xl(a,l),o?n.classBindings=s:n.styleBindings=s}(i,o,n,t,s,r)}}function vh(e,n,t,r,i){let o=null;const s=t.directiveEnd;let a=t.directiveStylingLast;for(-1===a?a=t.directiveStart:a++;a0;){const l=e[i],c=Array.isArray(l),u=c?l[1]:l,d=null===u;let g=t[i+1];g===J&&(g=d?le:void 0);let h=d?Ou(g,r):u===r?g:void 0;if(c&&!tc(h)&&(h=Ou(l,r)),tc(h)&&(a=h,s))return a;const m=e[i+1];i=s?hr(m):ii(m)}if(null!==n){let l=o?n.residualClasses:n.residualStyles;null!=l&&(a=Ou(l,r))}return a}function tc(e){return void 0!==e}function sw(e,n){return!!(e.flags&(n?8:16))}function Kt(e,n,t){!function ln(e,n,t,r){const i=Z(),o=Pn(2);i.firstUpdatePass&&nw(i,null,o,r);const s=D();if(t!==J&&Re(s,o,t)){const a=i.data[rt()];if(sw(a,r)&&!tw(i,o)){let l=r?a.classesWithoutHost:a.stylesWithoutHost;null!==l&&(t=vu(l,t||"")),mh(i,a,s,t,r)}else!function PR(e,n,t,r,i,o,s,a){i===J&&(i=le);let l=0,c=0,u=0(mn(!0),Il(r,i,function ym(){return Q.lFrame.currentNamespace}()));function X(e,n,t){const r=D(),i=Z(),o=e+k,s=i.firstCreatePass?function ck(e,n,t,r,i){const o=n.consts,s=qt(o,r),a=Jr(n,e,8,"ng-container",s);return null!==s&&Bl(a,s,!0),df(n,t,a,qt(o,i)),null!==n.queries&&n.queries.elementStart(n,a),a}(o,i,r,n,t):i.data[o];nn(s,!0);const a=fw(i,r,s,e);return r[o]=a,$o()&&Nl(i,r,a,s),vt(a,r),Va(s)&&(lf(i,r,s),Qd(i,s,r)),null!=t&&cf(r,s),X}function ee(){let e=ie();const n=Z();return Ku()?Ju():(e=e.parent,nn(e,!1)),n.firstCreatePass&&(Ga(n,e),Uu(e)&&n.queries.elementEnd(e)),ee}let fw=(e,n,t,r)=>(mn(!0),af(n[G],""));function ge(){return D()}const rc="en-US";let vw=rc;function q(e,n,t,r){const i=D(),o=Z(),s=ie();return bh(o,i,i[G],s,e,n,r),q}function bh(e,n,t,r,i,o,s){const a=Va(r),c=e.firstCreatePass&&om(e),u=n[8],d=im(n);let g=!0;if(3&r.type||s){const C=ft(r,n),E=s?s(C):C,I=d.length,w=s?z=>s(ae(z[r.index])):r.index;let L=null;if(!s&&a&&(L=function nF(e,n,t,r){const i=e.cleanup;if(null!=i)for(let o=0;ol?a[l]:null}"string"==typeof s&&(o+=2)}return null}(e,n,i,r.index)),null!==L)(L.__ngLastListenerFn__||L).__ngNextListenerFn__=o,L.__ngLastListenerFn__=o,g=!1;else{o=Hw(r,n,u,o);const z=t.listen(E,i,o);d.push(o,z),c&&c.push(i,w,I,I+1)}}else o=Hw(r,n,u,o);const h=r.outputs;let m;if(g&&null!==h&&(m=h[i])){const C=m.length;if(C)for(let E=0;E0;)n=n[14],e--;return n}(e,Q.lFrame.contextLView))[8]}(e)}function In(e,n,t){return Eh(e,"",n,"",t),In}function Eh(e,n,t,r,i){const o=D(),s=ao(o,n,t,r);return s!==J&&St(Z(),me(),o,e,s,o[G],i,!1),Eh}function Zw(e,n,t,r){!function zy(e,n,t,r){const i=Z();if(i.firstCreatePass){const o=ie();Gy(i,new By(n,t,r),o.index),function rO(e,n){const t=e.contentQueries||(e.contentQueries=[]);n!==(t.length?t[t.length-1]:-1)&&t.push(e.queries.length-1,n)}(i,e),!(2&~t)&&(i.staticContentQueries=!0)}return Uy(i,D(),t)}(e,n,t,r)}function Vt(e,n,t){!function $y(e,n,t){const r=Z();return r.firstCreatePass&&(Gy(r,new By(e,n,t),-1),!(2&~n)&&(r.staticViewQueries=!0)),Uy(r,D(),n)}(e,n,t)}function Ot(e){const n=D(),t=Z(),r=td();za(r+1);const i=Qf(t,r);if(e.dirty&&function P0(e){return!(4&~e[2])}(n)===!(2&~i.metadata.flags)){if(null===i.matches)e.reset([]);else{const o=qy(n,r);e.reset(o,Km),e.notifyOnChanges()}return!0}return!1}function At(){return function Zf(e,n){return e[18].queries[n].queryList}(D(),td())}function b(e,n=""){const t=D(),r=Z(),i=e+k,o=r.firstCreatePass?Jr(r,i,1,n,null):r.data[i],s=iD(r,t,o,n,e);t[i]=s,$o()&&Nl(r,t,s,o),nn(o,!1)}let iD=(e,n,t,r,i)=>(mn(!0),function sf(e,n){return e.createText(n)}(n[G],r));function O(e){return U("",e,""),O}function U(e,n,t){const r=D(),i=ao(r,e,n,t);return i!==J&&function Un(e,n,t){const r=Ai(n,e);!function I_(e,n,t){e.setValue(n,t)}(e[G],r,t)}(r,rt(),i),U}function Qe(e,n,t){ev(n)&&(n=n());const r=D();return Re(r,Wt(),n)&&St(Z(),me(),r,e,n,r[G],t,!1),Qe}function be(e,n){const t=ev(e);return t&&e.set(n),t}function tt(e,n){const t=D(),r=Z(),i=ie();return bh(r,t,t[G],i,e,n),tt}function Mh(e,n,t,r,i){if(e=W(e),Array.isArray(e))for(let o=0;o>20;if(kr(e)||!e.multi){const h=new zo(c,i,T),m=Sh(l,n,i?u:u+g,d);-1===m?(dd(Qa(a,s),o,l),Th(o,e,n.length),n.push(l),a.directiveStart++,a.directiveEnd++,i&&(a.providerIndexes+=1048576),t.push(h),s.push(h)):(t[m]=h,s[m]=h)}else{const h=Sh(l,n,u+g,d),m=Sh(l,n,u,u+g),E=m>=0&&t[m];if(i&&!E||!i&&!(h>=0&&t[h])){dd(Qa(a,s),o,l);const I=function SF(e,n,t,r,i){const o=new zo(e,t,T);return o.multi=[],o.index=n,o.componentProviders=0,pD(o,i,r&&!t),o}(i?TF:MF,t.length,i,r,c);!i&&E&&(t[m].providerFactory=I),Th(o,e,n.length,0),n.push(l),a.directiveStart++,a.directiveEnd++,i&&(a.providerIndexes+=1048576),t.push(I),s.push(I)}else Th(o,e,h>-1?h:m,pD(t[i?m:h],c,!i&&r));!i&&r&&E&&t[m].componentProviders++}}}function Th(e,n,t,r){const i=kr(n),o=function h0(e){return!!e.useClass}(n);if(i||o){const l=(o?W(n.useClass):n).prototype.ngOnDestroy;if(l){const c=e.destroyHooks||(e.destroyHooks=[]);if(!i&&n.multi){const u=c.indexOf(t);-1===u?c.push(t,[r,l]):c[u+1].push(r,l)}else c.push(t,l)}}}function pD(e,n,t){return t&&e.componentProviders++,e.multi.push(n)-1}function Sh(e,n,t,r){for(let i=t;i{t.providersResolver=(r,i)=>function IF(e,n,t){const r=Z();if(r.firstCreatePass){const i=zt(e);Mh(t,r.data,r.blueprint,i,!0),Mh(n,r.data,r.blueprint,i,!1)}}(r,i?i(e):e,n)}}function _o(e,n,t,r){return function vD(e,n,t,r,i,o){const s=n+t;return Re(e,s,i)?Dn(e,s+1,o?r.call(o,i):r(i)):Hs(e,s+1)}(D(),gt(),e,n,t,r)}function xh(e,n,t,r,i){return function _D(e,n,t,r,i,o,s){const a=n+t;return ni(e,a,i,o)?Dn(e,a+2,s?r.call(s,i,o):r(i,o)):Hs(e,a+2)}(D(),gt(),e,n,t,r,i)}function Fe(e,n,t,r,i,o){return yD(D(),gt(),e,n,t,r,i,o)}function Hs(e,n){const t=e[n];return t===J?void 0:t}function yD(e,n,t,r,i,o,s,a){const l=n+t;return function Gl(e,n,t,r,i){const o=ni(e,n,t,r);return Re(e,n+2,i)||o}(e,l,i,o,s)?Dn(e,l+3,a?r.call(a,i,o,s):r(i,o,s)):Hs(e,l+3)}let wL=(()=>{class e{zone=A(de);changeDetectionScheduler=A(Vn);applicationRef=A(Yt);_onMicrotaskEmptySubscription;initialize(){this._onMicrotaskEmptySubscription||(this._onMicrotaskEmptySubscription=this.zone.onMicrotaskEmpty.subscribe({next:()=>{this.changeDetectionScheduler.runningTick||this.zone.run(()=>{this.applicationRef.tick()})}}))}ngOnDestroy(){this._onMicrotaskEmptySubscription?.unsubscribe()}static \u0275fac=function(r){return new(r||e)};static \u0275prov=re({token:e,factory:e.\u0275fac,providedIn:"root"})}return e})();function Fh({ngZoneFactory:e,ignoreChangesOutsideZone:n,scheduleInRootZone:t}){return e??=()=>new de({...Lh(),scheduleInRootZone:t}),[{provide:de,useFactory:e},{provide:en,multi:!0,useFactory:()=>{const r=A(wL,{optional:!0});return()=>r.initialize()}},{provide:en,multi:!0,useFactory:()=>{const r=A(bL);return()=>{r.initialize()}}},!0===n?{provide:zm,useValue:!0}:[],{provide:gd,useValue:t??Um}]}function Lh(e){return{enableLongStackTrace:!1,shouldCoalesceEventChangeDetection:e?.eventCoalescing??!1,shouldCoalesceRunChangeDetection:e?.runCoalescing??!1}}let bL=(()=>{class e{subscription=new Rt;initialized=!1;zone=A(de);pendingTasks=A(Xn);initialize(){if(this.initialized)return;this.initialized=!0;let t=null;!this.zone.isStable&&!this.zone.hasPendingMacrotasks&&!this.zone.hasPendingMicrotasks&&(t=this.pendingTasks.add()),this.zone.runOutsideAngular(()=>{this.subscription.add(this.zone.onStable.subscribe(()=>{de.assertNotInAngularZone(),queueMicrotask(()=>{null!==t&&!this.zone.hasPendingMacrotasks&&!this.zone.hasPendingMicrotasks&&(this.pendingTasks.remove(t),t=null)})}))}),this.subscription.add(this.zone.onUnstable.subscribe(()=>{de.assertInAngularZone(),t??=this.pendingTasks.add()}))}ngOnDestroy(){this.subscription.unsubscribe()}static \u0275fac=function(r){return new(r||e)};static \u0275prov=re({token:e,factory:e.\u0275fac,providedIn:"root"})}return e})(),Us=(()=>{class e{appRef=A(Yt);taskService=A(Xn);ngZone=A(de);zonelessEnabled=A(Zo);tracing=A(Hi,{optional:!0});disableScheduling=A(zm,{optional:!0})??!1;zoneIsDefined=typeof Zone<"u"&&!!Zone.root.run;schedulerTickApplyArgs=[{data:{__scheduler_tick__:!0}}];subscriptions=new Rt;angularZoneId=this.zoneIsDefined?this.ngZone._inner?.get(el):null;scheduleInRootZone=!this.zonelessEnabled&&this.zoneIsDefined&&(A(gd,{optional:!0})??!1);cancelScheduledCallback=null;useMicrotaskScheduler=!1;runningTick=!1;pendingRenderTaskId=null;constructor(){this.subscriptions.add(this.appRef.afterTick.subscribe(()=>{this.runningTick||this.cleanup()})),this.subscriptions.add(this.ngZone.onUnstable.subscribe(()=>{this.runningTick||this.cleanup()})),this.disableScheduling||=!this.zonelessEnabled&&(this.ngZone instanceof _d||!this.zoneIsDefined)}notify(t){if(!this.zonelessEnabled&&5===t)return;let r=!1;switch(t){case 0:this.appRef.dirtyFlags|=2;break;case 3:case 2:case 4:case 5:case 1:this.appRef.dirtyFlags|=4;break;case 8:this.appRef.deferredDirtyFlags|=8;break;case 6:case 14:this.appRef.dirtyFlags|=2,r=!0;break;case 13:this.appRef.dirtyFlags|=16,r=!0;break;case 12:r=!0;break;default:this.appRef.dirtyFlags|=8}if(this.appRef.tracingSnapshot=this.tracing?.snapshot(this.appRef.tracingSnapshot)??null,!this.shouldScheduleTick(r))return;const i=this.useMicrotaskScheduler?qm:Gm;this.pendingRenderTaskId=this.taskService.add(),this.cancelScheduledCallback=this.scheduleInRootZone?Zone.root.run(()=>i(()=>this.tick())):this.ngZone.runOutsideAngular(()=>i(()=>this.tick()))}shouldScheduleTick(t){return!(this.disableScheduling&&!t||this.appRef.destroyed||null!==this.pendingRenderTaskId||this.runningTick||this.appRef._runningTick||!this.zonelessEnabled&&this.zoneIsDefined&&Zone.current.get(el+this.angularZoneId))}tick(){if(this.runningTick||this.appRef.destroyed)return;if(0===this.appRef.dirtyFlags)return void this.cleanup();!this.zonelessEnabled&&7&this.appRef.dirtyFlags&&(this.appRef.dirtyFlags|=1);const t=this.taskService.add();try{this.ngZone.run(()=>{this.runningTick=!0,this.appRef._tick()},void 0,this.schedulerTickApplyArgs)}catch(r){throw this.taskService.remove(t),r}finally{this.cleanup()}this.useMicrotaskScheduler=!0,qm(()=>{this.useMicrotaskScheduler=!1,this.taskService.remove(t)})}ngOnDestroy(){this.subscriptions.unsubscribe(),this.cleanup()}cleanup(){if(this.runningTick=!1,this.cancelScheduledCallback?.(),this.cancelScheduledCallback=null,null!==this.pendingRenderTaskId){const t=this.pendingRenderTaskId;this.pendingRenderTaskId=null,this.taskService.remove(t)}}static \u0275fac=function(r){return new(r||e)};static \u0275prov=re({token:e,factory:e.\u0275fac,providedIn:"root"})}return e})();const gr=new R("",{providedIn:"root",factory:()=>A(gr,oe.Optional|oe.SkipSelf)||function EL(){return typeof $localize<"u"&&$localize.locale||rc}()}),dc=new R(""),xL=new R("");function $s(e){return!e.moduleRef}let zD=(()=>{class e{_injector;_modules=[];_destroyListeners=[];_destroyed=!1;constructor(t){this._injector=t}bootstrapModuleFactory(t,r){const i=r?.scheduleInRootZone,s=r?.ignoreChangesOutsideZone,a=[Fh({ngZoneFactory:()=>function FT(e="zone.js",n){return"noop"===e?new _d:"zone.js"===e?new de(n):e}(r?.ngZone,{...Lh({eventCoalescing:r?.ngZoneEventCoalescing,runCoalescing:r?.ngZoneRunCoalescing}),scheduleInRootZone:i}),ignoreChangesOutsideZone:s}),{provide:Vn,useExisting:Us}],l=function pO(e,n,t){return new Kf(e,n,t,!1)}(t.moduleType,this.injector,a);return function $D(e){const n=$s(e)?e.r3Injector:e.moduleRef.injector,t=n.get(de);return t.run(()=>{$s(e)?e.r3Injector.resolveInjectorInitializers():e.moduleRef.resolveInjectorInitializers();const r=n.get(_n,null);let i;if(t.runOutsideAngular(()=>{i=t.onError.subscribe({next:o=>{r.handleError(o)}})}),$s(e)){const o=()=>n.destroy(),s=e.platformInjector.get(dc);s.add(o),n.onDestroy(()=>{i.unsubscribe(),s.delete(o)})}else{const o=()=>e.moduleRef.destroy(),s=e.platformInjector.get(dc);s.add(o),e.moduleRef.onDestroy(()=>{Jl(e.allPlatformModules,e.moduleRef),i.unsubscribe(),s.delete(o)})}return function PA(e,n,t){try{const r=t();return Yl(r)?r.catch(i=>{throw n.runOutsideAngular(()=>e.handleError(i)),i}):r}catch(r){throw n.runOutsideAngular(()=>e.handleError(r)),r}}(r,t,()=>{const o=n.get(xC);return o.runInitializers(),o.donePromise.then(()=>{if(function _k(e){"string"==typeof e&&(vw=e.toLowerCase().replace(/_/g,"-"))}(n.get(gr,rc)||rc),!n.get(xL,!0))return $s(e)?n.get(Yt):(e.allPlatformModules.push(e.moduleRef),e.moduleRef);if($s(e)){const l=n.get(Yt);return void 0!==e.rootComponent&&l.bootstrap(e.rootComponent),l}return function OL(e,n){const t=e.injector.get(Yt);if(e._bootstrapComponents.length>0)e._bootstrapComponents.forEach(r=>t.bootstrap(r));else{if(!e.instance.ngDoBootstrap)throw new N(-403,!1);e.instance.ngDoBootstrap(t)}n.push(e)}(e.moduleRef,e.allPlatformModules),e.moduleRef})})})}({moduleRef:l,allPlatformModules:this._modules,platformInjector:this.injector})}bootstrapModule(t,r=[]){const i=RC({},r);return function CL(e,n,t){const r=new Jf(t);return Promise.resolve(r)}(0,0,t).then(o=>this.bootstrapModuleFactory(o,i))}onDestroy(t){this._destroyListeners.push(t)}get injector(){return this._injector}destroy(){if(this._destroyed)throw new N(404,!1);this._modules.slice().forEach(r=>r.destroy()),this._destroyListeners.forEach(r=>r());const t=this._injector.get(dc,null);t&&(t.forEach(r=>r()),t.clear()),this._destroyed=!0}get destroyed(){return this._destroyed}static \u0275fac=function(r){return new(r||e)(se(We))};static \u0275prov=re({token:e,factory:e.\u0275fac,providedIn:"platform"})}return e})(),pr=null;const GD=new R("");function qD(e,n,t=[]){const r=`Platform: ${n}`,i=new R(r);return(o=[])=>{let s=Vh();if(!s||s.injector.get(GD,!1)){const a=[...t,...o,{provide:i,useValue:!0}];e?e(a):function AL(e){if(pr&&!pr.get(GD,!1))throw new N(400,!1);(function AC(){!function yM(e){sp=e}(()=>{throw new N(600,!1)})})(),pr=e;const n=e.get(zD);(function ZD(e){const n=e.get(Ed,null);jp(e,()=>{n?.forEach(t=>t())})})(e)}(function WD(e=[],n){return We.create({name:n,providers:[{provide:Lu,useValue:"platform"},{provide:dc,useValue:new Set([()=>pr=null])},...e]})}(a,r))}return function RL(){const n=Vh();if(!n)throw new N(401,!1);return n}()}}function Vh(){return pr?.get(zD)??null}let si=(()=>class e{static __NG_ELEMENT_ID__=FL})();function FL(e){return function LL(e,n,t){if($t(e)&&!t){const r=ht(e.index,n);return new vs(r,r)}return 175&e.type?new vs(n[15],n):null}(ie(),D(),!(16&~e))}class XD{constructor(){}supports(n){return zl(n)}create(n){return new jL(n)}}const BL=(e,n)=>n;class jL{length=0;collection;_linkedRecords=null;_unlinkedRecords=null;_previousItHead=null;_itHead=null;_itTail=null;_additionsHead=null;_additionsTail=null;_movesHead=null;_movesTail=null;_removalsHead=null;_removalsTail=null;_identityChangesHead=null;_identityChangesTail=null;_trackByFn;constructor(n){this._trackByFn=n||BL}forEachItem(n){let t;for(t=this._itHead;null!==t;t=t._next)n(t)}forEachOperation(n){let t=this._itHead,r=this._removalsHead,i=0,o=null;for(;t||r;){const s=!r||t&&t.currentIndex{s=this._trackByFn(i,a),null!==t&&Object.is(t.trackById,s)?(r&&(t=this._verifyReinsertion(t,a,s,i)),Object.is(t.item,a)||this._addIdentityChange(t,a)):(t=this._mismatch(t,a,s,i),r=!0),t=t._next,i++}),this.length=i;return this._truncate(t),this.collection=n,this.isDirty}get isDirty(){return null!==this._additionsHead||null!==this._movesHead||null!==this._removalsHead||null!==this._identityChangesHead}_reset(){if(this.isDirty){let n;for(n=this._previousItHead=this._itHead;null!==n;n=n._next)n._nextPrevious=n._next;for(n=this._additionsHead;null!==n;n=n._nextAdded)n.previousIndex=n.currentIndex;for(this._additionsHead=this._additionsTail=null,n=this._movesHead;null!==n;n=n._nextMoved)n.previousIndex=n.currentIndex;this._movesHead=this._movesTail=null,this._removalsHead=this._removalsTail=null,this._identityChangesHead=this._identityChangesTail=null}}_mismatch(n,t,r,i){let o;return null===n?o=this._itTail:(o=n._prev,this._remove(n)),null!==(n=null===this._unlinkedRecords?null:this._unlinkedRecords.get(r,null))?(Object.is(n.item,t)||this._addIdentityChange(n,t),this._reinsertAfter(n,o,i)):null!==(n=null===this._linkedRecords?null:this._linkedRecords.get(r,i))?(Object.is(n.item,t)||this._addIdentityChange(n,t),this._moveAfter(n,o,i)):n=this._addAfter(new UL(t,r),o,i),n}_verifyReinsertion(n,t,r,i){let o=null===this._unlinkedRecords?null:this._unlinkedRecords.get(r,null);return null!==o?n=this._reinsertAfter(o,n._prev,i):n.currentIndex!=i&&(n.currentIndex=i,this._addToMoves(n,i)),n}_truncate(n){for(;null!==n;){const t=n._next;this._addToRemovals(this._unlink(n)),n=t}null!==this._unlinkedRecords&&this._unlinkedRecords.clear(),null!==this._additionsTail&&(this._additionsTail._nextAdded=null),null!==this._movesTail&&(this._movesTail._nextMoved=null),null!==this._itTail&&(this._itTail._next=null),null!==this._removalsTail&&(this._removalsTail._nextRemoved=null),null!==this._identityChangesTail&&(this._identityChangesTail._nextIdentityChange=null)}_reinsertAfter(n,t,r){null!==this._unlinkedRecords&&this._unlinkedRecords.remove(n);const i=n._prevRemoved,o=n._nextRemoved;return null===i?this._removalsHead=o:i._nextRemoved=o,null===o?this._removalsTail=i:o._prevRemoved=i,this._insertAfter(n,t,r),this._addToMoves(n,r),n}_moveAfter(n,t,r){return this._unlink(n),this._insertAfter(n,t,r),this._addToMoves(n,r),n}_addAfter(n,t,r){return this._insertAfter(n,t,r),this._additionsTail=null===this._additionsTail?this._additionsHead=n:this._additionsTail._nextAdded=n,n}_insertAfter(n,t,r){const i=null===t?this._itHead:t._next;return n._next=i,n._prev=t,null===i?this._itTail=n:i._prev=n,null===t?this._itHead=n:t._next=n,null===this._linkedRecords&&(this._linkedRecords=new eb),this._linkedRecords.put(n),n.currentIndex=r,n}_remove(n){return this._addToRemovals(this._unlink(n))}_unlink(n){null!==this._linkedRecords&&this._linkedRecords.remove(n);const t=n._prev,r=n._next;return null===t?this._itHead=r:t._next=r,null===r?this._itTail=t:r._prev=t,n}_addToMoves(n,t){return n.previousIndex===t||(this._movesTail=null===this._movesTail?this._movesHead=n:this._movesTail._nextMoved=n),n}_addToRemovals(n){return null===this._unlinkedRecords&&(this._unlinkedRecords=new eb),this._unlinkedRecords.put(n),n.currentIndex=null,n._nextRemoved=null,null===this._removalsTail?(this._removalsTail=this._removalsHead=n,n._prevRemoved=null):(n._prevRemoved=this._removalsTail,this._removalsTail=this._removalsTail._nextRemoved=n),n}_addIdentityChange(n,t){return n.item=t,this._identityChangesTail=null===this._identityChangesTail?this._identityChangesHead=n:this._identityChangesTail._nextIdentityChange=n,n}}class UL{item;trackById;currentIndex=null;previousIndex=null;_nextPrevious=null;_prev=null;_next=null;_prevDup=null;_nextDup=null;_prevRemoved=null;_nextRemoved=null;_nextAdded=null;_nextMoved=null;_nextIdentityChange=null;constructor(n,t){this.item=n,this.trackById=t}}class $L{_head=null;_tail=null;add(n){null===this._head?(this._head=this._tail=n,n._nextDup=null,n._prevDup=null):(this._tail._nextDup=n,n._prevDup=this._tail,n._nextDup=null,this._tail=n)}get(n,t){let r;for(r=this._head;null!==r;r=r._nextDup)if((null===t||t<=r.currentIndex)&&Object.is(r.trackById,n))return r;return null}remove(n){const t=n._prevDup,r=n._nextDup;return null===t?this._head=r:t._nextDup=r,null===r?this._tail=t:r._prevDup=t,null===this._head}}class eb{map=new Map;put(n){const t=n.trackById;let r=this.map.get(t);r||(r=new $L,this.map.set(t,r)),r.add(n)}get(n,t){const i=this.map.get(n);return i?i.get(n,t):null}remove(n){const t=n.trackById;return this.map.get(t).remove(n)&&this.map.delete(t),n}get isEmpty(){return 0===this.map.size}clear(){this.map.clear()}}function tb(e,n,t){const r=e.previousIndex;if(null===r)return r;let i=0;return t&&r{if(t&&t.key===i)this._maybeAddToChanges(t,r),this._appendAfter=t,t=t._next;else{const o=this._getOrCreateRecordForKey(i,r);t=this._insertBeforeOrAppend(t,o)}}),t){t._prev&&(t._prev._next=null),this._removalsHead=t;for(let r=t;null!==r;r=r._nextRemoved)r===this._mapHead&&(this._mapHead=null),this._records.delete(r.key),r._nextRemoved=r._next,r.previousValue=r.currentValue,r.currentValue=null,r._prev=null,r._next=null}return this._changesTail&&(this._changesTail._nextChanged=null),this._additionsTail&&(this._additionsTail._nextAdded=null),this.isDirty}_insertBeforeOrAppend(n,t){if(n){const r=n._prev;return t._next=n,t._prev=r,n._prev=t,r&&(r._next=t),n===this._mapHead&&(this._mapHead=t),this._appendAfter=n,n}return this._appendAfter?(this._appendAfter._next=t,t._prev=this._appendAfter):this._mapHead=t,this._appendAfter=t,null}_getOrCreateRecordForKey(n,t){if(this._records.has(n)){const i=this._records.get(n);this._maybeAddToChanges(i,t);const o=i._prev,s=i._next;return o&&(o._next=s),s&&(s._prev=o),i._next=null,i._prev=null,i}const r=new GL(n);return this._records.set(n,r),r.currentValue=t,this._addToAdditions(r),r}_reset(){if(this.isDirty){let n;for(this._previousMapHead=this._mapHead,n=this._previousMapHead;null!==n;n=n._next)n._nextPrevious=n._next;for(n=this._changesHead;null!==n;n=n._nextChanged)n.previousValue=n.currentValue;for(n=this._additionsHead;null!=n;n=n._nextAdded)n.previousValue=n.currentValue;this._changesHead=this._changesTail=null,this._additionsHead=this._additionsTail=null,this._removalsHead=null}}_maybeAddToChanges(n,t){Object.is(t,n.currentValue)||(n.previousValue=n.currentValue,n.currentValue=t,this._addToChanges(n))}_addToAdditions(n){null===this._additionsHead?this._additionsHead=this._additionsTail=n:(this._additionsTail._nextAdded=n,this._additionsTail=n)}_addToChanges(n){null===this._changesHead?this._changesHead=this._changesTail=n:(this._changesTail._nextChanged=n,this._changesTail=n)}_forEach(n,t){n instanceof Map?n.forEach(t):Object.keys(n).forEach(r=>t(n[r],r))}}class GL{key;previousValue=null;currentValue=null;_nextPrevious=null;_next=null;_prev=null;_nextAdded=null;_nextRemoved=null;_nextChanged=null;constructor(n){this.key=n}}function rb(){return new $h([new XD])}let $h=(()=>{class e{factories;static \u0275prov=re({token:e,providedIn:"root",factory:rb});constructor(t){this.factories=t}static create(t,r){if(null!=r){const i=r.factories.slice();t=t.concat(i)}return new e(t)}static extend(t){return{provide:e,useFactory:r=>e.create(t,r||rb()),deps:[[e,new Nu,new Su]]}}find(t){const r=this.factories.find(i=>i.supports(t));if(null!=r)return r;throw new N(901,!1)}}return e})();function ib(){return new gc([new nb])}let gc=(()=>{class e{static \u0275prov=re({token:e,providedIn:"root",factory:ib});factories;constructor(t){this.factories=t}static create(t,r){if(r){const i=r.factories.slice();t=t.concat(i)}return new e(t)}static extend(t){return{provide:e,useFactory:r=>e.create(t,r||ib()),deps:[[e,new Nu,new Su]]}}find(t){const r=this.factories.find(i=>i.supports(t));if(r)return r;throw new N(901,!1)}}return e})();const ZL=qD(null,"core",[]);let QL=(()=>{class e{constructor(t){}static \u0275fac=function(r){return new(r||e)(se(Yt))};static \u0275mod=cr({type:e});static \u0275inj=Nn({})}return e})();function Mn(e,n){Xe("NgSignals");const t=function mM(e){const n=Object.create(vM);n.computation=e;const t=()=>{if(Ao(n),Oo(n),n.value===Gn)throw n.error;return n.value};return t[Ke]=n,t}(e);return n?.equal&&(t[Ke].equal=n.equal),t}function it(e){const n=te(null);try{return e()}finally{te(n)}}let Lb=null;function Qs(){return Lb}class JP{}const li=new R(""),ig=/\s+/,Gb=[];let Do=(()=>{class e{_ngEl;_renderer;initialClasses=Gb;rawClass;stateMap=new Map;constructor(t,r){this._ngEl=t,this._renderer=r}set klass(t){this.initialClasses=null!=t?t.trim().split(ig):Gb}set ngClass(t){this.rawClass="string"==typeof t?t.trim().split(ig):t}ngDoCheck(){for(const r of this.initialClasses)this._updateState(r,!0);const t=this.rawClass;if(Array.isArray(t)||t instanceof Set)for(const r of t)this._updateState(r,!0);else if(null!=t)for(const r of Object.keys(t))this._updateState(r,!!t[r]);this._applyStateDiff()}_updateState(t,r){const i=this.stateMap.get(t);void 0!==i?(i.enabled!==r&&(i.changed=!0,i.enabled=r),i.touched=!0):this.stateMap.set(t,{enabled:r,changed:!0,touched:!0})}_applyStateDiff(){for(const t of this.stateMap){const r=t[0],i=t[1];i.changed?(this._toggleClass(r,i.enabled),i.changed=!1):i.touched||(i.enabled&&this._toggleClass(r,!1),this.stateMap.delete(r)),i.touched=!1}}_toggleClass(t,r){(t=t.trim()).length>0&&t.split(ig).forEach(i=>{r?this._renderer.addClass(this._ngEl.nativeElement,i):this._renderer.removeClass(this._ngEl.nativeElement,i)})}static \u0275fac=function(r){return new(r||e)(T(pt),T(on))};static \u0275dir=Y({type:e,selectors:[["","ngClass",""]],inputs:{klass:[0,"class","klass"],ngClass:"ngClass"}})}return e})();class BV{$implicit;ngForOf;index;count;constructor(n,t,r,i){this.$implicit=n,this.ngForOf=t,this.index=r,this.count=i}get first(){return 0===this.index}get last(){return this.index===this.count-1}get even(){return this.index%2==0}get odd(){return!this.even}}let ci=(()=>{class e{_viewContainer;_template;_differs;set ngForOf(t){this._ngForOf=t,this._ngForOfDirty=!0}set ngForTrackBy(t){this._trackByFn=t}get ngForTrackBy(){return this._trackByFn}_ngForOf=null;_ngForOfDirty=!0;_differ=null;_trackByFn;constructor(t,r,i){this._viewContainer=t,this._template=r,this._differs=i}set ngForTemplate(t){t&&(this._template=t)}ngDoCheck(){if(this._ngForOfDirty){this._ngForOfDirty=!1;const t=this._ngForOf;!this._differ&&t&&(this._differ=this._differs.find(t).create(this.ngForTrackBy))}if(this._differ){const t=this._differ.diff(this._ngForOf);t&&this._applyChanges(t)}}_applyChanges(t){const r=this._viewContainer;t.forEachOperation((i,o,s)=>{if(null==i.previousIndex)r.createEmbeddedView(this._template,new BV(i.item,this._ngForOf,-1,-1),null===s?void 0:s);else if(null==s)r.remove(null===o?void 0:o);else if(null!==o){const a=r.get(o);r.move(a,s),Wb(a,i)}});for(let i=0,o=r.length;i{Wb(r.get(i.currentIndex),i)})}static ngTemplateContextGuard(t,r){return!0}static \u0275fac=function(r){return new(r||e)(T(wn),T(Bn),T($h))};static \u0275dir=Y({type:e,selectors:[["","ngFor","","ngForOf",""]],inputs:{ngForOf:"ngForOf",ngForTrackBy:"ngForTrackBy",ngForTemplate:"ngForTemplate"}})}return e})();function Wb(e,n){e.context.$implicit=n.item}let zn=(()=>{class e{_viewContainer;_context=new jV;_thenTemplateRef=null;_elseTemplateRef=null;_thenViewRef=null;_elseViewRef=null;constructor(t,r){this._viewContainer=t,this._thenTemplateRef=r}set ngIf(t){this._context.$implicit=this._context.ngIf=t,this._updateView()}set ngIfThen(t){Zb("ngIfThen",t),this._thenTemplateRef=t,this._thenViewRef=null,this._updateView()}set ngIfElse(t){Zb("ngIfElse",t),this._elseTemplateRef=t,this._elseViewRef=null,this._updateView()}_updateView(){this._context.$implicit?this._thenViewRef||(this._viewContainer.clear(),this._elseViewRef=null,this._thenTemplateRef&&(this._thenViewRef=this._viewContainer.createEmbeddedView(this._thenTemplateRef,this._context))):this._elseViewRef||(this._viewContainer.clear(),this._thenViewRef=null,this._elseTemplateRef&&(this._elseViewRef=this._viewContainer.createEmbeddedView(this._elseTemplateRef,this._context)))}static ngIfUseIfTypeGuard;static ngTemplateGuard_ngIf;static ngTemplateContextGuard(t,r){return!0}static \u0275fac=function(r){return new(r||e)(T(wn),T(Bn))};static \u0275dir=Y({type:e,selectors:[["","ngIf",""]],inputs:{ngIf:"ngIf",ngIfThen:"ngIfThen",ngIfElse:"ngIfElse"}})}return e})();class jV{$implicit=null;ngIf=null}function Zb(e,n){if(n&&!n.createEmbeddedView)throw new Error(`${e} must be a TemplateRef, but received '${$e(n)}'.`)}let Yb=(()=>{class e{_ngEl;_differs;_renderer;_ngStyle=null;_differ=null;constructor(t,r,i){this._ngEl=t,this._differs=r,this._renderer=i}set ngStyle(t){this._ngStyle=t,!this._differ&&t&&(this._differ=this._differs.find(t).create())}ngDoCheck(){if(this._differ){const t=this._differ.diff(this._ngStyle);t&&this._applyChanges(t)}}_setStyle(t,r){const[i,o]=t.split("."),s=-1===i.indexOf("-")?void 0:sr.DashCase;null!=r?this._renderer.setStyle(this._ngEl.nativeElement,i,o?`${r}${o}`:r,s):this._renderer.removeStyle(this._ngEl.nativeElement,i,s)}_applyChanges(t){t.forEachRemovedItem(r=>this._setStyle(r.key,null)),t.forEachAddedItem(r=>this._setStyle(r.key,r.currentValue)),t.forEachChangedItem(r=>this._setStyle(r.key,r.currentValue))}static \u0275fac=function(r){return new(r||e)(T(pt),T(gc),T(on))};static \u0275dir=Y({type:e,selectors:[["","ngStyle",""]],inputs:{ngStyle:"ngStyle"}})}return e})(),Kb=(()=>{class e{_viewContainerRef;_viewRef=null;ngTemplateOutletContext=null;ngTemplateOutlet=null;ngTemplateOutletInjector=null;constructor(t){this._viewContainerRef=t}ngOnChanges(t){if(this._shouldRecreateView(t)){const r=this._viewContainerRef;if(this._viewRef&&r.remove(r.indexOf(this._viewRef)),!this.ngTemplateOutlet)return void(this._viewRef=null);const i=this._createContextForwardProxy();this._viewRef=r.createEmbeddedView(this.ngTemplateOutlet,i,{injector:this.ngTemplateOutletInjector??void 0})}}_shouldRecreateView(t){return!!t.ngTemplateOutlet||!!t.ngTemplateOutletInjector}_createContextForwardProxy(){return new Proxy({},{set:(t,r,i)=>!!this.ngTemplateOutletContext&&Reflect.set(this.ngTemplateOutletContext,r,i),get:(t,r,i)=>{if(this.ngTemplateOutletContext)return Reflect.get(this.ngTemplateOutletContext,r,i)}})}static \u0275fac=function(r){return new(r||e)(T(wn))};static \u0275dir=Y({type:e,selectors:[["","ngTemplateOutlet",""]],inputs:{ngTemplateOutletContext:"ngTemplateOutletContext",ngTemplateOutlet:"ngTemplateOutlet",ngTemplateOutletInjector:"ngTemplateOutletInjector"},features:[kn]})}return e})();let Xb=(()=>{class e{transform(t,r,i){if(null==t)return null;if(!this.supports(t))throw function un(e,n){return new N(2100,!1)}();return t.slice(r,i)}supports(t){return"string"==typeof t||Array.isArray(t)}static \u0275fac=function(r){return new(r||e)};static \u0275pipe=Nt({name:"slice",type:e,pure:!1})}return e})(),eE=(()=>{class e{static \u0275fac=function(r){return new(r||e)};static \u0275mod=cr({type:e});static \u0275inj=Nn({})}return e})();function nE(e){return"server"===e}class $2 extends JP{supportsDOMEvents=!0}class fg extends $2{static makeCurrent(){!function KP(e){Lb??=e}(new fg)}onAndCancel(n,t,r,i){return n.addEventListener(t,r,i),()=>{n.removeEventListener(t,r,i)}}dispatchEvent(n,t){n.dispatchEvent(t)}remove(n){n.remove()}createElement(n,t){return(t=t||this.getDefaultDocument()).createElement(n)}createHtmlDocument(){return document.implementation.createHTMLDocument("fakeTitle")}getDefaultDocument(){return document}isElementNode(n){return n.nodeType===Node.ELEMENT_NODE}isShadowRoot(n){return n instanceof DocumentFragment}getGlobalEventTarget(n,t){return"window"===t?window:"document"===t?n:"body"===t?n.body:null}getBaseHref(n){const t=function z2(){return Xs=Xs||document.querySelector("base"),Xs?Xs.getAttribute("href"):null}();return null==t?null:function G2(e){return new URL(e,document.baseURI).pathname}(t)}resetBaseElement(){Xs=null}getUserAgent(){return window.navigator.userAgent}getCookie(n){return function VV(e,n){n=encodeURIComponent(n);for(const t of e.split(";")){const r=t.indexOf("="),[i,o]=-1==r?[t,""]:[t.slice(0,r),t.slice(r+1)];if(i.trim()===n)return decodeURIComponent(o)}return null}(document.cookie,n)}}let Xs=null,W2=(()=>{class e{build(){return new XMLHttpRequest}static \u0275fac=function(r){return new(r||e)};static \u0275prov=re({token:e,factory:e.\u0275fac})}return e})();const hg=new R("");let hE=(()=>{class e{_zone;_plugins;_eventNameToPlugin=new Map;constructor(t,r){this._zone=r,t.forEach(i=>{i.manager=this}),this._plugins=t.slice().reverse()}addEventListener(t,r,i,o){return this._findPluginFor(r).addEventListener(t,r,i,o)}getZone(){return this._zone}_findPluginFor(t){let r=this._eventNameToPlugin.get(t);if(r)return r;if(r=this._plugins.find(o=>o.supports(t)),!r)throw new N(5101,!1);return this._eventNameToPlugin.set(t,r),r}static \u0275fac=function(r){return new(r||e)(se(hg),se(de))};static \u0275prov=re({token:e,factory:e.\u0275fac})}return e})();class gE{_doc;constructor(n){this._doc=n}manager}const Vc="ng-app-id";function pE(e){for(const n of e)n.remove()}function mE(e,n){const t=n.createElement("style");return t.textContent=e,t}function gg(e,n){const t=n.createElement("link");return t.setAttribute("rel","stylesheet"),t.setAttribute("href",e),t}let vE=(()=>{class e{doc;appId;nonce;inline=new Map;external=new Map;hosts=new Set;isServer;constructor(t,r,i,o={}){this.doc=t,this.appId=r,this.nonce=i,this.isServer=nE(o),function Z2(e,n,t,r){const i=e.head?.querySelectorAll(`style[${Vc}="${n}"],link[${Vc}="${n}"]`);if(i)for(const o of i)o.removeAttribute(Vc),o instanceof HTMLLinkElement?r.set(o.href.slice(o.href.lastIndexOf("/")+1),{usage:0,elements:[o]}):o.textContent&&t.set(o.textContent,{usage:0,elements:[o]})}(t,r,this.inline,this.external),this.hosts.add(t.head)}addStyles(t,r){for(const i of t)this.addUsage(i,this.inline,mE);r?.forEach(i=>this.addUsage(i,this.external,gg))}removeStyles(t,r){for(const i of t)this.removeUsage(i,this.inline);r?.forEach(i=>this.removeUsage(i,this.external))}addUsage(t,r,i){const o=r.get(t);o?o.usage++:r.set(t,{usage:1,elements:[...this.hosts].map(s=>this.addElement(s,i(t,this.doc)))})}removeUsage(t,r){const i=r.get(t);i&&(i.usage--,i.usage<=0&&(pE(i.elements),r.delete(t)))}ngOnDestroy(){for(const[,{elements:t}]of[...this.inline,...this.external])pE(t);this.hosts.clear()}addHost(t){this.hosts.add(t);for(const[r,{elements:i}]of this.inline)i.push(this.addElement(t,mE(r,this.doc)));for(const[r,{elements:i}]of this.external)i.push(this.addElement(t,gg(r,this.doc)))}removeHost(t){this.hosts.delete(t)}addElement(t,r){return this.nonce&&r.setAttribute("nonce",this.nonce),this.isServer&&r.setAttribute(Vc,this.appId),t.appendChild(r)}static \u0275fac=function(r){return new(r||e)(se(li),se(qr),se(yv,8),se(Pi))};static \u0275prov=re({token:e,factory:e.\u0275fac})}return e})();const pg={svg:"http://www.w3.org/2000/svg",xhtml:"http://www.w3.org/1999/xhtml",xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/",math:"http://www.w3.org/1998/Math/MathML"},mg=/%COMP%/g,eH=new R("",{providedIn:"root",factory:()=>!0});function yE(e,n){return n.map(t=>t.replace(mg,e))}let CE=(()=>{class e{eventManager;sharedStylesHost;appId;removeStylesOnCompDestroy;doc;platformId;ngZone;nonce;tracingService;rendererByCompId=new Map;defaultRenderer;platformIsServer;constructor(t,r,i,o,s,a,l,c=null,u=null){this.eventManager=t,this.sharedStylesHost=r,this.appId=i,this.removeStylesOnCompDestroy=o,this.doc=s,this.platformId=a,this.ngZone=l,this.nonce=c,this.tracingService=u,this.platformIsServer=nE(a),this.defaultRenderer=new vg(t,s,l,this.platformIsServer,this.tracingService)}createRenderer(t,r){if(!t||!r)return this.defaultRenderer;this.platformIsServer&&r.encapsulation===Zt.ShadowDom&&(r={...r,encapsulation:Zt.Emulated});const i=this.getOrCreateRenderer(t,r);return i instanceof DE?i.applyToHost(t):i instanceof _g&&i.applyStyles(),i}getOrCreateRenderer(t,r){const i=this.rendererByCompId;let o=i.get(r.id);if(!o){const s=this.doc,a=this.ngZone,l=this.eventManager,c=this.sharedStylesHost,u=this.removeStylesOnCompDestroy,d=this.platformIsServer,g=this.tracingService;switch(r.encapsulation){case Zt.Emulated:o=new DE(l,c,r,this.appId,u,s,a,d,g);break;case Zt.ShadowDom:return new iH(l,c,t,r,s,a,this.nonce,d,g);default:o=new _g(l,c,r,u,s,a,d,g)}i.set(r.id,o)}return o}ngOnDestroy(){this.rendererByCompId.clear()}componentReplaced(t){this.rendererByCompId.delete(t)}static \u0275fac=function(r){return new(r||e)(se(hE),se(vE),se(qr),se(eH),se(li),se(Pi),se(de),se(yv),se(Hi,8))};static \u0275prov=re({token:e,factory:e.\u0275fac})}return e})();class vg{eventManager;doc;ngZone;platformIsServer;tracingService;data=Object.create(null);throwOnSyntheticProps=!0;constructor(n,t,r,i,o){this.eventManager=n,this.doc=t,this.ngZone=r,this.platformIsServer=i,this.tracingService=o}destroy(){}destroyNode=null;createElement(n,t){return t?this.doc.createElementNS(pg[t]||t,n):this.doc.createElement(n)}createComment(n){return this.doc.createComment(n)}createText(n){return this.doc.createTextNode(n)}appendChild(n,t){(wE(n)?n.content:n).appendChild(t)}insertBefore(n,t,r){n&&(wE(n)?n.content:n).insertBefore(t,r)}removeChild(n,t){t.remove()}selectRootElement(n,t){let r="string"==typeof n?this.doc.querySelector(n):n;if(!r)throw new N(-5104,!1);return t||(r.textContent=""),r}parentNode(n){return n.parentNode}nextSibling(n){return n.nextSibling}setAttribute(n,t,r,i){if(i){t=i+":"+t;const o=pg[i];o?n.setAttributeNS(o,t,r):n.setAttribute(t,r)}else n.setAttribute(t,r)}removeAttribute(n,t,r){if(r){const i=pg[r];i?n.removeAttributeNS(i,t):n.removeAttribute(`${r}:${t}`)}else n.removeAttribute(t)}addClass(n,t){n.classList.add(t)}removeClass(n,t){n.classList.remove(t)}setStyle(n,t,r,i){i&(sr.DashCase|sr.Important)?n.style.setProperty(t,r,i&sr.Important?"important":""):n.style[t]=r}removeStyle(n,t,r){r&sr.DashCase?n.style.removeProperty(t):n.style[t]=""}setProperty(n,t,r){null!=n&&(n[t]=r)}setValue(n,t){n.nodeValue=t}listen(n,t,r,i){if("string"==typeof n&&!(n=Qs().getGlobalEventTarget(this.doc,n)))throw new Error(`Unsupported event target ${n} for event ${t}`);let o=this.decoratePreventDefault(r);return null!==this.tracingService&&this.tracingService.wrapEventListener&&(o=this.tracingService.wrapEventListener(n,t,o)),this.eventManager.addEventListener(n,t,o,i)}decoratePreventDefault(n){return t=>{if("__ngUnwrap__"===t)return n;!1===(this.platformIsServer?this.ngZone.runGuarded(()=>n(t)):n(t))&&t.preventDefault()}}}function wE(e){return"TEMPLATE"===e.tagName&&void 0!==e.content}class iH extends vg{sharedStylesHost;hostEl;shadowRoot;constructor(n,t,r,i,o,s,a,l,c){super(n,o,s,l,c),this.sharedStylesHost=t,this.hostEl=r,this.shadowRoot=r.attachShadow({mode:"open"}),this.sharedStylesHost.addHost(this.shadowRoot);let u=i.styles;u=yE(i.id,u);for(const g of u){const h=document.createElement("style");a&&h.setAttribute("nonce",a),h.textContent=g,this.shadowRoot.appendChild(h)}const d=i.getExternalStyles?.();if(d)for(const g of d){const h=gg(g,o);a&&h.setAttribute("nonce",a),this.shadowRoot.appendChild(h)}}nodeOrShadowRoot(n){return n===this.hostEl?this.shadowRoot:n}appendChild(n,t){return super.appendChild(this.nodeOrShadowRoot(n),t)}insertBefore(n,t,r){return super.insertBefore(this.nodeOrShadowRoot(n),t,r)}removeChild(n,t){return super.removeChild(null,t)}parentNode(n){return this.nodeOrShadowRoot(super.parentNode(this.nodeOrShadowRoot(n)))}destroy(){this.sharedStylesHost.removeHost(this.shadowRoot)}}class _g extends vg{sharedStylesHost;removeStylesOnCompDestroy;styles;styleUrls;constructor(n,t,r,i,o,s,a,l,c){super(n,o,s,a,l),this.sharedStylesHost=t,this.removeStylesOnCompDestroy=i;let u=r.styles;this.styles=c?yE(c,u):u,this.styleUrls=r.getExternalStyles?.(c)}applyStyles(){this.sharedStylesHost.addStyles(this.styles,this.styleUrls)}destroy(){this.removeStylesOnCompDestroy&&this.sharedStylesHost.removeStyles(this.styles,this.styleUrls)}}class DE extends _g{contentAttr;hostAttr;constructor(n,t,r,i,o,s,a,l,c){const u=i+"-"+r.id;super(n,t,r,o,s,a,l,c,u),this.contentAttr=function tH(e){return"_ngcontent-%COMP%".replace(mg,e)}(u),this.hostAttr=function nH(e){return"_nghost-%COMP%".replace(mg,e)}(u)}applyToHost(n){this.applyStyles(),this.setAttribute(n,this.hostAttr,"")}createElement(n,t){const r=super.createElement(n,t);return super.setAttribute(r,this.contentAttr,""),r}}let oH=(()=>{class e extends gE{constructor(t){super(t)}supports(t){return!0}addEventListener(t,r,i,o){return t.addEventListener(r,i,o),()=>this.removeEventListener(t,r,i,o)}removeEventListener(t,r,i,o){return t.removeEventListener(r,i,o)}static \u0275fac=function(r){return new(r||e)(se(li))};static \u0275prov=re({token:e,factory:e.\u0275fac})}return e})();const bE=["alt","control","meta","shift"],sH={"\b":"Backspace","\t":"Tab","\x7f":"Delete","\x1b":"Escape",Del:"Delete",Esc:"Escape",Left:"ArrowLeft",Right:"ArrowRight",Up:"ArrowUp",Down:"ArrowDown",Menu:"ContextMenu",Scroll:"ScrollLock",Win:"OS"},aH={alt:e=>e.altKey,control:e=>e.ctrlKey,meta:e=>e.metaKey,shift:e=>e.shiftKey};let lH=(()=>{class e extends gE{constructor(t){super(t)}supports(t){return null!=e.parseEventName(t)}addEventListener(t,r,i,o){const s=e.parseEventName(r),a=e.eventCallback(s.fullKey,i,this.manager.getZone());return this.manager.getZone().runOutsideAngular(()=>Qs().onAndCancel(t,s.domEventName,a,o))}static parseEventName(t){const r=t.toLowerCase().split("."),i=r.shift();if(0===r.length||"keydown"!==i&&"keyup"!==i)return null;const o=e._normalizeKey(r.pop());let s="",a=r.indexOf("code");if(a>-1&&(r.splice(a,1),s="code."),bE.forEach(c=>{const u=r.indexOf(c);u>-1&&(r.splice(u,1),s+=c+".")}),s+=o,0!=r.length||0===o.length)return null;const l={};return l.domEventName=i,l.fullKey=s,l}static matchEventFullKeyCode(t,r){let i=sH[t.key]||t.key,o="";return r.indexOf("code.")>-1&&(i=t.code,o="code."),!(null==i||!i)&&(i=i.toLowerCase()," "===i?i="space":"."===i&&(i="dot"),bE.forEach(s=>{s!==i&&(0,aH[s])(t)&&(o+=s+".")}),o+=i,o===r)}static eventCallback(t,r,i){return o=>{e.matchEventFullKeyCode(o,t)&&i.runGuarded(()=>r(o))}}static _normalizeKey(t){return"esc"===t?"escape":t}static \u0275fac=function(r){return new(r||e)(se(li))};static \u0275prov=re({token:e,factory:e.\u0275fac})}return e})();const fH=qD(ZL,"browser",[{provide:Pi,useValue:"browser"},{provide:Ed,useValue:function cH(){fg.makeCurrent()},multi:!0},{provide:li,useFactory:function dH(){return function sS(e){bd=e}(document),document},deps:[]}]),ME=[{provide:Ql,useClass:class q2{addToWindow(n){Ie.getAngularTestability=(r,i=!0)=>{const o=n.findTestabilityInTree(r,i);if(null==o)throw new N(5103,!1);return o},Ie.getAllAngularTestabilities=()=>n.getAllTestabilities(),Ie.getAllAngularRootElements=()=>n.getAllRootElements(),Ie.frameworkStabilizers||(Ie.frameworkStabilizers=[]),Ie.frameworkStabilizers.push(r=>{const i=Ie.getAllAngularTestabilities();let o=i.length;const s=function(){o--,0==o&&r()};i.forEach(a=>{a.whenStable(s)})})}findTestabilityInTree(n,t,r){return null==t?null:n.getTestability(t)??(r?Qs().isShadowRoot(t)?this.findTestabilityInTree(n,t.host,!0):this.findTestabilityInTree(n,t.parentElement,!0):null)}},deps:[]},{provide:TC,useClass:sh,deps:[de,ah,Ql]},{provide:sh,useClass:sh,deps:[de,ah,Ql]}],TE=[{provide:Lu,useValue:"root"},{provide:_n,useFactory:function uH(){return new _n},deps:[]},{provide:hg,useClass:oH,multi:!0,deps:[li,de,Pi]},{provide:hg,useClass:lH,multi:!0,deps:[li]},CE,vE,hE,{provide:Vf,useExisting:CE},{provide:class p2{},useClass:W2,deps:[]},[]];let hH=(()=>{class e{constructor(){}static \u0275fac=function(r){return new(r||e)};static \u0275mod=cr({type:e});static \u0275inj=Nn({providers:[...TE,...ME],imports:[eE,QL]})}return e})();function vr(e){return this instanceof vr?(this.v=e,this):new vr(e)}function RE(e){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var t,n=e[Symbol.asyncIterator];return n?n.call(e):(e=function Dg(e){var n="function"==typeof Symbol&&Symbol.iterator,t=n&&e[n],r=0;if(t)return t.call(e);if(e&&"number"==typeof e.length)return{next:function(){return e&&r>=e.length&&(e=void 0),{value:e&&e[r++],done:!e}}};throw new TypeError(n?"Object is not iterable.":"Symbol.iterator is not defined.")}(e),t={},r("next"),r("throw"),r("return"),t[Symbol.asyncIterator]=function(){return this},t);function r(o){t[o]=e[o]&&function(s){return new Promise(function(a,l){!function i(o,s,a,l){Promise.resolve(l).then(function(c){o({value:c,done:a})},s)}(a,l,(s=e[o](s)).done,s.value)})}}}"function"==typeof SuppressedError&&SuppressedError;const kE=e=>e&&"number"==typeof e.length&&"function"!=typeof e;function FE(e){return Be(e?.then)}function LE(e){return Be(e[hu])}function PE(e){return Symbol.asyncIterator&&Be(e?.[Symbol.asyncIterator])}function VE(e){return new TypeError(`You provided ${null!==e&&"object"==typeof e?"an invalid object":`'${e}'`} where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.`)}const HE=function $H(){return"function"==typeof Symbol&&Symbol.iterator?Symbol.iterator:"@@iterator"}();function BE(e){return Be(e?.[HE])}function jE(e){return function AE(e,n,t){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var i,r=t.apply(e,n||[]),o=[];return i=Object.create(("function"==typeof AsyncIterator?AsyncIterator:Object).prototype),a("next"),a("throw"),a("return",function s(h){return function(m){return Promise.resolve(m).then(h,d)}}),i[Symbol.asyncIterator]=function(){return this},i;function a(h,m){r[h]&&(i[h]=function(C){return new Promise(function(E,I){o.push([h,C,E,I])>1||l(h,C)})},m&&(i[h]=m(i[h])))}function l(h,m){try{!function c(h){h.value instanceof vr?Promise.resolve(h.value.v).then(u,d):g(o[0][2],h)}(r[h](m))}catch(C){g(o[0][3],C)}}function u(h){l("next",h)}function d(h){l("throw",h)}function g(h,m){h(m),o.shift(),o.length&&l(o[0][0],o[0][1])}}(this,arguments,function*(){const t=e.getReader();try{for(;;){const{value:r,done:i}=yield vr(t.read());if(i)return yield vr(void 0);yield yield vr(r)}}finally{t.releaseLock()}})}function UE(e){return Be(e?.getReader)}function ta(e){if(e instanceof kt)return e;if(null!=e){if(LE(e))return function zH(e){return new kt(n=>{const t=e[hu]();if(Be(t.subscribe))return t.subscribe(n);throw new TypeError("Provided object does not correctly implement Symbol.observable")})}(e);if(kE(e))return function GH(e){return new kt(n=>{for(let t=0;t{e.then(t=>{n.closed||(n.next(t),n.complete())},t=>n.error(t)).then(null,pp)})}(e);if(PE(e))return $E(e);if(BE(e))return function WH(e){return new kt(n=>{for(const t of e)if(n.next(t),n.closed)return;n.complete()})}(e);if(UE(e))return function ZH(e){return $E(jE(e))}(e)}throw VE(e)}function $E(e){return new kt(n=>{(function QH(e,n){var t,r,i,o;return function xE(e,n,t,r){return new(t||(t=Promise))(function(o,s){function a(u){try{c(r.next(u))}catch(d){s(d)}}function l(u){try{c(r.throw(u))}catch(d){s(d)}}function c(u){u.done?o(u.value):function i(o){return o instanceof t?o:new t(function(s){s(o)})}(u.value).then(a,l)}c((r=r.apply(e,n||[])).next())})}(this,void 0,void 0,function*(){try{for(t=RE(e);!(r=yield t.next()).done;)if(n.next(r.value),n.closed)return}catch(s){i={error:s}}finally{try{r&&!r.done&&(o=t.return)&&(yield o.call(t))}finally{if(i)throw i.error}}n.complete()})})(e,n).catch(t=>n.error(t))})}function ui(e,n,t,r=0,i=!1){const o=n.schedule(function(){t(),i?e.add(this.schedule(null,r)):this.unsubscribe()},r);if(e.add(o),!i)return o}function zE(e,n=0){return Nr((t,r)=>{t.subscribe(qn(r,i=>ui(r,e,()=>r.next(i),n),()=>ui(r,e,()=>r.complete(),n),i=>ui(r,e,()=>r.error(i),n)))})}function GE(e,n=0){return Nr((t,r)=>{r.add(e.schedule(()=>t.subscribe(r),n))})}function qE(e,n){if(!e)throw new Error("Iterable cannot be null");return new kt(t=>{ui(t,n,()=>{const r=e[Symbol.asyncIterator]();ui(t,n,()=>{r.next().then(i=>{i.done?t.complete():t.next(i.value)})},0,!0)})})}const{isArray:rB}=Array,{getPrototypeOf:iB,prototype:oB,keys:sB}=Object;const{isArray:uB}=Array;function hB(e,n){return e.reduce((t,r,i)=>(t[r]=n[i],t),{})}function gB(...e){const n=function cB(e){return Be(function Eg(e){return e[e.length-1]}(e))?e.pop():void 0}(e),{args:t,keys:r}=function aB(e){if(1===e.length){const n=e[0];if(rB(n))return{args:n,keys:null};if(function lB(e){return e&&"object"==typeof e&&iB(e)===oB}(n)){const t=sB(n);return{args:t.map(r=>n[r]),keys:t}}}return{args:e,keys:null}}(e),i=new kt(o=>{const{length:s}=t;if(!s)return void o.complete();const a=new Array(s);let l=s,c=s;for(let u=0;u{d||(d=!0,c--),a[u]=g},()=>l--,void 0,()=>{(!l||!d)&&(c||o.next(r?hB(r,a):a),o.complete())}))}});return n?i.pipe(function fB(e){return pu(n=>function dB(e,n){return uB(n)?e(...n):e(n)}(e,n))}(n)):i}let WE=(()=>{class e{_renderer;_elementRef;onChange=t=>{};onTouched=()=>{};constructor(t,r){this._renderer=t,this._elementRef=r}setProperty(t,r){this._renderer.setProperty(this._elementRef.nativeElement,t,r)}registerOnTouched(t){this.onTouched=t}registerOnChange(t){this.onChange=t}setDisabledState(t){this.setProperty("disabled",t)}static \u0275fac=function(r){return new(r||e)(T(on),T(pt))};static \u0275dir=Y({type:e})}return e})(),di=(()=>{class e extends WE{static \u0275fac=(()=>{let t;return function(i){return(t||(t=lt(e)))(i||e)}})();static \u0275dir=Y({type:e,features:[ue]})}return e})();const dn=new R(""),pB={provide:dn,useExisting:ve(()=>Ig),multi:!0};let Ig=(()=>{class e extends di{writeValue(t){this.setProperty("checked",t)}static \u0275fac=(()=>{let t;return function(i){return(t||(t=lt(e)))(i||e)}})();static \u0275dir=Y({type:e,selectors:[["input","type","checkbox","formControlName",""],["input","type","checkbox","formControl",""],["input","type","checkbox","ngModel",""]],hostBindings:function(r,i){1&r&&q("change",function(s){return i.onChange(s.target.checked)})("blur",function(){return i.onTouched()})},standalone:!1,features:[Me([pB]),ue]})}return e})();const mB={provide:dn,useExisting:ve(()=>na),multi:!0},_B=new R("");let na=(()=>{class e extends WE{_compositionMode;_composing=!1;constructor(t,r,i){super(t,r),this._compositionMode=i,null==this._compositionMode&&(this._compositionMode=!function vB(){const e=Qs()?Qs().getUserAgent():"";return/android (\d+)/.test(e.toLowerCase())}())}writeValue(t){this.setProperty("value",t??"")}_handleInput(t){(!this._compositionMode||this._compositionMode&&!this._composing)&&this.onChange(t)}_compositionStart(){this._composing=!0}_compositionEnd(t){this._composing=!1,this._compositionMode&&this.onChange(t)}static \u0275fac=function(r){return new(r||e)(T(on),T(pt),T(_B,8))};static \u0275dir=Y({type:e,selectors:[["input","formControlName","",3,"type","checkbox"],["textarea","formControlName",""],["input","formControl","",3,"type","checkbox"],["textarea","formControl",""],["input","ngModel","",3,"type","checkbox"],["textarea","ngModel",""],["","ngDefaultControl",""]],hostBindings:function(r,i){1&r&&q("input",function(s){return i._handleInput(s.target.value)})("blur",function(){return i.onTouched()})("compositionstart",function(){return i._compositionStart()})("compositionend",function(s){return i._compositionEnd(s.target.value)})},standalone:!1,features:[Me([mB]),ue]})}return e})();const ct=new R(""),yr=new R("");function rI(e){return null!=e}function iI(e){return Yl(e)?function nB(e,n){return n?function tB(e,n){if(null!=e){if(LE(e))return function YH(e,n){return ta(e).pipe(GE(n),zE(n))}(e,n);if(kE(e))return function JH(e,n){return new kt(t=>{let r=0;return n.schedule(function(){r===e.length?t.complete():(t.next(e[r++]),t.closed||this.schedule())})})}(e,n);if(FE(e))return function KH(e,n){return ta(e).pipe(GE(n),zE(n))}(e,n);if(PE(e))return qE(e,n);if(BE(e))return function XH(e,n){return new kt(t=>{let r;return ui(t,n,()=>{r=e[HE](),ui(t,n,()=>{let i,o;try{({value:i,done:o}=r.next())}catch(s){return void t.error(s)}o?t.complete():t.next(i)},0,!0)}),()=>Be(r?.return)&&r.return()})}(e,n);if(UE(e))return function eB(e,n){return qE(jE(e),n)}(e,n)}throw VE(e)}(e,n):ta(e)}(e):e}function oI(e){let n={};return e.forEach(t=>{n=null!=t?{...n,...t}:n}),0===Object.keys(n).length?null:n}function sI(e,n){return n.map(t=>t(e))}function aI(e){return e.map(n=>function CB(e){return!e.validate}(n)?n:t=>n.validate(t))}function Mg(e){return null!=e?function lI(e){if(!e)return null;const n=e.filter(rI);return 0==n.length?null:function(t){return oI(sI(t,n))}}(aI(e)):null}function Tg(e){return null!=e?function cI(e){if(!e)return null;const n=e.filter(rI);return 0==n.length?null:function(t){return gB(sI(t,n).map(iI)).pipe(pu(oI))}}(aI(e)):null}function uI(e,n){return null===e?[n]:Array.isArray(e)?[...e,n]:[e,n]}function Sg(e){return e?Array.isArray(e)?e:[e]:[]}function Bc(e,n){return Array.isArray(e)?e.includes(n):e===n}function hI(e,n){const t=Sg(n);return Sg(e).forEach(i=>{Bc(t,i)||t.push(i)}),t}function gI(e,n){return Sg(n).filter(t=>!Bc(e,t))}class pI{get value(){return this.control?this.control.value:null}get valid(){return this.control?this.control.valid:null}get invalid(){return this.control?this.control.invalid:null}get pending(){return this.control?this.control.pending:null}get disabled(){return this.control?this.control.disabled:null}get enabled(){return this.control?this.control.enabled:null}get errors(){return this.control?this.control.errors:null}get pristine(){return this.control?this.control.pristine:null}get dirty(){return this.control?this.control.dirty:null}get touched(){return this.control?this.control.touched:null}get status(){return this.control?this.control.status:null}get untouched(){return this.control?this.control.untouched:null}get statusChanges(){return this.control?this.control.statusChanges:null}get valueChanges(){return this.control?this.control.valueChanges:null}get path(){return null}_composedValidatorFn;_composedAsyncValidatorFn;_rawValidators=[];_rawAsyncValidators=[];_setValidators(n){this._rawValidators=n||[],this._composedValidatorFn=Mg(this._rawValidators)}_setAsyncValidators(n){this._rawAsyncValidators=n||[],this._composedAsyncValidatorFn=Tg(this._rawAsyncValidators)}get validator(){return this._composedValidatorFn||null}get asyncValidator(){return this._composedAsyncValidatorFn||null}_onDestroyCallbacks=[];_registerOnDestroy(n){this._onDestroyCallbacks.push(n)}_invokeOnDestroyCallbacks(){this._onDestroyCallbacks.forEach(n=>n()),this._onDestroyCallbacks=[]}reset(n=void 0){this.control&&this.control.reset(n)}hasError(n,t){return!!this.control&&this.control.hasError(n,t)}getError(n,t){return this.control?this.control.getError(n,t):null}}class Dt extends pI{name;get formDirective(){return null}get path(){return null}}class Cr extends pI{_parent=null;name=null;valueAccessor=null}class mI{_cd;constructor(n){this._cd=n}get isTouched(){return this._cd?.control?._touched?.(),!!this._cd?.control?.touched}get isUntouched(){return!!this._cd?.control?.untouched}get isPristine(){return this._cd?.control?._pristine?.(),!!this._cd?.control?.pristine}get isDirty(){return!!this._cd?.control?.dirty}get isValid(){return this._cd?.control?._status?.(),!!this._cd?.control?.valid}get isInvalid(){return!!this._cd?.control?.invalid}get isPending(){return!!this._cd?.control?.pending}get isSubmitted(){return this._cd?._submitted?.(),!!this._cd?.submitted}}let jc=(()=>{class e extends mI{constructor(t){super(t)}static \u0275fac=function(r){return new(r||e)(T(Cr,2))};static \u0275dir=Y({type:e,selectors:[["","formControlName",""],["","ngModel",""],["","formControl",""]],hostVars:14,hostBindings:function(r,i){2&r&&jn("ng-untouched",i.isUntouched)("ng-touched",i.isTouched)("ng-pristine",i.isPristine)("ng-dirty",i.isDirty)("ng-valid",i.isValid)("ng-invalid",i.isInvalid)("ng-pending",i.isPending)},standalone:!1,features:[ue]})}return e})();const ra="VALID",$c="INVALID",Eo="PENDING",ia="DISABLED";class Io{}class _I extends Io{value;source;constructor(n,t){super(),this.value=n,this.source=t}}class Og extends Io{pristine;source;constructor(n,t){super(),this.pristine=n,this.source=t}}class Ag extends Io{touched;source;constructor(n,t){super(),this.touched=n,this.source=t}}class zc extends Io{status;source;constructor(n,t){super(),this.status=n,this.source=t}}function Gc(e){return null!=e&&!Array.isArray(e)&&"object"==typeof e}class Fg{_pendingDirty=!1;_hasOwnPendingAsyncValidator=null;_pendingTouched=!1;_onCollectionChange=()=>{};_updateOn;_parent=null;_asyncValidationSubscription;_composedValidatorFn;_composedAsyncValidatorFn;_rawValidators;_rawAsyncValidators;value;constructor(n,t){this._assignValidators(n),this._assignAsyncValidators(t)}get validator(){return this._composedValidatorFn}set validator(n){this._rawValidators=this._composedValidatorFn=n}get asyncValidator(){return this._composedAsyncValidatorFn}set asyncValidator(n){this._rawAsyncValidators=this._composedAsyncValidatorFn=n}get parent(){return this._parent}get status(){return it(this.statusReactive)}set status(n){it(()=>this.statusReactive.set(n))}_status=Mn(()=>this.statusReactive());statusReactive=Gr(void 0);get valid(){return this.status===ra}get invalid(){return this.status===$c}get pending(){return this.status==Eo}get disabled(){return this.status===ia}get enabled(){return this.status!==ia}errors;get pristine(){return it(this.pristineReactive)}set pristine(n){it(()=>this.pristineReactive.set(n))}_pristine=Mn(()=>this.pristineReactive());pristineReactive=Gr(!0);get dirty(){return!this.pristine}get touched(){return it(this.touchedReactive)}set touched(n){it(()=>this.touchedReactive.set(n))}_touched=Mn(()=>this.touchedReactive());touchedReactive=Gr(!1);get untouched(){return!this.touched}_events=new fn;events=this._events.asObservable();valueChanges;statusChanges;get updateOn(){return this._updateOn?this._updateOn:this.parent?this.parent.updateOn:"change"}setValidators(n){this._assignValidators(n)}setAsyncValidators(n){this._assignAsyncValidators(n)}addValidators(n){this.setValidators(hI(n,this._rawValidators))}addAsyncValidators(n){this.setAsyncValidators(hI(n,this._rawAsyncValidators))}removeValidators(n){this.setValidators(gI(n,this._rawValidators))}removeAsyncValidators(n){this.setAsyncValidators(gI(n,this._rawAsyncValidators))}hasValidator(n){return Bc(this._rawValidators,n)}hasAsyncValidator(n){return Bc(this._rawAsyncValidators,n)}clearValidators(){this.validator=null}clearAsyncValidators(){this.asyncValidator=null}markAsTouched(n={}){const t=!1===this.touched;this.touched=!0;const r=n.sourceControl??this;this._parent&&!n.onlySelf&&this._parent.markAsTouched({...n,sourceControl:r}),t&&!1!==n.emitEvent&&this._events.next(new Ag(!0,r))}markAllAsTouched(n={}){this.markAsTouched({onlySelf:!0,emitEvent:n.emitEvent,sourceControl:this}),this._forEachChild(t=>t.markAllAsTouched(n))}markAsUntouched(n={}){const t=!0===this.touched;this.touched=!1,this._pendingTouched=!1;const r=n.sourceControl??this;this._forEachChild(i=>{i.markAsUntouched({onlySelf:!0,emitEvent:n.emitEvent,sourceControl:r})}),this._parent&&!n.onlySelf&&this._parent._updateTouched(n,r),t&&!1!==n.emitEvent&&this._events.next(new Ag(!1,r))}markAsDirty(n={}){const t=!0===this.pristine;this.pristine=!1;const r=n.sourceControl??this;this._parent&&!n.onlySelf&&this._parent.markAsDirty({...n,sourceControl:r}),t&&!1!==n.emitEvent&&this._events.next(new Og(!1,r))}markAsPristine(n={}){const t=!1===this.pristine;this.pristine=!0,this._pendingDirty=!1;const r=n.sourceControl??this;this._forEachChild(i=>{i.markAsPristine({onlySelf:!0,emitEvent:n.emitEvent})}),this._parent&&!n.onlySelf&&this._parent._updatePristine(n,r),t&&!1!==n.emitEvent&&this._events.next(new Og(!0,r))}markAsPending(n={}){this.status=Eo;const t=n.sourceControl??this;!1!==n.emitEvent&&(this._events.next(new zc(this.status,t)),this.statusChanges.emit(this.status)),this._parent&&!n.onlySelf&&this._parent.markAsPending({...n,sourceControl:t})}disable(n={}){const t=this._parentMarkedDirty(n.onlySelf);this.status=ia,this.errors=null,this._forEachChild(i=>{i.disable({...n,onlySelf:!0})}),this._updateValue();const r=n.sourceControl??this;!1!==n.emitEvent&&(this._events.next(new _I(this.value,r)),this._events.next(new zc(this.status,r)),this.valueChanges.emit(this.value),this.statusChanges.emit(this.status)),this._updateAncestors({...n,skipPristineCheck:t},this),this._onDisabledChange.forEach(i=>i(!0))}enable(n={}){const t=this._parentMarkedDirty(n.onlySelf);this.status=ra,this._forEachChild(r=>{r.enable({...n,onlySelf:!0})}),this.updateValueAndValidity({onlySelf:!0,emitEvent:n.emitEvent}),this._updateAncestors({...n,skipPristineCheck:t},this),this._onDisabledChange.forEach(r=>r(!1))}_updateAncestors(n,t){this._parent&&!n.onlySelf&&(this._parent.updateValueAndValidity(n),n.skipPristineCheck||this._parent._updatePristine({},t),this._parent._updateTouched({},t))}setParent(n){this._parent=n}getRawValue(){return this.value}updateValueAndValidity(n={}){if(this._setInitialStatus(),this._updateValue(),this.enabled){const r=this._cancelExistingSubscription();this.errors=this._runValidator(),this.status=this._calculateStatus(),(this.status===ra||this.status===Eo)&&this._runAsyncValidator(r,n.emitEvent)}const t=n.sourceControl??this;!1!==n.emitEvent&&(this._events.next(new _I(this.value,t)),this._events.next(new zc(this.status,t)),this.valueChanges.emit(this.value),this.statusChanges.emit(this.status)),this._parent&&!n.onlySelf&&this._parent.updateValueAndValidity({...n,sourceControl:t})}_updateTreeValidity(n={emitEvent:!0}){this._forEachChild(t=>t._updateTreeValidity(n)),this.updateValueAndValidity({onlySelf:!0,emitEvent:n.emitEvent})}_setInitialStatus(){this.status=this._allControlsDisabled()?ia:ra}_runValidator(){return this.validator?this.validator(this):null}_runAsyncValidator(n,t){if(this.asyncValidator){this.status=Eo,this._hasOwnPendingAsyncValidator={emitEvent:!1!==t};const r=iI(this.asyncValidator(this));this._asyncValidationSubscription=r.subscribe(i=>{this._hasOwnPendingAsyncValidator=null,this.setErrors(i,{emitEvent:t,shouldHaveEmitted:n})})}}_cancelExistingSubscription(){if(this._asyncValidationSubscription){this._asyncValidationSubscription.unsubscribe();const n=this._hasOwnPendingAsyncValidator?.emitEvent??!1;return this._hasOwnPendingAsyncValidator=null,n}return!1}setErrors(n,t={}){this.errors=n,this._updateControlsErrors(!1!==t.emitEvent,this,t.shouldHaveEmitted)}get(n){let t=n;return null==t||(Array.isArray(t)||(t=t.split(".")),0===t.length)?null:t.reduce((r,i)=>r&&r._find(i),this)}getError(n,t){const r=t?this.get(t):this;return r&&r.errors?r.errors[n]:null}hasError(n,t){return!!this.getError(n,t)}get root(){let n=this;for(;n._parent;)n=n._parent;return n}_updateControlsErrors(n,t,r){this.status=this._calculateStatus(),n&&this.statusChanges.emit(this.status),(n||r)&&this._events.next(new zc(this.status,t)),this._parent&&this._parent._updateControlsErrors(n,t,r)}_initObservables(){this.valueChanges=new we,this.statusChanges=new we}_calculateStatus(){return this._allControlsDisabled()?ia:this.errors?$c:this._hasOwnPendingAsyncValidator||this._anyControlsHaveStatus(Eo)?Eo:this._anyControlsHaveStatus($c)?$c:ra}_anyControlsHaveStatus(n){return this._anyControls(t=>t.status===n)}_anyControlsDirty(){return this._anyControls(n=>n.dirty)}_anyControlsTouched(){return this._anyControls(n=>n.touched)}_updatePristine(n,t){const r=!this._anyControlsDirty(),i=this.pristine!==r;this.pristine=r,this._parent&&!n.onlySelf&&this._parent._updatePristine(n,t),i&&this._events.next(new Og(this.pristine,t))}_updateTouched(n={},t){this.touched=this._anyControlsTouched(),this._events.next(new Ag(this.touched,t)),this._parent&&!n.onlySelf&&this._parent._updateTouched(n,t)}_onDisabledChange=[];_registerOnCollectionChange(n){this._onCollectionChange=n}_setUpdateStrategy(n){Gc(n)&&null!=n.updateOn&&(this._updateOn=n.updateOn)}_parentMarkedDirty(n){return!n&&!(!this._parent||!this._parent.dirty)&&!this._parent._anyControlsDirty()}_find(n){return null}_assignValidators(n){this._rawValidators=Array.isArray(n)?n.slice():n,this._composedValidatorFn=function SB(e){return Array.isArray(e)?Mg(e):e||null}(this._rawValidators)}_assignAsyncValidators(n){this._rawAsyncValidators=Array.isArray(n)?n.slice():n,this._composedAsyncValidatorFn=function NB(e){return Array.isArray(e)?Tg(e):e||null}(this._rawAsyncValidators)}}const Mo=new R("",{providedIn:"root",factory:()=>qc}),qc="always";function oa(e,n,t=qc){(function Pg(e,n){const t=function dI(e){return e._rawValidators}(e);null!==n.validator?e.setValidators(uI(t,n.validator)):"function"==typeof t&&e.setValidators([t]);const r=function fI(e){return e._rawAsyncValidators}(e);null!==n.asyncValidator?e.setAsyncValidators(uI(r,n.asyncValidator)):"function"==typeof r&&e.setAsyncValidators([r]);const i=()=>e.updateValueAndValidity();Qc(n._rawValidators,i),Qc(n._rawAsyncValidators,i)})(e,n),n.valueAccessor.writeValue(e.value),(e.disabled||"always"===t)&&n.valueAccessor.setDisabledState?.(e.disabled),function AB(e,n){n.valueAccessor.registerOnChange(t=>{e._pendingValue=t,e._pendingChange=!0,e._pendingDirty=!0,"change"===e.updateOn&&wI(e,n)})}(e,n),function kB(e,n){const t=(r,i)=>{n.valueAccessor.writeValue(r),i&&n.viewToModelUpdate(r)};e.registerOnChange(t),n._registerOnDestroy(()=>{e._unregisterOnChange(t)})}(e,n),function RB(e,n){n.valueAccessor.registerOnTouched(()=>{e._pendingTouched=!0,"blur"===e.updateOn&&e._pendingChange&&wI(e,n),"submit"!==e.updateOn&&e.markAsTouched()})}(e,n),function OB(e,n){if(n.valueAccessor.setDisabledState){const t=r=>{n.valueAccessor.setDisabledState(r)};e.registerOnDisabledChange(t),n._registerOnDestroy(()=>{e._unregisterOnDisabledChange(t)})}}(e,n)}function Qc(e,n){e.forEach(t=>{t.registerOnValidatorChange&&t.registerOnValidatorChange(n)})}function wI(e,n){e._pendingDirty&&e.markAsDirty(),e.setValue(e._pendingValue,{emitModelToViewChange:!1}),n.viewToModelUpdate(e._pendingValue),e._pendingChange=!1}function EI(e,n){const t=e.indexOf(n);t>-1&&e.splice(t,1)}function II(e){return"object"==typeof e&&null!==e&&2===Object.keys(e).length&&"value"in e&&"disabled"in e}Promise.resolve();const MI=class extends Fg{defaultValue=null;_onChange=[];_pendingValue;_pendingChange=!1;constructor(n=null,t,r){super(function Rg(e){return(Gc(e)?e.validators:e)||null}(t),function kg(e,n){return(Gc(n)?n.asyncValidators:e)||null}(r,t)),this._applyFormState(n),this._setUpdateStrategy(t),this._initObservables(),this.updateValueAndValidity({onlySelf:!0,emitEvent:!!this.asyncValidator}),Gc(t)&&(t.nonNullable||t.initialValueIsDefault)&&(this.defaultValue=II(n)?n.value:n)}setValue(n,t={}){this.value=this._pendingValue=n,this._onChange.length&&!1!==t.emitModelToViewChange&&this._onChange.forEach(r=>r(this.value,!1!==t.emitViewToModelChange)),this.updateValueAndValidity(t)}patchValue(n,t={}){this.setValue(n,t)}reset(n=this.defaultValue,t={}){this._applyFormState(n),this.markAsPristine(t),this.markAsUntouched(t),this.setValue(this.value,t),this._pendingChange=!1}_updateValue(){}_anyControls(n){return!1}_allControlsDisabled(){return this.disabled}registerOnChange(n){this._onChange.push(n)}_unregisterOnChange(n){EI(this._onChange,n)}registerOnDisabledChange(n){this._onDisabledChange.push(n)}_unregisterOnDisabledChange(n){EI(this._onDisabledChange,n)}_forEachChild(n){}_syncPendingControls(){return!("submit"!==this.updateOn||(this._pendingDirty&&this.markAsDirty(),this._pendingTouched&&this.markAsTouched(),!this._pendingChange)||(this.setValue(this._pendingValue,{onlySelf:!0,emitModelToViewChange:!1}),0))}_applyFormState(n){II(n)?(this.value=this._pendingValue=n.value,n.disabled?this.disable({onlySelf:!0,emitEvent:!1}):this.enable({onlySelf:!0,emitEvent:!1})):this.value=this._pendingValue=n}},UB={provide:Cr,useExisting:ve(()=>aa)},NI=Promise.resolve();let aa=(()=>{class e extends Cr{_changeDetectorRef;callSetDisabledState;control=new MI;static ngAcceptInputType_isDisabled;_registered=!1;viewModel;name="";isDisabled;model;options;update=new we;constructor(t,r,i,o,s,a){super(),this._changeDetectorRef=s,this.callSetDisabledState=a,this._parent=t,this._setValidators(r),this._setAsyncValidators(i),this.valueAccessor=function Bg(e,n){if(!n)return null;let t,r,i;return Array.isArray(n),n.forEach(o=>{o.constructor===na?t=o:function PB(e){return Object.getPrototypeOf(e.constructor)===di}(o)?r=o:i=o}),i||r||t||null}(0,o)}ngOnChanges(t){if(this._checkForErrors(),!this._registered||"name"in t){if(this._registered&&(this._checkName(),this.formDirective)){const r=t.name.previousValue;this.formDirective.removeControl({name:r,path:this._getPath(r)})}this._setUpControl()}"isDisabled"in t&&this._updateDisabled(t),function Hg(e,n){if(!e.hasOwnProperty("model"))return!1;const t=e.model;return!!t.isFirstChange()||!Object.is(n,t.currentValue)}(t,this.viewModel)&&(this._updateValue(this.model),this.viewModel=this.model)}ngOnDestroy(){this.formDirective&&this.formDirective.removeControl(this)}get path(){return this._getPath(this.name)}get formDirective(){return this._parent?this._parent.formDirective:null}viewToModelUpdate(t){this.viewModel=t,this.update.emit(t)}_setUpControl(){this._setUpdateStrategy(),this._isStandalone()?this._setUpStandalone():this.formDirective.addControl(this),this._registered=!0}_setUpdateStrategy(){this.options&&null!=this.options.updateOn&&(this.control._updateOn=this.options.updateOn)}_isStandalone(){return!this._parent||!(!this.options||!this.options.standalone)}_setUpStandalone(){oa(this.control,this,this.callSetDisabledState),this.control.updateValueAndValidity({emitEvent:!1})}_checkForErrors(){this._checkName()}_checkParentType(){}_checkName(){this.options&&this.options.name&&(this.name=this.options.name),this._isStandalone()}_updateValue(t){NI.then(()=>{this.control.setValue(t,{emitViewToModelChange:!1}),this._changeDetectorRef?.markForCheck()})}_updateDisabled(t){const r=t.isDisabled.currentValue,i=0!==r&&function qh(e){return"boolean"==typeof e?e:null!=e&&"false"!==e}(r);NI.then(()=>{i&&!this.control.disabled?this.control.disable():!i&&this.control.disabled&&this.control.enable(),this._changeDetectorRef?.markForCheck()})}_getPath(t){return this._parent?function Wc(e,n){return[...n.path,e]}(t,this._parent):[t]}static \u0275fac=function(r){return new(r||e)(T(Dt,9),T(ct,10),T(yr,10),T(dn,10),T(si,8),T(Mo,8))};static \u0275dir=Y({type:e,selectors:[["","ngModel","",3,"formControlName","",3,"formControl",""]],inputs:{name:"name",isDisabled:[0,"disabled","isDisabled"],model:[0,"ngModel","model"],options:[0,"ngModelOptions","options"]},outputs:{update:"ngModelChange"},exportAs:["ngModel"],standalone:!1,features:[Me([UB]),ue,kn]})}return e})();const WB={provide:dn,useExisting:ve(()=>Ug),multi:!0};let Ug=(()=>{class e extends di{writeValue(t){this.setProperty("value",parseFloat(t))}registerOnChange(t){this.onChange=r=>{t(""==r?null:parseFloat(r))}}static \u0275fac=(()=>{let t;return function(i){return(t||(t=lt(e)))(i||e)}})();static \u0275dir=Y({type:e,selectors:[["input","type","range","formControlName",""],["input","type","range","formControl",""],["input","type","range","ngModel",""]],hostBindings:function(r,i){1&r&&q("change",function(s){return i.onChange(s.target.value)})("input",function(s){return i.onChange(s.target.value)})("blur",function(){return i.onTouched()})},standalone:!1,features:[Me([WB]),ue]})}return e})();const XB={provide:dn,useExisting:ve(()=>la),multi:!0};function LI(e,n){return null==e?`${n}`:(n&&"object"==typeof n&&(n="Object"),`${e}: ${n}`.slice(0,50))}let la=(()=>{class e extends di{value;_optionMap=new Map;_idCounter=0;set compareWith(t){this._compareWith=t}_compareWith=Object.is;writeValue(t){this.value=t;const i=LI(this._getOptionId(t),t);this.setProperty("value",i)}registerOnChange(t){this.onChange=r=>{this.value=this._getOptionValue(r),t(this.value)}}_registerOption(){return(this._idCounter++).toString()}_getOptionId(t){for(const r of this._optionMap.keys())if(this._compareWith(this._optionMap.get(r),t))return r;return null}_getOptionValue(t){const r=function ej(e){return e.split(":")[0]}(t);return this._optionMap.has(r)?this._optionMap.get(r):t}static \u0275fac=(()=>{let t;return function(i){return(t||(t=lt(e)))(i||e)}})();static \u0275dir=Y({type:e,selectors:[["select","formControlName","",3,"multiple",""],["select","formControl","",3,"multiple",""],["select","ngModel","",3,"multiple",""]],hostBindings:function(r,i){1&r&&q("change",function(s){return i.onChange(s.target.value)})("blur",function(){return i.onTouched()})},inputs:{compareWith:"compareWith"},standalone:!1,features:[Me([XB]),ue]})}return e})(),qg=(()=>{class e{_element;_renderer;_select;id;constructor(t,r,i){this._element=t,this._renderer=r,this._select=i,this._select&&(this.id=this._select._registerOption())}set ngValue(t){null!=this._select&&(this._select._optionMap.set(this.id,t),this._setElementValue(LI(this.id,t)),this._select.writeValue(this._select.value))}set value(t){this._setElementValue(t),this._select&&this._select.writeValue(this._select.value)}_setElementValue(t){this._renderer.setProperty(this._element.nativeElement,"value",t)}ngOnDestroy(){this._select&&(this._select._optionMap.delete(this.id),this._select.writeValue(this._select.value))}static \u0275fac=function(r){return new(r||e)(T(pt),T(on),T(la,9))};static \u0275dir=Y({type:e,selectors:[["option"]],inputs:{ngValue:"ngValue",value:"value"},standalone:!1})}return e})();const tj={provide:dn,useExisting:ve(()=>Wg),multi:!0};function PI(e,n){return null==e?`${n}`:("string"==typeof n&&(n=`'${n}'`),n&&"object"==typeof n&&(n="Object"),`${e}: ${n}`.slice(0,50))}let Wg=(()=>{class e extends di{value;_optionMap=new Map;_idCounter=0;set compareWith(t){this._compareWith=t}_compareWith=Object.is;writeValue(t){let r;if(this.value=t,Array.isArray(t)){const i=t.map(o=>this._getOptionId(o));r=(o,s)=>{o._setSelected(i.indexOf(s.toString())>-1)}}else r=(i,o)=>{i._setSelected(!1)};this._optionMap.forEach(r)}registerOnChange(t){this.onChange=r=>{const i=[],o=r.selectedOptions;if(void 0!==o){const s=o;for(let a=0;a{let t;return function(i){return(t||(t=lt(e)))(i||e)}})();static \u0275dir=Y({type:e,selectors:[["select","multiple","","formControlName",""],["select","multiple","","formControl",""],["select","multiple","","ngModel",""]],hostBindings:function(r,i){1&r&&q("change",function(s){return i.onChange(s.target)})("blur",function(){return i.onTouched()})},inputs:{compareWith:"compareWith"},standalone:!1,features:[Me([tj]),ue]})}return e})(),Zg=(()=>{class e{_element;_renderer;_select;id;_value;constructor(t,r,i){this._element=t,this._renderer=r,this._select=i,this._select&&(this.id=this._select._registerOption(this))}set ngValue(t){null!=this._select&&(this._value=t,this._setElementValue(PI(this.id,t)),this._select.writeValue(this._select.value))}set value(t){this._select?(this._value=t,this._setElementValue(PI(this.id,t)),this._select.writeValue(this._select.value)):this._setElementValue(t)}_setElementValue(t){this._renderer.setProperty(this._element.nativeElement,"value",t)}_setSelected(t){this._renderer.setProperty(this._element.nativeElement,"selected",t)}ngOnDestroy(){this._select&&(this._select._optionMap.delete(this.id),this._select.writeValue(this._select.value))}static \u0275fac=function(r){return new(r||e)(T(pt),T(on),T(Wg,9))};static \u0275dir=Y({type:e,selectors:[["option"]],inputs:{ngValue:"ngValue",value:"value"},standalone:!1})}return e})(),dj=(()=>{class e{static \u0275fac=function(r){return new(r||e)};static \u0275mod=cr({type:e});static \u0275inj=Nn({})}return e})(),hj=(()=>{class e{static withConfig(t){return{ngModule:e,providers:[{provide:Mo,useValue:t.callSetDisabledState??qc}]}}static \u0275fac=function(r){return new(r||e)};static \u0275mod=cr({type:e});static \u0275inj=Nn({imports:[dj]})}return e})();class gj extends Rt{constructor(n,t){super()}schedule(n,t=0){return this}}const Kc={setInterval(e,n,...t){const{delegate:r}=Kc;return r?.setInterval?r.setInterval(e,n,...t):setInterval(e,n,...t)},clearInterval(e){const{delegate:n}=Kc;return(n?.clearInterval||clearInterval)(e)},delegate:void 0},WI={now:()=>(WI.delegate||Date).now(),delegate:void 0};class ca{constructor(n,t=ca.now){this.schedulerActionCtor=n,this.now=t}schedule(n,t=0,r){return new this.schedulerActionCtor(this,n).schedule(r,t)}}ca.now=WI.now;const ZI=new class mj extends ca{constructor(n,t=ca.now){super(n,t),this.actions=[],this._active=!1}flush(n){const{actions:t}=this;if(this._active)return void t.push(n);let r;this._active=!0;do{if(r=n.execute(n.state,n.delay))break}while(n=t.shift());if(this._active=!1,r){for(;n=t.shift();)n.unsubscribe();throw r}}}(class pj extends gj{constructor(n,t){super(n,t),this.scheduler=n,this.work=t,this.pending=!1}schedule(n,t=0){var r;if(this.closed)return this;this.state=n;const i=this.id,o=this.scheduler;return null!=i&&(this.id=this.recycleAsyncId(o,i,t)),this.pending=!0,this.delay=t,this.id=null!==(r=this.id)&&void 0!==r?r:this.requestAsyncId(o,this.id,t),this}requestAsyncId(n,t,r=0){return Kc.setInterval(n.flush.bind(n,this),r)}recycleAsyncId(n,t,r=0){if(null!=r&&this.delay===r&&!1===this.pending)return t;null!=t&&Kc.clearInterval(t)}execute(n,t){if(this.closed)return new Error("executing a cancelled action");this.pending=!1;const r=this._execute(n,t);if(r)return r;!1===this.pending&&null!=this.id&&(this.id=this.recycleAsyncId(this.scheduler,this.id,null))}_execute(n,t){let i,r=!1;try{this.work(n)}catch(o){r=!0,i=o||new Error("Scheduled action threw falsy error")}if(r)return this.unsubscribe(),i}unsubscribe(){if(!this.closed){const{id:n,scheduler:t}=this,{actions:r}=t;this.work=this.state=this.scheduler=null,this.pending=!1,pa(r,this),null!=n&&(this.id=this.recycleAsyncId(t,n,null)),this.delay=null,super.unsubscribe()}}}),vj=ZI;function QI(e,n=ZI,t){const r=function wj(e=0,n,t=vj){let r=-1;return null!=n&&(function yj(e){return e&&Be(e.schedule)}(n)?t=n:r=n),new kt(i=>{let o=function Cj(e){return e instanceof Date&&!isNaN(e)}(e)?+e-t.now():e;o<0&&(o=0);let s=0;return t.schedule(function(){i.closed||(i.next(s++),0<=r?this.schedule(void 0,r):i.complete())},o)})}(e,n);return function _j(e,n){return Nr((t,r)=>{const{leading:i=!0,trailing:o=!1}=n??{};let s=!1,a=null,l=null,c=!1;const u=()=>{l?.unsubscribe(),l=null,o&&(h(),c&&r.complete())},d=()=>{l=null,c&&r.complete()},g=m=>l=ta(e(m)).subscribe(qn(r,u,d)),h=()=>{if(s){s=!1;const m=a;a=null,r.next(m),!c&&g(m)}};t.subscribe(qn(r,m=>{s=!0,a=m,(!l||l.closed)&&(i?h():g(m))},()=>{c=!0,(!(o&&s&&l)||l.closed)&&r.complete()}))})}(()=>r,t)}function YI(e,n,t){const r=Be(e)||n||t?{next:e,error:n,complete:t}:e;return r?Nr((i,o)=>{var s;null===(s=r.subscribe)||void 0===s||s.call(r);let a=!0;i.subscribe(qn(o,l=>{var c;null===(c=r.next)||void 0===c||c.call(r,l),o.next(l)},()=>{var l;a=!1,null===(l=r.complete)||void 0===l||l.call(r),o.complete()},l=>{var c;a=!1,null===(c=r.error)||void 0===c||c.call(r,l),o.error(l)},()=>{var l,c;a&&(null===(l=r.unsubscribe)||void 0===l||l.call(r)),null===(c=r.finalize)||void 0===c||c.call(r)}))}):gu}function KI(e,n=gu){return e=e??Dj,Nr((t,r)=>{let i,o=!0;t.subscribe(qn(r,s=>{const a=n(s);(o||!e(i,a))&&(o=!1,i=a,r.next(s))}))})}function Dj(e,n){return e===n}var Bt=typeof window<"u"?window:{screen:{},navigator:{}},To=(Bt.matchMedia||function(){return{matches:!1}}).bind(Bt),JI=!1,XI=function(){};Bt.addEventListener&&Bt.addEventListener("p",XI,{get passive(){return JI=!0}}),Bt.removeEventListener&&Bt.removeEventListener("p",XI,!1);var eM=JI,Yg="ontouchstart"in Bt,nM=(Yg||"TouchEvent"in Bt&&To("(any-pointer: coarse)"),Bt.navigator.userAgent||"");To("(pointer: coarse)").matches&&/iPad|Macintosh/.test(nM)&&Math.min(Bt.screen.width||0,Bt.screen.height||0);(To("(pointer: coarse)").matches||!To("(pointer: fine)").matches&&Yg)&&/Windows.*Firefox/.test(nM),To("(any-pointer: fine)").matches||To("(any-hover: hover)");const Nj=(e,n,t)=>({tooltip:e,placement:n,content:t});function xj(e,n){}function Oj(e,n){1&e&&V(0,xj,0,0,"ng-template")}function Aj(e,n){if(1&e&&(X(0),V(1,Oj,1,0,null,1),ee()),2&e){const t=v();f(),p("ngTemplateOutlet",t.template)("ngTemplateOutletContext",Fe(2,Nj,t.tooltip,t.placement,t.content))}}function Rj(e,n){if(1&e&&(X(0),y(1,"div",2),b(2),_(),ee()),2&e){const t=v();f(),_t("title",t.tooltip)("data-tooltip-placement",t.placement),f(),U(" ",t.content," ")}}const kj=["tooltipTemplate"],Fj=["leftOuterSelectionBar"],Lj=["rightOuterSelectionBar"],Pj=["fullBar"],Vj=["selectionBar"],Hj=["minHandle"],Bj=["maxHandle"],jj=["floorLabel"],Uj=["ceilLabel"],$j=["minHandleLabel"],zj=["maxHandleLabel"],Gj=["combinedLabel"],qj=["ticksElement"],Wj=e=>({"ngx-slider-selected":e});function Zj(e,n){if(1&e&&x(0,"ngx-slider-tooltip-wrapper",32),2&e){const t=v().$implicit;p("template",v().tooltipTemplate)("tooltip",t.valueTooltip)("placement",t.valueTooltipPlacement)("content",t.value)}}function Qj(e,n){1&e&&x(0,"span",33),2&e&&p("innerText",v().$implicit.legend)}function Yj(e,n){1&e&&x(0,"span",34),2&e&&p("innerHTML",v().$implicit.legend,f_)}function Kj(e,n){if(1&e&&(y(0,"span",27),x(1,"ngx-slider-tooltip-wrapper",28),V(2,Zj,1,4,"ngx-slider-tooltip-wrapper",29)(3,Qj,1,1,"span",30)(4,Yj,1,1,"span",31),_()),2&e){const t=n.$implicit,r=v();p("ngClass",_o(8,Wj,t.selected))("ngStyle",t.style),f(),p("template",r.tooltipTemplate)("tooltip",t.tooltip)("placement",t.tooltipPlacement),f(),p("ngIf",null!=t.value),f(),p("ngIf",null!=t.legend&&!1===r.allowUnsafeHtmlInSlider),f(),p("ngIf",null!=t.legend&&(null==r.allowUnsafeHtmlInSlider||r.allowUnsafeHtmlInSlider))}}var Tn=function(e){return e[e.Low=0]="Low",e[e.High=1]="High",e[e.Floor=2]="Floor",e[e.Ceil=3]="Ceil",e[e.TickValue=4]="TickValue",e}(Tn||{});class Jc{floor=0;ceil=null;step=1;minRange=null;maxRange=null;pushRange=!1;minLimit=null;maxLimit=null;translate=null;combineLabels=null;getLegend=null;getStepLegend=null;stepsArray=null;bindIndexForStepsArray=!1;draggableRange=!1;draggableRangeOnly=!1;showSelectionBar=!1;showSelectionBarEnd=!1;showSelectionBarFromValue=null;showOuterSelectionBars=!1;hidePointerLabels=!1;hideLimitLabels=!1;autoHideLimitLabels=!0;readOnly=!1;disabled=!1;showTicks=!1;showTicksValues=!1;tickStep=null;tickValueStep=null;ticksArray=null;ticksTooltip=null;ticksValuesTooltip=null;vertical=!1;getSelectionBarColor=null;getTickColor=null;getPointerColor=null;keyboardSupport=!0;scale=1;rotate=0;enforceStep=!0;enforceRange=!0;enforceStepsArray=!0;noSwitching=!1;onlyBindHandles=!1;rightToLeft=!1;reversedControls=!1;boundPointerLabels=!0;logScale=!1;customValueToPosition=null;customPositionToValue=null;precisionLimit=12;selectionBarGradient=null;ariaLabel="ngx-slider";ariaLabelledBy=null;ariaLabelHigh="ngx-slider-max";ariaLabelledByHigh=null;handleDimension=null;barDimension=null;animate=!0;animateOnMove=!1}const oM=new R("AllowUnsafeHtmlInSlider");var F=function(e){return e[e.Min=0]="Min",e[e.Max=1]="Max",e}(F||{});class Jj{value;highValue;pointerType}class M{static isNullOrUndefined(n){return null==n}static areArraysEqual(n,t){if(n.length!==t.length)return!1;for(let r=0;rMath.abs(n-o.value));let i=0;for(let o=0;o{o.events.next(a)};return n.addEventListener(t,s,{passive:!0,capture:!1}),o.teardownCallback=()=>{n.removeEventListener(t,s,{passive:!0,capture:!1})},o.eventsSubscription=o.events.pipe(M.isNullOrUndefined(i)?YI(()=>{}):QI(i,void 0,{leading:!0,trailing:!0})).subscribe(a=>{r(a)}),o}detachEventListener(n){M.isNullOrUndefined(n.eventsSubscription)||(n.eventsSubscription.unsubscribe(),n.eventsSubscription=null),M.isNullOrUndefined(n.events)||(n.events.complete(),n.events=null),M.isNullOrUndefined(n.teardownCallback)||(n.teardownCallback(),n.teardownCallback=null)}attachEventListener(n,t,r,i){const o=new sM;return o.eventName=t,o.events=new fn,o.teardownCallback=this.renderer.listen(n,t,a=>{o.events.next(a)}),o.eventsSubscription=o.events.pipe(M.isNullOrUndefined(i)?YI(()=>{}):QI(i,void 0,{leading:!0,trailing:!0})).subscribe(a=>{r(a)}),o}}let Dr=(()=>{class e{elemRef;renderer;changeDetectionRef;_position=0;get position(){return this._position}_dimension=0;get dimension(){return this._dimension}_alwaysHide=!1;get alwaysHide(){return this._alwaysHide}_vertical=!1;get vertical(){return this._vertical}_scale=1;get scale(){return this._scale}_rotate=0;get rotate(){return this._rotate}opacity=1;visibility="visible";left="";bottom="";height="";width="";transform="";eventListenerHelper;eventListeners=[];constructor(t,r,i){this.elemRef=t,this.renderer=r,this.changeDetectionRef=i,this.eventListenerHelper=new aM(this.renderer)}setAlwaysHide(t){this._alwaysHide=t,this.visibility=t?"hidden":"visible"}hide(){this.opacity=0}show(){this.alwaysHide||(this.opacity=1)}isVisible(){return!this.alwaysHide&&0!==this.opacity}setVertical(t){this._vertical=t,this._vertical?(this.left="",this.width=""):(this.bottom="",this.height="")}setScale(t){this._scale=t}setRotate(t){this._rotate=t,this.transform="rotate("+t+"deg)"}getRotate(){return this._rotate}setPosition(t){this._position!==t&&!this.isRefDestroyed()&&this.changeDetectionRef.markForCheck(),this._position=t,this._vertical?this.bottom=Math.round(t)+"px":this.left=Math.round(t)+"px"}calculateDimension(){const t=this.getBoundingClientRect();this._dimension=this.vertical?(t.bottom-t.top)*this.scale:(t.right-t.left)*this.scale}setDimension(t){this._dimension!==t&&!this.isRefDestroyed()&&this.changeDetectionRef.markForCheck(),this._dimension=t,this._vertical?this.height=Math.round(t)+"px":this.width=Math.round(t)+"px"}getBoundingClientRect(){return this.elemRef.nativeElement.getBoundingClientRect()}on(t,r,i){const o=this.eventListenerHelper.attachEventListener(this.elemRef.nativeElement,t,r,i);this.eventListeners.push(o)}onPassive(t,r,i){const o=this.eventListenerHelper.attachPassiveEventListener(this.elemRef.nativeElement,t,r,i);this.eventListeners.push(o)}off(t){let r,i;M.isNullOrUndefined(t)?(r=[],i=this.eventListeners):(r=this.eventListeners.filter(o=>o.eventName!==t),i=this.eventListeners.filter(o=>o.eventName===t));for(const o of i)this.eventListenerHelper.detachEventListener(o);this.eventListeners=r}isRefDestroyed(){return M.isNullOrUndefined(this.changeDetectionRef)||this.changeDetectionRef.destroyed}static \u0275fac=function(r){return new(r||e)(T(pt),T(on),T(si))};static \u0275dir=Y({type:e,selectors:[["","ngxSliderElement",""]],hostVars:14,hostBindings:function(r,i){2&r&&ec("opacity",i.opacity)("visibility",i.visibility)("left",i.left)("bottom",i.bottom)("height",i.height)("width",i.width)("transform",i.transform)},standalone:!1})}return e})(),Kg=(()=>{class e extends Dr{active=!1;role="";tabindex="";ariaOrientation="";ariaLabel="";ariaLabelledBy="";ariaValueNow="";ariaValueText="";ariaValueMin="";ariaValueMax="";focus(){this.elemRef.nativeElement.focus()}focusIfNeeded(){document.activeElement!==this.elemRef.nativeElement&&this.elemRef.nativeElement.focus()}constructor(t,r,i){super(t,r,i)}static \u0275fac=function(r){return new(r||e)(T(pt),T(on),T(si))};static \u0275dir=Y({type:e,selectors:[["","ngxSliderHandle",""]],hostVars:11,hostBindings:function(r,i){2&r&&(_t("role",i.role)("tabindex",i.tabindex)("aria-orientation",i.ariaOrientation)("aria-label",i.ariaLabel)("aria-labelledby",i.ariaLabelledBy)("aria-valuenow",i.ariaValueNow)("aria-valuetext",i.ariaValueText)("aria-valuemin",i.ariaValueMin)("aria-valuemax",i.ariaValueMax),jn("ngx-slider-active",i.active))},standalone:!1,features:[ue]})}return e})(),So=(()=>{class e extends Dr{allowUnsafeHtmlInSlider;_value=null;get value(){return this._value}constructor(t,r,i,o){super(t,r,i),this.allowUnsafeHtmlInSlider=o}setValue(t){let r=!1;!this.alwaysHide&&(M.isNullOrUndefined(this.value)||this.value.length!==t.length||this.value.length>0&&0===this.dimension)&&(r=!0),this._value=t,!1===this.allowUnsafeHtmlInSlider?this.elemRef.nativeElement.innerText=t:this.elemRef.nativeElement.innerHTML=t,r&&this.calculateDimension()}static \u0275fac=function(r){return new(r||e)(T(pt),T(on),T(si),T(oM,8))};static \u0275dir=Y({type:e,selectors:[["","ngxSliderLabel",""]],standalone:!1,features:[ue]})}return e})(),Xj=(()=>{class e{template;tooltip;placement;content;static \u0275fac=function(r){return new(r||e)};static \u0275cmp=sn({type:e,selectors:[["ngx-slider-tooltip-wrapper"]],inputs:{template:"template",tooltip:"tooltip",placement:"placement",content:"content"},standalone:!1,decls:2,vars:2,consts:[[4,"ngIf"],[4,"ngTemplateOutlet","ngTemplateOutletContext"],[1,"ngx-slider-inner-tooltip"]],template:function(r,i){1&r&&V(0,Aj,2,6,"ng-container",0)(1,Rj,3,3,"ng-container",0),2&r&&(p("ngIf",i.template),f(),p("ngIf",!i.template))},dependencies:[zn,Kb],styles:[".ngx-slider-inner-tooltip[_ngcontent-%COMP%]{height:100%}"]})}return e})();class e3{selected=!1;style={};tooltip=null;tooltipPlacement=null;value=null;valueTooltip=null;valueTooltipPlacement=null;legend=null}class lM{active=!1;value=0;difference=0;position=0;lowLimit=0;highLimit=0}class Xc{value;highValue;static compare(n,t){return!(M.isNullOrUndefined(n)&&M.isNullOrUndefined(t)||M.isNullOrUndefined(n)!==M.isNullOrUndefined(t))&&n.value===t.value&&n.highValue===t.highValue}}class cM extends Xc{forceChange;static compare(n,t){return!(M.isNullOrUndefined(n)&&M.isNullOrUndefined(t)||M.isNullOrUndefined(n)!==M.isNullOrUndefined(t))&&n.value===t.value&&n.highValue===t.highValue&&n.forceChange===t.forceChange}}const t3={provide:dn,useExisting:ve(()=>uM),multi:!0};let uM=(()=>{class e{renderer;elementRef;changeDetectionRef;zone;allowUnsafeHtmlInSlider;sliderElementNgxSliderClass=!0;value=null;valueChange=new we;highValue=null;highValueChange=new we;options=new Jc;userChangeStart=new we;userChange=new we;userChangeEnd=new we;manualRefreshSubscription;set manualRefresh(t){this.unsubscribeManualRefresh(),this.manualRefreshSubscription=t.subscribe(()=>{setTimeout(()=>this.calculateViewDimensionsAndDetectChanges())})}triggerFocusSubscription;set triggerFocus(t){this.unsubscribeTriggerFocus(),this.triggerFocusSubscription=t.subscribe(r=>{this.focusPointer(r)})}cancelUserChangeSubscription;set cancelUserChange(t){this.unsubscribeCancelUserChange(),this.cancelUserChangeSubscription=t.subscribe(()=>{this.moving&&(this.positionTrackingHandle(this.preStartHandleValue),this.forceEnd(!0))})}get range(){return!M.isNullOrUndefined(this.value)&&!M.isNullOrUndefined(this.highValue)}initHasRun=!1;inputModelChangeSubject=new fn;inputModelChangeSubscription=null;outputModelChangeSubject=new fn;outputModelChangeSubscription=null;viewLowValue=null;viewHighValue=null;viewOptions=new Jc;handleHalfDimension=0;maxHandlePosition=0;currentTrackingPointer=null;currentFocusPointer=null;firstKeyDown=!1;touchId=null;dragging=new lM;preStartHandleValue=null;leftOuterSelectionBarElement;rightOuterSelectionBarElement;fullBarElement;selectionBarElement;minHandleElement;maxHandleElement;floorLabelElement;ceilLabelElement;minHandleLabelElement;maxHandleLabelElement;combinedLabelElement;ticksElement;tooltipTemplate;sliderElementVerticalClass=!1;sliderElementAnimateClass=!1;sliderElementWithLegendClass=!1;sliderElementDisabledAttr=null;sliderElementAriaLabel="ngx-slider";barStyle={};minPointerStyle={};maxPointerStyle={};fullBarTransparentClass=!1;selectionBarDraggableClass=!1;ticksUnderValuesClass=!1;get showTicks(){return this.viewOptions.showTicks}intermediateTicks=!1;ticks=[];eventListenerHelper=null;onMoveEventListener=null;onEndEventListener=null;moving=!1;resizeObserver=null;onTouchedCallback=null;onChangeCallback=null;constructor(t,r,i,o,s){this.renderer=t,this.elementRef=r,this.changeDetectionRef=i,this.zone=o,this.allowUnsafeHtmlInSlider=s,this.eventListenerHelper=new aM(this.renderer)}ngOnInit(){this.viewOptions=new Jc,Object.assign(this.viewOptions,this.options),this.updateDisabledState(),this.updateVerticalState(),this.updateAriaLabel()}ngAfterViewInit(){this.applyOptions(),this.subscribeInputModelChangeSubject(),this.subscribeOutputModelChangeSubject(),this.renormaliseModelValues(),this.viewLowValue=this.modelValueToViewValue(this.value),this.viewHighValue=this.range?this.modelValueToViewValue(this.highValue):null,this.updateVerticalState(),this.manageElementsStyle(),this.updateDisabledState(),this.calculateViewDimensions(),this.addAccessibility(),this.updateCeilLabel(),this.updateFloorLabel(),this.initHandles(),this.manageEventsBindings(),this.updateAriaLabel(),this.subscribeResizeObserver(),this.initHasRun=!0,this.isRefDestroyed()||this.changeDetectionRef.detectChanges()}ngOnChanges(t){!M.isNullOrUndefined(t.options)&&JSON.stringify(t.options.previousValue)!==JSON.stringify(t.options.currentValue)&&this.onChangeOptions(),(!M.isNullOrUndefined(t.value)||!M.isNullOrUndefined(t.highValue))&&this.inputModelChangeSubject.next({value:this.value,highValue:this.highValue,controlAccessorChange:!1,forceChange:!1,internalChange:!1})}ngOnDestroy(){this.unbindEvents(),this.unsubscribeResizeObserver(),this.unsubscribeInputModelChangeSubject(),this.unsubscribeOutputModelChangeSubject(),this.unsubscribeManualRefresh(),this.unsubscribeTriggerFocus()}writeValue(t){t instanceof Array?(this.value=t[0],this.highValue=t[1]):this.value=t,this.inputModelChangeSubject.next({value:this.value,highValue:this.highValue,forceChange:!1,internalChange:!1,controlAccessorChange:!0})}registerOnChange(t){this.onChangeCallback=t}registerOnTouched(t){this.onTouchedCallback=t}setDisabledState(t){this.viewOptions.disabled=t,this.updateDisabledState(),this.initHasRun&&this.manageEventsBindings()}setAriaLabel(t){this.viewOptions.ariaLabel=t,this.updateAriaLabel()}onResize(t){this.calculateViewDimensionsAndDetectChanges()}subscribeInputModelChangeSubject(){this.inputModelChangeSubscription=this.inputModelChangeSubject.pipe(KI(cM.compare),function bj(e,n){return Nr((t,r)=>{let i=0;t.subscribe(qn(r,o=>e.call(n,o,i++)&&r.next(o)))})}(t=>!t.forceChange&&!t.internalChange)).subscribe(t=>this.applyInputModelChange(t))}subscribeOutputModelChangeSubject(){this.outputModelChangeSubscription=this.outputModelChangeSubject.pipe(KI(cM.compare)).subscribe(t=>this.publishOutputModelChange(t))}subscribeResizeObserver(){wr.isResizeObserverAvailable()&&(this.resizeObserver=new ResizeObserver(()=>this.calculateViewDimensionsAndDetectChanges()),this.resizeObserver.observe(this.elementRef.nativeElement))}unsubscribeResizeObserver(){wr.isResizeObserverAvailable()&&null!==this.resizeObserver&&(this.resizeObserver.disconnect(),this.resizeObserver=null)}unsubscribeOnMove(){M.isNullOrUndefined(this.onMoveEventListener)||(this.eventListenerHelper.detachEventListener(this.onMoveEventListener),this.onMoveEventListener=null)}unsubscribeOnEnd(){M.isNullOrUndefined(this.onEndEventListener)||(this.eventListenerHelper.detachEventListener(this.onEndEventListener),this.onEndEventListener=null)}unsubscribeInputModelChangeSubject(){M.isNullOrUndefined(this.inputModelChangeSubscription)||(this.inputModelChangeSubscription.unsubscribe(),this.inputModelChangeSubscription=null)}unsubscribeOutputModelChangeSubject(){M.isNullOrUndefined(this.outputModelChangeSubscription)||(this.outputModelChangeSubscription.unsubscribe(),this.outputModelChangeSubscription=null)}unsubscribeManualRefresh(){M.isNullOrUndefined(this.manualRefreshSubscription)||(this.manualRefreshSubscription.unsubscribe(),this.manualRefreshSubscription=null)}unsubscribeTriggerFocus(){M.isNullOrUndefined(this.triggerFocusSubscription)||(this.triggerFocusSubscription.unsubscribe(),this.triggerFocusSubscription=null)}unsubscribeCancelUserChange(){M.isNullOrUndefined(this.cancelUserChangeSubscription)||(this.cancelUserChangeSubscription.unsubscribe(),this.cancelUserChangeSubscription=null)}getPointerElement(t){return t===F.Min?this.minHandleElement:t===F.Max?this.maxHandleElement:null}getCurrentTrackingValue(){return this.currentTrackingPointer===F.Min?this.viewLowValue:this.currentTrackingPointer===F.Max?this.viewHighValue:null}modelValueToViewValue(t){return M.isNullOrUndefined(t)?NaN:M.isNullOrUndefined(this.viewOptions.stepsArray)||this.viewOptions.bindIndexForStepsArray?+t:M.findStepIndex(+t,this.viewOptions.stepsArray)}viewValueToModelValue(t){return M.isNullOrUndefined(this.viewOptions.stepsArray)||this.viewOptions.bindIndexForStepsArray?t:this.getStepValue(t)}getStepValue(t){const r=this.viewOptions.stepsArray[t];return M.isNullOrUndefined(r)?NaN:r.value}applyViewChange(){this.value=this.viewValueToModelValue(this.viewLowValue),this.range&&(this.highValue=this.viewValueToModelValue(this.viewHighValue)),this.outputModelChangeSubject.next({value:this.value,highValue:this.highValue,controlAccessorChange:!1,userEventInitiated:!0,forceChange:!1}),this.inputModelChangeSubject.next({value:this.value,highValue:this.highValue,controlAccessorChange:!1,forceChange:!1,internalChange:!0})}applyInputModelChange(t){const r=this.normaliseModelValues(t),i=!Xc.compare(t,r);i&&(this.value=r.value,this.highValue=r.highValue),this.viewLowValue=this.modelValueToViewValue(r.value),this.viewHighValue=this.range?this.modelValueToViewValue(r.highValue):null,this.updateLowHandle(this.valueToPosition(this.viewLowValue)),this.range&&this.updateHighHandle(this.valueToPosition(this.viewHighValue)),this.updateSelectionBar(),this.updateTicksScale(),this.updateAriaAttributes(),this.range&&this.updateCombinedLabel(),this.outputModelChangeSubject.next({value:r.value,highValue:r.highValue,controlAccessorChange:t.controlAccessorChange,forceChange:i,userEventInitiated:!1})}publishOutputModelChange(t){const r=()=>{this.valueChange.emit(t.value),this.range&&this.highValueChange.emit(t.highValue),!t.controlAccessorChange&&(M.isNullOrUndefined(this.onChangeCallback)||this.onChangeCallback(this.range?[t.value,t.highValue]:t.value),M.isNullOrUndefined(this.onTouchedCallback)||this.onTouchedCallback(this.range?[t.value,t.highValue]:t.value))};t.userEventInitiated?(r(),this.userChange.emit(this.getChangeContext())):setTimeout(()=>{r()})}normaliseModelValues(t){const r=new Xc;if(r.value=t.value,r.highValue=t.highValue,!M.isNullOrUndefined(this.viewOptions.stepsArray)){if(this.viewOptions.enforceStepsArray){const i=M.findStepIndex(r.value,this.viewOptions.stepsArray);if(r.value=this.viewOptions.stepsArray[i].value,this.range){const o=M.findStepIndex(r.highValue,this.viewOptions.stepsArray);r.highValue=this.viewOptions.stepsArray[o].value}}return r}if(this.viewOptions.enforceStep&&(r.value=this.roundStep(r.value),this.range&&(r.highValue=this.roundStep(r.highValue))),this.viewOptions.enforceRange&&(r.value=He.clampToRange(r.value,this.viewOptions.floor,this.viewOptions.ceil),this.range&&(r.highValue=He.clampToRange(r.highValue,this.viewOptions.floor,this.viewOptions.ceil)),this.range&&t.value>t.highValue))if(this.viewOptions.noSwitching)r.value=r.highValue;else{const i=t.value;r.value=t.highValue,r.highValue=i}return r}renormaliseModelValues(){const t={value:this.value,highValue:this.highValue},r=this.normaliseModelValues(t);Xc.compare(r,t)||(this.value=r.value,this.highValue=r.highValue,this.outputModelChangeSubject.next({value:this.value,highValue:this.highValue,controlAccessorChange:!1,forceChange:!0,userEventInitiated:!1}))}onChangeOptions(){if(!this.initHasRun)return;const t=this.getOptionsInfluencingEventBindings(this.viewOptions);this.applyOptions();const r=this.getOptionsInfluencingEventBindings(this.viewOptions),i=!M.areArraysEqual(t,r);this.renormaliseModelValues(),this.viewLowValue=this.modelValueToViewValue(this.value),this.viewHighValue=this.range?this.modelValueToViewValue(this.highValue):null,this.resetSlider(i)}applyOptions(){if(this.viewOptions=new Jc,Object.assign(this.viewOptions,this.options),this.viewOptions.draggableRange=this.range&&this.viewOptions.draggableRange,this.viewOptions.draggableRangeOnly=this.range&&this.viewOptions.draggableRangeOnly,this.viewOptions.draggableRangeOnly&&(this.viewOptions.draggableRange=!0),this.viewOptions.showTicks=this.viewOptions.showTicks||this.viewOptions.showTicksValues||!M.isNullOrUndefined(this.viewOptions.ticksArray),this.viewOptions.showTicks&&(!M.isNullOrUndefined(this.viewOptions.tickStep)||!M.isNullOrUndefined(this.viewOptions.ticksArray))&&(this.intermediateTicks=!0),this.viewOptions.showSelectionBar=this.viewOptions.showSelectionBar||this.viewOptions.showSelectionBarEnd||!M.isNullOrUndefined(this.viewOptions.showSelectionBarFromValue),M.isNullOrUndefined(this.viewOptions.stepsArray)?this.applyFloorCeilOptions():this.applyStepsArrayOptions(),M.isNullOrUndefined(this.viewOptions.combineLabels)&&(this.viewOptions.combineLabels=(t,r)=>t+" - "+r),this.viewOptions.logScale&&0===this.viewOptions.floor)throw Error("Can't use floor=0 with logarithmic scale")}applyStepsArrayOptions(){this.viewOptions.floor=0,this.viewOptions.ceil=this.viewOptions.stepsArray.length-1,this.viewOptions.step=1,M.isNullOrUndefined(this.viewOptions.translate)&&(this.viewOptions.translate=t=>String(this.viewOptions.bindIndexForStepsArray?this.getStepValue(t):t))}applyFloorCeilOptions(){if(M.isNullOrUndefined(this.viewOptions.step)?this.viewOptions.step=1:(this.viewOptions.step=+this.viewOptions.step,this.viewOptions.step<=0&&(this.viewOptions.step=1)),M.isNullOrUndefined(this.viewOptions.ceil)||M.isNullOrUndefined(this.viewOptions.floor))throw Error("floor and ceil options must be supplied");this.viewOptions.ceil=+this.viewOptions.ceil,this.viewOptions.floor=+this.viewOptions.floor,M.isNullOrUndefined(this.viewOptions.translate)&&(this.viewOptions.translate=t=>String(t))}resetSlider(t=!0){this.manageElementsStyle(),this.addAccessibility(),this.updateCeilLabel(),this.updateFloorLabel(),t&&(this.unbindEvents(),this.manageEventsBindings()),this.updateDisabledState(),this.updateAriaLabel(),this.calculateViewDimensions(),this.refocusPointerIfNeeded()}focusPointer(t){t!==F.Min&&t!==F.Max&&(t=F.Min),t===F.Min?this.minHandleElement.focus():this.range&&t===F.Max&&this.maxHandleElement.focus()}refocusPointerIfNeeded(){M.isNullOrUndefined(this.currentFocusPointer)||this.getPointerElement(this.currentFocusPointer).focusIfNeeded()}manageElementsStyle(){this.updateScale(),this.floorLabelElement.setAlwaysHide(this.viewOptions.showTicksValues||this.viewOptions.hideLimitLabels),this.ceilLabelElement.setAlwaysHide(this.viewOptions.showTicksValues||this.viewOptions.hideLimitLabels);const t=this.viewOptions.showTicksValues&&!this.intermediateTicks;this.minHandleLabelElement.setAlwaysHide(t||this.viewOptions.hidePointerLabels),this.maxHandleLabelElement.setAlwaysHide(t||!this.range||this.viewOptions.hidePointerLabels),this.combinedLabelElement.setAlwaysHide(t||!this.range||this.viewOptions.hidePointerLabels),this.selectionBarElement.setAlwaysHide(!this.range&&!this.viewOptions.showSelectionBar),this.leftOuterSelectionBarElement.setAlwaysHide(!this.range||!this.viewOptions.showOuterSelectionBars),this.rightOuterSelectionBarElement.setAlwaysHide(!this.range||!this.viewOptions.showOuterSelectionBars),this.fullBarTransparentClass=this.range&&this.viewOptions.showOuterSelectionBars,this.selectionBarDraggableClass=this.viewOptions.draggableRange&&!this.viewOptions.onlyBindHandles,this.ticksUnderValuesClass=this.intermediateTicks&&this.options.showTicksValues,this.sliderElementVerticalClass!==this.viewOptions.vertical&&(this.updateVerticalState(),setTimeout(()=>{this.resetSlider()})),this.sliderElementAnimateClass!==this.viewOptions.animate&&setTimeout(()=>{this.sliderElementAnimateClass=this.viewOptions.animate}),this.updateRotate()}manageEventsBindings(){this.viewOptions.disabled||this.viewOptions.readOnly?this.unbindEvents():this.bindEvents()}updateDisabledState(){this.sliderElementDisabledAttr=this.viewOptions.disabled?"disabled":null}updateAriaLabel(){this.sliderElementAriaLabel=this.viewOptions.ariaLabel||"nxg-slider"}updateVerticalState(){this.sliderElementVerticalClass=this.viewOptions.vertical;for(const t of this.getAllSliderElements())M.isNullOrUndefined(t)||t.setVertical(this.viewOptions.vertical)}updateScale(){for(const t of this.getAllSliderElements())t.setScale(this.viewOptions.scale)}updateRotate(){for(const t of this.getAllSliderElements())t.setRotate(this.viewOptions.rotate)}getAllSliderElements(){return[this.leftOuterSelectionBarElement,this.rightOuterSelectionBarElement,this.fullBarElement,this.selectionBarElement,this.minHandleElement,this.maxHandleElement,this.floorLabelElement,this.ceilLabelElement,this.minHandleLabelElement,this.maxHandleLabelElement,this.combinedLabelElement,this.ticksElement]}initHandles(){this.updateLowHandle(this.valueToPosition(this.viewLowValue)),this.range&&this.updateHighHandle(this.valueToPosition(this.viewHighValue)),this.updateSelectionBar(),this.range&&this.updateCombinedLabel(),this.updateTicksScale()}addAccessibility(){this.updateAriaAttributes(),this.minHandleElement.role="slider",this.minHandleElement.tabindex=!this.viewOptions.keyboardSupport||this.viewOptions.readOnly||this.viewOptions.disabled?"":"0",this.minHandleElement.ariaOrientation=this.viewOptions.vertical||0!==this.viewOptions.rotate?"vertical":"horizontal",M.isNullOrUndefined(this.viewOptions.ariaLabel)?M.isNullOrUndefined(this.viewOptions.ariaLabelledBy)||(this.minHandleElement.ariaLabelledBy=this.viewOptions.ariaLabelledBy):this.minHandleElement.ariaLabel=this.viewOptions.ariaLabel,this.range&&(this.maxHandleElement.role="slider",this.maxHandleElement.tabindex=!this.viewOptions.keyboardSupport||this.viewOptions.readOnly||this.viewOptions.disabled?"":"0",this.maxHandleElement.ariaOrientation=this.viewOptions.vertical||0!==this.viewOptions.rotate?"vertical":"horizontal",M.isNullOrUndefined(this.viewOptions.ariaLabelHigh)?M.isNullOrUndefined(this.viewOptions.ariaLabelledByHigh)||(this.maxHandleElement.ariaLabelledBy=this.viewOptions.ariaLabelledByHigh):this.maxHandleElement.ariaLabel=this.viewOptions.ariaLabelHigh)}updateAriaAttributes(){this.minHandleElement.ariaValueNow=(+this.value).toString(),this.minHandleElement.ariaValueText=this.viewOptions.translate(+this.value,Tn.Low),this.minHandleElement.ariaValueMin=this.viewOptions.floor.toString(),this.minHandleElement.ariaValueMax=this.viewOptions.ceil.toString(),this.range&&(this.maxHandleElement.ariaValueNow=(+this.highValue).toString(),this.maxHandleElement.ariaValueText=this.viewOptions.translate(+this.highValue,Tn.High),this.maxHandleElement.ariaValueMin=this.viewOptions.floor.toString(),this.maxHandleElement.ariaValueMax=this.viewOptions.ceil.toString())}calculateViewDimensions(){M.isNullOrUndefined(this.viewOptions.handleDimension)?this.minHandleElement.calculateDimension():this.minHandleElement.setDimension(this.viewOptions.handleDimension);const t=this.minHandleElement.dimension;this.handleHalfDimension=t/2,M.isNullOrUndefined(this.viewOptions.barDimension)?this.fullBarElement.calculateDimension():this.fullBarElement.setDimension(this.viewOptions.barDimension),this.maxHandlePosition=this.fullBarElement.dimension-t,this.initHasRun&&(this.updateFloorLabel(),this.updateCeilLabel(),this.initHandles())}calculateViewDimensionsAndDetectChanges(){this.calculateViewDimensions(),this.isRefDestroyed()||this.changeDetectionRef.detectChanges()}isRefDestroyed(){return this.changeDetectionRef.destroyed}updateTicksScale(){if(!this.viewOptions.showTicks&&this.sliderElementWithLegendClass)return void setTimeout(()=>{this.sliderElementWithLegendClass=!1});const t=M.isNullOrUndefined(this.viewOptions.ticksArray)?this.getTicksArray():this.viewOptions.ticksArray,r=this.viewOptions.vertical?"translateY":"translateX";this.viewOptions.rightToLeft&&t.reverse();const i=M.isNullOrUndefined(this.viewOptions.tickValueStep)?M.isNullOrUndefined(this.viewOptions.tickStep)?this.viewOptions.step:this.viewOptions.tickStep:this.viewOptions.tickValueStep;let o=!1;const s=t.map(a=>{let l=this.valueToPosition(a);this.viewOptions.vertical&&(l=this.maxHandlePosition-l);const c=r+"("+Math.round(l)+"px)",u=new e3;u.selected=this.isTickSelected(a),u.style={"-webkit-transform":c,"-moz-transform":c,"-o-transform":c,"-ms-transform":c,transform:c},u.selected&&!M.isNullOrUndefined(this.viewOptions.getSelectionBarColor)&&(u.style["background-color"]=this.getSelectionBarColor()),!u.selected&&!M.isNullOrUndefined(this.viewOptions.getTickColor)&&(u.style["background-color"]=this.getTickColor(a)),M.isNullOrUndefined(this.viewOptions.ticksTooltip)||(u.tooltip=this.viewOptions.ticksTooltip(a),u.tooltipPlacement=this.viewOptions.vertical?"right":"top"),this.viewOptions.showTicksValues&&!M.isNullOrUndefined(i)&&He.isModuloWithinPrecisionLimit(a,i,this.viewOptions.precisionLimit)&&(u.value=this.getDisplayValue(a,Tn.TickValue),M.isNullOrUndefined(this.viewOptions.ticksValuesTooltip)||(u.valueTooltip=this.viewOptions.ticksValuesTooltip(a),u.valueTooltipPlacement=this.viewOptions.vertical?"right":"top"));let d=null;if(M.isNullOrUndefined(this.viewOptions.stepsArray))M.isNullOrUndefined(this.viewOptions.getLegend)||(d=this.viewOptions.getLegend(a));else{const g=this.viewOptions.stepsArray[a];M.isNullOrUndefined(this.viewOptions.getStepLegend)?M.isNullOrUndefined(g)||(d=g.legend):d=this.viewOptions.getStepLegend(g)}return M.isNullOrUndefined(d)||(u.legend=d,o=!0),u});if(this.sliderElementWithLegendClass!==o&&setTimeout(()=>{this.sliderElementWithLegendClass=o}),M.isNullOrUndefined(this.ticks)||this.ticks.length!==s.length)this.ticks=s,this.isRefDestroyed()||this.changeDetectionRef.detectChanges();else for(let a=0;a=this.viewLowValue)return!0}else if(this.viewOptions.showSelectionBar&&t<=this.viewLowValue)return!0}else{const r=this.viewOptions.showSelectionBarFromValue;if(this.viewLowValue>r&&t>=r&&t<=this.viewLowValue)return!0;if(this.viewLowValue=this.viewLowValue)return!0}return!!(this.range&&t>=this.viewLowValue&&t<=this.viewHighValue)}updateFloorLabel(){this.floorLabelElement.alwaysHide||(this.floorLabelElement.setValue(this.getDisplayValue(this.viewOptions.floor,Tn.Floor)),this.floorLabelElement.calculateDimension(),this.floorLabelElement.setPosition(this.viewOptions.rightToLeft?this.fullBarElement.dimension-this.floorLabelElement.dimension:0))}updateCeilLabel(){this.ceilLabelElement.alwaysHide||(this.ceilLabelElement.setValue(this.getDisplayValue(this.viewOptions.ceil,Tn.Ceil)),this.ceilLabelElement.calculateDimension(),this.ceilLabelElement.setPosition(this.viewOptions.rightToLeft?0:this.fullBarElement.dimension-this.ceilLabelElement.dimension))}updateHandles(t,r){t===F.Min?this.updateLowHandle(r):t===F.Max&&this.updateHighHandle(r),this.updateSelectionBar(),this.updateTicksScale(),this.range&&this.updateCombinedLabel()}getHandleLabelPos(t,r){const i=t===F.Min?this.minHandleLabelElement.dimension:this.maxHandleLabelElement.dimension,o=r-i/2+this.handleHalfDimension,s=this.fullBarElement.dimension-i;return this.viewOptions.boundPointerLabels?this.viewOptions.rightToLeft&&t===F.Min||!this.viewOptions.rightToLeft&&t===F.Max?Math.min(o,s):Math.min(Math.max(o,0),s):o}updateLowHandle(t){this.minHandleElement.setPosition(t),this.minHandleLabelElement.setValue(this.getDisplayValue(this.viewLowValue,Tn.Low)),this.minHandleLabelElement.setPosition(this.getHandleLabelPos(F.Min,t)),M.isNullOrUndefined(this.viewOptions.getPointerColor)||(this.minPointerStyle={backgroundColor:this.getPointerColor(F.Min)}),this.viewOptions.autoHideLimitLabels&&this.updateFloorAndCeilLabelsVisibility()}updateHighHandle(t){this.maxHandleElement.setPosition(t),this.maxHandleLabelElement.setValue(this.getDisplayValue(this.viewHighValue,Tn.High)),this.maxHandleLabelElement.setPosition(this.getHandleLabelPos(F.Max,t)),M.isNullOrUndefined(this.viewOptions.getPointerColor)||(this.maxPointerStyle={backgroundColor:this.getPointerColor(F.Max)}),this.viewOptions.autoHideLimitLabels&&this.updateFloorAndCeilLabelsVisibility()}updateFloorAndCeilLabelsVisibility(){if(this.viewOptions.hidePointerLabels)return;let t=!1,r=!1;const i=this.isLabelBelowFloorLabel(this.minHandleLabelElement),o=this.isLabelAboveCeilLabel(this.minHandleLabelElement),s=this.isLabelAboveCeilLabel(this.maxHandleLabelElement),a=this.isLabelBelowFloorLabel(this.combinedLabelElement),l=this.isLabelAboveCeilLabel(this.combinedLabelElement);if(i?(t=!0,this.floorLabelElement.hide()):(t=!1,this.floorLabelElement.show()),o?(r=!0,this.ceilLabelElement.hide()):(r=!1,this.ceilLabelElement.show()),this.range){const c=this.combinedLabelElement.isVisible()?l:s,u=this.combinedLabelElement.isVisible()?a:i;c?this.ceilLabelElement.hide():r||this.ceilLabelElement.show(),u?this.floorLabelElement.hide():t||this.floorLabelElement.show()}}isLabelBelowFloorLabel(t){const r=t.position,o=this.floorLabelElement.position;return this.viewOptions.rightToLeft?r+t.dimension>=o-2:r<=o+this.floorLabelElement.dimension+2}isLabelAboveCeilLabel(t){const r=t.position,o=this.ceilLabelElement.position;return this.viewOptions.rightToLeft?r<=o+this.ceilLabelElement.dimension+2:r+t.dimension>=o-2}updateSelectionBar(){let t=0,r=0;const i=this.viewOptions.rightToLeft?!this.viewOptions.showSelectionBarEnd:this.viewOptions.showSelectionBarEnd,o=this.viewOptions.rightToLeft?this.maxHandleElement.position+this.handleHalfDimension:this.minHandleElement.position+this.handleHalfDimension;if(this.range)r=Math.abs(this.maxHandleElement.position-this.minHandleElement.position),t=o;else if(M.isNullOrUndefined(this.viewOptions.showSelectionBarFromValue))i?(r=Math.ceil(Math.abs(this.maxHandlePosition-this.minHandleElement.position)+this.handleHalfDimension),t=Math.floor(this.minHandleElement.position+this.handleHalfDimension)):(r=this.minHandleElement.position+this.handleHalfDimension,t=0);else{const s=this.viewOptions.showSelectionBarFromValue,a=this.valueToPosition(s);(this.viewOptions.rightToLeft?this.viewLowValue<=s:this.viewLowValue>s)?(r=this.minHandleElement.position-a,t=a+this.handleHalfDimension):(r=a-this.minHandleElement.position,t=this.minHandleElement.position+this.handleHalfDimension)}if(this.selectionBarElement.setDimension(r),this.selectionBarElement.setPosition(t),this.range&&this.viewOptions.showOuterSelectionBars&&(this.viewOptions.rightToLeft?(this.rightOuterSelectionBarElement.setDimension(t),this.rightOuterSelectionBarElement.setPosition(0),this.fullBarElement.calculateDimension(),this.leftOuterSelectionBarElement.setDimension(this.fullBarElement.dimension-(t+r)),this.leftOuterSelectionBarElement.setPosition(t+r)):(this.leftOuterSelectionBarElement.setDimension(t),this.leftOuterSelectionBarElement.setPosition(0),this.fullBarElement.calculateDimension(),this.rightOuterSelectionBarElement.setDimension(this.fullBarElement.dimension-(t+r)),this.rightOuterSelectionBarElement.setPosition(t+r))),M.isNullOrUndefined(this.viewOptions.getSelectionBarColor)){if(!M.isNullOrUndefined(this.viewOptions.selectionBarGradient)){const s=M.isNullOrUndefined(this.viewOptions.showSelectionBarFromValue)?0:this.valueToPosition(this.viewOptions.showSelectionBarFromValue),a=s-t>0&&!i||s-t<=0&&i;this.barStyle={backgroundImage:"linear-gradient(to "+(this.viewOptions.vertical?a?"bottom":"top":a?"left":"right")+", "+this.viewOptions.selectionBarGradient.from+" 0%,"+this.viewOptions.selectionBarGradient.to+" 100%)"},this.viewOptions.vertical?(this.barStyle.backgroundPosition="center "+(s+r+t+(a?-this.handleHalfDimension:0))+"px",this.barStyle.backgroundSize="100% "+(this.fullBarElement.dimension-this.handleHalfDimension)+"px"):(this.barStyle.backgroundPosition=s-t+(a?this.handleHalfDimension:0)+"px center",this.barStyle.backgroundSize=this.fullBarElement.dimension-this.handleHalfDimension+"px 100%")}}else{const s=this.getSelectionBarColor();this.barStyle={backgroundColor:s}}}getSelectionBarColor(){return this.range?this.viewOptions.getSelectionBarColor(this.value,this.highValue):this.viewOptions.getSelectionBarColor(this.value)}getPointerColor(t){return this.viewOptions.getPointerColor(t===F.Max?this.highValue:this.value,t)}getTickColor(t){return this.viewOptions.getTickColor(t)}updateCombinedLabel(){let t=null;if(t=this.viewOptions.rightToLeft?this.minHandleLabelElement.position-this.minHandleLabelElement.dimension-10<=this.maxHandleLabelElement.position:this.minHandleLabelElement.position+this.minHandleLabelElement.dimension+10>=this.maxHandleLabelElement.position,t){const r=this.getDisplayValue(this.viewLowValue,Tn.Low),i=this.getDisplayValue(this.viewHighValue,Tn.High),o=this.viewOptions.rightToLeft?this.viewOptions.combineLabels(i,r):this.viewOptions.combineLabels(r,i);this.combinedLabelElement.setValue(o);const s=this.viewOptions.boundPointerLabels?Math.min(Math.max(this.selectionBarElement.position+this.selectionBarElement.dimension/2-this.combinedLabelElement.dimension/2,0),this.fullBarElement.dimension-this.combinedLabelElement.dimension):this.selectionBarElement.position+this.selectionBarElement.dimension/2-this.combinedLabelElement.dimension/2;this.combinedLabelElement.setPosition(s),this.minHandleLabelElement.hide(),this.maxHandleLabelElement.hide(),this.combinedLabelElement.show()}else this.updateHighHandle(this.valueToPosition(this.viewHighValue)),this.updateLowHandle(this.valueToPosition(this.viewLowValue)),this.maxHandleLabelElement.show(),this.minHandleLabelElement.show(),this.combinedLabelElement.hide();this.viewOptions.autoHideLimitLabels&&this.updateFloorAndCeilLabelsVisibility()}getDisplayValue(t,r){return!M.isNullOrUndefined(this.viewOptions.stepsArray)&&!this.viewOptions.bindIndexForStepsArray&&(t=this.getStepValue(t)),this.viewOptions.translate(t,r)}roundStep(t,r){const i=M.isNullOrUndefined(r)?this.viewOptions.step:r;let o=He.roundToPrecisionLimit((t-this.viewOptions.floor)/i,this.viewOptions.precisionLimit);return o=Math.round(o)*i,He.roundToPrecisionLimit(this.viewOptions.floor+o,this.viewOptions.precisionLimit)}valueToPosition(t){let r=M.linearValueToPosition;M.isNullOrUndefined(this.viewOptions.customValueToPosition)?this.viewOptions.logScale&&(r=M.logValueToPosition):r=this.viewOptions.customValueToPosition;let i=r(t=He.clampToRange(t,this.viewOptions.floor,this.viewOptions.ceil),this.viewOptions.floor,this.viewOptions.ceil);return M.isNullOrUndefined(i)&&(i=0),this.viewOptions.rightToLeft&&(i=1-i),i*this.maxHandlePosition}positionToValue(t){let r=t/this.maxHandlePosition;this.viewOptions.rightToLeft&&(r=1-r);let i=M.linearPositionToValue;M.isNullOrUndefined(this.viewOptions.customPositionToValue)?this.viewOptions.logScale&&(i=M.logPositionToValue):i=this.viewOptions.customPositionToValue;const o=i(r,this.viewOptions.floor,this.viewOptions.ceil);return M.isNullOrUndefined(o)?0:o}getEventXY(t,r){if(t instanceof MouseEvent)return this.viewOptions.vertical||0!==this.viewOptions.rotate?t.clientY:t.clientX;let i=0;const o=t.touches;if(!M.isNullOrUndefined(r))for(let s=0;so?F.Max:this.viewOptions.rightToLeft?r>this.minHandleElement.position?F.Min:F.Max:rthis.onBarStart(null,t,r,!0,!0,!0)),this.viewOptions.draggableRangeOnly?(this.minHandleElement.on("mousedown",r=>this.onBarStart(F.Min,t,r,!0,!0)),this.maxHandleElement.on("mousedown",r=>this.onBarStart(F.Max,t,r,!0,!0))):(this.minHandleElement.on("mousedown",r=>this.onStart(F.Min,r,!0,!0)),this.range&&this.maxHandleElement.on("mousedown",r=>this.onStart(F.Max,r,!0,!0)),this.viewOptions.onlyBindHandles||(this.fullBarElement.on("mousedown",r=>this.onStart(null,r,!0,!0,!0)),this.ticksElement.on("mousedown",r=>this.onStart(null,r,!0,!0,!0,!0)))),this.viewOptions.onlyBindHandles||this.selectionBarElement.onPassive("touchstart",r=>this.onBarStart(null,t,r,!0,!0,!0)),this.viewOptions.draggableRangeOnly?(this.minHandleElement.onPassive("touchstart",r=>this.onBarStart(F.Min,t,r,!0,!0)),this.maxHandleElement.onPassive("touchstart",r=>this.onBarStart(F.Max,t,r,!0,!0))):(this.minHandleElement.onPassive("touchstart",r=>this.onStart(F.Min,r,!0,!0)),this.range&&this.maxHandleElement.onPassive("touchstart",r=>this.onStart(F.Max,r,!0,!0)),this.viewOptions.onlyBindHandles||(this.fullBarElement.onPassive("touchstart",r=>this.onStart(null,r,!0,!0,!0)),this.ticksElement.onPassive("touchstart",r=>this.onStart(null,r,!1,!1,!0,!0)))),this.viewOptions.keyboardSupport&&(this.minHandleElement.on("focus",()=>this.onPointerFocus(F.Min)),this.range&&this.maxHandleElement.on("focus",()=>this.onPointerFocus(F.Max)))}getOptionsInfluencingEventBindings(t){return[t.disabled,t.readOnly,t.draggableRange,t.draggableRangeOnly,t.onlyBindHandles,t.keyboardSupport]}unbindEvents(){this.unsubscribeOnMove(),this.unsubscribeOnEnd();for(const t of this.getAllSliderElements())M.isNullOrUndefined(t)||t.off()}onBarStart(t,r,i,o,s,a,l){r?this.onDragStart(t,i,o,s):this.onStart(t,i,o,s,a,l)}onStart(t,r,i,o,s,a){r.stopPropagation(),!wr.isTouchEvent(r)&&!eM&&r.preventDefault(),this.moving=!1,this.calculateViewDimensions(),M.isNullOrUndefined(t)&&(t=this.getNearestHandle(r)),this.currentTrackingPointer=t;const l=this.getPointerElement(t);if(l.active=!0,this.preStartHandleValue=this.getCurrentTrackingValue(),this.viewOptions.keyboardSupport&&l.focus(),i){this.unsubscribeOnMove();const c=u=>this.dragging.active?this.onDragMove(u):this.onMove(u);this.onMoveEventListener=wr.isTouchEvent(r)?this.eventListenerHelper.attachPassiveEventListener(document,"touchmove",c):this.eventListenerHelper.attachEventListener(document,"mousemove",c)}if(o){this.unsubscribeOnEnd();const c=u=>this.onEnd(u);this.onEndEventListener=wr.isTouchEvent(r)?this.eventListenerHelper.attachPassiveEventListener(document,"touchend",c):this.eventListenerHelper.attachEventListener(document,"mouseup",c)}this.userChangeStart.emit(this.getChangeContext()),wr.isTouchEvent(r)&&!M.isNullOrUndefined(r.changedTouches)&&M.isNullOrUndefined(this.touchId)&&(this.touchId=r.changedTouches[0].identifier),s&&this.onMove(r,!0),a&&this.onEnd(r)}onMove(t,r){let i=null;if(wr.isTouchEvent(t)){const c=t.changedTouches;for(let u=0;u=this.maxHandlePosition?s=this.viewOptions.rightToLeft?this.viewOptions.floor:this.viewOptions.ceil:(s=this.positionToValue(o),s=r&&!M.isNullOrUndefined(this.viewOptions.tickStep)?this.roundStep(s,this.viewOptions.tickStep):this.roundStep(s)),this.positionTrackingHandle(s)}forceEnd(t=!1){this.moving=!1,this.viewOptions.animate&&(this.sliderElementAnimateClass=!0),t&&(this.sliderElementAnimateClass=!1,setTimeout(()=>{this.sliderElementAnimateClass=this.viewOptions.animate})),this.touchId=null,this.viewOptions.keyboardSupport||(this.minHandleElement.active=!1,this.maxHandleElement.active=!1,this.currentTrackingPointer=null),this.dragging.active=!1,this.unsubscribeOnMove(),this.unsubscribeOnEnd(),this.userChangeEnd.emit(this.getChangeContext())}onEnd(t){wr.isTouchEvent(t)&&t.changedTouches[0].identifier!==this.touchId||this.forceEnd()}onPointerFocus(t){const r=this.getPointerElement(t);r.on("blur",()=>this.onPointerBlur(r)),r.on("keydown",i=>this.onKeyboardEvent(i)),r.on("keyup",()=>this.onKeyUp()),r.active=!0,this.currentTrackingPointer=t,this.currentFocusPointer=t,this.firstKeyDown=!0}onKeyUp(){this.firstKeyDown=!0,this.userChangeEnd.emit(this.getChangeContext())}onPointerBlur(t){t.off("blur"),t.off("keydown"),t.off("keyup"),t.active=!1,M.isNullOrUndefined(this.touchId)&&(this.currentTrackingPointer=null,this.currentFocusPointer=null)}getKeyActions(t){const r=this.viewOptions.ceil-this.viewOptions.floor;let i=t+this.viewOptions.step,o=t-this.viewOptions.step,s=t+r/10,a=t-r/10;this.viewOptions.reversedControls&&(i=t-this.viewOptions.step,o=t+this.viewOptions.step,s=t-r/10,a=t+r/10);const l={UP:i,DOWN:o,LEFT:o,RIGHT:i,PAGEUP:s,PAGEDOWN:a,HOME:this.viewOptions.reversedControls?this.viewOptions.ceil:this.viewOptions.floor,END:this.viewOptions.reversedControls?this.viewOptions.floor:this.viewOptions.ceil};return this.viewOptions.rightToLeft&&(l.LEFT=i,l.RIGHT=o,(this.viewOptions.vertical||0!==this.viewOptions.rotate)&&(l.UP=o,l.DOWN=i)),l}onKeyboardEvent(t){const r=this.getCurrentTrackingValue(),i=M.isNullOrUndefined(t.keyCode)?t.which:t.keyCode,l=this.getKeyActions(r)[{38:"UP",40:"DOWN",37:"LEFT",39:"RIGHT",33:"PAGEUP",34:"PAGEDOWN",36:"HOME",35:"END"}[i]];if(M.isNullOrUndefined(l)||M.isNullOrUndefined(this.currentTrackingPointer))return;t.preventDefault(),this.firstKeyDown&&(this.firstKeyDown=!1,this.userChangeStart.emit(this.getChangeContext()));const c=He.clampToRange(l,this.viewOptions.floor,this.viewOptions.ceil),u=this.roundStep(c);if(this.viewOptions.draggableRangeOnly){const d=this.viewHighValue-this.viewLowValue;let g,h;this.currentTrackingPointer===F.Min?(g=u,h=u+d,h>this.viewOptions.ceil&&(h=this.viewOptions.ceil,g=h-d)):this.currentTrackingPointer===F.Max&&(h=u,g=u-d,g=this.maxHandlePosition-i;let u,d;if(r<=o){if(0===s.position)return;u=this.getMinValue(r,!0,!1),d=this.getMaxValue(r,!0,!1)}else if(c){if(a.position===this.maxHandlePosition)return;d=this.getMaxValue(r,!0,!0),u=this.getMinValue(r,!0,!0)}else u=this.getMinValue(r,!1,!1),d=this.getMaxValue(r,!1,!1);this.positionTrackingBar(u,d)}positionTrackingBar(t,r){!M.isNullOrUndefined(this.viewOptions.minLimit)&&tthis.viewOptions.maxLimit&&(t=He.roundToPrecisionLimit((r=this.viewOptions.maxLimit)-this.dragging.difference,this.viewOptions.precisionLimit)),this.viewLowValue=t,this.viewHighValue=r,this.applyViewChange(),this.updateHandles(F.Min,this.valueToPosition(t)),this.updateHandles(F.Max,this.valueToPosition(r))}positionTrackingHandle(t){t=this.applyMinMaxLimit(t),this.range&&(this.viewOptions.pushRange?t=this.applyPushRange(t):(this.viewOptions.noSwitching&&(this.currentTrackingPointer===F.Min&&t>this.viewHighValue?t=this.applyMinMaxRange(this.viewHighValue):this.currentTrackingPointer===F.Max&&tthis.viewHighValue?(this.viewLowValue=this.viewHighValue,this.applyViewChange(),this.updateHandles(F.Min,this.maxHandleElement.position),this.updateAriaAttributes(),this.currentTrackingPointer=F.Max,this.minHandleElement.active=!1,this.maxHandleElement.active=!0,this.viewOptions.keyboardSupport&&this.maxHandleElement.focus()):this.currentTrackingPointer===F.Max&&tthis.viewOptions.maxLimit?this.viewOptions.maxLimit:t}applyMinMaxRange(t){const i=Math.abs(t-(this.currentTrackingPointer===F.Min?this.viewHighValue:this.viewLowValue));if(!M.isNullOrUndefined(this.viewOptions.minRange)&&ithis.viewOptions.maxRange){if(this.currentTrackingPointer===F.Min)return He.roundToPrecisionLimit(this.viewHighValue-this.viewOptions.maxRange,this.viewOptions.precisionLimit);if(this.currentTrackingPointer===F.Max)return He.roundToPrecisionLimit(this.viewLowValue+this.viewOptions.maxRange,this.viewOptions.precisionLimit)}return t}applyPushRange(t){const r=this.currentTrackingPointer===F.Min?this.viewHighValue-t:t-this.viewLowValue,i=M.isNullOrUndefined(this.viewOptions.minRange)?this.viewOptions.step:this.viewOptions.minRange,o=this.viewOptions.maxRange;return ro&&(this.currentTrackingPointer===F.Min?(this.viewHighValue=He.roundToPrecisionLimit(t+o,this.viewOptions.precisionLimit),this.applyViewChange(),this.updateHandles(F.Max,this.valueToPosition(this.viewHighValue))):this.currentTrackingPointer===F.Max&&(this.viewLowValue=He.roundToPrecisionLimit(t-o,this.viewOptions.precisionLimit),this.applyViewChange(),this.updateHandles(F.Min,this.valueToPosition(this.viewLowValue))),this.updateAriaAttributes()),t}getChangeContext(){const t=new Jj;return t.pointerType=this.currentTrackingPointer,t.value=+this.value,this.range&&(t.highValue=+this.highValue),t}static \u0275fac=function(r){return new(r||e)(T(on),T(pt),T(si),T(de),T(oM,8))};static \u0275cmp=sn({type:e,selectors:[["ngx-slider"]],contentQueries:function(r,i,o){if(1&r&&Zw(o,kj,5),2&r){let s;Ot(s=At())&&(i.tooltipTemplate=s.first)}},viewQuery:function(r,i){if(1&r&&(Vt(Fj,5,Dr),Vt(Lj,5,Dr),Vt(Pj,5,Dr),Vt(Vj,5,Dr),Vt(Hj,5,Kg),Vt(Bj,5,Kg),Vt(jj,5,So),Vt(Uj,5,So),Vt($j,5,So),Vt(zj,5,So),Vt(Gj,5,So),Vt(qj,5,Dr)),2&r){let o;Ot(o=At())&&(i.leftOuterSelectionBarElement=o.first),Ot(o=At())&&(i.rightOuterSelectionBarElement=o.first),Ot(o=At())&&(i.fullBarElement=o.first),Ot(o=At())&&(i.selectionBarElement=o.first),Ot(o=At())&&(i.minHandleElement=o.first),Ot(o=At())&&(i.maxHandleElement=o.first),Ot(o=At())&&(i.floorLabelElement=o.first),Ot(o=At())&&(i.ceilLabelElement=o.first),Ot(o=At())&&(i.minHandleLabelElement=o.first),Ot(o=At())&&(i.maxHandleLabelElement=o.first),Ot(o=At())&&(i.combinedLabelElement=o.first),Ot(o=At())&&(i.ticksElement=o.first)}},hostVars:10,hostBindings:function(r,i){1&r&&q("resize",function(s){return i.onResize(s)},0,El),2&r&&(_t("disabled",i.sliderElementDisabledAttr)("aria-label",i.sliderElementAriaLabel),jn("ngx-slider",i.sliderElementNgxSliderClass)("vertical",i.sliderElementVerticalClass)("animate",i.sliderElementAnimateClass)("with-legend",i.sliderElementWithLegendClass))},inputs:{value:"value",highValue:"highValue",options:"options",manualRefresh:"manualRefresh",triggerFocus:"triggerFocus",cancelUserChange:"cancelUserChange"},outputs:{valueChange:"valueChange",highValueChange:"highValueChange",userChangeStart:"userChangeStart",userChange:"userChange",userChangeEnd:"userChangeEnd"},standalone:!1,features:[Me([t3]),kn],decls:29,vars:13,consts:[["leftOuterSelectionBar",""],["rightOuterSelectionBar",""],["fullBar",""],["selectionBar",""],["minHandle",""],["maxHandle",""],["floorLabel",""],["ceilLabel",""],["minHandleLabel",""],["maxHandleLabel",""],["combinedLabel",""],["ticksElement",""],["ngxSliderElement","",1,"ngx-slider-span","ngx-slider-bar-wrapper","ngx-slider-left-out-selection"],[1,"ngx-slider-span","ngx-slider-bar"],["ngxSliderElement","",1,"ngx-slider-span","ngx-slider-bar-wrapper","ngx-slider-right-out-selection"],["ngxSliderElement","",1,"ngx-slider-span","ngx-slider-bar-wrapper","ngx-slider-full-bar"],["ngxSliderElement","",1,"ngx-slider-span","ngx-slider-bar-wrapper","ngx-slider-selection-bar"],[1,"ngx-slider-span","ngx-slider-bar","ngx-slider-selection",3,"ngStyle"],["ngxSliderHandle","",1,"ngx-slider-span","ngx-slider-pointer","ngx-slider-pointer-min",3,"ngStyle"],["ngxSliderHandle","",1,"ngx-slider-span","ngx-slider-pointer","ngx-slider-pointer-max",3,"ngStyle"],["ngxSliderLabel","",1,"ngx-slider-span","ngx-slider-bubble","ngx-slider-limit","ngx-slider-floor"],["ngxSliderLabel","",1,"ngx-slider-span","ngx-slider-bubble","ngx-slider-limit","ngx-slider-ceil"],["ngxSliderLabel","",1,"ngx-slider-span","ngx-slider-bubble","ngx-slider-model-value"],["ngxSliderLabel","",1,"ngx-slider-span","ngx-slider-bubble","ngx-slider-model-high"],["ngxSliderLabel","",1,"ngx-slider-span","ngx-slider-bubble","ngx-slider-combined"],["ngxSliderElement","",1,"ngx-slider-ticks",3,"hidden"],["class","ngx-slider-tick",3,"ngClass","ngStyle",4,"ngFor","ngForOf"],[1,"ngx-slider-tick",3,"ngClass","ngStyle"],[3,"template","tooltip","placement"],["class","ngx-slider-span ngx-slider-tick-value",3,"template","tooltip","placement","content",4,"ngIf"],["class","ngx-slider-span ngx-slider-tick-legend",3,"innerText",4,"ngIf"],["class","ngx-slider-span ngx-slider-tick-legend",3,"innerHTML",4,"ngIf"],[1,"ngx-slider-span","ngx-slider-tick-value",3,"template","tooltip","placement","content"],[1,"ngx-slider-span","ngx-slider-tick-legend",3,"innerText"],[1,"ngx-slider-span","ngx-slider-tick-legend",3,"innerHTML"]],template:function(r,i){1&r&&(y(0,"span",12,0),x(2,"span",13),_(),y(3,"span",14,1),x(5,"span",13),_(),y(6,"span",15,2),x(8,"span",13),_(),y(9,"span",16,3),x(11,"span",17),_(),x(12,"span",18,4)(14,"span",19,5)(16,"span",20,6)(18,"span",21,7)(20,"span",22,8)(22,"span",23,9)(24,"span",24,10),y(26,"span",25,11),V(28,Kj,5,10,"span",26),_()),2&r&&(f(6),jn("ngx-slider-transparent",i.fullBarTransparentClass),f(3),jn("ngx-slider-draggable",i.selectionBarDraggableClass),f(2),p("ngStyle",i.barStyle),f(),p("ngStyle",i.minPointerStyle),f(2),ec("display",i.range?"inherit":"none"),p("ngStyle",i.maxPointerStyle),f(12),jn("ngx-slider-ticks-values-under",i.ticksUnderValuesClass),p("hidden",!i.showTicks),f(2),p("ngForOf",i.ticks))},dependencies:[Do,ci,zn,Yb,Dr,Kg,So,Xj],styles:['.ngx-slider{display:inline-block;position:relative;height:4px;width:100%;margin:35px 0 15px;vertical-align:middle;-webkit-user-select:none;user-select:none;touch-action:pan-y} .ngx-slider.with-legend{margin-bottom:40px} .ngx-slider[disabled]{cursor:not-allowed} .ngx-slider[disabled] .ngx-slider-pointer{cursor:not-allowed;background-color:#d8e0f3} .ngx-slider[disabled] .ngx-slider-draggable{cursor:not-allowed} .ngx-slider[disabled] .ngx-slider-selection{background:#8b91a2} .ngx-slider[disabled] .ngx-slider-tick{cursor:not-allowed} .ngx-slider[disabled] .ngx-slider-tick.ngx-slider-selected{background:#8b91a2} .ngx-slider .ngx-slider-span{white-space:nowrap;position:absolute;display:inline-block} .ngx-slider .ngx-slider-base{width:100%;height:100%;padding:0} .ngx-slider .ngx-slider-bar-wrapper{left:0;box-sizing:border-box;margin-top:-16px;padding-top:16px;width:100%;height:32px;z-index:1} .ngx-slider .ngx-slider-draggable{cursor:move} .ngx-slider .ngx-slider-bar{left:0;width:100%;height:4px;z-index:1;background:#d8e0f3;-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px} .ngx-slider .ngx-slider-bar-wrapper.ngx-slider-transparent .ngx-slider-bar{background:transparent} .ngx-slider .ngx-slider-bar-wrapper.ngx-slider-left-out-selection .ngx-slider-bar{background:#df002d} .ngx-slider .ngx-slider-bar-wrapper.ngx-slider-right-out-selection .ngx-slider-bar{background:#03a688} .ngx-slider .ngx-slider-selection{z-index:2;background:#0db9f0;-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px} .ngx-slider .ngx-slider-pointer{cursor:pointer;width:32px;height:32px;top:-14px;background-color:#0db9f0;z-index:3;-webkit-border-radius:16px;-moz-border-radius:16px;border-radius:16px} .ngx-slider .ngx-slider-pointer:after{content:"";width:8px;height:8px;position:absolute;top:12px;left:12px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;background:#fff} .ngx-slider .ngx-slider-pointer:hover:after{background-color:#fff} .ngx-slider .ngx-slider-pointer.ngx-slider-active{z-index:4} .ngx-slider .ngx-slider-pointer.ngx-slider-active:after{background-color:#451aff} .ngx-slider .ngx-slider-bubble{cursor:default;bottom:16px;padding:1px 3px;color:#55637d;font-size:16px} .ngx-slider .ngx-slider-bubble.ngx-slider-limit{color:#55637d} .ngx-slider .ngx-slider-ticks{box-sizing:border-box;width:100%;height:0;position:absolute;left:0;top:-3px;margin:0;z-index:1;list-style:none} .ngx-slider .ngx-slider-ticks-values-under .ngx-slider-tick-value{top:auto;bottom:-36px} .ngx-slider .ngx-slider-tick{text-align:center;cursor:pointer;width:10px;height:10px;background:#d8e0f3;border-radius:50%;position:absolute;top:0;left:0;margin-left:11px} .ngx-slider .ngx-slider-tick.ngx-slider-selected{background:#0db9f0} .ngx-slider .ngx-slider-tick-value{position:absolute;top:-34px;transform:translate(-50%)} .ngx-slider .ngx-slider-tick-legend{position:absolute;top:24px;transform:translate(-50%);max-width:50px;white-space:normal} .ngx-slider.vertical{position:relative;width:4px;height:100%;margin:0 20px;padding:0;vertical-align:baseline;touch-action:pan-x} .ngx-slider.vertical .ngx-slider-base{width:100%;height:100%;padding:0} .ngx-slider.vertical .ngx-slider-bar-wrapper{top:auto;left:0;margin:0 0 0 -16px;padding:0 0 0 16px;height:100%;width:32px} .ngx-slider.vertical .ngx-slider-bar{bottom:0;left:auto;width:4px;height:100%} .ngx-slider.vertical .ngx-slider-pointer{left:-14px!important;top:auto;bottom:0} .ngx-slider.vertical .ngx-slider-bubble{left:16px!important;bottom:0} .ngx-slider.vertical .ngx-slider-ticks{height:100%;width:0;left:-3px;top:0;z-index:1} .ngx-slider.vertical .ngx-slider-tick{vertical-align:middle;margin-left:auto;margin-top:11px} .ngx-slider.vertical .ngx-slider-tick-value{left:24px;top:auto;transform:translateY(-28%)} .ngx-slider.vertical .ngx-slider-tick-legend{top:auto;right:24px;transform:translateY(-28%);max-width:none;white-space:nowrap} .ngx-slider.vertical .ngx-slider-ticks-values-under .ngx-slider-tick-value{bottom:auto;left:auto;right:24px} .ngx-slider *{transition:none} .ngx-slider.animate .ngx-slider-bar-wrapper{transition:all linear .3s} .ngx-slider.animate .ngx-slider-selection{transition:background-color linear .3s} .ngx-slider.animate .ngx-slider-pointer{transition:all linear .3s} .ngx-slider.animate .ngx-slider-pointer:after{transition:all linear .3s} .ngx-slider.animate .ngx-slider-bubble{transition:all linear .3s} .ngx-slider.animate .ngx-slider-bubble.ngx-slider-limit{transition:opacity linear .3s} .ngx-slider.animate .ngx-slider-bubble.ngx-slider-combined{transition:opacity linear .3s} .ngx-slider.animate .ngx-slider-tick{transition:background-color linear .3s}']})}return e})(),n3=(()=>{class e{static \u0275fac=function(r){return new(r||e)};static \u0275mod=cr({type:e});static \u0275inj=Nn({imports:[eE]})}return e})();class dM{constructor(){this.riskHotspotsSettings=null,this.coverageInfoSettings=null}}class r3{constructor(){this.showLineCoverage=!0,this.showBranchCoverage=!0,this.showMethodCoverage=!0,this.showFullMethodCoverage=!0,this.visibleMetrics=[],this.groupingMaximum=0,this.grouping=0,this.historyComparisionDate="",this.historyComparisionType="",this.filter="",this.lineCoverageMin=0,this.lineCoverageMax=100,this.branchCoverageMin=0,this.branchCoverageMax=100,this.methodCoverageMin=0,this.methodCoverageMax=100,this.methodFullCoverageMin=0,this.methodFullCoverageMax=100,this.sortBy="name",this.sortOrder="asc",this.collapseStates=[]}}class i3{constructor(n){this.et="",this.et=n.et,this.cl=n.cl,this.ucl=n.ucl,this.cal=n.cal,this.tl=n.tl,this.lcq=n.lcq,this.cb=n.cb,this.tb=n.tb,this.bcq=n.bcq,this.cm=n.cm,this.fcm=n.fcm,this.tm=n.tm,this.mcq=n.mcq,this.mfcq=n.mfcq}get coverageRatioText(){return 0===this.tl?"-":this.cl+"/"+this.cal}get branchCoverageRatioText(){return 0===this.tb?"-":this.cb+"/"+this.tb}get methodCoverageRatioText(){return 0===this.tm?"-":this.cm+"/"+this.tm}get methodFullCoverageRatioText(){return 0===this.tm?"-":this.fcm+"/"+this.tm}}class jt{static roundNumber(n){return Math.floor(n*Math.pow(10,jt.maximumDecimalPlacesForCoverageQuotas))/Math.pow(10,jt.maximumDecimalPlacesForCoverageQuotas)}static getNthOrLastIndexOf(n,t,r){let i=0,o=-1,s=-1;for(;i{this.historicCoverages.push(new i3(r))}),this.metrics=n.metrics}get coverage(){return 0===this.coverableLines?NaN:jt.roundNumber(100*this.coveredLines/this.coverableLines)}visible(n){if(""!==n.filter&&-1===this.name.toLowerCase().indexOf(n.filter.toLowerCase()))return!1;let t=this.coverage,r=t;if(t=Number.isNaN(t)?0:t,r=Number.isNaN(r)?100:r,n.lineCoverageMin>t||n.lineCoverageMaxi||n.branchCoverageMaxs||n.methodCoverageMaxl||n.methodFullCoverageMax=this.currentHistoricCoverage.lcq)return!1}else if("branchCoverageIncreaseOnly"===n.historyComparisionType){let u=this.branchCoverage;if(isNaN(u)||u<=this.currentHistoricCoverage.bcq)return!1}else if("branchCoverageDecreaseOnly"===n.historyComparisionType){let u=this.branchCoverage;if(isNaN(u)||u>=this.currentHistoricCoverage.bcq)return!1}else if("methodCoverageIncreaseOnly"===n.historyComparisionType){let u=this.methodCoverage;if(isNaN(u)||u<=this.currentHistoricCoverage.mcq)return!1}else if("methodCoverageDecreaseOnly"===n.historyComparisionType){let u=this.methodCoverage;if(isNaN(u)||u>=this.currentHistoricCoverage.mcq)return!1}else if("fullMethodCoverageIncreaseOnly"===n.historyComparisionType){let u=this.methodFullCoverage;if(isNaN(u)||u<=this.currentHistoricCoverage.mfcq)return!1}else if("fullMethodCoverageDecreaseOnly"===n.historyComparisionType){let u=this.methodFullCoverage;if(isNaN(u)||u>=this.currentHistoricCoverage.mfcq)return!1}return!0}updateCurrentHistoricCoverage(n){if(this.currentHistoricCoverage=null,""!==n)for(let t=0;t-1&&null===t}visible(n){if(""!==n.filter&&this.name.toLowerCase().indexOf(n.filter.toLowerCase())>-1)return!0;for(let t=0;t{class e{get nativeWindow(){return function o3(){return window}()}static{this.\u0275fac=function(r){return new(r||e)}}static{this.\u0275prov=re({token:e,factory:e.\u0275fac})}}return e})(),s3=(()=>{class e{constructor(){this.translations={}}static{this.\u0275fac=function(r){return new(r||e)}}static{this.\u0275cmp=sn({type:e,selectors:[["pro-button"]],inputs:{translations:"translations"},standalone:!1,decls:3,vars:1,consts:[["href","https://reportgenerator.io/pro","target","_blank",1,"pro-button","pro-button-tiny",3,"title"]],template:function(r,i){1&r&&(b(0,"\xa0"),y(1,"a",0),b(2,"PRO"),_()),2&r&&(f(),In("title",i.translations.methodCoverageProVersion))},encapsulation:2})}}return e})();function a3(e,n){if(1&e){const t=ge();y(0,"div",3)(1,"label")(2,"input",4),tt("ngModelChange",function(i){B(t);const o=v();return be(o.showBranchCoverage,i)||(o.showBranchCoverage=i),j(i)}),q("change",function(){B(t);const i=v();return j(i.showBranchCoverageChange.emit(i.showBranchCoverage))}),_(),b(3),_()()}if(2&e){const t=v();f(2),Qe("ngModel",t.showBranchCoverage),f(),U(" ",t.translations.branchCoverage,"")}}function l3(e,n){1&e&&x(0,"pro-button",9),2&e&&p("translations",v().translations)}function c3(e,n){1&e&&x(0,"pro-button",9),2&e&&p("translations",v().translations)}function u3(e,n){1&e&&x(0,"pro-button",9),2&e&&p("translations",v(2).translations)}function d3(e,n){1&e&&(y(0,"a",13),x(1,"i",14),_()),2&e&&p("href",v().$implicit.explanationUrl,ir)}function f3(e,n){if(1&e){const t=ge();y(0,"div",3)(1,"label")(2,"input",11),q("change",function(){const i=B(t).$implicit;return j(v(2).toggleMetric(i))}),_(),b(3),_(),b(4,"\xa0"),V(5,d3,2,1,"a",12),_()}if(2&e){const t=n.$implicit,r=v(2);f(2),p("checked",r.isMetricSelected(t))("disabled",!r.methodCoverageAvailable),f(),U(" ",t.name,""),f(2),p("ngIf",t.explanationUrl)}}function h3(e,n){if(1&e&&(X(0),x(1,"br")(2,"br"),y(3,"b"),b(4),_(),V(5,u3,1,1,"pro-button",7)(6,f3,6,4,"div",10),ee()),2&e){const t=v();f(4),O(t.translations.metrics),f(),p("ngIf",!t.methodCoverageAvailable),f(),p("ngForOf",t.metrics)}}let g3=(()=>{class e{constructor(){this.visible=!1,this.visibleChange=new we,this.translations={},this.branchCoverageAvailable=!1,this.methodCoverageAvailable=!1,this.metrics=[],this.showLineCoverage=!1,this.showLineCoverageChange=new we,this.showBranchCoverage=!1,this.showBranchCoverageChange=new we,this.showMethodCoverage=!1,this.showMethodCoverageChange=new we,this.showMethodFullCoverage=!1,this.showMethodFullCoverageChange=new we,this.visibleMetrics=[],this.visibleMetricsChange=new we}isMetricSelected(t){return void 0!==this.visibleMetrics.find(r=>r.name===t.name)}toggleMetric(t){let r=this.visibleMetrics.find(i=>i.name===t.name);r?this.visibleMetrics.splice(this.visibleMetrics.indexOf(r),1):this.visibleMetrics.push(t),this.visibleMetrics=[...this.visibleMetrics],this.visibleMetricsChange.emit(this.visibleMetrics)}close(){this.visible=!1,this.visibleChange.emit(this.visible)}cancelEvent(t){t.stopPropagation()}static{this.\u0275fac=function(r){return new(r||e)}}static{this.\u0275cmp=sn({type:e,selectors:[["popup"]],inputs:{visible:"visible",translations:"translations",branchCoverageAvailable:"branchCoverageAvailable",methodCoverageAvailable:"methodCoverageAvailable",metrics:"metrics",showLineCoverage:"showLineCoverage",showBranchCoverage:"showBranchCoverage",showMethodCoverage:"showMethodCoverage",showMethodFullCoverage:"showMethodFullCoverage",visibleMetrics:"visibleMetrics"},outputs:{visibleChange:"visibleChange",showLineCoverageChange:"showLineCoverageChange",showBranchCoverageChange:"showBranchCoverageChange",showMethodCoverageChange:"showMethodCoverageChange",showMethodFullCoverageChange:"showMethodFullCoverageChange",visibleMetricsChange:"visibleMetricsChange"},standalone:!1,decls:22,vars:13,consts:[[1,"popup-container",3,"click"],[1,"popup",3,"click"],[1,"close",3,"click"],[1,"mt-1"],["type","checkbox",3,"ngModelChange","change","ngModel"],["class","mt-1",4,"ngIf"],["type","checkbox",3,"ngModelChange","change","ngModel","disabled"],[3,"translations",4,"ngIf"],[4,"ngIf"],[3,"translations"],["class","mt-1",4,"ngFor","ngForOf"],["type","checkbox",3,"change","checked","disabled"],["target","_blank",3,"href",4,"ngIf"],["target","_blank",3,"href"],[1,"icon-info-circled"]],template:function(r,i){1&r&&(y(0,"div",0),q("click",function(){return i.close()}),y(1,"div",1),q("click",function(s){return i.cancelEvent(s)}),y(2,"div",2),q("click",function(){return i.close()}),b(3,"X"),_(),y(4,"b"),b(5),_(),y(6,"div",3)(7,"label")(8,"input",4),tt("ngModelChange",function(s){return be(i.showLineCoverage,s)||(i.showLineCoverage=s),s}),q("change",function(){return i.showLineCoverageChange.emit(i.showLineCoverage)}),_(),b(9),_()(),V(10,a3,4,2,"div",5),y(11,"div",3)(12,"label")(13,"input",6),tt("ngModelChange",function(s){return be(i.showMethodCoverage,s)||(i.showMethodCoverage=s),s}),q("change",function(){return i.showMethodCoverageChange.emit(i.showMethodCoverage)}),_(),b(14),_(),V(15,l3,1,1,"pro-button",7),_(),y(16,"div",3)(17,"label")(18,"input",6),tt("ngModelChange",function(s){return be(i.showMethodFullCoverage,s)||(i.showMethodFullCoverage=s),s}),q("change",function(){return i.showMethodFullCoverageChange.emit(i.showMethodFullCoverage)}),_(),b(19),_(),V(20,c3,1,1,"pro-button",7),_(),V(21,h3,7,3,"ng-container",8),_()()),2&r&&(f(5),O(i.translations.coverageTypes),f(3),Qe("ngModel",i.showLineCoverage),f(),U(" ",i.translations.coverage,""),f(),p("ngIf",i.branchCoverageAvailable),f(3),Qe("ngModel",i.showMethodCoverage),p("disabled",!i.methodCoverageAvailable),f(),U(" ",i.translations.methodCoverage,""),f(),p("ngIf",!i.methodCoverageAvailable),f(3),Qe("ngModel",i.showMethodFullCoverage),p("disabled",!i.methodCoverageAvailable),f(),U(" ",i.translations.fullMethodCoverage,""),f(),p("ngIf",!i.methodCoverageAvailable),f(),p("ngIf",i.metrics.length>0))},dependencies:[ci,zn,Ig,jc,aa,s3],encapsulation:2})}}return e})();function p3(e,n){1&e&&x(0,"td",3)}function m3(e,n){1&e&&x(0,"td"),2&e&&Kt("green ",v().greenClass,"")}function v3(e,n){1&e&&x(0,"td"),2&e&&Kt("red ",v().redClass,"")}let hM=(()=>{class e{constructor(){this.grayVisible=!0,this.greenVisible=!1,this.redVisible=!1,this.greenClass="",this.redClass="",this._percentage=NaN}get percentage(){return this._percentage}set percentage(t){this._percentage=t,this.grayVisible=isNaN(t),this.greenVisible=!isNaN(t)&&Math.round(t)>0,this.redVisible=!isNaN(t)&&100-Math.round(t)>0,this.greenClass="covered"+Math.round(t),this.redClass="covered"+(100-Math.round(t))}static{this.\u0275fac=function(r){return new(r||e)}}static{this.\u0275cmp=sn({type:e,selectors:[["coverage-bar"]],inputs:{percentage:"percentage"},standalone:!1,decls:4,vars:3,consts:[[1,"coverage"],["class","gray covered100",4,"ngIf"],[3,"class",4,"ngIf"],[1,"gray","covered100"]],template:function(r,i){1&r&&(y(0,"table",0),V(1,p3,1,0,"td",1)(2,m3,1,3,"td",2)(3,v3,1,3,"td",2),_()),2&r&&(f(),p("ngIf",i.grayVisible),f(),p("ngIf",i.greenVisible),f(),p("ngIf",i.redVisible))},dependencies:[zn],encapsulation:2,changeDetection:0})}}return e})();const _3=["codeelement-row",""],y3=(e,n)=>({"icon-plus":e,"icon-minus":n});function C3(e,n){if(1&e&&(y(0,"th",5),b(1),_()),2&e){const t=v();f(),O(t.element.coveredLines)}}function w3(e,n){if(1&e&&(y(0,"th",5),b(1),_()),2&e){const t=v();f(),O(t.element.uncoveredLines)}}function D3(e,n){if(1&e&&(y(0,"th",5),b(1),_()),2&e){const t=v();f(),O(t.element.coverableLines)}}function b3(e,n){if(1&e&&(y(0,"th",5),b(1),_()),2&e){const t=v();f(),O(t.element.totalLines)}}function E3(e,n){if(1&e&&(y(0,"th",6),b(1),_()),2&e){const t=v();p("title",t.element.coverageRatioText),f(),O(t.element.coveragePercentage)}}function I3(e,n){if(1&e&&(y(0,"th",5),x(1,"coverage-bar",7),_()),2&e){const t=v();f(),p("percentage",t.element.coverage)}}function M3(e,n){if(1&e&&(y(0,"th",5),b(1),_()),2&e){const t=v();f(),O(t.element.coveredBranches)}}function T3(e,n){if(1&e&&(y(0,"th",5),b(1),_()),2&e){const t=v();f(),O(t.element.totalBranches)}}function S3(e,n){if(1&e&&(y(0,"th",6),b(1),_()),2&e){const t=v();p("title",t.element.branchCoverageRatioText),f(),O(t.element.branchCoveragePercentage)}}function N3(e,n){if(1&e&&(y(0,"th",5),x(1,"coverage-bar",7),_()),2&e){const t=v();f(),p("percentage",t.element.branchCoverage)}}function x3(e,n){if(1&e&&(y(0,"th",5),b(1),_()),2&e){const t=v();f(),O(t.element.coveredMethods)}}function O3(e,n){if(1&e&&(y(0,"th",5),b(1),_()),2&e){const t=v();f(),O(t.element.totalMethods)}}function A3(e,n){if(1&e&&(y(0,"th",6),b(1),_()),2&e){const t=v();p("title",t.element.methodCoverageRatioText),f(),O(t.element.methodCoveragePercentage)}}function R3(e,n){if(1&e&&(y(0,"th",5),x(1,"coverage-bar",7),_()),2&e){const t=v();f(),p("percentage",t.element.methodCoverage)}}function k3(e,n){if(1&e&&(y(0,"th",5),b(1),_()),2&e){const t=v();f(),O(t.element.fullyCoveredMethods)}}function F3(e,n){if(1&e&&(y(0,"th",5),b(1),_()),2&e){const t=v();f(),O(t.element.totalMethods)}}function L3(e,n){if(1&e&&(y(0,"th",6),b(1),_()),2&e){const t=v();p("title",t.element.methodFullCoverageRatioText),f(),O(t.element.methodFullCoveragePercentage)}}function P3(e,n){if(1&e&&(y(0,"th",5),x(1,"coverage-bar",7),_()),2&e){const t=v();f(),p("percentage",t.element.methodFullCoverage)}}function V3(e,n){1&e&&x(0,"th",5)}let H3=(()=>{class e{constructor(){this.collapsed=!1,this.lineCoverageAvailable=!1,this.branchCoverageAvailable=!1,this.methodCoverageAvailable=!1,this.methodFullCoverageAvailable=!1,this.visibleMetrics=[]}static{this.\u0275fac=function(r){return new(r||e)}}static{this.\u0275cmp=sn({type:e,selectors:[["","codeelement-row",""]],inputs:{element:"element",collapsed:"collapsed",lineCoverageAvailable:"lineCoverageAvailable",branchCoverageAvailable:"branchCoverageAvailable",methodCoverageAvailable:"methodCoverageAvailable",methodFullCoverageAvailable:"methodFullCoverageAvailable",visibleMetrics:"visibleMetrics"},standalone:!1,attrs:_3,decls:23,vars:24,consts:[["href","#",3,"click"],[3,"ngClass"],["class","right",4,"ngIf"],["class","right",3,"title",4,"ngIf"],["class","right",4,"ngFor","ngForOf"],[1,"right"],[1,"right",3,"title"],[3,"percentage"]],template:function(r,i){1&r&&(y(0,"th")(1,"a",0),q("click",function(s){return i.element.toggleCollapse(s)}),x(2,"i",1),b(3),_()(),V(4,C3,2,1,"th",2)(5,w3,2,1,"th",2)(6,D3,2,1,"th",2)(7,b3,2,1,"th",2)(8,E3,2,2,"th",3)(9,I3,2,1,"th",2)(10,M3,2,1,"th",2)(11,T3,2,1,"th",2)(12,S3,2,2,"th",3)(13,N3,2,1,"th",2)(14,x3,2,1,"th",2)(15,O3,2,1,"th",2)(16,A3,2,2,"th",3)(17,R3,2,1,"th",2)(18,k3,2,1,"th",2)(19,F3,2,1,"th",2)(20,L3,2,2,"th",3)(21,P3,2,1,"th",2)(22,V3,1,0,"th",4)),2&r&&(f(2),p("ngClass",xh(21,y3,i.element.collapsed,!i.element.collapsed)),f(),U(" ",i.element.name,""),f(),p("ngIf",i.lineCoverageAvailable),f(),p("ngIf",i.lineCoverageAvailable),f(),p("ngIf",i.lineCoverageAvailable),f(),p("ngIf",i.lineCoverageAvailable),f(),p("ngIf",i.lineCoverageAvailable),f(),p("ngIf",i.lineCoverageAvailable),f(),p("ngIf",i.branchCoverageAvailable),f(),p("ngIf",i.branchCoverageAvailable),f(),p("ngIf",i.branchCoverageAvailable),f(),p("ngIf",i.branchCoverageAvailable),f(),p("ngIf",i.methodCoverageAvailable),f(),p("ngIf",i.methodCoverageAvailable),f(),p("ngIf",i.methodCoverageAvailable),f(),p("ngIf",i.methodCoverageAvailable),f(),p("ngIf",i.methodFullCoverageAvailable),f(),p("ngIf",i.methodFullCoverageAvailable),f(),p("ngIf",i.methodFullCoverageAvailable),f(),p("ngIf",i.methodFullCoverageAvailable),f(),p("ngForOf",i.visibleMetrics))},dependencies:[Do,ci,zn,hM],encapsulation:2,changeDetection:0})}}return e})();const B3=["coverage-history-chart",""];let j3=(()=>{class e{constructor(){this.path=null,this._historicCoverages=[]}get historicCoverages(){return this._historicCoverages}set historicCoverages(t){if(this._historicCoverages=t,t.length>1){let r="";for(let i=0;i({historiccoverageoffset:e});function $3(e,n){if(1&e&&(y(0,"a",5),b(1),_()),2&e){const t=v();p("href",t.clazz.reportPath,ir),f(),O(t.clazz.name)}}function z3(e,n){if(1&e&&(X(0),b(1),ee()),2&e){const t=v();f(),O(t.clazz.name)}}function G3(e,n){if(1&e&&(X(0),y(1,"div"),b(2),_(),y(3,"div",7),b(4),_(),ee()),2&e){const t=v(2);f(),Kt("currenthistory ",t.getClassName(t.clazz.coveredLines,t.clazz.currentHistoricCoverage.cl),""),f(),U(" ",t.clazz.coveredLines," "),f(),p("title",t.clazz.currentHistoricCoverage.et),f(),U(" ",t.clazz.currentHistoricCoverage.cl," ")}}function q3(e,n){if(1&e&&(X(0),b(1),ee()),2&e){const t=v(2);f(),U(" ",t.clazz.coveredLines," ")}}function W3(e,n){if(1&e&&(y(0,"td",6),V(1,G3,5,6,"ng-container",1)(2,q3,2,1,"ng-container",1),_()),2&e){const t=v();f(),p("ngIf",null!==t.clazz.currentHistoricCoverage),f(),p("ngIf",null===t.clazz.currentHistoricCoverage)}}function Z3(e,n){if(1&e&&(X(0),y(1,"div"),b(2),_(),y(3,"div",7),b(4),_(),ee()),2&e){const t=v(2);f(),Kt("currenthistory ",t.getClassName(t.clazz.currentHistoricCoverage.ucl,t.clazz.uncoveredLines),""),f(),U(" ",t.clazz.uncoveredLines," "),f(),p("title",t.clazz.currentHistoricCoverage.et),f(),U(" ",t.clazz.currentHistoricCoverage.ucl," ")}}function Q3(e,n){if(1&e&&(X(0),b(1),ee()),2&e){const t=v(2);f(),U(" ",t.clazz.uncoveredLines," ")}}function Y3(e,n){if(1&e&&(y(0,"td",6),V(1,Z3,5,6,"ng-container",1)(2,Q3,2,1,"ng-container",1),_()),2&e){const t=v();f(),p("ngIf",null!==t.clazz.currentHistoricCoverage),f(),p("ngIf",null===t.clazz.currentHistoricCoverage)}}function K3(e,n){if(1&e&&(X(0),y(1,"div",8),b(2),_(),y(3,"div",7),b(4),_(),ee()),2&e){const t=v(2);f(2),O(t.clazz.coverableLines),f(),p("title",t.clazz.currentHistoricCoverage.et),f(),O(t.clazz.currentHistoricCoverage.cal)}}function J3(e,n){if(1&e&&(X(0),b(1),ee()),2&e){const t=v(2);f(),U(" ",t.clazz.coverableLines," ")}}function X3(e,n){if(1&e&&(y(0,"td",6),V(1,K3,5,3,"ng-container",1)(2,J3,2,1,"ng-container",1),_()),2&e){const t=v();f(),p("ngIf",null!==t.clazz.currentHistoricCoverage),f(),p("ngIf",null===t.clazz.currentHistoricCoverage)}}function eU(e,n){if(1&e&&(X(0),y(1,"div",8),b(2),_(),y(3,"div",7),b(4),_(),ee()),2&e){const t=v(2);f(2),O(t.clazz.totalLines),f(),p("title",t.clazz.currentHistoricCoverage.et),f(),O(t.clazz.currentHistoricCoverage.tl)}}function tU(e,n){if(1&e&&(X(0),b(1),ee()),2&e){const t=v(2);f(),U(" ",t.clazz.totalLines," ")}}function nU(e,n){if(1&e&&(y(0,"td",6),V(1,eU,5,3,"ng-container",1)(2,tU,2,1,"ng-container",1),_()),2&e){const t=v();f(),p("ngIf",null!==t.clazz.currentHistoricCoverage),f(),p("ngIf",null===t.clazz.currentHistoricCoverage)}}function rU(e,n){if(1&e&&x(0,"div",11),2&e){const t=v(2);In("title",t.translations.history+": "+t.translations.coverage),p("historicCoverages",t.clazz.lineCoverageHistory)("ngClass",_o(3,eu,null!==t.clazz.currentHistoricCoverage))}}function iU(e,n){if(1&e&&(X(0),y(1,"div"),b(2),_(),y(3,"div",7),b(4),_(),ee()),2&e){const t=v(2);f(),Kt("currenthistory ",t.getClassName(t.clazz.coverage,t.clazz.currentHistoricCoverage.lcq),""),f(),U(" ",t.clazz.coveragePercentage," "),f(),p("title",t.clazz.currentHistoricCoverage.et+": "+t.clazz.currentHistoricCoverage.coverageRatioText),f(),U("",t.clazz.currentHistoricCoverage.lcq,"%")}}function oU(e,n){if(1&e&&(X(0),b(1),ee()),2&e){const t=v(2);f(),U(" ",t.clazz.coveragePercentage," ")}}function sU(e,n){if(1&e&&(y(0,"td",9),V(1,rU,1,5,"div",10)(2,iU,5,6,"ng-container",1)(3,oU,2,1,"ng-container",1),_()),2&e){const t=v();p("title",t.clazz.coverageRatioText),f(),p("ngIf",t.clazz.lineCoverageHistory.length>1),f(),p("ngIf",null!==t.clazz.currentHistoricCoverage),f(),p("ngIf",null===t.clazz.currentHistoricCoverage)}}function aU(e,n){if(1&e&&(y(0,"td",6),x(1,"coverage-bar",12),_()),2&e){const t=v();f(),p("percentage",t.clazz.coverage)}}function lU(e,n){if(1&e&&(X(0),y(1,"div"),b(2),_(),y(3,"div",7),b(4),_(),ee()),2&e){const t=v(2);f(),Kt("currenthistory ",t.getClassName(t.clazz.coveredBranches,t.clazz.currentHistoricCoverage.cb),""),f(),U(" ",t.clazz.coveredBranches," "),f(),p("title",t.clazz.currentHistoricCoverage.et),f(),U(" ",t.clazz.currentHistoricCoverage.cb," ")}}function cU(e,n){if(1&e&&(X(0),b(1),ee()),2&e){const t=v(2);f(),U(" ",t.clazz.coveredBranches," ")}}function uU(e,n){if(1&e&&(y(0,"td",6),V(1,lU,5,6,"ng-container",1)(2,cU,2,1,"ng-container",1),_()),2&e){const t=v();f(),p("ngIf",null!==t.clazz.currentHistoricCoverage),f(),p("ngIf",null===t.clazz.currentHistoricCoverage)}}function dU(e,n){if(1&e&&(X(0),y(1,"div",8),b(2),_(),y(3,"div",7),b(4),_(),ee()),2&e){const t=v(2);f(2),O(t.clazz.totalBranches),f(),p("title",t.clazz.currentHistoricCoverage.et),f(),O(t.clazz.currentHistoricCoverage.tb)}}function fU(e,n){if(1&e&&(X(0),b(1),ee()),2&e){const t=v(2);f(),U(" ",t.clazz.totalBranches," ")}}function hU(e,n){if(1&e&&(y(0,"td",6),V(1,dU,5,3,"ng-container",1)(2,fU,2,1,"ng-container",1),_()),2&e){const t=v();f(),p("ngIf",null!==t.clazz.currentHistoricCoverage),f(),p("ngIf",null===t.clazz.currentHistoricCoverage)}}function gU(e,n){if(1&e&&x(0,"div",14),2&e){const t=v(2);In("title",t.translations.history+": "+t.translations.branchCoverage),p("historicCoverages",t.clazz.branchCoverageHistory)("ngClass",_o(3,eu,null!==t.clazz.currentHistoricCoverage))}}function pU(e,n){if(1&e&&(X(0),y(1,"div"),b(2),_(),y(3,"div",7),b(4),_(),ee()),2&e){const t=v(2);f(),Kt("currenthistory ",t.getClassName(t.clazz.branchCoverage,t.clazz.currentHistoricCoverage.bcq),""),f(),U(" ",t.clazz.branchCoveragePercentage," "),f(),p("title",t.clazz.currentHistoricCoverage.et+": "+t.clazz.currentHistoricCoverage.branchCoverageRatioText),f(),U("",t.clazz.currentHistoricCoverage.bcq,"%")}}function mU(e,n){if(1&e&&(X(0),b(1),ee()),2&e){const t=v(2);f(),U(" ",t.clazz.branchCoveragePercentage," ")}}function vU(e,n){if(1&e&&(y(0,"td",9),V(1,gU,1,5,"div",13)(2,pU,5,6,"ng-container",1)(3,mU,2,1,"ng-container",1),_()),2&e){const t=v();p("title",t.clazz.branchCoverageRatioText),f(),p("ngIf",t.clazz.branchCoverageHistory.length>1),f(),p("ngIf",null!==t.clazz.currentHistoricCoverage),f(),p("ngIf",null===t.clazz.currentHistoricCoverage)}}function _U(e,n){if(1&e&&(y(0,"td",6),x(1,"coverage-bar",12),_()),2&e){const t=v();f(),p("percentage",t.clazz.branchCoverage)}}function yU(e,n){if(1&e&&(X(0),y(1,"div"),b(2),_(),y(3,"div",7),b(4),_(),ee()),2&e){const t=v(2);f(),Kt("currenthistory ",t.getClassName(t.clazz.coveredMethods,t.clazz.currentHistoricCoverage.cm),""),f(),U(" ",t.clazz.coveredMethods," "),f(),p("title",t.clazz.currentHistoricCoverage.et),f(),U(" ",t.clazz.currentHistoricCoverage.cm," ")}}function CU(e,n){if(1&e&&(X(0),b(1),ee()),2&e){const t=v(2);f(),U(" ",t.clazz.coveredMethods," ")}}function wU(e,n){if(1&e&&(y(0,"td",6),V(1,yU,5,6,"ng-container",1)(2,CU,2,1,"ng-container",1),_()),2&e){const t=v();f(),p("ngIf",null!==t.clazz.currentHistoricCoverage),f(),p("ngIf",null===t.clazz.currentHistoricCoverage)}}function DU(e,n){if(1&e&&(X(0),y(1,"div",8),b(2),_(),y(3,"div",7),b(4),_(),ee()),2&e){const t=v(2);f(2),O(t.clazz.totalMethods),f(),p("title",t.clazz.currentHistoricCoverage.et),f(),O(t.clazz.currentHistoricCoverage.tm)}}function bU(e,n){if(1&e&&(X(0),b(1),ee()),2&e){const t=v(2);f(),U(" ",t.clazz.totalMethods," ")}}function EU(e,n){if(1&e&&(y(0,"td",6),V(1,DU,5,3,"ng-container",1)(2,bU,2,1,"ng-container",1),_()),2&e){const t=v();f(),p("ngIf",null!==t.clazz.currentHistoricCoverage),f(),p("ngIf",null===t.clazz.currentHistoricCoverage)}}function IU(e,n){if(1&e&&x(0,"div",16),2&e){const t=v(2);In("title",t.translations.history+": "+t.translations.methodCoverage),p("historicCoverages",t.clazz.methodCoverageHistory)("ngClass",_o(3,eu,null!==t.clazz.currentHistoricCoverage))}}function MU(e,n){if(1&e&&(X(0),y(1,"div"),b(2),_(),y(3,"div",7),b(4),_(),ee()),2&e){const t=v(2);f(),Kt("currenthistory ",t.getClassName(t.clazz.methodCoverage,t.clazz.currentHistoricCoverage.mcq),""),f(),U(" ",t.clazz.methodCoveragePercentage," "),f(),p("title",t.clazz.currentHistoricCoverage.et+": "+t.clazz.currentHistoricCoverage.methodCoverageRatioText),f(),U("",t.clazz.currentHistoricCoverage.mcq,"%")}}function TU(e,n){if(1&e&&(X(0),b(1),ee()),2&e){const t=v(2);f(),U(" ",t.clazz.methodCoveragePercentage," ")}}function SU(e,n){if(1&e&&(y(0,"td",9),V(1,IU,1,5,"div",15)(2,MU,5,6,"ng-container",1)(3,TU,2,1,"ng-container",1),_()),2&e){const t=v();p("title",t.clazz.methodCoverageRatioText),f(),p("ngIf",t.clazz.methodCoverageHistory.length>1),f(),p("ngIf",null!==t.clazz.currentHistoricCoverage),f(),p("ngIf",null===t.clazz.currentHistoricCoverage)}}function NU(e,n){if(1&e&&(y(0,"td",6),x(1,"coverage-bar",12),_()),2&e){const t=v();f(),p("percentage",t.clazz.methodCoverage)}}function xU(e,n){if(1&e&&(X(0),y(1,"div"),b(2),_(),y(3,"div",7),b(4),_(),ee()),2&e){const t=v(2);f(),Kt("currenthistory ",t.getClassName(t.clazz.fullyCoveredMethods,t.clazz.currentHistoricCoverage.fcm),""),f(),U(" ",t.clazz.fullyCoveredMethods," "),f(),p("title",t.clazz.currentHistoricCoverage.et),f(),U(" ",t.clazz.currentHistoricCoverage.fcm," ")}}function OU(e,n){if(1&e&&(X(0),b(1),ee()),2&e){const t=v(2);f(),U(" ",t.clazz.fullyCoveredMethods," ")}}function AU(e,n){if(1&e&&(y(0,"td",6),V(1,xU,5,6,"ng-container",1)(2,OU,2,1,"ng-container",1),_()),2&e){const t=v();f(),p("ngIf",null!==t.clazz.currentHistoricCoverage),f(),p("ngIf",null===t.clazz.currentHistoricCoverage)}}function RU(e,n){if(1&e&&(X(0),y(1,"div",8),b(2),_(),y(3,"div",7),b(4),_(),ee()),2&e){const t=v(2);f(2),O(t.clazz.totalMethods),f(),p("title",t.clazz.currentHistoricCoverage.et),f(),O(t.clazz.currentHistoricCoverage.tm)}}function kU(e,n){if(1&e&&(X(0),b(1),ee()),2&e){const t=v(2);f(),U(" ",t.clazz.totalMethods," ")}}function FU(e,n){if(1&e&&(y(0,"td",6),V(1,RU,5,3,"ng-container",1)(2,kU,2,1,"ng-container",1),_()),2&e){const t=v();f(),p("ngIf",null!==t.clazz.currentHistoricCoverage),f(),p("ngIf",null===t.clazz.currentHistoricCoverage)}}function LU(e,n){if(1&e&&x(0,"div",18),2&e){const t=v(2);In("title",t.translations.history+": "+t.translations.fullMethodCoverage),p("historicCoverages",t.clazz.methodFullCoverageHistory)("ngClass",_o(3,eu,null!==t.clazz.currentHistoricCoverage))}}function PU(e,n){if(1&e&&(X(0),y(1,"div"),b(2),_(),y(3,"div",7),b(4),_(),ee()),2&e){const t=v(2);f(),Kt("currenthistory ",t.getClassName(t.clazz.methodFullCoverage,t.clazz.currentHistoricCoverage.mfcq),""),f(),U(" ",t.clazz.methodFullCoveragePercentage," "),f(),p("title",t.clazz.currentHistoricCoverage.et+": "+t.clazz.currentHistoricCoverage.methodFullCoverageRatioText),f(),U("",t.clazz.currentHistoricCoverage.mfcq,"%")}}function VU(e,n){if(1&e&&(X(0),b(1),ee()),2&e){const t=v(2);f(),U(" ",t.clazz.methodFullCoveragePercentage," ")}}function HU(e,n){if(1&e&&(y(0,"td",9),V(1,LU,1,5,"div",17)(2,PU,5,6,"ng-container",1)(3,VU,2,1,"ng-container",1),_()),2&e){const t=v();p("title",t.clazz.methodFullCoverageRatioText),f(),p("ngIf",t.clazz.methodFullCoverageHistory.length>1),f(),p("ngIf",null!==t.clazz.currentHistoricCoverage),f(),p("ngIf",null===t.clazz.currentHistoricCoverage)}}function BU(e,n){if(1&e&&(y(0,"td",6),x(1,"coverage-bar",12),_()),2&e){const t=v();f(),p("percentage",t.clazz.methodFullCoverage)}}function jU(e,n){if(1&e&&(y(0,"td",6),b(1),_()),2&e){const t=n.$implicit,r=v();f(),O(r.clazz.metrics[t.abbreviation])}}let UU=(()=>{class e{constructor(){this.translations={},this.lineCoverageAvailable=!1,this.branchCoverageAvailable=!1,this.methodCoverageAvailable=!1,this.methodFullCoverageAvailable=!1,this.visibleMetrics=[],this.historyComparisionDate=""}getClassName(t,r){return t>r?"lightgreen":t({"icon-up-dir_active":e,"icon-down-dir_active":n,"icon-up-down-dir":t});function $U(e,n){if(1&e){const t=ge();y(0,"popup",30),tt("visibleChange",function(i){B(t);const o=v(2);return be(o.popupVisible,i)||(o.popupVisible=i),j(i)})("showLineCoverageChange",function(i){B(t);const o=v(2);return be(o.settings.showLineCoverage,i)||(o.settings.showLineCoverage=i),j(i)})("showBranchCoverageChange",function(i){B(t);const o=v(2);return be(o.settings.showBranchCoverage,i)||(o.settings.showBranchCoverage=i),j(i)})("showMethodCoverageChange",function(i){B(t);const o=v(2);return be(o.settings.showMethodCoverage,i)||(o.settings.showMethodCoverage=i),j(i)})("showMethodFullCoverageChange",function(i){B(t);const o=v(2);return be(o.settings.showFullMethodCoverage,i)||(o.settings.showFullMethodCoverage=i),j(i)})("visibleMetricsChange",function(i){B(t);const o=v(2);return be(o.settings.visibleMetrics,i)||(o.settings.visibleMetrics=i),j(i)}),_()}if(2&e){const t=v(2);Qe("visible",t.popupVisible),p("translations",t.translations)("branchCoverageAvailable",t.branchCoverageAvailable)("methodCoverageAvailable",t.methodCoverageAvailable)("metrics",t.metrics),Qe("showLineCoverage",t.settings.showLineCoverage)("showBranchCoverage",t.settings.showBranchCoverage)("showMethodCoverage",t.settings.showMethodCoverage)("showMethodFullCoverage",t.settings.showFullMethodCoverage)("visibleMetrics",t.settings.visibleMetrics)}}function zU(e,n){if(1&e&&(X(0),b(1),ee()),2&e){const t=v(2);f(),O(t.translations.noGrouping)}}function GU(e,n){if(1&e&&(X(0),b(1),ee()),2&e){const t=v(2);f(),O(t.translations.byAssembly)}}function qU(e,n){if(1&e&&(X(0),b(1),ee()),2&e){const t=v(2);f(),O(t.translations.byNamespace+" "+t.settings.grouping)}}function WU(e,n){if(1&e&&(y(0,"option",34),b(1),_()),2&e){const t=n.$implicit;p("value",t),f(),O(t)}}function ZU(e,n){1&e&&x(0,"br")}function QU(e,n){if(1&e&&(y(0,"option",44),b(1),_()),2&e){const t=v(4);f(),U(" ",t.translations.branchCoverageIncreaseOnly," ")}}function YU(e,n){if(1&e&&(y(0,"option",45),b(1),_()),2&e){const t=v(4);f(),U(" ",t.translations.branchCoverageDecreaseOnly," ")}}function KU(e,n){if(1&e&&(y(0,"option",46),b(1),_()),2&e){const t=v(4);f(),U(" ",t.translations.methodCoverageIncreaseOnly," ")}}function JU(e,n){if(1&e&&(y(0,"option",47),b(1),_()),2&e){const t=v(4);f(),U(" ",t.translations.methodCoverageDecreaseOnly," ")}}function XU(e,n){if(1&e&&(y(0,"option",48),b(1),_()),2&e){const t=v(4);f(),U(" ",t.translations.fullMethodCoverageIncreaseOnly," ")}}function e$(e,n){if(1&e&&(y(0,"option",49),b(1),_()),2&e){const t=v(4);f(),U(" ",t.translations.fullMethodCoverageDecreaseOnly," ")}}function t$(e,n){if(1&e){const t=ge();y(0,"div")(1,"select",31),tt("ngModelChange",function(i){B(t);const o=v(3);return be(o.settings.historyComparisionType,i)||(o.settings.historyComparisionType=i),j(i)}),y(2,"option",32),b(3),_(),y(4,"option",35),b(5),_(),y(6,"option",36),b(7),_(),y(8,"option",37),b(9),_(),V(10,QU,2,1,"option",38)(11,YU,2,1,"option",39)(12,KU,2,1,"option",40)(13,JU,2,1,"option",41)(14,XU,2,1,"option",42)(15,e$,2,1,"option",43),_()()}if(2&e){const t=v(3);f(),Qe("ngModel",t.settings.historyComparisionType),f(2),O(t.translations.filter),f(2),O(t.translations.allChanges),f(2),O(t.translations.lineCoverageIncreaseOnly),f(2),O(t.translations.lineCoverageDecreaseOnly),f(),p("ngIf",t.branchCoverageAvailable),f(),p("ngIf",t.branchCoverageAvailable),f(),p("ngIf",t.methodCoverageAvailable),f(),p("ngIf",t.methodCoverageAvailable),f(),p("ngIf",t.methodCoverageAvailable),f(),p("ngIf",t.methodCoverageAvailable)}}function n$(e,n){if(1&e){const t=ge();X(0),y(1,"div"),b(2),y(3,"select",31),tt("ngModelChange",function(i){B(t);const o=v(2);return be(o.settings.historyComparisionDate,i)||(o.settings.historyComparisionDate=i),j(i)}),q("ngModelChange",function(){return B(t),j(v(2).updateCurrentHistoricCoverage())}),y(4,"option",32),b(5),_(),V(6,WU,2,2,"option",33),_()(),V(7,ZU,1,0,"br",0)(8,t$,16,11,"div",0),ee()}if(2&e){const t=v(2);f(2),U(" ",t.translations.compareHistory," "),f(),Qe("ngModel",t.settings.historyComparisionDate),f(2),O(t.translations.date),f(),p("ngForOf",t.historicCoverageExecutionTimes),f(),p("ngIf",""!==t.settings.historyComparisionDate),f(),p("ngIf",""!==t.settings.historyComparisionDate)}}function r$(e,n){1&e&&x(0,"col",50)}function i$(e,n){1&e&&x(0,"col",51)}function o$(e,n){1&e&&x(0,"col",52)}function s$(e,n){1&e&&x(0,"col",53)}function a$(e,n){1&e&&x(0,"col",54)}function l$(e,n){1&e&&x(0,"col",55)}function c$(e,n){1&e&&x(0,"col",50)}function u$(e,n){1&e&&x(0,"col",53)}function d$(e,n){1&e&&x(0,"col",54)}function f$(e,n){1&e&&x(0,"col",55)}function h$(e,n){1&e&&x(0,"col",50)}function g$(e,n){1&e&&x(0,"col",53)}function p$(e,n){1&e&&x(0,"col",54)}function m$(e,n){1&e&&x(0,"col",55)}function v$(e,n){1&e&&x(0,"col",50)}function _$(e,n){1&e&&x(0,"col",53)}function y$(e,n){1&e&&x(0,"col",54)}function C$(e,n){1&e&&x(0,"col",55)}function w$(e,n){1&e&&x(0,"col",55)}function D$(e,n){if(1&e&&(y(0,"th",56),b(1),_()),2&e){const t=v(2);f(),O(t.translations.coverage)}}function b$(e,n){if(1&e&&(y(0,"th",57),b(1),_()),2&e){const t=v(2);f(),O(t.translations.branchCoverage)}}function E$(e,n){if(1&e&&(y(0,"th",57),b(1),_()),2&e){const t=v(2);f(),O(t.translations.methodCoverage)}}function I$(e,n){if(1&e&&(y(0,"th",57),b(1),_()),2&e){const t=v(2);f(),O(t.translations.fullMethodCoverage)}}function M$(e,n){if(1&e&&(y(0,"th",58),b(1),_()),2&e){const t=v(2);_t("colspan",t.settings.visibleMetrics.length),f(),O(t.translations.metrics)}}function T$(e,n){if(1&e){const t=ge();y(0,"td",56)(1,"ngx-slider",59),tt("valueChange",function(i){B(t);const o=v(2);return be(o.settings.lineCoverageMin,i)||(o.settings.lineCoverageMin=i),j(i)})("highValueChange",function(i){B(t);const o=v(2);return be(o.settings.lineCoverageMax,i)||(o.settings.lineCoverageMax=i),j(i)}),_()()}if(2&e){const t=v(2);f(),Qe("value",t.settings.lineCoverageMin)("highValue",t.settings.lineCoverageMax),p("options",t.sliderOptions)}}function S$(e,n){if(1&e){const t=ge();y(0,"td",57)(1,"ngx-slider",59),tt("valueChange",function(i){B(t);const o=v(2);return be(o.settings.branchCoverageMin,i)||(o.settings.branchCoverageMin=i),j(i)})("highValueChange",function(i){B(t);const o=v(2);return be(o.settings.branchCoverageMax,i)||(o.settings.branchCoverageMax=i),j(i)}),_()()}if(2&e){const t=v(2);f(),Qe("value",t.settings.branchCoverageMin)("highValue",t.settings.branchCoverageMax),p("options",t.sliderOptions)}}function N$(e,n){if(1&e){const t=ge();y(0,"td",57)(1,"ngx-slider",59),tt("valueChange",function(i){B(t);const o=v(2);return be(o.settings.methodCoverageMin,i)||(o.settings.methodCoverageMin=i),j(i)})("highValueChange",function(i){B(t);const o=v(2);return be(o.settings.methodCoverageMax,i)||(o.settings.methodCoverageMax=i),j(i)}),_()()}if(2&e){const t=v(2);f(),Qe("value",t.settings.methodCoverageMin)("highValue",t.settings.methodCoverageMax),p("options",t.sliderOptions)}}function x$(e,n){if(1&e){const t=ge();y(0,"td",57)(1,"ngx-slider",59),tt("valueChange",function(i){B(t);const o=v(2);return be(o.settings.methodFullCoverageMin,i)||(o.settings.methodFullCoverageMin=i),j(i)})("highValueChange",function(i){B(t);const o=v(2);return be(o.settings.methodFullCoverageMax,i)||(o.settings.methodFullCoverageMax=i),j(i)}),_()()}if(2&e){const t=v(2);f(),Qe("value",t.settings.methodFullCoverageMin)("highValue",t.settings.methodFullCoverageMax),p("options",t.sliderOptions)}}function O$(e,n){1&e&&x(0,"td",58),2&e&&_t("colspan",v(2).settings.visibleMetrics.length)}function A$(e,n){if(1&e){const t=ge();y(0,"th",60)(1,"a",3),q("click",function(i){return B(t),j(v(2).updateSorting("covered",i))}),x(2,"i",26),b(3),_()()}if(2&e){const t=v(2);f(2),p("ngClass",Fe(2,ut,"covered"===t.settings.sortBy&&"asc"===t.settings.sortOrder,"covered"===t.settings.sortBy&&"desc"===t.settings.sortOrder,"covered"!==t.settings.sortBy)),f(),O(t.translations.covered)}}function R$(e,n){if(1&e){const t=ge();y(0,"th",60)(1,"a",3),q("click",function(i){return B(t),j(v(2).updateSorting("uncovered",i))}),x(2,"i",26),b(3),_()()}if(2&e){const t=v(2);f(2),p("ngClass",Fe(2,ut,"uncovered"===t.settings.sortBy&&"asc"===t.settings.sortOrder,"uncovered"===t.settings.sortBy&&"desc"===t.settings.sortOrder,"uncovered"!==t.settings.sortBy)),f(),O(t.translations.uncovered)}}function k$(e,n){if(1&e){const t=ge();y(0,"th",60)(1,"a",3),q("click",function(i){return B(t),j(v(2).updateSorting("coverable",i))}),x(2,"i",26),b(3),_()()}if(2&e){const t=v(2);f(2),p("ngClass",Fe(2,ut,"coverable"===t.settings.sortBy&&"asc"===t.settings.sortOrder,"coverable"===t.settings.sortBy&&"desc"===t.settings.sortOrder,"coverable"!==t.settings.sortBy)),f(),O(t.translations.coverable)}}function F$(e,n){if(1&e){const t=ge();y(0,"th",60)(1,"a",3),q("click",function(i){return B(t),j(v(2).updateSorting("total",i))}),x(2,"i",26),b(3),_()()}if(2&e){const t=v(2);f(2),p("ngClass",Fe(2,ut,"total"===t.settings.sortBy&&"asc"===t.settings.sortOrder,"total"===t.settings.sortBy&&"desc"===t.settings.sortOrder,"total"!==t.settings.sortBy)),f(),O(t.translations.total)}}function L$(e,n){if(1&e){const t=ge();y(0,"th",61)(1,"a",3),q("click",function(i){return B(t),j(v(2).updateSorting("coverage",i))}),x(2,"i",26),b(3),_()()}if(2&e){const t=v(2);f(2),p("ngClass",Fe(2,ut,"coverage"===t.settings.sortBy&&"asc"===t.settings.sortOrder,"coverage"===t.settings.sortBy&&"desc"===t.settings.sortOrder,"coverage"!==t.settings.sortBy)),f(),O(t.translations.percentage)}}function P$(e,n){if(1&e){const t=ge();y(0,"th",60)(1,"a",3),q("click",function(i){return B(t),j(v(2).updateSorting("covered_branches",i))}),x(2,"i",26),b(3),_()()}if(2&e){const t=v(2);f(2),p("ngClass",Fe(2,ut,"covered_branches"===t.settings.sortBy&&"asc"===t.settings.sortOrder,"covered_branches"===t.settings.sortBy&&"desc"===t.settings.sortOrder,"covered_branches"!==t.settings.sortBy)),f(),O(t.translations.covered)}}function V$(e,n){if(1&e){const t=ge();y(0,"th",60)(1,"a",3),q("click",function(i){return B(t),j(v(2).updateSorting("total_branches",i))}),x(2,"i",26),b(3),_()()}if(2&e){const t=v(2);f(2),p("ngClass",Fe(2,ut,"total_branches"===t.settings.sortBy&&"asc"===t.settings.sortOrder,"total_branches"===t.settings.sortBy&&"desc"===t.settings.sortOrder,"total_branches"!==t.settings.sortBy)),f(),O(t.translations.total)}}function H$(e,n){if(1&e){const t=ge();y(0,"th",61)(1,"a",3),q("click",function(i){return B(t),j(v(2).updateSorting("branchcoverage",i))}),x(2,"i",26),b(3),_()()}if(2&e){const t=v(2);f(2),p("ngClass",Fe(2,ut,"branchcoverage"===t.settings.sortBy&&"asc"===t.settings.sortOrder,"branchcoverage"===t.settings.sortBy&&"desc"===t.settings.sortOrder,"branchcoverage"!==t.settings.sortBy)),f(),O(t.translations.percentage)}}function B$(e,n){if(1&e){const t=ge();y(0,"th",60)(1,"a",3),q("click",function(i){return B(t),j(v(2).updateSorting("covered_methods",i))}),x(2,"i",26),b(3),_()()}if(2&e){const t=v(2);f(2),p("ngClass",Fe(2,ut,"covered_methods"===t.settings.sortBy&&"asc"===t.settings.sortOrder,"covered_methods"===t.settings.sortBy&&"desc"===t.settings.sortOrder,"covered_methods"!==t.settings.sortBy)),f(),O(t.translations.covered)}}function j$(e,n){if(1&e){const t=ge();y(0,"th",60)(1,"a",3),q("click",function(i){return B(t),j(v(2).updateSorting("total_methods",i))}),x(2,"i",26),b(3),_()()}if(2&e){const t=v(2);f(2),p("ngClass",Fe(2,ut,"total_methods"===t.settings.sortBy&&"asc"===t.settings.sortOrder,"total_methods"===t.settings.sortBy&&"desc"===t.settings.sortOrder,"total_methods"!==t.settings.sortBy)),f(),O(t.translations.total)}}function U$(e,n){if(1&e){const t=ge();y(0,"th",61)(1,"a",3),q("click",function(i){return B(t),j(v(2).updateSorting("methodcoverage",i))}),x(2,"i",26),b(3),_()()}if(2&e){const t=v(2);f(2),p("ngClass",Fe(2,ut,"methodcoverage"===t.settings.sortBy&&"asc"===t.settings.sortOrder,"methodcoverage"===t.settings.sortBy&&"desc"===t.settings.sortOrder,"methodcoverage"!==t.settings.sortBy)),f(),O(t.translations.percentage)}}function $$(e,n){if(1&e){const t=ge();y(0,"th",60)(1,"a",3),q("click",function(i){return B(t),j(v(2).updateSorting("fullycovered_methods",i))}),x(2,"i",26),b(3),_()()}if(2&e){const t=v(2);f(2),p("ngClass",Fe(2,ut,"fullycovered_methods"===t.settings.sortBy&&"asc"===t.settings.sortOrder,"fullycovered_methods"===t.settings.sortBy&&"desc"===t.settings.sortOrder,"fullycovered_methods"!==t.settings.sortBy)),f(),O(t.translations.covered)}}function z$(e,n){if(1&e){const t=ge();y(0,"th",60)(1,"a",3),q("click",function(i){return B(t),j(v(2).updateSorting("total_methods",i))}),x(2,"i",26),b(3),_()()}if(2&e){const t=v(2);f(2),p("ngClass",Fe(2,ut,"total_methods"===t.settings.sortBy&&"asc"===t.settings.sortOrder,"total_methods"===t.settings.sortBy&&"desc"===t.settings.sortOrder,"total_methods"!==t.settings.sortBy)),f(),O(t.translations.total)}}function G$(e,n){if(1&e){const t=ge();y(0,"th",61)(1,"a",3),q("click",function(i){return B(t),j(v(2).updateSorting("methodfullcoverage",i))}),x(2,"i",26),b(3),_()()}if(2&e){const t=v(2);f(2),p("ngClass",Fe(2,ut,"methodfullcoverage"===t.settings.sortBy&&"asc"===t.settings.sortOrder,"methodfullcoverage"===t.settings.sortBy&&"desc"===t.settings.sortOrder,"methodfullcoverage"!==t.settings.sortBy)),f(),O(t.translations.percentage)}}function q$(e,n){if(1&e){const t=ge();y(0,"th")(1,"a",3),q("click",function(i){const o=B(t).$implicit;return j(v(2).updateSorting(o.abbreviation,i))}),x(2,"i",26),b(3),_(),y(4,"a",62),x(5,"i",63),_()()}if(2&e){const t=n.$implicit,r=v(2);f(2),p("ngClass",Fe(3,ut,r.settings.sortBy===t.abbreviation&&"asc"===r.settings.sortOrder,r.settings.sortBy===t.abbreviation&&"desc"===r.settings.sortOrder,r.settings.sortBy!==t.abbreviation)),f(),O(t.name),f(),In("href",t.explanationUrl,ir)}}function W$(e,n){if(1&e&&x(0,"tr",65),2&e){const t=v().$implicit,r=v(2);p("element",t)("collapsed",t.collapsed)("lineCoverageAvailable",r.settings.showLineCoverage)("branchCoverageAvailable",r.branchCoverageAvailable&&r.settings.showBranchCoverage)("methodCoverageAvailable",r.methodCoverageAvailable&&r.settings.showMethodCoverage)("methodFullCoverageAvailable",r.methodCoverageAvailable&&r.settings.showFullMethodCoverage)("visibleMetrics",r.settings.visibleMetrics)}}function Z$(e,n){if(1&e&&x(0,"tr",67),2&e){const t=v().$implicit,r=v(3);p("clazz",t)("translations",r.translations)("lineCoverageAvailable",r.settings.showLineCoverage)("branchCoverageAvailable",r.branchCoverageAvailable&&r.settings.showBranchCoverage)("methodCoverageAvailable",r.methodCoverageAvailable&&r.settings.showMethodCoverage)("methodFullCoverageAvailable",r.methodCoverageAvailable&&r.settings.showFullMethodCoverage)("visibleMetrics",r.settings.visibleMetrics)("historyComparisionDate",r.settings.historyComparisionDate)}}function Q$(e,n){if(1&e&&(X(0),V(1,Z$,1,8,"tr",66),ee()),2&e){const t=n.$implicit,r=v().$implicit,i=v(2);f(),p("ngIf",!r.collapsed&&t.visible(i.settings))}}function Y$(e,n){if(1&e&&x(0,"tr",70),2&e){const t=v().$implicit,r=v(5);p("clazz",t)("translations",r.translations)("lineCoverageAvailable",r.settings.showLineCoverage)("branchCoverageAvailable",r.branchCoverageAvailable&&r.settings.showBranchCoverage)("methodCoverageAvailable",r.methodCoverageAvailable&&r.settings.showMethodCoverage)("methodFullCoverageAvailable",r.methodCoverageAvailable&&r.settings.showFullMethodCoverage)("visibleMetrics",r.settings.visibleMetrics)("historyComparisionDate",r.settings.historyComparisionDate)}}function K$(e,n){if(1&e&&(X(0),V(1,Y$,1,8,"tr",69),ee()),2&e){const t=n.$implicit,r=v(2).$implicit,i=v(3);f(),p("ngIf",!r.collapsed&&t.visible(i.settings))}}function J$(e,n){if(1&e&&(X(0),x(1,"tr",68),V(2,K$,2,1,"ng-container",29),ee()),2&e){const t=v().$implicit,r=v(3);f(),p("element",t)("collapsed",t.collapsed)("lineCoverageAvailable",r.settings.showLineCoverage)("branchCoverageAvailable",r.branchCoverageAvailable&&r.settings.showBranchCoverage)("methodCoverageAvailable",r.methodCoverageAvailable&&r.settings.showMethodCoverage)("methodFullCoverageAvailable",r.methodCoverageAvailable&&r.settings.showFullMethodCoverage)("visibleMetrics",r.settings.visibleMetrics),f(),p("ngForOf",t.classes)}}function X$(e,n){if(1&e&&(X(0),V(1,J$,3,8,"ng-container",0),ee()),2&e){const t=n.$implicit,r=v().$implicit,i=v(2);f(),p("ngIf",!r.collapsed&&t.visible(i.settings))}}function ez(e,n){if(1&e&&(X(0),V(1,W$,1,7,"tr",64)(2,Q$,2,1,"ng-container",29)(3,X$,2,1,"ng-container",29),ee()),2&e){const t=n.$implicit,r=v(2);f(),p("ngIf",t.visible(r.settings)),f(),p("ngForOf",t.classes),f(),p("ngForOf",t.subElements)}}function tz(e,n){if(1&e){const t=ge();y(0,"div"),V(1,$U,1,10,"popup",1),y(2,"div",2)(3,"div")(4,"a",3),q("click",function(i){return B(t),j(v().collapseAll(i))}),b(5),_(),b(6," | "),y(7,"a",3),q("click",function(i){return B(t),j(v().expandAll(i))}),b(8),_()(),y(9,"div",4)(10,"span",5),V(11,zU,2,1,"ng-container",0)(12,GU,2,1,"ng-container",0)(13,qU,2,1,"ng-container",0),_(),x(14,"br"),b(15),y(16,"input",6),tt("ngModelChange",function(i){B(t);const o=v();return be(o.settings.grouping,i)||(o.settings.grouping=i),j(i)}),q("ngModelChange",function(){return B(t),j(v().updateCoverageInfo())}),_()(),y(17,"div",4),V(18,n$,9,6,"ng-container",0),_(),y(19,"div",7)(20,"button",8),q("click",function(){return B(t),j(v().popupVisible=!0)}),x(21,"i",9),b(22),_()()(),y(23,"div",10)(24,"table",11)(25,"colgroup"),x(26,"col",12),V(27,r$,1,0,"col",13)(28,i$,1,0,"col",14)(29,o$,1,0,"col",15)(30,s$,1,0,"col",16)(31,a$,1,0,"col",17)(32,l$,1,0,"col",18)(33,c$,1,0,"col",13)(34,u$,1,0,"col",16)(35,d$,1,0,"col",17)(36,f$,1,0,"col",18)(37,h$,1,0,"col",13)(38,g$,1,0,"col",16)(39,p$,1,0,"col",17)(40,m$,1,0,"col",18)(41,v$,1,0,"col",13)(42,_$,1,0,"col",16)(43,y$,1,0,"col",17)(44,C$,1,0,"col",18)(45,w$,1,0,"col",19),_(),y(46,"thead")(47,"tr",20),x(48,"th"),V(49,D$,2,1,"th",21)(50,b$,2,1,"th",22)(51,E$,2,1,"th",22)(52,I$,2,1,"th",22)(53,M$,2,2,"th",23),_(),y(54,"tr",24)(55,"td")(56,"input",25),tt("ngModelChange",function(i){B(t);const o=v();return be(o.settings.filter,i)||(o.settings.filter=i),j(i)}),_()(),V(57,T$,2,3,"td",21)(58,S$,2,3,"td",22)(59,N$,2,3,"td",22)(60,x$,2,3,"td",22)(61,O$,1,1,"td",23),_(),y(62,"tr")(63,"th")(64,"a",3),q("click",function(i){return B(t),j(v().updateSorting("name",i))}),x(65,"i",26),b(66),_()(),V(67,A$,4,6,"th",27)(68,R$,4,6,"th",27)(69,k$,4,6,"th",27)(70,F$,4,6,"th",27)(71,L$,4,6,"th",28)(72,P$,4,6,"th",27)(73,V$,4,6,"th",27)(74,H$,4,6,"th",28)(75,B$,4,6,"th",27)(76,j$,4,6,"th",27)(77,U$,4,6,"th",28)(78,$$,4,6,"th",27)(79,z$,4,6,"th",27)(80,G$,4,6,"th",28)(81,q$,6,7,"th",29),_()(),y(82,"tbody"),V(83,ez,4,3,"ng-container",29),_()()()()}if(2&e){const t=v();f(),p("ngIf",t.popupVisible),f(4),O(t.translations.collapseAll),f(3),O(t.translations.expandAll),f(3),p("ngIf",-1===t.settings.grouping),f(),p("ngIf",0===t.settings.grouping),f(),p("ngIf",t.settings.grouping>0),f(2),U(" ",t.translations.grouping," "),f(),p("max",t.settings.groupingMaximum),Qe("ngModel",t.settings.grouping),f(2),p("ngIf",t.historicCoverageExecutionTimes.length>0),f(4),O(t.metrics.length>0?t.translations.selectCoverageTypesAndMetrics:t.translations.selectCoverageTypes),f(5),p("ngIf",t.settings.showLineCoverage),f(),p("ngIf",t.settings.showLineCoverage),f(),p("ngIf",t.settings.showLineCoverage),f(),p("ngIf",t.settings.showLineCoverage),f(),p("ngIf",t.settings.showLineCoverage),f(),p("ngIf",t.settings.showLineCoverage),f(),p("ngIf",t.branchCoverageAvailable&&t.settings.showBranchCoverage),f(),p("ngIf",t.branchCoverageAvailable&&t.settings.showBranchCoverage),f(),p("ngIf",t.branchCoverageAvailable&&t.settings.showBranchCoverage),f(),p("ngIf",t.branchCoverageAvailable&&t.settings.showBranchCoverage),f(),p("ngIf",t.methodCoverageAvailable&&t.settings.showMethodCoverage),f(),p("ngIf",t.methodCoverageAvailable&&t.settings.showMethodCoverage),f(),p("ngIf",t.methodCoverageAvailable&&t.settings.showMethodCoverage),f(),p("ngIf",t.methodCoverageAvailable&&t.settings.showMethodCoverage),f(),p("ngIf",t.methodCoverageAvailable&&t.settings.showFullMethodCoverage),f(),p("ngIf",t.methodCoverageAvailable&&t.settings.showFullMethodCoverage),f(),p("ngIf",t.methodCoverageAvailable&&t.settings.showFullMethodCoverage),f(),p("ngIf",t.methodCoverageAvailable&&t.settings.showFullMethodCoverage),f(),p("ngForOf",t.settings.visibleMetrics),f(4),p("ngIf",t.settings.showLineCoverage),f(),p("ngIf",t.branchCoverageAvailable&&t.settings.showBranchCoverage),f(),p("ngIf",t.methodCoverageAvailable&&t.settings.showMethodCoverage),f(),p("ngIf",t.methodCoverageAvailable&&t.settings.showFullMethodCoverage),f(),p("ngIf",t.settings.visibleMetrics.length>0),f(3),In("placeholder",t.translations.filter),Qe("ngModel",t.settings.filter),f(),p("ngIf",t.settings.showLineCoverage),f(),p("ngIf",t.branchCoverageAvailable&&t.settings.showBranchCoverage),f(),p("ngIf",t.methodCoverageAvailable&&t.settings.showMethodCoverage),f(),p("ngIf",t.methodCoverageAvailable&&t.settings.showFullMethodCoverage),f(),p("ngIf",t.settings.visibleMetrics.length>0),f(4),p("ngClass",Fe(60,ut,"name"===t.settings.sortBy&&"asc"===t.settings.sortOrder,"name"===t.settings.sortBy&&"desc"===t.settings.sortOrder,"name"!==t.settings.sortBy)),f(),O(t.translations.name),f(),p("ngIf",t.settings.showLineCoverage),f(),p("ngIf",t.settings.showLineCoverage),f(),p("ngIf",t.settings.showLineCoverage),f(),p("ngIf",t.settings.showLineCoverage),f(),p("ngIf",t.settings.showLineCoverage),f(),p("ngIf",t.branchCoverageAvailable&&t.settings.showBranchCoverage),f(),p("ngIf",t.branchCoverageAvailable&&t.settings.showBranchCoverage),f(),p("ngIf",t.branchCoverageAvailable&&t.settings.showBranchCoverage),f(),p("ngIf",t.methodCoverageAvailable&&t.settings.showMethodCoverage),f(),p("ngIf",t.methodCoverageAvailable&&t.settings.showMethodCoverage),f(),p("ngIf",t.methodCoverageAvailable&&t.settings.showMethodCoverage),f(),p("ngIf",t.methodCoverageAvailable&&t.settings.showFullMethodCoverage),f(),p("ngIf",t.methodCoverageAvailable&&t.settings.showFullMethodCoverage),f(),p("ngIf",t.methodCoverageAvailable&&t.settings.showFullMethodCoverage),f(),p("ngForOf",t.settings.visibleMetrics),f(2),p("ngForOf",t.codeElements)}}let nz=(()=>{class e{constructor(t){this.queryString="",this.historicCoverageExecutionTimes=[],this.branchCoverageAvailable=!1,this.methodCoverageAvailable=!1,this.metrics=[],this.codeElements=[],this.translations={},this.popupVisible=!1,this.settings=new r3,this.sliderOptions={floor:0,ceil:100,step:1,ticksArray:[0,10,20,30,40,50,60,70,80,90,100],showTicks:!0},this.window=t.nativeWindow}ngOnInit(){this.historicCoverageExecutionTimes=this.window.historicCoverageExecutionTimes,this.branchCoverageAvailable=this.window.branchCoverageAvailable,this.methodCoverageAvailable=this.window.methodCoverageAvailable,this.metrics=this.window.metrics,this.translations=this.window.translations,jt.maximumDecimalPlacesForCoverageQuotas=this.window.maximumDecimalPlacesForCoverageQuotas;let t=!1;if(void 0!==this.window.history&&void 0!==this.window.history.replaceState&&null!==this.window.history.state&&null!=this.window.history.state.coverageInfoSettings)console.log("Coverage info: Restoring from history",this.window.history.state.coverageInfoSettings),t=!0,this.settings=JSON.parse(JSON.stringify(this.window.history.state.coverageInfoSettings));else{let i=0,o=this.window.assemblies;for(let s=0;s-1&&(this.queryString=window.location.href.substring(r)),this.updateCoverageInfo(),t&&this.restoreCollapseState()}onBeforeUnload(){if(this.saveCollapseState(),void 0!==this.window.history&&void 0!==this.window.history.replaceState){console.log("Coverage info: Updating history",this.settings);let t=new dM;null!==window.history.state&&(t=JSON.parse(JSON.stringify(this.window.history.state))),t.coverageInfoSettings=JSON.parse(JSON.stringify(this.settings)),window.history.replaceState(t,"")}}updateCoverageInfo(){let t=(new Date).getTime(),r=this.window.assemblies,i=[],o=0;if(0===this.settings.grouping)for(let l=0;l{for(let i=0;i{for(let o=0;ot&&(i[o].collapsed=this.settings.collapseStates[t]),t++,r(i[o].subElements)};r(this.codeElements)}static{this.\u0275fac=function(r){return new(r||e)(T(Xg))}}static{this.\u0275cmp=sn({type:e,selectors:[["coverage-info"]],hostBindings:function(r,i){1&r&&q("beforeunload",function(){return i.onBeforeUnload()},0,El)},standalone:!1,decls:1,vars:1,consts:[[4,"ngIf"],[3,"visible","translations","branchCoverageAvailable","methodCoverageAvailable","metrics","showLineCoverage","showBranchCoverage","showMethodCoverage","showMethodFullCoverage","visibleMetrics","visibleChange","showLineCoverageChange","showBranchCoverageChange","showMethodCoverageChange","showMethodFullCoverageChange","visibleMetricsChange",4,"ngIf"],[1,"customizebox"],["href","#",3,"click"],[1,"col-center"],[1,"slider-label"],["type","range","step","1","min","-1",3,"ngModelChange","max","ngModel"],[1,"col-right","right"],["type","button",3,"click"],[1,"icon-cog"],[1,"table-responsive"],[1,"overview","table-fixed","stripped"],[1,"column-min-200"],["class","column90",4,"ngIf"],["class","column105",4,"ngIf"],["class","column100",4,"ngIf"],["class","column70",4,"ngIf"],["class","column98",4,"ngIf"],["class","column112",4,"ngIf"],["class","column112",4,"ngFor","ngForOf"],[1,"header"],["class","center","colspan","6",4,"ngIf"],["class","center","colspan","4",4,"ngIf"],["class","center",4,"ngIf"],[1,"filterbar"],["type","text",3,"ngModelChange","ngModel","placeholder"],[3,"ngClass"],["class","right",4,"ngIf"],["class","center","colspan","2",4,"ngIf"],[4,"ngFor","ngForOf"],[3,"visibleChange","showLineCoverageChange","showBranchCoverageChange","showMethodCoverageChange","showMethodFullCoverageChange","visibleMetricsChange","visible","translations","branchCoverageAvailable","methodCoverageAvailable","metrics","showLineCoverage","showBranchCoverage","showMethodCoverage","showMethodFullCoverage","visibleMetrics"],[3,"ngModelChange","ngModel"],["value",""],[3,"value",4,"ngFor","ngForOf"],[3,"value"],["value","allChanges"],["value","lineCoverageIncreaseOnly"],["value","lineCoverageDecreaseOnly"],["value","branchCoverageIncreaseOnly",4,"ngIf"],["value","branchCoverageDecreaseOnly",4,"ngIf"],["value","methodCoverageIncreaseOnly",4,"ngIf"],["value","methodCoverageDecreaseOnly",4,"ngIf"],["value","fullMethodCoverageIncreaseOnly",4,"ngIf"],["value","fullMethodCoverageDecreaseOnly",4,"ngIf"],["value","branchCoverageIncreaseOnly"],["value","branchCoverageDecreaseOnly"],["value","methodCoverageIncreaseOnly"],["value","methodCoverageDecreaseOnly"],["value","fullMethodCoverageIncreaseOnly"],["value","fullMethodCoverageDecreaseOnly"],[1,"column90"],[1,"column105"],[1,"column100"],[1,"column70"],[1,"column98"],[1,"column112"],["colspan","6",1,"center"],["colspan","4",1,"center"],[1,"center"],[3,"valueChange","highValueChange","value","highValue","options"],[1,"right"],["colspan","2",1,"center"],["target","_blank",3,"href"],[1,"icon-info-circled"],["codeelement-row","",3,"element","collapsed","lineCoverageAvailable","branchCoverageAvailable","methodCoverageAvailable","methodFullCoverageAvailable","visibleMetrics",4,"ngIf"],["codeelement-row","",3,"element","collapsed","lineCoverageAvailable","branchCoverageAvailable","methodCoverageAvailable","methodFullCoverageAvailable","visibleMetrics"],["class-row","",3,"clazz","translations","lineCoverageAvailable","branchCoverageAvailable","methodCoverageAvailable","methodFullCoverageAvailable","visibleMetrics","historyComparisionDate",4,"ngIf"],["class-row","",3,"clazz","translations","lineCoverageAvailable","branchCoverageAvailable","methodCoverageAvailable","methodFullCoverageAvailable","visibleMetrics","historyComparisionDate"],["codeelement-row","",1,"namespace",3,"element","collapsed","lineCoverageAvailable","branchCoverageAvailable","methodCoverageAvailable","methodFullCoverageAvailable","visibleMetrics"],["class","namespace","class-row","",3,"clazz","translations","lineCoverageAvailable","branchCoverageAvailable","methodCoverageAvailable","methodFullCoverageAvailable","visibleMetrics","historyComparisionDate",4,"ngIf"],["class-row","",1,"namespace",3,"clazz","translations","lineCoverageAvailable","branchCoverageAvailable","methodCoverageAvailable","methodFullCoverageAvailable","visibleMetrics","historyComparisionDate"]],template:function(r,i){1&r&&V(0,tz,84,64,"div",0),2&r&&p("ngIf",i.codeElements.length>0)},dependencies:[Do,ci,zn,qg,Zg,na,Ug,la,jc,aa,uM,g3,H3,UU],encapsulation:2})}}return e})();class rz{constructor(){this.assembly="",this.numberOfRiskHotspots=10,this.filter="",this.sortBy="",this.sortOrder="asc"}}const tu=(e,n,t)=>({"icon-up-dir_active":e,"icon-down-dir_active":n,"icon-up-down-dir":t}),iz=(e,n)=>({lightred:e,lightgreen:n});function oz(e,n){if(1&e&&(y(0,"option",16),b(1),_()),2&e){const t=n.$implicit;p("value",t),f(),O(t)}}function sz(e,n){if(1&e&&(y(0,"span"),b(1),_()),2&e){const t=v(2);f(),O(t.translations.top)}}function az(e,n){1&e&&(y(0,"option",23),b(1,"20"),_())}function lz(e,n){1&e&&(y(0,"option",24),b(1,"50"),_())}function cz(e,n){1&e&&(y(0,"option",25),b(1,"100"),_())}function uz(e,n){if(1&e&&(y(0,"option",16),b(1),_()),2&e){const t=v(3);p("value",t.totalNumberOfRiskHotspots),f(),O(t.translations.all)}}function dz(e,n){if(1&e){const t=ge();y(0,"select",17),tt("ngModelChange",function(i){B(t);const o=v(2);return be(o.settings.numberOfRiskHotspots,i)||(o.settings.numberOfRiskHotspots=i),j(i)}),y(1,"option",18),b(2,"10"),_(),V(3,az,2,0,"option",19)(4,lz,2,0,"option",20)(5,cz,2,0,"option",21)(6,uz,2,2,"option",22),_()}if(2&e){const t=v(2);Qe("ngModel",t.settings.numberOfRiskHotspots),f(3),p("ngIf",t.totalNumberOfRiskHotspots>10),f(),p("ngIf",t.totalNumberOfRiskHotspots>20),f(),p("ngIf",t.totalNumberOfRiskHotspots>50),f(),p("ngIf",t.totalNumberOfRiskHotspots>100)}}function fz(e,n){1&e&&x(0,"col",26)}function hz(e,n){if(1&e){const t=ge();y(0,"th")(1,"a",13),q("click",function(i){const o=B(t).index;return j(v(2).updateSorting(""+o,i))}),x(2,"i",14),b(3),_(),y(4,"a",27),x(5,"i",28),_()()}if(2&e){const t=n.$implicit,r=n.index,i=v(2);f(2),p("ngClass",Fe(3,tu,i.settings.sortBy===""+r&&"asc"===i.settings.sortOrder,i.settings.sortBy===""+r&&"desc"===i.settings.sortOrder,i.settings.sortBy!==""+r)),f(),O(t.name),f(),In("href",t.explanationUrl,ir)}}function gz(e,n){if(1&e&&(y(0,"td",32),b(1),_()),2&e){const t=n.$implicit;p("ngClass",xh(2,iz,t.exceeded,!t.exceeded)),f(),O(t.value)}}function pz(e,n){if(1&e&&(y(0,"tr")(1,"td"),b(2),_(),y(3,"td")(4,"a",29),b(5),_()(),y(6,"td",30)(7,"a",29),b(8),_()(),V(9,gz,2,5,"td",31),_()),2&e){const t=n.$implicit,r=v(2);f(2),O(t.assembly),f(2),p("href",t.reportPath+r.queryString,ir),f(),O(t.class),f(),p("title",t.methodName),f(),p("href",t.reportPath+r.queryString+"#file"+t.fileIndex+"_line"+t.line,ir),f(),U(" ",t.methodShortName," "),f(),p("ngForOf",t.metrics)}}function mz(e,n){if(1&e){const t=ge();y(0,"div")(1,"div",1)(2,"div")(3,"select",2),tt("ngModelChange",function(i){B(t);const o=v();return be(o.settings.assembly,i)||(o.settings.assembly=i),j(i)}),q("ngModelChange",function(){return B(t),j(v().updateRiskHotpots())}),y(4,"option",3),b(5),_(),V(6,oz,2,2,"option",4),_()(),y(7,"div",5),V(8,sz,2,1,"span",0)(9,dz,7,5,"select",6),_(),x(10,"div",5),y(11,"div",7)(12,"span"),b(13),_(),y(14,"input",8),tt("ngModelChange",function(i){B(t);const o=v();return be(o.settings.filter,i)||(o.settings.filter=i),j(i)}),q("ngModelChange",function(){return B(t),j(v().updateRiskHotpots())}),_()()(),y(15,"div",9)(16,"table",10)(17,"colgroup"),x(18,"col",11)(19,"col",11)(20,"col",11),V(21,fz,1,0,"col",12),_(),y(22,"thead")(23,"tr")(24,"th")(25,"a",13),q("click",function(i){return B(t),j(v().updateSorting("assembly",i))}),x(26,"i",14),b(27),_()(),y(28,"th")(29,"a",13),q("click",function(i){return B(t),j(v().updateSorting("class",i))}),x(30,"i",14),b(31),_()(),y(32,"th")(33,"a",13),q("click",function(i){return B(t),j(v().updateSorting("method",i))}),x(34,"i",14),b(35),_()(),V(36,hz,6,7,"th",15),_()(),y(37,"tbody"),V(38,pz,10,7,"tr",15),function DD(e,n){const t=Z();let r;const i=e+k;t.firstCreatePass?(r=function HF(e,n){if(n)for(let t=n.length-1;t>=0;t--){const r=n[t];if(e===r.name)return r}}(n,t.pipeRegistry),t.data[i]=r,r.onDestroy&&(t.destroyHooks??=[]).push(i,r.onDestroy)):r=t.data[i];const o=r.factory||(r.factory=Or(r.type)),a=Et(T);try{const l=Za(!1),c=o();return Za(l),function Ih(e,n,t,r){t>=e.data.length&&(e.data[t]=null,e.blueprint[t]=null),n[t]=r}(t,D(),i,c),c}finally{Et(a)}}(39,"slice"),_()()()()}if(2&e){const t=v();f(3),Qe("ngModel",t.settings.assembly),f(2),O(t.translations.assembly),f(),p("ngForOf",t.assemblies),f(2),p("ngIf",t.totalNumberOfRiskHotspots>10),f(),p("ngIf",t.totalNumberOfRiskHotspots>10),f(4),U("",t.translations.filter," "),f(),Qe("ngModel",t.settings.filter),f(7),p("ngForOf",t.riskHotspotMetrics),f(5),p("ngClass",Fe(20,tu,"assembly"===t.settings.sortBy&&"asc"===t.settings.sortOrder,"assembly"===t.settings.sortBy&&"desc"===t.settings.sortOrder,"assembly"!==t.settings.sortBy)),f(),O(t.translations.assembly),f(3),p("ngClass",Fe(24,tu,"class"===t.settings.sortBy&&"asc"===t.settings.sortOrder,"class"===t.settings.sortBy&&"desc"===t.settings.sortOrder,"class"!==t.settings.sortBy)),f(),O(t.translations.class),f(3),p("ngClass",Fe(28,tu,"method"===t.settings.sortBy&&"asc"===t.settings.sortOrder,"method"===t.settings.sortBy&&"desc"===t.settings.sortOrder,"method"!==t.settings.sortBy)),f(),O(t.translations.method),f(),p("ngForOf",t.riskHotspotMetrics),f(2),p("ngForOf",function bD(e,n,t,r,i){const o=e+k,s=D(),a=function Br(e,n){return e[n]}(s,o);return function Bs(e,n){return e[1].data[n].pure}(s,o)?yD(s,gt(),n,a.transform,t,r,i,a):a.transform(t,r,i)}(39,16,t.riskHotspots,0,t.settings.numberOfRiskHotspots))}}let vz=(()=>{class e{constructor(t){this.queryString="",this.riskHotspotMetrics=[],this.riskHotspots=[],this.totalNumberOfRiskHotspots=0,this.assemblies=[],this.translations={},this.settings=new rz,this.window=t.nativeWindow}ngOnInit(){this.riskHotspotMetrics=this.window.riskHotspotMetrics,this.translations=this.window.translations,void 0!==this.window.history&&void 0!==this.window.history.replaceState&&null!==this.window.history.state&&null!=this.window.history.state.riskHotspotsSettings&&(console.log("Risk hotspots: Restoring from history",this.window.history.state.riskHotspotsSettings),this.settings=JSON.parse(JSON.stringify(this.window.history.state.riskHotspotsSettings)));const t=window.location.href.indexOf("?");t>-1&&(this.queryString=window.location.href.substring(t)),this.updateRiskHotpots()}onDonBeforeUnlodad(){if(void 0!==this.window.history&&void 0!==this.window.history.replaceState){console.log("Risk hotspots: Updating history",this.settings);let t=new dM;null!==window.history.state&&(t=JSON.parse(JSON.stringify(this.window.history.state))),t.riskHotspotsSettings=JSON.parse(JSON.stringify(this.settings)),window.history.replaceState(t,"")}}updateRiskHotpots(){const t=this.window.riskHotspots;if(this.totalNumberOfRiskHotspots=t.length,0===this.assemblies.length){let s=[];for(let a=0;a0)},dependencies:[Do,ci,zn,qg,Zg,na,la,jc,aa,Xb],encapsulation:2})}}return e})(),_z=(()=>{class e{static{this.\u0275fac=function(r){return new(r||e)}}static{this.\u0275mod=cr({type:e,bootstrap:[vz,nz]})}static{this.\u0275inj=Nn({providers:[Xg],imports:[hH,hj,n3]})}}return e})();fH().bootstrapModule(_z).catch(e=>console.error(e))}},No=>{No(No.s=332)}]); \ No newline at end of file diff --git a/source/coverage/report.css b/source/coverage/report.css deleted file mode 100644 index 42a58f6..0000000 --- a/source/coverage/report.css +++ /dev/null @@ -1,834 +0,0 @@ -:root { - --green: #0aad0a; - --lightgreen: #dcf4dc; -} - -html { font-family: sans-serif; margin: 0; padding: 0; font-size: 0.9em; background-color: #d6d6d6; height: 100%; } -body { margin: 0; padding: 0; height: 100%; color: #000; } -h1 { font-family: 'Century Gothic', sans-serif; font-size: 1.2em; font-weight: normal; color: #fff; background-color: #6f6f6f; padding: 10px; margin: 20px -20px 20px -20px; } -h1:first-of-type { margin-top: 0; } -h2 { font-size: 1.0em; font-weight: bold; margin: 10px 0 15px 0; padding: 0; } -h3 { font-size: 1.0em; font-weight: bold; margin: 0 0 10px 0; padding: 0; display: inline-block; } -input, select, button { border: 1px solid #767676; border-radius: 0; } -button { background-color: #ddd; cursor: pointer; } -a { color: #c00; text-decoration: none; } -a:hover { color: #000; text-decoration: none; } -h1 a.back { color: #fff; background-color: #949494; display: inline-block; margin: -12px 5px -10px -10px; padding: 10px; border-right: 1px solid #fff; } -h1 a.back:hover { background-color: #ccc; } -h1 a.button { color: #000; background-color: #bebebe; margin: -5px 0 0 10px; padding: 5px 8px 5px 8px; border: 1px solid #fff; font-size: 0.9em; border-radius: 3px; float:right; } -h1 a.button:hover { background-color: #ccc; } -h1 a.button i { position: relative; top: 1px; } - -.container { margin: auto; max-width: 1650px; width: 90%; background-color: #fff; display: flex; box-shadow: 0 0 60px #7d7d7d; min-height: 100%; } -.containerleft { padding: 0 20px 20px 20px; flex: 1; min-width: 1%; } -.containerright { width: 340px; min-width: 340px; background-color: #e5e5e5; height: 100%; } -.containerrightfixed { position: fixed; padding: 0 20px 20px 20px; border-left: 1px solid #6f6f6f; width: 300px; overflow-y: auto; height: 100%; top: 0; bottom: 0; } -.containerrightfixed h1 { background-color: #c00; } -.containerrightfixed label, .containerright a { white-space: nowrap; overflow: hidden; display: inline-block; width: 100%; max-width: 300px; text-overflow: ellipsis; } -.containerright a { margin-bottom: 3px; } - -@media screen and (max-width:1200px){ - .container { box-shadow: none; width: 100%; } - .containerright { display: none; } -} - -.popup-container { position: fixed; left: 0; right: 0; top: 0; bottom: 0; background-color: rgb(0, 0, 0, 0.6); z-index: 100; } -.popup { position: absolute; top: 50%; right: 50%; transform: translate(50%,-50%); background-color: #fff; padding: 25px; border-radius: 15px; min-width: 300px; } -.popup .close { text-align: right; color: #979797; font-size: 25px;position: relative; left: 10px; bottom: 10px; cursor: pointer; } - -.footer { font-size: 0.7em; text-align: center; margin-top: 35px; } - -.card-group { display: flex; flex-wrap: wrap; margin-top: -15px; margin-left: -15px; } -.card-group + .card-group { margin-top: 0; } -.card-group .card { margin-top: 15px; margin-left: 15px; display: flex; flex-direction: column; background-color: #e4e4e4; background: radial-gradient(circle, #fefefe 0%, #f6f6f6 100%); border: 1px solid #c1c1c1; padding: 15px; color: #6f6f6f; max-width: 100% } -.card-group .card .card-header { font-size: 1.5rem; font-family: 'Century Gothic', sans-serif; margin-bottom: 15px; flex-grow: 1; } -.card-group .card .card-body { display: flex; flex-direction: row; gap: 15px; flex-grow: 1; } -.card-group .card .card-body div.table { display: flex; flex-direction: column; } -.card-group .card .large { font-size: 5rem; line-height: 5rem; font-weight: bold; align-self: flex-end; border-left-width: 4px; padding-left: 10px; } -.card-group .card table { align-self: flex-end; border-collapse: collapse; } -.card-group .card table tr { border-bottom: 1px solid #c1c1c1; } -.card-group .card table tr:hover { background-color: #c1c1c1; } -.card-group .card table tr:last-child { border-bottom: none; } -.card-group .card table th, .card-group .card table td { padding: 2px; } -.card-group td.limit-width { max-width: 200px; text-overflow: ellipsis; overflow: hidden; } -.card-group td.overflow-wrap { overflow-wrap: anywhere; } - -.pro-button { color: #fff; background-color: #20A0D2; background-image: linear-gradient(50deg, #1c7ed6 0%, #23b8cf 100%); padding: 10px; border-radius: 3px; font-weight: bold; display: inline-block; } -.pro-button:hover { color: #fff; background-color: #1C8EB7; background-image: linear-gradient(50deg, #1A6FBA 0%, #1EA1B5 100%); } -.pro-button-tiny { border-radius: 10px; padding: 3px 8px; } - -th { text-align: left; } -.table-fixed { table-layout: fixed; } -.table-responsive { overflow-x: auto; } -.table-responsive::-webkit-scrollbar { height: 20px; } -.table-responsive::-webkit-scrollbar-thumb { background-color: #6f6f6f; border-radius: 20px; border: 5px solid #fff; } -.overview { border: 1px solid #c1c1c1; border-collapse: collapse; width: 100%; word-wrap: break-word; } -.overview th { border: 1px solid #c1c1c1; border-collapse: collapse; padding: 2px 4px 2px 4px; background-color: #ddd; } -.overview tr.namespace th { background-color: #dcdcdc; } -.overview thead th { background-color: #d1d1d1; } -.overview th a { color: #000; } -.overview tr.namespace a { margin-left: 15px; display: block; } -.overview td { border: 1px solid #c1c1c1; border-collapse: collapse; padding: 2px 5px 2px 5px; } -.overview tr.filterbar td { height: 60px; } -.overview tr.header th { background-color: #d1d1d1; } -.overview tr.header th:nth-child(2n+1) { background-color: #ddd; } -.overview tr.header th:first-child { border-left: 1px solid #fff; border-top: 1px solid #fff; background-color: #fff; } -.overview tbody tr:hover>td { background-color: #b0b0b0; } - -div.currenthistory { margin: -2px -5px 0 -5px; padding: 2px 5px 2px 5px; height: 16px; } -.coverage { border-collapse: collapse; font-size: 5px; height: 10px; } -.coverage td { padding: 0; border: none; } -.stripped tr:nth-child(2n+1) { background-color: #F3F3F3; } - -.customizebox { font-size: 0.75em; margin-bottom: 7px; display: grid; grid-template-columns: 1fr; grid-template-rows: auto auto auto auto; grid-column-gap: 10px; grid-row-gap: 10px; } -.customizebox>div { align-self: end; } -.customizebox div.col-right input { width: 150px; } - -@media screen and (min-width: 1000px) { - .customizebox { grid-template-columns: repeat(4, 1fr); grid-template-rows: 1fr; } - .customizebox div.col-center { justify-self: center; } - .customizebox div.col-right { justify-self: end; } -} -.slider-label { position: relative; left: 85px; } - -.percentagebar { - padding-left: 3px; -} -a.percentagebar { - padding-left: 6px; -} -.percentagebarundefined { - border-left: 2px solid #fff; -} -.percentagebar0 { - border-left: 2px solid #c10909; -} -.percentagebar10 { - border-left: 2px solid; - border-image: linear-gradient(to bottom, #c10909 90%, var(--green) 90%, var(--green) 100%) 1; -} -.percentagebar20 { - border-left: 2px solid; - border-image: linear-gradient(to bottom, #c10909 80%, var(--green) 80%, var(--green) 100%) 1; -} -.percentagebar30 { - border-left: 2px solid; - border-image: linear-gradient(to bottom, #c10909 70%, var(--green) 70%, var(--green) 100%) 1; -} -.percentagebar40 { - border-left: 2px solid; - border-image: linear-gradient(to bottom, #c10909 60%, var(--green) 60%, var(--green) 100%) 1; -} -.percentagebar50 { - border-left: 2px solid; - border-image: linear-gradient(to bottom, #c10909 50%, var(--green) 50%, var(--green) 100%) 1; -} -.percentagebar60 { - border-left: 2px solid; - border-image: linear-gradient(to bottom, #c10909 40%, var(--green) 40%, var(--green) 100%) 1; -} -.percentagebar70 { - border-left: 2px solid; - border-image: linear-gradient(to bottom, #c10909 30%, var(--green) 30%, var(--green) 100%) 1; -} -.percentagebar80 { - border-left: 2px solid; - border-image: linear-gradient(to bottom, #c10909 20%, var(--green) 20%, var(--green) 100%) 1; -} -.percentagebar90 { - border-left: 2px solid; - border-image: linear-gradient(to bottom, #c10909 10%, var(--green) 10%, var(--green) 100%) 1; -} -.percentagebar100 { - border-left: 2px solid var(--green); -} - -.mt-1 { margin-top: 4px; } -.hidden, .ng-hide { display: none; } -.right { text-align: right; } -.center { text-align: center; } -.rightmargin { padding-right: 8px; } -.leftmargin { padding-left: 5px; } -.green { background-color: var(--green); } -.lightgreen { background-color: var(--lightgreen); } -.red { background-color: #c10909; } -.lightred { background-color: #f7dede; } -.orange { background-color: #FFA500; } -.lightorange { background-color: #FFEFD5; } -.gray { background-color: #dcdcdc; } -.lightgray { color: #888888; } -.lightgraybg { background-color: #dadada; } - -code { font-family: Consolas, monospace; font-size: 0.9em; } - -.toggleZoom { text-align:right; } - -.historychart svg { max-width: 100%; } -.ct-chart { position: relative; } -.ct-chart .ct-line { stroke-width: 2px !important; } -.ct-chart .ct-point { stroke-width: 6px !important; transition: stroke-width .2s; } -.ct-chart .ct-point:hover { stroke-width: 10px !important; } -.ct-chart .ct-series.ct-series-a .ct-line, .ct-chart .ct-series.ct-series-a .ct-point { stroke: #c00 !important;} -.ct-chart .ct-series.ct-series-b .ct-line, .ct-chart .ct-series.ct-series-b .ct-point { stroke: #1c2298 !important;} -.ct-chart .ct-series.ct-series-c .ct-line, .ct-chart .ct-series.ct-series-c .ct-point { stroke: #0aad0a !important;} -.ct-chart .ct-series.ct-series-d .ct-line, .ct-chart .ct-series.ct-series-d .ct-point { stroke: #FF6A00 !important;} - -.tinylinecoveragechart, .tinybranchcoveragechart, .tinymethodcoveragechart, .tinyfullmethodcoveragechart { background-color: #fff; margin-left: -3px; float: left; border: 1px solid #c1c1c1; width: 30px; height: 18px; } -.historiccoverageoffset { margin-top: 7px; } - -.tinylinecoveragechart .ct-line, .tinybranchcoveragechart .ct-line, .tinymethodcoveragechart .ct-line, .tinyfullmethodcoveragechart .ct-line { stroke-width: 1px !important; } -.tinybranchcoveragechart .ct-series.ct-series-a .ct-line { stroke: #1c2298 !important; } -.tinymethodcoveragechart .ct-series.ct-series-a .ct-line { stroke: #0aad0a !important; } -.tinyfullmethodcoveragechart .ct-series.ct-series-a .ct-line { stroke: #FF6A00 !important; } - -.linecoverage { background-color: #c00; width: 10px; height: 8px; border: 1px solid #000; display: inline-block; } -.branchcoverage { background-color: #1c2298; width: 10px; height: 8px; border: 1px solid #000; display: inline-block; } -.codeelementcoverage { background-color: #0aad0a; width: 10px; height: 8px; border: 1px solid #000; display: inline-block; } -.fullcodeelementcoverage { background-color: #FF6A00; width: 10px; height: 8px; border: 1px solid #000; display: inline-block; } - -.tooltip { position: absolute; display: none; padding: 5px; background: #F4C63D; color: #453D3F; pointer-events: none; z-index: 1; min-width: 250px; } - -.column-min-200 { min-width: 200px; } -.column60 { width: 60px; } -.column70 { width: 70px; } -.column90 { width: 90px; } -.column98 { width: 98px; } -.column100 { width: 100px; } -.column105 { width: 105px; } -.column112 { width: 112px; } - -.cardpercentagebar { border-left-style: solid; } -.cardpercentagebar0 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 0%, var(--green) 0%) 1; } -.cardpercentagebar1 { border-image: linear-gradient(to bottom, #c10909 1%, #c10909 1%, var(--green) 1%) 1; } -.cardpercentagebar2 { border-image: linear-gradient(to bottom, #c10909 2%, #c10909 2%, var(--green) 2%) 1; } -.cardpercentagebar3 { border-image: linear-gradient(to bottom, #c10909 3%, #c10909 3%, var(--green) 3%) 1; } -.cardpercentagebar4 { border-image: linear-gradient(to bottom, #c10909 4%, #c10909 4%, var(--green) 4%) 1; } -.cardpercentagebar5 { border-image: linear-gradient(to bottom, #c10909 5%, #c10909 5%, var(--green) 5%) 1; } -.cardpercentagebar6 { border-image: linear-gradient(to bottom, #c10909 6%, #c10909 6%, var(--green) 6%) 1; } -.cardpercentagebar7 { border-image: linear-gradient(to bottom, #c10909 7%, #c10909 7%, var(--green) 7%) 1; } -.cardpercentagebar8 { border-image: linear-gradient(to bottom, #c10909 8%, #c10909 8%, var(--green) 8%) 1; } -.cardpercentagebar9 { border-image: linear-gradient(to bottom, #c10909 9%, #c10909 9%, var(--green) 9%) 1; } -.cardpercentagebar10 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 10%, var(--green) 10%) 1; } -.cardpercentagebar11 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 11%, var(--green) 11%) 1; } -.cardpercentagebar12 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 12%, var(--green) 12%) 1; } -.cardpercentagebar13 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 13%, var(--green) 13%) 1; } -.cardpercentagebar14 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 14%, var(--green) 14%) 1; } -.cardpercentagebar15 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 15%, var(--green) 15%) 1; } -.cardpercentagebar16 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 16%, var(--green) 16%) 1; } -.cardpercentagebar17 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 17%, var(--green) 17%) 1; } -.cardpercentagebar18 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 18%, var(--green) 18%) 1; } -.cardpercentagebar19 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 19%, var(--green) 19%) 1; } -.cardpercentagebar20 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 20%, var(--green) 20%) 1; } -.cardpercentagebar21 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 21%, var(--green) 21%) 1; } -.cardpercentagebar22 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 22%, var(--green) 22%) 1; } -.cardpercentagebar23 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 23%, var(--green) 23%) 1; } -.cardpercentagebar24 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 24%, var(--green) 24%) 1; } -.cardpercentagebar25 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 25%, var(--green) 25%) 1; } -.cardpercentagebar26 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 26%, var(--green) 26%) 1; } -.cardpercentagebar27 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 27%, var(--green) 27%) 1; } -.cardpercentagebar28 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 28%, var(--green) 28%) 1; } -.cardpercentagebar29 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 29%, var(--green) 29%) 1; } -.cardpercentagebar30 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 30%, var(--green) 30%) 1; } -.cardpercentagebar31 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 31%, var(--green) 31%) 1; } -.cardpercentagebar32 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 32%, var(--green) 32%) 1; } -.cardpercentagebar33 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 33%, var(--green) 33%) 1; } -.cardpercentagebar34 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 34%, var(--green) 34%) 1; } -.cardpercentagebar35 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 35%, var(--green) 35%) 1; } -.cardpercentagebar36 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 36%, var(--green) 36%) 1; } -.cardpercentagebar37 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 37%, var(--green) 37%) 1; } -.cardpercentagebar38 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 38%, var(--green) 38%) 1; } -.cardpercentagebar39 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 39%, var(--green) 39%) 1; } -.cardpercentagebar40 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 40%, var(--green) 40%) 1; } -.cardpercentagebar41 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 41%, var(--green) 41%) 1; } -.cardpercentagebar42 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 42%, var(--green) 42%) 1; } -.cardpercentagebar43 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 43%, var(--green) 43%) 1; } -.cardpercentagebar44 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 44%, var(--green) 44%) 1; } -.cardpercentagebar45 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 45%, var(--green) 45%) 1; } -.cardpercentagebar46 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 46%, var(--green) 46%) 1; } -.cardpercentagebar47 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 47%, var(--green) 47%) 1; } -.cardpercentagebar48 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 48%, var(--green) 48%) 1; } -.cardpercentagebar49 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 49%, var(--green) 49%) 1; } -.cardpercentagebar50 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 50%, var(--green) 50%) 1; } -.cardpercentagebar51 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 51%, var(--green) 51%) 1; } -.cardpercentagebar52 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 52%, var(--green) 52%) 1; } -.cardpercentagebar53 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 53%, var(--green) 53%) 1; } -.cardpercentagebar54 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 54%, var(--green) 54%) 1; } -.cardpercentagebar55 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 55%, var(--green) 55%) 1; } -.cardpercentagebar56 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 56%, var(--green) 56%) 1; } -.cardpercentagebar57 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 57%, var(--green) 57%) 1; } -.cardpercentagebar58 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 58%, var(--green) 58%) 1; } -.cardpercentagebar59 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 59%, var(--green) 59%) 1; } -.cardpercentagebar60 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 60%, var(--green) 60%) 1; } -.cardpercentagebar61 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 61%, var(--green) 61%) 1; } -.cardpercentagebar62 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 62%, var(--green) 62%) 1; } -.cardpercentagebar63 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 63%, var(--green) 63%) 1; } -.cardpercentagebar64 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 64%, var(--green) 64%) 1; } -.cardpercentagebar65 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 65%, var(--green) 65%) 1; } -.cardpercentagebar66 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 66%, var(--green) 66%) 1; } -.cardpercentagebar67 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 67%, var(--green) 67%) 1; } -.cardpercentagebar68 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 68%, var(--green) 68%) 1; } -.cardpercentagebar69 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 69%, var(--green) 69%) 1; } -.cardpercentagebar70 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 70%, var(--green) 70%) 1; } -.cardpercentagebar71 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 71%, var(--green) 71%) 1; } -.cardpercentagebar72 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 72%, var(--green) 72%) 1; } -.cardpercentagebar73 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 73%, var(--green) 73%) 1; } -.cardpercentagebar74 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 74%, var(--green) 74%) 1; } -.cardpercentagebar75 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 75%, var(--green) 75%) 1; } -.cardpercentagebar76 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 76%, var(--green) 76%) 1; } -.cardpercentagebar77 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 77%, var(--green) 77%) 1; } -.cardpercentagebar78 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 78%, var(--green) 78%) 1; } -.cardpercentagebar79 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 79%, var(--green) 79%) 1; } -.cardpercentagebar80 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 80%, var(--green) 80%) 1; } -.cardpercentagebar81 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 81%, var(--green) 81%) 1; } -.cardpercentagebar82 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 82%, var(--green) 82%) 1; } -.cardpercentagebar83 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 83%, var(--green) 83%) 1; } -.cardpercentagebar84 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 84%, var(--green) 84%) 1; } -.cardpercentagebar85 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 85%, var(--green) 85%) 1; } -.cardpercentagebar86 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 86%, var(--green) 86%) 1; } -.cardpercentagebar87 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 87%, var(--green) 87%) 1; } -.cardpercentagebar88 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 88%, var(--green) 88%) 1; } -.cardpercentagebar89 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 89%, var(--green) 89%) 1; } -.cardpercentagebar90 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 90%, var(--green) 90%) 1; } -.cardpercentagebar91 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 91%, var(--green) 91%) 1; } -.cardpercentagebar92 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 92%, var(--green) 92%) 1; } -.cardpercentagebar93 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 93%, var(--green) 93%) 1; } -.cardpercentagebar94 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 94%, var(--green) 94%) 1; } -.cardpercentagebar95 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 95%, var(--green) 95%) 1; } -.cardpercentagebar96 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 96%, var(--green) 96%) 1; } -.cardpercentagebar97 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 97%, var(--green) 97%) 1; } -.cardpercentagebar98 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 98%, var(--green) 98%) 1; } -.cardpercentagebar99 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 99%, var(--green) 99%) 1; } -.cardpercentagebar100 { border-image: linear-gradient(to bottom, #c10909 0%, #c10909 100%, var(--green) 100%) 1; } - -.covered0 { width: 0px; } -.covered1 { width: 1px; } -.covered2 { width: 2px; } -.covered3 { width: 3px; } -.covered4 { width: 4px; } -.covered5 { width: 5px; } -.covered6 { width: 6px; } -.covered7 { width: 7px; } -.covered8 { width: 8px; } -.covered9 { width: 9px; } -.covered10 { width: 10px; } -.covered11 { width: 11px; } -.covered12 { width: 12px; } -.covered13 { width: 13px; } -.covered14 { width: 14px; } -.covered15 { width: 15px; } -.covered16 { width: 16px; } -.covered17 { width: 17px; } -.covered18 { width: 18px; } -.covered19 { width: 19px; } -.covered20 { width: 20px; } -.covered21 { width: 21px; } -.covered22 { width: 22px; } -.covered23 { width: 23px; } -.covered24 { width: 24px; } -.covered25 { width: 25px; } -.covered26 { width: 26px; } -.covered27 { width: 27px; } -.covered28 { width: 28px; } -.covered29 { width: 29px; } -.covered30 { width: 30px; } -.covered31 { width: 31px; } -.covered32 { width: 32px; } -.covered33 { width: 33px; } -.covered34 { width: 34px; } -.covered35 { width: 35px; } -.covered36 { width: 36px; } -.covered37 { width: 37px; } -.covered38 { width: 38px; } -.covered39 { width: 39px; } -.covered40 { width: 40px; } -.covered41 { width: 41px; } -.covered42 { width: 42px; } -.covered43 { width: 43px; } -.covered44 { width: 44px; } -.covered45 { width: 45px; } -.covered46 { width: 46px; } -.covered47 { width: 47px; } -.covered48 { width: 48px; } -.covered49 { width: 49px; } -.covered50 { width: 50px; } -.covered51 { width: 51px; } -.covered52 { width: 52px; } -.covered53 { width: 53px; } -.covered54 { width: 54px; } -.covered55 { width: 55px; } -.covered56 { width: 56px; } -.covered57 { width: 57px; } -.covered58 { width: 58px; } -.covered59 { width: 59px; } -.covered60 { width: 60px; } -.covered61 { width: 61px; } -.covered62 { width: 62px; } -.covered63 { width: 63px; } -.covered64 { width: 64px; } -.covered65 { width: 65px; } -.covered66 { width: 66px; } -.covered67 { width: 67px; } -.covered68 { width: 68px; } -.covered69 { width: 69px; } -.covered70 { width: 70px; } -.covered71 { width: 71px; } -.covered72 { width: 72px; } -.covered73 { width: 73px; } -.covered74 { width: 74px; } -.covered75 { width: 75px; } -.covered76 { width: 76px; } -.covered77 { width: 77px; } -.covered78 { width: 78px; } -.covered79 { width: 79px; } -.covered80 { width: 80px; } -.covered81 { width: 81px; } -.covered82 { width: 82px; } -.covered83 { width: 83px; } -.covered84 { width: 84px; } -.covered85 { width: 85px; } -.covered86 { width: 86px; } -.covered87 { width: 87px; } -.covered88 { width: 88px; } -.covered89 { width: 89px; } -.covered90 { width: 90px; } -.covered91 { width: 91px; } -.covered92 { width: 92px; } -.covered93 { width: 93px; } -.covered94 { width: 94px; } -.covered95 { width: 95px; } -.covered96 { width: 96px; } -.covered97 { width: 97px; } -.covered98 { width: 98px; } -.covered99 { width: 99px; } -.covered100 { width: 100px; } - - @media print { - html, body { background-color: #fff; } - .container { max-width: 100%; width: 100%; padding: 0; } - .overview colgroup col:first-child { width: 300px; } -} - -.icon-up-down-dir { - background-image: url(icon_up-down-dir.svg), url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB3aWR0aD0iMTc5MiIgaGVpZ2h0PSIxNzkyIiB2aWV3Qm94PSIwIDAgMTc5MiAxNzkyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Im0gMTQwOCw3NDIgcSAwLDI2IC0xOSw0NSAtMTksMTkgLTQ1LDE5IEggNDQ4IHEgLTI2LDAgLTQ1LC0xOSAtMTksLTE5IC0xOSwtNDUgMCwtMjYgMTksLTQ1IEwgODUxLDI0OSBxIDE5LC0xOSA0NSwtMTkgMjYsMCA0NSwxOSBsIDQ0OCw0NDggcSAxOSwxOSAxOSw0NSB6IiAvPjxwYXRoIGQ9Im0gMTQwOCwxMDUwIHEgMCwyNiAtMTksNDUgbCAtNDQ4LDQ0OCBxIC0xOSwxOSAtNDUsMTkgLTI2LDAgLTQ1LC0xOSBMIDQwMywxMDk1IHEgLTE5LC0xOSAtMTksLTQ1IDAsLTI2IDE5LC00NSAxOSwtMTkgNDUsLTE5IGggODk2IHEgMjYsMCA0NSwxOSAxOSwxOSAxOSw0NSB6IiAvPjwvc3ZnPg==); - background-repeat: no-repeat; - background-size: contain; - padding-left: 15px; - height: 0.9em; - display: inline-block; - position: relative; - top: 3px; -} -.icon-up-dir_active { - background-image: url(icon_up-dir.svg), url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB3aWR0aD0iMTc5MiIgaGVpZ2h0PSIxNzkyIiB2aWV3Qm94PSIwIDAgMTc5MiAxNzkyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGZpbGw9IiNjMDAiIGQ9Ik0xNDA4IDEyMTZxMCAyNi0xOSA0NXQtNDUgMTloLTg5NnEtMjYgMC00NS0xOXQtMTktNDUgMTktNDVsNDQ4LTQ0OHExOS0xOSA0NS0xOXQ0NSAxOWw0NDggNDQ4cTE5IDE5IDE5IDQ1eiIvPjwvc3ZnPg==); - background-repeat: no-repeat; - background-size: contain; - padding-left: 15px; - height: 0.9em; - display: inline-block; - position: relative; - top: 3px; -} -.icon-down-dir_active { - background-image: url(icon_up-dir_active.svg), url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB3aWR0aD0iMTc5MiIgaGVpZ2h0PSIxNzkyIiB2aWV3Qm94PSIwIDAgMTc5MiAxNzkyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGZpbGw9IiNjMDAiIGQ9Ik0xNDA4IDcwNHEwIDI2LTE5IDQ1bC00NDggNDQ4cS0xOSAxOS00NSAxOXQtNDUtMTlsLTQ0OC00NDhxLTE5LTE5LTE5LTQ1dDE5LTQ1IDQ1LTE5aDg5NnEyNiAwIDQ1IDE5dDE5IDQ1eiIvPjwvc3ZnPg==); - background-repeat: no-repeat; - background-size: contain; - padding-left: 15px; - height: 0.9em; - display: inline-block; - position: relative; - top: 3px; -} -.icon-info-circled { - background-image: url(icon_info-circled.svg), url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB3aWR0aD0iMTc5MiIgaGVpZ2h0PSIxNzkyIiB2aWV3Qm94PSIwIDAgMTc5MiAxNzkyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxjaXJjbGUgY3g9Ijg5NiIgY3k9Ijg5NiIgcj0iNzUwIiBmaWxsPSIjZmZmIiAvPjxwYXRoIGZpbGw9IiMyOEE1RkYiIGQ9Ik0xMTUyIDEzNzZ2LTE2MHEwLTE0LTktMjN0LTIzLTloLTk2di01MTJxMC0xNC05LTIzdC0yMy05aC0zMjBxLTE0IDAtMjMgOXQtOSAyM3YxNjBxMCAxNCA5IDIzdDIzIDloOTZ2MzIwaC05NnEtMTQgMC0yMyA5dC05IDIzdjE2MHEwIDE0IDkgMjN0MjMgOWg0NDhxMTQgMCAyMy05dDktMjN6bS0xMjgtODk2di0xNjBxMC0xNC05LTIzdC0yMy05aC0xOTJxLTE0IDAtMjMgOXQtOSAyM3YxNjBxMCAxNCA5IDIzdDIzIDloMTkycTE0IDAgMjMtOXQ5LTIzem02NDAgNDE2cTAgMjA5LTEwMyAzODUuNXQtMjc5LjUgMjc5LjUtMzg1LjUgMTAzLTM4NS41LTEwMy0yNzkuNS0yNzkuNS0xMDMtMzg1LjUgMTAzLTM4NS41IDI3OS41LTI3OS41IDM4NS41LTEwMyAzODUuNSAxMDMgMjc5LjUgMjc5LjUgMTAzIDM4NS41eiIvPjwvc3ZnPg==); - background-repeat: no-repeat; - background-size: contain; - padding-left: 15px; - height: 0.9em; - display: inline-block; -} -.icon-plus { - background-image: url(icon_plus.svg), url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB3aWR0aD0iMTc5MiIgaGVpZ2h0PSIxNzkyIiB2aWV3Qm94PSIwIDAgMTc5MiAxNzkyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Ik0xNjAwIDczNnYxOTJxMCA0MC0yOCA2OHQtNjggMjhoLTQxNnY0MTZxMCA0MC0yOCA2OHQtNjggMjhoLTE5MnEtNDAgMC02OC0yOHQtMjgtNjh2LTQxNmgtNDE2cS00MCAwLTY4LTI4dC0yOC02OHYtMTkycTAtNDAgMjgtNjh0NjgtMjhoNDE2di00MTZxMC00MCAyOC02OHQ2OC0yOGgxOTJxNDAgMCA2OCAyOHQyOCA2OHY0MTZoNDE2cTQwIDAgNjggMjh0MjggNjh6Ii8+PC9zdmc+); - background-repeat: no-repeat; - background-size: contain; - padding-left: 15px; - height: 0.9em; - display: inline-block; - position: relative; - top: 3px; -} -.icon-minus { - background-image: url(icon_minus.svg), url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB3aWR0aD0iMTc5MiIgaGVpZ2h0PSIxNzkyIiB2aWV3Qm94PSIwIDAgMTc5MiAxNzkyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGZpbGw9IiNjMDAiIGQ9Ik0xNjAwIDczNnYxOTJxMCA0MC0yOCA2OHQtNjggMjhoLTEyMTZxLTQwIDAtNjgtMjh0LTI4LTY4di0xOTJxMC00MCAyOC02OHQ2OC0yOGgxMjE2cTQwIDAgNjggMjh0MjggNjh6Ii8+PC9zdmc+); - background-repeat: no-repeat; - background-size: contain; - padding-left: 15px; - height: 0.9em; - display: inline-block; - position: relative; - top: 3px; -} -.icon-wrench { - background-image: url(icon_wrench.svg), url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB3aWR0aD0iMTc5MiIgaGVpZ2h0PSIxNzkyIiB2aWV3Qm94PSIwIDAgMTc5MiAxNzkyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Ik00NDggMTQ3MnEwLTI2LTE5LTQ1dC00NS0xOS00NSAxOS0xOSA0NSAxOSA0NSA0NSAxOSA0NS0xOSAxOS00NXptNjQ0LTQyMGwtNjgyIDY4MnEtMzcgMzctOTAgMzctNTIgMC05MS0zN2wtMTA2LTEwOHEtMzgtMzYtMzgtOTAgMC01MyAzOC05MWw2ODEtNjgxcTM5IDk4IDExNC41IDE3My41dDE3My41IDExNC41em02MzQtNDM1cTAgMzktMjMgMTA2LTQ3IDEzNC0xNjQuNSAyMTcuNXQtMjU4LjUgODMuNXEtMTg1IDAtMzE2LjUtMTMxLjV0LTEzMS41LTMxNi41IDEzMS41LTMxNi41IDMxNi41LTEzMS41cTU4IDAgMTIxLjUgMTYuNXQxMDcuNSA0Ni41cTE2IDExIDE2IDI4dC0xNiAyOGwtMjkzIDE2OXYyMjRsMTkzIDEwN3E1LTMgNzktNDguNXQxMzUuNS04MSA3MC41LTM1LjVxMTUgMCAyMy41IDEwdDguNSAyNXoiLz48L3N2Zz4=); - background-repeat: no-repeat; - background-size: contain; - padding-left: 20px; - height: 0.9em; - display: inline-block; -} -.icon-cog { - background-image: url(icon_cog.svg), url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHdpZHRoPSI1MTIiIGhlaWdodD0iNTEyIiB2aWV3Qm94PSIwIDAgNTEyIDUxMiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNNDQ0Ljc4OCAyOTEuMWw0Mi42MTYgMjQuNTk5YzQuODY3IDIuODA5IDcuMTI2IDguNjE4IDUuNDU5IDEzLjk4NS0xMS4wNyAzNS42NDItMjkuOTcgNjcuODQyLTU0LjY4OSA5NC41ODZhMTIuMDE2IDEyLjAxNiAwIDAgMS0xNC44MzIgMi4yNTRsLTQyLjU4NC0yNC41OTVhMTkxLjU3NyAxOTEuNTc3IDAgMCAxLTYwLjc1OSAzNS4xM3Y0OS4xODJhMTIuMDEgMTIuMDEgMCAwIDEtOS4zNzcgMTEuNzE4Yy0zNC45NTYgNy44NS03Mi40OTkgOC4yNTYtMTA5LjIxOS4wMDctNS40OS0xLjIzMy05LjQwMy02LjA5Ni05LjQwMy0xMS43MjN2LTQ5LjE4NGExOTEuNTU1IDE5MS41NTUgMCAwIDEtNjAuNzU5LTM1LjEzbC00Mi41ODQgMjQuNTk1YTEyLjAxNiAxMi4wMTYgMCAwIDEtMTQuODMyLTIuMjU0Yy0yNC43MTgtMjYuNzQ0LTQzLjYxOS01OC45NDQtNTQuNjg5LTk0LjU4Ni0xLjY2Ny01LjM2Ni41OTItMTEuMTc1IDUuNDU5LTEzLjk4NUw2Ny4yMTIgMjkxLjFhMTkzLjQ4IDE5My40OCAwIDAgMSAwLTcwLjE5OWwtNDIuNjE2LTI0LjU5OWMtNC44NjctMi44MDktNy4xMjYtOC42MTgtNS40NTktMTMuOTg1IDExLjA3LTM1LjY0MiAyOS45Ny02Ny44NDIgNTQuNjg5LTk0LjU4NmExMi4wMTYgMTIuMDE2IDAgMCAxIDE0LjgzMi0yLjI1NGw0Mi41ODQgMjQuNTk1YTE5MS41NzcgMTkxLjU3NyAwIDAgMSA2MC43NTktMzUuMTNWMjUuNzU5YTEyLjAxIDEyLjAxIDAgMCAxIDkuMzc3LTExLjcxOGMzNC45NTYtNy44NSA3Mi40OTktOC4yNTYgMTA5LjIxOS0uMDA3IDUuNDkgMS4yMzMgOS40MDMgNi4wOTYgOS40MDMgMTEuNzIzdjQ5LjE4NGExOTEuNTU1IDE5MS41NTUgMCAwIDEgNjAuNzU5IDM1LjEzbDQyLjU4NC0yNC41OTVhMTIuMDE2IDEyLjAxNiAwIDAgMSAxNC44MzIgMi4yNTRjMjQuNzE4IDI2Ljc0NCA0My42MTkgNTguOTQ0IDU0LjY4OSA5NC41ODYgMS42NjcgNS4zNjYtLjU5MiAxMS4xNzUtNS40NTkgMTMuOTg1TDQ0NC43ODggMjIwLjlhMTkzLjQ4NSAxOTMuNDg1IDAgMCAxIDAgNzAuMnpNMzM2IDI1NmMwLTQ0LjExMi0zNS44ODgtODAtODAtODBzLTgwIDM1Ljg4OC04MCA4MCAzNS44ODggODAgODAgODAgODAtMzUuODg4IDgwLTgweiIvPjwvc3ZnPg==); - background-repeat: no-repeat; - background-size: contain; - padding-left: 16px; - height: 0.8em; - display: inline-block; -} -.icon-fork { - background-image: url(icon_fork.svg), url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB3aWR0aD0iMTc5MiIgaGVpZ2h0PSIxNzkyIiB2aWV3Qm94PSIwIDAgMTc5MiAxNzkyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxyZWN0IHdpZHRoPSIxNzkyIiBoZWlnaHQ9IjE3OTIiIHN0eWxlPSJmaWxsOiNmZmYiIC8+PHBhdGggZD0iTTY3MiAxNDcycTAtNDAtMjgtNjh0LTY4LTI4LTY4IDI4LTI4IDY4IDI4IDY4IDY4IDI4IDY4LTI4IDI4LTY4em0wLTExNTJxMC00MC0yOC02OHQtNjgtMjgtNjggMjgtMjggNjggMjggNjggNjggMjggNjgtMjggMjgtNjh6bTY0MCAxMjhxMC00MC0yOC02OHQtNjgtMjgtNjggMjgtMjggNjggMjggNjggNjggMjggNjgtMjggMjgtNjh6bTk2IDBxMCA1Mi0yNiA5Ni41dC03MCA2OS41cS0yIDI4Ny0yMjYgNDE0LTY3IDM4LTIwMyA4MS0xMjggNDAtMTY5LjUgNzF0LTQxLjUgMTAwdjI2cTQ0IDI1IDcwIDY5LjV0MjYgOTYuNXEwIDgwLTU2IDEzNnQtMTM2IDU2LTEzNi01Ni01Ni0xMzZxMC01MiAyNi05Ni41dDcwLTY5LjV2LTgyMHEtNDQtMjUtNzAtNjkuNXQtMjYtOTYuNXEwLTgwIDU2LTEzNnQxMzYtNTYgMTM2IDU2IDU2IDEzNnEwIDUyLTI2IDk2LjV0LTcwIDY5LjV2NDk3cTU0LTI2IDE1NC01NyA1NS0xNyA4Ny41LTI5LjV0NzAuNS0zMSA1OS0zOS41IDQwLjUtNTEgMjgtNjkuNSA4LjUtOTEuNXEtNDQtMjUtNzAtNjkuNXQtMjYtOTYuNXEwLTgwIDU2LTEzNnQxMzYtNTYgMTM2IDU2IDU2IDEzNnoiLz48L3N2Zz4=); - background-repeat: no-repeat; - background-size: contain; - padding-left: 20px; - height: 0.9em; - display: inline-block; -} -.icon-cube { - background-image: url(icon_cube.svg), url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB3aWR0aD0iMTc5MiIgaGVpZ2h0PSIxNzkyIiB2aWV3Qm94PSIwIDAgMTc5MiAxNzkyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Ik04OTYgMTYyOWw2NDAtMzQ5di02MzZsLTY0MCAyMzN2NzUyem0tNjQtODY1bDY5OC0yNTQtNjk4LTI1NC02OTggMjU0em04MzItMjUydjc2OHEwIDM1LTE4IDY1dC00OSA0N2wtNzA0IDM4NHEtMjggMTYtNjEgMTZ0LTYxLTE2bC03MDQtMzg0cS0zMS0xNy00OS00N3QtMTgtNjV2LTc2OHEwLTQwIDIzLTczdDYxLTQ3bDcwNC0yNTZxMjItOCA0NC04dDQ0IDhsNzA0IDI1NnEzOCAxNCA2MSA0N3QyMyA3M3oiLz48L3N2Zz4=); - background-repeat: no-repeat; - background-size: contain; - padding-left: 20px; - height: 0.9em; - display: inline-block; -} -.icon-search-plus { - background-image: url(icon_search-plus.svg), url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB3aWR0aD0iMTc5MiIgaGVpZ2h0PSIxNzkyIiB2aWV3Qm94PSIwIDAgMTc5MiAxNzkyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGZpbGw9IiM2ZjZmNmYiIGQ9Ik0xMDg4IDgwMHY2NHEwIDEzLTkuNSAyMi41dC0yMi41IDkuNWgtMjI0djIyNHEwIDEzLTkuNSAyMi41dC0yMi41IDkuNWgtNjRxLTEzIDAtMjIuNS05LjV0LTkuNS0yMi41di0yMjRoLTIyNHEtMTMgMC0yMi41LTkuNXQtOS41LTIyLjV2LTY0cTAtMTMgOS41LTIyLjV0MjIuNS05LjVoMjI0di0yMjRxMC0xMyA5LjUtMjIuNXQyMi41LTkuNWg2NHExMyAwIDIyLjUgOS41dDkuNSAyMi41djIyNGgyMjRxMTMgMCAyMi41IDkuNXQ5LjUgMjIuNXptMTI4IDMycTAtMTg1LTEzMS41LTMxNi41dC0zMTYuNS0xMzEuNS0zMTYuNSAxMzEuNS0xMzEuNSAzMTYuNSAxMzEuNSAzMTYuNSAzMTYuNSAxMzEuNSAzMTYuNS0xMzEuNSAxMzEuNS0zMTYuNXptNTEyIDgzMnEwIDUzLTM3LjUgOTAuNXQtOTAuNSAzNy41cS01NCAwLTkwLTM4bC0zNDMtMzQycS0xNzkgMTI0LTM5OSAxMjQtMTQzIDAtMjczLjUtNTUuNXQtMjI1LTE1MC0xNTAtMjI1LTU1LjUtMjczLjUgNTUuNS0yNzMuNSAxNTAtMjI1IDIyNS0xNTAgMjczLjUtNTUuNSAyNzMuNSA1NS41IDIyNSAxNTAgMTUwIDIyNSA1NS41IDI3My41cTAgMjIwLTEyNCAzOTlsMzQzIDM0M3EzNyAzNyAzNyA5MHoiLz48L3N2Zz4=); - background-repeat: no-repeat; - background-size: contain; - padding-left: 20px; - height: 0.9em; - display: inline-block; -} -.icon-search-minus { - background-image: url(icon_search-minus.svg), url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB3aWR0aD0iMTc5MiIgaGVpZ2h0PSIxNzkyIiB2aWV3Qm94PSIwIDAgMTc5MiAxNzkyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGZpbGw9IiM2ZjZmNmYiIGQ9Ik0xMDg4IDgwMHY2NHEwIDEzLTkuNSAyMi41dC0yMi41IDkuNWgtNTc2cS0xMyAwLTIyLjUtOS41dC05LjUtMjIuNXYtNjRxMC0xMyA5LjUtMjIuNXQyMi41LTkuNWg1NzZxMTMgMCAyMi41IDkuNXQ5LjUgMjIuNXptMTI4IDMycTAtMTg1LTEzMS41LTMxNi41dC0zMTYuNS0xMzEuNS0zMTYuNSAxMzEuNS0xMzEuNSAzMTYuNSAxMzEuNSAzMTYuNSAzMTYuNSAxMzEuNSAzMTYuNS0xMzEuNSAxMzEuNS0zMTYuNXptNTEyIDgzMnEwIDUzLTM3LjUgOTAuNXQtOTAuNSAzNy41cS01NCAwLTkwLTM4bC0zNDMtMzQycS0xNzkgMTI0LTM5OSAxMjQtMTQzIDAtMjczLjUtNTUuNXQtMjI1LTE1MC0xNTAtMjI1LTU1LjUtMjczLjUgNTUuNS0yNzMuNSAxNTAtMjI1IDIyNS0xNTAgMjczLjUtNTUuNSAyNzMuNSA1NS41IDIyNSAxNTAgMTUwIDIyNSA1NS41IDI3My41cTAgMjIwLTEyNCAzOTlsMzQzIDM0M3EzNyAzNyAzNyA5MHoiLz48L3N2Zz4=); - background-repeat: no-repeat; - background-size: contain; - padding-left: 20px; - height: 0.9em; - display: inline-block; -} -.icon-star { - background-image: url(icon_star.svg), url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB3aWR0aD0iMTc5MiIgaGVpZ2h0PSIxNzkyIiB2aWV3Qm94PSIwIDAgMTc5MiAxNzkyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Ik0xNzI4IDY0N3EwIDIyLTI2IDQ4bC0zNjMgMzU0IDg2IDUwMHExIDcgMSAyMCAwIDIxLTEwLjUgMzUuNXQtMzAuNSAxNC41cS0xOSAwLTQwLTEybC00NDktMjM2LTQ0OSAyMzZxLTIyIDEyLTQwIDEyLTIxIDAtMzEuNS0xNC41dC0xMC41LTM1LjVxMC02IDItMjBsODYtNTAwLTM2NC0zNTRxLTI1LTI3LTI1LTQ4IDAtMzcgNTYtNDZsNTAyLTczIDIyNS00NTVxMTktNDEgNDktNDF0NDkgNDFsMjI1IDQ1NSA1MDIgNzNxNTYgOSA1NiA0NnoiIGZpbGw9IiMwMDAiLz48L3N2Zz4=); - background-repeat: no-repeat; - background-size: contain; - padding-left: 20px; - height: 0.9em; - display: inline-block; -} -.icon-sponsor { - background-image: url(icon_sponsor.svg), url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB3aWR0aD0iMTc5MiIgaGVpZ2h0PSIxNzkyIiB2aWV3Qm94PSIwIDAgMTc5MiAxNzkyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Ik04OTYgMTY2NHEtMjYgMC00NC0xOGwtNjI0LTYwMnEtMTAtOC0yNy41LTI2dC01NS41LTY1LjUtNjgtOTcuNS01My41LTEyMS0yMy41LTEzOHEwLTIyMCAxMjctMzQ0dDM1MS0xMjRxNjIgMCAxMjYuNSAyMS41dDEyMCA1OCA5NS41IDY4LjUgNzYgNjhxMzYtMzYgNzYtNjh0OTUuNS02OC41IDEyMC01OCAxMjYuNS0yMS41cTIyNCAwIDM1MSAxMjR0MTI3IDM0NHEwIDIyMS0yMjkgNDUwbC02MjMgNjAwcS0xOCAxOC00NCAxOHoiIGZpbGw9IiNlYTRhYWEiLz48L3N2Zz4=); - background-repeat: no-repeat; - background-size: contain; - padding-left: 20px; - height: 0.9em; - display: inline-block; -} - -.ngx-slider .ngx-slider-bar { - background: #a9a9a9 !important; -} - -.ngx-slider .ngx-slider-selection { - background: #818181 !important; -} - -.ngx-slider .ngx-slider-bubble { - padding: 3px 4px !important; - font-size: 12px !important; -} - -.ngx-slider .ngx-slider-pointer { - width: 20px !important; - height: 20px !important; - top: -8px !important; - background-color: #0075FF !important; - -webkit-border-radius: 10px !important; - -moz-border-radius: 10px !important; - border-radius: 10px !important; -} - - .ngx-slider .ngx-slider-pointer:after { - content: none !important; - } - -.ngx-slider .ngx-slider-tick.ngx-slider-selected { - background-color: #62a5f4 !important; - width: 8px !important; - height: 8px !important; - top: 1px !important; -} - - - -@media (prefers-color-scheme: dark) { - @media screen { - html { - background-color: #333; - color: #fff; - } - - body { - color: #fff; - } - - h1 { - background-color: #555453; - color: #fff; - } - - .container { - background-color: #333; - box-shadow: 0 0 60px #0c0c0c; - } - - .containerrightfixed { - background-color: #3D3C3C; - border-left: 1px solid #515050; - } - - .containerrightfixed h1 { - background-color: #484747; - } - - .popup-container { - background-color: rgb(80, 80, 80, 0.6); - } - - .popup { - background-color: #333; - } - - .card-group .card { - background-color: #333; - background: radial-gradient(circle, #444 0%, #333 100%); - border: 1px solid #545454; - color: #fff; - } - - .card-group .card table tr { - border-bottom: 1px solid #545454; - } - - .card-group .card table tr:hover { - background-color: #2E2D2C; - } - - .table-responsive::-webkit-scrollbar-thumb { - background-color: #555453; - border: 5px solid #333; - } - - .overview tr:hover > td { - background-color: #2E2D2C; - } - - .overview th { - background-color: #444; - border: 1px solid #3B3A39; - } - - .overview tr.namespace th { - background-color: #444; - } - - .overview thead th { - background-color: #444; - } - - .overview th a { - color: #fff; - color: rgba(255, 255, 255, 0.95); - } - - .overview th a:hover { - color: #0078d4; - } - - .overview td { - border: 1px solid #3B3A39; - } - - .overview .coverage td { - border: none; - } - - .overview tr.header th { - background-color: #444; - } - - .overview tr.header th:nth-child(2n+1) { - background-color: #3a3a3a; - } - - .overview tr.header th:first-child { - border-left: 1px solid #333; - border-top: 1px solid #333; - background-color: #333; - } - - .stripped tr:nth-child(2n+1) { - background-color: #3c3c3c; - } - - input, select, button { - background-color: #333; - color: #fff; - border: 1px solid #A19F9D; - } - - a { - color: #fff; - color: rgba(255, 255, 255, 0.95); - } - - a:hover { - color: #0078d4; - } - - h1 a.back { - background-color: #4a4846; - } - - h1 a.button { - color: #fff; - background-color: #565656; - border-color: #c1c1c1; - } - - h1 a.button:hover { - background-color: #8d8d8d; - } - - .gray { - background-color: #484747; - } - - .lightgray { - color: #ebebeb; - } - - .lightgraybg { - background-color: #474747; - } - - .lightgreen { - background-color: #406540; - } - - .lightorange { - background-color: #ab7f36; - } - - .lightred { - background-color: #954848; - } - - .ct-label { - color: #fff !important; - fill: #fff !important; - } - - .ct-grid { - stroke: #fff !important; - } - - .ct-chart .ct-series.ct-series-a .ct-line, .ct-chart .ct-series.ct-series-a .ct-point { - stroke: #0078D4 !important; - } - - .ct-chart .ct-series.ct-series-b .ct-line, .ct-chart .ct-series.ct-series-b .ct-point { - stroke: #6dc428 !important; - } - - .ct-chart .ct-series.ct-series-c .ct-line, .ct-chart .ct-series.ct-series-c .ct-point { - stroke: #e58f1d !important; - } - - .ct-chart .ct-series.ct-series-d .ct-line, .ct-chart .ct-series.ct-series-d .ct-point { - stroke: #c71bca !important; - } - - .linecoverage { - background-color: #0078D4; - } - - .branchcoverage { - background-color: #6dc428; - } - .codeelementcoverage { - background-color: #e58f1d; - } - - .fullcodeelementcoverage { - background-color: #c71bca; - } - - .tinylinecoveragechart, .tinybranchcoveragechart, .tinymethodcoveragechart, .tinyfullmethodcoveragechart { - background-color: #333; - } - - .tinybranchcoveragechart .ct-series.ct-series-a .ct-line { - stroke: #6dc428 !important; - } - - .tinymethodcoveragechart .ct-series.ct-series-a .ct-line { - stroke: #e58f1d !important; - } - - .tinyfullmethodcoveragechart .ct-series.ct-series-a .ct-line { - stroke: #c71bca !important; - } - - .icon-up-down-dir { - background-image: url(icon_up-down-dir_dark.svg), url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB3aWR0aD0iMTc5MiIgaGVpZ2h0PSIxNzkyIiB2aWV3Qm94PSIwIDAgMTc5MiAxNzkyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGZpbGw9IiNCRkJGQzAiIGQ9Im0gMTQwOCw3NDIgcSAwLDI2IC0xOSw0NSAtMTksMTkgLTQ1LDE5IEggNDQ4IHEgLTI2LDAgLTQ1LC0xOSAtMTksLTE5IC0xOSwtNDUgMCwtMjYgMTksLTQ1IEwgODUxLDI0OSBxIDE5LC0xOSA0NSwtMTkgMjYsMCA0NSwxOSBsIDQ0OCw0NDggcSAxOSwxOSAxOSw0NSB6IiAvPjxwYXRoIGZpbGw9IiNCRkJGQzAiIGQ9Im0gMTQwOCwxMDUwIHEgMCwyNiAtMTksNDUgbCAtNDQ4LDQ0OCBxIC0xOSwxOSAtNDUsMTkgLTI2LDAgLTQ1LC0xOSBMIDQwMywxMDk1IHEgLTE5LC0xOSAtMTksLTQ1IDAsLTI2IDE5LC00NSAxOSwtMTkgNDUsLTE5IGggODk2IHEgMjYsMCA0NSwxOSAxOSwxOSAxOSw0NSB6IiAvPjwvc3ZnPg==); - } - .icon-info-circled { - background-image: url(icon_info-circled_dark.svg), url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB3aWR0aD0iMTc5MiIgaGVpZ2h0PSIxNzkyIiB2aWV3Qm94PSIwIDAgMTc5MiAxNzkyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxjaXJjbGUgY3g9Ijg5NiIgY3k9Ijg5NiIgcj0iNzUwIiBmaWxsPSIjZmZmIiAvPjxwYXRoIGZpbGw9IiMyOEE1RkYiIGQ9Ik0xMTUyIDEzNzZ2LTE2MHEwLTE0LTktMjN0LTIzLTloLTk2di01MTJxMC0xNC05LTIzdC0yMy05aC0zMjBxLTE0IDAtMjMgOXQtOSAyM3YxNjBxMCAxNCA5IDIzdDIzIDloOTZ2MzIwaC05NnEtMTQgMC0yMyA5dC05IDIzdjE2MHEwIDE0IDkgMjN0MjMgOWg0NDhxMTQgMCAyMy05dDktMjN6bS0xMjgtODk2di0xNjBxMC0xNC05LTIzdC0yMy05aC0xOTJxLTE0IDAtMjMgOXQtOSAyM3YxNjBxMCAxNCA5IDIzdDIzIDloMTkycTE0IDAgMjMtOXQ5LTIzem02NDAgNDE2cTAgMjA5LTEwMyAzODUuNXQtMjc5LjUgMjc5LjUtMzg1LjUgMTAzLTM4NS41LTEwMy0yNzkuNS0yNzkuNS0xMDMtMzg1LjUgMTAzLTM4NS41IDI3OS41LTI3OS41IDM4NS41LTEwMyAzODUuNSAxMDMgMjc5LjUgMjc5LjUgMTAzIDM4NS41eiIvPjwvc3ZnPg==); - } - - .icon-plus { - background-image: url(icon_plus_dark.svg), url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHdpZHRoPSIxNzkyIiBoZWlnaHQ9IjE3OTIiIHZpZXdCb3g9IjAgMCAxNzkyIDE3OTIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZmlsbD0iI0JGQkZDMCIgZD0iTTE2MDAgNzM2djE5MnEwIDQwLTI4IDY4dC02OCAyOGgtNDE2djQxNnEwIDQwLTI4IDY4dC02OCAyOGgtMTkycS00MCAwLTY4LTI4dC0yOC02OHYtNDE2aC00MTZxLTQwIDAtNjgtMjh0LTI4LTY4di0xOTJxMC00MCAyOC02OHQ2OC0yOGg0MTZ2LTQxNnEwLTQwIDI4LTY4dDY4LTI4aDE5MnE0MCAwIDY4IDI4dDI4IDY4djQxNmg0MTZxNDAgMCA2OCAyOHQyOCA2OHoiLz48L3N2Zz4=); - } - - .icon-minus { - background-image: url(icon_minus_dark.svg), url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHdpZHRoPSIxNzkyIiBoZWlnaHQ9IjE3OTIiIHZpZXdCb3g9IjAgMCAxNzkyIDE3OTIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZmlsbD0iI0JGQkZDMCIgZD0iTTE2MDAgNzM2djE5MnEwIDQwLTI4IDY4dC02OCAyOGgtMTIxNnEtNDAgMC02OC0yOHQtMjgtNjh2LTE5MnEwLTQwIDI4LTY4dDY4LTI4aDEyMTZxNDAgMCA2OCAyOHQyOCA2OHoiLz48L3N2Zz4=); - } - - .icon-wrench { - background-image: url(icon_wrench_dark.svg), url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHdpZHRoPSIxNzkyIiBoZWlnaHQ9IjE3OTIiIHZpZXdCb3g9IjAgMCAxNzkyIDE3OTIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZmlsbD0iI0JEQkRCRiIgZD0iTTQ0OCAxNDcycTAtMjYtMTktNDV0LTQ1LTE5LTQ1IDE5LTE5IDQ1IDE5IDQ1IDQ1IDE5IDQ1LTE5IDE5LTQ1em02NDQtNDIwbC02ODIgNjgycS0zNyAzNy05MCAzNy01MiAwLTkxLTM3bC0xMDYtMTA4cS0zOC0zNi0zOC05MCAwLTUzIDM4LTkxbDY4MS02ODFxMzkgOTggMTE0LjUgMTczLjV0MTczLjUgMTE0LjV6bTYzNC00MzVxMCAzOS0yMyAxMDYtNDcgMTM0LTE2NC41IDIxNy41dC0yNTguNSA4My41cS0xODUgMC0zMTYuNS0xMzEuNXQtMTMxLjUtMzE2LjUgMTMxLjUtMzE2LjUgMzE2LjUtMTMxLjVxNTggMCAxMjEuNSAxNi41dDEwNy41IDQ2LjVxMTYgMTEgMTYgMjh0LTE2IDI4bC0yOTMgMTY5djIyNGwxOTMgMTA3cTUtMyA3OS00OC41dDEzNS41LTgxIDcwLjUtMzUuNXExNSAwIDIzLjUgMTB0OC41IDI1eiIvPjwvc3ZnPg==); - } - - .icon-cog { - background-image: url(icon_cog_dark.svg), url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHdpZHRoPSI1MTIiIGhlaWdodD0iNTEyIiB2aWV3Qm94PSIwIDAgNTEyIDUxMiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBmaWxsPSIjQkRCREJGIiBkPSJNNDQ0Ljc4OCAyOTEuMWw0Mi42MTYgMjQuNTk5YzQuODY3IDIuODA5IDcuMTI2IDguNjE4IDUuNDU5IDEzLjk4NS0xMS4wNyAzNS42NDItMjkuOTcgNjcuODQyLTU0LjY4OSA5NC41ODZhMTIuMDE2IDEyLjAxNiAwIDAgMS0xNC44MzIgMi4yNTRsLTQyLjU4NC0yNC41OTVhMTkxLjU3NyAxOTEuNTc3IDAgMCAxLTYwLjc1OSAzNS4xM3Y0OS4xODJhMTIuMDEgMTIuMDEgMCAwIDEtOS4zNzcgMTEuNzE4Yy0zNC45NTYgNy44NS03Mi40OTkgOC4yNTYtMTA5LjIxOS4wMDctNS40OS0xLjIzMy05LjQwMy02LjA5Ni05LjQwMy0xMS43MjN2LTQ5LjE4NGExOTEuNTU1IDE5MS41NTUgMCAwIDEtNjAuNzU5LTM1LjEzbC00Mi41ODQgMjQuNTk1YTEyLjAxNiAxMi4wMTYgMCAwIDEtMTQuODMyLTIuMjU0Yy0yNC43MTgtMjYuNzQ0LTQzLjYxOS01OC45NDQtNTQuNjg5LTk0LjU4Ni0xLjY2Ny01LjM2Ni41OTItMTEuMTc1IDUuNDU5LTEzLjk4NUw2Ny4yMTIgMjkxLjFhMTkzLjQ4IDE5My40OCAwIDAgMSAwLTcwLjE5OWwtNDIuNjE2LTI0LjU5OWMtNC44NjctMi44MDktNy4xMjYtOC42MTgtNS40NTktMTMuOTg1IDExLjA3LTM1LjY0MiAyOS45Ny02Ny44NDIgNTQuNjg5LTk0LjU4NmExMi4wMTYgMTIuMDE2IDAgMCAxIDE0LjgzMi0yLjI1NGw0Mi41ODQgMjQuNTk1YTE5MS41NzcgMTkxLjU3NyAwIDAgMSA2MC43NTktMzUuMTNWMjUuNzU5YTEyLjAxIDEyLjAxIDAgMCAxIDkuMzc3LTExLjcxOGMzNC45NTYtNy44NSA3Mi40OTktOC4yNTYgMTA5LjIxOS0uMDA3IDUuNDkgMS4yMzMgOS40MDMgNi4wOTYgOS40MDMgMTEuNzIzdjQ5LjE4NGExOTEuNTU1IDE5MS41NTUgMCAwIDEgNjAuNzU5IDM1LjEzbDQyLjU4NC0yNC41OTVhMTIuMDE2IDEyLjAxNiAwIDAgMSAxNC44MzIgMi4yNTRjMjQuNzE4IDI2Ljc0NCA0My42MTkgNTguOTQ0IDU0LjY4OSA5NC41ODYgMS42NjcgNS4zNjYtLjU5MiAxMS4xNzUtNS40NTkgMTMuOTg1TDQ0NC43ODggMjIwLjlhMTkzLjQ4NSAxOTMuNDg1IDAgMCAxIDAgNzAuMnpNMzM2IDI1NmMwLTQ0LjExMi0zNS44ODgtODAtODAtODBzLTgwIDM1Ljg4OC04MCA4MCAzNS44ODggODAgODAgODAgODAtMzUuODg4IDgwLTgweiIvPjwvc3ZnPg==); - } - - .icon-fork { - background-image: url(icon_fork_dark.svg), url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHdpZHRoPSIxNzkyIiBoZWlnaHQ9IjE3OTIiIHZpZXdCb3g9IjAgMCAxNzkyIDE3OTIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZmlsbD0iI0JGQkZDMCIgZD0iTTY3MiAxNDcycTAtNDAtMjgtNjh0LTY4LTI4LTY4IDI4LTI4IDY4IDI4IDY4IDY4IDI4IDY4LTI4IDI4LTY4em0wLTExNTJxMC00MC0yOC02OHQtNjgtMjgtNjggMjgtMjggNjggMjggNjggNjggMjggNjgtMjggMjgtNjh6bTY0MCAxMjhxMC00MC0yOC02OHQtNjgtMjgtNjggMjgtMjggNjggMjggNjggNjggMjggNjgtMjggMjgtNjh6bTk2IDBxMCA1Mi0yNiA5Ni41dC03MCA2OS41cS0yIDI4Ny0yMjYgNDE0LTY3IDM4LTIwMyA4MS0xMjggNDAtMTY5LjUgNzF0LTQxLjUgMTAwdjI2cTQ0IDI1IDcwIDY5LjV0MjYgOTYuNXEwIDgwLTU2IDEzNnQtMTM2IDU2LTEzNi01Ni01Ni0xMzZxMC01MiAyNi05Ni41dDcwLTY5LjV2LTgyMHEtNDQtMjUtNzAtNjkuNXQtMjYtOTYuNXEwLTgwIDU2LTEzNnQxMzYtNTYgMTM2IDU2IDU2IDEzNnEwIDUyLTI2IDk2LjV0LTcwIDY5LjV2NDk3cTU0LTI2IDE1NC01NyA1NS0xNyA4Ny41LTI5LjV0NzAuNS0zMSA1OS0zOS41IDQwLjUtNTEgMjgtNjkuNSA4LjUtOTEuNXEtNDQtMjUtNzAtNjkuNXQtMjYtOTYuNXEwLTgwIDU2LTEzNnQxMzYtNTYgMTM2IDU2IDU2IDEzNnoiLz48L3N2Zz4=); - } - - .icon-cube { - background-image: url(icon_cube_dark.svg), url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHdpZHRoPSIxNzkyIiBoZWlnaHQ9IjE3OTIiIHZpZXdCb3g9IjAgMCAxNzkyIDE3OTIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZmlsbD0iI0JGQkZDMCIgZD0iTTg5NiAxNjI5bDY0MC0zNDl2LTYzNmwtNjQwIDIzM3Y3NTJ6bS02NC04NjVsNjk4LTI1NC02OTgtMjU0LTY5OCAyNTR6bTgzMi0yNTJ2NzY4cTAgMzUtMTggNjV0LTQ5IDQ3bC03MDQgMzg0cS0yOCAxNi02MSAxNnQtNjEtMTZsLTcwNC0zODRxLTMxLTE3LTQ5LTQ3dC0xOC02NXYtNzY4cTAtNDAgMjMtNzN0NjEtNDdsNzA0LTI1NnEyMi04IDQ0LTh0NDQgOGw3MDQgMjU2cTM4IDE0IDYxIDQ3dDIzIDczeiIvPjwvc3ZnPg==); - } - - .icon-search-plus { - background-image: url(icon_search-plus_dark.svg), url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHdpZHRoPSIxNzkyIiBoZWlnaHQ9IjE3OTIiIHZpZXdCb3g9IjAgMCAxNzkyIDE3OTIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZmlsbD0iI0JGQkZDMCIgZD0iTTEwODggODAwdjY0cTAgMTMtOS41IDIyLjV0LTIyLjUgOS41aC0yMjR2MjI0cTAgMTMtOS41IDIyLjV0LTIyLjUgOS41aC02NHEtMTMgMC0yMi41LTkuNXQtOS41LTIyLjV2LTIyNGgtMjI0cS0xMyAwLTIyLjUtOS41dC05LjUtMjIuNXYtNjRxMC0xMyA5LjUtMjIuNXQyMi41LTkuNWgyMjR2LTIyNHEwLTEzIDkuNS0yMi41dDIyLjUtOS41aDY0cTEzIDAgMjIuNSA5LjV0OS41IDIyLjV2MjI0aDIyNHExMyAwIDIyLjUgOS41dDkuNSAyMi41em0xMjggMzJxMC0xODUtMTMxLjUtMzE2LjV0LTMxNi41LTEzMS41LTMxNi41IDEzMS41LTEzMS41IDMxNi41IDEzMS41IDMxNi41IDMxNi41IDEzMS41IDMxNi41LTEzMS41IDEzMS41LTMxNi41em01MTIgODMycTAgNTMtMzcuNSA5MC41dC05MC41IDM3LjVxLTU0IDAtOTAtMzhsLTM0My0zNDJxLTE3OSAxMjQtMzk5IDEyNC0xNDMgMC0yNzMuNS01NS41dC0yMjUtMTUwLTE1MC0yMjUtNTUuNS0yNzMuNSA1NS41LTI3My41IDE1MC0yMjUgMjI1LTE1MCAyNzMuNS01NS41IDI3My41IDU1LjUgMjI1IDE1MCAxNTAgMjI1IDU1LjUgMjczLjVxMCAyMjAtMTI0IDM5OWwzNDMgMzQzcTM3IDM3IDM3IDkweiIvPjwvc3ZnPg==); - } - - .icon-search-minus { - background-image: url(icon_search-minus_dark.svg), url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHdpZHRoPSIxNzkyIiBoZWlnaHQ9IjE3OTIiIHZpZXdCb3g9IjAgMCAxNzkyIDE3OTIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZmlsbD0iI0JGQkZDMCIgZD0iTTEwODggODAwdjY0cTAgMTMtOS41IDIyLjV0LTIyLjUgOS41aC01NzZxLTEzIDAtMjIuNS05LjV0LTkuNS0yMi41di02NHEwLTEzIDkuNS0yMi41dDIyLjUtOS41aDU3NnExMyAwIDIyLjUgOS41dDkuNSAyMi41em0xMjggMzJxMC0xODUtMTMxLjUtMzE2LjV0LTMxNi41LTEzMS41LTMxNi41IDEzMS41LTEzMS41IDMxNi41IDEzMS41IDMxNi41IDMxNi41IDEzMS41IDMxNi41LTEzMS41IDEzMS41LTMxNi41em01MTIgODMycTAgNTMtMzcuNSA5MC41dC05MC41IDM3LjVxLTU0IDAtOTAtMzhsLTM0My0zNDJxLTE3OSAxMjQtMzk5IDEyNC0xNDMgMC0yNzMuNS01NS41dC0yMjUtMTUwLTE1MC0yMjUtNTUuNS0yNzMuNSA1NS41LTI3My41IDE1MC0yMjUgMjI1LTE1MCAyNzMuNS01NS41IDI3My41IDU1LjUgMjI1IDE1MCAxNTAgMjI1IDU1LjUgMjczLjVxMCAyMjAtMTI0IDM5OWwzNDMgMzQzcTM3IDM3IDM3IDkweiIvPjwvc3ZnPg==); - } - - .icon-star { - background-image: url(icon_star_dark.svg), url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB3aWR0aD0iMTc5MiIgaGVpZ2h0PSIxNzkyIiB2aWV3Qm94PSIwIDAgMTc5MiAxNzkyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Ik0xNzI4IDY0N3EwIDIyLTI2IDQ4bC0zNjMgMzU0IDg2IDUwMHExIDcgMSAyMCAwIDIxLTEwLjUgMzUuNXQtMzAuNSAxNC41cS0xOSAwLTQwLTEybC00NDktMjM2LTQ0OSAyMzZxLTIyIDEyLTQwIDEyLTIxIDAtMzEuNS0xNC41dC0xMC41LTM1LjVxMC02IDItMjBsODYtNTAwLTM2NC0zNTRxLTI1LTI3LTI1LTQ4IDAtMzcgNTYtNDZsNTAyLTczIDIyNS00NTVxMTktNDEgNDktNDF0NDkgNDFsMjI1IDQ1NSA1MDIgNzNxNTYgOSA1NiA0NnoiIGZpbGw9IiNmZmYiLz48L3N2Zz4=); - } - } -} - -.ct-double-octave:after,.ct-golden-section:after,.ct-major-eleventh:after,.ct-major-second:after,.ct-major-seventh:after,.ct-major-sixth:after,.ct-major-tenth:after,.ct-major-third:after,.ct-major-twelfth:after,.ct-minor-second:after,.ct-minor-seventh:after,.ct-minor-sixth:after,.ct-minor-third:after,.ct-octave:after,.ct-perfect-fifth:after,.ct-perfect-fourth:after,.ct-square:after{content:"";clear:both}.ct-label{fill:rgba(0,0,0,.4);color:rgba(0,0,0,.4);font-size:.75rem;line-height:1}.ct-chart-bar .ct-label,.ct-chart-line .ct-label{display:block;display:-webkit-box;display:-moz-box;display:-ms-flexbox;display:-webkit-flex;display:flex}.ct-chart-donut .ct-label,.ct-chart-pie .ct-label{dominant-baseline:central}.ct-label.ct-horizontal.ct-start{-webkit-box-align:flex-end;-webkit-align-items:flex-end;-ms-flex-align:flex-end;align-items:flex-end;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:start}.ct-label.ct-horizontal.ct-end{-webkit-box-align:flex-start;-webkit-align-items:flex-start;-ms-flex-align:flex-start;align-items:flex-start;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:start}.ct-label.ct-vertical.ct-start{-webkit-box-align:flex-end;-webkit-align-items:flex-end;-ms-flex-align:flex-end;align-items:flex-end;-webkit-box-pack:flex-end;-webkit-justify-content:flex-end;-ms-flex-pack:flex-end;justify-content:flex-end;text-align:right;text-anchor:end}.ct-label.ct-vertical.ct-end{-webkit-box-align:flex-end;-webkit-align-items:flex-end;-ms-flex-align:flex-end;align-items:flex-end;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:start}.ct-chart-bar .ct-label.ct-horizontal.ct-start{-webkit-box-align:flex-end;-webkit-align-items:flex-end;-ms-flex-align:flex-end;align-items:flex-end;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;text-align:center;text-anchor:start}.ct-chart-bar .ct-label.ct-horizontal.ct-end{-webkit-box-align:flex-start;-webkit-align-items:flex-start;-ms-flex-align:flex-start;align-items:flex-start;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;text-align:center;text-anchor:start}.ct-chart-bar.ct-horizontal-bars .ct-label.ct-horizontal.ct-start{-webkit-box-align:flex-end;-webkit-align-items:flex-end;-ms-flex-align:flex-end;align-items:flex-end;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:start}.ct-chart-bar.ct-horizontal-bars .ct-label.ct-horizontal.ct-end{-webkit-box-align:flex-start;-webkit-align-items:flex-start;-ms-flex-align:flex-start;align-items:flex-start;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:start}.ct-chart-bar.ct-horizontal-bars .ct-label.ct-vertical.ct-start{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:flex-end;-webkit-justify-content:flex-end;-ms-flex-pack:flex-end;justify-content:flex-end;text-align:right;text-anchor:end}.ct-chart-bar.ct-horizontal-bars .ct-label.ct-vertical.ct-end{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:end}.ct-grid{stroke:rgba(0,0,0,.2);stroke-width:1px;stroke-dasharray:2px}.ct-grid-background{fill:none}.ct-point{stroke-width:10px;stroke-linecap:round}.ct-line{fill:none;stroke-width:4px}.ct-area{stroke:none;fill-opacity:.1}.ct-bar{fill:none;stroke-width:10px}.ct-slice-donut{fill:none;stroke-width:60px}.ct-series-a .ct-bar,.ct-series-a .ct-line,.ct-series-a .ct-point,.ct-series-a .ct-slice-donut{stroke:#d70206}.ct-series-a .ct-area,.ct-series-a .ct-slice-donut-solid,.ct-series-a .ct-slice-pie{fill:#d70206}.ct-series-b .ct-bar,.ct-series-b .ct-line,.ct-series-b .ct-point,.ct-series-b .ct-slice-donut{stroke:#f05b4f}.ct-series-b .ct-area,.ct-series-b .ct-slice-donut-solid,.ct-series-b .ct-slice-pie{fill:#f05b4f}.ct-series-c .ct-bar,.ct-series-c .ct-line,.ct-series-c .ct-point,.ct-series-c .ct-slice-donut{stroke:#f4c63d}.ct-series-c .ct-area,.ct-series-c .ct-slice-donut-solid,.ct-series-c .ct-slice-pie{fill:#f4c63d}.ct-series-d .ct-bar,.ct-series-d .ct-line,.ct-series-d .ct-point,.ct-series-d .ct-slice-donut{stroke:#d17905}.ct-series-d .ct-area,.ct-series-d .ct-slice-donut-solid,.ct-series-d .ct-slice-pie{fill:#d17905}.ct-series-e .ct-bar,.ct-series-e .ct-line,.ct-series-e .ct-point,.ct-series-e .ct-slice-donut{stroke:#453d3f}.ct-series-e .ct-area,.ct-series-e .ct-slice-donut-solid,.ct-series-e .ct-slice-pie{fill:#453d3f}.ct-series-f .ct-bar,.ct-series-f .ct-line,.ct-series-f .ct-point,.ct-series-f .ct-slice-donut{stroke:#59922b}.ct-series-f .ct-area,.ct-series-f .ct-slice-donut-solid,.ct-series-f .ct-slice-pie{fill:#59922b}.ct-series-g .ct-bar,.ct-series-g .ct-line,.ct-series-g .ct-point,.ct-series-g .ct-slice-donut{stroke:#0544d3}.ct-series-g .ct-area,.ct-series-g .ct-slice-donut-solid,.ct-series-g .ct-slice-pie{fill:#0544d3}.ct-series-h .ct-bar,.ct-series-h .ct-line,.ct-series-h .ct-point,.ct-series-h .ct-slice-donut{stroke:#6b0392}.ct-series-h .ct-area,.ct-series-h .ct-slice-donut-solid,.ct-series-h .ct-slice-pie{fill:#6b0392}.ct-series-i .ct-bar,.ct-series-i .ct-line,.ct-series-i .ct-point,.ct-series-i .ct-slice-donut{stroke:#f05b4f}.ct-series-i .ct-area,.ct-series-i .ct-slice-donut-solid,.ct-series-i .ct-slice-pie{fill:#f05b4f}.ct-series-j .ct-bar,.ct-series-j .ct-line,.ct-series-j .ct-point,.ct-series-j .ct-slice-donut{stroke:#dda458}.ct-series-j .ct-area,.ct-series-j .ct-slice-donut-solid,.ct-series-j .ct-slice-pie{fill:#dda458}.ct-series-k .ct-bar,.ct-series-k .ct-line,.ct-series-k .ct-point,.ct-series-k .ct-slice-donut{stroke:#eacf7d}.ct-series-k .ct-area,.ct-series-k .ct-slice-donut-solid,.ct-series-k .ct-slice-pie{fill:#eacf7d}.ct-series-l .ct-bar,.ct-series-l .ct-line,.ct-series-l .ct-point,.ct-series-l .ct-slice-donut{stroke:#86797d}.ct-series-l .ct-area,.ct-series-l .ct-slice-donut-solid,.ct-series-l .ct-slice-pie{fill:#86797d}.ct-series-m .ct-bar,.ct-series-m .ct-line,.ct-series-m .ct-point,.ct-series-m .ct-slice-donut{stroke:#b2c326}.ct-series-m .ct-area,.ct-series-m .ct-slice-donut-solid,.ct-series-m .ct-slice-pie{fill:#b2c326}.ct-series-n .ct-bar,.ct-series-n .ct-line,.ct-series-n .ct-point,.ct-series-n .ct-slice-donut{stroke:#6188e2}.ct-series-n .ct-area,.ct-series-n .ct-slice-donut-solid,.ct-series-n .ct-slice-pie{fill:#6188e2}.ct-series-o .ct-bar,.ct-series-o .ct-line,.ct-series-o .ct-point,.ct-series-o .ct-slice-donut{stroke:#a748ca}.ct-series-o .ct-area,.ct-series-o .ct-slice-donut-solid,.ct-series-o .ct-slice-pie{fill:#a748ca}.ct-square{display:block;position:relative;width:100%}.ct-square:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:100%}.ct-square:after{display:table}.ct-square>svg{display:block;position:absolute;top:0;left:0}.ct-minor-second{display:block;position:relative;width:100%}.ct-minor-second:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:93.75%}.ct-minor-second:after{display:table}.ct-minor-second>svg{display:block;position:absolute;top:0;left:0}.ct-major-second{display:block;position:relative;width:100%}.ct-major-second:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:88.8888888889%}.ct-major-second:after{display:table}.ct-major-second>svg{display:block;position:absolute;top:0;left:0}.ct-minor-third{display:block;position:relative;width:100%}.ct-minor-third:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:83.3333333333%}.ct-minor-third:after{display:table}.ct-minor-third>svg{display:block;position:absolute;top:0;left:0}.ct-major-third{display:block;position:relative;width:100%}.ct-major-third:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:80%}.ct-major-third:after{display:table}.ct-major-third>svg{display:block;position:absolute;top:0;left:0}.ct-perfect-fourth{display:block;position:relative;width:100%}.ct-perfect-fourth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:75%}.ct-perfect-fourth:after{display:table}.ct-perfect-fourth>svg{display:block;position:absolute;top:0;left:0}.ct-perfect-fifth{display:block;position:relative;width:100%}.ct-perfect-fifth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:66.6666666667%}.ct-perfect-fifth:after{display:table}.ct-perfect-fifth>svg{display:block;position:absolute;top:0;left:0}.ct-minor-sixth{display:block;position:relative;width:100%}.ct-minor-sixth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:62.5%}.ct-minor-sixth:after{display:table}.ct-minor-sixth>svg{display:block;position:absolute;top:0;left:0}.ct-golden-section{display:block;position:relative;width:100%}.ct-golden-section:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:61.804697157%}.ct-golden-section:after{display:table}.ct-golden-section>svg{display:block;position:absolute;top:0;left:0}.ct-major-sixth{display:block;position:relative;width:100%}.ct-major-sixth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:60%}.ct-major-sixth:after{display:table}.ct-major-sixth>svg{display:block;position:absolute;top:0;left:0}.ct-minor-seventh{display:block;position:relative;width:100%}.ct-minor-seventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:56.25%}.ct-minor-seventh:after{display:table}.ct-minor-seventh>svg{display:block;position:absolute;top:0;left:0}.ct-major-seventh{display:block;position:relative;width:100%}.ct-major-seventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:53.3333333333%}.ct-major-seventh:after{display:table}.ct-major-seventh>svg{display:block;position:absolute;top:0;left:0}.ct-octave{display:block;position:relative;width:100%}.ct-octave:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:50%}.ct-octave:after{display:table}.ct-octave>svg{display:block;position:absolute;top:0;left:0}.ct-major-tenth{display:block;position:relative;width:100%}.ct-major-tenth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:40%}.ct-major-tenth:after{display:table}.ct-major-tenth>svg{display:block;position:absolute;top:0;left:0}.ct-major-eleventh{display:block;position:relative;width:100%}.ct-major-eleventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:37.5%}.ct-major-eleventh:after{display:table}.ct-major-eleventh>svg{display:block;position:absolute;top:0;left:0}.ct-major-twelfth{display:block;position:relative;width:100%}.ct-major-twelfth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:33.3333333333%}.ct-major-twelfth:after{display:table}.ct-major-twelfth>svg{display:block;position:absolute;top:0;left:0}.ct-double-octave{display:block;position:relative;width:100%}.ct-double-octave:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:25%}.ct-double-octave:after{display:table}.ct-double-octave>svg{display:block;position:absolute;top:0;left:0} \ No newline at end of file From 0c3f55282c15c59a8c141e470711ee3c23c32be8 Mon Sep 17 00:00:00 2001 From: grant-dot-dev <12433404+grant-dot-dev@users.noreply.github.com> Date: Tue, 18 Feb 2025 11:30:07 +0000 Subject: [PATCH 3/3] v1.6 add create sql script HierarchyProvider table --- .../V1.6__AddHierarchyProviderTable.sql | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 database/schema/V1.6__AddHierarchyProviderTable.sql diff --git a/database/schema/V1.6__AddHierarchyProviderTable.sql b/database/schema/V1.6__AddHierarchyProviderTable.sql new file mode 100644 index 0000000..b67e2fc --- /dev/null +++ b/database/schema/V1.6__AddHierarchyProviderTable.sql @@ -0,0 +1,20 @@ +SET + ANSI_NULLS ON; + +SET + QUOTED_IDENTIFIER ON; + +CREATE TABLE Data.HierarchyProviderConsumers ( + OdsCode NVARCHAR(450) NOT NULL, + PracticeName NVARCHAR(MAX) NULL, + RegisteredPatientCount INT NOT NULL, + RegionCode NVARCHAR(MAX) NULL, + RegionName NVARCHAR(MAX) NULL, + Icb22Name NVARCHAR(MAX) NULL, + PcnName NVARCHAR(MAX) NULL, + Appointments13000 INT NOT NULL, + CONSTRAINT PK_HierarchyProviderConsumers PRIMARY KEY CLUSTERED (OdsCode ASC) +) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]; + +SET + ANSI_PADDING ON; \ No newline at end of file