From c85463bc1850e0247ca3c2e3e33c5ee54103f2b1 Mon Sep 17 00:00:00 2001 From: Anthony Stirling <77850077+Frooodle@users.noreply.github.com> Date: Mon, 14 Oct 2024 22:34:41 +0100 Subject: [PATCH] Frooodle/license (#1994) --- .gitignore | 1 - build.gradle | 13 +- cucumber/exampleFiles/example.html | 11 + cucumber/exampleFiles/example.md | 16 + cucumber/exampleFiles/example_html.zip | Bin 0 -> 284 bytes cucumber/features/external.feature | 30 +- .../docker-compose-latest-fat-security.yml | 4 +- .../software/SPDF/EE/EEAppConfig.java | 7 +- .../SPDF/EE/KeygenLicenseVerifier.java | 204 ++++++++++ .../software/SPDF/EE/LicenseKeyChecker.java | 59 +++ .../software/SPDF/LibreOfficeListener.java | 5 +- .../software/SPDF/config/AppConfig.java | 23 ++ .../SPDF/config/AppUpdateService.java | 1 + .../software/SPDF/config/InitialSetup.java | 42 ++ .../{Beans.java => LocaleConfiguration.java} | 2 +- .../software/SPDF/config/MetricsFilter.java | 6 +- .../software/SPDF/config/PostHogConfig.java | 34 ++ .../FingerprintBasedSessionFilter.java | 68 ++++ .../FingerprintBasedSessionManager.java | 134 +++++++ .../fingerprint/FingerprintGenerator.java | 77 ++++ .../DatabaseBackupInterface.java | 2 +- .../{ => interfaces}/ShowAdminInterface.java | 2 +- .../config/security/AppUpdateAuthService.java | 2 +- .../config/security/FirstLoginFilter.java | 21 + .../config/security/InitialSecuritySetup.java | 45 +-- .../security/SecurityConfiguration.java | 273 ++++--------- .../security/UserAuthenticationFilter.java | 31 +- .../SPDF/config/security/UserService.java | 6 +- .../database/DatabaseBackupHelper.java | 2 +- .../saml/ConvertResponseToAuthentication.java | 68 ++++ ...ustomSAMLAuthenticationFailureHandler.java | 51 +++ ...ustomSAMLAuthenticationSuccessHandler.java | 108 +++++ .../saml/SAMLLogoutSuccessHandler.java | 38 ++ .../saml/Saml2AuthorityAttributeLookup.java | 7 + .../Saml2AuthorityAttributeLookupImpl.java | 17 + .../security/saml/SamlAssertionUtils.java | 63 +++ .../SPDF/config/security/saml/SamlConfig.java | 42 ++ .../saml/ScimSaml2AuthenticatedPrincipal.java | 89 ++++ .../security/saml/SimpleScimMappings.java | 10 + .../session/CustomHttpSessionListener.java | 13 +- .../session/SessionPersistentRegistry.java | 8 + .../SPDF/controller/api/CropController.java | 7 +- .../controller/api/SettingsController.java | 37 ++ .../controller/api/SplitPDFController.java | 2 - .../api/SplitPdfByChaptersController.java | 2 +- .../SPDF/controller/api/UserController.java | 8 +- .../ConvertBookToPDFController.java | 6 +- .../api/converters/ConvertHtmlToPDF.java | 28 +- .../api/converters/ConvertMarkdownToPdf.java | 28 +- .../ConvertPDFToBookController.java | 4 +- .../api/converters/ConvertPDFToPDFA.java | 2 +- .../api/misc/ExtractImagesController.java | 2 - .../api/misc/PrintFileController.java | 4 +- .../api/security/RedactController.java | 2 - .../controller/web/GeneralWebController.java | 7 + .../SPDF/model/ApplicationProperties.java | 39 ++ .../software/SPDF/pdf/TextFinder.java | 4 +- .../SPDF/service/CustomPDDocumentFactory.java | 31 +- .../service/MetricsAggregatorService.java | 56 +++ .../PdfMetadataService.java | 57 ++- .../software/SPDF/service/PostHogService.java | 379 ++++++++++++++++++ .../SPDF/utils/CustomHtmlSanitizer.java | 21 + .../software/SPDF/utils/FileToPdf.java | 104 ++++- .../software/SPDF/utils/GeneralUtils.java | 87 ++++ .../software/SPDF/utils/PDFToFile.java | 1 - .../software/SPDF/utils/RequestUriUtils.java | 1 + .../misc/ReplaceAndInvertColorStrategy.java | 3 +- src/main/resources/application.properties | 6 +- src/main/resources/messages_ar_AR.properties | 48 ++- src/main/resources/messages_bg_BG.properties | 46 ++- src/main/resources/messages_ca_CA.properties | 48 ++- src/main/resources/messages_cs_CZ.properties | 48 ++- src/main/resources/messages_da_DK.properties | 46 ++- src/main/resources/messages_de_DE.properties | 48 ++- src/main/resources/messages_el_GR.properties | 46 ++- src/main/resources/messages_en_GB.properties | 54 ++- src/main/resources/messages_en_US.properties | 46 ++- src/main/resources/messages_es_ES.properties | 48 ++- src/main/resources/messages_eu_ES.properties | 46 ++- src/main/resources/messages_fr_FR.properties | 48 ++- src/main/resources/messages_ga_IE.properties | 46 ++- src/main/resources/messages_hi_IN.properties | 46 ++- src/main/resources/messages_hr_HR.properties | 48 ++- src/main/resources/messages_hu_HU.properties | 46 ++- src/main/resources/messages_id_ID.properties | 48 ++- src/main/resources/messages_it_IT.properties | 48 ++- src/main/resources/messages_ja_JP.properties | 48 ++- src/main/resources/messages_ko_KR.properties | 46 ++- src/main/resources/messages_nl_NL.properties | 48 ++- src/main/resources/messages_no_NB.properties | 46 ++- src/main/resources/messages_pl_PL.properties | 48 ++- src/main/resources/messages_pt_BR.properties | 48 ++- src/main/resources/messages_pt_PT.properties | 46 ++- src/main/resources/messages_ro_RO.properties | 46 ++- src/main/resources/messages_ru_RU.properties | 46 ++- src/main/resources/messages_sk_SK.properties | 48 ++- .../resources/messages_sr_LATN_RS.properties | 46 ++- src/main/resources/messages_sv_SE.properties | 46 ++- src/main/resources/messages_th_TH.properties | 46 ++- src/main/resources/messages_tr_TR.properties | 48 ++- src/main/resources/messages_uk_UA.properties | 46 ++- src/main/resources/messages_vi_VN.properties | 46 ++- src/main/resources/messages_zh_CN.properties | 46 ++- src/main/resources/messages_zh_TW.properties | 46 ++- src/main/resources/settings.yml.template | 5 +- .../resources/static/css/bootstrap.min.css | 2 +- src/main/resources/static/css/multi-tool.css | 2 +- src/main/resources/static/css/navbar.css | 31 ++ src/main/resources/static/css/rotate-pdf.css | 13 + src/main/resources/static/js/downloader.js | 23 +- src/main/resources/static/js/favourites.js | 68 +++- src/main/resources/static/js/homecard.js | 54 ++- .../static/js/multitool/PdfActionsManager.js | 1 + .../static/js/multitool/PdfContainer.js | 4 + .../static/js/multitool/horizontalScroll.js | 25 +- src/main/resources/templates/account.html | 6 +- src/main/resources/templates/addUsers.html | 2 + .../resources/templates/fragments/card.html | 2 +- .../resources/templates/fragments/common.html | 44 ++ .../resources/templates/fragments/footer.html | 2 +- .../resources/templates/fragments/navbar.html | 9 + src/main/resources/templates/home.html | 162 ++++++-- .../templates/split-pdf-by-chapters.html | 64 +++ test.sh | 48 +-- 124 files changed, 4323 insertions(+), 501 deletions(-) create mode 100644 cucumber/exampleFiles/example.html create mode 100644 cucumber/exampleFiles/example.md create mode 100644 cucumber/exampleFiles/example_html.zip create mode 100644 src/main/java/stirling/software/SPDF/EE/KeygenLicenseVerifier.java create mode 100644 src/main/java/stirling/software/SPDF/EE/LicenseKeyChecker.java create mode 100644 src/main/java/stirling/software/SPDF/config/InitialSetup.java rename src/main/java/stirling/software/SPDF/config/{Beans.java => LocaleConfiguration.java} (97%) create mode 100644 src/main/java/stirling/software/SPDF/config/PostHogConfig.java create mode 100644 src/main/java/stirling/software/SPDF/config/fingerprint/FingerprintBasedSessionFilter.java create mode 100644 src/main/java/stirling/software/SPDF/config/fingerprint/FingerprintBasedSessionManager.java create mode 100644 src/main/java/stirling/software/SPDF/config/fingerprint/FingerprintGenerator.java rename src/main/java/stirling/software/SPDF/config/{ => interfaces}/DatabaseBackupInterface.java (85%) rename src/main/java/stirling/software/SPDF/config/{ => interfaces}/ShowAdminInterface.java (69%) create mode 100644 src/main/java/stirling/software/SPDF/config/security/saml/ConvertResponseToAuthentication.java create mode 100644 src/main/java/stirling/software/SPDF/config/security/saml/CustomSAMLAuthenticationFailureHandler.java create mode 100644 src/main/java/stirling/software/SPDF/config/security/saml/CustomSAMLAuthenticationSuccessHandler.java create mode 100644 src/main/java/stirling/software/SPDF/config/security/saml/SAMLLogoutSuccessHandler.java create mode 100644 src/main/java/stirling/software/SPDF/config/security/saml/Saml2AuthorityAttributeLookup.java create mode 100644 src/main/java/stirling/software/SPDF/config/security/saml/Saml2AuthorityAttributeLookupImpl.java create mode 100644 src/main/java/stirling/software/SPDF/config/security/saml/SamlAssertionUtils.java create mode 100644 src/main/java/stirling/software/SPDF/config/security/saml/SamlConfig.java create mode 100644 src/main/java/stirling/software/SPDF/config/security/saml/ScimSaml2AuthenticatedPrincipal.java create mode 100644 src/main/java/stirling/software/SPDF/config/security/saml/SimpleScimMappings.java create mode 100644 src/main/java/stirling/software/SPDF/controller/api/SettingsController.java create mode 100644 src/main/java/stirling/software/SPDF/service/MetricsAggregatorService.java rename src/main/java/stirling/software/SPDF/{config => service}/PdfMetadataService.java (62%) create mode 100644 src/main/java/stirling/software/SPDF/service/PostHogService.java create mode 100644 src/main/java/stirling/software/SPDF/utils/CustomHtmlSanitizer.java create mode 100644 src/main/resources/templates/split-pdf-by-chapters.html diff --git a/.gitignore b/.gitignore index ba9d755d..c5a8f2e7 100644 --- a/.gitignore +++ b/.gitignore @@ -110,7 +110,6 @@ watchedFolders/ *.war *.nar *.ear -*.zip *.tar.gz *.rar *.db diff --git a/build.gradle b/build.gradle index 860a574a..f4683882 100644 --- a/build.gradle +++ b/build.gradle @@ -22,7 +22,7 @@ ext { } group = "stirling.software" -version = "0.29.0" +version = "0.30.0" java { // 17 is lowest but we support and recommend 21 @@ -32,6 +32,12 @@ java { repositories { mavenCentral() maven { url "https://jitpack.io" } + maven { + url "https://build.shibboleth.net/nexus/content/repositories/releases/" + } + maven { + url "https://build.shibboleth.net/maven/releases/" + } } licenseReport { @@ -127,6 +133,9 @@ dependencies { implementation "org.springframework.boot:spring-boot-starter-jetty:$springBootVersion" implementation "org.springframework.boot:spring-boot-starter-thymeleaf:$springBootVersion" + implementation 'com.posthog.java:posthog:1.1.1' + implementation 'com.googlecode.owasp-java-html-sanitizer:owasp-java-html-sanitizer:20240325.1' + if (System.getenv("DOCKER_ENABLE_SECURITY") != "false") { implementation "org.springframework.boot:spring-boot-starter-security:$springBootVersion" @@ -134,6 +143,8 @@ dependencies { implementation "org.springframework.boot:spring-boot-starter-data-jpa:$springBootVersion" implementation "org.springframework.boot:spring-boot-starter-oauth2-client:$springBootVersion" + implementation 'org.springframework.security:spring-security-saml2-service-provider:6.3.3' + implementation 'com.unboundid.product.scim2:scim2-sdk-client:2.3.5' //2.2.x requires rebuild of DB file.. need migration path runtimeOnly "com.h2database:h2:2.1.214" // implementation "com.h2database:h2:2.2.224" diff --git a/cucumber/exampleFiles/example.html b/cucumber/exampleFiles/example.html new file mode 100644 index 00000000..82e96100 --- /dev/null +++ b/cucumber/exampleFiles/example.html @@ -0,0 +1,11 @@ + + + + +

My First Heading

+ +

My first paragraph.

+ + + + diff --git a/cucumber/exampleFiles/example.md b/cucumber/exampleFiles/example.md new file mode 100644 index 00000000..10bb117b --- /dev/null +++ b/cucumber/exampleFiles/example.md @@ -0,0 +1,16 @@ +header +============ + +Header2 +------------ +text + +text2 + +## **PDF Features** + +### **Page Operations** + +- View and modify PDFs - View multi page PDFs with custom viewing sorting and searching. Plus on page edit features like annotate, draw and adding text and images. (Using PDF.js with Joxit and Liberation.Liberation fonts) +- Full interactive GUI for merging/splitting/rotating/moving PDFs and their pages. +- Merge multiple PDFs together into a single resultant file. \ No newline at end of file diff --git a/cucumber/exampleFiles/example_html.zip b/cucumber/exampleFiles/example_html.zip new file mode 100644 index 0000000000000000000000000000000000000000..23bd1950c444d74aff9bee2916f8d44526dbf80b GIT binary patch literal 284 zcmWIWW@Zs#-~horu8|B-Pz0oT7!(*%D-v@Ha#Hm&N^)~TLwFh33-&Rl*8y=d5SLbP zGcdA%bbyJ?fh8Zy`8s(DLQiO%JiGDn(@l*RJ%4IWb&yg?%6J~V^1-yokeEdeCeE5M zY3B62#rz^H-eL_;E*&Uh?R4#Y>DtLES!MQ%RUoo response = client.send(request, HttpResponse.BodyHandlers.ofString()); + log.info(" validateLicenseResponse body: " + response.body()); + JsonNode jsonResponse = objectMapper.readTree(response.body()); + if (response.statusCode() == 200) { + + JsonNode metaNode = jsonResponse.path("meta"); + boolean isValid = metaNode.path("valid").asBoolean(); + + String detail = metaNode.path("detail").asText(); + String code = metaNode.path("code").asText(); + + log.debug("License validity: " + isValid); + log.debug("Validation detail: " + detail); + log.debug("Validation code: " + code); + + int users = + jsonResponse + .path("data") + .path("attributes") + .path("metadata") + .path("users") + .asInt(0); + applicationProperties.getEnterpriseEdition().setMaxUsers(users); + log.info(applicationProperties.toString()); + + } else { + log.error("Error validating license. Status code: " + response.statusCode()); + } + return jsonResponse; + } + + private boolean activateMachine(String licenseKey, String licenseId, String machineFingerprint) + throws Exception { + HttpClient client = HttpClient.newHttpClient(); + + String hostname; + try { + hostname = java.net.InetAddress.getLocalHost().getHostName(); + } catch (Exception e) { + hostname = "Unknown"; + } + + JSONObject body = + new JSONObject() + .put( + "data", + new JSONObject() + .put("type", "machines") + .put( + "attributes", + new JSONObject() + .put("fingerprint", machineFingerprint) + .put( + "platform", + System.getProperty( + "os.name")) // Added + // platform + // parameter + .put( + "name", + hostname)) // Added name parameter + .put( + "relationships", + new JSONObject() + .put( + "license", + new JSONObject() + .put( + "data", + new JSONObject() + .put( + "type", + "licenses") + .put( + "id", + licenseId))))); + + HttpRequest request = + HttpRequest.newBuilder() + .uri(URI.create(BASE_URL + "/" + ACCOUNT_ID + "/machines")) + .header("Content-Type", "application/vnd.api+json") + .header("Accept", "application/vnd.api+json") + .header( + "Authorization", + "License " + licenseKey) // Keep the license key authentication + .POST( + HttpRequest.BodyPublishers.ofString( + body.toString())) // Send the JSON body + .build(); + + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); + log.debug("activateMachine Response body: " + response.body()); + if (response.statusCode() == 201) { + log.info("Machine activated successfully"); + return true; + } else { + log.error( + "Error activating machine. Status code: {}, error: {}", + response.statusCode(), + response.body()); + + return false; + } + } + + private String generateMachineFingerprint() { + return GeneralUtils.generateMachineFingerprint(); + } +} diff --git a/src/main/java/stirling/software/SPDF/EE/LicenseKeyChecker.java b/src/main/java/stirling/software/SPDF/EE/LicenseKeyChecker.java new file mode 100644 index 00000000..3da7da05 --- /dev/null +++ b/src/main/java/stirling/software/SPDF/EE/LicenseKeyChecker.java @@ -0,0 +1,59 @@ +package stirling.software.SPDF.EE; + +import java.io.IOException; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import lombok.extern.slf4j.Slf4j; +import stirling.software.SPDF.model.ApplicationProperties; +import stirling.software.SPDF.utils.GeneralUtils; + +@Component +@Slf4j +public class LicenseKeyChecker { + + private final KeygenLicenseVerifier licenseService; + + private final ApplicationProperties applicationProperties; + + private boolean enterpriseEnbaledResult = false; + + @Autowired + public LicenseKeyChecker( + KeygenLicenseVerifier licenseService, ApplicationProperties applicationProperties) { + this.licenseService = licenseService; + this.applicationProperties = applicationProperties; + } + + @Scheduled(fixedRate = 604800000, initialDelay = 1000) // 7 days in milliseconds + public void checkLicensePeriodically() { + checkLicense(); + } + + private void checkLicense() { + if (!applicationProperties.getEnterpriseEdition().isEnabled()) { + enterpriseEnbaledResult = false; + } else { + enterpriseEnbaledResult = + licenseService.verifyLicense( + applicationProperties.getEnterpriseEdition().getKey()); + if (enterpriseEnbaledResult) { + log.info("License key is valid."); + } else { + log.info("License key is invalid."); + } + } + } + + public void updateLicenseKey(String newKey) throws IOException { + applicationProperties.getEnterpriseEdition().setKey(newKey); + GeneralUtils.saveKeyToConfig("EnterpriseEdition.key", newKey, false); + checkLicense(); + } + + public boolean getEnterpriseEnabledResult() { + return enterpriseEnbaledResult; + } +} diff --git a/src/main/java/stirling/software/SPDF/LibreOfficeListener.java b/src/main/java/stirling/software/SPDF/LibreOfficeListener.java index 06e19512..549a0092 100644 --- a/src/main/java/stirling/software/SPDF/LibreOfficeListener.java +++ b/src/main/java/stirling/software/SPDF/LibreOfficeListener.java @@ -11,6 +11,9 @@ import org.slf4j.LoggerFactory; import io.github.pixee.security.SystemCommand; +import lombok.extern.slf4j.Slf4j; + +@Slf4j public class LibreOfficeListener { private static final Logger logger = LoggerFactory.getLogger(LibreOfficeListener.class); @@ -31,7 +34,7 @@ public class LibreOfficeListener { private LibreOfficeListener() {} private boolean isListenerRunning() { - System.out.println("waiting for listener to start"); + log.info("waiting for listener to start"); try (Socket socket = new Socket()) { socket.connect( new InetSocketAddress("localhost", 2002), 1000); // Timeout after 1 second diff --git a/src/main/java/stirling/software/SPDF/config/AppConfig.java b/src/main/java/stirling/software/SPDF/config/AppConfig.java index 6fc09917..3391a50f 100644 --- a/src/main/java/stirling/software/SPDF/config/AppConfig.java +++ b/src/main/java/stirling/software/SPDF/config/AppConfig.java @@ -160,4 +160,27 @@ public class AppConfig { public String accessibilityStatement() { return applicationProperties.getLegal().getAccessibilityStatement(); } + + @Bean(name = "analyticsPrompt") + public boolean analyticsPrompt() { + return applicationProperties.getSystem().getEnableAnalytics() == null + || "undefined".equals(applicationProperties.getSystem().getEnableAnalytics()); + } + + @Bean(name = "analyticsEnabled") + public boolean analyticsEnabled() { + if (applicationProperties.getEnterpriseEdition().isEnabled()) return true; + return applicationProperties.getSystem().getEnableAnalytics() != null + && Boolean.parseBoolean(applicationProperties.getSystem().getEnableAnalytics()); + } + + @Bean(name = "StirlingPDFLabel") + public String stirlingPDFLabel() { + return "Stirling-PDF" + " v" + appVersion(); + } + + @Bean(name = "UUID") + public String uuid() { + return applicationProperties.getAutomaticallyGenerated().getUUID(); + } } diff --git a/src/main/java/stirling/software/SPDF/config/AppUpdateService.java b/src/main/java/stirling/software/SPDF/config/AppUpdateService.java index 7fc87629..3eb20488 100644 --- a/src/main/java/stirling/software/SPDF/config/AppUpdateService.java +++ b/src/main/java/stirling/software/SPDF/config/AppUpdateService.java @@ -5,6 +5,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Service; +import stirling.software.SPDF.config.interfaces.ShowAdminInterface; import stirling.software.SPDF.model.ApplicationProperties; @Service diff --git a/src/main/java/stirling/software/SPDF/config/InitialSetup.java b/src/main/java/stirling/software/SPDF/config/InitialSetup.java new file mode 100644 index 00000000..043b08c9 --- /dev/null +++ b/src/main/java/stirling/software/SPDF/config/InitialSetup.java @@ -0,0 +1,42 @@ +package stirling.software.SPDF.config; + +import java.io.IOException; +import java.util.UUID; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import jakarta.annotation.PostConstruct; +import lombok.extern.slf4j.Slf4j; +import stirling.software.SPDF.model.ApplicationProperties; +import stirling.software.SPDF.utils.GeneralUtils; + +@Component +@Slf4j +@Order(Ordered.HIGHEST_PRECEDENCE + 1) +public class InitialSetup { + + @Autowired private ApplicationProperties applicationProperties; + + @PostConstruct + public void initUUIDKey() throws IOException { + String uuid = applicationProperties.getAutomaticallyGenerated().getUUID(); + if (!GeneralUtils.isValidUUID(uuid)) { + uuid = UUID.randomUUID().toString(); // Generating a random UUID as the secret key + GeneralUtils.saveKeyToConfig("AutomaticallyGenerated.UUID", uuid); + applicationProperties.getAutomaticallyGenerated().setUUID(uuid); + } + } + + @PostConstruct + public void initSecretKey() throws IOException { + String secretKey = applicationProperties.getAutomaticallyGenerated().getKey(); + if (!GeneralUtils.isValidUUID(secretKey)) { + secretKey = UUID.randomUUID().toString(); // Generating a random UUID as the secret key + GeneralUtils.saveKeyToConfig("AutomaticallyGenerated.key", secretKey); + applicationProperties.getAutomaticallyGenerated().setKey(secretKey); + } + } +} diff --git a/src/main/java/stirling/software/SPDF/config/Beans.java b/src/main/java/stirling/software/SPDF/config/LocaleConfiguration.java similarity index 97% rename from src/main/java/stirling/software/SPDF/config/Beans.java rename to src/main/java/stirling/software/SPDF/config/LocaleConfiguration.java index 03084b24..a15d6c16 100644 --- a/src/main/java/stirling/software/SPDF/config/Beans.java +++ b/src/main/java/stirling/software/SPDF/config/LocaleConfiguration.java @@ -14,7 +14,7 @@ import org.springframework.web.servlet.i18n.SessionLocaleResolver; import stirling.software.SPDF.model.ApplicationProperties; @Configuration -public class Beans implements WebMvcConfigurer { +public class LocaleConfiguration implements WebMvcConfigurer { @Autowired ApplicationProperties applicationProperties; diff --git a/src/main/java/stirling/software/SPDF/config/MetricsFilter.java b/src/main/java/stirling/software/SPDF/config/MetricsFilter.java index c0231ca7..fba1ee9c 100644 --- a/src/main/java/stirling/software/SPDF/config/MetricsFilter.java +++ b/src/main/java/stirling/software/SPDF/config/MetricsFilter.java @@ -13,6 +13,7 @@ import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpSession; import stirling.software.SPDF.utils.RequestUriUtils; @Component @@ -32,10 +33,11 @@ public class MetricsFilter extends OncePerRequestFilter { String uri = request.getRequestURI(); if (RequestUriUtils.isTrackableResource(request.getContextPath(), uri)) { - + HttpSession session = request.getSession(false); + String sessionId = (session != null) ? session.getId() : "no-session"; Counter counter = Counter.builder("http.requests") - .tag("session", request.getSession().getId()) + .tag("session", sessionId) .tag("method", request.getMethod()) .tag("uri", uri) .register(meterRegistry); diff --git a/src/main/java/stirling/software/SPDF/config/PostHogConfig.java b/src/main/java/stirling/software/SPDF/config/PostHogConfig.java new file mode 100644 index 00000000..42d5b101 --- /dev/null +++ b/src/main/java/stirling/software/SPDF/config/PostHogConfig.java @@ -0,0 +1,34 @@ +package stirling.software.SPDF.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import com.posthog.java.PostHog; + +import jakarta.annotation.PreDestroy; + +@Configuration +public class PostHogConfig { + + @Value("${posthog.api.key}") + private String posthogApiKey; + + @Value("${posthog.host}") + private String posthogHost; + + private PostHog postHogClient; + + @Bean + public PostHog postHogClient() { + postHogClient = new PostHog.Builder(posthogApiKey).host(posthogHost).build(); + return postHogClient; + } + + @PreDestroy + public void shutdownPostHog() { + if (postHogClient != null) { + postHogClient.shutdown(); + } + } +} diff --git a/src/main/java/stirling/software/SPDF/config/fingerprint/FingerprintBasedSessionFilter.java b/src/main/java/stirling/software/SPDF/config/fingerprint/FingerprintBasedSessionFilter.java new file mode 100644 index 00000000..3815b95b --- /dev/null +++ b/src/main/java/stirling/software/SPDF/config/fingerprint/FingerprintBasedSessionFilter.java @@ -0,0 +1,68 @@ +// package stirling.software.SPDF.config.fingerprint; +// +// import java.io.IOException; +// +// import org.springframework.beans.factory.annotation.Autowired; +// import org.springframework.stereotype.Component; +// import org.springframework.web.filter.OncePerRequestFilter; +// +// import jakarta.servlet.FilterChain; +// import jakarta.servlet.ServletException; +// import jakarta.servlet.http.HttpServletRequest; +// import jakarta.servlet.http.HttpServletResponse; +// import jakarta.servlet.http.HttpSession; +// import lombok.extern.slf4j.Slf4j; +// import stirling.software.SPDF.utils.RequestUriUtils; +// +//// @Component +// @Slf4j +// public class FingerprintBasedSessionFilter extends OncePerRequestFilter { +// private final FingerprintGenerator fingerprintGenerator; +// private final FingerprintBasedSessionManager sessionManager; +// +// @Autowired +// public FingerprintBasedSessionFilter( +// FingerprintGenerator fingerprintGenerator, +// FingerprintBasedSessionManager sessionManager) { +// this.fingerprintGenerator = fingerprintGenerator; +// this.sessionManager = sessionManager; +// } +// +// @Override +// protected void doFilterInternal( +// HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) +// throws ServletException, IOException { +// +// if (RequestUriUtils.isStaticResource(request.getContextPath(), request.getRequestURI())) { +// filterChain.doFilter(request, response); +// return; +// } +// +// String fingerprint = fingerprintGenerator.generateFingerprint(request); +// log.debug("Generated fingerprint for request: {}", fingerprint); +// +// HttpSession session = request.getSession(); +// boolean isNewSession = session.isNew(); +// String sessionId = session.getId(); +// +// if (isNewSession) { +// log.info("New session created: {}", sessionId); +// } +// +// if (!sessionManager.isFingerPrintAllowed(fingerprint)) { +// log.info("Blocked fingerprint detected, redirecting: {}", fingerprint); +// response.sendRedirect(request.getContextPath() + "/too-many-requests"); +// return; +// } +// +// session.setAttribute("userFingerprint", fingerprint); +// session.setAttribute( +// FingerprintBasedSessionManager.STARTUP_TIMESTAMP, +// FingerprintBasedSessionManager.APP_STARTUP_TIME); +// +// sessionManager.registerFingerprint(fingerprint, sessionId); +// +// log.debug("Proceeding with request: {}", request.getRequestURI()); +// filterChain.doFilter(request, response); +// } +// } diff --git a/src/main/java/stirling/software/SPDF/config/fingerprint/FingerprintBasedSessionManager.java b/src/main/java/stirling/software/SPDF/config/fingerprint/FingerprintBasedSessionManager.java new file mode 100644 index 00000000..3854f62b --- /dev/null +++ b/src/main/java/stirling/software/SPDF/config/fingerprint/FingerprintBasedSessionManager.java @@ -0,0 +1,134 @@ +// package stirling.software.SPDF.config.fingerprint; +// +// import java.util.Iterator; +// import java.util.Map; +// import java.util.concurrent.ConcurrentHashMap; +// import java.util.concurrent.TimeUnit; +// +// import org.springframework.scheduling.annotation.Scheduled; +// import org.springframework.stereotype.Component; +// +// import jakarta.servlet.http.HttpSession; +// import jakarta.servlet.http.HttpSessionAttributeListener; +// import jakarta.servlet.http.HttpSessionEvent; +// import jakarta.servlet.http.HttpSessionListener; +// import lombok.AllArgsConstructor; +// import lombok.Data; +// import lombok.extern.slf4j.Slf4j; +// +// @Slf4j +// @Component +// public class FingerprintBasedSessionManager +// implements HttpSessionListener, HttpSessionAttributeListener { +// private static final ConcurrentHashMap activeFingerprints = +// new ConcurrentHashMap<>(); +// +// // To be reduced in later version to 8~ +// private static final int MAX_ACTIVE_FINGERPRINTS = 30; +// +// static final String STARTUP_TIMESTAMP = "appStartupTimestamp"; +// static final long APP_STARTUP_TIME = System.currentTimeMillis(); +// private static final long FINGERPRINT_EXPIRATION = TimeUnit.MINUTES.toMillis(30); +// +// @Override +// public void sessionCreated(HttpSessionEvent se) { +// HttpSession session = se.getSession(); +// String sessionId = session.getId(); +// String fingerprint = (String) session.getAttribute("userFingerprint"); +// +// if (fingerprint == null) { +// log.warn("Session created without fingerprint: {}", sessionId); +// return; +// } +// +// synchronized (activeFingerprints) { +// if (activeFingerprints.size() >= MAX_ACTIVE_FINGERPRINTS +// && !activeFingerprints.containsKey(fingerprint)) { +// log.info("Max fingerprints reached. Marking session as blocked: {}", sessionId); +// session.setAttribute("blocked", true); +// } else { +// activeFingerprints.put( +// fingerprint, new FingerprintInfo(sessionId, System.currentTimeMillis())); +// log.info( +// "New fingerprint registered: {}. Total active fingerprints: {}", +// fingerprint, +// activeFingerprints.size()); +// } +// session.setAttribute(STARTUP_TIMESTAMP, APP_STARTUP_TIME); +// } +// } +// +// @Override +// public void sessionDestroyed(HttpSessionEvent se) { +// HttpSession session = se.getSession(); +// String fingerprint = (String) session.getAttribute("userFingerprint"); +// +// if (fingerprint != null) { +// synchronized (activeFingerprints) { +// activeFingerprints.remove(fingerprint); +// log.info( +// "Fingerprint removed: {}. Total active fingerprints: {}", +// fingerprint, +// activeFingerprints.size()); +// } +// } +// } +// +// public boolean isFingerPrintAllowed(String fingerprint) { +// synchronized (activeFingerprints) { +// return activeFingerprints.size() < MAX_ACTIVE_FINGERPRINTS +// || activeFingerprints.containsKey(fingerprint); +// } +// } +// +// public void registerFingerprint(String fingerprint, String sessionId) { +// synchronized (activeFingerprints) { +// activeFingerprints.put( +// fingerprint, new FingerprintInfo(sessionId, System.currentTimeMillis())); +// } +// } +// +// public void unregisterFingerprint(String fingerprint) { +// synchronized (activeFingerprints) { +// activeFingerprints.remove(fingerprint); +// } +// } +// +// @Scheduled(fixedRate = 1800000) // Run every 30 mins +// public void cleanupStaleFingerprints() { +// log.info("Starting cleanup of stale fingerprints"); +// long now = System.currentTimeMillis(); +// int removedCount = 0; +// +// synchronized (activeFingerprints) { +// Iterator> iterator = +// activeFingerprints.entrySet().iterator(); +// while (iterator.hasNext()) { +// Map.Entry entry = iterator.next(); +// FingerprintInfo info = entry.getValue(); +// +// if (now - info.getLastAccessTime() > FINGERPRINT_EXPIRATION) { +// iterator.remove(); +// removedCount++; +// log.info("Removed stale fingerprint: {}", entry.getKey()); +// } +// } +// } +// +// log.info("Cleanup complete. Removed {} stale fingerprints", removedCount); +// } +// +// public void updateLastAccessTime(String fingerprint) { +// FingerprintInfo info = activeFingerprints.get(fingerprint); +// if (info != null) { +// info.setLastAccessTime(System.currentTimeMillis()); +// } +// } +// +// @Data +// @AllArgsConstructor +// private static class FingerprintInfo { +// private String sessionId; +// private long lastAccessTime; +// } +// } diff --git a/src/main/java/stirling/software/SPDF/config/fingerprint/FingerprintGenerator.java b/src/main/java/stirling/software/SPDF/config/fingerprint/FingerprintGenerator.java new file mode 100644 index 00000000..f1a65cf8 --- /dev/null +++ b/src/main/java/stirling/software/SPDF/config/fingerprint/FingerprintGenerator.java @@ -0,0 +1,77 @@ +// package stirling.software.SPDF.config.fingerprint; +// +// import java.security.MessageDigest; +// import java.security.NoSuchAlgorithmException; +// +// import org.springframework.stereotype.Component; +// +// import jakarta.servlet.http.HttpServletRequest; +// +// @Component +// public class FingerprintGenerator { +// +// public String generateFingerprint(HttpServletRequest request) { +// if (request == null) { +// return ""; +// } +// StringBuilder fingerprintBuilder = new StringBuilder(); +// +// // Add IP address +// fingerprintBuilder.append(request.getRemoteAddr()); +// +// // Add X-Forwarded-For header if present (for clients behind proxies) +// String forwardedFor = request.getHeader("X-Forwarded-For"); +// if (forwardedFor != null) { +// fingerprintBuilder.append(forwardedFor); +// } +// +// // Add User-Agent +// String userAgent = request.getHeader("User-Agent"); +// if (userAgent != null) { +// fingerprintBuilder.append(userAgent); +// } +// +// // Add Accept-Language header +// String acceptLanguage = request.getHeader("Accept-Language"); +// if (acceptLanguage != null) { +// fingerprintBuilder.append(acceptLanguage); +// } +// +// // Add Accept header +// String accept = request.getHeader("Accept"); +// if (accept != null) { +// fingerprintBuilder.append(accept); +// } +// +// // Add Connection header +// String connection = request.getHeader("Connection"); +// if (connection != null) { +// fingerprintBuilder.append(connection); +// } +// +// // Add server port +// fingerprintBuilder.append(request.getServerPort()); +// +// // Add secure flag +// fingerprintBuilder.append(request.isSecure()); +// +// // Generate a hash of the fingerprint +// return generateHash(fingerprintBuilder.toString()); +// } +// +// private String generateHash(String input) { +// try { +// MessageDigest digest = MessageDigest.getInstance("SHA-256"); +// byte[] hash = digest.digest(input.getBytes()); +// StringBuilder hexString = new StringBuilder(); +// for (byte b : hash) { +// String hex = Integer.toHexString(0xff & b); +// if (hex.length() == 1) hexString.append('0'); +// hexString.append(hex); +// } +// return hexString.toString(); +// } catch (NoSuchAlgorithmException e) { +// throw new RuntimeException("Failed to generate fingerprint hash", e); +// } +// } +// } diff --git a/src/main/java/stirling/software/SPDF/config/DatabaseBackupInterface.java b/src/main/java/stirling/software/SPDF/config/interfaces/DatabaseBackupInterface.java similarity index 85% rename from src/main/java/stirling/software/SPDF/config/DatabaseBackupInterface.java rename to src/main/java/stirling/software/SPDF/config/interfaces/DatabaseBackupInterface.java index 267981d1..3ad11f2a 100644 --- a/src/main/java/stirling/software/SPDF/config/DatabaseBackupInterface.java +++ b/src/main/java/stirling/software/SPDF/config/interfaces/DatabaseBackupInterface.java @@ -1,4 +1,4 @@ -package stirling.software.SPDF.config; +package stirling.software.SPDF.config.interfaces; import java.io.IOException; import java.util.List; diff --git a/src/main/java/stirling/software/SPDF/config/ShowAdminInterface.java b/src/main/java/stirling/software/SPDF/config/interfaces/ShowAdminInterface.java similarity index 69% rename from src/main/java/stirling/software/SPDF/config/ShowAdminInterface.java rename to src/main/java/stirling/software/SPDF/config/interfaces/ShowAdminInterface.java index e49376e2..1bbebf5a 100644 --- a/src/main/java/stirling/software/SPDF/config/ShowAdminInterface.java +++ b/src/main/java/stirling/software/SPDF/config/interfaces/ShowAdminInterface.java @@ -1,4 +1,4 @@ -package stirling.software.SPDF.config; +package stirling.software.SPDF.config.interfaces; public interface ShowAdminInterface { default boolean getShowUpdateOnlyAdmins() { diff --git a/src/main/java/stirling/software/SPDF/config/security/AppUpdateAuthService.java b/src/main/java/stirling/software/SPDF/config/security/AppUpdateAuthService.java index 5a16aa30..57ce7b7d 100644 --- a/src/main/java/stirling/software/SPDF/config/security/AppUpdateAuthService.java +++ b/src/main/java/stirling/software/SPDF/config/security/AppUpdateAuthService.java @@ -7,7 +7,7 @@ import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Service; -import stirling.software.SPDF.config.ShowAdminInterface; +import stirling.software.SPDF.config.interfaces.ShowAdminInterface; import stirling.software.SPDF.model.ApplicationProperties; import stirling.software.SPDF.model.User; import stirling.software.SPDF.repository.UserRepository; diff --git a/src/main/java/stirling/software/SPDF/config/security/FirstLoginFilter.java b/src/main/java/stirling/software/SPDF/config/security/FirstLoginFilter.java index 86afa028..babba64d 100644 --- a/src/main/java/stirling/software/SPDF/config/security/FirstLoginFilter.java +++ b/src/main/java/stirling/software/SPDF/config/security/FirstLoginFilter.java @@ -1,6 +1,8 @@ package stirling.software.SPDF.config.security; import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.Date; import java.util.Optional; import org.springframework.beans.factory.annotation.Autowired; @@ -14,9 +16,12 @@ import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpSession; +import lombok.extern.slf4j.Slf4j; import stirling.software.SPDF.model.User; import stirling.software.SPDF.utils.RequestUriUtils; +@Slf4j @Component public class FirstLoginFilter extends OncePerRequestFilter { @@ -50,6 +55,22 @@ public class FirstLoginFilter extends OncePerRequestFilter { return; } } + + if (log.isDebugEnabled()) { + HttpSession session = request.getSession(true); + SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm:ss"); + String creationTime = timeFormat.format(new Date(session.getCreationTime())); + + log.debug( + "Request Info - New: {}, creationTimeSession {}, ID: {}, IP: {}, User-Agent: {}, Referer: {}, Request URL: {}", + session.isNew(), + creationTime, + session.getId(), + request.getRemoteAddr(), + request.getHeader("User-Agent"), + request.getHeader("Referer"), + request.getRequestURL().toString()); + } filterChain.doFilter(request, response); } } diff --git a/src/main/java/stirling/software/SPDF/config/security/InitialSecuritySetup.java b/src/main/java/stirling/software/SPDF/config/security/InitialSecuritySetup.java index b7442c5b..f43baf0a 100644 --- a/src/main/java/stirling/software/SPDF/config/security/InitialSecuritySetup.java +++ b/src/main/java/stirling/software/SPDF/config/security/InitialSecuritySetup.java @@ -1,19 +1,14 @@ package stirling.software.SPDF.config.security; import java.io.IOException; -import java.nio.file.Path; -import java.nio.file.Paths; import java.util.UUID; -import org.simpleyaml.configuration.file.YamlFile; -import org.simpleyaml.configuration.implementation.SimpleYamlImplementation; -import org.simpleyaml.configuration.implementation.snakeyaml.lib.DumperOptions; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import jakarta.annotation.PostConstruct; import lombok.extern.slf4j.Slf4j; -import stirling.software.SPDF.config.DatabaseBackupInterface; +import stirling.software.SPDF.config.interfaces.DatabaseBackupInterface; import stirling.software.SPDF.model.ApplicationProperties; import stirling.software.SPDF.model.Role; @@ -39,15 +34,6 @@ public class InitialSecuritySetup { initializeInternalApiUser(); } - @PostConstruct - public void initSecretKey() throws IOException { - String secretKey = applicationProperties.getAutomaticallyGenerated().getKey(); - if (!isValidUUID(secretKey)) { - secretKey = UUID.randomUUID().toString(); // Generating a random UUID as the secret key - saveKeyToConfig(secretKey); - } - } - private void initializeAdminUser() throws IOException { String initialUsername = applicationProperties.getSecurity().getInitialLogin().getUsername(); @@ -89,33 +75,4 @@ public class InitialSecuritySetup { log.info("Internal API user created: " + Role.INTERNAL_API_USER.getRoleId()); } } - - private void saveKeyToConfig(String key) throws IOException { - Path path = Paths.get("configs", "settings.yml"); // Target the configs/settings.yml - - final YamlFile settingsYml = new YamlFile(path.toFile()); - DumperOptions yamlOptionssettingsYml = - ((SimpleYamlImplementation) settingsYml.getImplementation()).getDumperOptions(); - yamlOptionssettingsYml.setSplitLines(false); - - settingsYml.loadWithComments(); - - settingsYml - .path("AutomaticallyGenerated.key") - .set(key) - .comment("# Automatically Generated Settings (Do Not Edit Directly)"); - settingsYml.save(); - } - - private boolean isValidUUID(String uuid) { - if (uuid == null) { - return false; - } - try { - UUID.fromString(uuid); - return true; - } catch (IllegalArgumentException e) { - return false; - } - } } diff --git a/src/main/java/stirling/software/SPDF/config/security/SecurityConfiguration.java b/src/main/java/stirling/software/SPDF/config/security/SecurityConfiguration.java index aa266d2f..79e40e2b 100644 --- a/src/main/java/stirling/software/SPDF/config/security/SecurityConfiguration.java +++ b/src/main/java/stirling/software/SPDF/config/security/SecurityConfiguration.java @@ -1,57 +1,55 @@ package stirling.software.SPDF.config.security; -import java.util.*; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Lazy; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.AuthenticationProvider; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.http.SessionCreationPolicy; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.security.oauth2.client.registration.ClientRegistration; -import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; -import org.springframework.security.oauth2.client.registration.ClientRegistrations; -import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository; -import org.springframework.security.oauth2.core.user.OAuth2UserAuthority; +import org.springframework.security.saml2.provider.service.authentication.OpenSaml4AuthenticationProvider; +import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository; +import org.springframework.security.saml2.provider.service.web.authentication.Saml2WebSsoAuthenticationFilter; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository; import org.springframework.security.web.savedrequest.NullRequestCache; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; +import lombok.extern.slf4j.Slf4j; import stirling.software.SPDF.config.security.oauth2.CustomOAuth2AuthenticationFailureHandler; import stirling.software.SPDF.config.security.oauth2.CustomOAuth2AuthenticationSuccessHandler; import stirling.software.SPDF.config.security.oauth2.CustomOAuth2LogoutSuccessHandler; import stirling.software.SPDF.config.security.oauth2.CustomOAuth2UserService; +import stirling.software.SPDF.config.security.saml.ConvertResponseToAuthentication; +import stirling.software.SPDF.config.security.saml.CustomSAMLAuthenticationFailureHandler; +import stirling.software.SPDF.config.security.saml.CustomSAMLAuthenticationSuccessHandler; import stirling.software.SPDF.config.security.session.SessionPersistentRegistry; import stirling.software.SPDF.model.ApplicationProperties; -import stirling.software.SPDF.model.ApplicationProperties.Security.OAUTH2; -import stirling.software.SPDF.model.ApplicationProperties.Security.OAUTH2.Client; -import stirling.software.SPDF.model.User; -import stirling.software.SPDF.model.provider.GithubProvider; -import stirling.software.SPDF.model.provider.GoogleProvider; -import stirling.software.SPDF.model.provider.KeycloakProvider; import stirling.software.SPDF.repository.JPATokenRepositoryImpl; @Configuration @EnableWebSecurity @EnableMethodSecurity +@Slf4j public class SecurityConfiguration { @Autowired private CustomUserDetailsService userDetailsService; - private static final Logger logger = LoggerFactory.getLogger(SecurityConfiguration.class); + @Autowired(required = false) + private GrantedAuthoritiesMapper userAuthoritiesMapper; + + @Autowired(required = false) + private RelyingPartyRegistrationRepository relyingPartyRegistrationRepository; @Bean public PasswordEncoder passwordEncoder() { @@ -73,13 +71,18 @@ public class SecurityConfiguration { @Autowired private FirstLoginFilter firstLoginFilter; @Autowired private SessionPersistentRegistry sessionRegistry; + @Autowired private ConvertResponseToAuthentication convertResponseToAuthentication; + @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - http.addFilterBefore(userAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); + http.authenticationManager(authenticationManager(http)); if (loginEnabledValue) { - - http.csrf(csrf -> csrf.disable()); + http.addFilterBefore( + userAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); + if (applicationProperties.getSecurity().getCsrfDisabled()) { + http.csrf(csrf -> csrf.disable()); + } http.addFilterBefore(rateLimitingFilter(), UsernamePasswordAuthenticationFilter.class); http.addFilterAfter(firstLoginFilter, UsernamePasswordAuthenticationFilter.class); http.sessionManagement( @@ -135,6 +138,7 @@ public class SecurityConfiguration { return trimmedUri.startsWith("/login") || trimmedUri.startsWith("/oauth") + || trimmedUri.startsWith("/saml2") || trimmedUri.endsWith(".svg") || trimmedUri.startsWith( "/register") @@ -184,191 +188,82 @@ public class SecurityConfiguration { userService, loginAttemptService)) .userAuthoritiesMapper( - userAuthoritiesMapper()))) + userAuthoritiesMapper))) .logout( logout -> logout.logoutSuccessHandler( new CustomOAuth2LogoutSuccessHandler( applicationProperties))); } + + // Handle SAML + if (applicationProperties.getSecurity().getSaml() != null + && applicationProperties.getSecurity().getSaml().getEnabled() + && !applicationProperties + .getSecurity() + .getLoginMethod() + .equalsIgnoreCase("normal")) { + http.saml2Login( + saml2 -> { + saml2.loginPage("/saml2") + .relyingPartyRegistrationRepository( + relyingPartyRegistrationRepository) + .successHandler( + new CustomSAMLAuthenticationSuccessHandler( + loginAttemptService, + userService, + applicationProperties)) + .failureHandler( + new CustomSAMLAuthenticationFailureHandler()); + }) + .addFilterBefore( + userAuthenticationFilter, Saml2WebSsoAuthenticationFilter.class); + } } else { - http.csrf(csrf -> csrf.disable()) - .authorizeHttpRequests(authz -> authz.anyRequest().permitAll()); + if (applicationProperties.getSecurity().getCsrfDisabled()) { + http.csrf(csrf -> csrf.disable()); + } + http.authorizeHttpRequests(authz -> authz.anyRequest().permitAll()); } return http.build(); } - // Client Registration Repository for OAUTH2 OIDC Login @Bean @ConditionalOnProperty( - value = "security.oauth2.enabled", + name = "security.saml.enabled", havingValue = "true", matchIfMissing = false) - public ClientRegistrationRepository clientRegistrationRepository() { - List registrations = new ArrayList<>(); - - githubClientRegistration().ifPresent(registrations::add); - oidcClientRegistration().ifPresent(registrations::add); - googleClientRegistration().ifPresent(registrations::add); - keycloakClientRegistration().ifPresent(registrations::add); - - if (registrations.isEmpty()) { - logger.error("At least one OAuth2 provider must be configured"); - System.exit(1); - } - - return new InMemoryClientRegistrationRepository(registrations); + public AuthenticationProvider samlAuthenticationProvider() { + OpenSaml4AuthenticationProvider authenticationProvider = + new OpenSaml4AuthenticationProvider(); + authenticationProvider.setResponseAuthenticationConverter(convertResponseToAuthentication); + return authenticationProvider; } - private Optional googleClientRegistration() { - OAUTH2 oauth = applicationProperties.getSecurity().getOauth2(); - if (oauth == null || !oauth.getEnabled()) { - return Optional.empty(); - } - Client client = oauth.getClient(); - if (client == null) { - return Optional.empty(); - } - GoogleProvider google = client.getGoogle(); - return google != null && google.isSettingsValid() - ? Optional.of( - ClientRegistration.withRegistrationId(google.getName()) - .clientId(google.getClientId()) - .clientSecret(google.getClientSecret()) - .scope(google.getScopes()) - .authorizationUri(google.getAuthorizationuri()) - .tokenUri(google.getTokenuri()) - .userInfoUri(google.getUserinfouri()) - .userNameAttributeName(google.getUseAsUsername()) - .clientName(google.getClientName()) - .redirectUri("{baseUrl}/login/oauth2/code/" + google.getName()) - .authorizationGrantType( - org.springframework.security.oauth2.core - .AuthorizationGrantType.AUTHORIZATION_CODE) - .build()) - : Optional.empty(); - } + // @Bean + // public AuthenticationProvider daoAuthenticationProvider() { + // DaoAuthenticationProvider provider = new DaoAuthenticationProvider(); + // provider.setUserDetailsService(userDetailsService); // UserDetailsService + // provider.setPasswordEncoder(passwordEncoder()); // PasswordEncoder + // return provider; + // } - private Optional keycloakClientRegistration() { - OAUTH2 oauth = applicationProperties.getSecurity().getOauth2(); - if (oauth == null || !oauth.getEnabled()) { - return Optional.empty(); - } - Client client = oauth.getClient(); - if (client == null) { - return Optional.empty(); - } - KeycloakProvider keycloak = client.getKeycloak(); - - return keycloak != null && keycloak.isSettingsValid() - ? Optional.of( - ClientRegistrations.fromIssuerLocation(keycloak.getIssuer()) - .registrationId(keycloak.getName()) - .clientId(keycloak.getClientId()) - .clientSecret(keycloak.getClientSecret()) - .scope(keycloak.getScopes()) - .userNameAttributeName(keycloak.getUseAsUsername()) - .clientName(keycloak.getClientName()) - .build()) - : Optional.empty(); - } - - private Optional githubClientRegistration() { - OAUTH2 oauth = applicationProperties.getSecurity().getOauth2(); - if (oauth == null || !oauth.getEnabled()) { - return Optional.empty(); - } - Client client = oauth.getClient(); - if (client == null) { - return Optional.empty(); - } - GithubProvider github = client.getGithub(); - return github != null && github.isSettingsValid() - ? Optional.of( - ClientRegistration.withRegistrationId(github.getName()) - .clientId(github.getClientId()) - .clientSecret(github.getClientSecret()) - .scope(github.getScopes()) - .authorizationUri(github.getAuthorizationuri()) - .tokenUri(github.getTokenuri()) - .userInfoUri(github.getUserinfouri()) - .userNameAttributeName(github.getUseAsUsername()) - .clientName(github.getClientName()) - .redirectUri("{baseUrl}/login/oauth2/code/" + github.getName()) - .authorizationGrantType( - org.springframework.security.oauth2.core - .AuthorizationGrantType.AUTHORIZATION_CODE) - .build()) - : Optional.empty(); - } - - private Optional oidcClientRegistration() { - OAUTH2 oauth = applicationProperties.getSecurity().getOauth2(); - if (oauth == null - || oauth.getIssuer() == null - || oauth.getIssuer().isEmpty() - || oauth.getClientId() == null - || oauth.getClientId().isEmpty() - || oauth.getClientSecret() == null - || oauth.getClientSecret().isEmpty() - || oauth.getScopes() == null - || oauth.getScopes().isEmpty() - || oauth.getUseAsUsername() == null - || oauth.getUseAsUsername().isEmpty()) { - return Optional.empty(); - } - return Optional.of( - ClientRegistrations.fromIssuerLocation(oauth.getIssuer()) - .registrationId("oidc") - .clientId(oauth.getClientId()) - .clientSecret(oauth.getClientSecret()) - .scope(oauth.getScopes()) - .userNameAttributeName(oauth.getUseAsUsername()) - .clientName("OIDC") - .build()); - } - - /* - This following function is to grant Authorities to the OAUTH2 user from the values stored in the database. - This is required for the internal; 'hasRole()' function to give out the correct role. - */ @Bean - @ConditionalOnProperty( - value = "security.oauth2.enabled", - havingValue = "true", - matchIfMissing = false) - GrantedAuthoritiesMapper userAuthoritiesMapper() { - return (authorities) -> { - Set mappedAuthorities = new HashSet<>(); + public AuthenticationManager authenticationManager(HttpSecurity http) throws Exception { + AuthenticationManagerBuilder authenticationManagerBuilder = + http.getSharedObject(AuthenticationManagerBuilder.class); - authorities.forEach( - authority -> { - // Add existing OAUTH2 Authorities - mappedAuthorities.add(new SimpleGrantedAuthority(authority.getAuthority())); + // authenticationManagerBuilder = + // authenticationManagerBuilder.authenticationProvider( + // daoAuthenticationProvider()); // Benutzername/Passwort - // Add Authorities from database for existing user, if user is present. - if (authority instanceof OAuth2UserAuthority oauth2Auth) { - String useAsUsername = - applicationProperties - .getSecurity() - .getOauth2() - .getUseAsUsername(); - Optional userOpt = - userService.findByUsernameIgnoreCase( - (String) oauth2Auth.getAttributes().get(useAsUsername)); - if (userOpt.isPresent()) { - User user = userOpt.get(); - if (user != null) { - mappedAuthorities.add( - new SimpleGrantedAuthority( - userService.findRole(user).getAuthority())); - } - } - } - }); - return mappedAuthorities; - }; + if (applicationProperties.getSecurity().getSaml() != null + && applicationProperties.getSecurity().getSaml().getEnabled()) { + authenticationManagerBuilder.authenticationProvider( + samlAuthenticationProvider()); // SAML + } + return authenticationManagerBuilder.build(); } @Bean @@ -386,4 +281,14 @@ public class SecurityConfiguration { public boolean activSecurity() { return true; } + + // // Only Dev test + // @Bean + // public WebSecurityCustomizer webSecurityCustomizer() { + // return (web) -> + // web.ignoring() + // .requestMatchers( + // "/css/**", "/images/**", "/js/**", "/**.svg", + // "/pdfjs-legacy/**"); + // } } diff --git a/src/main/java/stirling/software/SPDF/config/security/UserAuthenticationFilter.java b/src/main/java/stirling/software/SPDF/config/security/UserAuthenticationFilter.java index 79b28521..7b5bb47a 100644 --- a/src/main/java/stirling/software/SPDF/config/security/UserAuthenticationFilter.java +++ b/src/main/java/stirling/software/SPDF/config/security/UserAuthenticationFilter.java @@ -5,7 +5,6 @@ import java.util.List; import java.util.Optional; import java.util.stream.Collectors; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Lazy; import org.springframework.http.HttpStatus; @@ -30,13 +29,18 @@ import stirling.software.SPDF.model.User; @Component public class UserAuthenticationFilter extends OncePerRequestFilter { - @Autowired @Lazy private UserService userService; + private final UserService userService; + private final SessionPersistentRegistry sessionPersistentRegistry; + private final boolean loginEnabledValue; - @Autowired private SessionPersistentRegistry sessionPersistentRegistry; - - @Autowired - @Qualifier("loginEnabled") - public boolean loginEnabledValue; + public UserAuthenticationFilter( + @Lazy UserService userService, + SessionPersistentRegistry sessionPersistentRegistry, + @Qualifier("loginEnabled") boolean loginEnabledValue) { + this.userService = userService; + this.sessionPersistentRegistry = sessionPersistentRegistry; + this.loginEnabledValue = loginEnabledValue; + } @Override protected void doFilterInternal( @@ -51,6 +55,19 @@ public class UserAuthenticationFilter extends OncePerRequestFilter { String requestURI = request.getRequestURI(); Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + // Check for session expiration (unsure if needed) + // if (authentication != null && authentication.isAuthenticated()) { + // String sessionId = request.getSession().getId(); + // SessionInformation sessionInfo = + // sessionPersistentRegistry.getSessionInformation(sessionId); + // + // if (sessionInfo != null && sessionInfo.isExpired()) { + // SecurityContextHolder.clearContext(); + // response.sendRedirect(request.getContextPath() + "/login?expired=true"); + // return; + // } + // } + // Check for API key in the request headers if no authentication exists if (authentication == null || !authentication.isAuthenticated()) { String apiKey = request.getHeader("X-API-Key"); diff --git a/src/main/java/stirling/software/SPDF/config/security/UserService.java b/src/main/java/stirling/software/SPDF/config/security/UserService.java index ece81355..27e0baa2 100644 --- a/src/main/java/stirling/software/SPDF/config/security/UserService.java +++ b/src/main/java/stirling/software/SPDF/config/security/UserService.java @@ -19,7 +19,7 @@ import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.oauth2.core.user.OAuth2User; import org.springframework.stereotype.Service; -import stirling.software.SPDF.config.DatabaseBackupInterface; +import stirling.software.SPDF.config.interfaces.DatabaseBackupInterface; import stirling.software.SPDF.config.security.session.SessionPersistentRegistry; import stirling.software.SPDF.controller.api.pipeline.UserServiceInterface; import stirling.software.SPDF.model.AuthenticationType; @@ -44,6 +44,10 @@ public class UserService implements UserServiceInterface { @Autowired DatabaseBackupInterface databaseBackupHelper; + public long getTotalUserCount() { + return userRepository.count(); + } + // Handle OAUTH2 login and user auto creation. public boolean processOAuth2PostLogin(String username, boolean autoCreateUser) throws IllegalArgumentException, IOException { diff --git a/src/main/java/stirling/software/SPDF/config/security/database/DatabaseBackupHelper.java b/src/main/java/stirling/software/SPDF/config/security/database/DatabaseBackupHelper.java index 3fd7993f..6ccd0ac3 100644 --- a/src/main/java/stirling/software/SPDF/config/security/database/DatabaseBackupHelper.java +++ b/src/main/java/stirling/software/SPDF/config/security/database/DatabaseBackupHelper.java @@ -24,7 +24,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; import lombok.extern.slf4j.Slf4j; -import stirling.software.SPDF.config.DatabaseBackupInterface; +import stirling.software.SPDF.config.interfaces.DatabaseBackupInterface; import stirling.software.SPDF.utils.FileInfo; @Slf4j diff --git a/src/main/java/stirling/software/SPDF/config/security/saml/ConvertResponseToAuthentication.java b/src/main/java/stirling/software/SPDF/config/security/saml/ConvertResponseToAuthentication.java new file mode 100644 index 00000000..02bf0593 --- /dev/null +++ b/src/main/java/stirling/software/SPDF/config/security/saml/ConvertResponseToAuthentication.java @@ -0,0 +1,68 @@ +package stirling.software.SPDF.config.security.saml; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.opensaml.saml.saml2.core.Assertion; +import org.springframework.core.convert.converter.Converter; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.saml2.provider.service.authentication.OpenSaml4AuthenticationProvider.ResponseToken; +import org.springframework.security.saml2.provider.service.authentication.Saml2Authentication; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import lombok.extern.slf4j.Slf4j; + +@Component +@Slf4j +public class ConvertResponseToAuthentication + implements Converter { + + private final Saml2AuthorityAttributeLookup saml2AuthorityAttributeLookup; + + public ConvertResponseToAuthentication( + Saml2AuthorityAttributeLookup saml2AuthorityAttributeLookup) { + this.saml2AuthorityAttributeLookup = saml2AuthorityAttributeLookup; + } + + @Override + public Saml2Authentication convert(ResponseToken responseToken) { + final Assertion assertion = + CollectionUtils.firstElement(responseToken.getResponse().getAssertions()); + final Map> attributes = + SamlAssertionUtils.getAssertionAttributes(assertion); + final String registrationId = + responseToken.getToken().getRelyingPartyRegistration().getRegistrationId(); + final ScimSaml2AuthenticatedPrincipal principal = + new ScimSaml2AuthenticatedPrincipal( + assertion, + attributes, + saml2AuthorityAttributeLookup.getIdentityMappings(registrationId)); + final Collection assertionAuthorities = + getAssertionAuthorities( + attributes, + saml2AuthorityAttributeLookup.getAuthorityAttribute(registrationId)); + return new Saml2Authentication( + principal, responseToken.getToken().getSaml2Response(), assertionAuthorities); + } + + private static Collection getAssertionAuthorities( + final Map> attributes, final String authoritiesAttributeName) { + if (attributes == null || attributes.isEmpty()) { + return Collections.emptySet(); + } + + final List groups = new ArrayList<>(attributes.get(authoritiesAttributeName)); + return groups.stream() + .filter(String.class::isInstance) + .map(String.class::cast) + .map(String::toLowerCase) + .map(SimpleGrantedAuthority::new) + .collect(Collectors.toSet()); + } +} diff --git a/src/main/java/stirling/software/SPDF/config/security/saml/CustomSAMLAuthenticationFailureHandler.java b/src/main/java/stirling/software/SPDF/config/security/saml/CustomSAMLAuthenticationFailureHandler.java new file mode 100644 index 00000000..2a61e771 --- /dev/null +++ b/src/main/java/stirling/software/SPDF/config/security/saml/CustomSAMLAuthenticationFailureHandler.java @@ -0,0 +1,51 @@ +package stirling.software.SPDF.config.security.saml; + +import java.io.IOException; + +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.authentication.DisabledException; +import org.springframework.security.authentication.LockedException; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException; +import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler; + +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class CustomSAMLAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler { + + @Override + public void onAuthenticationFailure( + HttpServletRequest request, + HttpServletResponse response, + AuthenticationException exception) + throws IOException, ServletException { + + if (exception instanceof BadCredentialsException) { + log.error("BadCredentialsException", exception); + getRedirectStrategy().sendRedirect(request, response, "/login?error=badcredentials"); + return; + } + if (exception instanceof DisabledException) { + log.error("User is deactivated: ", exception); + getRedirectStrategy().sendRedirect(request, response, "/logout?userIsDisabled=true"); + return; + } + if (exception instanceof LockedException) { + log.error("Account locked: ", exception); + getRedirectStrategy().sendRedirect(request, response, "/logout?error=locked"); + return; + } + if (exception instanceof Saml2AuthenticationException) { + log.error("SAML2 Authentication error: ", exception); + getRedirectStrategy() + .sendRedirect(request, response, "/logout?error=saml2AuthenticationError"); + return; + } + log.error("Unhandled authentication exception", exception); + super.onAuthenticationFailure(request, response, exception); + } +} diff --git a/src/main/java/stirling/software/SPDF/config/security/saml/CustomSAMLAuthenticationSuccessHandler.java b/src/main/java/stirling/software/SPDF/config/security/saml/CustomSAMLAuthenticationSuccessHandler.java new file mode 100644 index 00000000..46d20ac0 --- /dev/null +++ b/src/main/java/stirling/software/SPDF/config/security/saml/CustomSAMLAuthenticationSuccessHandler.java @@ -0,0 +1,108 @@ +package stirling.software.SPDF.config.security.saml; + +import java.io.IOException; + +import org.springframework.security.authentication.LockedException; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.oauth2.core.user.OAuth2User; +import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler; +import org.springframework.security.web.savedrequest.SavedRequest; + +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpSession; +import lombok.extern.slf4j.Slf4j; +import stirling.software.SPDF.config.security.LoginAttemptService; +import stirling.software.SPDF.config.security.UserService; +import stirling.software.SPDF.model.ApplicationProperties; +import stirling.software.SPDF.model.ApplicationProperties.Security.OAUTH2; +import stirling.software.SPDF.model.AuthenticationType; +import stirling.software.SPDF.utils.RequestUriUtils; + +@Slf4j +public class CustomSAMLAuthenticationSuccessHandler + extends SavedRequestAwareAuthenticationSuccessHandler { + + private LoginAttemptService loginAttemptService; + private UserService userService; + private ApplicationProperties applicationProperties; + + public CustomSAMLAuthenticationSuccessHandler( + LoginAttemptService loginAttemptService, + UserService userService, + ApplicationProperties applicationProperties) { + this.loginAttemptService = loginAttemptService; + this.userService = userService; + this.applicationProperties = applicationProperties; + } + + @Override + public void onAuthenticationSuccess( + HttpServletRequest request, HttpServletResponse response, Authentication authentication) + throws ServletException, IOException { + + Object principal = authentication.getPrincipal(); + String username = ""; + + if (principal instanceof OAuth2User) { + OAuth2User oauthUser = (OAuth2User) principal; + username = oauthUser.getName(); + } else if (principal instanceof UserDetails) { + UserDetails oauthUser = (UserDetails) principal; + username = oauthUser.getUsername(); + } else if (principal instanceof ScimSaml2AuthenticatedPrincipal) { + ScimSaml2AuthenticatedPrincipal samlPrincipal = + (ScimSaml2AuthenticatedPrincipal) principal; + username = samlPrincipal.getName(); + } + + // Get the saved request + HttpSession session = request.getSession(false); + String contextPath = request.getContextPath(); + SavedRequest savedRequest = + (session != null) + ? (SavedRequest) session.getAttribute("SPRING_SECURITY_SAVED_REQUEST") + : null; + + if (savedRequest != null + && !RequestUriUtils.isStaticResource(contextPath, savedRequest.getRedirectUrl())) { + // Redirect to the original destination + super.onAuthenticationSuccess(request, response, authentication); + } else { + OAUTH2 oAuth = applicationProperties.getSecurity().getOauth2(); + + if (loginAttemptService.isBlocked(username)) { + if (session != null) { + session.removeAttribute("SPRING_SECURITY_SAVED_REQUEST"); + } + throw new LockedException( + "Your account has been locked due to too many failed login attempts."); + } + if (userService.usernameExistsIgnoreCase(username) + && userService.hasPassword(username) + && !userService.isAuthenticationTypeByUsername( + username, AuthenticationType.OAUTH2) + && oAuth.getAutoCreateUser()) { + response.sendRedirect(contextPath + "/logout?oauth2AuthenticationErrorWeb=true"); + return; + } + try { + if (oAuth.getBlockRegistration() + && !userService.usernameExistsIgnoreCase(username)) { + response.sendRedirect(contextPath + "/logout?oauth2_admin_blocked_user=true"); + return; + } + if (principal instanceof OAuth2User) { + userService.processOAuth2PostLogin(username, oAuth.getAutoCreateUser()); + } + response.sendRedirect(contextPath + "/"); + return; + } catch (IllegalArgumentException e) { + response.sendRedirect(contextPath + "/logout?invalidUsername=true"); + return; + } + } + } +} diff --git a/src/main/java/stirling/software/SPDF/config/security/saml/SAMLLogoutSuccessHandler.java b/src/main/java/stirling/software/SPDF/config/security/saml/SAMLLogoutSuccessHandler.java new file mode 100644 index 00000000..24e81889 --- /dev/null +++ b/src/main/java/stirling/software/SPDF/config/security/saml/SAMLLogoutSuccessHandler.java @@ -0,0 +1,38 @@ +package stirling.software.SPDF.config.security.saml; + +import java.io.IOException; + +import org.springframework.security.core.Authentication; +import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler; + +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class SAMLLogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler { + + @Override + public void onLogoutSuccess( + HttpServletRequest request, HttpServletResponse response, Authentication authentication) + throws IOException, ServletException { + + String redirectUrl = determineTargetUrl(request, response, authentication); + + if (response.isCommitted()) { + log.debug("Response has already been committed. Unable to redirect to " + redirectUrl); + return; + } + + getRedirectStrategy().sendRedirect(request, response, redirectUrl); + } + + protected String determineTargetUrl( + HttpServletRequest request, + HttpServletResponse response, + Authentication authentication) { + // Default to the root URL + return "/"; + } +} diff --git a/src/main/java/stirling/software/SPDF/config/security/saml/Saml2AuthorityAttributeLookup.java b/src/main/java/stirling/software/SPDF/config/security/saml/Saml2AuthorityAttributeLookup.java new file mode 100644 index 00000000..cceb5bf3 --- /dev/null +++ b/src/main/java/stirling/software/SPDF/config/security/saml/Saml2AuthorityAttributeLookup.java @@ -0,0 +1,7 @@ +package stirling.software.SPDF.config.security.saml; + +public interface Saml2AuthorityAttributeLookup { + String getAuthorityAttribute(String registrationId); + + SimpleScimMappings getIdentityMappings(String registrationId); +} diff --git a/src/main/java/stirling/software/SPDF/config/security/saml/Saml2AuthorityAttributeLookupImpl.java b/src/main/java/stirling/software/SPDF/config/security/saml/Saml2AuthorityAttributeLookupImpl.java new file mode 100644 index 00000000..c3b038e5 --- /dev/null +++ b/src/main/java/stirling/software/SPDF/config/security/saml/Saml2AuthorityAttributeLookupImpl.java @@ -0,0 +1,17 @@ +package stirling.software.SPDF.config.security.saml; + +import org.springframework.stereotype.Component; + +@Component +public class Saml2AuthorityAttributeLookupImpl implements Saml2AuthorityAttributeLookup { + + @Override + public String getAuthorityAttribute(String registrationId) { + return "authorityAttributeName"; + } + + @Override + public SimpleScimMappings getIdentityMappings(String registrationId) { + return new SimpleScimMappings(); + } +} diff --git a/src/main/java/stirling/software/SPDF/config/security/saml/SamlAssertionUtils.java b/src/main/java/stirling/software/SPDF/config/security/saml/SamlAssertionUtils.java new file mode 100644 index 00000000..c4a560bf --- /dev/null +++ b/src/main/java/stirling/software/SPDF/config/security/saml/SamlAssertionUtils.java @@ -0,0 +1,63 @@ +package stirling.software.SPDF.config.security.saml; + +import java.time.Instant; +import java.util.*; + +import org.opensaml.core.xml.XMLObject; +import org.opensaml.core.xml.schema.*; +import org.opensaml.saml.saml2.core.Assertion; + +public class SamlAssertionUtils { + + public static Map> getAssertionAttributes(Assertion assertion) { + Map> attributeMap = new LinkedHashMap<>(); + + assertion + .getAttributeStatements() + .forEach( + attributeStatement -> { + attributeStatement + .getAttributes() + .forEach( + attribute -> { + List attributeValues = new ArrayList<>(); + + attribute + .getAttributeValues() + .forEach( + xmlObject -> { + Object attributeValue = + getXmlObjectValue( + xmlObject); + if (attributeValue != null) { + attributeValues.add( + attributeValue); + } + }); + + attributeMap.put( + attribute.getName(), attributeValues); + }); + }); + + return attributeMap; + } + + public static Object getXmlObjectValue(XMLObject xmlObject) { + if (xmlObject instanceof XSAny) { + return ((XSAny) xmlObject).getTextContent(); + } else if (xmlObject instanceof XSString) { + return ((XSString) xmlObject).getValue(); + } else if (xmlObject instanceof XSInteger) { + return ((XSInteger) xmlObject).getValue(); + } else if (xmlObject instanceof XSURI) { + return ((XSURI) xmlObject).getURI(); + } else if (xmlObject instanceof XSBoolean) { + return ((XSBoolean) xmlObject).getValue().getValue(); + } else if (xmlObject instanceof XSDateTime) { + Instant dateTime = ((XSDateTime) xmlObject).getValue(); + return (dateTime != null) ? Instant.ofEpochMilli(dateTime.toEpochMilli()) : null; + } + return null; + } +} diff --git a/src/main/java/stirling/software/SPDF/config/security/saml/SamlConfig.java b/src/main/java/stirling/software/SPDF/config/security/saml/SamlConfig.java new file mode 100644 index 00000000..358c4488 --- /dev/null +++ b/src/main/java/stirling/software/SPDF/config/security/saml/SamlConfig.java @@ -0,0 +1,42 @@ +package stirling.software.SPDF.config.security.saml; + +import java.security.cert.CertificateException; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.saml2.provider.service.registration.InMemoryRelyingPartyRegistrationRepository; +import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration; +import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository; +import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrations; + +import lombok.extern.slf4j.Slf4j; +import stirling.software.SPDF.model.ApplicationProperties; + +@Configuration +@Slf4j +public class SamlConfig { + + @Autowired ApplicationProperties applicationProperties; + + @Bean + @ConditionalOnProperty( + value = "security.saml.enabled", + havingValue = "true", + matchIfMissing = false) + public RelyingPartyRegistrationRepository relyingPartyRegistrationRepository() + throws CertificateException { + RelyingPartyRegistration registration = + RelyingPartyRegistrations.fromMetadataLocation( + applicationProperties + .getSecurity() + .getSaml() + .getIdpMetadataLocation()) + .entityId(applicationProperties.getSecurity().getSaml().getEntityId()) + .registrationId( + applicationProperties.getSecurity().getSaml().getRegistrationId()) + .build(); + return new InMemoryRelyingPartyRegistrationRepository(registration); + } +} diff --git a/src/main/java/stirling/software/SPDF/config/security/saml/ScimSaml2AuthenticatedPrincipal.java b/src/main/java/stirling/software/SPDF/config/security/saml/ScimSaml2AuthenticatedPrincipal.java new file mode 100644 index 00000000..9be94f38 --- /dev/null +++ b/src/main/java/stirling/software/SPDF/config/security/saml/ScimSaml2AuthenticatedPrincipal.java @@ -0,0 +1,89 @@ +package stirling.software.SPDF.config.security.saml; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +import org.opensaml.saml.saml2.core.Assertion; +import org.springframework.security.core.AuthenticatedPrincipal; +import org.springframework.util.Assert; + +import com.unboundid.scim2.common.types.Email; +import com.unboundid.scim2.common.types.Name; +import com.unboundid.scim2.common.types.UserResource; + +public class ScimSaml2AuthenticatedPrincipal implements AuthenticatedPrincipal, Serializable { + + private static final long serialVersionUID = 1L; + + private final transient UserResource userResource; + + public ScimSaml2AuthenticatedPrincipal( + final Assertion assertion, + final Map> attributes, + final SimpleScimMappings attributeMappings) { + Assert.notNull(assertion, "assertion cannot be null"); + Assert.notNull(assertion.getSubject(), "assertion subject cannot be null"); + Assert.notNull( + assertion.getSubject().getNameID(), "assertion subject NameID cannot be null"); + Assert.notNull(attributes, "attributes cannot be null"); + Assert.notNull(attributeMappings, "attributeMappings cannot be null"); + + final Name name = + new Name() + .setFamilyName( + getAttribute( + attributes, + attributeMappings, + SimpleScimMappings::getFamilyName)) + .setGivenName( + getAttribute( + attributes, + attributeMappings, + SimpleScimMappings::getGivenName)); + + final List emails = new ArrayList<>(1); + emails.add( + new Email() + .setValue( + getAttribute( + attributes, + attributeMappings, + SimpleScimMappings::getEmail)) + .setPrimary(true)); + + userResource = + new UserResource() + .setUserName(assertion.getSubject().getNameID().getValue()) + .setName(name) + .setEmails(emails); + } + + private static String getAttribute( + final Map> attributes, + final SimpleScimMappings simpleScimMappings, + final Function attributeMapper) { + + final String key = attributeMapper.apply(simpleScimMappings); + + final List values = attributes.getOrDefault(key, Collections.emptyList()); + + return values.stream() + .filter(String.class::isInstance) + .map(String.class::cast) + .findFirst() + .orElse(null); + } + + @Override + public String getName() { + return this.userResource.getUserName(); + } + + public UserResource getUserResource() { + return this.userResource; + } +} diff --git a/src/main/java/stirling/software/SPDF/config/security/saml/SimpleScimMappings.java b/src/main/java/stirling/software/SPDF/config/security/saml/SimpleScimMappings.java new file mode 100644 index 00000000..97f61d31 --- /dev/null +++ b/src/main/java/stirling/software/SPDF/config/security/saml/SimpleScimMappings.java @@ -0,0 +1,10 @@ +package stirling.software.SPDF.config.security.saml; + +import lombok.Data; + +@Data +public class SimpleScimMappings { + String givenName; + String familyName; + String email; +} diff --git a/src/main/java/stirling/software/SPDF/config/security/session/CustomHttpSessionListener.java b/src/main/java/stirling/software/SPDF/config/security/session/CustomHttpSessionListener.java index a4129e6a..305684b9 100644 --- a/src/main/java/stirling/software/SPDF/config/security/session/CustomHttpSessionListener.java +++ b/src/main/java/stirling/software/SPDF/config/security/session/CustomHttpSessionListener.java @@ -11,16 +11,19 @@ import lombok.extern.slf4j.Slf4j; @Slf4j public class CustomHttpSessionListener implements HttpSessionListener { - @Autowired private SessionPersistentRegistry sessionPersistentRegistry; + private SessionPersistentRegistry sessionPersistentRegistry; + + @Autowired + public CustomHttpSessionListener(SessionPersistentRegistry sessionPersistentRegistry) { + super(); + this.sessionPersistentRegistry = sessionPersistentRegistry; + } @Override - public void sessionCreated(HttpSessionEvent se) { - log.info("Session created: " + se.getSession().getId()); - } + public void sessionCreated(HttpSessionEvent se) {} @Override public void sessionDestroyed(HttpSessionEvent se) { - log.info("Session destroyed: " + se.getSession().getId()); sessionPersistentRegistry.expireSession(se.getSession().getId()); } } diff --git a/src/main/java/stirling/software/SPDF/config/security/session/SessionPersistentRegistry.java b/src/main/java/stirling/software/SPDF/config/security/session/SessionPersistentRegistry.java index bb63a8b5..f7f78d1e 100644 --- a/src/main/java/stirling/software/SPDF/config/security/session/SessionPersistentRegistry.java +++ b/src/main/java/stirling/software/SPDF/config/security/session/SessionPersistentRegistry.java @@ -84,6 +84,14 @@ public class SessionPersistentRegistry implements SessionRegistry { } if (principalName != null) { + // Clear old sessions for the principal (unsure if needed) + // List existingSessions = + // sessionRepository.findByPrincipalName(principalName); + // for (SessionEntity session : existingSessions) { + // session.setExpired(true); + // sessionRepository.save(session); + // } + SessionEntity sessionEntity = new SessionEntity(); sessionEntity.setSessionId(sessionId); sessionEntity.setPrincipalName(principalName); diff --git a/src/main/java/stirling/software/SPDF/controller/api/CropController.java b/src/main/java/stirling/software/SPDF/controller/api/CropController.java index 551cd72d..d386d1ce 100644 --- a/src/main/java/stirling/software/SPDF/controller/api/CropController.java +++ b/src/main/java/stirling/software/SPDF/controller/api/CropController.java @@ -25,6 +25,7 @@ import io.swagger.v3.oas.annotations.tags.Tag; import stirling.software.SPDF.model.api.general.CropPdfForm; import stirling.software.SPDF.service.CustomPDDocumentFactory; +import stirling.software.SPDF.service.PostHogService; import stirling.software.SPDF.utils.WebResponseUtils; @RestController @@ -36,9 +37,13 @@ public class CropController { private final CustomPDDocumentFactory pdfDocumentFactory; + private final PostHogService postHogService; + @Autowired - public CropController(CustomPDDocumentFactory pdfDocumentFactory) { + public CropController( + CustomPDDocumentFactory pdfDocumentFactory, PostHogService postHogService) { this.pdfDocumentFactory = pdfDocumentFactory; + this.postHogService = postHogService; } @PostMapping(value = "/crop", consumes = "multipart/form-data") diff --git a/src/main/java/stirling/software/SPDF/controller/api/SettingsController.java b/src/main/java/stirling/software/SPDF/controller/api/SettingsController.java new file mode 100644 index 00000000..dd674210 --- /dev/null +++ b/src/main/java/stirling/software/SPDF/controller/api/SettingsController.java @@ -0,0 +1,37 @@ +package stirling.software.SPDF.controller.api; + +import java.io.IOException; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.*; + +import io.swagger.v3.oas.annotations.Hidden; +import io.swagger.v3.oas.annotations.tags.Tag; + +import stirling.software.SPDF.model.ApplicationProperties; +import stirling.software.SPDF.utils.GeneralUtils; + +@Controller +@Tag(name = "Settings", description = "Settings APIs") +@RequestMapping("/api/v1/settings") +@Hidden +public class SettingsController { + + @Autowired ApplicationProperties applicationProperties; + + @PostMapping("/update-enable-analytics") + @Hidden + public ResponseEntity updateApiKey(@RequestBody Boolean enabled) throws IOException { + if (!"undefined".equals(applicationProperties.getSystem().getEnableAnalytics())) { + return ResponseEntity.status(HttpStatus.ALREADY_REPORTED) + .body( + "Setting has already been set, To adjust please edit /config/settings.yml"); + } + GeneralUtils.saveKeyToConfig("system.enableAnalytics", String.valueOf(enabled), false); + applicationProperties.getSystem().setEnableAnalytics(String.valueOf(enabled)); + return ResponseEntity.ok("Updated"); + } +} diff --git a/src/main/java/stirling/software/SPDF/controller/api/SplitPDFController.java b/src/main/java/stirling/software/SPDF/controller/api/SplitPDFController.java index 2da76fa3..e27df103 100644 --- a/src/main/java/stirling/software/SPDF/controller/api/SplitPDFController.java +++ b/src/main/java/stirling/software/SPDF/controller/api/SplitPDFController.java @@ -60,8 +60,6 @@ public class SplitPDFController { // PdfMetadata metadata = PdfMetadataService.extractMetadataFromPdf(document); int totalPages = document.getNumberOfPages(); List pageNumbers = request.getPageNumbersList(document, false); - System.out.println( - pageNumbers.stream().map(String::valueOf).collect(Collectors.joining(","))); if (!pageNumbers.contains(totalPages - 1)) { // Create a mutable ArrayList so we can add to it pageNumbers = new ArrayList<>(pageNumbers); diff --git a/src/main/java/stirling/software/SPDF/controller/api/SplitPdfByChaptersController.java b/src/main/java/stirling/software/SPDF/controller/api/SplitPdfByChaptersController.java index 0cca8f78..f344c276 100644 --- a/src/main/java/stirling/software/SPDF/controller/api/SplitPdfByChaptersController.java +++ b/src/main/java/stirling/software/SPDF/controller/api/SplitPdfByChaptersController.java @@ -32,9 +32,9 @@ import lombok.AllArgsConstructor; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; -import stirling.software.SPDF.config.PdfMetadataService; import stirling.software.SPDF.model.PdfMetadata; import stirling.software.SPDF.model.api.SplitPdfByChaptersRequest; +import stirling.software.SPDF.service.PdfMetadataService; import stirling.software.SPDF.utils.WebResponseUtils; @RestController diff --git a/src/main/java/stirling/software/SPDF/controller/api/UserController.java b/src/main/java/stirling/software/SPDF/controller/api/UserController.java index 719adac1..cc928749 100644 --- a/src/main/java/stirling/software/SPDF/controller/api/UserController.java +++ b/src/main/java/stirling/software/SPDF/controller/api/UserController.java @@ -30,6 +30,7 @@ import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; import stirling.software.SPDF.config.security.UserService; import stirling.software.SPDF.config.security.session.SessionPersistentRegistry; import stirling.software.SPDF.model.AuthenticationType; @@ -40,6 +41,7 @@ import stirling.software.SPDF.model.api.user.UsernameAndPass; @Controller @Tag(name = "User", description = "User APIs") @RequestMapping("/api/v1/user") +@Slf4j public class UserController { @Autowired private UserService userService; @@ -191,13 +193,11 @@ public class UserController { Map paramMap = request.getParameterMap(); Map updates = new HashMap<>(); - System.out.println("Received parameter map: " + paramMap); - for (Map.Entry entry : paramMap.entrySet()) { updates.put(entry.getKey(), entry.getValue()[0]); } - System.out.println("Processed updates: " + updates); + log.debug("Processed updates: " + updates); // Assuming you have a method in userService to update the settings for a user userService.updateUserSettings(principal.getName(), updates); @@ -209,7 +209,7 @@ public class UserController { @PostMapping("/admin/saveUser") public RedirectView saveUser( @RequestParam(name = "username", required = true) String username, - @RequestParam(name = "password", required = true) String password, + @RequestParam(name = "password", required = false) String password, @RequestParam(name = "role") String role, @RequestParam(name = "authType") String authType, @RequestParam(name = "forceChange", required = false, defaultValue = "false") diff --git a/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertBookToPDFController.java b/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertBookToPDFController.java index 694d30ab..778aab04 100644 --- a/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertBookToPDFController.java +++ b/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertBookToPDFController.java @@ -1,5 +1,6 @@ package stirling.software.SPDF.controller.api.converters; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.ModelAttribute; @@ -14,7 +15,6 @@ import stirling.software.SPDF.service.CustomPDDocumentFactory; import stirling.software.SPDF.utils.FileToPdf; import stirling.software.SPDF.utils.WebResponseUtils; -// Disabled for now // @RestController // @Tag(name = "Convert", description = "Convert APIs") // @RequestMapping("/api/v1/convert") @@ -24,7 +24,7 @@ public class ConvertBookToPDFController { private final CustomPDDocumentFactory pdfDocumentFactory; - // @Autowired + @Autowired public ConvertBookToPDFController( CustomPDDocumentFactory pdfDocumentFactory, @Qualifier("bookAndHtmlFormatsInstalled") boolean bookAndHtmlFormatsInstalled) { @@ -66,6 +66,8 @@ public class ConvertBookToPDFController { } byte[] pdfBytes = FileToPdf.convertBookTypeToPdf(fileInput.getBytes(), originalFilename); + pdfBytes = pdfDocumentFactory.createNewBytesBasedOnOldDocument(pdfBytes); + String outputFilename = originalFilename.replaceFirst("[.][^.]+$", "") + ".pdf"; // Remove file extension and append .pdf diff --git a/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertHtmlToPDF.java b/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertHtmlToPDF.java index 19ba1ac4..a4fe57bb 100644 --- a/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertHtmlToPDF.java +++ b/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertHtmlToPDF.java @@ -1,27 +1,39 @@ package stirling.software.SPDF.controller.api.converters; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import io.github.pixee.security.Filenames; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import stirling.software.SPDF.model.api.converters.HTMLToPdfRequest; +import stirling.software.SPDF.service.CustomPDDocumentFactory; import stirling.software.SPDF.utils.FileToPdf; import stirling.software.SPDF.utils.WebResponseUtils; -// Disabled for now -// @RestController -// @Tag(name = "Convert", description = "Convert APIs") -// @RequestMapping("/api/v1/convert") +@RestController +@Tag(name = "Convert", description = "Convert APIs") +@RequestMapping("/api/v1/convert") public class ConvertHtmlToPDF { - // @Autowired - @Qualifier("bookAndHtmlFormatsInstalled") - private boolean bookAndHtmlFormatsInstalled; + private final boolean bookAndHtmlFormatsInstalled; + + private final CustomPDDocumentFactory pdfDocumentFactory; + + @Autowired + public ConvertHtmlToPDF( + CustomPDDocumentFactory pdfDocumentFactory, + @Qualifier("bookAndHtmlFormatsInstalled") boolean bookAndHtmlFormatsInstalled) { + this.pdfDocumentFactory = pdfDocumentFactory; + this.bookAndHtmlFormatsInstalled = bookAndHtmlFormatsInstalled; + } @PostMapping(consumes = "multipart/form-data", value = "/html/pdf") @Operation( @@ -49,6 +61,8 @@ public class ConvertHtmlToPDF { originalFilename, bookAndHtmlFormatsInstalled); + pdfBytes = pdfDocumentFactory.createNewBytesBasedOnOldDocument(pdfBytes); + String outputFilename = originalFilename.replaceFirst("[.][^.]+$", "") + ".pdf"; // Remove file extension and append .pdf diff --git a/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertMarkdownToPdf.java b/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertMarkdownToPdf.java index 5b2f3fdf..b378f479 100644 --- a/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertMarkdownToPdf.java +++ b/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertMarkdownToPdf.java @@ -10,28 +10,40 @@ import org.commonmark.node.Node; import org.commonmark.parser.Parser; import org.commonmark.renderer.html.AttributeProvider; import org.commonmark.renderer.html.HtmlRenderer; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import io.github.pixee.security.Filenames; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import stirling.software.SPDF.model.api.GeneralFile; +import stirling.software.SPDF.service.CustomPDDocumentFactory; import stirling.software.SPDF.utils.FileToPdf; import stirling.software.SPDF.utils.WebResponseUtils; -// Disabled for now -// @RestController -// @Tag(name = "Convert", description = "Convert APIs") -// @RequestMapping("/api/v1/convert") +@RestController +@Tag(name = "Convert", description = "Convert APIs") +@RequestMapping("/api/v1/convert") public class ConvertMarkdownToPdf { - // @Autowired - @Qualifier("bookAndHtmlFormatsInstalled") - private boolean bookAndHtmlFormatsInstalled; + private final boolean bookAndHtmlFormatsInstalled; + + private final CustomPDDocumentFactory pdfDocumentFactory; + + @Autowired + public ConvertMarkdownToPdf( + CustomPDDocumentFactory pdfDocumentFactory, + @Qualifier("bookAndHtmlFormatsInstalled") boolean bookAndHtmlFormatsInstalled) { + this.pdfDocumentFactory = pdfDocumentFactory; + this.bookAndHtmlFormatsInstalled = bookAndHtmlFormatsInstalled; + } @PostMapping(consumes = "multipart/form-data", value = "/markdown/pdf") @Operation( @@ -70,7 +82,7 @@ public class ConvertMarkdownToPdf { htmlContent.getBytes(), "converted.html", bookAndHtmlFormatsInstalled); - + pdfBytes = pdfDocumentFactory.createNewBytesBasedOnOldDocument(pdfBytes); String outputFilename = originalFilename.replaceFirst("[.][^.]+$", "") + ".pdf"; // Remove file extension and append .pdf diff --git a/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertPDFToBookController.java b/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertPDFToBookController.java index 181b5713..f1c672e1 100644 --- a/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertPDFToBookController.java +++ b/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertPDFToBookController.java @@ -6,6 +6,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.ModelAttribute; @@ -20,13 +21,12 @@ import stirling.software.SPDF.utils.ProcessExecutor; import stirling.software.SPDF.utils.ProcessExecutor.ProcessExecutorResult; import stirling.software.SPDF.utils.WebResponseUtils; -// Disabled for now // @RestController // @Tag(name = "Convert", description = "Convert APIs") // @RequestMapping("/api/v1/convert") public class ConvertPDFToBookController { - // @Autowired + @Autowired @Qualifier("bookAndHtmlFormatsInstalled") private boolean bookAndHtmlFormatsInstalled; diff --git a/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertPDFToPDFA.java b/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertPDFToPDFA.java index 14aef734..c437c4cb 100644 --- a/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertPDFToPDFA.java +++ b/src/main/java/stirling/software/SPDF/controller/api/converters/ConvertPDFToPDFA.java @@ -61,7 +61,7 @@ public class ConvertPDFToPDFA { command.add("-dPDFA=" + ("pdfa".equals(outputFormat) ? "2" : "1")); command.add("-dNOPAUSE"); command.add("-dBATCH"); - command.add("-sColorConversionStrategy=UseDeviceIndependentColor"); + command.add("-sColorConversionStrategy=sRGB"); command.add("-sDEVICE=pdfwrite"); command.add("-dPDFACompatibilityPolicy=2"); command.add("-o"); diff --git a/src/main/java/stirling/software/SPDF/controller/api/misc/ExtractImagesController.java b/src/main/java/stirling/software/SPDF/controller/api/misc/ExtractImagesController.java index 3dff43e8..075de0d1 100644 --- a/src/main/java/stirling/software/SPDF/controller/api/misc/ExtractImagesController.java +++ b/src/main/java/stirling/software/SPDF/controller/api/misc/ExtractImagesController.java @@ -60,8 +60,6 @@ public class ExtractImagesController { MultipartFile file = request.getFileInput(); String format = request.getFormat(); boolean allowDuplicates = request.isAllowDuplicates(); - System.out.println( - System.currentTimeMillis() + " file=" + file.getName() + ", format=" + format); PDDocument document = Loader.loadPDF(file.getBytes()); // Determine if multithreading should be used based on PDF size or number of pages diff --git a/src/main/java/stirling/software/SPDF/controller/api/misc/PrintFileController.java b/src/main/java/stirling/software/SPDF/controller/api/misc/PrintFileController.java index bc0a6715..8f993abd 100644 --- a/src/main/java/stirling/software/SPDF/controller/api/misc/PrintFileController.java +++ b/src/main/java/stirling/software/SPDF/controller/api/misc/PrintFileController.java @@ -26,11 +26,13 @@ import org.springframework.web.multipart.MultipartFile; import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; import stirling.software.SPDF.model.api.misc.PrintFileRequest; @RestController @RequestMapping("/api/v1/misc") @Tag(name = "Misc", description = "Miscellaneous APIs") +@Slf4j public class PrintFileController { // TODO @@ -59,7 +61,7 @@ public class PrintFileController { new IllegalArgumentException( "No matching printer found")); - System.out.println("Selected Printer: " + selectedService.getName()); + log.info("Selected Printer: " + selectedService.getName()); if ("application/pdf".equals(contentType)) { PDDocument document = Loader.loadPDF(file.getBytes()); diff --git a/src/main/java/stirling/software/SPDF/controller/api/security/RedactController.java b/src/main/java/stirling/software/SPDF/controller/api/security/RedactController.java index 40dc2c75..d9e1e4ca 100644 --- a/src/main/java/stirling/software/SPDF/controller/api/security/RedactController.java +++ b/src/main/java/stirling/software/SPDF/controller/api/security/RedactController.java @@ -58,7 +58,6 @@ public class RedactController { float customPadding = request.getCustomPadding(); boolean convertPDFToImage = request.isConvertPDFToImage(); - System.out.println(listOfTextString); String[] listOfText = listOfTextString.split("\n"); PDDocument document = pdfDocumentFactory.load(file); @@ -75,7 +74,6 @@ public class RedactController { for (String text : listOfText) { text = text.trim(); - System.out.println(text); TextFinder textFinder = new TextFinder(text, useRegex, wholeWordSearchBool); List foundTexts = textFinder.getTextLocations(document); redactFoundText(document, foundTexts, customPadding, redactColor); diff --git a/src/main/java/stirling/software/SPDF/controller/web/GeneralWebController.java b/src/main/java/stirling/software/SPDF/controller/web/GeneralWebController.java index 93ad5f34..14af6ee7 100644 --- a/src/main/java/stirling/software/SPDF/controller/web/GeneralWebController.java +++ b/src/main/java/stirling/software/SPDF/controller/web/GeneralWebController.java @@ -108,6 +108,13 @@ public class GeneralWebController { return "split-pdf-by-sections"; } + @GetMapping("/split-pdf-by-chapters") + @Hidden + public String splitPdfByChapters(Model model) { + model.addAttribute("currentPage", "split-pdf-by-chapters"); + return "split-pdf-by-chapters"; + } + @GetMapping("/view-pdf") @Hidden public String ViewPdfForm2(Model model) { diff --git a/src/main/java/stirling/software/SPDF/model/ApplicationProperties.java b/src/main/java/stirling/software/SPDF/model/ApplicationProperties.java index 46c92633..10ad434a 100644 --- a/src/main/java/stirling/software/SPDF/model/ApplicationProperties.java +++ b/src/main/java/stirling/software/SPDF/model/ApplicationProperties.java @@ -11,6 +11,11 @@ import org.slf4j.LoggerFactory; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.FileSystemResource; +import org.springframework.core.io.Resource; import lombok.Data; import lombok.ToString; @@ -24,6 +29,7 @@ import stirling.software.SPDF.model.provider.UnsupportedProviderException; @ConfigurationProperties(prefix = "") @PropertySource(value = "file:./configs/settings.yml", factory = YamlPropertySourceFactory.class) @Data +@Order(Ordered.HIGHEST_PRECEDENCE) public class ApplicationProperties { private Legal legal = new Legal(); @@ -57,6 +63,7 @@ public class ApplicationProperties { private Boolean csrfDisabled; private InitialLogin initialLogin = new InitialLogin(); private OAUTH2 oauth2 = new OAUTH2(); + private SAML saml = new SAML(); private int loginAttemptCount; private long loginResetTimeMinutes; private String loginMethod = "all"; @@ -67,6 +74,34 @@ public class ApplicationProperties { @ToString.Exclude private String password; } + @Data + public static class SAML { + private Boolean enabled = false; + private String entityId; + private String registrationId; + private String spBaseUrl; + private String idpMetadataLocation; + private KeyStore keystore; + + @Data + public static class KeyStore { + private String keystoreLocation; + private String keystorePassword; + private String keyAlias; + private String keyPassword; + private String realmCertificateAlias; + + public Resource getKeystoreResource() { + if (keystoreLocation.startsWith("classpath:")) { + return new ClassPathResource( + keystoreLocation.substring("classpath:".length())); + } else { + return new FileSystemResource(keystoreLocation); + } + } + } + } + @Data public static class OAUTH2 { private Boolean enabled = false; @@ -136,6 +171,7 @@ public class ApplicationProperties { private boolean customHTMLFiles; private String tessdataDir; private Boolean enableAlphaFunctionality; + private String enableAnalytics; } @Data @@ -175,11 +211,14 @@ public class ApplicationProperties { @Data public static class AutomaticallyGenerated { @ToString.Exclude private String key; + private String UUID; } @Data public static class EnterpriseEdition { + private boolean enabled; @ToString.Exclude private String key; + private int maxUsers; private CustomMetadata customMetadata = new CustomMetadata(); @Data diff --git a/src/main/java/stirling/software/SPDF/pdf/TextFinder.java b/src/main/java/stirling/software/SPDF/pdf/TextFinder.java index f9e339c2..77f7d0c6 100644 --- a/src/main/java/stirling/software/SPDF/pdf/TextFinder.java +++ b/src/main/java/stirling/software/SPDF/pdf/TextFinder.java @@ -10,8 +10,10 @@ import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.text.PDFTextStripper; import org.apache.pdfbox.text.TextPosition; +import lombok.extern.slf4j.Slf4j; import stirling.software.SPDF.model.PDFText; +@Slf4j public class TextFinder extends PDFTextStripper { private final String searchText; @@ -92,7 +94,7 @@ public class TextFinder extends PDFTextStripper { public List getTextLocations(PDDocument document) throws Exception { this.getText(document); - System.out.println( + log.debug( "Found " + textOccurrences.size() + " occurrences of '" diff --git a/src/main/java/stirling/software/SPDF/service/CustomPDDocumentFactory.java b/src/main/java/stirling/software/SPDF/service/CustomPDDocumentFactory.java index 2d3d8990..0807e0d1 100644 --- a/src/main/java/stirling/software/SPDF/service/CustomPDDocumentFactory.java +++ b/src/main/java/stirling/software/SPDF/service/CustomPDDocumentFactory.java @@ -13,7 +13,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.web.multipart.MultipartFile; -import stirling.software.SPDF.config.PdfMetadataService; import stirling.software.SPDF.model.PdfMetadata; import stirling.software.SPDF.model.api.PDFFile; @@ -35,6 +34,36 @@ public class CustomPDDocumentFactory { return document; } + public byte[] createNewBytesBasedOnOldDocument(byte[] oldDocument) throws IOException { + PDDocument document = Loader.loadPDF(oldDocument); + return createNewBytesBasedOnOldDocument(document); + } + + public byte[] createNewBytesBasedOnOldDocument(File oldDocument) throws IOException { + PDDocument document = Loader.loadPDF(oldDocument); + return createNewBytesBasedOnOldDocument(document); + } + + public byte[] createNewBytesBasedOnOldDocument(PDDocument oldDocument) throws IOException { + pdfMetadataService.setMetadataToPdf( + oldDocument, pdfMetadataService.extractMetadataFromPdf(oldDocument), true); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + oldDocument.save(baos); + oldDocument.close(); + return baos.toByteArray(); + } + + public PDDocument createNewDocumentBasedOnOldDocument(byte[] oldDocument) throws IOException { + PDDocument document = Loader.loadPDF(oldDocument); + return createNewDocumentBasedOnOldDocument(document); + } + + public PDDocument createNewDocumentBasedOnOldDocument(File oldDocument) throws IOException { + PDDocument document = Loader.loadPDF(oldDocument); + return createNewDocumentBasedOnOldDocument(document); + } + public PDDocument createNewDocumentBasedOnOldDocument(PDDocument oldDocument) throws IOException { PDDocument document = new PDDocument(); diff --git a/src/main/java/stirling/software/SPDF/service/MetricsAggregatorService.java b/src/main/java/stirling/software/SPDF/service/MetricsAggregatorService.java new file mode 100644 index 00000000..eb3a83b0 --- /dev/null +++ b/src/main/java/stirling/software/SPDF/service/MetricsAggregatorService.java @@ -0,0 +1,56 @@ +package stirling.software.SPDF.service; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; + +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.search.Search; + +@Service +public class MetricsAggregatorService { + + private final MeterRegistry meterRegistry; + private final PostHogService postHogService; + private final Map lastSentMetrics = new ConcurrentHashMap<>(); + + @Autowired + public MetricsAggregatorService(MeterRegistry meterRegistry, PostHogService postHogService) { + this.meterRegistry = meterRegistry; + this.postHogService = postHogService; + } + + @Scheduled(fixedRate = 900000) // Run every 15 minutes + public void aggregateAndSendMetrics() { + Map metrics = new HashMap<>(); + Search.in(meterRegistry) + .name("http.requests") + .counters() + .forEach( + counter -> { + String key = + String.format( + "http_requests_%s_%s", + counter.getId().getTag("method"), + counter.getId().getTag("uri").replace("/", "_")); + + double currentCount = counter.count(); + double lastCount = lastSentMetrics.getOrDefault(key, 0.0); + double difference = currentCount - lastCount; + + if (difference > 0) { + metrics.put(key, difference); + lastSentMetrics.put(key, currentCount); + } + }); + + // Send aggregated metrics to PostHog + if (!metrics.isEmpty()) { + postHogService.captureEvent("aggregated_metrics", metrics); + } + } +} diff --git a/src/main/java/stirling/software/SPDF/config/PdfMetadataService.java b/src/main/java/stirling/software/SPDF/service/PdfMetadataService.java similarity index 62% rename from src/main/java/stirling/software/SPDF/config/PdfMetadataService.java rename to src/main/java/stirling/software/SPDF/service/PdfMetadataService.java index 7b40a878..373b4c91 100644 --- a/src/main/java/stirling/software/SPDF/config/PdfMetadataService.java +++ b/src/main/java/stirling/software/SPDF/service/PdfMetadataService.java @@ -1,4 +1,4 @@ -package stirling.software.SPDF.config; +package stirling.software.SPDF.service; import java.util.Calendar; @@ -15,16 +15,16 @@ import stirling.software.SPDF.model.PdfMetadata; public class PdfMetadataService { private final ApplicationProperties applicationProperties; - private final String appVersion; + private final String stirlingPDFLabel; private final UserServiceInterface userService; @Autowired public PdfMetadataService( ApplicationProperties applicationProperties, - @Qualifier("appVersion") String appVersion, + @Qualifier("StirlingPDFLabel") String stirlingPDFLabel, @Autowired(required = false) UserServiceInterface userService) { this.applicationProperties = applicationProperties; - this.appVersion = appVersion; + this.stirlingPDFLabel = stirlingPDFLabel; this.userService = userService; } @@ -59,51 +59,40 @@ public class PdfMetadataService { private void setNewDocumentMetadata(PDDocument pdf, PdfMetadata pdfMetadata) { - String creator = "Stirling-PDF"; + String creator = stirlingPDFLabel; - // if (applicationProperties - // .getEnterpriseEdition() - // .getCustomMetadata() - // .isAutoUpdateMetadata()) { + if (applicationProperties + .getEnterpriseEdition() + .getCustomMetadata() + .isAutoUpdateMetadata()) { - // producer = - // - // applicationProperties.getEnterpriseEdition().getCustomMetadata().getProducer(); - // creator = - // applicationProperties.getEnterpriseEdition().getCustomMetadata().getCreator(); - // title = applicationProperties.getEnterpriseEdition().getCustomMetadata().getTitle(); + creator = applicationProperties.getEnterpriseEdition().getCustomMetadata().getCreator(); + pdf.getDocumentInformation().setProducer(stirlingPDFLabel); + } - // if ("{filename}".equals(title)) { - // title = "Filename"; // Replace with actual filename logic - // } else if ("{unchanged}".equals(title)) { - // title = pdfMetadata.getTitle(); // Keep the original title - // } - // } - - pdf.getDocumentInformation().setCreator(creator + " " + appVersion); + pdf.getDocumentInformation().setCreator(creator); pdf.getDocumentInformation().setCreationDate(Calendar.getInstance()); } private void setCommonMetadata(PDDocument pdf, PdfMetadata pdfMetadata) { - String producer = "Stirling-PDF"; String title = pdfMetadata.getTitle(); pdf.getDocumentInformation().setTitle(title); - pdf.getDocumentInformation().setProducer(producer + " " + appVersion); + pdf.getDocumentInformation().setProducer(stirlingPDFLabel); pdf.getDocumentInformation().setSubject(pdfMetadata.getSubject()); pdf.getDocumentInformation().setKeywords(pdfMetadata.getKeywords()); pdf.getDocumentInformation().setModificationDate(Calendar.getInstance()); String author = pdfMetadata.getAuthor(); - // if (applicationProperties - // .getEnterpriseEdition() - // .getCustomMetadata() - // .isAutoUpdateMetadata()) { - // author = applicationProperties.getEnterpriseEdition().getCustomMetadata().getAuthor(); + if (applicationProperties + .getEnterpriseEdition() + .getCustomMetadata() + .isAutoUpdateMetadata()) { + author = applicationProperties.getEnterpriseEdition().getCustomMetadata().getAuthor(); - // if (userService != null) { - // author = author.replace("username", userService.getCurrentUsername()); - // } - // } + if (userService != null) { + author = author.replace("username", userService.getCurrentUsername()); + } + } pdf.getDocumentInformation().setAuthor(author); } } diff --git a/src/main/java/stirling/software/SPDF/service/PostHogService.java b/src/main/java/stirling/software/SPDF/service/PostHogService.java new file mode 100644 index 00000000..9b22cf1c --- /dev/null +++ b/src/main/java/stirling/software/SPDF/service/PostHogService.java @@ -0,0 +1,379 @@ +package stirling.software.SPDF.service; + +import java.io.File; +import java.lang.management.*; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.TimeZone; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Service; + +import com.posthog.java.PostHog; + +import stirling.software.SPDF.model.ApplicationProperties; + +@Service +public class PostHogService { + private final PostHog postHog; + private final String uniqueId; + private final ApplicationProperties applicationProperties; + + @Autowired + public PostHogService( + PostHog postHog, + @Qualifier("UUID") String uuid, + ApplicationProperties applicationProperties) { + this.postHog = postHog; + this.uniqueId = uuid; + this.applicationProperties = applicationProperties; + captureSystemInfo(); + } + + private void captureSystemInfo() { + if (!Boolean.getBoolean(applicationProperties.getSystem().getEnableAnalytics())) { + return; + } + try { + postHog.capture(uniqueId, "system_info_captured", captureServerMetrics()); + } catch (Exception e) { + // Handle exceptions + } + } + + public void captureEvent(String eventName, Map properties) { + if (!Boolean.getBoolean(applicationProperties.getSystem().getEnableAnalytics())) { + return; + } + postHog.capture(uniqueId, eventName, properties); + } + + public Map captureServerMetrics() { + Map metrics = new HashMap<>(); + + try { + // System info + metrics.put("os_name", System.getProperty("os.name")); + metrics.put("os_version", System.getProperty("os.version")); + metrics.put("java_version", System.getProperty("java.version")); + metrics.put("user_name", System.getProperty("user.name")); + metrics.put("user_home", System.getProperty("user.home")); + metrics.put("user_dir", System.getProperty("user.dir")); + + // CPU and Memory + metrics.put("cpu_cores", Runtime.getRuntime().availableProcessors()); + metrics.put("total_memory", Runtime.getRuntime().totalMemory()); + metrics.put("free_memory", Runtime.getRuntime().freeMemory()); + + // Network and Server Identity + InetAddress localHost = InetAddress.getLocalHost(); + metrics.put("ip_address", localHost.getHostAddress()); + metrics.put("hostname", localHost.getHostName()); + metrics.put("mac_address", getMacAddress()); + + // JVM info + metrics.put("jvm_vendor", System.getProperty("java.vendor")); + metrics.put("jvm_version", System.getProperty("java.vm.version")); + + // Locale and Timezone + metrics.put("system_language", System.getProperty("user.language")); + metrics.put("system_country", System.getProperty("user.country")); + metrics.put("timezone", TimeZone.getDefault().getID()); + metrics.put("locale", Locale.getDefault().toString()); + + // Disk info + File root = new File("."); + metrics.put("total_disk_space", root.getTotalSpace()); + metrics.put("free_disk_space", root.getFreeSpace()); + + // Process info + metrics.put("process_id", ProcessHandle.current().pid()); + + // JVM metrics + RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean(); + metrics.put("jvm_uptime_ms", runtimeMXBean.getUptime()); + metrics.put("jvm_start_time", runtimeMXBean.getStartTime()); + + // Memory metrics + MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean(); + metrics.put("heap_memory_usage", memoryMXBean.getHeapMemoryUsage().getUsed()); + metrics.put("non_heap_memory_usage", memoryMXBean.getNonHeapMemoryUsage().getUsed()); + + // CPU metrics + OperatingSystemMXBean osMXBean = ManagementFactory.getOperatingSystemMXBean(); + metrics.put("system_load_average", osMXBean.getSystemLoadAverage()); + + // Thread metrics + ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean(); + metrics.put("thread_count", threadMXBean.getThreadCount()); + metrics.put("daemon_thread_count", threadMXBean.getDaemonThreadCount()); + metrics.put("peak_thread_count", threadMXBean.getPeakThreadCount()); + + // Garbage collection metrics + for (GarbageCollectorMXBean gcBean : ManagementFactory.getGarbageCollectorMXBeans()) { + metrics.put("gc_" + gcBean.getName() + "_count", gcBean.getCollectionCount()); + metrics.put("gc_" + gcBean.getName() + "_time", gcBean.getCollectionTime()); + } + + // Network interfaces + metrics.put("network_interfaces", getNetworkInterfacesInfo()); + + // Docker detection and stats + boolean isDocker = isRunningInDocker(); + metrics.put("is_docker", isDocker); + if (isDocker) { + metrics.put("docker_metrics", getDockerMetrics()); + } + metrics.put("application_properties", captureApplicationProperties()); + + } catch (Exception e) { + metrics.put("error", e.getMessage()); + } + + return metrics; + } + + private boolean isRunningInDocker() { + return Files.exists(Paths.get("/.dockerenv")); + } + + private Map getDockerMetrics() { + Map dockerMetrics = new HashMap<>(); + + // Network-related Docker info + dockerMetrics.put("docker_network_mode", System.getenv("DOCKER_NETWORK_MODE")); + + // Container name (if set) + String containerName = System.getenv("CONTAINER_NAME"); + if (containerName != null && !containerName.isEmpty()) { + dockerMetrics.put("container_name", containerName); + } + + // Docker compose information + String composeProject = System.getenv("COMPOSE_PROJECT_NAME"); + String composeService = System.getenv("COMPOSE_SERVICE_NAME"); + if (composeProject != null && composeService != null) { + dockerMetrics.put("compose_project", composeProject); + dockerMetrics.put("compose_service", composeService); + } + + // Kubernetes-specific info (if running in K8s) + String k8sPodName = System.getenv("KUBERNETES_POD_NAME"); + if (k8sPodName != null) { + dockerMetrics.put("k8s_pod_name", k8sPodName); + dockerMetrics.put("k8s_namespace", System.getenv("KUBERNETES_NAMESPACE")); + dockerMetrics.put("k8s_node_name", System.getenv("KUBERNETES_NODE_NAME")); + } + + // New environment variables + dockerMetrics.put("version_tag", System.getenv("VERSION_TAG")); + dockerMetrics.put("docker_enable_security", System.getenv("DOCKER_ENABLE_SECURITY")); + dockerMetrics.put("fat_docker", System.getenv("FAT_DOCKER")); + + return dockerMetrics; + } + + private void addIfNotEmpty(Map map, String key, Object value) { + if (value != null) { + if (value instanceof String) { + String strValue = (String) value; + if (!StringUtils.isBlank(strValue)) { + map.put(key, strValue.trim()); + } + } else { + map.put(key, value); + } + } + } + + public Map captureApplicationProperties() { + Map properties = new HashMap<>(); + + // Capture Legal properties + addIfNotEmpty( + properties, + "legal_termsAndConditions", + applicationProperties.getLegal().getTermsAndConditions()); + addIfNotEmpty( + properties, + "legal_privacyPolicy", + applicationProperties.getLegal().getPrivacyPolicy()); + addIfNotEmpty( + properties, + "legal_accessibilityStatement", + applicationProperties.getLegal().getAccessibilityStatement()); + addIfNotEmpty( + properties, + "legal_cookiePolicy", + applicationProperties.getLegal().getCookiePolicy()); + addIfNotEmpty( + properties, "legal_impressum", applicationProperties.getLegal().getImpressum()); + + // Capture Security properties + addIfNotEmpty( + properties, + "security_enableLogin", + applicationProperties.getSecurity().getEnableLogin()); + addIfNotEmpty( + properties, + "security_csrfDisabled", + applicationProperties.getSecurity().getCsrfDisabled()); + addIfNotEmpty( + properties, + "security_loginAttemptCount", + applicationProperties.getSecurity().getLoginAttemptCount()); + addIfNotEmpty( + properties, + "security_loginResetTimeMinutes", + applicationProperties.getSecurity().getLoginResetTimeMinutes()); + addIfNotEmpty( + properties, + "security_loginMethod", + applicationProperties.getSecurity().getLoginMethod()); + + // Capture OAuth2 properties (excluding sensitive information) + addIfNotEmpty( + properties, + "security_oauth2_enabled", + applicationProperties.getSecurity().getOauth2().getEnabled()); + if (applicationProperties.getSecurity().getOauth2().getEnabled()) { + addIfNotEmpty( + properties, + "security_oauth2_autoCreateUser", + applicationProperties.getSecurity().getOauth2().getAutoCreateUser()); + addIfNotEmpty( + properties, + "security_oauth2_blockRegistration", + applicationProperties.getSecurity().getOauth2().getBlockRegistration()); + addIfNotEmpty( + properties, + "security_oauth2_useAsUsername", + applicationProperties.getSecurity().getOauth2().getUseAsUsername()); + addIfNotEmpty( + properties, + "security_oauth2_provider", + applicationProperties.getSecurity().getOauth2().getProvider()); + } + // Capture System properties + addIfNotEmpty( + properties, + "system_defaultLocale", + applicationProperties.getSystem().getDefaultLocale()); + addIfNotEmpty( + properties, + "system_googlevisibility", + applicationProperties.getSystem().getGooglevisibility()); + addIfNotEmpty( + properties, "system_showUpdate", applicationProperties.getSystem().isShowUpdate()); + addIfNotEmpty( + properties, + "system_showUpdateOnlyAdmin", + applicationProperties.getSystem().getShowUpdateOnlyAdmin()); + addIfNotEmpty( + properties, + "system_customHTMLFiles", + applicationProperties.getSystem().isCustomHTMLFiles()); + addIfNotEmpty( + properties, + "system_tessdataDir", + applicationProperties.getSystem().getTessdataDir()); + addIfNotEmpty( + properties, + "system_enableAlphaFunctionality", + applicationProperties.getSystem().getEnableAlphaFunctionality()); + addIfNotEmpty( + properties, + "system_enableAnalytics", + applicationProperties.getSystem().getEnableAnalytics()); + + // Capture UI properties + addIfNotEmpty(properties, "ui_appName", applicationProperties.getUi().getAppName()); + addIfNotEmpty( + properties, + "ui_homeDescription", + applicationProperties.getUi().getHomeDescription()); + addIfNotEmpty( + properties, "ui_appNameNavbar", applicationProperties.getUi().getAppNameNavbar()); + + // Capture Metrics properties + addIfNotEmpty( + properties, "metrics_enabled", applicationProperties.getMetrics().getEnabled()); + + // Capture EnterpriseEdition properties + addIfNotEmpty( + properties, + "enterpriseEdition_enabled", + applicationProperties.getEnterpriseEdition().isEnabled()); + if (applicationProperties.getEnterpriseEdition().isEnabled()) { + addIfNotEmpty( + properties, + "enterpriseEdition_customMetadata_autoUpdateMetadata", + applicationProperties + .getEnterpriseEdition() + .getCustomMetadata() + .isAutoUpdateMetadata()); + addIfNotEmpty( + properties, + "enterpriseEdition_customMetadata_author", + applicationProperties.getEnterpriseEdition().getCustomMetadata().getAuthor()); + addIfNotEmpty( + properties, + "enterpriseEdition_customMetadata_creator", + applicationProperties.getEnterpriseEdition().getCustomMetadata().getCreator()); + addIfNotEmpty( + properties, + "enterpriseEdition_customMetadata_producer", + applicationProperties.getEnterpriseEdition().getCustomMetadata().getProducer()); + } + // Capture AutoPipeline properties + addIfNotEmpty( + properties, + "autoPipeline_outputFolder", + applicationProperties.getAutoPipeline().getOutputFolder()); + + return properties; + } + + private String getMacAddress() { + try { + Enumeration networkInterfaces = + NetworkInterface.getNetworkInterfaces(); + while (networkInterfaces.hasMoreElements()) { + NetworkInterface ni = networkInterfaces.nextElement(); + byte[] hardwareAddress = ni.getHardwareAddress(); + if (hardwareAddress != null) { + String[] hexadecimal = new String[hardwareAddress.length]; + for (int i = 0; i < hardwareAddress.length; i++) { + hexadecimal[i] = String.format("%02X", hardwareAddress[i]); + } + return String.join("-", hexadecimal); + } + } + } catch (Exception e) { + // Handle exception + } + return "Unknown"; + } + + private Map getNetworkInterfacesInfo() { + Map interfacesInfo = new HashMap<>(); + try { + Enumeration nets = NetworkInterface.getNetworkInterfaces(); + while (nets.hasMoreElements()) { + NetworkInterface netint = nets.nextElement(); + interfacesInfo.put(netint.getName(), netint.getDisplayName()); + } + } catch (Exception e) { + interfacesInfo.put("error", e.getMessage()); + } + return interfacesInfo; + } +} diff --git a/src/main/java/stirling/software/SPDF/utils/CustomHtmlSanitizer.java b/src/main/java/stirling/software/SPDF/utils/CustomHtmlSanitizer.java new file mode 100644 index 00000000..587aae6f --- /dev/null +++ b/src/main/java/stirling/software/SPDF/utils/CustomHtmlSanitizer.java @@ -0,0 +1,21 @@ +package stirling.software.SPDF.utils; + +import org.owasp.html.HtmlPolicyBuilder; +import org.owasp.html.PolicyFactory; +import org.owasp.html.Sanitizers; + +public class CustomHtmlSanitizer { + private static final PolicyFactory POLICY = + Sanitizers.FORMATTING + .and(Sanitizers.BLOCKS) + .and(Sanitizers.STYLES) + .and(Sanitizers.LINKS) + .and(Sanitizers.TABLES) + .and(Sanitizers.IMAGES) + .and(new HtmlPolicyBuilder().disallowElements("noscript").toFactory()); + + public static String sanitize(String html) { + String htmlAfter = POLICY.sanitize(html); + return htmlAfter; + } +} diff --git a/src/main/java/stirling/software/SPDF/utils/FileToPdf.java b/src/main/java/stirling/software/SPDF/utils/FileToPdf.java index c7123424..d18277df 100644 --- a/src/main/java/stirling/software/SPDF/utils/FileToPdf.java +++ b/src/main/java/stirling/software/SPDF/utils/FileToPdf.java @@ -2,16 +2,23 @@ package stirling.software.SPDF.utils; import java.io.ByteArrayInputStream; import java.io.File; +import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.FileVisitResult; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; +import java.util.zip.ZipOutputStream; import io.github.pixee.security.ZipSecurity; @@ -33,19 +40,25 @@ public class FileToPdf { try { if (fileName.endsWith(".html")) { tempInputFile = Files.createTempFile("input_", ".html"); - Files.write(tempInputFile, fileBytes); - } else { + String sanitizedHtml = + sanitizeHtmlContent(new String(fileBytes, StandardCharsets.UTF_8)); + Files.write(tempInputFile, sanitizedHtml.getBytes(StandardCharsets.UTF_8)); + } else if (fileName.endsWith(".zip")) { tempInputFile = Files.createTempFile("input_", ".zip"); Files.write(tempInputFile, fileBytes); + sanitizeHtmlFilesInZip(tempInputFile); + } else { + throw new IllegalArgumentException("Unsupported file format: " + fileName); } List command = new ArrayList<>(); if (!htmlFormatsInstalled) { command.add("weasyprint"); - command.add("-e utf-8"); + command.add("-e"); + command.add("utf-8"); + command.add("-v"); command.add(tempInputFile.toString()); command.add(tempOutputFile.toString()); - } else { command.add("ebook-convert"); command.add(tempInputFile.toString()); @@ -54,10 +67,8 @@ public class FileToPdf { command.add("a4"); if (request != null && request.getZoom() != 1.0) { - // Create a temporary CSS file File tempCssFile = Files.createTempFile("customStyle", ".css").toFile(); try (FileWriter writer = new FileWriter(tempCssFile)) { - // Write the CSS rule to the file writer.write("body { zoom: " + request.getZoom() + "; }"); } command.add("--extra-css"); @@ -65,9 +76,7 @@ public class FileToPdf { } } - ProcessExecutorResult returnCode; - - returnCode = + ProcessExecutorResult returnCode = ProcessExecutor.getInstance(ProcessExecutor.Processes.WEASYPRINT) .runCommandWithOutputHandling(command); @@ -78,8 +87,6 @@ public class FileToPdf { throw e; } } finally { - - // Clean up temporary files Files.deleteIfExists(tempOutputFile); Files.deleteIfExists(tempInputFile); } @@ -87,6 +94,81 @@ public class FileToPdf { return pdfBytes; } + private static String sanitizeHtmlContent(String htmlContent) { + return CustomHtmlSanitizer.sanitize(htmlContent); + } + + private static void sanitizeHtmlFilesInZip(Path zipFilePath) throws IOException { + Path tempUnzippedDir = Files.createTempDirectory("unzipped_"); + try (ZipInputStream zipIn = + ZipSecurity.createHardenedInputStream( + new ByteArrayInputStream(Files.readAllBytes(zipFilePath)))) { + ZipEntry entry = zipIn.getNextEntry(); + while (entry != null) { + Path filePath = tempUnzippedDir.resolve(entry.getName()); + if (!entry.isDirectory()) { + Files.createDirectories(filePath.getParent()); + if (entry.getName().toLowerCase().endsWith(".html") + || entry.getName().toLowerCase().endsWith(".htm")) { + String content = new String(zipIn.readAllBytes(), StandardCharsets.UTF_8); + String sanitizedContent = sanitizeHtmlContent(content); + Files.write(filePath, sanitizedContent.getBytes(StandardCharsets.UTF_8)); + } else { + Files.copy(zipIn, filePath); + } + } + zipIn.closeEntry(); + entry = zipIn.getNextEntry(); + } + } + + // Repack the sanitized files + zipDirectory(tempUnzippedDir, zipFilePath); + + // Clean up + deleteDirectory(tempUnzippedDir); + } + + private static void zipDirectory(Path sourceDir, Path zipFilePath) throws IOException { + try (ZipOutputStream zos = + new ZipOutputStream(new FileOutputStream(zipFilePath.toFile()))) { + Files.walk(sourceDir) + .filter(path -> !Files.isDirectory(path)) + .forEach( + path -> { + ZipEntry zipEntry = + new ZipEntry(sourceDir.relativize(path).toString()); + try { + zos.putNextEntry(zipEntry); + Files.copy(path, zos); + zos.closeEntry(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + }); + } + } + + private static void deleteDirectory(Path dir) throws IOException { + Files.walkFileTree( + dir, + new SimpleFileVisitor() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) + throws IOException { + Files.delete(file); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(Path dir, IOException exc) + throws IOException { + Files.delete(dir); + return FileVisitResult.CONTINUE; + } + }); + } + private static Path unzipAndGetMainHtml(byte[] fileBytes) throws IOException { Path tempDirectory = Files.createTempDirectory("unzipped_"); try (ZipInputStream zipIn = diff --git a/src/main/java/stirling/software/SPDF/utils/GeneralUtils.java b/src/main/java/stirling/software/SPDF/utils/GeneralUtils.java index 21d921c8..8e56c8df 100644 --- a/src/main/java/stirling/software/SPDF/utils/GeneralUtils.java +++ b/src/main/java/stirling/software/SPDF/utils/GeneralUtils.java @@ -5,18 +5,28 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; +import java.net.InetAddress; import java.net.MalformedURLException; +import java.net.NetworkInterface; import java.net.URI; import java.net.URL; +import java.nio.charset.StandardCharsets; import java.nio.file.FileVisitResult; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.SimpleFileVisitor; import java.nio.file.attribute.BasicFileAttributes; +import java.security.MessageDigest; import java.util.ArrayList; +import java.util.Enumeration; import java.util.List; +import java.util.UUID; +import org.simpleyaml.configuration.file.YamlFile; +import org.simpleyaml.configuration.file.YamlFileWrapper; +import org.simpleyaml.configuration.implementation.SimpleYamlImplementation; +import org.simpleyaml.configuration.implementation.snakeyaml.lib.DumperOptions; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.multipart.MultipartFile; @@ -262,4 +272,81 @@ public class GeneralUtils { } return true; } + + public static boolean isValidUUID(String uuid) { + if (uuid == null) { + return false; + } + try { + UUID.fromString(uuid); + return true; + } catch (IllegalArgumentException e) { + return false; + } + } + + public static void saveKeyToConfig(String id, String key) throws IOException { + saveKeyToConfig(id, key, true); + } + + public static void saveKeyToConfig(String id, String key, boolean autoGenerated) + throws IOException { + Path path = Paths.get("configs", "settings.yml"); // Target the configs/settings.yml + + final YamlFile settingsYml = new YamlFile(path.toFile()); + DumperOptions yamlOptionssettingsYml = + ((SimpleYamlImplementation) settingsYml.getImplementation()).getDumperOptions(); + yamlOptionssettingsYml.setSplitLines(false); + + settingsYml.loadWithComments(); + + YamlFileWrapper writer = settingsYml.path(id).set(key); + if (autoGenerated) { + writer.comment("# Automatically Generated Settings (Do Not Edit Directly)"); + } + settingsYml.save(); + } + + public static String generateMachineFingerprint() { + try { + // Get the MAC address + StringBuilder sb = new StringBuilder(); + InetAddress ip = InetAddress.getLocalHost(); + NetworkInterface network = NetworkInterface.getByInetAddress(ip); + + if (network == null) { + Enumeration networks = NetworkInterface.getNetworkInterfaces(); + while (networks.hasMoreElements()) { + NetworkInterface net = networks.nextElement(); + byte[] mac = net.getHardwareAddress(); + if (mac != null) { + for (int i = 0; i < mac.length; i++) { + sb.append(String.format("%02X", mac[i])); + } + break; // Use the first network interface with a MAC address + } + } + } else { + byte[] mac = network.getHardwareAddress(); + if (mac != null) { + for (int i = 0; i < mac.length; i++) { + sb.append(String.format("%02X", mac[i])); + } + } + } + + // Hash the MAC address for privacy and consistency + MessageDigest md = MessageDigest.getInstance("SHA-256"); + byte[] hash = md.digest(sb.toString().getBytes(StandardCharsets.UTF_8)); + StringBuilder fingerprint = new StringBuilder(); + for (byte b : hash) { + fingerprint.append(String.format("%02x", b)); + } + + return fingerprint.toString(); + + } catch (Exception e) { + return "GenericID"; + } + } } diff --git a/src/main/java/stirling/software/SPDF/utils/PDFToFile.java b/src/main/java/stirling/software/SPDF/utils/PDFToFile.java index 920e987b..1a1957cf 100644 --- a/src/main/java/stirling/software/SPDF/utils/PDFToFile.java +++ b/src/main/java/stirling/software/SPDF/utils/PDFToFile.java @@ -191,7 +191,6 @@ public class PDFToFile { Files.deleteIfExists(tempInputFile); if (tempOutputDir != null) FileUtils.deleteDirectory(tempOutputDir.toFile()); } - System.out.println("fileBytes=" + fileBytes.length); return WebResponseUtils.bytesToWebResponse( fileBytes, fileName, MediaType.APPLICATION_OCTET_STREAM); } diff --git a/src/main/java/stirling/software/SPDF/utils/RequestUriUtils.java b/src/main/java/stirling/software/SPDF/utils/RequestUriUtils.java index 7aeab8e1..7033fa7a 100644 --- a/src/main/java/stirling/software/SPDF/utils/RequestUriUtils.java +++ b/src/main/java/stirling/software/SPDF/utils/RequestUriUtils.java @@ -17,6 +17,7 @@ public class RequestUriUtils { || requestURI.startsWith(contextPath + "/public/") || requestURI.startsWith(contextPath + "/pdfjs/") || requestURI.startsWith(contextPath + "/login") + || requestURI.startsWith(contextPath + "/error") || requestURI.endsWith(".svg") || requestURI.endsWith(".png") || requestURI.endsWith(".ico") diff --git a/src/main/java/stirling/software/SPDF/utils/misc/ReplaceAndInvertColorStrategy.java b/src/main/java/stirling/software/SPDF/utils/misc/ReplaceAndInvertColorStrategy.java index 87590731..024e0e70 100644 --- a/src/main/java/stirling/software/SPDF/utils/misc/ReplaceAndInvertColorStrategy.java +++ b/src/main/java/stirling/software/SPDF/utils/misc/ReplaceAndInvertColorStrategy.java @@ -6,11 +6,12 @@ import org.springframework.core.io.InputStreamResource; import org.springframework.web.multipart.MultipartFile; import lombok.Data; +import lombok.EqualsAndHashCode; import stirling.software.SPDF.model.api.PDFFile; import stirling.software.SPDF.model.api.misc.ReplaceAndInvert; @Data -// @EqualsAndHashCode(callSuper = true) +@EqualsAndHashCode(callSuper = true) public abstract class ReplaceAndInvertColorStrategy extends PDFFile { protected ReplaceAndInvert replaceAndInvert; diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index cae1dce3..0f957c0a 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -27,9 +27,9 @@ server.servlet.context-path=${SYSTEM_ROOTURIPATH:/} spring.devtools.restart.enabled=true spring.devtools.livereload.enabled=true - spring.thymeleaf.encoding=UTF-8 +spring.web.resources.mime-mappings.webmanifest=application/manifest+json spring.mvc.async.request-timeout=${SYSTEM_CONNECTIONTIMEOUTMILLISECONDS:1200000} #spring.thymeleaf.prefix=file:/customFiles/templates/,classpath:/templates/ @@ -41,7 +41,7 @@ spring.datasource.username=sa spring.datasource.password= spring.h2.console.enabled=false spring.jpa.hibernate.ddl-auto=update - +server.servlet.session.timeout: 30m # Change the default URL path for OpenAPI JSON springdoc.api-docs.path=/v1/api-docs @@ -49,3 +49,5 @@ springdoc.api-docs.path=/v1/api-docs springdoc.swagger-ui.url=/v1/api-docs +posthog.api.key=phc_fiR65u5j6qmXTYL56MNrLZSWqLaDW74OrZH0Insd2xq +posthog.host=https://eu.i.posthog.com \ No newline at end of file diff --git a/src/main/resources/messages_ar_AR.properties b/src/main/resources/messages_ar_AR.properties index 19fe9944..0c2f6188 100644 --- a/src/main/resources/messages_ar_AR.properties +++ b/src/main/resources/messages_ar_AR.properties @@ -76,6 +76,7 @@ donate=تبرع color=لون sponsor=راعٍ info=معلومات +pro=Pro page=Page pages=Pages @@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=خط الأنابيب: pipelineOptions.saveButton=تنزيل pipelineOptions.validateButton=تحقق +######################## +# ENTERPRISE EDITION # +######################## +enterpriseEdition.button=Upgrade to Pro +enterpriseEdition.warning=This feature is only available to Pro users. +enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features. +enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro +################# +# Analytics # +################# +analytics.title=Do you want make Stirling PDF better? +analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents. +analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better. +analytics.enable=Enable analytics +analytics.disable=Disable analytics +analytics.settings=You can change the settings for analytics in the config/settings.yml file ############# # NAVBAR # @@ -128,6 +145,7 @@ navbar.sections.convertFrom=تحويل من PDF navbar.sections.security=التوقيع والأمان navbar.sections.advance=متقدم navbar.sections.edit=عرض وتعديل +navbar.sections.popular=Popular ############# # SETTINGS # @@ -225,6 +243,8 @@ database.fileNotFound=لم يتم العثور على الملف database.fileNullOrEmpty=يجب ألا يكون الملف فارغًا أو خاليًا database.failedImportFile=فشل استيراد الملف +session.expired=Your session has expired. Please refresh the page and try again. + ############# # HOME-PAGE # ############# @@ -382,7 +402,7 @@ home.scalePages.title=ضبط حجم/مقياس الصفحة home.scalePages.desc=تغيير حجم/مقياس الصفحة و/أو محتواها. scalePages.tags=تغيير الحجم,تعديل,الأبعاد,تكييف -home.pipeline.title=خط الأنابيب (متقدم) +home.pipeline.title=خط الأنابيب home.pipeline.desc=تشغيل إجراءات متعددة على ملفات PDF عن طريق تحديد نصوص خط الأنابيب pipeline.tags=أتمتة,تسلسل,مبرمج,معالجة دفعات @@ -482,6 +502,11 @@ home.removeImagePdf.title=إزالة الصورة home.removeImagePdf.desc=إزالة الصورة من PDF لتقليل حجم الملف removeImagePdf.tags=إزالة الصورة,عمليات الصفحة,الخلفية,جانب الخادم + +home.splitPdfByChapters.title=Split PDF by Chapters +home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure. +splitPdfByChapters.tags=split,chapters,bookmarks,organize + #replace-invert-color replace-color.title=Replace-Invert-Color replace-color.header=Replace-Invert Color PDF @@ -526,7 +551,10 @@ login.oauth2AccessDenied=تم رفض الوصول login.oauth2InvalidTokenResponse=استجابة الرمز المميز غير صالحة login.oauth2InvalidIdToken=رمز الهوية غير صالح login.userIsDisabled=تم تعطيل المستخدم، تم حظر تسجيل الدخول حاليًا باستخدام اسم المستخدم هذا. يرجى الاتصال بالمسؤول. - +login.alreadyLoggedIn=You are already logged in to +login.alreadyLoggedIn2=devices. Please log out of the devices and try again. +login.toManySessions=You have too many active sessions +login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro. #auto-redact autoRedact.title=حجب تلقائي @@ -1154,6 +1182,8 @@ licenses.license=الترخيص survey.nav=استطلاع survey.title=استطلاع Stirling-PDF survey.description=Stirling-PDF لا يحتوي على تتبع لذا نريد أن نسمع من مستخدمينا لتحسين Stirling-PDF! +survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here: +survey.changes2=With these changes we are getting paid business support and funding survey.please=يرجى النظر في المشاركة في استطلاعنا! survey.disabled=(سيتم تعطيل النافذة المنبثقة للاستطلاع في التحديثات التالية ولكنها ستكون متاحة في أسفل الصفحة) survey.button=المشاركة في الاستطلاع @@ -1179,3 +1209,17 @@ removeImage.title=إزالة الصورة removeImage.header=إزالة الصورة removeImage.removeImage=إزالة الصورة removeImage.submit=إزالة الصورة + + +splitByChapters.title=Split PDF by Chapters +splitByChapters.header=Split PDF by Chapters +splitByChapters.bookmarkLevel=Bookmark Level +splitByChapters.includeMetadata=Include Metadata +splitByChapters.allowDuplicates=Allow Duplicates +splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure. +splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.). +splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF. +splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs. +splitByChapters.submit=Split PDF + + diff --git a/src/main/resources/messages_bg_BG.properties b/src/main/resources/messages_bg_BG.properties index 2e224ba7..54db6e89 100644 --- a/src/main/resources/messages_bg_BG.properties +++ b/src/main/resources/messages_bg_BG.properties @@ -76,6 +76,7 @@ donate=Направете дарение color=Цвят sponsor=Спонсор info=Info +pro=Pro page=Page pages=Pages @@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Pipeline: pipelineOptions.saveButton=Изтегли pipelineOptions.validateButton=Валидирай +######################## +# ENTERPRISE EDITION # +######################## +enterpriseEdition.button=Upgrade to Pro +enterpriseEdition.warning=This feature is only available to Pro users. +enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features. +enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro +################# +# Analytics # +################# +analytics.title=Do you want make Stirling PDF better? +analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents. +analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better. +analytics.enable=Enable analytics +analytics.disable=Disable analytics +analytics.settings=You can change the settings for analytics in the config/settings.yml file ############# # NAVBAR # @@ -128,6 +145,7 @@ navbar.sections.convertFrom=Преобразуване от PDF navbar.sections.security=Подписване и сигурност navbar.sections.advance=Разширено navbar.sections.edit=Преглед и редактиране +navbar.sections.popular=Popular ############# # SETTINGS # @@ -225,6 +243,8 @@ database.fileNotFound=File not Found database.fileNullOrEmpty=File must not be null or empty database.failedImportFile=Failed Import File +session.expired=Your session has expired. Please refresh the page and try again. + ############# # HOME-PAGE # ############# @@ -482,6 +502,11 @@ home.removeImagePdf.title=Remove image home.removeImagePdf.desc=Remove image from PDF to reduce file size removeImagePdf.tags=Remove Image,Page operations,Back end,server side + +home.splitPdfByChapters.title=Split PDF by Chapters +home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure. +splitPdfByChapters.tags=split,chapters,bookmarks,organize + #replace-invert-color replace-color.title=Replace-Invert-Color replace-color.header=Replace-Invert Color PDF @@ -526,7 +551,10 @@ login.oauth2AccessDenied=Отказан достъп login.oauth2InvalidTokenResponse=Невалиден отговор на токена login.oauth2InvalidIdToken=Невалиден токен за идентификатор login.userIsDisabled=User is deactivated, login is currently blocked with this username. Please contact the administrator. - +login.alreadyLoggedIn=You are already logged in to +login.alreadyLoggedIn2=devices. Please log out of the devices and try again. +login.toManySessions=You have too many active sessions +login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro. #auto-redact autoRedact.title=Автоматично редактиране @@ -1154,6 +1182,8 @@ licenses.license=Лиценз survey.nav=Survey survey.title=Stirling-PDF Survey survey.description=Stirling-PDF has no tracking so we want to hear from our users to improve Stirling-PDF! +survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here: +survey.changes2=With these changes we are getting paid business support and funding survey.please=Please consider taking our survey! survey.disabled=(Survey popup will be disabled in following updates but available at foot of page) survey.button=Take Survey @@ -1179,3 +1209,17 @@ removeImage.title=Remove image removeImage.header=Remove image removeImage.removeImage=Remove image removeImage.submit=Remove image + + +splitByChapters.title=Split PDF by Chapters +splitByChapters.header=Split PDF by Chapters +splitByChapters.bookmarkLevel=Bookmark Level +splitByChapters.includeMetadata=Include Metadata +splitByChapters.allowDuplicates=Allow Duplicates +splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure. +splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.). +splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF. +splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs. +splitByChapters.submit=Split PDF + + diff --git a/src/main/resources/messages_ca_CA.properties b/src/main/resources/messages_ca_CA.properties index 48ffcb69..7c4967f7 100644 --- a/src/main/resources/messages_ca_CA.properties +++ b/src/main/resources/messages_ca_CA.properties @@ -76,6 +76,7 @@ donate=Donate color=Color sponsor=Sponsor info=Info +pro=Pro page=Page pages=Pages @@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Pipeline: pipelineOptions.saveButton=Download pipelineOptions.validateButton=Validate +######################## +# ENTERPRISE EDITION # +######################## +enterpriseEdition.button=Upgrade to Pro +enterpriseEdition.warning=This feature is only available to Pro users. +enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features. +enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro +################# +# Analytics # +################# +analytics.title=Do you want make Stirling PDF better? +analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents. +analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better. +analytics.enable=Enable analytics +analytics.disable=Disable analytics +analytics.settings=You can change the settings for analytics in the config/settings.yml file ############# # NAVBAR # @@ -128,6 +145,7 @@ navbar.sections.convertFrom=Convert from PDF navbar.sections.security=Sign & Security navbar.sections.advance=Advanced navbar.sections.edit=View & Edit +navbar.sections.popular=Popular ############# # SETTINGS # @@ -225,6 +243,8 @@ database.fileNotFound=File not Found database.fileNullOrEmpty=File must not be null or empty database.failedImportFile=Failed Import File +session.expired=Your session has expired. Please refresh the page and try again. + ############# # HOME-PAGE # ############# @@ -382,7 +402,7 @@ home.scalePages.title=Adjust page size/scale home.scalePages.desc=Change the size/scale of page and/or its contents. scalePages.tags=resize,modify,dimension,adapt -home.pipeline.title=Pipeline (Advanced) +home.pipeline.title=Pipeline home.pipeline.desc=Run multiple actions on PDFs by defining pipeline scripts pipeline.tags=automate,sequence,scripted,batch-process @@ -482,6 +502,11 @@ home.removeImagePdf.title=Remove image home.removeImagePdf.desc=Remove image from PDF to reduce file size removeImagePdf.tags=Remove Image,Page operations,Back end,server side + +home.splitPdfByChapters.title=Split PDF by Chapters +home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure. +splitPdfByChapters.tags=split,chapters,bookmarks,organize + #replace-invert-color replace-color.title=Replace-Invert-Color replace-color.header=Replace-Invert Color PDF @@ -526,7 +551,10 @@ login.oauth2AccessDenied=Access Denied login.oauth2InvalidTokenResponse=Invalid Token Response login.oauth2InvalidIdToken=Invalid Id Token login.userIsDisabled=User is deactivated, login is currently blocked with this username. Please contact the administrator. - +login.alreadyLoggedIn=You are already logged in to +login.alreadyLoggedIn2=devices. Please log out of the devices and try again. +login.toManySessions=You have too many active sessions +login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro. #auto-redact autoRedact.title=Auto Redact @@ -1154,6 +1182,8 @@ licenses.license=License survey.nav=Survey survey.title=Stirling-PDF Survey survey.description=Stirling-PDF has no tracking so we want to hear from our users to improve Stirling-PDF! +survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here: +survey.changes2=With these changes we are getting paid business support and funding survey.please=Please consider taking our survey! survey.disabled=(Survey popup will be disabled in following updates but available at foot of page) survey.button=Take Survey @@ -1179,3 +1209,17 @@ removeImage.title=Remove image removeImage.header=Remove image removeImage.removeImage=Remove image removeImage.submit=Remove image + + +splitByChapters.title=Split PDF by Chapters +splitByChapters.header=Split PDF by Chapters +splitByChapters.bookmarkLevel=Bookmark Level +splitByChapters.includeMetadata=Include Metadata +splitByChapters.allowDuplicates=Allow Duplicates +splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure. +splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.). +splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF. +splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs. +splitByChapters.submit=Split PDF + + diff --git a/src/main/resources/messages_cs_CZ.properties b/src/main/resources/messages_cs_CZ.properties index 4f4ec782..6798197a 100644 --- a/src/main/resources/messages_cs_CZ.properties +++ b/src/main/resources/messages_cs_CZ.properties @@ -76,6 +76,7 @@ donate=Přispějte color=Barva sponsor=Sponzor info=Info +pro=Pro page=Page pages=Pages @@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Pipeline: pipelineOptions.saveButton=Stáhnout pipelineOptions.validateButton=Ověřit +######################## +# ENTERPRISE EDITION # +######################## +enterpriseEdition.button=Upgrade to Pro +enterpriseEdition.warning=This feature is only available to Pro users. +enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features. +enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro +################# +# Analytics # +################# +analytics.title=Do you want make Stirling PDF better? +analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents. +analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better. +analytics.enable=Enable analytics +analytics.disable=Disable analytics +analytics.settings=You can change the settings for analytics in the config/settings.yml file ############# # NAVBAR # @@ -128,6 +145,7 @@ navbar.sections.convertFrom=Převést z PDF navbar.sections.security=Podpis a Bezpečnost navbar.sections.advance=Pokročilé navbar.sections.edit=Prohlédnout a Upravit +navbar.sections.popular=Popular ############# # SETTINGS # @@ -225,6 +243,8 @@ database.fileNotFound=File not Found database.fileNullOrEmpty=File must not be null or empty database.failedImportFile=Failed Import File +session.expired=Your session has expired. Please refresh the page and try again. + ############# # HOME-PAGE # ############# @@ -382,7 +402,7 @@ home.scalePages.title=Upravit velikost/škálu stránky home.scalePages.desc=Změnit velikost/škálu stránky a/nebo její obsah. scalePages.tags=změnit velikost,upravit,rozměr,přizpůsobit -home.pipeline.title=Potrubí (Pokročilé) +home.pipeline.title=Potrubí home.pipeline.desc=Spustit více akcí na PDF s definicí skriptů potrubí pipeline.tags=automatizovat,sekvence,skriptované,dávkové zpracování @@ -482,6 +502,11 @@ home.removeImagePdf.title=Remove image home.removeImagePdf.desc=Remove image from PDF to reduce file size removeImagePdf.tags=Remove Image,Page operations,Back end,server side + +home.splitPdfByChapters.title=Split PDF by Chapters +home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure. +splitPdfByChapters.tags=split,chapters,bookmarks,organize + #replace-invert-color replace-color.title=Replace-Invert-Color replace-color.header=Replace-Invert Color PDF @@ -526,7 +551,10 @@ login.oauth2AccessDenied=Access Denied login.oauth2InvalidTokenResponse=Invalid Token Response login.oauth2InvalidIdToken=Invalid Id Token login.userIsDisabled=User is deactivated, login is currently blocked with this username. Please contact the administrator. - +login.alreadyLoggedIn=You are already logged in to +login.alreadyLoggedIn2=devices. Please log out of the devices and try again. +login.toManySessions=You have too many active sessions +login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro. #auto-redact autoRedact.title=Auto Redact @@ -1154,6 +1182,8 @@ licenses.license=Licence survey.nav=Survey survey.title=Stirling-PDF Survey survey.description=Stirling-PDF has no tracking so we want to hear from our users to improve Stirling-PDF! +survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here: +survey.changes2=With these changes we are getting paid business support and funding survey.please=Please consider taking our survey! survey.disabled=(Survey popup will be disabled in following updates but available at foot of page) survey.button=Take Survey @@ -1179,3 +1209,17 @@ removeImage.title=Remove image removeImage.header=Remove image removeImage.removeImage=Remove image removeImage.submit=Remove image + + +splitByChapters.title=Split PDF by Chapters +splitByChapters.header=Split PDF by Chapters +splitByChapters.bookmarkLevel=Bookmark Level +splitByChapters.includeMetadata=Include Metadata +splitByChapters.allowDuplicates=Allow Duplicates +splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure. +splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.). +splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF. +splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs. +splitByChapters.submit=Split PDF + + diff --git a/src/main/resources/messages_da_DK.properties b/src/main/resources/messages_da_DK.properties index 7e2c4538..667d8434 100644 --- a/src/main/resources/messages_da_DK.properties +++ b/src/main/resources/messages_da_DK.properties @@ -76,6 +76,7 @@ donate=Donér color=Farve sponsor=Sponsor info=Info +pro=Pro page=Page pages=Pages @@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Pipeline: pipelineOptions.saveButton=Download pipelineOptions.validateButton=Validér +######################## +# ENTERPRISE EDITION # +######################## +enterpriseEdition.button=Upgrade to Pro +enterpriseEdition.warning=This feature is only available to Pro users. +enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features. +enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro +################# +# Analytics # +################# +analytics.title=Do you want make Stirling PDF better? +analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents. +analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better. +analytics.enable=Enable analytics +analytics.disable=Disable analytics +analytics.settings=You can change the settings for analytics in the config/settings.yml file ############# # NAVBAR # @@ -128,6 +145,7 @@ navbar.sections.convertFrom=Konvertér fra PDF navbar.sections.security=Signér & Sikkerhed navbar.sections.advance=Avanceret navbar.sections.edit=Vis & Redigér +navbar.sections.popular=Popular ############# # SETTINGS # @@ -225,6 +243,8 @@ database.fileNotFound=Fil ikke fundet database.fileNullOrEmpty=Fil må ikke være null eller tom database.failedImportFile=Kunne ikke importere fil +session.expired=Your session has expired. Please refresh the page and try again. + ############# # HOME-PAGE # ############# @@ -482,6 +502,11 @@ home.removeImagePdf.title=Fjern billede home.removeImagePdf.desc=Fjern billede fra PDF for at reducere filstørrelse removeImagePdf.tags=Fjern Billede,Sideoperationer,Back end,server side + +home.splitPdfByChapters.title=Split PDF by Chapters +home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure. +splitPdfByChapters.tags=split,chapters,bookmarks,organize + #replace-invert-color replace-color.title=Replace-Invert-Color replace-color.header=Replace-Invert Color PDF @@ -526,7 +551,10 @@ login.oauth2AccessDenied=Adgang Nægtet login.oauth2InvalidTokenResponse=Ugyldigt Token Svar login.oauth2InvalidIdToken=Ugyldigt Id Token login.userIsDisabled=Bruger er deaktiveret, login er i øjeblikket blokeret med dette brugernavn. Kontakt venligst administratoren. - +login.alreadyLoggedIn=You are already logged in to +login.alreadyLoggedIn2=devices. Please log out of the devices and try again. +login.toManySessions=You have too many active sessions +login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro. #auto-redact autoRedact.title=Auto Rediger @@ -1154,6 +1182,8 @@ licenses.license=License survey.nav=Undersøgelse survey.title=Stirling-PDF Undersøgelse survey.description=Stirling-PDF har ingen sporing, så vi vil gerne høre fra vores brugere for at forbedre Stirling-PDF! +survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here: +survey.changes2=With these changes we are getting paid business support and funding survey.please=Overvej venligst at deltage i vores undersøgelse! survey.disabled=(Undersøgelsespop-up vil blive deaktiveret i følgende opdateringer, men vil være tilgængelig i bunden af siden) survey.button=Tag Undersøgelsen @@ -1179,3 +1209,17 @@ removeImage.title=Fjern billede removeImage.header=Fjern billede removeImage.removeImage=Fjern billede removeImage.submit=Fjern + + +splitByChapters.title=Split PDF by Chapters +splitByChapters.header=Split PDF by Chapters +splitByChapters.bookmarkLevel=Bookmark Level +splitByChapters.includeMetadata=Include Metadata +splitByChapters.allowDuplicates=Allow Duplicates +splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure. +splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.). +splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF. +splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs. +splitByChapters.submit=Split PDF + + diff --git a/src/main/resources/messages_de_DE.properties b/src/main/resources/messages_de_DE.properties index e156dbf2..ddaa0dbd 100644 --- a/src/main/resources/messages_de_DE.properties +++ b/src/main/resources/messages_de_DE.properties @@ -76,6 +76,7 @@ donate=Spenden color=Farbe sponsor=Sponsor info=Informationen +pro=Pro page=Page pages=Pages @@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Pipeline: pipelineOptions.saveButton=Herunterladen pipelineOptions.validateButton=Validieren +######################## +# ENTERPRISE EDITION # +######################## +enterpriseEdition.button=Upgrade to Pro +enterpriseEdition.warning=This feature is only available to Pro users. +enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features. +enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro +################# +# Analytics # +################# +analytics.title=Do you want make Stirling PDF better? +analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents. +analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better. +analytics.enable=Enable analytics +analytics.disable=Disable analytics +analytics.settings=You can change the settings for analytics in the config/settings.yml file ############# # NAVBAR # @@ -128,6 +145,7 @@ navbar.sections.convertFrom=Konvertieren von PDF navbar.sections.security=Zeichen und Sicherheit navbar.sections.advance=Fortschrittlich navbar.sections.edit=Anzeigen und Bearbeiten +navbar.sections.popular=Popular ############# # SETTINGS # @@ -225,6 +243,8 @@ database.fileNotFound=Datei nicht gefunden database.fileNullOrEmpty=Datei darf nicht null oder leer sein database.failedImportFile=Dateiimport fehlgeschlagen +session.expired=Your session has expired. Please refresh the page and try again. + ############# # HOME-PAGE # ############# @@ -382,7 +402,7 @@ home.scalePages.title=Seitengröße/Skalierung anpassen home.scalePages.desc=Größe/Skalierung der Seite und/oder des Inhalts ändern scalePages.tags=größe ändern,ändern,dimensionieren,anpassen -home.pipeline.title=Pipeline (Fortgeschritten) +home.pipeline.title=Pipeline home.pipeline.desc=Mehrere Aktionen auf ein PDF anwenden, definiert durch ein Pipeline Skript pipeline.tags=automatisieren,sequenzieren,skriptgesteuert,batch prozess @@ -482,6 +502,11 @@ home.removeImagePdf.title=Bild entfernen home.removeImagePdf.desc=Bild aus PDF entfernen, um die Dateigröße zu verringern removeImagePdf.tags=bild entfernen,seitenoperationen,back end,server side + +home.splitPdfByChapters.title=Split PDF by Chapters +home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure. +splitPdfByChapters.tags=split,chapters,bookmarks,organize + #replace-invert-color replace-color.title=Replace-Invert-Color replace-color.header=Replace-Invert Color PDF @@ -526,7 +551,10 @@ login.oauth2AccessDenied=Zugriff abgelehnt login.oauth2InvalidTokenResponse=Ungültige Token-Antwort login.oauth2InvalidIdToken=Ungültiges ID-Token login.userIsDisabled=Benutzer ist deaktiviert, die Anmeldung ist mit diesem Benutzernamen derzeit gesperrt. Bitte wenden Sie sich an den Administrator. - +login.alreadyLoggedIn=You are already logged in to +login.alreadyLoggedIn2=devices. Please log out of the devices and try again. +login.toManySessions=You have too many active sessions +login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro. #auto-redact autoRedact.title=Automatisch zensieren/schwärzen @@ -1154,6 +1182,8 @@ licenses.license=Lizenz survey.nav=Umfrage survey.title=Stirling-PDF-Umfrage survey.description=Stirling-PDF hat kein Tracking, daher möchten wir von unseren Benutzern hören, wie wir Stirling-PDF verbessern können! +survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here: +survey.changes2=With these changes we are getting paid business support and funding survey.please=Bitte nehmen Sie an unserer Umfrage teil! survey.disabled=(Das Umfrage-Popup wird in folgenden Updates deaktiviert, ist aber am Fuß der Seite verfügbar.) survey.button=Umfrage durchführen @@ -1179,3 +1209,17 @@ removeImage.title=Bild entfernen removeImage.header=Bild entfernen removeImage.removeImage=Bild entfernen removeImage.submit=Bild entfernen + + +splitByChapters.title=Split PDF by Chapters +splitByChapters.header=Split PDF by Chapters +splitByChapters.bookmarkLevel=Bookmark Level +splitByChapters.includeMetadata=Include Metadata +splitByChapters.allowDuplicates=Allow Duplicates +splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure. +splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.). +splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF. +splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs. +splitByChapters.submit=Split PDF + + diff --git a/src/main/resources/messages_el_GR.properties b/src/main/resources/messages_el_GR.properties index b19770e0..3154db02 100644 --- a/src/main/resources/messages_el_GR.properties +++ b/src/main/resources/messages_el_GR.properties @@ -76,6 +76,7 @@ donate=Δωρισε color=Χρώμα sponsor=Yποστηρικτής info=Info +pro=Pro page=Page pages=Pages @@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Pipeline: pipelineOptions.saveButton=Λήψη pipelineOptions.validateButton=Επικυρώνω +######################## +# ENTERPRISE EDITION # +######################## +enterpriseEdition.button=Upgrade to Pro +enterpriseEdition.warning=This feature is only available to Pro users. +enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features. +enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro +################# +# Analytics # +################# +analytics.title=Do you want make Stirling PDF better? +analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents. +analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better. +analytics.enable=Enable analytics +analytics.disable=Disable analytics +analytics.settings=You can change the settings for analytics in the config/settings.yml file ############# # NAVBAR # @@ -128,6 +145,7 @@ navbar.sections.convertFrom=Convert from PDF navbar.sections.security=Sign & Security navbar.sections.advance=Advanced navbar.sections.edit=View & Edit +navbar.sections.popular=Popular ############# # SETTINGS # @@ -225,6 +243,8 @@ database.fileNotFound=File not Found database.fileNullOrEmpty=File must not be null or empty database.failedImportFile=Failed Import File +session.expired=Your session has expired. Please refresh the page and try again. + ############# # HOME-PAGE # ############# @@ -482,6 +502,11 @@ home.removeImagePdf.title=Remove image home.removeImagePdf.desc=Remove image from PDF to reduce file size removeImagePdf.tags=Remove Image,Page operations,Back end,server side + +home.splitPdfByChapters.title=Split PDF by Chapters +home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure. +splitPdfByChapters.tags=split,chapters,bookmarks,organize + #replace-invert-color replace-color.title=Replace-Invert-Color replace-color.header=Replace-Invert Color PDF @@ -526,7 +551,10 @@ login.oauth2AccessDenied=Access Denied login.oauth2InvalidTokenResponse=Invalid Token Response login.oauth2InvalidIdToken=Invalid Id Token login.userIsDisabled=User is deactivated, login is currently blocked with this username. Please contact the administrator. - +login.alreadyLoggedIn=You are already logged in to +login.alreadyLoggedIn2=devices. Please log out of the devices and try again. +login.toManySessions=You have too many active sessions +login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro. #auto-redact autoRedact.title=Αυτόματο Μαύρισμα Κειμένου @@ -1154,6 +1182,8 @@ licenses.license=Άδεια survey.nav=Survey survey.title=Stirling-PDF Survey survey.description=Stirling-PDF has no tracking so we want to hear from our users to improve Stirling-PDF! +survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here: +survey.changes2=With these changes we are getting paid business support and funding survey.please=Please consider taking our survey! survey.disabled=(Survey popup will be disabled in following updates but available at foot of page) survey.button=Take Survey @@ -1179,3 +1209,17 @@ removeImage.title=Remove image removeImage.header=Remove image removeImage.removeImage=Remove image removeImage.submit=Remove image + + +splitByChapters.title=Split PDF by Chapters +splitByChapters.header=Split PDF by Chapters +splitByChapters.bookmarkLevel=Bookmark Level +splitByChapters.includeMetadata=Include Metadata +splitByChapters.allowDuplicates=Allow Duplicates +splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure. +splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.). +splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF. +splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs. +splitByChapters.submit=Split PDF + + diff --git a/src/main/resources/messages_en_GB.properties b/src/main/resources/messages_en_GB.properties index dbebccc0..6cdfaadb 100644 --- a/src/main/resources/messages_en_GB.properties +++ b/src/main/resources/messages_en_GB.properties @@ -76,6 +76,7 @@ donate=Donate color=Color sponsor=Sponsor info=Info +pro=Pro page=Page pages=Pages @@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Pipeline: pipelineOptions.saveButton=Download pipelineOptions.validateButton=Validate +######################## +# ENTERPRISE EDITION # +######################## +enterpriseEdition.button=Upgrade to Pro +enterpriseEdition.warning=This feature is only available to Pro users. +enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features. +enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro +################# +# Analytics # +################# +analytics.title=Do you want make Stirling PDF better? +analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents. +analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better. +analytics.enable=Enable analytics +analytics.disable=Disable analytics +analytics.settings=You can change the settings for analytics in the config/settings.yml file ############# # NAVBAR # @@ -128,6 +145,7 @@ navbar.sections.convertFrom=Convert from PDF navbar.sections.security=Sign & Security navbar.sections.advance=Advanced navbar.sections.edit=View & Edit +navbar.sections.popular=Popular ############# # SETTINGS # @@ -225,6 +243,8 @@ database.fileNotFound=File not found database.fileNullOrEmpty=File must not be null or empty database.failedImportFile=Failed to import file +session.expired=Your session has expired. Please refresh the page and try again. + ############# # HOME-PAGE # ############# @@ -382,7 +402,7 @@ home.scalePages.title=Adjust page size/scale home.scalePages.desc=Change the size/scale of a page and/or its contents. scalePages.tags=resize,modify,dimension,adapt -home.pipeline.title=Pipeline (Advanced) +home.pipeline.title=Pipeline home.pipeline.desc=Run multiple actions on PDFs by defining pipeline scripts pipeline.tags=automate,sequence,scripted,batch-process @@ -482,10 +502,15 @@ home.removeImagePdf.title=Remove image home.removeImagePdf.desc=Remove image from PDF to reduce file size removeImagePdf.tags=Remove Image,Page operations,Back end,server side + +home.splitPdfByChapters.title=Split PDF by Chapters +home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure. +splitPdfByChapters.tags=split,chapters,bookmarks,organize + #replace-invert-color -replace-color.title=Replace-Invert-Color +replace-color.title=Advanced Colour options replace-color.header=Replace-Invert Color PDF -home.replaceColorPdf.title=Replace and Invert Color +home.replaceColorPdf.title=Advanced Colour options home.replaceColorPdf.desc=Replace color for text and background in PDF and invert full color of pdf to reduce file size replaceColorPdf.tags=Replace Color,Page operations,Back end,server side replace-color.selectText.1=Replace or Invert color Options @@ -526,7 +551,10 @@ login.oauth2AccessDenied=Access Denied login.oauth2InvalidTokenResponse=Invalid Token Response login.oauth2InvalidIdToken=Invalid Id Token login.userIsDisabled=User is deactivated, login is currently blocked with this username. Please contact the administrator. - +login.alreadyLoggedIn=You are already logged in to +login.alreadyLoggedIn2=devices. Please log out of the devices and try again. +login.toManySessions=You have too many active sessions +login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro. #auto-redact autoRedact.title=Auto Redact @@ -1154,7 +1182,9 @@ licenses.license=Licence survey.nav=Survey survey.title=Stirling-PDF Survey survey.description=Stirling-PDF has no tracking so we want to hear from our users to improve Stirling-PDF! -survey.please=Please consider taking our survey! +survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here: +survey.changes2=With these changes we are getting paid business support and funding +survey.please=Please consider taking our survey to have input on the future of Stirling-PDF! survey.disabled=(Survey popup will be disabled in following updates but available at foot of page) survey.button=Take Survey survey.dontShowAgain=Don't show again @@ -1179,3 +1209,17 @@ removeImage.title=Remove image removeImage.header=Remove image removeImage.removeImage=Remove image removeImage.submit=Remove image + + +splitByChapters.title=Split PDF by Chapters +splitByChapters.header=Split PDF by Chapters +splitByChapters.bookmarkLevel=Bookmark Level +splitByChapters.includeMetadata=Include Metadata +splitByChapters.allowDuplicates=Allow Duplicates +splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure. +splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.). +splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF. +splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs. +splitByChapters.submit=Split PDF + + diff --git a/src/main/resources/messages_en_US.properties b/src/main/resources/messages_en_US.properties index 6ea5dd95..41bd756a 100644 --- a/src/main/resources/messages_en_US.properties +++ b/src/main/resources/messages_en_US.properties @@ -76,6 +76,7 @@ donate=Donate color=Color sponsor=Sponsor info=Info +pro=Pro page=Page pages=Pages @@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Pipeline: pipelineOptions.saveButton=Download pipelineOptions.validateButton=Validate +######################## +# ENTERPRISE EDITION # +######################## +enterpriseEdition.button=Upgrade to Pro +enterpriseEdition.warning=This feature is only available to Pro users. +enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features. +enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro +################# +# Analytics # +################# +analytics.title=Do you want make Stirling PDF better? +analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents. +analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better. +analytics.enable=Enable analytics +analytics.disable=Disable analytics +analytics.settings=You can change the settings for analytics in the config/settings.yml file ############# # NAVBAR # @@ -128,6 +145,7 @@ navbar.sections.convertFrom=Convert from PDF navbar.sections.security=Sign & Security navbar.sections.advance=Advanced navbar.sections.edit=View & Edit +navbar.sections.popular=Popular ############# # SETTINGS # @@ -225,6 +243,8 @@ database.fileNotFound=File not Found database.fileNullOrEmpty=File must not be null or empty database.failedImportFile=Failed Import File +session.expired=Your session has expired. Please refresh the page and try again. + ############# # HOME-PAGE # ############# @@ -482,6 +502,11 @@ home.removeImagePdf.title=Remove image home.removeImagePdf.desc=Remove image from PDF to reduce file size removeImagePdf.tags=Remove Image,Page operations,Back end,server side + +home.splitPdfByChapters.title=Split PDF by Chapters +home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure. +splitPdfByChapters.tags=split,chapters,bookmarks,organize + #replace-invert-color replace-color.title=Replace-Invert-Color replace-color.header=Replace-Invert Color PDF @@ -526,7 +551,10 @@ login.oauth2AccessDenied=Access Denied login.oauth2InvalidTokenResponse=Invalid Token Response login.oauth2InvalidIdToken=Invalid Id Token login.userIsDisabled=User is deactivated, login is currently blocked with this username. Please contact the administrator. - +login.alreadyLoggedIn=You are already logged in to +login.alreadyLoggedIn2=devices. Please log out of the devices and try again. +login.toManySessions=You have too many active sessions +login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro. #auto-redact autoRedact.title=Auto Redact @@ -1154,6 +1182,8 @@ licenses.license=License survey.nav=Survey survey.title=Stirling-PDF Survey survey.description=Stirling-PDF has no tracking so we want to hear from our users to improve Stirling-PDF! +survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here: +survey.changes2=With these changes we are getting paid business support and funding survey.please=Please consider taking our survey! survey.disabled=(Survey popup will be disabled in following updates but available at foot of page) survey.button=Take Survey @@ -1179,3 +1209,17 @@ removeImage.title=Remove image removeImage.header=Remove image removeImage.removeImage=Remove image removeImage.submit=Remove image + + +splitByChapters.title=Split PDF by Chapters +splitByChapters.header=Split PDF by Chapters +splitByChapters.bookmarkLevel=Bookmark Level +splitByChapters.includeMetadata=Include Metadata +splitByChapters.allowDuplicates=Allow Duplicates +splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure. +splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.). +splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF. +splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs. +splitByChapters.submit=Split PDF + + diff --git a/src/main/resources/messages_es_ES.properties b/src/main/resources/messages_es_ES.properties index 5274fc1d..0f45980e 100644 --- a/src/main/resources/messages_es_ES.properties +++ b/src/main/resources/messages_es_ES.properties @@ -76,6 +76,7 @@ donate=Donar color=Color sponsor=Patrocinador info=Info +pro=Pro page=Page pages=Pages @@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Canalización: pipelineOptions.saveButton=Descargar pipelineOptions.validateButton=Validar +######################## +# ENTERPRISE EDITION # +######################## +enterpriseEdition.button=Upgrade to Pro +enterpriseEdition.warning=This feature is only available to Pro users. +enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features. +enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro +################# +# Analytics # +################# +analytics.title=Do you want make Stirling PDF better? +analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents. +analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better. +analytics.enable=Enable analytics +analytics.disable=Disable analytics +analytics.settings=You can change the settings for analytics in the config/settings.yml file ############# # NAVBAR # @@ -128,6 +145,7 @@ navbar.sections.convertFrom=Convertir desde PDF navbar.sections.security=Señalización y seguridad navbar.sections.advance=Avanzado navbar.sections.edit=Ver y Editar +navbar.sections.popular=Popular ############# # SETTINGS # @@ -225,6 +243,8 @@ database.fileNotFound=Archivo no encontrado database.fileNullOrEmpty=El archivo no debe ser nulo o vacío. database.failedImportFile=Archivo de importación fallido +session.expired=Your session has expired. Please refresh the page and try again. + ############# # HOME-PAGE # ############# @@ -382,7 +402,7 @@ home.scalePages.title=Escalar/ajustar tamaño de página home.scalePages.desc=Escalar/cambiar el tamaño de una pagina y/o su contenido scalePages.tags=cambiar tamaño,modificar,dimensionar,adaptar -home.pipeline.title=Secuencia (Avanzado) +home.pipeline.title=Secuencia home.pipeline.desc=Ejecutar varias tareas a PDFs definiendo una secuencia de comandos pipeline.tags=automatizar,secuencia,con script,proceso por lotes @@ -482,6 +502,11 @@ home.removeImagePdf.title=Eliminar imagen home.removeImagePdf.desc=Eliminar imagen del PDF> para reducir el tamaño de archivo removeImagePdf.tags=Eliminar imagen,Operaciones de página,Back end,lado del servidor + +home.splitPdfByChapters.title=Split PDF by Chapters +home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure. +splitPdfByChapters.tags=split,chapters,bookmarks,organize + #replace-invert-color replace-color.title=Replace-Invert-Color replace-color.header=Replace-Invert Color PDF @@ -526,7 +551,10 @@ login.oauth2AccessDenied=Acceso denegado login.oauth2InvalidTokenResponse=Respuesta de token no válida login.oauth2InvalidIdToken=Token de identificación no válido login.userIsDisabled=El usuario está desactivado, actualmente el acceso está bloqueado para ese nombre de usuario. Por favor, póngase en contacto con el administrador. - +login.alreadyLoggedIn=You are already logged in to +login.alreadyLoggedIn2=devices. Please log out of the devices and try again. +login.toManySessions=You have too many active sessions +login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro. #auto-redact autoRedact.title=Auto Redactar @@ -1154,6 +1182,8 @@ licenses.license=Licencia survey.nav=Encuesta survey.title=Encuesta Stirling-PDF survey.description=Stirling-PDF no tiene seguimiento, por lo que queremos escuchar a nuestros usuarios para mejorar Stirling-PDF. +survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here: +survey.changes2=With these changes we are getting paid business support and funding survey.please=¡Considere realizar nuestra encuesta! survey.disabled=(La ventana emergente de la encuesta se desactivará en las siguientes actualizaciones, pero estará disponible al pie de la página.) survey.button=Realizar encuesta @@ -1179,3 +1209,17 @@ removeImage.title=Eliminar imagen removeImage.header=Eliminar imagen removeImage.removeImage=Eliminar imagen removeImage.submit=Eliminar imagen + + +splitByChapters.title=Split PDF by Chapters +splitByChapters.header=Split PDF by Chapters +splitByChapters.bookmarkLevel=Bookmark Level +splitByChapters.includeMetadata=Include Metadata +splitByChapters.allowDuplicates=Allow Duplicates +splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure. +splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.). +splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF. +splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs. +splitByChapters.submit=Split PDF + + diff --git a/src/main/resources/messages_eu_ES.properties b/src/main/resources/messages_eu_ES.properties index 792955c3..7c56fed9 100644 --- a/src/main/resources/messages_eu_ES.properties +++ b/src/main/resources/messages_eu_ES.properties @@ -76,6 +76,7 @@ donate=Donate color=Color sponsor=Sponsor info=Info +pro=Pro page=Page pages=Pages @@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Pipeline: pipelineOptions.saveButton=Download pipelineOptions.validateButton=Validate +######################## +# ENTERPRISE EDITION # +######################## +enterpriseEdition.button=Upgrade to Pro +enterpriseEdition.warning=This feature is only available to Pro users. +enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features. +enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro +################# +# Analytics # +################# +analytics.title=Do you want make Stirling PDF better? +analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents. +analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better. +analytics.enable=Enable analytics +analytics.disable=Disable analytics +analytics.settings=You can change the settings for analytics in the config/settings.yml file ############# # NAVBAR # @@ -128,6 +145,7 @@ navbar.sections.convertFrom=Convert from PDF navbar.sections.security=Sign & Security navbar.sections.advance=Advanced navbar.sections.edit=View & Edit +navbar.sections.popular=Popular ############# # SETTINGS # @@ -225,6 +243,8 @@ database.fileNotFound=File not Found database.fileNullOrEmpty=File must not be null or empty database.failedImportFile=Failed Import File +session.expired=Your session has expired. Please refresh the page and try again. + ############# # HOME-PAGE # ############# @@ -482,6 +502,11 @@ home.removeImagePdf.title=Remove image home.removeImagePdf.desc=Remove image from PDF to reduce file size removeImagePdf.tags=Remove Image,Page operations,Back end,server side + +home.splitPdfByChapters.title=Split PDF by Chapters +home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure. +splitPdfByChapters.tags=split,chapters,bookmarks,organize + #replace-invert-color replace-color.title=Replace-Invert-Color replace-color.header=Replace-Invert Color PDF @@ -526,7 +551,10 @@ login.oauth2AccessDenied=Access Denied login.oauth2InvalidTokenResponse=Invalid Token Response login.oauth2InvalidIdToken=Invalid Id Token login.userIsDisabled=User is deactivated, login is currently blocked with this username. Please contact the administrator. - +login.alreadyLoggedIn=You are already logged in to +login.alreadyLoggedIn2=devices. Please log out of the devices and try again. +login.toManySessions=You have too many active sessions +login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro. #auto-redact autoRedact.title=Auto Idatzi @@ -1154,6 +1182,8 @@ licenses.license=License survey.nav=Survey survey.title=Stirling-PDF Survey survey.description=Stirling-PDF has no tracking so we want to hear from our users to improve Stirling-PDF! +survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here: +survey.changes2=With these changes we are getting paid business support and funding survey.please=Please consider taking our survey! survey.disabled=(Survey popup will be disabled in following updates but available at foot of page) survey.button=Take Survey @@ -1179,3 +1209,17 @@ removeImage.title=Remove image removeImage.header=Remove image removeImage.removeImage=Remove image removeImage.submit=Remove image + + +splitByChapters.title=Split PDF by Chapters +splitByChapters.header=Split PDF by Chapters +splitByChapters.bookmarkLevel=Bookmark Level +splitByChapters.includeMetadata=Include Metadata +splitByChapters.allowDuplicates=Allow Duplicates +splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure. +splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.). +splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF. +splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs. +splitByChapters.submit=Split PDF + + diff --git a/src/main/resources/messages_fr_FR.properties b/src/main/resources/messages_fr_FR.properties index ee00bb48..b6756e8a 100644 --- a/src/main/resources/messages_fr_FR.properties +++ b/src/main/resources/messages_fr_FR.properties @@ -76,6 +76,7 @@ donate=Faire un don color=Couleur sponsor=Sponsor info=Info +pro=Pro page=Page pages=Pages @@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Pipeline: pipelineOptions.saveButton=Télécharger pipelineOptions.validateButton=Valider +######################## +# ENTERPRISE EDITION # +######################## +enterpriseEdition.button=Upgrade to Pro +enterpriseEdition.warning=This feature is only available to Pro users. +enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features. +enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro +################# +# Analytics # +################# +analytics.title=Do you want make Stirling PDF better? +analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents. +analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better. +analytics.enable=Enable analytics +analytics.disable=Disable analytics +analytics.settings=You can change the settings for analytics in the config/settings.yml file ############# # NAVBAR # @@ -128,6 +145,7 @@ navbar.sections.convertFrom=Convertir depuis PDF navbar.sections.security=Signature et sécurité navbar.sections.advance=Mode avancé navbar.sections.edit=Voir et modifier +navbar.sections.popular=Popular ############# # SETTINGS # @@ -225,6 +243,8 @@ database.fileNotFound=File not Found database.fileNullOrEmpty=File must not be null or empty database.failedImportFile=Failed Import File +session.expired=Your session has expired. Please refresh the page and try again. + ############# # HOME-PAGE # ############# @@ -382,7 +402,7 @@ home.scalePages.title=Ajuster l’échelle ou la taille home.scalePages.desc=Modifiez la taille ou l’échelle d’une page et/ou de son contenu. scalePages.tags=ajuster,redimensionner,resize,modify,dimension,adapt -home.pipeline.title=Pipeline (avancé) +home.pipeline.title=Pipeline home.pipeline.desc=Exécutez plusieurs actions sur les PDF en définissant des scripts de pipeline. pipeline.tags=automatiser,séquencer,automate,sequence,scripted,batch-process @@ -482,6 +502,11 @@ home.removeImagePdf.title=Remove image home.removeImagePdf.desc=Remove image from PDF to reduce file size removeImagePdf.tags=Remove Image,Page operations,Back end,server side + +home.splitPdfByChapters.title=Split PDF by Chapters +home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure. +splitPdfByChapters.tags=split,chapters,bookmarks,organize + #replace-invert-color replace-color.title=Replace-Invert-Color replace-color.header=Replace-Invert Color PDF @@ -526,7 +551,10 @@ login.oauth2AccessDenied=Accès refusé login.oauth2InvalidTokenResponse=Réponse contenant le jeton est invalide login.oauth2InvalidIdToken=Jeton d'identification invalide login.userIsDisabled=User is deactivated, login is currently blocked with this username. Please contact the administrator. - +login.alreadyLoggedIn=You are already logged in to +login.alreadyLoggedIn2=devices. Please log out of the devices and try again. +login.toManySessions=You have too many active sessions +login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro. #auto-redact autoRedact.title=Caviarder automatiquement @@ -1154,6 +1182,8 @@ licenses.license=Licence survey.nav=Survey survey.title=Stirling-PDF Survey survey.description=Stirling-PDF has no tracking so we want to hear from our users to improve Stirling-PDF! +survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here: +survey.changes2=With these changes we are getting paid business support and funding survey.please=Please consider taking our survey! survey.disabled=(Survey popup will be disabled in following updates but available at foot of page) survey.button=Take Survey @@ -1179,3 +1209,17 @@ removeImage.title=Remove image removeImage.header=Remove image removeImage.removeImage=Remove image removeImage.submit=Remove image + + +splitByChapters.title=Split PDF by Chapters +splitByChapters.header=Split PDF by Chapters +splitByChapters.bookmarkLevel=Bookmark Level +splitByChapters.includeMetadata=Include Metadata +splitByChapters.allowDuplicates=Allow Duplicates +splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure. +splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.). +splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF. +splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs. +splitByChapters.submit=Split PDF + + diff --git a/src/main/resources/messages_ga_IE.properties b/src/main/resources/messages_ga_IE.properties index 2360538a..a8970c75 100644 --- a/src/main/resources/messages_ga_IE.properties +++ b/src/main/resources/messages_ga_IE.properties @@ -76,6 +76,7 @@ donate=Síntiúis color=Dath sponsor=Urraitheoir info=Eolas +pro=Pro page=Page pages=Pages @@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Píblíne: pipelineOptions.saveButton=Íosluchtaigh pipelineOptions.validateButton=Bailíochtaigh +######################## +# ENTERPRISE EDITION # +######################## +enterpriseEdition.button=Upgrade to Pro +enterpriseEdition.warning=This feature is only available to Pro users. +enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features. +enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro +################# +# Analytics # +################# +analytics.title=Do you want make Stirling PDF better? +analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents. +analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better. +analytics.enable=Enable analytics +analytics.disable=Disable analytics +analytics.settings=You can change the settings for analytics in the config/settings.yml file ############# # NAVBAR # @@ -128,6 +145,7 @@ navbar.sections.convertFrom=Tiontaigh ó PDF navbar.sections.security=Comhartha & Slándáil navbar.sections.advance=Casta navbar.sections.edit=Féach ar & Cuir in Eagar +navbar.sections.popular=Popular ############# # SETTINGS # @@ -225,6 +243,8 @@ database.fileNotFound=Comhad gan aimsiú database.fileNullOrEmpty=Níor cheart go mbeadh an comhad ar neamhní nó folamh database.failedImportFile=Theip ar iompórtáil an chomhaid +session.expired=Your session has expired. Please refresh the page and try again. + ############# # HOME-PAGE # ############# @@ -482,6 +502,11 @@ home.removeImagePdf.title=Remove image home.removeImagePdf.desc=Remove image from PDF to reduce file size removeImagePdf.tags=Remove Image,Page operations,Back end,server side + +home.splitPdfByChapters.title=Split PDF by Chapters +home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure. +splitPdfByChapters.tags=split,chapters,bookmarks,organize + #replace-invert-color replace-color.title=Replace-Invert-Color replace-color.header=Replace-Invert Color PDF @@ -526,7 +551,10 @@ login.oauth2AccessDenied=Rochtain Diúltaithe login.oauth2InvalidTokenResponse=Freagra Comhartha Neamhbhailí login.oauth2InvalidIdToken=Comhartha Aitheantais Neamhbhailí login.userIsDisabled=User is deactivated, login is currently blocked with this username. Please contact the administrator. - +login.alreadyLoggedIn=You are already logged in to +login.alreadyLoggedIn2=devices. Please log out of the devices and try again. +login.toManySessions=You have too many active sessions +login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro. #auto-redact autoRedact.title=Auto Redact @@ -1154,6 +1182,8 @@ licenses.license=Ceadúnas survey.nav=Suirbhé survey.title=Suirbhé Stirling-PDF survey.description=Níl aon rian ar Stirling-PDF agus mar sin ba mhaith linn cloisteáil ónár n-úsáideoirí chun feabhas a chur ar Stirling-PDF! +survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here: +survey.changes2=With these changes we are getting paid business support and funding survey.please=Smaoinigh ar ár suirbhé a dhéanamh le do thoil! survey.disabled=(Díchumasófar aníos an tsuirbhé sna nuashonruithe seo a leanas ach beidh siad ar fáil ag bun an leathanaigh) survey.button=Tóg Suirbhé @@ -1179,3 +1209,17 @@ removeImage.title=Remove image removeImage.header=Remove image removeImage.removeImage=Remove image removeImage.submit=Remove image + + +splitByChapters.title=Split PDF by Chapters +splitByChapters.header=Split PDF by Chapters +splitByChapters.bookmarkLevel=Bookmark Level +splitByChapters.includeMetadata=Include Metadata +splitByChapters.allowDuplicates=Allow Duplicates +splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure. +splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.). +splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF. +splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs. +splitByChapters.submit=Split PDF + + diff --git a/src/main/resources/messages_hi_IN.properties b/src/main/resources/messages_hi_IN.properties index d93dc2dd..58d2257f 100644 --- a/src/main/resources/messages_hi_IN.properties +++ b/src/main/resources/messages_hi_IN.properties @@ -76,6 +76,7 @@ donate=Donate color=Color sponsor=Sponsor info=Info +pro=Pro page=पृष्ठ pages=पृष्ठों @@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Pipeline: pipelineOptions.saveButton=Download pipelineOptions.validateButton=Validate +######################## +# ENTERPRISE EDITION # +######################## +enterpriseEdition.button=Upgrade to Pro +enterpriseEdition.warning=This feature is only available to Pro users. +enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features. +enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro +################# +# Analytics # +################# +analytics.title=Do you want make Stirling PDF better? +analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents. +analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better. +analytics.enable=Enable analytics +analytics.disable=Disable analytics +analytics.settings=You can change the settings for analytics in the config/settings.yml file ############# # NAVBAR # @@ -128,6 +145,7 @@ navbar.sections.convertFrom=पीडीएफ से कनवर्ट कर navbar.sections.security=संकेत और सुरक्षा navbar.sections.advance=उन्नत navbar.sections.edit=देखें और संपादित करें +navbar.sections.popular=Popular ############# # SETTINGS # @@ -225,6 +243,8 @@ database.fileNotFound=File not Found database.fileNullOrEmpty=File must not be null or empty database.failedImportFile=Failed Import File +session.expired=Your session has expired. Please refresh the page and try again. + ############# # HOME-PAGE # ############# @@ -482,6 +502,11 @@ home.removeImagePdf.title=Remove image home.removeImagePdf.desc=Remove image from PDF to reduce file size removeImagePdf.tags=Remove Image,Page operations,Back end,server side + +home.splitPdfByChapters.title=Split PDF by Chapters +home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure. +splitPdfByChapters.tags=split,chapters,bookmarks,organize + #replace-invert-color replace-color.title=Replace-Invert-Color replace-color.header=Replace-Invert Color PDF @@ -526,7 +551,10 @@ login.oauth2AccessDenied=Access Denied login.oauth2InvalidTokenResponse=Invalid Token Response login.oauth2InvalidIdToken=Invalid Id Token login.userIsDisabled=User is deactivated, login is currently blocked with this username. Please contact the administrator. - +login.alreadyLoggedIn=You are already logged in to +login.alreadyLoggedIn2=devices. Please log out of the devices and try again. +login.toManySessions=You have too many active sessions +login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro. #auto-redact autoRedact.title=स्वत: गोपनीयकरण @@ -1154,6 +1182,8 @@ licenses.license=License survey.nav=Survey survey.title=Stirling-PDF Survey survey.description=Stirling-PDF has no tracking so we want to hear from our users to improve Stirling-PDF! +survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here: +survey.changes2=With these changes we are getting paid business support and funding survey.please=Please consider taking our survey! survey.disabled=(Survey popup will be disabled in following updates but available at foot of page) survey.button=Take Survey @@ -1179,3 +1209,17 @@ removeImage.title=Remove image removeImage.header=Remove image removeImage.removeImage=Remove image removeImage.submit=Remove image + + +splitByChapters.title=Split PDF by Chapters +splitByChapters.header=Split PDF by Chapters +splitByChapters.bookmarkLevel=Bookmark Level +splitByChapters.includeMetadata=Include Metadata +splitByChapters.allowDuplicates=Allow Duplicates +splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure. +splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.). +splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF. +splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs. +splitByChapters.submit=Split PDF + + diff --git a/src/main/resources/messages_hr_HR.properties b/src/main/resources/messages_hr_HR.properties index e8f93b20..b31ad75b 100644 --- a/src/main/resources/messages_hr_HR.properties +++ b/src/main/resources/messages_hr_HR.properties @@ -76,6 +76,7 @@ donate=Doniraj color=Boja sponsor=Sponzor info=Info +pro=Pro page=Page pages=Pages @@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Pipeline: pipelineOptions.saveButton=Preuzmi datoteku pipelineOptions.validateButton=Potvrdi +######################## +# ENTERPRISE EDITION # +######################## +enterpriseEdition.button=Upgrade to Pro +enterpriseEdition.warning=This feature is only available to Pro users. +enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features. +enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro +################# +# Analytics # +################# +analytics.title=Do you want make Stirling PDF better? +analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents. +analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better. +analytics.enable=Enable analytics +analytics.disable=Disable analytics +analytics.settings=You can change the settings for analytics in the config/settings.yml file ############# # NAVBAR # @@ -128,6 +145,7 @@ navbar.sections.convertFrom=Pretvori iz PDF navbar.sections.security=Potpis & sigurnost navbar.sections.advance=Napredno navbar.sections.edit=Pregled & Uređivanje +navbar.sections.popular=Popular ############# # SETTINGS # @@ -225,6 +243,8 @@ database.fileNotFound=File not Found database.fileNullOrEmpty=File must not be null or empty database.failedImportFile=Failed Import File +session.expired=Your session has expired. Please refresh the page and try again. + ############# # HOME-PAGE # ############# @@ -382,7 +402,7 @@ home.scalePages.title=Prilagodite veličinu/razmjer stranice home.scalePages.desc=Promijenite veličinu/razmjer stranice i/ili njezin sadržaj. scalePages.tags=izmjena,modifikacija,dimenzija,adaptacija -home.pipeline.title=Pipeline (Advanced) +home.pipeline.title=Pipeline home.pipeline.desc=Izvršite više radnji na PDF-ovima definiranjem skripti u pipeline-u pipeline.tags=automatizacija,sekvenciranje,skriptirano,batch-process @@ -482,6 +502,11 @@ home.removeImagePdf.title=Remove image home.removeImagePdf.desc=Remove image from PDF to reduce file size removeImagePdf.tags=Remove Image,Page operations,Back end,server side + +home.splitPdfByChapters.title=Split PDF by Chapters +home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure. +splitPdfByChapters.tags=split,chapters,bookmarks,organize + #replace-invert-color replace-color.title=Replace-Invert-Color replace-color.header=Replace-Invert Color PDF @@ -526,7 +551,10 @@ login.oauth2AccessDenied=Pristup odbijen login.oauth2InvalidTokenResponse=Nevažeći odgovor tokena login.oauth2InvalidIdToken=Nevažeći ID token login.userIsDisabled=User is deactivated, login is currently blocked with this username. Please contact the administrator. - +login.alreadyLoggedIn=You are already logged in to +login.alreadyLoggedIn2=devices. Please log out of the devices and try again. +login.toManySessions=You have too many active sessions +login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro. #auto-redact autoRedact.title=Automatsko uređivanje @@ -1154,6 +1182,8 @@ licenses.license=Licenca survey.nav=Survey survey.title=Stirling-PDF Survey survey.description=Stirling-PDF has no tracking so we want to hear from our users to improve Stirling-PDF! +survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here: +survey.changes2=With these changes we are getting paid business support and funding survey.please=Please consider taking our survey! survey.disabled=(Survey popup will be disabled in following updates but available at foot of page) survey.button=Take Survey @@ -1179,3 +1209,17 @@ removeImage.title=Remove image removeImage.header=Remove image removeImage.removeImage=Remove image removeImage.submit=Remove image + + +splitByChapters.title=Split PDF by Chapters +splitByChapters.header=Split PDF by Chapters +splitByChapters.bookmarkLevel=Bookmark Level +splitByChapters.includeMetadata=Include Metadata +splitByChapters.allowDuplicates=Allow Duplicates +splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure. +splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.). +splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF. +splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs. +splitByChapters.submit=Split PDF + + diff --git a/src/main/resources/messages_hu_HU.properties b/src/main/resources/messages_hu_HU.properties index e22cee08..e5457609 100644 --- a/src/main/resources/messages_hu_HU.properties +++ b/src/main/resources/messages_hu_HU.properties @@ -76,6 +76,7 @@ donate=Donate color=Color sponsor=Sponsor info=Info +pro=Pro page=Page pages=Pages @@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Pipeline: pipelineOptions.saveButton=Download pipelineOptions.validateButton=Validate +######################## +# ENTERPRISE EDITION # +######################## +enterpriseEdition.button=Upgrade to Pro +enterpriseEdition.warning=This feature is only available to Pro users. +enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features. +enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro +################# +# Analytics # +################# +analytics.title=Do you want make Stirling PDF better? +analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents. +analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better. +analytics.enable=Enable analytics +analytics.disable=Disable analytics +analytics.settings=You can change the settings for analytics in the config/settings.yml file ############# # NAVBAR # @@ -128,6 +145,7 @@ navbar.sections.convertFrom=Convert from PDF navbar.sections.security=Sign & Security navbar.sections.advance=Advanced navbar.sections.edit=View & Edit +navbar.sections.popular=Popular ############# # SETTINGS # @@ -225,6 +243,8 @@ database.fileNotFound=File not Found database.fileNullOrEmpty=File must not be null or empty database.failedImportFile=Failed Import File +session.expired=Your session has expired. Please refresh the page and try again. + ############# # HOME-PAGE # ############# @@ -482,6 +502,11 @@ home.removeImagePdf.title=Remove image home.removeImagePdf.desc=Remove image from PDF to reduce file size removeImagePdf.tags=Remove Image,Page operations,Back end,server side + +home.splitPdfByChapters.title=Split PDF by Chapters +home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure. +splitPdfByChapters.tags=split,chapters,bookmarks,organize + #replace-invert-color replace-color.title=Replace-Invert-Color replace-color.header=Replace-Invert Color PDF @@ -526,7 +551,10 @@ login.oauth2AccessDenied=Access Denied login.oauth2InvalidTokenResponse=Invalid Token Response login.oauth2InvalidIdToken=Invalid Id Token login.userIsDisabled=User is deactivated, login is currently blocked with this username. Please contact the administrator. - +login.alreadyLoggedIn=You are already logged in to +login.alreadyLoggedIn2=devices. Please log out of the devices and try again. +login.toManySessions=You have too many active sessions +login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro. #auto-redact autoRedact.title=Érzékeny tartalom eltávolítása @@ -1154,6 +1182,8 @@ licenses.license=License survey.nav=Survey survey.title=Stirling-PDF Survey survey.description=Stirling-PDF has no tracking so we want to hear from our users to improve Stirling-PDF! +survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here: +survey.changes2=With these changes we are getting paid business support and funding survey.please=Please consider taking our survey! survey.disabled=(Survey popup will be disabled in following updates but available at foot of page) survey.button=Take Survey @@ -1179,3 +1209,17 @@ removeImage.title=Remove image removeImage.header=Remove image removeImage.removeImage=Remove image removeImage.submit=Remove image + + +splitByChapters.title=Split PDF by Chapters +splitByChapters.header=Split PDF by Chapters +splitByChapters.bookmarkLevel=Bookmark Level +splitByChapters.includeMetadata=Include Metadata +splitByChapters.allowDuplicates=Allow Duplicates +splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure. +splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.). +splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF. +splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs. +splitByChapters.submit=Split PDF + + diff --git a/src/main/resources/messages_id_ID.properties b/src/main/resources/messages_id_ID.properties index cbc0e61a..9c4f8bc3 100644 --- a/src/main/resources/messages_id_ID.properties +++ b/src/main/resources/messages_id_ID.properties @@ -76,6 +76,7 @@ donate=Donate color=Color sponsor=Sponsor info=Info +pro=Pro page=Page pages=Pages @@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Pipeline: pipelineOptions.saveButton=Download pipelineOptions.validateButton=Validate +######################## +# ENTERPRISE EDITION # +######################## +enterpriseEdition.button=Upgrade to Pro +enterpriseEdition.warning=This feature is only available to Pro users. +enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features. +enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro +################# +# Analytics # +################# +analytics.title=Do you want make Stirling PDF better? +analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents. +analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better. +analytics.enable=Enable analytics +analytics.disable=Disable analytics +analytics.settings=You can change the settings for analytics in the config/settings.yml file ############# # NAVBAR # @@ -128,6 +145,7 @@ navbar.sections.convertFrom=Convert from PDF navbar.sections.security=Sign & Security navbar.sections.advance=Advanced navbar.sections.edit=View & Edit +navbar.sections.popular=Popular ############# # SETTINGS # @@ -225,6 +243,8 @@ database.fileNotFound=File not Found database.fileNullOrEmpty=File must not be null or empty database.failedImportFile=Failed Import File +session.expired=Your session has expired. Please refresh the page and try again. + ############# # HOME-PAGE # ############# @@ -382,7 +402,7 @@ home.scalePages.title=Menyesuaikan ukuran/skala halaman home.scalePages.desc=Mengubah ukuran/skala halaman dan/atau isinya. scalePages.tags=mengubah ukuran, memodifikasi, dimensi, mengadaptasi -home.pipeline.title=Pipeline (Lanjutan) +home.pipeline.title=Pipeline home.pipeline.desc=Menjalankan beberapa tindakan pada PDF dengan mendefinisikan skrip pipeline pipeline.tags=mengotomatiskan, mengurutkan, menulis, proses batch @@ -482,6 +502,11 @@ home.removeImagePdf.title=Remove image home.removeImagePdf.desc=Remove image from PDF to reduce file size removeImagePdf.tags=Remove Image,Page operations,Back end,server side + +home.splitPdfByChapters.title=Split PDF by Chapters +home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure. +splitPdfByChapters.tags=split,chapters,bookmarks,organize + #replace-invert-color replace-color.title=Replace-Invert-Color replace-color.header=Replace-Invert Color PDF @@ -526,7 +551,10 @@ login.oauth2AccessDenied=Access Denied login.oauth2InvalidTokenResponse=Invalid Token Response login.oauth2InvalidIdToken=Invalid Id Token login.userIsDisabled=User is deactivated, login is currently blocked with this username. Please contact the administrator. - +login.alreadyLoggedIn=You are already logged in to +login.alreadyLoggedIn2=devices. Please log out of the devices and try again. +login.toManySessions=You have too many active sessions +login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro. #auto-redact autoRedact.title=Redaksional Otomatis @@ -1154,6 +1182,8 @@ licenses.license=License survey.nav=Survey survey.title=Stirling-PDF Survey survey.description=Stirling-PDF has no tracking so we want to hear from our users to improve Stirling-PDF! +survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here: +survey.changes2=With these changes we are getting paid business support and funding survey.please=Please consider taking our survey! survey.disabled=(Survey popup will be disabled in following updates but available at foot of page) survey.button=Take Survey @@ -1179,3 +1209,17 @@ removeImage.title=Remove image removeImage.header=Remove image removeImage.removeImage=Remove image removeImage.submit=Remove image + + +splitByChapters.title=Split PDF by Chapters +splitByChapters.header=Split PDF by Chapters +splitByChapters.bookmarkLevel=Bookmark Level +splitByChapters.includeMetadata=Include Metadata +splitByChapters.allowDuplicates=Allow Duplicates +splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure. +splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.). +splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF. +splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs. +splitByChapters.submit=Split PDF + + diff --git a/src/main/resources/messages_it_IT.properties b/src/main/resources/messages_it_IT.properties index e8fb9fcc..8ba53f6d 100644 --- a/src/main/resources/messages_it_IT.properties +++ b/src/main/resources/messages_it_IT.properties @@ -76,6 +76,7 @@ donate=Donazione color=Colore sponsor=Sponsor info=Info +pro=Pro page=Page pages=Pages @@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Pipeline: pipelineOptions.saveButton=Download pipelineOptions.validateButton=Convalidare +######################## +# ENTERPRISE EDITION # +######################## +enterpriseEdition.button=Upgrade to Pro +enterpriseEdition.warning=This feature is only available to Pro users. +enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features. +enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro +################# +# Analytics # +################# +analytics.title=Do you want make Stirling PDF better? +analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents. +analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better. +analytics.enable=Enable analytics +analytics.disable=Disable analytics +analytics.settings=You can change the settings for analytics in the config/settings.yml file ############# # NAVBAR # @@ -128,6 +145,7 @@ navbar.sections.convertFrom=Converti da PDF navbar.sections.security=Firma & Sicurezza navbar.sections.advance=Avanzate navbar.sections.edit=Visualizza & Modifica +navbar.sections.popular=Popular ############# # SETTINGS # @@ -225,6 +243,8 @@ database.fileNotFound=File non trovato database.fileNullOrEmpty=Il file non deve essere nullo o vuoto database.failedImportFile=Importazione file non riuscita +session.expired=Your session has expired. Please refresh the page and try again. + ############# # HOME-PAGE # ############# @@ -382,7 +402,7 @@ home.scalePages.title=Regola le dimensioni/scala della pagina home.scalePages.desc=Modificare le dimensioni/scala della pagina e/o dei suoi contenuti. scalePages.tags=ridimensionare,modificare,dimensionare,adattare -home.pipeline.title=Pipeline (avanzato) +home.pipeline.title=Pipeline home.pipeline.desc=Esegui più azioni sui PDF definendo script di pipeline pipeline.tags=automatizzare,sequenziare,scriptare,elaborare in batch @@ -482,6 +502,11 @@ home.removeImagePdf.title=Rimuovi immagine home.removeImagePdf.desc=Rimuovi le immagini dal PDF per ridurre la dimensione del file removeImagePdf.tags=Rimuovi immagine,operazioni sulla pagina,back-end,lato server + +home.splitPdfByChapters.title=Split PDF by Chapters +home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure. +splitPdfByChapters.tags=split,chapters,bookmarks,organize + #replace-invert-color replace-color.title=Sostituisci-Inverti-Colore replace-color.header=Sostituisci-Inverti colore PDF @@ -526,7 +551,10 @@ login.oauth2AccessDenied=Accesso negato login.oauth2InvalidTokenResponse=Risposta token non valida login.oauth2InvalidIdToken=Id Token non valido login.userIsDisabled=L'utente è disattivato, l'accesso è attualmente bloccato con questo nome utente. Si prega di contattare l'amministratore. - +login.alreadyLoggedIn=You are already logged in to +login.alreadyLoggedIn2=devices. Please log out of the devices and try again. +login.toManySessions=You have too many active sessions +login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro. #auto-redact autoRedact.title=Redazione automatica @@ -1154,6 +1182,8 @@ licenses.license=Licenza survey.nav=Sondaggio survey.title=Sondaggio Stirling-PDF survey.description=Stirling-PDF non fa tracciamento, quindi vogliamo sentire i nostri utenti per migliorare Stirling-PDF! +survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here: +survey.changes2=With these changes we are getting paid business support and funding survey.please=Ti invitiamo a prendere in considerazione la possibilità di partecipare al nostro sondaggio! survey.disabled=(Il popup del sondaggio verrà disabilitato nei prossimi aggiornamenti ma sarà disponibile a piè di pagina) survey.button=Partecipa al sondaggio @@ -1179,3 +1209,17 @@ removeImage.title=Rimuovere immagine removeImage.header=Rimuovi immagine removeImage.removeImage=Rimuovi immagine removeImage.submit=Rimuovi immagine + + +splitByChapters.title=Split PDF by Chapters +splitByChapters.header=Split PDF by Chapters +splitByChapters.bookmarkLevel=Bookmark Level +splitByChapters.includeMetadata=Include Metadata +splitByChapters.allowDuplicates=Allow Duplicates +splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure. +splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.). +splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF. +splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs. +splitByChapters.submit=Split PDF + + diff --git a/src/main/resources/messages_ja_JP.properties b/src/main/resources/messages_ja_JP.properties index e5286295..473bcb10 100644 --- a/src/main/resources/messages_ja_JP.properties +++ b/src/main/resources/messages_ja_JP.properties @@ -76,6 +76,7 @@ donate=寄付する color=色 sponsor=スポンサー info=Info +pro=Pro page=Page pages=Pages @@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=パイプライン: pipelineOptions.saveButton=ダウンロード pipelineOptions.validateButton=検証 +######################## +# ENTERPRISE EDITION # +######################## +enterpriseEdition.button=Upgrade to Pro +enterpriseEdition.warning=This feature is only available to Pro users. +enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features. +enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro +################# +# Analytics # +################# +analytics.title=Do you want make Stirling PDF better? +analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents. +analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better. +analytics.enable=Enable analytics +analytics.disable=Disable analytics +analytics.settings=You can change the settings for analytics in the config/settings.yml file ############# # NAVBAR # @@ -128,6 +145,7 @@ navbar.sections.convertFrom=PDFから変換 navbar.sections.security=署名とセキュリティ navbar.sections.advance=アドバンスド navbar.sections.edit=閲覧と編集 +navbar.sections.popular=Popular ############# # SETTINGS # @@ -225,6 +243,8 @@ database.fileNotFound=ファイルが見つかりません database.fileNullOrEmpty=ファイルは null または空であってはなりません database.failedImportFile=ファイルのインポートに失敗 +session.expired=Your session has expired. Please refresh the page and try again. + ############# # HOME-PAGE # ############# @@ -382,7 +402,7 @@ home.scalePages.title=ページの縮尺の調整 home.scalePages.desc=ページやコンテンツの縮尺を変更します。 scalePages.tags=resize,modify,dimension,adapt -home.pipeline.title=パイプライン (高度) +home.pipeline.title=パイプライン home.pipeline.desc=パイプラインスクリプトを定義してPDF上で複数のアクションを実行します。 pipeline.tags=automate,sequence,scripted,batch-process @@ -482,6 +502,11 @@ home.removeImagePdf.title=画像の削除 home.removeImagePdf.desc=PDFから画像を削除してファイルサイズを小さくします removeImagePdf.tags=Remove Image,Page operations,Back end,server side + +home.splitPdfByChapters.title=Split PDF by Chapters +home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure. +splitPdfByChapters.tags=split,chapters,bookmarks,organize + #replace-invert-color replace-color.title=Replace-Invert-Color replace-color.header=Replace-Invert Color PDF @@ -526,7 +551,10 @@ login.oauth2AccessDenied=アクセス拒否 login.oauth2InvalidTokenResponse=無効なトークン応答 login.oauth2InvalidIdToken=無効なIDトークン login.userIsDisabled=ユーザーは非アクティブ化されており、現在このユーザー名でのログインはブロックされています。管理者に連絡してください。 - +login.alreadyLoggedIn=You are already logged in to +login.alreadyLoggedIn2=devices. Please log out of the devices and try again. +login.toManySessions=You have too many active sessions +login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro. #auto-redact autoRedact.title=自動塗りつぶし @@ -1154,6 +1182,8 @@ licenses.license=ライセンス survey.nav=アンケート survey.title=Stirling-PDFのアンケート survey.description=Stirling-PDFには追跡機能がないため、Stirling-PDFをより良くするために皆様の意見を聞かせてください! +survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here: +survey.changes2=With these changes we are getting paid business support and funding survey.please=アンケートにご協力ください! survey.disabled=(アンケートのポップアップは、次の更新では無効になりますが、ページの下部に表示されます。) survey.button=アンケートに答える @@ -1179,3 +1209,17 @@ removeImage.title=画像の削除 removeImage.header=画像の削除 removeImage.removeImage=画像の削除 removeImage.submit=画像を削除 + + +splitByChapters.title=Split PDF by Chapters +splitByChapters.header=Split PDF by Chapters +splitByChapters.bookmarkLevel=Bookmark Level +splitByChapters.includeMetadata=Include Metadata +splitByChapters.allowDuplicates=Allow Duplicates +splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure. +splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.). +splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF. +splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs. +splitByChapters.submit=Split PDF + + diff --git a/src/main/resources/messages_ko_KR.properties b/src/main/resources/messages_ko_KR.properties index 43d8f84e..32419992 100644 --- a/src/main/resources/messages_ko_KR.properties +++ b/src/main/resources/messages_ko_KR.properties @@ -76,6 +76,7 @@ donate=기부하기 color=색상 sponsor=스폰서 info=Info +pro=Pro page=Page pages=Pages @@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=파이프라인: pipelineOptions.saveButton=다운로드 pipelineOptions.validateButton=확인 +######################## +# ENTERPRISE EDITION # +######################## +enterpriseEdition.button=Upgrade to Pro +enterpriseEdition.warning=This feature is only available to Pro users. +enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features. +enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro +################# +# Analytics # +################# +analytics.title=Do you want make Stirling PDF better? +analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents. +analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better. +analytics.enable=Enable analytics +analytics.disable=Disable analytics +analytics.settings=You can change the settings for analytics in the config/settings.yml file ############# # NAVBAR # @@ -128,6 +145,7 @@ navbar.sections.convertFrom=Convert from PDF navbar.sections.security=Sign & Security navbar.sections.advance=Advanced navbar.sections.edit=View & Edit +navbar.sections.popular=Popular ############# # SETTINGS # @@ -225,6 +243,8 @@ database.fileNotFound=File not Found database.fileNullOrEmpty=File must not be null or empty database.failedImportFile=Failed Import File +session.expired=Your session has expired. Please refresh the page and try again. + ############# # HOME-PAGE # ############# @@ -482,6 +502,11 @@ home.removeImagePdf.title=Remove image home.removeImagePdf.desc=Remove image from PDF to reduce file size removeImagePdf.tags=Remove Image,Page operations,Back end,server side + +home.splitPdfByChapters.title=Split PDF by Chapters +home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure. +splitPdfByChapters.tags=split,chapters,bookmarks,organize + #replace-invert-color replace-color.title=Replace-Invert-Color replace-color.header=Replace-Invert Color PDF @@ -526,7 +551,10 @@ login.oauth2AccessDenied=Access Denied login.oauth2InvalidTokenResponse=Invalid Token Response login.oauth2InvalidIdToken=Invalid Id Token login.userIsDisabled=User is deactivated, login is currently blocked with this username. Please contact the administrator. - +login.alreadyLoggedIn=You are already logged in to +login.alreadyLoggedIn2=devices. Please log out of the devices and try again. +login.toManySessions=You have too many active sessions +login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro. #auto-redact autoRedact.title=자동 검열 @@ -1154,6 +1182,8 @@ licenses.license=라이센스 survey.nav=Survey survey.title=Stirling-PDF Survey survey.description=Stirling-PDF has no tracking so we want to hear from our users to improve Stirling-PDF! +survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here: +survey.changes2=With these changes we are getting paid business support and funding survey.please=Please consider taking our survey! survey.disabled=(Survey popup will be disabled in following updates but available at foot of page) survey.button=Take Survey @@ -1179,3 +1209,17 @@ removeImage.title=Remove image removeImage.header=Remove image removeImage.removeImage=Remove image removeImage.submit=Remove image + + +splitByChapters.title=Split PDF by Chapters +splitByChapters.header=Split PDF by Chapters +splitByChapters.bookmarkLevel=Bookmark Level +splitByChapters.includeMetadata=Include Metadata +splitByChapters.allowDuplicates=Allow Duplicates +splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure. +splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.). +splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF. +splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs. +splitByChapters.submit=Split PDF + + diff --git a/src/main/resources/messages_nl_NL.properties b/src/main/resources/messages_nl_NL.properties index 4d1469d8..b21d3dd2 100644 --- a/src/main/resources/messages_nl_NL.properties +++ b/src/main/resources/messages_nl_NL.properties @@ -76,6 +76,7 @@ donate=Doneer color=Kleur sponsor=Sponsor info=Info +pro=Pro page=Page pages=Pages @@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Pijplijn: pipelineOptions.saveButton=Downloaden pipelineOptions.validateButton=Valideren +######################## +# ENTERPRISE EDITION # +######################## +enterpriseEdition.button=Upgrade to Pro +enterpriseEdition.warning=This feature is only available to Pro users. +enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features. +enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro +################# +# Analytics # +################# +analytics.title=Do you want make Stirling PDF better? +analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents. +analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better. +analytics.enable=Enable analytics +analytics.disable=Disable analytics +analytics.settings=You can change the settings for analytics in the config/settings.yml file ############# # NAVBAR # @@ -128,6 +145,7 @@ navbar.sections.convertFrom=Converteren van PDF navbar.sections.security=Ondertekenen & beveiliging navbar.sections.advance=Geavanceerd navbar.sections.edit=Bekijken & wijzigen +navbar.sections.popular=Popular ############# # SETTINGS # @@ -225,6 +243,8 @@ database.fileNotFound=File not Found database.fileNullOrEmpty=File must not be null or empty database.failedImportFile=Failed Import File +session.expired=Your session has expired. Please refresh the page and try again. + ############# # HOME-PAGE # ############# @@ -382,7 +402,7 @@ home.scalePages.title=Aanpassen paginaformaat/schaal home.scalePages.desc=Wijzig de grootte/schaal van een pagina en/of de inhoud ervan. scalePages.tags=resize,aanpassen,dimensie,aanpassen -home.pipeline.title=Pijplijn (Geavanceerd) +home.pipeline.title=Pijplijn home.pipeline.desc=Voer meerdere acties uit op PDF's door pipelinescripts te definiëren pipeline.tags=automatiseren,volgorde,gescrript,batch-verwerking @@ -482,6 +502,11 @@ home.removeImagePdf.title=Remove image home.removeImagePdf.desc=Remove image from PDF to reduce file size removeImagePdf.tags=Remove Image,Page operations,Back end,server side + +home.splitPdfByChapters.title=Split PDF by Chapters +home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure. +splitPdfByChapters.tags=split,chapters,bookmarks,organize + #replace-invert-color replace-color.title=Replace-Invert-Color replace-color.header=Replace-Invert Color PDF @@ -526,7 +551,10 @@ login.oauth2AccessDenied=Toegang geweigerd login.oauth2InvalidTokenResponse=Ongeldige tokenreactie login.oauth2InvalidIdToken=Ongeldige ID token login.userIsDisabled=User is deactivated, login is currently blocked with this username. Please contact the administrator. - +login.alreadyLoggedIn=You are already logged in to +login.alreadyLoggedIn2=devices. Please log out of the devices and try again. +login.toManySessions=You have too many active sessions +login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro. #auto-redact autoRedact.title=Automatisch censureren @@ -1154,6 +1182,8 @@ licenses.license=Licentie survey.nav=Enquête survey.title=Stirling-PDF Enquête survey.description=Stirling-PDF heeft geen tracking, dus we willen van onze gebruikers horen om Stirling-PDF te verbeteren. +survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here: +survey.changes2=With these changes we are getting paid business support and funding survey.please=Overweeg alstublieft om onze enquête in te vullen! survey.disabled=(Enquête popup wordt in een toekomstige update weggehaald, maar is beschikbaar aan de onderkant van de pagina.) survey.button=Vul enquête in. @@ -1179,3 +1209,17 @@ removeImage.title=Remove image removeImage.header=Remove image removeImage.removeImage=Remove image removeImage.submit=Remove image + + +splitByChapters.title=Split PDF by Chapters +splitByChapters.header=Split PDF by Chapters +splitByChapters.bookmarkLevel=Bookmark Level +splitByChapters.includeMetadata=Include Metadata +splitByChapters.allowDuplicates=Allow Duplicates +splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure. +splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.). +splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF. +splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs. +splitByChapters.submit=Split PDF + + diff --git a/src/main/resources/messages_no_NB.properties b/src/main/resources/messages_no_NB.properties index abd0738a..64152299 100644 --- a/src/main/resources/messages_no_NB.properties +++ b/src/main/resources/messages_no_NB.properties @@ -76,6 +76,7 @@ donate=Doner color=Farge sponsor=Sponsor info=Info +pro=Pro page=Page pages=Pages @@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Pipeline: pipelineOptions.saveButton=Last ned pipelineOptions.validateButton=Valider +######################## +# ENTERPRISE EDITION # +######################## +enterpriseEdition.button=Upgrade to Pro +enterpriseEdition.warning=This feature is only available to Pro users. +enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features. +enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro +################# +# Analytics # +################# +analytics.title=Do you want make Stirling PDF better? +analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents. +analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better. +analytics.enable=Enable analytics +analytics.disable=Disable analytics +analytics.settings=You can change the settings for analytics in the config/settings.yml file ############# # NAVBAR # @@ -128,6 +145,7 @@ navbar.sections.convertFrom=Konverter fra PDF navbar.sections.security=Signer & Sikkerhet navbar.sections.advance=Avansert navbar.sections.edit=Vis & Rediger +navbar.sections.popular=Popular ############# # SETTINGS # @@ -225,6 +243,8 @@ database.fileNotFound=Fil ikke funnet database.fileNullOrEmpty=Fil må ikke være tom eller null database.failedImportFile=Import av fil mislyktes +session.expired=Your session has expired. Please refresh the page and try again. + ############# # HOME-PAGE # ############# @@ -482,6 +502,11 @@ home.removeImagePdf.title=Remove image home.removeImagePdf.desc=Remove image from PDF to reduce file size removeImagePdf.tags=Remove Image,Page operations,Back end,server side + +home.splitPdfByChapters.title=Split PDF by Chapters +home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure. +splitPdfByChapters.tags=split,chapters,bookmarks,organize + #replace-invert-color replace-color.title=Replace-Invert-Color replace-color.header=Replace-Invert Color PDF @@ -526,7 +551,10 @@ login.oauth2AccessDenied=Tilgang nektet login.oauth2InvalidTokenResponse=Ugyldig tokenrespons login.oauth2InvalidIdToken=Ugyldig Id Token login.userIsDisabled=User is deactivated, login is currently blocked with this username. Please contact the administrator. - +login.alreadyLoggedIn=You are already logged in to +login.alreadyLoggedIn2=devices. Please log out of the devices and try again. +login.toManySessions=You have too many active sessions +login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro. #auto-redact autoRedact.title=Automatisk Sensurering @@ -1154,6 +1182,8 @@ licenses.license=Lisens survey.nav=Survey survey.title=Stirling-PDF Survey survey.description=Stirling-PDF has no tracking so we want to hear from our users to improve Stirling-PDF! +survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here: +survey.changes2=With these changes we are getting paid business support and funding survey.please=Please consider taking our survey! survey.disabled=(Survey popup will be disabled in following updates but available at foot of page) survey.button=Take Survey @@ -1179,3 +1209,17 @@ removeImage.title=Remove image removeImage.header=Remove image removeImage.removeImage=Remove image removeImage.submit=Remove image + + +splitByChapters.title=Split PDF by Chapters +splitByChapters.header=Split PDF by Chapters +splitByChapters.bookmarkLevel=Bookmark Level +splitByChapters.includeMetadata=Include Metadata +splitByChapters.allowDuplicates=Allow Duplicates +splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure. +splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.). +splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF. +splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs. +splitByChapters.submit=Split PDF + + diff --git a/src/main/resources/messages_pl_PL.properties b/src/main/resources/messages_pl_PL.properties index c15170cb..e252dad6 100755 --- a/src/main/resources/messages_pl_PL.properties +++ b/src/main/resources/messages_pl_PL.properties @@ -76,6 +76,7 @@ donate=Podaruj color=kolor sponsor=sponsor info=informacje +pro=Pro page=Page pages=Pages @@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Automatyzacja pipelineOptions.saveButton=Pobierz pipelineOptions.validateButton=Waliduj +######################## +# ENTERPRISE EDITION # +######################## +enterpriseEdition.button=Upgrade to Pro +enterpriseEdition.warning=This feature is only available to Pro users. +enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features. +enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro +################# +# Analytics # +################# +analytics.title=Do you want make Stirling PDF better? +analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents. +analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better. +analytics.enable=Enable analytics +analytics.disable=Disable analytics +analytics.settings=You can change the settings for analytics in the config/settings.yml file ############# # NAVBAR # @@ -128,6 +145,7 @@ navbar.sections.convertFrom=Przetwórz z PDF navbar.sections.security=Podpis i bezpieczeństwo navbar.sections.advance=Zaawansowane navbar.sections.edit=Podgląd i edycja +navbar.sections.popular=Popular ############# # SETTINGS # @@ -225,6 +243,8 @@ database.fileNotFound=Plik nie znaleziony database.fileNullOrEmpty=Plik nie może być pusty database.failedImportFile=Nie udało się zaimportować pliku +session.expired=Your session has expired. Please refresh the page and try again. + ############# # HOME-PAGE # ############# @@ -382,7 +402,7 @@ home.scalePages.title=Dopasuj rozmiar stron home.scalePages.desc=Dopasuj rozmiar stron wybranego dokumentu PDF scalePages.tags=resize,modify,dimension,adapt -home.pipeline.title=Automatyzacja (Zaawansowane) +home.pipeline.title=Automatyzacja home.pipeline.desc=Wykonaj wiele akcji na dokumentach PDF, tworząc automatyzację pipeline.tags=automate,sequence,scripted,batch-process @@ -482,6 +502,11 @@ home.removeImagePdf.title=Remove image home.removeImagePdf.desc=Remove image from PDF to reduce file size removeImagePdf.tags=Remove Image,Page operations,Back end,server side + +home.splitPdfByChapters.title=Split PDF by Chapters +home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure. +splitPdfByChapters.tags=split,chapters,bookmarks,organize + #replace-invert-color replace-color.title=Replace-Invert-Color replace-color.header=Replace-Invert Color PDF @@ -526,7 +551,10 @@ login.oauth2AccessDenied=Brak dostępu login.oauth2InvalidTokenResponse=Nieprawidłowa odpowiedź na token login.oauth2InvalidIdToken=Nieprawidłowa wartość tokenu login.userIsDisabled=User is deactivated, login is currently blocked with this username. Please contact the administrator. - +login.alreadyLoggedIn=You are already logged in to +login.alreadyLoggedIn2=devices. Please log out of the devices and try again. +login.toManySessions=You have too many active sessions +login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro. #auto-redact autoRedact.title=Automatyczne zaciemnienie @@ -1154,6 +1182,8 @@ licenses.license=Licencja survey.nav=Ankieta survey.title=Ankieta Stirling-PDF survey.description=Stirling-PDF nie śledzi swoich użytkowników, więc chciałby poznać opinie swoich użytkowników! +survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here: +survey.changes2=With these changes we are getting paid business support and funding survey.please=Wypełnij proszę ankietę dla nas! survey.disabled=(Blokada wyskakującego okienka z ankieta zostanie dodane w następnych aktualizacjach, ale będzie dostępna na dole strony) survey.button=Wypełnij ankietę @@ -1179,3 +1209,17 @@ removeImage.title=Remove image removeImage.header=Remove image removeImage.removeImage=Remove image removeImage.submit=Remove image + + +splitByChapters.title=Split PDF by Chapters +splitByChapters.header=Split PDF by Chapters +splitByChapters.bookmarkLevel=Bookmark Level +splitByChapters.includeMetadata=Include Metadata +splitByChapters.allowDuplicates=Allow Duplicates +splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure. +splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.). +splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF. +splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs. +splitByChapters.submit=Split PDF + + diff --git a/src/main/resources/messages_pt_BR.properties b/src/main/resources/messages_pt_BR.properties index b1fc9dee..1c809b8a 100644 --- a/src/main/resources/messages_pt_BR.properties +++ b/src/main/resources/messages_pt_BR.properties @@ -76,6 +76,7 @@ donate=Doar color=Cor sponsor=Patrocine info=Informações +pro=Pro page=Page pages=Pages @@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Pipeline: pipelineOptions.saveButton=Baixar pipelineOptions.validateButton=Validar +######################## +# ENTERPRISE EDITION # +######################## +enterpriseEdition.button=Upgrade to Pro +enterpriseEdition.warning=This feature is only available to Pro users. +enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features. +enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro +################# +# Analytics # +################# +analytics.title=Do you want make Stirling PDF better? +analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents. +analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better. +analytics.enable=Enable analytics +analytics.disable=Disable analytics +analytics.settings=You can change the settings for analytics in the config/settings.yml file ############# # NAVBAR # @@ -128,6 +145,7 @@ navbar.sections.convertFrom=Converter de PDF navbar.sections.security=Assinatura & Segurança navbar.sections.advance=Avançado navbar.sections.edit=Visualizar & editar +navbar.sections.popular=Popular ############# # SETTINGS # @@ -225,6 +243,8 @@ database.fileNotFound=Arquivo não encontrado database.fileNullOrEmpty=O arquivo não estar nulo ou vazio database.failedImportFile=Falha ao importar arquivo +session.expired=Your session has expired. Please refresh the page and try again. + ############# # HOME-PAGE # ############# @@ -382,7 +402,7 @@ home.scalePages.title=Ajustar Tamanho/Escala de Página home.scalePages.desc=Alterar o tamanho/escala da página e/ou seu conteúdo. scalePages.tags=redimensionar,modificar,dimensão,adaptar -home.pipeline.title=Pipeline (Avançado) +home.pipeline.title=Pipeline home.pipeline.desc=Executar várias ações em PDFs definindo scripts de pipeline pipeline.tags=automatizar,sequência,scriptado,processo-em-lote @@ -482,6 +502,11 @@ home.removeImagePdf.title=Remover imagem home.removeImagePdf.desc=Remova a imagem do PDF para reduzir o tamanho do arquivo removeImagePdf.tags=Remover imagem,operações de página,back-end,lado do servidor + +home.splitPdfByChapters.title=Split PDF by Chapters +home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure. +splitPdfByChapters.tags=split,chapters,bookmarks,organize + #replace-invert-color replace-color.title=Replace-Invert-Color replace-color.header=Replace-Invert Color PDF @@ -526,7 +551,10 @@ login.oauth2AccessDenied=Acesso negado login.oauth2InvalidTokenResponse=Resposta de token inválida login.oauth2InvalidIdToken=Id de token inválido login.userIsDisabled=O usuário está desativado, o login está atualmente bloqueado com este nome de usuário. Entre em contato com o administrador. - +login.alreadyLoggedIn=You are already logged in to +login.alreadyLoggedIn2=devices. Please log out of the devices and try again. +login.toManySessions=You have too many active sessions +login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro. #auto-redact autoRedact.title=Redigir automaticamente @@ -1154,6 +1182,8 @@ licenses.license=Licença survey.nav=Pesquisa survey.title=Pesquisa Stirling-PDF survey.description=Stirling-PDF não tem rastreamento, então queremos ouvir nossos usuários para melhorar o Stirling-PDF! +survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here: +survey.changes2=With these changes we are getting paid business support and funding survey.please=Por favor, considere responder à nossa pesquisa! survey.disabled=(O pop-up da pesquisa será desativado nas atualizações seguintes, mas estará disponível no final da página) survey.button=Responda a pesquisa @@ -1179,3 +1209,17 @@ removeImage.title=Remover imagem removeImage.header=Remover imagem removeImage.removeImage=Remover imagem removeImage.submit=Remover imagem + + +splitByChapters.title=Split PDF by Chapters +splitByChapters.header=Split PDF by Chapters +splitByChapters.bookmarkLevel=Bookmark Level +splitByChapters.includeMetadata=Include Metadata +splitByChapters.allowDuplicates=Allow Duplicates +splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure. +splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.). +splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF. +splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs. +splitByChapters.submit=Split PDF + + diff --git a/src/main/resources/messages_pt_PT.properties b/src/main/resources/messages_pt_PT.properties index 7f6e2956..60f96104 100644 --- a/src/main/resources/messages_pt_PT.properties +++ b/src/main/resources/messages_pt_PT.properties @@ -76,6 +76,7 @@ donate=Donate color=Color sponsor=Sponsor info=Info +pro=Pro page=Page pages=Pages @@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Pipeline: pipelineOptions.saveButton=Descarregar pipelineOptions.validateButton=Validar +######################## +# ENTERPRISE EDITION # +######################## +enterpriseEdition.button=Upgrade to Pro +enterpriseEdition.warning=This feature is only available to Pro users. +enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features. +enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro +################# +# Analytics # +################# +analytics.title=Do you want make Stirling PDF better? +analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents. +analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better. +analytics.enable=Enable analytics +analytics.disable=Disable analytics +analytics.settings=You can change the settings for analytics in the config/settings.yml file ############# # NAVBAR # @@ -128,6 +145,7 @@ navbar.sections.convertFrom=Convert from PDF navbar.sections.security=Sign & Security navbar.sections.advance=Advanced navbar.sections.edit=View & Edit +navbar.sections.popular=Popular ############# # SETTINGS # @@ -225,6 +243,8 @@ database.fileNotFound=File not Found database.fileNullOrEmpty=File must not be null or empty database.failedImportFile=Failed Import File +session.expired=Your session has expired. Please refresh the page and try again. + ############# # HOME-PAGE # ############# @@ -482,6 +502,11 @@ home.removeImagePdf.title=Remove image home.removeImagePdf.desc=Remove image from PDF to reduce file size removeImagePdf.tags=Remove Image,Page operations,Back end,server side + +home.splitPdfByChapters.title=Split PDF by Chapters +home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure. +splitPdfByChapters.tags=split,chapters,bookmarks,organize + #replace-invert-color replace-color.title=Replace-Invert-Color replace-color.header=Replace-Invert Color PDF @@ -526,7 +551,10 @@ login.oauth2AccessDenied=Access Denied login.oauth2InvalidTokenResponse=Invalid Token Response login.oauth2InvalidIdToken=Invalid Id Token login.userIsDisabled=User is deactivated, login is currently blocked with this username. Please contact the administrator. - +login.alreadyLoggedIn=You are already logged in to +login.alreadyLoggedIn2=devices. Please log out of the devices and try again. +login.toManySessions=You have too many active sessions +login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro. #auto-redact autoRedact.title=Edição Automática @@ -1154,6 +1182,8 @@ licenses.license=Licença survey.nav=Survey survey.title=Stirling-PDF Survey survey.description=Stirling-PDF has no tracking so we want to hear from our users to improve Stirling-PDF! +survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here: +survey.changes2=With these changes we are getting paid business support and funding survey.please=Please consider taking our survey! survey.disabled=(Survey popup will be disabled in following updates but available at foot of page) survey.button=Take Survey @@ -1179,3 +1209,17 @@ removeImage.title=Remove image removeImage.header=Remove image removeImage.removeImage=Remove image removeImage.submit=Remove image + + +splitByChapters.title=Split PDF by Chapters +splitByChapters.header=Split PDF by Chapters +splitByChapters.bookmarkLevel=Bookmark Level +splitByChapters.includeMetadata=Include Metadata +splitByChapters.allowDuplicates=Allow Duplicates +splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure. +splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.). +splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF. +splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs. +splitByChapters.submit=Split PDF + + diff --git a/src/main/resources/messages_ro_RO.properties b/src/main/resources/messages_ro_RO.properties index f065256d..0fdb5695 100644 --- a/src/main/resources/messages_ro_RO.properties +++ b/src/main/resources/messages_ro_RO.properties @@ -76,6 +76,7 @@ donate=Donează color=Culoare sponsor=Sponsor info=Informații +pro=Pro page=Page pages=Pages @@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Pipeline: pipelineOptions.saveButton=Descarcă pipelineOptions.validateButton=Validează +######################## +# ENTERPRISE EDITION # +######################## +enterpriseEdition.button=Upgrade to Pro +enterpriseEdition.warning=This feature is only available to Pro users. +enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features. +enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro +################# +# Analytics # +################# +analytics.title=Do you want make Stirling PDF better? +analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents. +analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better. +analytics.enable=Enable analytics +analytics.disable=Disable analytics +analytics.settings=You can change the settings for analytics in the config/settings.yml file ############# # NAVBAR # @@ -128,6 +145,7 @@ navbar.sections.convertFrom=Convertește din PDF navbar.sections.security=Semnează & Securitate navbar.sections.advance=Avansat navbar.sections.edit=Vizualizează & Editează +navbar.sections.popular=Popular ############# # SETTINGS # @@ -225,6 +243,8 @@ database.fileNotFound=Fișierul nu a fost găsit database.fileNullOrEmpty=Fișierul nu trebuie să fie nul sau gol database.failedImportFile=Importul Fișierului a Eșuat +session.expired=Your session has expired. Please refresh the page and try again. + ############# # HOME-PAGE # ############# @@ -482,6 +502,11 @@ home.removeImagePdf.title=Elimină imagine home.removeImagePdf.desc=Elimină imaginea din PDF pentru a reduce dimensiunea fișierului removeImagePdf.tags=Elimină Imagine,Operații pagină,Back end,server side + +home.splitPdfByChapters.title=Split PDF by Chapters +home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure. +splitPdfByChapters.tags=split,chapters,bookmarks,organize + #replace-invert-color replace-color.title=Replace-Invert-Color replace-color.header=Replace-Invert Color PDF @@ -526,7 +551,10 @@ login.oauth2AccessDenied=Acces Refuzat login.oauth2InvalidTokenResponse=Răspuns Invalid la Token login.oauth2InvalidIdToken=Token de Id Invalid login.userIsDisabled=Utilizatorul este dezactivat, conectarea este în prezent blocată cu acest nume de utilizator. Te rugăm să contactezi administratorul. - +login.alreadyLoggedIn=You are already logged in to +login.alreadyLoggedIn2=devices. Please log out of the devices and try again. +login.toManySessions=You have too many active sessions +login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro. #auto-redact autoRedact.title=Redactare Automată @@ -1154,6 +1182,8 @@ licenses.license=Licență survey.nav=Sondaj survey.title=Sondaj Stirling-PDF survey.description=Stirling-PDF nu are urmărire, așa că vrem să auzim de la utilizatorii noștri pentru a îmbunătăți Stirling-PDF! +survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here: +survey.changes2=With these changes we are getting paid business support and funding survey.please=Te rugăm să iei în considerare completarea sondajului nostru! survey.disabled=(Fereastra pop-up a sondajului va fi dezactivată în următoarele actualizări, dar va fi disponibilă în subsolul paginii) survey.button=Completează Sondajul @@ -1179,3 +1209,17 @@ removeImage.title=Elimină imagine removeImage.header=Elimină imagine removeImage.removeImage=Elimină imagine removeImage.submit=Elimină imagine + + +splitByChapters.title=Split PDF by Chapters +splitByChapters.header=Split PDF by Chapters +splitByChapters.bookmarkLevel=Bookmark Level +splitByChapters.includeMetadata=Include Metadata +splitByChapters.allowDuplicates=Allow Duplicates +splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure. +splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.). +splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF. +splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs. +splitByChapters.submit=Split PDF + + diff --git a/src/main/resources/messages_ru_RU.properties b/src/main/resources/messages_ru_RU.properties index b5db3c47..1ac98ac3 100644 --- a/src/main/resources/messages_ru_RU.properties +++ b/src/main/resources/messages_ru_RU.properties @@ -76,6 +76,7 @@ donate=Пожертвовать color=Цвет sponsor=Спонсор info=Info +pro=Pro page=Page pages=Pages @@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Конвейер: pipelineOptions.saveButton=Скачать pipelineOptions.validateButton=Проверить +######################## +# ENTERPRISE EDITION # +######################## +enterpriseEdition.button=Upgrade to Pro +enterpriseEdition.warning=This feature is only available to Pro users. +enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features. +enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro +################# +# Analytics # +################# +analytics.title=Do you want make Stirling PDF better? +analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents. +analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better. +analytics.enable=Enable analytics +analytics.disable=Disable analytics +analytics.settings=You can change the settings for analytics in the config/settings.yml file ############# # NAVBAR # @@ -128,6 +145,7 @@ navbar.sections.convertFrom=Convert from PDF navbar.sections.security=Sign & Security navbar.sections.advance=Advanced navbar.sections.edit=View & Edit +navbar.sections.popular=Popular ############# # SETTINGS # @@ -225,6 +243,8 @@ database.fileNotFound=File not Found database.fileNullOrEmpty=File must not be null or empty database.failedImportFile=Failed Import File +session.expired=Your session has expired. Please refresh the page and try again. + ############# # HOME-PAGE # ############# @@ -482,6 +502,11 @@ home.removeImagePdf.title=Remove image home.removeImagePdf.desc=Remove image from PDF to reduce file size removeImagePdf.tags=Remove Image,Page operations,Back end,server side + +home.splitPdfByChapters.title=Split PDF by Chapters +home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure. +splitPdfByChapters.tags=split,chapters,bookmarks,organize + #replace-invert-color replace-color.title=Replace-Invert-Color replace-color.header=Replace-Invert Color PDF @@ -526,7 +551,10 @@ login.oauth2AccessDenied=Access Denied login.oauth2InvalidTokenResponse=Invalid Token Response login.oauth2InvalidIdToken=Invalid Id Token login.userIsDisabled=User is deactivated, login is currently blocked with this username. Please contact the administrator. - +login.alreadyLoggedIn=You are already logged in to +login.alreadyLoggedIn2=devices. Please log out of the devices and try again. +login.toManySessions=You have too many active sessions +login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro. #auto-redact autoRedact.title=Автоматическое редактирование @@ -1154,6 +1182,8 @@ licenses.license=Лицензия survey.nav=Survey survey.title=Stirling-PDF Survey survey.description=Stirling-PDF has no tracking so we want to hear from our users to improve Stirling-PDF! +survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here: +survey.changes2=With these changes we are getting paid business support and funding survey.please=Please consider taking our survey! survey.disabled=(Survey popup will be disabled in following updates but available at foot of page) survey.button=Take Survey @@ -1179,3 +1209,17 @@ removeImage.title=Remove image removeImage.header=Remove image removeImage.removeImage=Remove image removeImage.submit=Remove image + + +splitByChapters.title=Split PDF by Chapters +splitByChapters.header=Split PDF by Chapters +splitByChapters.bookmarkLevel=Bookmark Level +splitByChapters.includeMetadata=Include Metadata +splitByChapters.allowDuplicates=Allow Duplicates +splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure. +splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.). +splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF. +splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs. +splitByChapters.submit=Split PDF + + diff --git a/src/main/resources/messages_sk_SK.properties b/src/main/resources/messages_sk_SK.properties index d64aaeaf..b1a3d568 100644 --- a/src/main/resources/messages_sk_SK.properties +++ b/src/main/resources/messages_sk_SK.properties @@ -76,6 +76,7 @@ donate=Darovať color=Farba sponsor=Sponzorovať info=Info +pro=Pro page=Page pages=Pages @@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Pipeline: pipelineOptions.saveButton=Stiahnuť pipelineOptions.validateButton=Overiť +######################## +# ENTERPRISE EDITION # +######################## +enterpriseEdition.button=Upgrade to Pro +enterpriseEdition.warning=This feature is only available to Pro users. +enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features. +enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro +################# +# Analytics # +################# +analytics.title=Do you want make Stirling PDF better? +analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents. +analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better. +analytics.enable=Enable analytics +analytics.disable=Disable analytics +analytics.settings=You can change the settings for analytics in the config/settings.yml file ############# # NAVBAR # @@ -128,6 +145,7 @@ navbar.sections.convertFrom=Convert from PDF navbar.sections.security=Sign & Security navbar.sections.advance=Advanced navbar.sections.edit=View & Edit +navbar.sections.popular=Popular ############# # SETTINGS # @@ -225,6 +243,8 @@ database.fileNotFound=File not Found database.fileNullOrEmpty=File must not be null or empty database.failedImportFile=Failed Import File +session.expired=Your session has expired. Please refresh the page and try again. + ############# # HOME-PAGE # ############# @@ -382,7 +402,7 @@ home.scalePages.title=Prispôsobiť veľkosť/škálovanie stránok home.scalePages.desc=Zmeniť veľkosť/škálovanie stránky a/alebo jej obsahu. scalePages.tags=veľkosť,modifikovať,rozmery,prispôsobiť -home.pipeline.title=Pipeline (Pokročilé) +home.pipeline.title=Pipeline home.pipeline.desc=Spustiť viacero akcií na PDF definovaním pipeline skriptov pipeline.tags=automatizovať,sekvencia,skriptované,dávkové spracovanie @@ -482,6 +502,11 @@ home.removeImagePdf.title=Remove image home.removeImagePdf.desc=Remove image from PDF to reduce file size removeImagePdf.tags=Remove Image,Page operations,Back end,server side + +home.splitPdfByChapters.title=Split PDF by Chapters +home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure. +splitPdfByChapters.tags=split,chapters,bookmarks,organize + #replace-invert-color replace-color.title=Replace-Invert-Color replace-color.header=Replace-Invert Color PDF @@ -526,7 +551,10 @@ login.oauth2AccessDenied=Access Denied login.oauth2InvalidTokenResponse=Invalid Token Response login.oauth2InvalidIdToken=Invalid Id Token login.userIsDisabled=User is deactivated, login is currently blocked with this username. Please contact the administrator. - +login.alreadyLoggedIn=You are already logged in to +login.alreadyLoggedIn2=devices. Please log out of the devices and try again. +login.toManySessions=You have too many active sessions +login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro. #auto-redact autoRedact.title=Automatické redigovanie @@ -1154,6 +1182,8 @@ licenses.license=Licencia survey.nav=Survey survey.title=Stirling-PDF Survey survey.description=Stirling-PDF has no tracking so we want to hear from our users to improve Stirling-PDF! +survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here: +survey.changes2=With these changes we are getting paid business support and funding survey.please=Please consider taking our survey! survey.disabled=(Survey popup will be disabled in following updates but available at foot of page) survey.button=Take Survey @@ -1179,3 +1209,17 @@ removeImage.title=Remove image removeImage.header=Remove image removeImage.removeImage=Remove image removeImage.submit=Remove image + + +splitByChapters.title=Split PDF by Chapters +splitByChapters.header=Split PDF by Chapters +splitByChapters.bookmarkLevel=Bookmark Level +splitByChapters.includeMetadata=Include Metadata +splitByChapters.allowDuplicates=Allow Duplicates +splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure. +splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.). +splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF. +splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs. +splitByChapters.submit=Split PDF + + diff --git a/src/main/resources/messages_sr_LATN_RS.properties b/src/main/resources/messages_sr_LATN_RS.properties index 53bb4230..a96a510a 100644 --- a/src/main/resources/messages_sr_LATN_RS.properties +++ b/src/main/resources/messages_sr_LATN_RS.properties @@ -76,6 +76,7 @@ donate=Donate color=Color sponsor=Sponsor info=Info +pro=Pro page=Page pages=Pages @@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Pipeline: pipelineOptions.saveButton=Preuzmi pipelineOptions.validateButton=Proveri +######################## +# ENTERPRISE EDITION # +######################## +enterpriseEdition.button=Upgrade to Pro +enterpriseEdition.warning=This feature is only available to Pro users. +enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features. +enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro +################# +# Analytics # +################# +analytics.title=Do you want make Stirling PDF better? +analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents. +analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better. +analytics.enable=Enable analytics +analytics.disable=Disable analytics +analytics.settings=You can change the settings for analytics in the config/settings.yml file ############# # NAVBAR # @@ -128,6 +145,7 @@ navbar.sections.convertFrom=Convert from PDF navbar.sections.security=Sign & Security navbar.sections.advance=Advanced navbar.sections.edit=View & Edit +navbar.sections.popular=Popular ############# # SETTINGS # @@ -225,6 +243,8 @@ database.fileNotFound=File not Found database.fileNullOrEmpty=File must not be null or empty database.failedImportFile=Failed Import File +session.expired=Your session has expired. Please refresh the page and try again. + ############# # HOME-PAGE # ############# @@ -482,6 +502,11 @@ home.removeImagePdf.title=Remove image home.removeImagePdf.desc=Remove image from PDF to reduce file size removeImagePdf.tags=Remove Image,Page operations,Back end,server side + +home.splitPdfByChapters.title=Split PDF by Chapters +home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure. +splitPdfByChapters.tags=split,chapters,bookmarks,organize + #replace-invert-color replace-color.title=Replace-Invert-Color replace-color.header=Replace-Invert Color PDF @@ -526,7 +551,10 @@ login.oauth2AccessDenied=Access Denied login.oauth2InvalidTokenResponse=Invalid Token Response login.oauth2InvalidIdToken=Invalid Id Token login.userIsDisabled=User is deactivated, login is currently blocked with this username. Please contact the administrator. - +login.alreadyLoggedIn=You are already logged in to +login.alreadyLoggedIn2=devices. Please log out of the devices and try again. +login.toManySessions=You have too many active sessions +login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro. #auto-redact autoRedact.title=Auto Cenzura @@ -1154,6 +1182,8 @@ licenses.license=License survey.nav=Survey survey.title=Stirling-PDF Survey survey.description=Stirling-PDF has no tracking so we want to hear from our users to improve Stirling-PDF! +survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here: +survey.changes2=With these changes we are getting paid business support and funding survey.please=Please consider taking our survey! survey.disabled=(Survey popup will be disabled in following updates but available at foot of page) survey.button=Take Survey @@ -1179,3 +1209,17 @@ removeImage.title=Remove image removeImage.header=Remove image removeImage.removeImage=Remove image removeImage.submit=Remove image + + +splitByChapters.title=Split PDF by Chapters +splitByChapters.header=Split PDF by Chapters +splitByChapters.bookmarkLevel=Bookmark Level +splitByChapters.includeMetadata=Include Metadata +splitByChapters.allowDuplicates=Allow Duplicates +splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure. +splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.). +splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF. +splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs. +splitByChapters.submit=Split PDF + + diff --git a/src/main/resources/messages_sv_SE.properties b/src/main/resources/messages_sv_SE.properties index a85d294c..e42ae878 100644 --- a/src/main/resources/messages_sv_SE.properties +++ b/src/main/resources/messages_sv_SE.properties @@ -76,6 +76,7 @@ donate=Donera color=Färg sponsor=Sponsor info=Info +pro=Pro page=Page pages=Pages @@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Pipeline: pipelineOptions.saveButton=Ladda ner pipelineOptions.validateButton=Validera +######################## +# ENTERPRISE EDITION # +######################## +enterpriseEdition.button=Upgrade to Pro +enterpriseEdition.warning=This feature is only available to Pro users. +enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features. +enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro +################# +# Analytics # +################# +analytics.title=Do you want make Stirling PDF better? +analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents. +analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better. +analytics.enable=Enable analytics +analytics.disable=Disable analytics +analytics.settings=You can change the settings for analytics in the config/settings.yml file ############# # NAVBAR # @@ -128,6 +145,7 @@ navbar.sections.convertFrom=Konvertera från PDF navbar.sections.security=Signera & Säkerhet navbar.sections.advance=Avancerat navbar.sections.edit=Visa & Redigera +navbar.sections.popular=Popular ############# # SETTINGS # @@ -225,6 +243,8 @@ database.fileNotFound=Filen hittades inte database.fileNullOrEmpty=Filen får inte vara null eller tom database.failedImportFile=Misslyckades med att importera fil +session.expired=Your session has expired. Please refresh the page and try again. + ############# # HOME-PAGE # ############# @@ -482,6 +502,11 @@ home.removeImagePdf.title=Ta bort bild home.removeImagePdf.desc=Ta bort bild från PDF för att minska filstorlek removeImagePdf.tags=Ta bort bild,Sidoperationer,Backend,serversida + +home.splitPdfByChapters.title=Split PDF by Chapters +home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure. +splitPdfByChapters.tags=split,chapters,bookmarks,organize + #replace-invert-color replace-color.title=Replace-Invert-Color replace-color.header=Replace-Invert Color PDF @@ -526,7 +551,10 @@ login.oauth2AccessDenied=Åtkomst nekad login.oauth2InvalidTokenResponse=Ogiltigt token-svar login.oauth2InvalidIdToken=Ogiltigt Id-token login.userIsDisabled=Användaren är inaktiverad, inloggning är för närvarande blockerad med detta användarnamn. Kontakta administratören. - +login.alreadyLoggedIn=You are already logged in to +login.alreadyLoggedIn2=devices. Please log out of the devices and try again. +login.toManySessions=You have too many active sessions +login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro. #auto-redact autoRedact.title=Auto-redigera @@ -1154,6 +1182,8 @@ licenses.license=Licens survey.nav=Undersökning survey.title=Stirling-PDF-undersökning survey.description=Stirling-PDF har ingen spårning så vi vill höra från våra användare för att förbättra Stirling-PDF! +survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here: +survey.changes2=With these changes we are getting paid business support and funding survey.please=Vänligen överväg att delta i vår undersökning! survey.disabled=(Undersökningspopup kommer att inaktiveras i kommande uppdateringar men finns tillgänglig längst ner på sidan) survey.button=Delta i undersökningen @@ -1179,3 +1209,17 @@ removeImage.title=Ta bort bild removeImage.header=Ta bort bild removeImage.removeImage=Ta bort bild removeImage.submit=Ta bort bild + + +splitByChapters.title=Split PDF by Chapters +splitByChapters.header=Split PDF by Chapters +splitByChapters.bookmarkLevel=Bookmark Level +splitByChapters.includeMetadata=Include Metadata +splitByChapters.allowDuplicates=Allow Duplicates +splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure. +splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.). +splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF. +splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs. +splitByChapters.submit=Split PDF + + diff --git a/src/main/resources/messages_th_TH.properties b/src/main/resources/messages_th_TH.properties index 69f93721..9623bf2e 100644 --- a/src/main/resources/messages_th_TH.properties +++ b/src/main/resources/messages_th_TH.properties @@ -76,6 +76,7 @@ donate=บริจาค color=สี sponsor=ผู้สนับสนุน info=ข้อมูล +pro=Pro page=Page pages=Pages @@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Pipeline: pipelineOptions.saveButton=ดาวน์โหลด pipelineOptions.validateButton=ตรวจสอบความถูกต้อง +######################## +# ENTERPRISE EDITION # +######################## +enterpriseEdition.button=Upgrade to Pro +enterpriseEdition.warning=This feature is only available to Pro users. +enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features. +enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro +################# +# Analytics # +################# +analytics.title=Do you want make Stirling PDF better? +analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents. +analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better. +analytics.enable=Enable analytics +analytics.disable=Disable analytics +analytics.settings=You can change the settings for analytics in the config/settings.yml file ############# # NAVBAR # @@ -128,6 +145,7 @@ navbar.sections.convertFrom=แปลงจาก PDF navbar.sections.security=ลงนามและความปลอดภัย navbar.sections.advance=ขั้นสูง navbar.sections.edit=ดูและแก้ไข +navbar.sections.popular=Popular ############# # SETTINGS # @@ -225,6 +243,8 @@ database.fileNotFound=ไม่พบไฟล์ database.fileNullOrEmpty=ไฟล์ต้องไม่ว่างเปล่าหรือไม่มีข้อมูล database.failedImportFile=การนำเข้าไฟล์ล้มเหลว +session.expired=Your session has expired. Please refresh the page and try again. + ############# # HOME-PAGE # ############# @@ -482,6 +502,11 @@ home.removeImagePdf.title=Remove image home.removeImagePdf.desc=Remove image from PDF to reduce file size removeImagePdf.tags=Remove Image,Page operations,Back end,server side + +home.splitPdfByChapters.title=Split PDF by Chapters +home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure. +splitPdfByChapters.tags=split,chapters,bookmarks,organize + #replace-invert-color replace-color.title=Replace-Invert-Color replace-color.header=Replace-Invert Color PDF @@ -526,7 +551,10 @@ login.oauth2AccessDenied=การเข้าถึงถูกปฏิเส login.oauth2InvalidTokenResponse=การตอบกลับโทเค็นไม่ถูกต้อง login.oauth2InvalidIdToken=โทเค็น Id ไม่ถูกต้อง login.userIsDisabled=User is deactivated, login is currently blocked with this username. Please contact the administrator. - +login.alreadyLoggedIn=You are already logged in to +login.alreadyLoggedIn2=devices. Please log out of the devices and try again. +login.toManySessions=You have too many active sessions +login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro. #auto-redact autoRedact.title=ซ่อนข้อมูลอัตโนมัติ @@ -1154,6 +1182,8 @@ licenses.license=ใบอนุญาต survey.nav=สำรวจ survey.title=สำรวจ Stirling-PDF survey.description=Stirling-PDF ไม่มีการติดตาม ดังนั้นเราต้องการฟังความคิดเห็นจากผู้ใช้เพื่อปรับปรุง Stirling-PDF! +survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here: +survey.changes2=With these changes we are getting paid business support and funding survey.please=กรุณาพิจารณาการสำรวจของเรา! survey.disabled=(ป๊อปอัปการสำรวจจะถูกปิดใช้งานในการอัปเดตต่อไปนี้ แต่สามารถใช้ได้ที่ส่วนท้ายของหน้า) survey.button=เริ่มสำรวจ @@ -1179,3 +1209,17 @@ removeImage.title=Remove image removeImage.header=Remove image removeImage.removeImage=Remove image removeImage.submit=Remove image + + +splitByChapters.title=Split PDF by Chapters +splitByChapters.header=Split PDF by Chapters +splitByChapters.bookmarkLevel=Bookmark Level +splitByChapters.includeMetadata=Include Metadata +splitByChapters.allowDuplicates=Allow Duplicates +splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure. +splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.). +splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF. +splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs. +splitByChapters.submit=Split PDF + + diff --git a/src/main/resources/messages_tr_TR.properties b/src/main/resources/messages_tr_TR.properties index ad3a5339..88cade12 100644 --- a/src/main/resources/messages_tr_TR.properties +++ b/src/main/resources/messages_tr_TR.properties @@ -76,6 +76,7 @@ donate=Bağış Yapın color=Renk sponsor=Bağış info=Bilgi +pro=Pro page=Page pages=Pages @@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Çoklu İşlemler: pipelineOptions.saveButton=İndir pipelineOptions.validateButton=Doğrula +######################## +# ENTERPRISE EDITION # +######################## +enterpriseEdition.button=Upgrade to Pro +enterpriseEdition.warning=This feature is only available to Pro users. +enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features. +enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro +################# +# Analytics # +################# +analytics.title=Do you want make Stirling PDF better? +analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents. +analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better. +analytics.enable=Enable analytics +analytics.disable=Disable analytics +analytics.settings=You can change the settings for analytics in the config/settings.yml file ############# # NAVBAR # @@ -128,6 +145,7 @@ navbar.sections.convertFrom=PDF'den dönüştür navbar.sections.security=Oturum ve Güvenlik navbar.sections.advance=Gelişmiş navbar.sections.edit=Görüntüle ve Düzenle +navbar.sections.popular=Popular ############# # SETTINGS # @@ -225,6 +243,8 @@ database.fileNotFound=Dosya bulunamadı database.fileNullOrEmpty=Dosya yok veya boş olmamalıdır database.failedImportFile=Dosya İçe Aktarılamadı +session.expired=Your session has expired. Please refresh the page and try again. + ############# # HOME-PAGE # ############# @@ -382,7 +402,7 @@ home.scalePages.title=Sayfa boyutunu/ölçeğini ayarla home.scalePages.desc=Bir sayfanın ve/veya içeriğinin boyutunu/ölçeğini değiştirir scalePages.tags=boyutlandır,değiştir,boyut,uyarla -home.pipeline.title=Çoklu İşlemler (İleri Seviye) +home.pipeline.title=Çoklu İşlemler home.pipeline.desc=Çoklu İşlemler tanımlayarak PDF'lere birden fazla işlemi çalıştır pipeline.tags=otomatikleştir,sıralı,betikli,toplu-işlem @@ -482,6 +502,11 @@ home.removeImagePdf.title=Resmi kaldır home.removeImagePdf.desc=Dosya boyutunu küçültmek için PDF'den resmi kaldırın removeImagePdf.tags=Resmi Kaldır,Sayfa İşlemleri,Arka uç,sunucu tarafı + +home.splitPdfByChapters.title=Split PDF by Chapters +home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure. +splitPdfByChapters.tags=split,chapters,bookmarks,organize + #replace-invert-color replace-color.title=Replace-Invert-Color replace-color.header=Replace-Invert Color PDF @@ -526,7 +551,10 @@ login.oauth2AccessDenied=Erişim Reddedildi login.oauth2InvalidTokenResponse=Geçersiz Belirteç Yanıtı login.oauth2InvalidIdToken=Geçersiz Kimlik Belirteci login.userIsDisabled=Kullanıcı devre dışı bırakıldı, şu anda bu kullanıcı adıyla giriş engellendi. Lütfen yöneticiyle iletişime geçin. - +login.alreadyLoggedIn=You are already logged in to +login.alreadyLoggedIn2=devices. Please log out of the devices and try again. +login.toManySessions=You have too many active sessions +login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro. #auto-redact autoRedact.title=Otomatik Karartma @@ -1154,6 +1182,8 @@ licenses.license=Lisans survey.nav=Anket survey.title=Stirling-PDF Anketi survey.description=Stirling-PDF'te izleme yok, bu yüzden Stirling-PDF'i iyileştirmek için kullanıcılarımızdan geri bildirim almak istiyoruz! +survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here: +survey.changes2=With these changes we are getting paid business support and funding survey.please=Lütfen anketimize katılmayı düşünün! survey.disabled=(Anket açılır penceresi sonraki güncellemelerde devre dışı bırakılacak ancak sayfanın alt kısmında yer alacaktır) survey.button=Ankete Katıl @@ -1179,3 +1209,17 @@ removeImage.title=Resmi kaldır removeImage.header=Resmi kaldır removeImage.removeImage=Resmi kaldır removeImage.submit=Resmi kaldır + + +splitByChapters.title=Split PDF by Chapters +splitByChapters.header=Split PDF by Chapters +splitByChapters.bookmarkLevel=Bookmark Level +splitByChapters.includeMetadata=Include Metadata +splitByChapters.allowDuplicates=Allow Duplicates +splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure. +splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.). +splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF. +splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs. +splitByChapters.submit=Split PDF + + diff --git a/src/main/resources/messages_uk_UA.properties b/src/main/resources/messages_uk_UA.properties index ed35d4e6..b2b60611 100644 --- a/src/main/resources/messages_uk_UA.properties +++ b/src/main/resources/messages_uk_UA.properties @@ -76,6 +76,7 @@ donate=Задонатити color=Колір sponsor=Спонсор info=Інформація +pro=Pro page=Page pages=Pages @@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Конвеєр: pipelineOptions.saveButton=Завантажити pipelineOptions.validateButton=Перевірити +######################## +# ENTERPRISE EDITION # +######################## +enterpriseEdition.button=Upgrade to Pro +enterpriseEdition.warning=This feature is only available to Pro users. +enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features. +enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro +################# +# Analytics # +################# +analytics.title=Do you want make Stirling PDF better? +analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents. +analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better. +analytics.enable=Enable analytics +analytics.disable=Disable analytics +analytics.settings=You can change the settings for analytics in the config/settings.yml file ############# # NAVBAR # @@ -128,6 +145,7 @@ navbar.sections.convertFrom=Конвертувати з PDF navbar.sections.security=Підпис та Безпека navbar.sections.advance=Додаткове navbar.sections.edit=Перегляд та Редагування +navbar.sections.popular=Popular ############# # SETTINGS # @@ -225,6 +243,8 @@ database.fileNotFound=File not Found database.fileNullOrEmpty=File must not be null or empty database.failedImportFile=Failed Import File +session.expired=Your session has expired. Please refresh the page and try again. + ############# # HOME-PAGE # ############# @@ -482,6 +502,11 @@ home.removeImagePdf.title=Remove image home.removeImagePdf.desc=Remove image from PDF to reduce file size removeImagePdf.tags=Remove Image,Page operations,Back end,server side + +home.splitPdfByChapters.title=Split PDF by Chapters +home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure. +splitPdfByChapters.tags=split,chapters,bookmarks,organize + #replace-invert-color replace-color.title=Replace-Invert-Color replace-color.header=Replace-Invert Color PDF @@ -526,7 +551,10 @@ login.oauth2AccessDenied=Доступ заблоковано login.oauth2InvalidTokenResponse=Недійсна відповідь з токеном login.oauth2InvalidIdToken=Недійсний Id токен login.userIsDisabled=User is deactivated, login is currently blocked with this username. Please contact the administrator. - +login.alreadyLoggedIn=You are already logged in to +login.alreadyLoggedIn2=devices. Please log out of the devices and try again. +login.toManySessions=You have too many active sessions +login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro. #auto-redact autoRedact.title=Автоматичне редагування @@ -1154,6 +1182,8 @@ licenses.license=Ліцензія survey.nav=Опитування survey.title=Опитування Stirling-PDF survey.description=Stirling-PDF не має аналітичних засобів для відслідковування, тому ми хочемо почути думку від користувачів, як покращити Stirling-PDF! +survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here: +survey.changes2=With these changes we are getting paid business support and funding survey.please=Будь-ласка, пройдіть опитування! survey.disabled=(Вікно з опитування буде відключено у наступних оновленнях, але буде доступне внизу сторінки) survey.button=Пройти опитування @@ -1179,3 +1209,17 @@ removeImage.title=Remove image removeImage.header=Remove image removeImage.removeImage=Remove image removeImage.submit=Remove image + + +splitByChapters.title=Split PDF by Chapters +splitByChapters.header=Split PDF by Chapters +splitByChapters.bookmarkLevel=Bookmark Level +splitByChapters.includeMetadata=Include Metadata +splitByChapters.allowDuplicates=Allow Duplicates +splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure. +splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.). +splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF. +splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs. +splitByChapters.submit=Split PDF + + diff --git a/src/main/resources/messages_vi_VN.properties b/src/main/resources/messages_vi_VN.properties index c12a40d5..9b48912c 100644 --- a/src/main/resources/messages_vi_VN.properties +++ b/src/main/resources/messages_vi_VN.properties @@ -76,6 +76,7 @@ donate=Ủng hộ color=Màu sắc sponsor=Nhà tài trợ info=Thông tin +pro=Pro page=Page pages=Pages @@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=Pipeline: pipelineOptions.saveButton=Tải xuống pipelineOptions.validateButton=Xác thực +######################## +# ENTERPRISE EDITION # +######################## +enterpriseEdition.button=Upgrade to Pro +enterpriseEdition.warning=This feature is only available to Pro users. +enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features. +enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro +################# +# Analytics # +################# +analytics.title=Do you want make Stirling PDF better? +analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents. +analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better. +analytics.enable=Enable analytics +analytics.disable=Disable analytics +analytics.settings=You can change the settings for analytics in the config/settings.yml file ############# # NAVBAR # @@ -128,6 +145,7 @@ navbar.sections.convertFrom=Chuyển đổi từ PDF navbar.sections.security=Ký & Bảo mật navbar.sections.advance=Nâng cao navbar.sections.edit=Xem & Chỉnh sửa +navbar.sections.popular=Popular ############# # SETTINGS # @@ -225,6 +243,8 @@ database.fileNotFound=Không tìm thấy tệp database.fileNullOrEmpty=Tệp không được để trống hoặc rỗng database.failedImportFile=Không thể nhập tệp +session.expired=Your session has expired. Please refresh the page and try again. + ############# # HOME-PAGE # ############# @@ -482,6 +502,11 @@ home.removeImagePdf.title=Remove image home.removeImagePdf.desc=Remove image from PDF to reduce file size removeImagePdf.tags=Remove Image,Page operations,Back end,server side + +home.splitPdfByChapters.title=Split PDF by Chapters +home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure. +splitPdfByChapters.tags=split,chapters,bookmarks,organize + #replace-invert-color replace-color.title=Replace-Invert-Color replace-color.header=Replace-Invert Color PDF @@ -526,7 +551,10 @@ login.oauth2AccessDenied=Truy cập bị từ chối login.oauth2InvalidTokenResponse=Phản hồi token không hợp lệ login.oauth2InvalidIdToken=Id Token không hợp lệ login.userIsDisabled=User is deactivated, login is currently blocked with this username. Please contact the administrator. - +login.alreadyLoggedIn=You are already logged in to +login.alreadyLoggedIn2=devices. Please log out of the devices and try again. +login.toManySessions=You have too many active sessions +login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro. #auto-redact autoRedact.title=Tự động biên tập @@ -1154,6 +1182,8 @@ licenses.license=Giấy phép survey.nav=Khảo sát survey.title=Khảo sát Stirling-PDF survey.description=Stirling-PDF không có cài đặt theo dõi nên chúng tôi muốn nghe từ người dùng để cải thiện Stirling-PDF! +survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here: +survey.changes2=With these changes we are getting paid business support and funding survey.please=Vui lòng cân nhắc tham gia khảo sát của chúng tôi! survey.disabled=(Cửa sổ popup khảo sát sẽ bị vô hiệu hóa trong các bản cập nhật tiếp theo nhưng vẫn tìm thấy ở cuối trang) survey.button=Tham gia khảo sát @@ -1179,3 +1209,17 @@ removeImage.title=Remove image removeImage.header=Remove image removeImage.removeImage=Remove image removeImage.submit=Remove image + + +splitByChapters.title=Split PDF by Chapters +splitByChapters.header=Split PDF by Chapters +splitByChapters.bookmarkLevel=Bookmark Level +splitByChapters.includeMetadata=Include Metadata +splitByChapters.allowDuplicates=Allow Duplicates +splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure. +splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.). +splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF. +splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs. +splitByChapters.submit=Split PDF + + diff --git a/src/main/resources/messages_zh_CN.properties b/src/main/resources/messages_zh_CN.properties index 4ddf1e87..d30edd39 100644 --- a/src/main/resources/messages_zh_CN.properties +++ b/src/main/resources/messages_zh_CN.properties @@ -76,6 +76,7 @@ donate=捐款 color=颜色 sponsor=赞助 info=信息 +pro=Pro page=Page pages=Pages @@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=流水线: pipelineOptions.saveButton=下载 pipelineOptions.validateButton=验证 +######################## +# ENTERPRISE EDITION # +######################## +enterpriseEdition.button=Upgrade to Pro +enterpriseEdition.warning=This feature is only available to Pro users. +enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features. +enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro +################# +# Analytics # +################# +analytics.title=Do you want make Stirling PDF better? +analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents. +analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better. +analytics.enable=Enable analytics +analytics.disable=Disable analytics +analytics.settings=You can change the settings for analytics in the config/settings.yml file ############# # NAVBAR # @@ -128,6 +145,7 @@ navbar.sections.convertFrom=从PDF转换 navbar.sections.security=签名和安全 navbar.sections.advance=高级功能 navbar.sections.edit=查看和编辑 +navbar.sections.popular=Popular ############# # SETTINGS # @@ -225,6 +243,8 @@ database.fileNotFound=未找到文件 database.fileNullOrEmpty=文件不能为空 database.failedImportFile=导入文件失败 +session.expired=Your session has expired. Please refresh the page and try again. + ############# # HOME-PAGE # ############# @@ -482,6 +502,11 @@ home.removeImagePdf.title=删除图像 home.removeImagePdf.desc=删除图像减少PDF大小 removeImagePdf.tags=删除图像, 页面操作, 后端, 服务端 + +home.splitPdfByChapters.title=Split PDF by Chapters +home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure. +splitPdfByChapters.tags=split,chapters,bookmarks,organize + #replace-invert-color replace-color.title=Replace-Invert-Color replace-color.header=Replace-Invert Color PDF @@ -526,7 +551,10 @@ login.oauth2AccessDenied=拒绝访问 login.oauth2InvalidTokenResponse=无效的Token响应 login.oauth2InvalidIdToken=无效的Token login.userIsDisabled=用户被禁用,登录已被阻止。请联系管理员。 - +login.alreadyLoggedIn=You are already logged in to +login.alreadyLoggedIn2=devices. Please log out of the devices and try again. +login.toManySessions=You have too many active sessions +login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro. #auto-redact autoRedact.title=自动删除 @@ -1154,6 +1182,8 @@ licenses.license=许可证 survey.nav=调查 survey.title=Stirling-PDF调查 survey.description=Stirling-PDF没有跟踪器,所以我们希望听取用户的意见来改进Stirling-PDF! +survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here: +survey.changes2=With these changes we are getting paid business support and funding survey.please=请考虑参加我们的调查! survey.disabled=(调查弹出窗口将在后续更新中被禁用,但可在页脚处查看) survey.button=参与调查 @@ -1179,3 +1209,17 @@ removeImage.title=删除图像 removeImage.header=删除图像 removeImage.removeImage=删除图像 removeImage.submit=删除图像 + + +splitByChapters.title=Split PDF by Chapters +splitByChapters.header=Split PDF by Chapters +splitByChapters.bookmarkLevel=Bookmark Level +splitByChapters.includeMetadata=Include Metadata +splitByChapters.allowDuplicates=Allow Duplicates +splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure. +splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.). +splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF. +splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs. +splitByChapters.submit=Split PDF + + diff --git a/src/main/resources/messages_zh_TW.properties b/src/main/resources/messages_zh_TW.properties index 9e912b55..3f5f50f4 100644 --- a/src/main/resources/messages_zh_TW.properties +++ b/src/main/resources/messages_zh_TW.properties @@ -76,6 +76,7 @@ donate=捐贈 color=顏色 sponsor=贊助 info=Info +pro=Pro page=Page pages=Pages @@ -110,8 +111,24 @@ pipelineOptions.pipelineHeader=管道: pipelineOptions.saveButton=下載 pipelineOptions.validateButton=驗證 +######################## +# ENTERPRISE EDITION # +######################## +enterpriseEdition.button=Upgrade to Pro +enterpriseEdition.warning=This feature is only available to Pro users. +enterpriseEdition.yamlAdvert=Stirling PDF Pro supports YAML configuration files and other SSO features. +enterpriseEdition.ssoAdvert=Looking for more user management features? Check out Stirling PDF Pro +################# +# Analytics # +################# +analytics.title=Do you want make Stirling PDF better? +analytics.paragraph1=Stirling PDF has opt in analytics to help us improve the product. We do not track any personal information or file contents. +analytics.paragraph2=Please consider enabling analytics to help Stirling-PDF grow and to allow us to understand our users better. +analytics.enable=Enable analytics +analytics.disable=Disable analytics +analytics.settings=You can change the settings for analytics in the config/settings.yml file ############# # NAVBAR # @@ -128,6 +145,7 @@ navbar.sections.convertFrom=從 PDF 轉換 navbar.sections.security=簽章與安全性 navbar.sections.advance=進階 navbar.sections.edit=檢視與編輯 +navbar.sections.popular=Popular ############# # SETTINGS # @@ -225,6 +243,8 @@ database.fileNotFound=檔案未找到 database.fileNullOrEmpty=檔案不能為空或空白 database.failedImportFile=匯入檔案失敗 +session.expired=Your session has expired. Please refresh the page and try again. + ############# # HOME-PAGE # ############# @@ -482,6 +502,11 @@ home.removeImagePdf.title=Remove image home.removeImagePdf.desc=Remove image from PDF to reduce file size removeImagePdf.tags=Remove Image,Page operations,Back end,server side + +home.splitPdfByChapters.title=Split PDF by Chapters +home.splitPdfByChapters.desc=Split a PDF into multiple files based on its chapter structure. +splitPdfByChapters.tags=split,chapters,bookmarks,organize + #replace-invert-color replace-color.title=Replace-Invert-Color replace-color.header=Replace-Invert Color PDF @@ -526,7 +551,10 @@ login.oauth2AccessDenied=存取被拒 login.oauth2InvalidTokenResponse=無效的 Token 回應 login.oauth2InvalidIdToken=無效的 Tokne login.userIsDisabled=User is deactivated, login is currently blocked with this username. Please contact the administrator. - +login.alreadyLoggedIn=You are already logged in to +login.alreadyLoggedIn2=devices. Please log out of the devices and try again. +login.toManySessions=You have too many active sessions +login.toManySessions2=Please log out of the devices and try again. Alternatively, you can upgrade to Stirling PDF Pro. #auto-redact autoRedact.title=自動塗黑 @@ -1154,6 +1182,8 @@ licenses.license=許可證 survey.nav=問卷調查 survey.title=Stirling-PDF 問卷調查 survey.description=Stirling-PDF 沒有追蹤功能,所以我們希望聽取用戶的意見來改進 Stirling-PDF! +survey.changes=Stirling-PDF has changed since the last survey! To find out more please check our blog post here: +survey.changes2=With these changes we are getting paid business support and funding survey.please=請考慮參加我們的問卷調查! survey.disabled=(問卷調查彈出窗口將在後續更新中停用,但仍可在頁腳處使用) survey.button=參加問卷調查 @@ -1179,3 +1209,17 @@ removeImage.title=Remove image removeImage.header=Remove image removeImage.removeImage=Remove image removeImage.submit=Remove image + + +splitByChapters.title=Split PDF by Chapters +splitByChapters.header=Split PDF by Chapters +splitByChapters.bookmarkLevel=Bookmark Level +splitByChapters.includeMetadata=Include Metadata +splitByChapters.allowDuplicates=Allow Duplicates +splitByChapters.desc.1=This tool splits a PDF file into multiple PDFs based on its chapter structure. +splitByChapters.desc.2=Bookmark Level: Choose the level of bookmarks to use for splitting (0 for top-level, 1 for second-level, etc.). +splitByChapters.desc.3=Include Metadata: If checked, the original PDF's metadata will be included in each split PDF. +splitByChapters.desc.4=Allow Duplicates: If checked, allows multiple bookmarks on the same page to create separate PDFs. +splitByChapters.submit=Split PDF + + diff --git a/src/main/resources/settings.yml.template b/src/main/resources/settings.yml.template index 2a5400b6..cd248112 100644 --- a/src/main/resources/settings.yml.template +++ b/src/main/resources/settings.yml.template @@ -49,7 +49,8 @@ security: provider: google # Set this to your OAuth provider's name, e.g., 'google' or 'keycloak' # Enterprise edition settings unused for now please ignore! -EnterpriseEdition: +enterpriseEdition: + enabled: false # set to 'true' to enable enterprise edition key: 00000000-0000-0000-0000-000000000000 CustomMetadata: autoUpdateMetadata: true # set to 'true' to automatically update metadata with below values @@ -72,6 +73,7 @@ system: showUpdateOnlyAdmin: false # Only admins can see when a new update is available, depending on showUpdate it must be set to 'true' customHTMLFiles: false # enable to have files placed in /customFiles/templates override the existing template html files tessdataDir: /usr/share/tessdata # Path to the directory containing the Tessdata files. This setting is relevant for Windows systems. For Windows users, this path should be adjusted to point to the appropriate directory where the Tessdata files are stored. + enableAnalytics: undefined # Set to 'true' to enable analytics, set to 'false' to disable analytics, for enterprise users this is set to true ui: appName: '' # Application's visible name @@ -88,3 +90,4 @@ metrics: # Automatically Generated Settings (Do Not Edit Directly) AutomaticallyGenerated: key: example + UUID: example diff --git a/src/main/resources/static/css/bootstrap.min.css b/src/main/resources/static/css/bootstrap.min.css index 92e022d3..5c4d3c11 100644 --- a/src/main/resources/static/css/bootstrap.min.css +++ b/src/main/resources/static/css/bootstrap.min.css @@ -3,5 +3,5 @@ * Copyright 2011-2021 The Bootstrap Authors * Copyright 2011-2021 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) - */:root{--bs-blue:#0d6efd;--bs-indigo:#6610f2;--bs-purple:#6f42c1;--bs-pink:#d63384;--bs-red:#dc3545;--bs-orange:#fd7e14;--bs-yellow:#ffc107;--bs-green:#198754;--bs-teal:#20c997;--bs-cyan:#0dcaf0;--bs-white:#fff;--bs-gray:#6c757d;--bs-gray-dark:#343a40;--bs-primary:#0d6efd;--bs-secondary:#6c757d;--bs-success:#198754;--bs-info:#0dcaf0;--bs-warning:#ffc107;--bs-danger:#dc3545;--bs-light:#f8f9fa;--bs-dark:#212529;--bs-font-sans-serif:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","Liberation Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--bs-font-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--bs-gradient:linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0))}*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:var(--bs-font-sans-serif);font-size:1rem;font-weight:400;line-height:1.5;color:#212529;background-color:#fff;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;background-color:currentColor;border:0;opacity:.25}hr:not([size]){height:1px}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2}.h1,h1{font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){.h1,h1{font-size:2.5rem}}.h2,h2{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){.h2,h2{font-size:2rem}}.h3,h3{font-size:calc(1.3rem + .6vw)}@media (min-width:1200px){.h3,h3{font-size:1.75rem}}.h4,h4{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){.h4,h4{font-size:1.5rem}}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[data-bs-original-title],abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}.small,small{font-size:.875em}.mark,mark{padding:.2em;background-color:#fcf8e3}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#0d6efd;text-decoration:underline}a:hover{color:#0a58ca}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:var(--bs-font-monospace);font-size:1em;direction:ltr;unicode-bidi:bidi-override}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:#d63384;word-wrap:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:.875em;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:1em;font-weight:700}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:#6c757d;text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]::-webkit-calendar-picker-indicator{display:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + .3vw);line-height:inherit}@media (min-width:1200px){legend{font-size:1.5rem}}legend+*{clear:left}::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-text,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:textfield}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::file-selector-button{font:inherit}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none!important}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:calc(1.625rem + 4.5vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-1{font-size:5rem}}.display-2{font-size:calc(1.575rem + 3.9vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-2{font-size:4.5rem}}.display-3{font-size:calc(1.525rem + 3.3vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-3{font-size:4rem}}.display-4{font-size:calc(1.475rem + 2.7vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-4{font-size:3.5rem}}.display-5{font-size:calc(1.425rem + 2.1vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-5{font-size:3rem}}.display-6{font-size:calc(1.375rem + 1.5vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-6{font-size:2.5rem}}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:.875em;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote>:last-child{margin-bottom:0}.blockquote-footer{margin-top:-1rem;margin-bottom:1rem;font-size:.875em;color:#6c757d}.blockquote-footer::before{content:"— "}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:#fff;border:1px solid #dee2e6;border-radius:.25rem;max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:.875em;color:#6c757d}.container,.container-fluid,.container-lg,.container-md,.container-sm,.container-xl,.container-xxl{width:100%;padding-right:var(--bs-gutter-x,.75rem);padding-left:var(--bs-gutter-x,.75rem);margin-right:auto;margin-left:auto}@media (min-width:576px){.container,.container-sm{max-width:540px}}@media (min-width:768px){.container,.container-md,.container-sm{max-width:720px}}@media (min-width:992px){.container,.container-lg,.container-md,.container-sm{max-width:960px}}@media (min-width:1200px){.container,.container-lg,.container-md,.container-sm,.container-xl{max-width:1140px}}@media (min-width:1400px){.container,.container-lg,.container-md,.container-sm,.container-xl,.container-xxl{max-width:1320px}}.row{--bs-gutter-x:1.5rem;--bs-gutter-y:0;display:flex;flex-wrap:wrap;margin-top:calc(var(--bs-gutter-y) * -1);margin-right:calc(var(--bs-gutter-x) * -.5);margin-left:calc(var(--bs-gutter-x) * -.5)}.row>*{flex-shrink:0;width:100%;max-width:100%;padding-right:calc(var(--bs-gutter-x) * .5);padding-left:calc(var(--bs-gutter-x) * .5);margin-top:var(--bs-gutter-y)}.col{flex:1 0 0%}.row-cols-auto>*{flex:0 0 auto;width:auto}.row-cols-1>*{flex:0 0 auto;width:100%}.row-cols-2>*{flex:0 0 auto;width:50%}.row-cols-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-4>*{flex:0 0 auto;width:25%}.row-cols-5>*{flex:0 0 auto;width:20%}.row-cols-6>*{flex:0 0 auto;width:16.6666666667%}@media (min-width:576px){.col-sm{flex:1 0 0%}.row-cols-sm-auto>*{flex:0 0 auto;width:auto}.row-cols-sm-1>*{flex:0 0 auto;width:100%}.row-cols-sm-2>*{flex:0 0 auto;width:50%}.row-cols-sm-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-sm-4>*{flex:0 0 auto;width:25%}.row-cols-sm-5>*{flex:0 0 auto;width:20%}.row-cols-sm-6>*{flex:0 0 auto;width:16.6666666667%}}@media (min-width:768px){.col-md{flex:1 0 0%}.row-cols-md-auto>*{flex:0 0 auto;width:auto}.row-cols-md-1>*{flex:0 0 auto;width:100%}.row-cols-md-2>*{flex:0 0 auto;width:50%}.row-cols-md-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-md-4>*{flex:0 0 auto;width:25%}.row-cols-md-5>*{flex:0 0 auto;width:20%}.row-cols-md-6>*{flex:0 0 auto;width:16.6666666667%}}@media (min-width:992px){.col-lg{flex:1 0 0%}.row-cols-lg-auto>*{flex:0 0 auto;width:auto}.row-cols-lg-1>*{flex:0 0 auto;width:100%}.row-cols-lg-2>*{flex:0 0 auto;width:50%}.row-cols-lg-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-lg-4>*{flex:0 0 auto;width:25%}.row-cols-lg-5>*{flex:0 0 auto;width:20%}.row-cols-lg-6>*{flex:0 0 auto;width:16.6666666667%}}@media (min-width:1200px){.col-xl{flex:1 0 0%}.row-cols-xl-auto>*{flex:0 0 auto;width:auto}.row-cols-xl-1>*{flex:0 0 auto;width:100%}.row-cols-xl-2>*{flex:0 0 auto;width:50%}.row-cols-xl-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-xl-4>*{flex:0 0 auto;width:25%}.row-cols-xl-5>*{flex:0 0 auto;width:20%}.row-cols-xl-6>*{flex:0 0 auto;width:16.6666666667%}}@media (min-width:1400px){.col-xxl{flex:1 0 0%}.row-cols-xxl-auto>*{flex:0 0 auto;width:auto}.row-cols-xxl-1>*{flex:0 0 auto;width:100%}.row-cols-xxl-2>*{flex:0 0 auto;width:50%}.row-cols-xxl-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-xxl-4>*{flex:0 0 auto;width:25%}.row-cols-xxl-5>*{flex:0 0 auto;width:20%}.row-cols-xxl-6>*{flex:0 0 auto;width:16.6666666667%}}.col-auto{flex:0 0 auto;width:auto}.col-1{flex:0 0 auto;width:8.33333333%}.col-2{flex:0 0 auto;width:16.66666667%}.col-3{flex:0 0 auto;width:25%}.col-4{flex:0 0 auto;width:33.33333333%}.col-5{flex:0 0 auto;width:41.66666667%}.col-6{flex:0 0 auto;width:50%}.col-7{flex:0 0 auto;width:58.33333333%}.col-8{flex:0 0 auto;width:66.66666667%}.col-9{flex:0 0 auto;width:75%}.col-10{flex:0 0 auto;width:83.33333333%}.col-11{flex:0 0 auto;width:91.66666667%}.col-12{flex:0 0 auto;width:100%}.offset-1{margin-left:8.33333333%}.offset-2{margin-left:16.66666667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.33333333%}.offset-5{margin-left:41.66666667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.33333333%}.offset-8{margin-left:66.66666667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.33333333%}.offset-11{margin-left:91.66666667%}.g-0,.gx-0{--bs-gutter-x:0}.g-0,.gy-0{--bs-gutter-y:0}.g-1,.gx-1{--bs-gutter-x:0.25rem}.g-1,.gy-1{--bs-gutter-y:0.25rem}.g-2,.gx-2{--bs-gutter-x:0.5rem}.g-2,.gy-2{--bs-gutter-y:0.5rem}.g-3,.gx-3{--bs-gutter-x:1rem}.g-3,.gy-3{--bs-gutter-y:1rem}.g-4,.gx-4{--bs-gutter-x:1.5rem}.g-4,.gy-4{--bs-gutter-y:1.5rem}.g-5,.gx-5{--bs-gutter-x:3rem}.g-5,.gy-5{--bs-gutter-y:3rem}@media (min-width:576px){.col-sm-auto{flex:0 0 auto;width:auto}.col-sm-1{flex:0 0 auto;width:8.33333333%}.col-sm-2{flex:0 0 auto;width:16.66666667%}.col-sm-3{flex:0 0 auto;width:25%}.col-sm-4{flex:0 0 auto;width:33.33333333%}.col-sm-5{flex:0 0 auto;width:41.66666667%}.col-sm-6{flex:0 0 auto;width:50%}.col-sm-7{flex:0 0 auto;width:58.33333333%}.col-sm-8{flex:0 0 auto;width:66.66666667%}.col-sm-9{flex:0 0 auto;width:75%}.col-sm-10{flex:0 0 auto;width:83.33333333%}.col-sm-11{flex:0 0 auto;width:91.66666667%}.col-sm-12{flex:0 0 auto;width:100%}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.33333333%}.offset-sm-2{margin-left:16.66666667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.33333333%}.offset-sm-5{margin-left:41.66666667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.33333333%}.offset-sm-8{margin-left:66.66666667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.33333333%}.offset-sm-11{margin-left:91.66666667%}.g-sm-0,.gx-sm-0{--bs-gutter-x:0}.g-sm-0,.gy-sm-0{--bs-gutter-y:0}.g-sm-1,.gx-sm-1{--bs-gutter-x:0.25rem}.g-sm-1,.gy-sm-1{--bs-gutter-y:0.25rem}.g-sm-2,.gx-sm-2{--bs-gutter-x:0.5rem}.g-sm-2,.gy-sm-2{--bs-gutter-y:0.5rem}.g-sm-3,.gx-sm-3{--bs-gutter-x:1rem}.g-sm-3,.gy-sm-3{--bs-gutter-y:1rem}.g-sm-4,.gx-sm-4{--bs-gutter-x:1.5rem}.g-sm-4,.gy-sm-4{--bs-gutter-y:1.5rem}.g-sm-5,.gx-sm-5{--bs-gutter-x:3rem}.g-sm-5,.gy-sm-5{--bs-gutter-y:3rem}}@media (min-width:768px){.col-md-auto{flex:0 0 auto;width:auto}.col-md-1{flex:0 0 auto;width:8.33333333%}.col-md-2{flex:0 0 auto;width:16.66666667%}.col-md-3{flex:0 0 auto;width:25%}.col-md-4{flex:0 0 auto;width:33.33333333%}.col-md-5{flex:0 0 auto;width:41.66666667%}.col-md-6{flex:0 0 auto;width:50%}.col-md-7{flex:0 0 auto;width:58.33333333%}.col-md-8{flex:0 0 auto;width:66.66666667%}.col-md-9{flex:0 0 auto;width:75%}.col-md-10{flex:0 0 auto;width:83.33333333%}.col-md-11{flex:0 0 auto;width:91.66666667%}.col-md-12{flex:0 0 auto;width:100%}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.33333333%}.offset-md-2{margin-left:16.66666667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.33333333%}.offset-md-5{margin-left:41.66666667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.33333333%}.offset-md-8{margin-left:66.66666667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.33333333%}.offset-md-11{margin-left:91.66666667%}.g-md-0,.gx-md-0{--bs-gutter-x:0}.g-md-0,.gy-md-0{--bs-gutter-y:0}.g-md-1,.gx-md-1{--bs-gutter-x:0.25rem}.g-md-1,.gy-md-1{--bs-gutter-y:0.25rem}.g-md-2,.gx-md-2{--bs-gutter-x:0.5rem}.g-md-2,.gy-md-2{--bs-gutter-y:0.5rem}.g-md-3,.gx-md-3{--bs-gutter-x:1rem}.g-md-3,.gy-md-3{--bs-gutter-y:1rem}.g-md-4,.gx-md-4{--bs-gutter-x:1.5rem}.g-md-4,.gy-md-4{--bs-gutter-y:1.5rem}.g-md-5,.gx-md-5{--bs-gutter-x:3rem}.g-md-5,.gy-md-5{--bs-gutter-y:3rem}}@media (min-width:992px){.col-lg-auto{flex:0 0 auto;width:auto}.col-lg-1{flex:0 0 auto;width:8.33333333%}.col-lg-2{flex:0 0 auto;width:16.66666667%}.col-lg-3{flex:0 0 auto;width:25%}.col-lg-4{flex:0 0 auto;width:33.33333333%}.col-lg-5{flex:0 0 auto;width:41.66666667%}.col-lg-6{flex:0 0 auto;width:50%}.col-lg-7{flex:0 0 auto;width:58.33333333%}.col-lg-8{flex:0 0 auto;width:66.66666667%}.col-lg-9{flex:0 0 auto;width:75%}.col-lg-10{flex:0 0 auto;width:83.33333333%}.col-lg-11{flex:0 0 auto;width:91.66666667%}.col-lg-12{flex:0 0 auto;width:100%}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.33333333%}.offset-lg-2{margin-left:16.66666667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.33333333%}.offset-lg-5{margin-left:41.66666667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.33333333%}.offset-lg-8{margin-left:66.66666667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.33333333%}.offset-lg-11{margin-left:91.66666667%}.g-lg-0,.gx-lg-0{--bs-gutter-x:0}.g-lg-0,.gy-lg-0{--bs-gutter-y:0}.g-lg-1,.gx-lg-1{--bs-gutter-x:0.25rem}.g-lg-1,.gy-lg-1{--bs-gutter-y:0.25rem}.g-lg-2,.gx-lg-2{--bs-gutter-x:0.5rem}.g-lg-2,.gy-lg-2{--bs-gutter-y:0.5rem}.g-lg-3,.gx-lg-3{--bs-gutter-x:1rem}.g-lg-3,.gy-lg-3{--bs-gutter-y:1rem}.g-lg-4,.gx-lg-4{--bs-gutter-x:1.5rem}.g-lg-4,.gy-lg-4{--bs-gutter-y:1.5rem}.g-lg-5,.gx-lg-5{--bs-gutter-x:3rem}.g-lg-5,.gy-lg-5{--bs-gutter-y:3rem}}@media (min-width:1200px){.col-xl-auto{flex:0 0 auto;width:auto}.col-xl-1{flex:0 0 auto;width:8.33333333%}.col-xl-2{flex:0 0 auto;width:16.66666667%}.col-xl-3{flex:0 0 auto;width:25%}.col-xl-4{flex:0 0 auto;width:33.33333333%}.col-xl-5{flex:0 0 auto;width:41.66666667%}.col-xl-6{flex:0 0 auto;width:50%}.col-xl-7{flex:0 0 auto;width:58.33333333%}.col-xl-8{flex:0 0 auto;width:66.66666667%}.col-xl-9{flex:0 0 auto;width:75%}.col-xl-10{flex:0 0 auto;width:83.33333333%}.col-xl-11{flex:0 0 auto;width:91.66666667%}.col-xl-12{flex:0 0 auto;width:100%}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.33333333%}.offset-xl-2{margin-left:16.66666667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.33333333%}.offset-xl-5{margin-left:41.66666667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.33333333%}.offset-xl-8{margin-left:66.66666667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.33333333%}.offset-xl-11{margin-left:91.66666667%}.g-xl-0,.gx-xl-0{--bs-gutter-x:0}.g-xl-0,.gy-xl-0{--bs-gutter-y:0}.g-xl-1,.gx-xl-1{--bs-gutter-x:0.25rem}.g-xl-1,.gy-xl-1{--bs-gutter-y:0.25rem}.g-xl-2,.gx-xl-2{--bs-gutter-x:0.5rem}.g-xl-2,.gy-xl-2{--bs-gutter-y:0.5rem}.g-xl-3,.gx-xl-3{--bs-gutter-x:1rem}.g-xl-3,.gy-xl-3{--bs-gutter-y:1rem}.g-xl-4,.gx-xl-4{--bs-gutter-x:1.5rem}.g-xl-4,.gy-xl-4{--bs-gutter-y:1.5rem}.g-xl-5,.gx-xl-5{--bs-gutter-x:3rem}.g-xl-5,.gy-xl-5{--bs-gutter-y:3rem}}@media (min-width:1400px){.col-xxl-auto{flex:0 0 auto;width:auto}.col-xxl-1{flex:0 0 auto;width:8.33333333%}.col-xxl-2{flex:0 0 auto;width:16.66666667%}.col-xxl-3{flex:0 0 auto;width:25%}.col-xxl-4{flex:0 0 auto;width:33.33333333%}.col-xxl-5{flex:0 0 auto;width:41.66666667%}.col-xxl-6{flex:0 0 auto;width:50%}.col-xxl-7{flex:0 0 auto;width:58.33333333%}.col-xxl-8{flex:0 0 auto;width:66.66666667%}.col-xxl-9{flex:0 0 auto;width:75%}.col-xxl-10{flex:0 0 auto;width:83.33333333%}.col-xxl-11{flex:0 0 auto;width:91.66666667%}.col-xxl-12{flex:0 0 auto;width:100%}.offset-xxl-0{margin-left:0}.offset-xxl-1{margin-left:8.33333333%}.offset-xxl-2{margin-left:16.66666667%}.offset-xxl-3{margin-left:25%}.offset-xxl-4{margin-left:33.33333333%}.offset-xxl-5{margin-left:41.66666667%}.offset-xxl-6{margin-left:50%}.offset-xxl-7{margin-left:58.33333333%}.offset-xxl-8{margin-left:66.66666667%}.offset-xxl-9{margin-left:75%}.offset-xxl-10{margin-left:83.33333333%}.offset-xxl-11{margin-left:91.66666667%}.g-xxl-0,.gx-xxl-0{--bs-gutter-x:0}.g-xxl-0,.gy-xxl-0{--bs-gutter-y:0}.g-xxl-1,.gx-xxl-1{--bs-gutter-x:0.25rem}.g-xxl-1,.gy-xxl-1{--bs-gutter-y:0.25rem}.g-xxl-2,.gx-xxl-2{--bs-gutter-x:0.5rem}.g-xxl-2,.gy-xxl-2{--bs-gutter-y:0.5rem}.g-xxl-3,.gx-xxl-3{--bs-gutter-x:1rem}.g-xxl-3,.gy-xxl-3{--bs-gutter-y:1rem}.g-xxl-4,.gx-xxl-4{--bs-gutter-x:1.5rem}.g-xxl-4,.gy-xxl-4{--bs-gutter-y:1.5rem}.g-xxl-5,.gx-xxl-5{--bs-gutter-x:3rem}.g-xxl-5,.gy-xxl-5{--bs-gutter-y:3rem}}.table{--bs-table-bg:transparent;--bs-table-accent-bg:transparent;--bs-table-striped-color:#212529;--bs-table-striped-bg:rgba(0, 0, 0, 0.05);--bs-table-active-color:#212529;--bs-table-active-bg:rgba(0, 0, 0, 0.1);--bs-table-hover-color:#212529;--bs-table-hover-bg:rgba(0, 0, 0, 0.075);width:100%;margin-bottom:1rem;color:#212529;vertical-align:top;border-color:#dee2e6}.table>:not(caption)>*>*{padding:.5rem .5rem;background-color:var(--bs-table-bg);border-bottom-width:1px;box-shadow:inset 0 0 0 9999px var(--bs-table-accent-bg)}.table>tbody{vertical-align:inherit}.table>thead{vertical-align:bottom}.table>:not(:last-child)>:last-child>*{border-bottom-color:currentColor}.caption-top{caption-side:top}.table-sm>:not(caption)>*>*{padding:.25rem .25rem}.table-bordered>:not(caption)>*{border-width:1px 0}.table-bordered>:not(caption)>*>*{border-width:0 1px}.table-borderless>:not(caption)>*>*{border-bottom-width:0}.table-striped>tbody>tr:nth-of-type(odd){--bs-table-accent-bg:var(--bs-table-striped-bg);color:var(--bs-table-striped-color)}.table-active{--bs-table-accent-bg:var(--bs-table-active-bg);color:var(--bs-table-active-color)}.table-hover>tbody>tr:hover{--bs-table-accent-bg:var(--bs-table-hover-bg);color:var(--bs-table-hover-color)}.table-primary{--bs-table-bg:#cfe2ff;--bs-table-striped-bg:#c5d7f2;--bs-table-striped-color:#000;--bs-table-active-bg:#bacbe6;--bs-table-active-color:#000;--bs-table-hover-bg:#bfd1ec;--bs-table-hover-color:#000;color:#000;border-color:#bacbe6}.table-secondary{--bs-table-bg:#e2e3e5;--bs-table-striped-bg:#d7d8da;--bs-table-striped-color:#000;--bs-table-active-bg:#cbccce;--bs-table-active-color:#000;--bs-table-hover-bg:#d1d2d4;--bs-table-hover-color:#000;color:#000;border-color:#cbccce}.table-success{--bs-table-bg:#d1e7dd;--bs-table-striped-bg:#c7dbd2;--bs-table-striped-color:#000;--bs-table-active-bg:#bcd0c7;--bs-table-active-color:#000;--bs-table-hover-bg:#c1d6cc;--bs-table-hover-color:#000;color:#000;border-color:#bcd0c7}.table-info{--bs-table-bg:#cff4fc;--bs-table-striped-bg:#c5e8ef;--bs-table-striped-color:#000;--bs-table-active-bg:#badce3;--bs-table-active-color:#000;--bs-table-hover-bg:#bfe2e9;--bs-table-hover-color:#000;color:#000;border-color:#badce3}.table-warning{--bs-table-bg:#fff3cd;--bs-table-striped-bg:#f2e7c3;--bs-table-striped-color:#000;--bs-table-active-bg:#e6dbb9;--bs-table-active-color:#000;--bs-table-hover-bg:#ece1be;--bs-table-hover-color:#000;color:#000;border-color:#e6dbb9}.table-danger{--bs-table-bg:#f8d7da;--bs-table-striped-bg:#eccccf;--bs-table-striped-color:#000;--bs-table-active-bg:#dfc2c4;--bs-table-active-color:#000;--bs-table-hover-bg:#e5c7ca;--bs-table-hover-color:#000;color:#000;border-color:#dfc2c4}.table-light{--bs-table-bg:#f8f9fa;--bs-table-striped-bg:#ecedee;--bs-table-striped-color:#000;--bs-table-active-bg:#dfe0e1;--bs-table-active-color:#000;--bs-table-hover-bg:#e5e6e7;--bs-table-hover-color:#000;color:#000;border-color:#dfe0e1}.table-dark{--bs-table-bg:#212529;--bs-table-striped-bg:#2c3034;--bs-table-striped-color:#fff;--bs-table-active-bg:#373b3e;--bs-table-active-color:#fff;--bs-table-hover-bg:#323539;--bs-table-hover-color:#fff;color:#fff;border-color:#373b3e}.table-responsive{overflow-x:auto;-webkit-overflow-scrolling:touch}@media (max-width:575.98px){.table-responsive-sm{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:767.98px){.table-responsive-md{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:991.98px){.table-responsive-lg{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:1199.98px){.table-responsive-xl{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:1399.98px){.table-responsive-xxl{overflow-x:auto;-webkit-overflow-scrolling:touch}}.form-label{margin-bottom:.5rem}.col-form-label{padding-top:calc(.375rem + 1px);padding-bottom:calc(.375rem + 1px);margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(.5rem + 1px);padding-bottom:calc(.5rem + 1px);font-size:1.25rem}.col-form-label-sm{padding-top:calc(.25rem + 1px);padding-bottom:calc(.25rem + 1px);font-size:.875rem}.form-text{margin-top:.25rem;font-size:.875em;color:#6c757d}.form-control{display:block;width:100%;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#212529;background-color:#fff;background-clip:padding-box;border:1px solid #ced4da;-webkit-appearance:none;-moz-appearance:none;appearance:none;border-radius:.25rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control{transition:none}}.form-control[type=file]{overflow:hidden}.form-control[type=file]:not(:disabled):not([readonly]){cursor:pointer}.form-control:focus{color:#212529;background-color:#fff;border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-control::-webkit-date-and-time-value{height:1.5em}.form-control::-moz-placeholder{color:#6c757d;opacity:1}.form-control::placeholder{color:#6c757d;opacity:1}.form-control:disabled,.form-control[readonly]{background-color:#e9ecef;opacity:1}.form-control::file-selector-button{padding:.375rem .75rem;margin:-.375rem -.75rem;-webkit-margin-end:.75rem;margin-inline-end:.75rem;color:#212529;background-color:#e9ecef;pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:1px;border-radius:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control::file-selector-button{transition:none}}.form-control:hover:not(:disabled):not([readonly])::file-selector-button{background-color:#dde0e3}.form-control::-webkit-file-upload-button{padding:.375rem .75rem;margin:-.375rem -.75rem;-webkit-margin-end:.75rem;margin-inline-end:.75rem;color:#212529;background-color:#e9ecef;pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:1px;border-radius:0;-webkit-transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control::-webkit-file-upload-button{-webkit-transition:none;transition:none}}.form-control:hover:not(:disabled):not([readonly])::-webkit-file-upload-button{background-color:#dde0e3}.form-control-plaintext{display:block;width:100%;padding:.375rem 0;margin-bottom:0;line-height:1.5;color:#212529;background-color:transparent;border:solid transparent;border-width:1px 0}.form-control-plaintext.form-control-lg,.form-control-plaintext.form-control-sm{padding-right:0;padding-left:0}.form-control-sm{min-height:calc(1.5em + (.5rem + 2px));padding:.25rem .5rem;font-size:.875rem;border-radius:.2rem}.form-control-sm::file-selector-button{padding:.25rem .5rem;margin:-.25rem -.5rem;-webkit-margin-end:.5rem;margin-inline-end:.5rem}.form-control-sm::-webkit-file-upload-button{padding:.25rem .5rem;margin:-.25rem -.5rem;-webkit-margin-end:.5rem;margin-inline-end:.5rem}.form-control-lg{min-height:calc(1.5em + (1rem + 2px));padding:.5rem 1rem;font-size:1.25rem;border-radius:.3rem}.form-control-lg::file-selector-button{padding:.5rem 1rem;margin:-.5rem -1rem;-webkit-margin-end:1rem;margin-inline-end:1rem}.form-control-lg::-webkit-file-upload-button{padding:.5rem 1rem;margin:-.5rem -1rem;-webkit-margin-end:1rem;margin-inline-end:1rem}textarea.form-control{min-height:calc(1.5em + (.75rem + 2px))}textarea.form-control-sm{min-height:calc(1.5em + (.5rem + 2px))}textarea.form-control-lg{min-height:calc(1.5em + (1rem + 2px))}.form-control-color{max-width:3rem;height:auto;padding:.375rem}.form-control-color:not(:disabled):not([readonly]){cursor:pointer}.form-control-color::-moz-color-swatch{height:1.5em;border-radius:.25rem}.form-control-color::-webkit-color-swatch{height:1.5em;border-radius:.25rem}.form-select{display:block;width:100%;padding:.375rem 2.25rem .375rem .75rem;-moz-padding-start:calc(0.75rem - 3px);font-size:1rem;font-weight:400;line-height:1.5;color:#212529;background-color:#fff;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right .75rem center;background-size:16px 12px;border:1px solid #ced4da;border-radius:.25rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out;-webkit-appearance:none;-moz-appearance:none;appearance:none}@media (prefers-reduced-motion:reduce){.form-select{transition:none}}.form-select:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-select[multiple],.form-select[size]:not([size="1"]){padding-right:.75rem;background-image:none}.form-select:disabled{background-color:#e9ecef}.form-select:-moz-focusring{color:transparent;text-shadow:0 0 0 #212529}.form-select-sm{padding-top:.25rem;padding-bottom:.25rem;padding-left:.5rem;font-size:.875rem}.form-select-lg{padding-top:.5rem;padding-bottom:.5rem;padding-left:1rem;font-size:1.25rem}.form-check{display:block;min-height:1.5rem;padding-left:1.5em;margin-bottom:.125rem}.form-check .form-check-input{float:left;margin-left:-1.5em}.form-check-input{width:1em;height:1em;margin-top:.25em;vertical-align:top;background-color:#fff;background-repeat:no-repeat;background-position:center;background-size:contain;border:1px solid rgba(0,0,0,.25);-webkit-appearance:none;-moz-appearance:none;appearance:none;-webkit-print-color-adjust:exact;color-adjust:exact}.form-check-input[type=checkbox]{border-radius:.25em}.form-check-input[type=radio]{border-radius:50%}.form-check-input:active{filter:brightness(90%)}.form-check-input:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-check-input:checked{background-color:#0d6efd;border-color:#0d6efd}.form-check-input:checked[type=checkbox]{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10l3 3l6-6'/%3e%3c/svg%3e")}.form-check-input:checked[type=radio]{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%23fff'/%3e%3c/svg%3e")}.form-check-input[type=checkbox]:indeterminate{background-color:#0d6efd;border-color:#0d6efd;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/%3e%3c/svg%3e")}.form-check-input:disabled{pointer-events:none;filter:none;opacity:.5}.form-check-input:disabled~.form-check-label,.form-check-input[disabled]~.form-check-label{opacity:.5}.form-switch{padding-left:2.5em}.form-switch .form-check-input{width:2em;margin-left:-2.5em;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%280, 0, 0, 0.25%29'/%3e%3c/svg%3e");background-position:left center;border-radius:2em;transition:background-position .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-switch .form-check-input{transition:none}}.form-switch .form-check-input:focus{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%2386b7fe'/%3e%3c/svg%3e")}.form-switch .form-check-input:checked{background-position:right center;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e")}.form-check-inline{display:inline-block;margin-right:1rem}.btn-check{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.btn-check:disabled+.btn,.btn-check[disabled]+.btn{pointer-events:none;filter:none;opacity:.65}.form-range{width:100%;height:1.5rem;padding:0;background-color:transparent;-webkit-appearance:none;-moz-appearance:none;appearance:none}.form-range:focus{outline:0}.form-range:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(13,110,253,.25)}.form-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(13,110,253,.25)}.form-range::-moz-focus-outer{border:0}.form-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-.25rem;background-color:#0d6efd;border:0;border-radius:1rem;-webkit-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;-webkit-appearance:none;appearance:none}@media (prefers-reduced-motion:reduce){.form-range::-webkit-slider-thumb{-webkit-transition:none;transition:none}}.form-range::-webkit-slider-thumb:active{background-color:#b6d4fe}.form-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem}.form-range::-moz-range-thumb{width:1rem;height:1rem;background-color:#0d6efd;border:0;border-radius:1rem;-moz-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;-moz-appearance:none;appearance:none}@media (prefers-reduced-motion:reduce){.form-range::-moz-range-thumb{-moz-transition:none;transition:none}}.form-range::-moz-range-thumb:active{background-color:#b6d4fe}.form-range::-moz-range-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem}.form-range:disabled{pointer-events:none}.form-range:disabled::-webkit-slider-thumb{background-color:#adb5bd}.form-range:disabled::-moz-range-thumb{background-color:#adb5bd}.form-floating{position:relative}.form-floating>.form-control,.form-floating>.form-select{height:calc(3.5rem + 2px);line-height:1.25}.form-floating>label{position:absolute;top:0;left:0;height:100%;padding:1rem .75rem;pointer-events:none;border:1px solid transparent;transform-origin:0 0;transition:opacity .1s ease-in-out,transform .1s ease-in-out}@media (prefers-reduced-motion:reduce){.form-floating>label{transition:none}}.form-floating>.form-control{padding:1rem .75rem}.form-floating>.form-control::-moz-placeholder{color:transparent}.form-floating>.form-control::placeholder{color:transparent}.form-floating>.form-control:not(:-moz-placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:focus,.form-floating>.form-control:not(:placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:-webkit-autofill{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-select{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:not(:-moz-placeholder-shown)~label{opacity:.65;transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.form-floating>.form-control:focus~label,.form-floating>.form-control:not(:placeholder-shown)~label,.form-floating>.form-select~label{opacity:.65;transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.form-floating>.form-control:-webkit-autofill~label{opacity:.65;transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.input-group{position:relative;display:flex;flex-wrap:wrap;align-items:stretch;width:100%}.input-group>.form-control,.input-group>.form-select{position:relative;flex:1 1 auto;width:1%;min-width:0}.input-group>.form-control:focus,.input-group>.form-select:focus{z-index:3}.input-group .btn{position:relative;z-index:2}.input-group .btn:focus{z-index:3}.input-group-text{display:flex;align-items:center;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:center;white-space:nowrap;background-color:#e9ecef;border:1px solid #ced4da;border-radius:.25rem}.input-group-lg>.btn,.input-group-lg>.form-control,.input-group-lg>.form-select,.input-group-lg>.input-group-text{padding:.5rem 1rem;font-size:1.25rem;border-radius:.3rem}.input-group-sm>.btn,.input-group-sm>.form-control,.input-group-sm>.form-select,.input-group-sm>.input-group-text{padding:.25rem .5rem;font-size:.875rem;border-radius:.2rem}.input-group-lg>.form-select,.input-group-sm>.form-select{padding-right:3rem}.input-group:not(.has-validation)>.dropdown-toggle:nth-last-child(n+3),.input-group:not(.has-validation)>:not(:last-child):not(.dropdown-toggle):not(.dropdown-menu){border-top-right-radius:0;border-bottom-right-radius:0}.input-group.has-validation>.dropdown-toggle:nth-last-child(n+4),.input-group.has-validation>:nth-last-child(n+3):not(.dropdown-toggle):not(.dropdown-menu){border-top-right-radius:0;border-bottom-right-radius:0}.input-group>:not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback){margin-left:-1px;border-top-left-radius:0;border-bottom-left-radius:0}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:.875em;color:#198754}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;color:#fff;background-color:rgba(25,135,84,.9);border-radius:.25rem}.is-valid~.valid-feedback,.is-valid~.valid-tooltip,.was-validated :valid~.valid-feedback,.was-validated :valid~.valid-tooltip{display:block}.form-control.is-valid,.was-validated .form-control:valid{border-color:#198754;padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-valid:focus,.was-validated .form-control:valid:focus{border-color:#198754;box-shadow:0 0 0 .25rem rgba(25,135,84,.25)}.was-validated textarea.form-control:valid,textarea.form-control.is-valid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.form-select.is-valid,.was-validated .form-select:valid{border-color:#198754}.form-select.is-valid:not([multiple]):not([size]),.form-select.is-valid:not([multiple])[size="1"],.was-validated .form-select:valid:not([multiple]):not([size]),.was-validated .form-select:valid:not([multiple])[size="1"]{padding-right:4.125rem;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e"),url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(.75em + .375rem) calc(.75em + .375rem)}.form-select.is-valid:focus,.was-validated .form-select:valid:focus{border-color:#198754;box-shadow:0 0 0 .25rem rgba(25,135,84,.25)}.form-check-input.is-valid,.was-validated .form-check-input:valid{border-color:#198754}.form-check-input.is-valid:checked,.was-validated .form-check-input:valid:checked{background-color:#198754}.form-check-input.is-valid:focus,.was-validated .form-check-input:valid:focus{box-shadow:0 0 0 .25rem rgba(25,135,84,.25)}.form-check-input.is-valid~.form-check-label,.was-validated .form-check-input:valid~.form-check-label{color:#198754}.form-check-inline .form-check-input~.valid-feedback{margin-left:.5em}.input-group .form-control.is-valid,.input-group .form-select.is-valid,.was-validated .input-group .form-control:valid,.was-validated .input-group .form-select:valid{z-index:1}.input-group .form-control.is-valid:focus,.input-group .form-select.is-valid:focus,.was-validated .input-group .form-control:valid:focus,.was-validated .input-group .form-select:valid:focus{z-index:3}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:.875em;color:#dc3545}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;color:#fff;background-color:rgba(220,53,69,.9);border-radius:.25rem}.is-invalid~.invalid-feedback,.is-invalid~.invalid-tooltip,.was-validated :invalid~.invalid-feedback,.was-validated :invalid~.invalid-tooltip{display:block}.form-control.is-invalid,.was-validated .form-control:invalid{border-color:#dc3545;padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-invalid:focus,.was-validated .form-control:invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .25rem rgba(220,53,69,.25)}.was-validated textarea.form-control:invalid,textarea.form-control.is-invalid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.form-select.is-invalid,.was-validated .form-select:invalid{border-color:#dc3545}.form-select.is-invalid:not([multiple]):not([size]),.form-select.is-invalid:not([multiple])[size="1"],.was-validated .form-select:invalid:not([multiple]):not([size]),.was-validated .form-select:invalid:not([multiple])[size="1"]{padding-right:4.125rem;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e"),url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(.75em + .375rem) calc(.75em + .375rem)}.form-select.is-invalid:focus,.was-validated .form-select:invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .25rem rgba(220,53,69,.25)}.form-check-input.is-invalid,.was-validated .form-check-input:invalid{border-color:#dc3545}.form-check-input.is-invalid:checked,.was-validated .form-check-input:invalid:checked{background-color:#dc3545}.form-check-input.is-invalid:focus,.was-validated .form-check-input:invalid:focus{box-shadow:0 0 0 .25rem rgba(220,53,69,.25)}.form-check-input.is-invalid~.form-check-label,.was-validated .form-check-input:invalid~.form-check-label{color:#dc3545}.form-check-inline .form-check-input~.invalid-feedback{margin-left:.5em}.input-group .form-control.is-invalid,.input-group .form-select.is-invalid,.was-validated .input-group .form-control:invalid,.was-validated .input-group .form-select:invalid{z-index:2}.input-group .form-control.is-invalid:focus,.input-group .form-select.is-invalid:focus,.was-validated .input-group .form-control:invalid:focus,.was-validated .input-group .form-select:invalid:focus{z-index:3}.btn{display:inline-block;font-weight:400;line-height:1.5;color:#212529;text-align:center;text-decoration:none;vertical-align:middle;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none;background-color:transparent;border:1px solid transparent;padding:.375rem .75rem;font-size:1rem;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.btn{transition:none}}.btn:hover{color:#212529}.btn-check:focus+.btn,.btn:focus{outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.btn.disabled,.btn:disabled,fieldset:disabled .btn{pointer-events:none;opacity:.65}.btn-primary{color:#fff;background-color:#0d6efd;border-color:#0d6efd}.btn-primary:hover{color:#fff;background-color:#0b5ed7;border-color:#0a58ca}.btn-check:focus+.btn-primary,.btn-primary:focus{color:#fff;background-color:#0b5ed7;border-color:#0a58ca;box-shadow:0 0 0 .25rem rgba(49,132,253,.5)}.btn-check:active+.btn-primary,.btn-check:checked+.btn-primary,.btn-primary.active,.btn-primary:active,.show>.btn-primary.dropdown-toggle{color:#fff;background-color:#0a58ca;border-color:#0a53be}.btn-check:active+.btn-primary:focus,.btn-check:checked+.btn-primary:focus,.btn-primary.active:focus,.btn-primary:active:focus,.show>.btn-primary.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(49,132,253,.5)}.btn-primary.disabled,.btn-primary:disabled{color:#fff;background-color:#0d6efd;border-color:#0d6efd}.btn-secondary{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-secondary:hover{color:#fff;background-color:#5c636a;border-color:#565e64}.btn-check:focus+.btn-secondary,.btn-secondary:focus{color:#fff;background-color:#5c636a;border-color:#565e64;box-shadow:0 0 0 .25rem rgba(130,138,145,.5)}.btn-check:active+.btn-secondary,.btn-check:checked+.btn-secondary,.btn-secondary.active,.btn-secondary:active,.show>.btn-secondary.dropdown-toggle{color:#fff;background-color:#565e64;border-color:#51585e}.btn-check:active+.btn-secondary:focus,.btn-check:checked+.btn-secondary:focus,.btn-secondary.active:focus,.btn-secondary:active:focus,.show>.btn-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(130,138,145,.5)}.btn-secondary.disabled,.btn-secondary:disabled{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-success{color:#fff;background-color:#198754;border-color:#198754}.btn-success:hover{color:#fff;background-color:#157347;border-color:#146c43}.btn-check:focus+.btn-success,.btn-success:focus{color:#fff;background-color:#157347;border-color:#146c43;box-shadow:0 0 0 .25rem rgba(60,153,110,.5)}.btn-check:active+.btn-success,.btn-check:checked+.btn-success,.btn-success.active,.btn-success:active,.show>.btn-success.dropdown-toggle{color:#fff;background-color:#146c43;border-color:#13653f}.btn-check:active+.btn-success:focus,.btn-check:checked+.btn-success:focus,.btn-success.active:focus,.btn-success:active:focus,.show>.btn-success.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(60,153,110,.5)}.btn-success.disabled,.btn-success:disabled{color:#fff;background-color:#198754;border-color:#198754}.btn-info{color:#000;background-color:#0dcaf0;border-color:#0dcaf0}.btn-info:hover{color:#000;background-color:#31d2f2;border-color:#25cff2}.btn-check:focus+.btn-info,.btn-info:focus{color:#000;background-color:#31d2f2;border-color:#25cff2;box-shadow:0 0 0 .25rem rgba(11,172,204,.5)}.btn-check:active+.btn-info,.btn-check:checked+.btn-info,.btn-info.active,.btn-info:active,.show>.btn-info.dropdown-toggle{color:#000;background-color:#3dd5f3;border-color:#25cff2}.btn-check:active+.btn-info:focus,.btn-check:checked+.btn-info:focus,.btn-info.active:focus,.btn-info:active:focus,.show>.btn-info.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(11,172,204,.5)}.btn-info.disabled,.btn-info:disabled{color:#000;background-color:#0dcaf0;border-color:#0dcaf0}.btn-warning{color:#000;background-color:#ffc107;border-color:#ffc107}.btn-warning:hover{color:#000;background-color:#ffca2c;border-color:#ffc720}.btn-check:focus+.btn-warning,.btn-warning:focus{color:#000;background-color:#ffca2c;border-color:#ffc720;box-shadow:0 0 0 .25rem rgba(217,164,6,.5)}.btn-check:active+.btn-warning,.btn-check:checked+.btn-warning,.btn-warning.active,.btn-warning:active,.show>.btn-warning.dropdown-toggle{color:#000;background-color:#ffcd39;border-color:#ffc720}.btn-check:active+.btn-warning:focus,.btn-check:checked+.btn-warning:focus,.btn-warning.active:focus,.btn-warning:active:focus,.show>.btn-warning.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(217,164,6,.5)}.btn-warning.disabled,.btn-warning:disabled{color:#000;background-color:#ffc107;border-color:#ffc107}.btn-danger{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-danger:hover{color:#fff;background-color:#bb2d3b;border-color:#b02a37}.btn-check:focus+.btn-danger,.btn-danger:focus{color:#fff;background-color:#bb2d3b;border-color:#b02a37;box-shadow:0 0 0 .25rem rgba(225,83,97,.5)}.btn-check:active+.btn-danger,.btn-check:checked+.btn-danger,.btn-danger.active,.btn-danger:active,.show>.btn-danger.dropdown-toggle{color:#fff;background-color:#b02a37;border-color:#a52834}.btn-check:active+.btn-danger:focus,.btn-check:checked+.btn-danger:focus,.btn-danger.active:focus,.btn-danger:active:focus,.show>.btn-danger.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(225,83,97,.5)}.btn-danger.disabled,.btn-danger:disabled{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-light{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:hover{color:#000;background-color:#f9fafb;border-color:#f9fafb}.btn-check:focus+.btn-light,.btn-light:focus{color:#000;background-color:#f9fafb;border-color:#f9fafb;box-shadow:0 0 0 .25rem rgba(211,212,213,.5)}.btn-check:active+.btn-light,.btn-check:checked+.btn-light,.btn-light.active,.btn-light:active,.show>.btn-light.dropdown-toggle{color:#000;background-color:#f9fafb;border-color:#f9fafb}.btn-check:active+.btn-light:focus,.btn-check:checked+.btn-light:focus,.btn-light.active:focus,.btn-light:active:focus,.show>.btn-light.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(211,212,213,.5)}.btn-light.disabled,.btn-light:disabled{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-dark{color:#fff;background-color:#212529;border-color:#212529}.btn-dark:hover{color:#fff;background-color:#1c1f23;border-color:#1a1e21}.btn-check:focus+.btn-dark,.btn-dark:focus{color:#fff;background-color:#1c1f23;border-color:#1a1e21;box-shadow:0 0 0 .25rem rgba(66,70,73,.5)}.btn-check:active+.btn-dark,.btn-check:checked+.btn-dark,.btn-dark.active,.btn-dark:active,.show>.btn-dark.dropdown-toggle{color:#fff;background-color:#1a1e21;border-color:#191c1f}.btn-check:active+.btn-dark:focus,.btn-check:checked+.btn-dark:focus,.btn-dark.active:focus,.btn-dark:active:focus,.show>.btn-dark.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(66,70,73,.5)}.btn-dark.disabled,.btn-dark:disabled{color:#fff;background-color:#212529;border-color:#212529}.btn-outline-primary{color:#0d6efd;border-color:#0d6efd}.btn-outline-primary:hover{color:#fff;background-color:#0d6efd;border-color:#0d6efd}.btn-check:focus+.btn-outline-primary,.btn-outline-primary:focus{box-shadow:0 0 0 .25rem rgba(13,110,253,.5)}.btn-check:active+.btn-outline-primary,.btn-check:checked+.btn-outline-primary,.btn-outline-primary.active,.btn-outline-primary.dropdown-toggle.show,.btn-outline-primary:active{color:#fff;background-color:#0d6efd;border-color:#0d6efd}.btn-check:active+.btn-outline-primary:focus,.btn-check:checked+.btn-outline-primary:focus,.btn-outline-primary.active:focus,.btn-outline-primary.dropdown-toggle.show:focus,.btn-outline-primary:active:focus{box-shadow:0 0 0 .25rem rgba(13,110,253,.5)}.btn-outline-primary.disabled,.btn-outline-primary:disabled{color:#0d6efd;background-color:transparent}.btn-outline-secondary{color:#6c757d;border-color:#6c757d}.btn-outline-secondary:hover{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-check:focus+.btn-outline-secondary,.btn-outline-secondary:focus{box-shadow:0 0 0 .25rem rgba(108,117,125,.5)}.btn-check:active+.btn-outline-secondary,.btn-check:checked+.btn-outline-secondary,.btn-outline-secondary.active,.btn-outline-secondary.dropdown-toggle.show,.btn-outline-secondary:active{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-check:active+.btn-outline-secondary:focus,.btn-check:checked+.btn-outline-secondary:focus,.btn-outline-secondary.active:focus,.btn-outline-secondary.dropdown-toggle.show:focus,.btn-outline-secondary:active:focus{box-shadow:0 0 0 .25rem rgba(108,117,125,.5)}.btn-outline-secondary.disabled,.btn-outline-secondary:disabled{color:#6c757d;background-color:transparent}.btn-outline-success{color:#198754;border-color:#198754}.btn-outline-success:hover{color:#fff;background-color:#198754;border-color:#198754}.btn-check:focus+.btn-outline-success,.btn-outline-success:focus{box-shadow:0 0 0 .25rem rgba(25,135,84,.5)}.btn-check:active+.btn-outline-success,.btn-check:checked+.btn-outline-success,.btn-outline-success.active,.btn-outline-success.dropdown-toggle.show,.btn-outline-success:active{color:#fff;background-color:#198754;border-color:#198754}.btn-check:active+.btn-outline-success:focus,.btn-check:checked+.btn-outline-success:focus,.btn-outline-success.active:focus,.btn-outline-success.dropdown-toggle.show:focus,.btn-outline-success:active:focus{box-shadow:0 0 0 .25rem rgba(25,135,84,.5)}.btn-outline-success.disabled,.btn-outline-success:disabled{color:#198754;background-color:transparent}.btn-outline-info{color:#0dcaf0;border-color:#0dcaf0}.btn-outline-info:hover{color:#000;background-color:#0dcaf0;border-color:#0dcaf0}.btn-check:focus+.btn-outline-info,.btn-outline-info:focus{box-shadow:0 0 0 .25rem rgba(13,202,240,.5)}.btn-check:active+.btn-outline-info,.btn-check:checked+.btn-outline-info,.btn-outline-info.active,.btn-outline-info.dropdown-toggle.show,.btn-outline-info:active{color:#000;background-color:#0dcaf0;border-color:#0dcaf0}.btn-check:active+.btn-outline-info:focus,.btn-check:checked+.btn-outline-info:focus,.btn-outline-info.active:focus,.btn-outline-info.dropdown-toggle.show:focus,.btn-outline-info:active:focus{box-shadow:0 0 0 .25rem rgba(13,202,240,.5)}.btn-outline-info.disabled,.btn-outline-info:disabled{color:#0dcaf0;background-color:transparent}.btn-outline-warning{color:#ffc107;border-color:#ffc107}.btn-outline-warning:hover{color:#000;background-color:#ffc107;border-color:#ffc107}.btn-check:focus+.btn-outline-warning,.btn-outline-warning:focus{box-shadow:0 0 0 .25rem rgba(255,193,7,.5)}.btn-check:active+.btn-outline-warning,.btn-check:checked+.btn-outline-warning,.btn-outline-warning.active,.btn-outline-warning.dropdown-toggle.show,.btn-outline-warning:active{color:#000;background-color:#ffc107;border-color:#ffc107}.btn-check:active+.btn-outline-warning:focus,.btn-check:checked+.btn-outline-warning:focus,.btn-outline-warning.active:focus,.btn-outline-warning.dropdown-toggle.show:focus,.btn-outline-warning:active:focus{box-shadow:0 0 0 .25rem rgba(255,193,7,.5)}.btn-outline-warning.disabled,.btn-outline-warning:disabled{color:#ffc107;background-color:transparent}.btn-outline-danger{color:#dc3545;border-color:#dc3545}.btn-outline-danger:hover{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-check:focus+.btn-outline-danger,.btn-outline-danger:focus{box-shadow:0 0 0 .25rem rgba(220,53,69,.5)}.btn-check:active+.btn-outline-danger,.btn-check:checked+.btn-outline-danger,.btn-outline-danger.active,.btn-outline-danger.dropdown-toggle.show,.btn-outline-danger:active{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-check:active+.btn-outline-danger:focus,.btn-check:checked+.btn-outline-danger:focus,.btn-outline-danger.active:focus,.btn-outline-danger.dropdown-toggle.show:focus,.btn-outline-danger:active:focus{box-shadow:0 0 0 .25rem rgba(220,53,69,.5)}.btn-outline-danger.disabled,.btn-outline-danger:disabled{color:#dc3545;background-color:transparent}.btn-outline-light{color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light:hover{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-check:focus+.btn-outline-light,.btn-outline-light:focus{box-shadow:0 0 0 .25rem rgba(248,249,250,.5)}.btn-check:active+.btn-outline-light,.btn-check:checked+.btn-outline-light,.btn-outline-light.active,.btn-outline-light.dropdown-toggle.show,.btn-outline-light:active{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-check:active+.btn-outline-light:focus,.btn-check:checked+.btn-outline-light:focus,.btn-outline-light.active:focus,.btn-outline-light.dropdown-toggle.show:focus,.btn-outline-light:active:focus{box-shadow:0 0 0 .25rem rgba(248,249,250,.5)}.btn-outline-light.disabled,.btn-outline-light:disabled{color:#f8f9fa;background-color:transparent}.btn-outline-dark{color:#212529;border-color:#212529}.btn-outline-dark:hover{color:#fff;background-color:#212529;border-color:#212529}.btn-check:focus+.btn-outline-dark,.btn-outline-dark:focus{box-shadow:0 0 0 .25rem rgba(33,37,41,.5)}.btn-check:active+.btn-outline-dark,.btn-check:checked+.btn-outline-dark,.btn-outline-dark.active,.btn-outline-dark.dropdown-toggle.show,.btn-outline-dark:active{color:#fff;background-color:#212529;border-color:#212529}.btn-check:active+.btn-outline-dark:focus,.btn-check:checked+.btn-outline-dark:focus,.btn-outline-dark.active:focus,.btn-outline-dark.dropdown-toggle.show:focus,.btn-outline-dark:active:focus{box-shadow:0 0 0 .25rem rgba(33,37,41,.5)}.btn-outline-dark.disabled,.btn-outline-dark:disabled{color:#212529;background-color:transparent}.btn-link{font-weight:400;color:#0d6efd;text-decoration:underline}.btn-link:hover{color:#0a58ca}.btn-link.disabled,.btn-link:disabled{color:#6c757d}.btn-group-lg>.btn,.btn-lg{padding:.5rem 1rem;font-size:1.25rem;border-radius:.3rem}.btn-group-sm>.btn,.btn-sm{padding:.25rem .5rem;font-size:.875rem;border-radius:.2rem}.fade{transition:opacity .15s linear}@media (prefers-reduced-motion:reduce){.fade{transition:none}}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{height:0;overflow:hidden;transition:height .35s ease}@media (prefers-reduced-motion:reduce){.collapsing{transition:none}}.dropdown,.dropend,.dropstart,.dropup{position:relative}.dropdown-toggle{white-space:nowrap}.dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-bottom:0;border-left:.3em solid transparent}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{position:absolute;z-index:1000;display:none;min-width:10rem;padding:.5rem 0;margin:0;font-size:1rem;color:#212529;text-align:left;list-style:none;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.15);border-radius:.25rem}.dropdown-menu[data-bs-popper]{top:100%;left:0;margin-top:.125rem}.dropdown-menu-start{--bs-position:start}.dropdown-menu-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-end{--bs-position:end}.dropdown-menu-end[data-bs-popper]{right:0;left:auto}@media (min-width:576px){.dropdown-menu-sm-start{--bs-position:start}.dropdown-menu-sm-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-sm-end{--bs-position:end}.dropdown-menu-sm-end[data-bs-popper]{right:0;left:auto}}@media (min-width:768px){.dropdown-menu-md-start{--bs-position:start}.dropdown-menu-md-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-md-end{--bs-position:end}.dropdown-menu-md-end[data-bs-popper]{right:0;left:auto}}@media (min-width:992px){.dropdown-menu-lg-start{--bs-position:start}.dropdown-menu-lg-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-lg-end{--bs-position:end}.dropdown-menu-lg-end[data-bs-popper]{right:0;left:auto}}@media (min-width:1200px){.dropdown-menu-xl-start{--bs-position:start}.dropdown-menu-xl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xl-end{--bs-position:end}.dropdown-menu-xl-end[data-bs-popper]{right:0;left:auto}}@media (min-width:1400px){.dropdown-menu-xxl-start{--bs-position:start}.dropdown-menu-xxl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xxl-end{--bs-position:end}.dropdown-menu-xxl-end[data-bs-popper]{right:0;left:auto}}.dropup .dropdown-menu[data-bs-popper]{top:auto;bottom:100%;margin-top:0;margin-bottom:.125rem}.dropup .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid transparent;border-bottom:.3em solid;border-left:.3em solid transparent}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-menu[data-bs-popper]{top:0;right:auto;left:100%;margin-top:0;margin-left:.125rem}.dropend .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:0;border-bottom:.3em solid transparent;border-left:.3em solid}.dropend .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-toggle::after{vertical-align:0}.dropstart .dropdown-menu[data-bs-popper]{top:0;right:100%;left:auto;margin-top:0;margin-right:.125rem}.dropstart .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:""}.dropstart .dropdown-toggle::after{display:none}.dropstart .dropdown-toggle::before{display:inline-block;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:.3em solid;border-bottom:.3em solid transparent}.dropstart .dropdown-toggle:empty::after{margin-left:0}.dropstart .dropdown-toggle::before{vertical-align:0}.dropdown-divider{height:0;margin:.5rem 0;overflow:hidden;border-top:1px solid rgba(0,0,0,.15)}.dropdown-item{display:block;width:100%;padding:.25rem 1rem;clear:both;font-weight:400;color:#212529;text-align:inherit;text-decoration:none;white-space:nowrap;background-color:transparent;border:0}.dropdown-item:focus,.dropdown-item:hover{color:#1e2125;background-color:#e9ecef}.dropdown-item.active,.dropdown-item:active{color:#fff;text-decoration:none;background-color:#0d6efd}.dropdown-item.disabled,.dropdown-item:disabled{color:#adb5bd;pointer-events:none;background-color:transparent}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:.5rem 1rem;margin-bottom:0;font-size:.875rem;color:#6c757d;white-space:nowrap}.dropdown-item-text{display:block;padding:.25rem 1rem;color:#212529}.dropdown-menu-dark{color:#dee2e6;background-color:#343a40;border-color:rgba(0,0,0,.15)}.dropdown-menu-dark .dropdown-item{color:#dee2e6}.dropdown-menu-dark .dropdown-item:focus,.dropdown-menu-dark .dropdown-item:hover{color:#fff;background-color:rgba(255,255,255,.15)}.dropdown-menu-dark .dropdown-item.active,.dropdown-menu-dark .dropdown-item:active{color:#fff;background-color:#0d6efd}.dropdown-menu-dark .dropdown-item.disabled,.dropdown-menu-dark .dropdown-item:disabled{color:#adb5bd}.dropdown-menu-dark .dropdown-divider{border-color:rgba(0,0,0,.15)}.dropdown-menu-dark .dropdown-item-text{color:#dee2e6}.dropdown-menu-dark .dropdown-header{color:#adb5bd}.btn-group,.btn-group-vertical{position:relative;display:inline-flex;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;flex:1 1 auto}.btn-group-vertical>.btn-check:checked+.btn,.btn-group-vertical>.btn-check:focus+.btn,.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn-check:checked+.btn,.btn-group>.btn-check:focus+.btn,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:1}.btn-toolbar{display:flex;flex-wrap:wrap;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group>.btn-group:not(:first-child),.btn-group>.btn:not(:first-child){margin-left:-1px}.btn-group>.btn-group:not(:last-child)>.btn,.btn-group>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:not(:first-child)>.btn,.btn-group>.btn:nth-child(n+3),.btn-group>:not(.btn-check)+.btn{border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.dropdown-toggle-split::after,.dropend .dropdown-toggle-split::after,.dropup .dropdown-toggle-split::after{margin-left:0}.dropstart .dropdown-toggle-split::before{margin-right:0}.btn-group-sm>.btn+.dropdown-toggle-split,.btn-sm+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-group-lg>.btn+.dropdown-toggle-split,.btn-lg+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{flex-direction:column;align-items:flex-start;justify-content:center}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{width:100%}.btn-group-vertical>.btn-group:not(:first-child),.btn-group-vertical>.btn:not(:first-child){margin-top:-1px}.btn-group-vertical>.btn-group:not(:last-child)>.btn,.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child)>.btn,.btn-group-vertical>.btn~.btn{border-top-left-radius:0;border-top-right-radius:0}.nav{display:flex;flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:.5rem 1rem;color:#0d6efd;text-decoration:none;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out}@media (prefers-reduced-motion:reduce){.nav-link{transition:none}}.nav-link:focus,.nav-link:hover{color:#0a58ca}.nav-link.disabled{color:#6c757d;pointer-events:none;cursor:default}.nav-tabs{border-bottom:1px solid #dee2e6}.nav-tabs .nav-link{margin-bottom:-1px;background:0 0;border:1px solid transparent;border-top-left-radius:.25rem;border-top-right-radius:.25rem}.nav-tabs .nav-link:focus,.nav-tabs .nav-link:hover{border-color:#e9ecef #e9ecef #dee2e6;isolation:isolate}.nav-tabs .nav-link.disabled{color:#6c757d;background-color:transparent;border-color:transparent}.nav-tabs .nav-item.show .nav-link,.nav-tabs .nav-link.active{color:#495057;background-color:#fff;border-color:#dee2e6 #dee2e6 #fff}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.nav-pills .nav-link{background:0 0;border:0;border-radius:.25rem}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:#fff;background-color:#0d6efd}.nav-fill .nav-item,.nav-fill>.nav-link{flex:1 1 auto;text-align:center}.nav-justified .nav-item,.nav-justified>.nav-link{flex-basis:0;flex-grow:1;text-align:center}.nav-fill .nav-item .nav-link,.nav-justified .nav-item .nav-link{width:100%}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{position:relative;display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;padding-top:.5rem;padding-bottom:.5rem}.navbar>.container,.navbar>.container-fluid,.navbar>.container-lg,.navbar>.container-md,.navbar>.container-sm,.navbar>.container-xl,.navbar>.container-xxl{display:flex;flex-wrap:inherit;align-items:center;justify-content:space-between}.navbar-brand{padding-top:.3125rem;padding-bottom:.3125rem;margin-right:1rem;font-size:1.25rem;text-decoration:none;white-space:nowrap}.navbar-nav{display:flex;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link{padding-right:0;padding-left:0}.navbar-nav .dropdown-menu{position:static}.navbar-text{padding-top:.5rem;padding-bottom:.5rem}.navbar-collapse{flex-basis:100%;flex-grow:1;align-items:center}.navbar-toggler{padding:.25rem .75rem;font-size:1.25rem;line-height:1;background-color:transparent;border:1px solid transparent;border-radius:.25rem;transition:box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.navbar-toggler{transition:none}}.navbar-toggler:hover{text-decoration:none}.navbar-toggler:focus{text-decoration:none;outline:0;box-shadow:0 0 0 .25rem}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;background-repeat:no-repeat;background-position:center;background-size:100%}.navbar-nav-scroll{max-height:var(--bs-scroll-height,75vh);overflow-y:auto}@media (min-width:576px){.navbar-expand-sm{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-sm .navbar-nav{flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-sm .navbar-nav-scroll{overflow:visible}.navbar-expand-sm .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}}@media (min-width:768px){.navbar-expand-md{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-md .navbar-nav{flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-md .navbar-nav-scroll{overflow:visible}.navbar-expand-md .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}}@media (min-width:992px){.navbar-expand-lg{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-lg .navbar-nav{flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-lg .navbar-nav-scroll{overflow:visible}.navbar-expand-lg .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}}@media (min-width:1200px){.navbar-expand-xl{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-xl .navbar-nav{flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-xl .navbar-nav-scroll{overflow:visible}.navbar-expand-xl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}}@media (min-width:1400px){.navbar-expand-xxl{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-xxl .navbar-nav{flex-direction:row}.navbar-expand-xxl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xxl .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-xxl .navbar-nav-scroll{overflow:visible}.navbar-expand-xxl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xxl .navbar-toggler{display:none}}.navbar-expand{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand .navbar-nav{flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand .navbar-nav-scroll{overflow:visible}.navbar-expand .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-light .navbar-brand{color:rgba(0,0,0,.9)}.navbar-light .navbar-brand:focus,.navbar-light .navbar-brand:hover{color:rgba(0,0,0,.9)}.navbar-light .navbar-nav .nav-link{color:rgba(0,0,0,.55)}.navbar-light .navbar-nav .nav-link:focus,.navbar-light .navbar-nav .nav-link:hover{color:rgba(0,0,0,.7)}.navbar-light .navbar-nav .nav-link.disabled{color:rgba(0,0,0,.3)}.navbar-light .navbar-nav .nav-link.active,.navbar-light .navbar-nav .show>.nav-link{color:rgba(0,0,0,.9)}.navbar-light .navbar-toggler{color:rgba(0,0,0,.55);border-color:rgba(0,0,0,.1)}.navbar-light .navbar-toggler-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%280, 0, 0, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.navbar-light .navbar-text{color:rgba(0,0,0,.55)}.navbar-light .navbar-text a,.navbar-light .navbar-text a:focus,.navbar-light .navbar-text a:hover{color:rgba(0,0,0,.9)}.navbar-dark .navbar-brand{color:#fff}.navbar-dark .navbar-brand:focus,.navbar-dark .navbar-brand:hover{color:#fff}.navbar-dark .navbar-nav .nav-link{color:rgba(255,255,255,.55)}.navbar-dark .navbar-nav .nav-link:focus,.navbar-dark .navbar-nav .nav-link:hover{color:rgba(255,255,255,.75)}.navbar-dark .navbar-nav .nav-link.disabled{color:rgba(255,255,255,.25)}.navbar-dark .navbar-nav .nav-link.active,.navbar-dark .navbar-nav .show>.nav-link{color:#fff}.navbar-dark .navbar-toggler{color:rgba(255,255,255,.55);border-color:rgba(255,255,255,.1)}.navbar-dark .navbar-toggler-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.navbar-dark .navbar-text{color:rgba(255,255,255,.55)}.navbar-dark .navbar-text a,.navbar-dark .navbar-text a:focus,.navbar-dark .navbar-text a:hover{color:#fff}.card{position:relative;display:flex;flex-direction:column;min-width:0;word-wrap:break-word;background-color:#fff;background-clip:border-box;border:1px solid rgba(0,0,0,.125);border-radius:.25rem}.card>hr{margin-right:0;margin-left:0}.card>.list-group{border-top:inherit;border-bottom:inherit}.card>.list-group:first-child{border-top-width:0;border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.card>.list-group:last-child{border-bottom-width:0;border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.card>.card-header+.list-group,.card>.list-group+.card-footer{border-top:0}.card-body{flex:1 1 auto;padding:1rem 1rem}.card-title{margin-bottom:.5rem}.card-subtitle{margin-top:-.25rem;margin-bottom:0}.card-text:last-child{margin-bottom:0}.card-link:hover{text-decoration:none}.card-link+.card-link{margin-left:1rem}.card-header{padding:.5rem 1rem;margin-bottom:0;background-color:rgba(0,0,0,.03);border-bottom:1px solid rgba(0,0,0,.125)}.card-header:first-child{border-radius:calc(.25rem - 1px) calc(.25rem - 1px) 0 0}.card-footer{padding:.5rem 1rem;background-color:rgba(0,0,0,.03);border-top:1px solid rgba(0,0,0,.125)}.card-footer:last-child{border-radius:0 0 calc(.25rem - 1px) calc(.25rem - 1px)}.card-header-tabs{margin-right:-.5rem;margin-bottom:-.5rem;margin-left:-.5rem;border-bottom:0}.card-header-pills{margin-right:-.5rem;margin-left:-.5rem}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1rem;border-radius:calc(.25rem - 1px)}.card-img,.card-img-bottom,.card-img-top{width:100%}.card-img,.card-img-top{border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.card-img,.card-img-bottom{border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.card-group>.card{margin-bottom:.75rem}@media (min-width:576px){.card-group{display:flex;flex-flow:row wrap}.card-group>.card{flex:1 0 0%;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}.card-group>.card:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.card-group>.card:not(:last-child) .card-header,.card-group>.card:not(:last-child) .card-img-top{border-top-right-radius:0}.card-group>.card:not(:last-child) .card-footer,.card-group>.card:not(:last-child) .card-img-bottom{border-bottom-right-radius:0}.card-group>.card:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.card-group>.card:not(:first-child) .card-header,.card-group>.card:not(:first-child) .card-img-top{border-top-left-radius:0}.card-group>.card:not(:first-child) .card-footer,.card-group>.card:not(:first-child) .card-img-bottom{border-bottom-left-radius:0}}.accordion-button{position:relative;display:flex;align-items:center;width:100%;padding:1rem 1.25rem;font-size:1rem;color:#212529;text-align:left;background-color:#fff;border:0;border-radius:0;overflow-anchor:none;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out,border-radius .15s ease}@media (prefers-reduced-motion:reduce){.accordion-button{transition:none}}.accordion-button:not(.collapsed){color:#0c63e4;background-color:#e7f1ff;box-shadow:inset 0 -1px 0 rgba(0,0,0,.125)}.accordion-button:not(.collapsed)::after{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%230c63e4'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");transform:rotate(-180deg)}.accordion-button::after{flex-shrink:0;width:1.25rem;height:1.25rem;margin-left:auto;content:"";background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23212529'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");background-repeat:no-repeat;background-size:1.25rem;transition:transform .2s ease-in-out}@media (prefers-reduced-motion:reduce){.accordion-button::after{transition:none}}.accordion-button:hover{z-index:2}.accordion-button:focus{z-index:3;border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.accordion-header{margin-bottom:0}.accordion-item{background-color:#fff;border:1px solid rgba(0,0,0,.125)}.accordion-item:first-of-type{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.accordion-item:first-of-type .accordion-button{border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.accordion-item:not(:first-of-type){border-top:0}.accordion-item:last-of-type{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.accordion-item:last-of-type .accordion-button.collapsed{border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.accordion-item:last-of-type .accordion-collapse{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.accordion-body{padding:1rem 1.25rem}.accordion-flush .accordion-collapse{border-width:0}.accordion-flush .accordion-item{border-right:0;border-left:0;border-radius:0}.accordion-flush .accordion-item:first-child{border-top:0}.accordion-flush .accordion-item:last-child{border-bottom:0}.accordion-flush .accordion-item .accordion-button{border-radius:0}.breadcrumb{display:flex;flex-wrap:wrap;padding:0 0;margin-bottom:1rem;list-style:none}.breadcrumb-item+.breadcrumb-item{padding-left:.5rem}.breadcrumb-item+.breadcrumb-item::before{float:left;padding-right:.5rem;color:#6c757d;content:var(--bs-breadcrumb-divider, "/")}.breadcrumb-item.active{color:#6c757d}.pagination{display:flex;padding-left:0;list-style:none}.page-link{position:relative;display:block;color:#0d6efd;text-decoration:none;background-color:#fff;border:1px solid #dee2e6;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.page-link{transition:none}}.page-link:hover{z-index:2;color:#0a58ca;background-color:#e9ecef;border-color:#dee2e6}.page-link:focus{z-index:3;color:#0a58ca;background-color:#e9ecef;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.page-item:not(:first-child) .page-link{margin-left:-1px}.page-item.active .page-link{z-index:3;color:#fff;background-color:#0d6efd;border-color:#0d6efd}.page-item.disabled .page-link{color:#6c757d;pointer-events:none;background-color:#fff;border-color:#dee2e6}.page-link{padding:.375rem .75rem}.page-item:first-child .page-link{border-top-left-radius:.25rem;border-bottom-left-radius:.25rem}.page-item:last-child .page-link{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.pagination-lg .page-link{padding:.75rem 1.5rem;font-size:1.25rem}.pagination-lg .page-item:first-child .page-link{border-top-left-radius:.3rem;border-bottom-left-radius:.3rem}.pagination-lg .page-item:last-child .page-link{border-top-right-radius:.3rem;border-bottom-right-radius:.3rem}.pagination-sm .page-link{padding:.25rem .5rem;font-size:.875rem}.pagination-sm .page-item:first-child .page-link{border-top-left-radius:.2rem;border-bottom-left-radius:.2rem}.pagination-sm .page-item:last-child .page-link{border-top-right-radius:.2rem;border-bottom-right-radius:.2rem}.badge{display:inline-block;padding:.35em .65em;font-size:.75em;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.alert{position:relative;padding:1rem 1rem;margin-bottom:1rem;border:1px solid transparent;border-radius:.25rem}.alert-heading{color:inherit}.alert-link{font-weight:700}.alert-dismissible{padding-right:3rem}.alert-dismissible .btn-close{position:absolute;top:0;right:0;z-index:2;padding:1.25rem 1rem}.alert-primary{color:#084298;background-color:#cfe2ff;border-color:#b6d4fe}.alert-primary .alert-link{color:#06357a}.alert-secondary{color:#41464b;background-color:#e2e3e5;border-color:#d3d6d8}.alert-secondary .alert-link{color:#34383c}.alert-success{color:#0f5132;background-color:#d1e7dd;border-color:#badbcc}.alert-success .alert-link{color:#0c4128}.alert-info{color:#055160;background-color:#cff4fc;border-color:#b6effb}.alert-info .alert-link{color:#04414d}.alert-warning{color:#664d03;background-color:#fff3cd;border-color:#ffecb5}.alert-warning .alert-link{color:#523e02}.alert-danger{color:#842029;background-color:#f8d7da;border-color:#f5c2c7}.alert-danger .alert-link{color:#6a1a21}.alert-light{color:#636464;background-color:#fefefe;border-color:#fdfdfe}.alert-light .alert-link{color:#4f5050}.alert-dark{color:#141619;background-color:#d3d3d4;border-color:#bcbebf}.alert-dark .alert-link{color:#101214}@-webkit-keyframes progress-bar-stripes{0%{background-position-x:1rem}}@keyframes progress-bar-stripes{0%{background-position-x:1rem}}.progress{display:flex;height:1rem;overflow:hidden;font-size:.75rem;background-color:#e9ecef;border-radius:.25rem}.progress-bar{display:flex;flex-direction:column;justify-content:center;overflow:hidden;color:#fff;text-align:center;white-space:nowrap;background-color:#0d6efd;transition:width .6s ease}@media (prefers-reduced-motion:reduce){.progress-bar{transition:none}}.progress-bar-striped{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:1rem 1rem}.progress-bar-animated{-webkit-animation:1s linear infinite progress-bar-stripes;animation:1s linear infinite progress-bar-stripes}@media (prefers-reduced-motion:reduce){.progress-bar-animated{-webkit-animation:none;animation:none}}.list-group{display:flex;flex-direction:column;padding-left:0;margin-bottom:0;border-radius:.25rem}.list-group-numbered{list-style-type:none;counter-reset:section}.list-group-numbered>li::before{content:counters(section, ".") ". ";counter-increment:section}.list-group-item-action{width:100%;color:#495057;text-align:inherit}.list-group-item-action:focus,.list-group-item-action:hover{z-index:1;color:#495057;text-decoration:none;background-color:#f8f9fa}.list-group-item-action:active{color:#212529;background-color:#e9ecef}.list-group-item{position:relative;display:block;padding:.5rem 1rem;color:#212529;text-decoration:none;background-color:#fff;border:1px solid rgba(0,0,0,.125)}.list-group-item:first-child{border-top-left-radius:inherit;border-top-right-radius:inherit}.list-group-item:last-child{border-bottom-right-radius:inherit;border-bottom-left-radius:inherit}.list-group-item.disabled,.list-group-item:disabled{color:#6c757d;pointer-events:none;background-color:#fff}.list-group-item.active{z-index:2;color:#fff;background-color:#0d6efd;border-color:#0d6efd}.list-group-item+.list-group-item{border-top-width:0}.list-group-item+.list-group-item.active{margin-top:-1px;border-top-width:1px}.list-group-horizontal{flex-direction:row}.list-group-horizontal>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal>.list-group-item.active{margin-top:0}.list-group-horizontal>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}@media (min-width:576px){.list-group-horizontal-sm{flex-direction:row}.list-group-horizontal-sm>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-sm>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-sm>.list-group-item.active{margin-top:0}.list-group-horizontal-sm>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-sm>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width:768px){.list-group-horizontal-md{flex-direction:row}.list-group-horizontal-md>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-md>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-md>.list-group-item.active{margin-top:0}.list-group-horizontal-md>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-md>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width:992px){.list-group-horizontal-lg{flex-direction:row}.list-group-horizontal-lg>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-lg>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-lg>.list-group-item.active{margin-top:0}.list-group-horizontal-lg>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-lg>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width:1200px){.list-group-horizontal-xl{flex-direction:row}.list-group-horizontal-xl>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-xl>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-xl>.list-group-item.active{margin-top:0}.list-group-horizontal-xl>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-xl>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width:1400px){.list-group-horizontal-xxl{flex-direction:row}.list-group-horizontal-xxl>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-xxl>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-xxl>.list-group-item.active{margin-top:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}.list-group-flush{border-radius:0}.list-group-flush>.list-group-item{border-width:0 0 1px}.list-group-flush>.list-group-item:last-child{border-bottom-width:0}.list-group-item-primary{color:#084298;background-color:#cfe2ff}.list-group-item-primary.list-group-item-action:focus,.list-group-item-primary.list-group-item-action:hover{color:#084298;background-color:#bacbe6}.list-group-item-primary.list-group-item-action.active{color:#fff;background-color:#084298;border-color:#084298}.list-group-item-secondary{color:#41464b;background-color:#e2e3e5}.list-group-item-secondary.list-group-item-action:focus,.list-group-item-secondary.list-group-item-action:hover{color:#41464b;background-color:#cbccce}.list-group-item-secondary.list-group-item-action.active{color:#fff;background-color:#41464b;border-color:#41464b}.list-group-item-success{color:#0f5132;background-color:#d1e7dd}.list-group-item-success.list-group-item-action:focus,.list-group-item-success.list-group-item-action:hover{color:#0f5132;background-color:#bcd0c7}.list-group-item-success.list-group-item-action.active{color:#fff;background-color:#0f5132;border-color:#0f5132}.list-group-item-info{color:#055160;background-color:#cff4fc}.list-group-item-info.list-group-item-action:focus,.list-group-item-info.list-group-item-action:hover{color:#055160;background-color:#badce3}.list-group-item-info.list-group-item-action.active{color:#fff;background-color:#055160;border-color:#055160}.list-group-item-warning{color:#664d03;background-color:#fff3cd}.list-group-item-warning.list-group-item-action:focus,.list-group-item-warning.list-group-item-action:hover{color:#664d03;background-color:#e6dbb9}.list-group-item-warning.list-group-item-action.active{color:#fff;background-color:#664d03;border-color:#664d03}.list-group-item-danger{color:#842029;background-color:#f8d7da}.list-group-item-danger.list-group-item-action:focus,.list-group-item-danger.list-group-item-action:hover{color:#842029;background-color:#dfc2c4}.list-group-item-danger.list-group-item-action.active{color:#fff;background-color:#842029;border-color:#842029}.list-group-item-light{color:#636464;background-color:#fefefe}.list-group-item-light.list-group-item-action:focus,.list-group-item-light.list-group-item-action:hover{color:#636464;background-color:#e5e5e5}.list-group-item-light.list-group-item-action.active{color:#fff;background-color:#636464;border-color:#636464}.list-group-item-dark{color:#141619;background-color:#d3d3d4}.list-group-item-dark.list-group-item-action:focus,.list-group-item-dark.list-group-item-action:hover{color:#141619;background-color:#bebebf}.list-group-item-dark.list-group-item-action.active{color:#fff;background-color:#141619;border-color:#141619}.btn-close{box-sizing:content-box;width:1em;height:1em;padding:.25em .25em;color:#000;background:transparent url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 011.414 0L8 6.586 14.293.293a1 1 0 111.414 1.414L9.414 8l6.293 6.293a1 1 0 01-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 01-1.414-1.414L6.586 8 .293 1.707a1 1 0 010-1.414z'/%3e%3c/svg%3e") center/1em auto no-repeat;border:0;border-radius:.25rem;opacity:.5}.btn-close:hover{color:#000;text-decoration:none;opacity:.75}.btn-close:focus{outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25);opacity:1}.btn-close.disabled,.btn-close:disabled{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;opacity:.25}.btn-close-white{filter:invert(1) grayscale(100%) brightness(200%)}.toast{width:350px;max-width:100%;font-size:.875rem;pointer-events:auto;background-color:rgba(255,255,255,.85);background-clip:padding-box;border:1px solid rgba(0,0,0,.1);box-shadow:0 .5rem 1rem rgba(0,0,0,.15);border-radius:.25rem}.toast:not(.showing):not(.show){opacity:0}.toast.hide{display:none}.toast-container{width:-webkit-max-content;width:-moz-max-content;width:max-content;max-width:100%;pointer-events:none}.toast-container>:not(:last-child){margin-bottom:.75rem}.toast-header{display:flex;align-items:center;padding:.5rem .75rem;color:#6c757d;background-color:rgba(255,255,255,.85);background-clip:padding-box;border-bottom:1px solid rgba(0,0,0,.05);border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.toast-header .btn-close{margin-right:-.375rem;margin-left:.75rem}.toast-body{padding:.75rem;word-wrap:break-word}.modal{position:fixed;top:0;left:0;z-index:1060;display:none;width:100%;height:100%;overflow-x:hidden;overflow-y:auto;outline:0}.modal-dialog{position:relative;width:auto;margin:.5rem;pointer-events:none}.modal.fade .modal-dialog{transition:transform .3s ease-out;transform:translate(0,-50px)}@media (prefers-reduced-motion:reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{transform:none}.modal.modal-static .modal-dialog{transform:scale(1.02)}.modal-dialog-scrollable{height:calc(100% - 1rem)}.modal-dialog-scrollable .modal-content{max-height:100%;overflow:hidden}.modal-dialog-scrollable .modal-body{overflow-y:auto}.modal-dialog-centered{display:flex;align-items:center;min-height:calc(100% - 1rem)}.modal-content{position:relative;display:flex;flex-direction:column;width:100%;pointer-events:auto;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem;outline:0}.modal-backdrop{position:fixed;top:0;left:0;z-index:1040;width:100vw;height:100vh;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:.5}.modal-header{display:flex;flex-shrink:0;align-items:center;justify-content:space-between;padding:1rem 1rem;border-bottom:1px solid #dee2e6;border-top-left-radius:calc(.3rem - 1px);border-top-right-radius:calc(.3rem - 1px)}.modal-header .btn-close{padding:.5rem .5rem;margin:-.5rem -.5rem -.5rem auto}.modal-title{margin-bottom:0;line-height:1.5}.modal-body{position:relative;flex:1 1 auto;padding:1rem}.modal-footer{display:flex;flex-wrap:wrap;flex-shrink:0;align-items:center;justify-content:flex-end;padding:.75rem;border-top:1px solid #dee2e6;border-bottom-right-radius:calc(.3rem - 1px);border-bottom-left-radius:calc(.3rem - 1px)}.modal-footer>*{margin:.25rem}@media (min-width:576px){.modal-dialog{max-width:500px;margin:1.75rem auto}.modal-dialog-scrollable{height:calc(100% - 3.5rem)}.modal-dialog-centered{min-height:calc(100% - 3.5rem)}.modal-sm{max-width:300px}}@media (min-width:992px){.modal-lg,.modal-xl{max-width:600px}}@media (min-width:1200px){.modal-xl{max-width:1140px}}.modal-fullscreen{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen .modal-header{border-radius:0}.modal-fullscreen .modal-body{overflow-y:auto}.modal-fullscreen .modal-footer{border-radius:0}@media (max-width:575.98px){.modal-fullscreen-sm-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-sm-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-sm-down .modal-header{border-radius:0}.modal-fullscreen-sm-down .modal-body{overflow-y:auto}.modal-fullscreen-sm-down .modal-footer{border-radius:0}}@media (max-width:767.98px){.modal-fullscreen-md-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-md-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-md-down .modal-header{border-radius:0}.modal-fullscreen-md-down .modal-body{overflow-y:auto}.modal-fullscreen-md-down .modal-footer{border-radius:0}}@media (max-width:991.98px){.modal-fullscreen-lg-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-lg-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-lg-down .modal-header{border-radius:0}.modal-fullscreen-lg-down .modal-body{overflow-y:auto}.modal-fullscreen-lg-down .modal-footer{border-radius:0}}@media (max-width:1199.98px){.modal-fullscreen-xl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xl-down .modal-header{border-radius:0}.modal-fullscreen-xl-down .modal-body{overflow-y:auto}.modal-fullscreen-xl-down .modal-footer{border-radius:0}}@media (max-width:1399.98px){.modal-fullscreen-xxl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xxl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xxl-down .modal-header{border-radius:0}.modal-fullscreen-xxl-down .modal-body{overflow-y:auto}.modal-fullscreen-xxl-down .modal-footer{border-radius:0}}.tooltip{position:absolute;z-index:1080;display:block;margin:0;font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;opacity:0}.tooltip.show{opacity:.9}.tooltip .tooltip-arrow{position:absolute;display:block;width:.8rem;height:.4rem}.tooltip .tooltip-arrow::before{position:absolute;content:"";border-color:transparent;border-style:solid}.bs-tooltip-auto[data-popper-placement^=top],.bs-tooltip-top{padding:.4rem 0}.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow,.bs-tooltip-top .tooltip-arrow{bottom:0}.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow::before,.bs-tooltip-top .tooltip-arrow::before{top:-1px;border-width:.4rem .4rem 0;border-top-color:#000}.bs-tooltip-auto[data-popper-placement^=right],.bs-tooltip-end{padding:0 .4rem}.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow,.bs-tooltip-end .tooltip-arrow{left:0;width:.4rem;height:.8rem}.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow::before,.bs-tooltip-end .tooltip-arrow::before{right:-1px;border-width:.4rem .4rem .4rem 0;border-right-color:#000}.bs-tooltip-auto[data-popper-placement^=bottom],.bs-tooltip-bottom{padding:.4rem 0}.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow,.bs-tooltip-bottom .tooltip-arrow{top:0}.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow::before,.bs-tooltip-bottom .tooltip-arrow::before{bottom:-1px;border-width:0 .4rem .4rem;border-bottom-color:#000}.bs-tooltip-auto[data-popper-placement^=left],.bs-tooltip-start{padding:0 .4rem}.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow,.bs-tooltip-start .tooltip-arrow{right:0;width:.4rem;height:.8rem}.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow::before,.bs-tooltip-start .tooltip-arrow::before{left:-1px;border-width:.4rem 0 .4rem .4rem;border-left-color:#000}.tooltip-inner{max-width:200px;padding:.25rem .5rem;color:#fff;text-align:center;background-color:#000;border-radius:.25rem}.popover{position:absolute;top:0;left:0;z-index:1070;display:block;max-width:276px;font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem}.popover .popover-arrow{position:absolute;display:block;width:1rem;height:.5rem}.popover .popover-arrow::after,.popover .popover-arrow::before{position:absolute;display:block;content:"";border-color:transparent;border-style:solid}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow,.bs-popover-top>.popover-arrow{bottom:calc(-.5rem - 1px)}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::before,.bs-popover-top>.popover-arrow::before{bottom:0;border-width:.5rem .5rem 0;border-top-color:rgba(0,0,0,.25)}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::after,.bs-popover-top>.popover-arrow::after{bottom:1px;border-width:.5rem .5rem 0;border-top-color:#fff}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow,.bs-popover-end>.popover-arrow{left:calc(-.5rem - 1px);width:.5rem;height:1rem}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::before,.bs-popover-end>.popover-arrow::before{left:0;border-width:.5rem .5rem .5rem 0;border-right-color:rgba(0,0,0,.25)}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::after,.bs-popover-end>.popover-arrow::after{left:1px;border-width:.5rem .5rem .5rem 0;border-right-color:#fff}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow,.bs-popover-bottom>.popover-arrow{top:calc(-.5rem - 1px)}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::before,.bs-popover-bottom>.popover-arrow::before{top:0;border-width:0 .5rem .5rem .5rem;border-bottom-color:rgba(0,0,0,.25)}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::after,.bs-popover-bottom>.popover-arrow::after{top:1px;border-width:0 .5rem .5rem .5rem;border-bottom-color:#fff}.bs-popover-auto[data-popper-placement^=bottom] .popover-header::before,.bs-popover-bottom .popover-header::before{position:absolute;top:0;left:50%;display:block;width:1rem;margin-left:-.5rem;content:"";border-bottom:1px solid #f0f0f0}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow,.bs-popover-start>.popover-arrow{right:calc(-.5rem - 1px);width:.5rem;height:1rem}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::before,.bs-popover-start>.popover-arrow::before{right:0;border-width:.5rem 0 .5rem .5rem;border-left-color:rgba(0,0,0,.25)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::after,.bs-popover-start>.popover-arrow::after{right:1px;border-width:.5rem 0 .5rem .5rem;border-left-color:#fff}.popover-header{padding:.5rem 1rem;margin-bottom:0;font-size:1rem;background-color:#f0f0f0;border-bottom:1px solid rgba(0,0,0,.2);border-top-left-radius:calc(.3rem - 1px);border-top-right-radius:calc(.3rem - 1px)}.popover-header:empty{display:none}.popover-body{padding:1rem 1rem;color:#212529}.carousel{position:relative}.carousel.pointer-event{touch-action:pan-y}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner::after{display:block;clear:both;content:""}.carousel-item{position:relative;display:none;float:left;width:100%;margin-right:-100%;-webkit-backface-visibility:hidden;backface-visibility:hidden;transition:transform .6s ease-in-out}@media (prefers-reduced-motion:reduce){.carousel-item{transition:none}}.carousel-item-next,.carousel-item-prev,.carousel-item.active{display:block}.active.carousel-item-end,.carousel-item-next:not(.carousel-item-start){transform:translateX(100%)}.active.carousel-item-start,.carousel-item-prev:not(.carousel-item-end){transform:translateX(-100%)}.carousel-fade .carousel-item{opacity:0;transition-property:opacity;transform:none}.carousel-fade .carousel-item-next.carousel-item-start,.carousel-fade .carousel-item-prev.carousel-item-end,.carousel-fade .carousel-item.active{z-index:1;opacity:1}.carousel-fade .active.carousel-item-end,.carousel-fade .active.carousel-item-start{z-index:0;opacity:0;transition:opacity 0s .6s}@media (prefers-reduced-motion:reduce){.carousel-fade .active.carousel-item-end,.carousel-fade .active.carousel-item-start{transition:none}}.carousel-control-next,.carousel-control-prev{position:absolute;top:0;bottom:0;z-index:1;display:flex;align-items:center;justify-content:center;width:15%;padding:0;color:#fff;text-align:center;background:0 0;border:0;opacity:.5;transition:opacity .15s ease}@media (prefers-reduced-motion:reduce){.carousel-control-next,.carousel-control-prev{transition:none}}.carousel-control-next:focus,.carousel-control-next:hover,.carousel-control-prev:focus,.carousel-control-prev:hover{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-next-icon,.carousel-control-prev-icon{display:inline-block;width:2rem;height:2rem;background-repeat:no-repeat;background-position:50%;background-size:100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'/%3e%3c/svg%3e")}.carousel-control-next-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e")}.carousel-indicators{position:absolute;right:0;bottom:0;left:0;z-index:2;display:flex;justify-content:center;padding:0;margin-right:15%;margin-bottom:1rem;margin-left:15%;list-style:none}.carousel-indicators [data-bs-target]{box-sizing:content-box;flex:0 1 auto;width:30px;height:3px;padding:0;margin-right:3px;margin-left:3px;text-indent:-999px;cursor:pointer;background-color:#fff;background-clip:padding-box;border:0;border-top:10px solid transparent;border-bottom:10px solid transparent;opacity:.5;transition:opacity .6s ease}@media (prefers-reduced-motion:reduce){.carousel-indicators [data-bs-target]{transition:none}}.carousel-indicators .active{opacity:1}.carousel-caption{position:absolute;right:15%;bottom:1.25rem;left:15%;padding-top:1.25rem;padding-bottom:1.25rem;color:#fff;text-align:center}.carousel-dark .carousel-control-next-icon,.carousel-dark .carousel-control-prev-icon{filter:invert(1) grayscale(100)}.carousel-dark .carousel-indicators [data-bs-target]{background-color:#000}.carousel-dark .carousel-caption{color:#000}@-webkit-keyframes spinner-border{to{transform:rotate(360deg)}}@keyframes spinner-border{to{transform:rotate(360deg)}}.spinner-border{display:inline-block;width:2rem;height:2rem;vertical-align:-.125em;border:.25em solid currentColor;border-right-color:transparent;border-radius:50%;-webkit-animation:.75s linear infinite spinner-border;animation:.75s linear infinite spinner-border}.spinner-border-sm{width:1rem;height:1rem;border-width:.2em}@-webkit-keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}@keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}.spinner-grow{display:inline-block;width:2rem;height:2rem;vertical-align:-.125em;background-color:currentColor;border-radius:50%;opacity:0;-webkit-animation:.75s linear infinite spinner-grow;animation:.75s linear infinite spinner-grow}.spinner-grow-sm{width:1rem;height:1rem}@media (prefers-reduced-motion:reduce){.spinner-border,.spinner-grow{-webkit-animation-duration:1.5s;animation-duration:1.5s}}.offcanvas{position:fixed;bottom:0;z-index:1050;display:flex;flex-direction:column;max-width:100%;visibility:hidden;background-color:#fff;background-clip:padding-box;outline:0;transition:transform .3s ease-in-out}@media (prefers-reduced-motion:reduce){.offcanvas{transition:none}}.offcanvas-header{display:flex;align-items:center;justify-content:space-between;padding:1rem 1rem}.offcanvas-header .btn-close{padding:.5rem .5rem;margin-top:-.5rem;margin-right:-.5rem;margin-bottom:-.5rem}.offcanvas-title{margin-bottom:0;line-height:1.5}.offcanvas-body{flex-grow:1;padding:1rem 1rem;overflow-y:auto}.offcanvas-start{top:0;left:0;width:400px;border-right:1px solid rgba(0,0,0,.2);transform:translateX(-100%)}.offcanvas-end{top:0;right:0;width:400px;border-left:1px solid rgba(0,0,0,.2);transform:translateX(100%)}.offcanvas-top{top:0;right:0;left:0;height:30vh;max-height:100%;border-bottom:1px solid rgba(0,0,0,.2);transform:translateY(-100%)}.offcanvas-bottom{right:0;left:0;height:30vh;max-height:100%;border-top:1px solid rgba(0,0,0,.2);transform:translateY(100%)}.offcanvas.show{transform:none}.clearfix::after{display:block;clear:both;content:""}.link-primary{color:#0d6efd}.link-primary:focus,.link-primary:hover{color:#0a58ca}.link-secondary{color:#6c757d}.link-secondary:focus,.link-secondary:hover{color:#565e64}.link-success{color:#198754}.link-success:focus,.link-success:hover{color:#146c43}.link-info{color:#0dcaf0}.link-info:focus,.link-info:hover{color:#3dd5f3}.link-warning{color:#ffc107}.link-warning:focus,.link-warning:hover{color:#ffcd39}.link-danger{color:#dc3545}.link-danger:focus,.link-danger:hover{color:#b02a37}.link-light{color:#f8f9fa}.link-light:focus,.link-light:hover{color:#f9fafb}.link-dark{color:#212529}.link-dark:focus,.link-dark:hover{color:#1a1e21}.ratio{position:relative;width:100%}.ratio::before{display:block;padding-top:var(--bs-aspect-ratio);content:""}.ratio>*{position:absolute;top:0;left:0;width:100%;height:100%}.ratio-1x1{--bs-aspect-ratio:100%}.ratio-4x3{--bs-aspect-ratio:calc(3 / 4 * 100%)}.ratio-16x9{--bs-aspect-ratio:calc(9 / 16 * 100%)}.ratio-21x9{--bs-aspect-ratio:calc(9 / 21 * 100%)}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}.sticky-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}@media (min-width:576px){.sticky-sm-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}@media (min-width:768px){.sticky-md-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}@media (min-width:992px){.sticky-lg-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}@media (min-width:1200px){.sticky-xl-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}@media (min-width:1400px){.sticky-xxl-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}.visually-hidden,.visually-hidden-focusable:not(:focus):not(:focus-within){position:absolute!important;width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important}.stretched-link::after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;content:""}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.align-baseline{vertical-align:baseline!important}.align-top{vertical-align:top!important}.align-middle{vertical-align:middle!important}.align-bottom{vertical-align:bottom!important}.align-text-bottom{vertical-align:text-bottom!important}.align-text-top{vertical-align:text-top!important}.float-start{float:left!important}.float-end{float:right!important}.float-none{float:none!important}.overflow-auto{overflow:auto!important}.overflow-hidden{overflow:hidden!important}.overflow-visible{overflow:visible!important}.overflow-scroll{overflow:scroll!important}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-grid{display:grid!important}.d-table{display:table!important}.d-table-row{display:table-row!important}.d-table-cell{display:table-cell!important}.d-flex{display:flex!important}.d-inline-flex{display:inline-flex!important}.d-none{display:none!important}.shadow{box-shadow:0 .5rem 1rem rgba(0,0,0,.15)!important}.shadow-sm{box-shadow:0 .125rem .25rem rgba(0,0,0,.075)!important}.shadow-lg{box-shadow:0 1rem 3rem rgba(0,0,0,.175)!important}.shadow-none{box-shadow:none!important}.position-static{position:static!important}.position-relative{position:relative!important}.position-absolute{position:absolute!important}.position-fixed{position:fixed!important}.position-sticky{position:-webkit-sticky!important;position:sticky!important}.top-0{top:0!important}.top-50{top:50%!important}.top-100{top:100%!important}.bottom-0{bottom:0!important}.bottom-50{bottom:50%!important}.bottom-100{bottom:100%!important}.start-0{left:0!important}.start-50{left:50%!important}.start-100{left:100%!important}.end-0{right:0!important}.end-50{right:50%!important}.end-100{right:100%!important}.translate-middle{transform:translate(-50%,-50%)!important}.translate-middle-x{transform:translateX(-50%)!important}.translate-middle-y{transform:translateY(-50%)!important}.border{border:1px solid #dee2e6!important}.border-0{border:0!important}.border-top{border-top:1px solid #dee2e6!important}.border-top-0{border-top:0!important}.border-end{border-right:1px solid #dee2e6!important}.border-end-0{border-right:0!important}.border-bottom{border-bottom:1px solid #dee2e6!important}.border-bottom-0{border-bottom:0!important}.border-start{border-left:1px solid #dee2e6!important}.border-start-0{border-left:0!important}.border-primary{border-color:#0d6efd!important}.border-secondary{border-color:#6c757d!important}.border-success{border-color:#198754!important}.border-info{border-color:#0dcaf0!important}.border-warning{border-color:#ffc107!important}.border-danger{border-color:#dc3545!important}.border-light{border-color:#f8f9fa!important}.border-dark{border-color:#212529!important}.border-white{border-color:#fff!important}.border-1{border-width:1px!important}.border-2{border-width:2px!important}.border-3{border-width:3px!important}.border-4{border-width:4px!important}.border-5{border-width:5px!important}.w-25{width:25%!important}.w-50{width:50%!important}.w-75{width:75%!important}.w-100{width:100%!important}.w-auto{width:auto!important}.mw-100{max-width:100%!important}.vw-100{width:100vw!important}.min-vw-100{min-width:100vw!important}.h-25{height:25%!important}.h-50{height:50%!important}.h-75{height:75%!important}.h-100{height:100%!important}.h-auto{height:auto!important}.mh-100{max-height:100%!important}.vh-100{height:100vh!important}.min-vh-100{min-height:100vh!important}.flex-fill{flex:1 1 auto!important}.flex-row{flex-direction:row!important}.flex-column{flex-direction:column!important}.flex-row-reverse{flex-direction:row-reverse!important}.flex-column-reverse{flex-direction:column-reverse!important}.flex-grow-0{flex-grow:0!important}.flex-grow-1{flex-grow:1!important}.flex-shrink-0{flex-shrink:0!important}.flex-shrink-1{flex-shrink:1!important}.flex-wrap{flex-wrap:wrap!important}.flex-nowrap{flex-wrap:nowrap!important}.flex-wrap-reverse{flex-wrap:wrap-reverse!important}.gap-0{gap:0!important}.gap-1{gap:.25rem!important}.gap-2{gap:.5rem!important}.gap-3{gap:1rem!important}.gap-4{gap:1.5rem!important}.gap-5{gap:3rem!important}.justify-content-start{justify-content:flex-start!important}.justify-content-end{justify-content:flex-end!important}.justify-content-center{justify-content:center!important}.justify-content-between{justify-content:space-between!important}.justify-content-around{justify-content:space-around!important}.justify-content-evenly{justify-content:space-evenly!important}.align-items-start{align-items:flex-start!important}.align-items-end{align-items:flex-end!important}.align-items-center{align-items:center!important}.align-items-baseline{align-items:baseline!important}.align-items-stretch{align-items:stretch!important}.align-content-start{align-content:flex-start!important}.align-content-end{align-content:flex-end!important}.align-content-center{align-content:center!important}.align-content-between{align-content:space-between!important}.align-content-around{align-content:space-around!important}.align-content-stretch{align-content:stretch!important}.align-self-auto{align-self:auto!important}.align-self-start{align-self:flex-start!important}.align-self-end{align-self:flex-end!important}.align-self-center{align-self:center!important}.align-self-baseline{align-self:baseline!important}.align-self-stretch{align-self:stretch!important}.order-first{order:-1!important}.order-0{order:0!important}.order-1{order:1!important}.order-2{order:2!important}.order-3{order:3!important}.order-4{order:4!important}.order-5{order:5!important}.order-last{order:6!important}.m-0{margin:0!important}.m-1{margin:.25rem!important}.m-2{margin:.5rem!important}.m-3{margin:1rem!important}.m-4{margin:1.5rem!important}.m-5{margin:3rem!important}.m-auto{margin:auto!important}.mx-0{margin-right:0!important;margin-left:0!important}.mx-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-3{margin-right:1rem!important;margin-left:1rem!important}.mx-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-5{margin-right:3rem!important;margin-left:3rem!important}.mx-auto{margin-right:auto!important;margin-left:auto!important}.my-0{margin-top:0!important;margin-bottom:0!important}.my-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-0{margin-top:0!important}.mt-1{margin-top:.25rem!important}.mt-2{margin-top:.5rem!important}.mt-3{margin-top:1rem!important}.mt-4{margin-top:1.5rem!important}.mt-5{margin-top:3rem!important}.mt-auto{margin-top:auto!important}.me-0{margin-right:0!important}.me-1{margin-right:.25rem!important}.me-2{margin-right:.5rem!important}.me-3{margin-right:1rem!important}.me-4{margin-right:1.5rem!important}.me-5{margin-right:3rem!important}.me-auto{margin-right:auto!important}.mb-0{margin-bottom:0!important}.mb-1{margin-bottom:.25rem!important}.mb-2{margin-bottom:.5rem!important}.mb-3{margin-bottom:1rem!important}.mb-4{margin-bottom:1.5rem!important}.mb-5{margin-bottom:3rem!important}.mb-auto{margin-bottom:auto!important}.ms-0{margin-left:0!important}.ms-1{margin-left:.25rem!important}.ms-2{margin-left:.5rem!important}.ms-3{margin-left:1rem!important}.ms-4{margin-left:1.5rem!important}.ms-5{margin-left:3rem!important}.ms-auto{margin-left:auto!important}.p-0{padding:0!important}.p-1{padding:.25rem!important}.p-2{padding:.5rem!important}.p-3{padding:1rem!important}.p-4{padding:1.5rem!important}.p-5{padding:3rem!important}.px-0{padding-right:0!important;padding-left:0!important}.px-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-3{padding-right:1rem!important;padding-left:1rem!important}.px-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-5{padding-right:3rem!important;padding-left:3rem!important}.py-0{padding-top:0!important;padding-bottom:0!important}.py-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-0{padding-top:0!important}.pt-1{padding-top:.25rem!important}.pt-2{padding-top:.5rem!important}.pt-3{padding-top:1rem!important}.pt-4{padding-top:1.5rem!important}.pt-5{padding-top:3rem!important}.pe-0{padding-right:0!important}.pe-1{padding-right:.25rem!important}.pe-2{padding-right:.5rem!important}.pe-3{padding-right:1rem!important}.pe-4{padding-right:1.5rem!important}.pe-5{padding-right:3rem!important}.pb-0{padding-bottom:0!important}.pb-1{padding-bottom:.25rem!important}.pb-2{padding-bottom:.5rem!important}.pb-3{padding-bottom:1rem!important}.pb-4{padding-bottom:1.5rem!important}.pb-5{padding-bottom:3rem!important}.ps-0{padding-left:0!important}.ps-1{padding-left:.25rem!important}.ps-2{padding-left:.5rem!important}.ps-3{padding-left:1rem!important}.ps-4{padding-left:1.5rem!important}.ps-5{padding-left:3rem!important}.font-monospace{font-family:var(--bs-font-monospace)!important}.fs-1{font-size:calc(1.375rem + 1.5vw)!important}.fs-2{font-size:calc(1.325rem + .9vw)!important}.fs-3{font-size:calc(1.3rem + .6vw)!important}.fs-4{font-size:calc(1.275rem + .3vw)!important}.fs-5{font-size:1.25rem!important}.fs-6{font-size:1rem!important}.fst-italic{font-style:italic!important}.fst-normal{font-style:normal!important}.fw-light{font-weight:300!important}.fw-lighter{font-weight:lighter!important}.fw-normal{font-weight:400!important}.fw-bold{font-weight:700!important}.fw-bolder{font-weight:bolder!important}.lh-1{line-height:1!important}.lh-sm{line-height:1.25!important}.lh-base{line-height:1.5!important}.lh-lg{line-height:2!important}.text-start{text-align:left!important}.text-end{text-align:right!important}.text-center{text-align:center!important}.text-decoration-none{text-decoration:none!important}.text-decoration-underline{text-decoration:underline!important}.text-decoration-line-through{text-decoration:line-through!important}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.text-wrap{white-space:normal!important}.text-nowrap{white-space:nowrap!important}.text-break{word-wrap:break-word!important;word-break:break-word!important}.text-primary{color:#0d6efd!important}.text-secondary{color:#6c757d!important}.text-success{color:#198754!important}.text-info{color:#0dcaf0!important}.text-warning{color:#ffc107!important}.text-danger{color:#dc3545!important}.text-light{color:#f8f9fa!important}.text-dark{color:#212529!important}.text-white{color:#fff!important}.text-body{color:#212529!important}.text-muted{color:#6c757d!important}.text-black-50{color:rgba(0,0,0,.5)!important}.text-white-50{color:rgba(255,255,255,.5)!important}.text-reset{color:inherit!important}.bg-primary{background-color:#0d6efd!important}.bg-secondary{background-color:#6c757d!important}.bg-success{background-color:#198754!important}.bg-info{background-color:#0dcaf0!important}.bg-warning{background-color:#ffc107!important}.bg-danger{background-color:#dc3545!important}.bg-light{background-color:#f8f9fa!important}.bg-dark{background-color:#212529!important}.bg-body{background-color:#fff!important}.bg-white{background-color:#fff!important}.bg-transparent{background-color:transparent!important}.bg-gradient{background-image:var(--bs-gradient)!important}.user-select-all{-webkit-user-select:all!important;-moz-user-select:all!important;user-select:all!important}.user-select-auto{-webkit-user-select:auto!important;-moz-user-select:auto!important;user-select:auto!important}.user-select-none{-webkit-user-select:none!important;-moz-user-select:none!important;user-select:none!important}.pe-none{pointer-events:none!important}.pe-auto{pointer-events:auto!important}.rounded{border-radius:.25rem!important}.rounded-0{border-radius:0!important}.rounded-1{border-radius:.2rem!important}.rounded-2{border-radius:.25rem!important}.rounded-3{border-radius:.3rem!important}.rounded-circle{border-radius:50%!important}.rounded-pill{border-radius:50rem!important}.rounded-top{border-top-left-radius:.25rem!important;border-top-right-radius:.25rem!important}.rounded-end{border-top-right-radius:.25rem!important;border-bottom-right-radius:.25rem!important}.rounded-bottom{border-bottom-right-radius:.25rem!important;border-bottom-left-radius:.25rem!important}.rounded-start{border-bottom-left-radius:.25rem!important;border-top-left-radius:.25rem!important}.visible{visibility:visible!important}.invisible{visibility:hidden!important}@media (min-width:576px){.float-sm-start{float:left!important}.float-sm-end{float:right!important}.float-sm-none{float:none!important}.d-sm-inline{display:inline!important}.d-sm-inline-block{display:inline-block!important}.d-sm-block{display:block!important}.d-sm-grid{display:grid!important}.d-sm-table{display:table!important}.d-sm-table-row{display:table-row!important}.d-sm-table-cell{display:table-cell!important}.d-sm-flex{display:flex!important}.d-sm-inline-flex{display:inline-flex!important}.d-sm-none{display:none!important}.flex-sm-fill{flex:1 1 auto!important}.flex-sm-row{flex-direction:row!important}.flex-sm-column{flex-direction:column!important}.flex-sm-row-reverse{flex-direction:row-reverse!important}.flex-sm-column-reverse{flex-direction:column-reverse!important}.flex-sm-grow-0{flex-grow:0!important}.flex-sm-grow-1{flex-grow:1!important}.flex-sm-shrink-0{flex-shrink:0!important}.flex-sm-shrink-1{flex-shrink:1!important}.flex-sm-wrap{flex-wrap:wrap!important}.flex-sm-nowrap{flex-wrap:nowrap!important}.flex-sm-wrap-reverse{flex-wrap:wrap-reverse!important}.gap-sm-0{gap:0!important}.gap-sm-1{gap:.25rem!important}.gap-sm-2{gap:.5rem!important}.gap-sm-3{gap:1rem!important}.gap-sm-4{gap:1.5rem!important}.gap-sm-5{gap:3rem!important}.justify-content-sm-start{justify-content:flex-start!important}.justify-content-sm-end{justify-content:flex-end!important}.justify-content-sm-center{justify-content:center!important}.justify-content-sm-between{justify-content:space-between!important}.justify-content-sm-around{justify-content:space-around!important}.justify-content-sm-evenly{justify-content:space-evenly!important}.align-items-sm-start{align-items:flex-start!important}.align-items-sm-end{align-items:flex-end!important}.align-items-sm-center{align-items:center!important}.align-items-sm-baseline{align-items:baseline!important}.align-items-sm-stretch{align-items:stretch!important}.align-content-sm-start{align-content:flex-start!important}.align-content-sm-end{align-content:flex-end!important}.align-content-sm-center{align-content:center!important}.align-content-sm-between{align-content:space-between!important}.align-content-sm-around{align-content:space-around!important}.align-content-sm-stretch{align-content:stretch!important}.align-self-sm-auto{align-self:auto!important}.align-self-sm-start{align-self:flex-start!important}.align-self-sm-end{align-self:flex-end!important}.align-self-sm-center{align-self:center!important}.align-self-sm-baseline{align-self:baseline!important}.align-self-sm-stretch{align-self:stretch!important}.order-sm-first{order:-1!important}.order-sm-0{order:0!important}.order-sm-1{order:1!important}.order-sm-2{order:2!important}.order-sm-3{order:3!important}.order-sm-4{order:4!important}.order-sm-5{order:5!important}.order-sm-last{order:6!important}.m-sm-0{margin:0!important}.m-sm-1{margin:.25rem!important}.m-sm-2{margin:.5rem!important}.m-sm-3{margin:1rem!important}.m-sm-4{margin:1.5rem!important}.m-sm-5{margin:3rem!important}.m-sm-auto{margin:auto!important}.mx-sm-0{margin-right:0!important;margin-left:0!important}.mx-sm-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-sm-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-sm-3{margin-right:1rem!important;margin-left:1rem!important}.mx-sm-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-sm-5{margin-right:3rem!important;margin-left:3rem!important}.mx-sm-auto{margin-right:auto!important;margin-left:auto!important}.my-sm-0{margin-top:0!important;margin-bottom:0!important}.my-sm-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-sm-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-sm-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-sm-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-sm-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-sm-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-sm-0{margin-top:0!important}.mt-sm-1{margin-top:.25rem!important}.mt-sm-2{margin-top:.5rem!important}.mt-sm-3{margin-top:1rem!important}.mt-sm-4{margin-top:1.5rem!important}.mt-sm-5{margin-top:3rem!important}.mt-sm-auto{margin-top:auto!important}.me-sm-0{margin-right:0!important}.me-sm-1{margin-right:.25rem!important}.me-sm-2{margin-right:.5rem!important}.me-sm-3{margin-right:1rem!important}.me-sm-4{margin-right:1.5rem!important}.me-sm-5{margin-right:3rem!important}.me-sm-auto{margin-right:auto!important}.mb-sm-0{margin-bottom:0!important}.mb-sm-1{margin-bottom:.25rem!important}.mb-sm-2{margin-bottom:.5rem!important}.mb-sm-3{margin-bottom:1rem!important}.mb-sm-4{margin-bottom:1.5rem!important}.mb-sm-5{margin-bottom:3rem!important}.mb-sm-auto{margin-bottom:auto!important}.ms-sm-0{margin-left:0!important}.ms-sm-1{margin-left:.25rem!important}.ms-sm-2{margin-left:.5rem!important}.ms-sm-3{margin-left:1rem!important}.ms-sm-4{margin-left:1.5rem!important}.ms-sm-5{margin-left:3rem!important}.ms-sm-auto{margin-left:auto!important}.p-sm-0{padding:0!important}.p-sm-1{padding:.25rem!important}.p-sm-2{padding:.5rem!important}.p-sm-3{padding:1rem!important}.p-sm-4{padding:1.5rem!important}.p-sm-5{padding:3rem!important}.px-sm-0{padding-right:0!important;padding-left:0!important}.px-sm-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-sm-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-sm-3{padding-right:1rem!important;padding-left:1rem!important}.px-sm-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-sm-5{padding-right:3rem!important;padding-left:3rem!important}.py-sm-0{padding-top:0!important;padding-bottom:0!important}.py-sm-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-sm-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-sm-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-sm-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-sm-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-sm-0{padding-top:0!important}.pt-sm-1{padding-top:.25rem!important}.pt-sm-2{padding-top:.5rem!important}.pt-sm-3{padding-top:1rem!important}.pt-sm-4{padding-top:1.5rem!important}.pt-sm-5{padding-top:3rem!important}.pe-sm-0{padding-right:0!important}.pe-sm-1{padding-right:.25rem!important}.pe-sm-2{padding-right:.5rem!important}.pe-sm-3{padding-right:1rem!important}.pe-sm-4{padding-right:1.5rem!important}.pe-sm-5{padding-right:3rem!important}.pb-sm-0{padding-bottom:0!important}.pb-sm-1{padding-bottom:.25rem!important}.pb-sm-2{padding-bottom:.5rem!important}.pb-sm-3{padding-bottom:1rem!important}.pb-sm-4{padding-bottom:1.5rem!important}.pb-sm-5{padding-bottom:3rem!important}.ps-sm-0{padding-left:0!important}.ps-sm-1{padding-left:.25rem!important}.ps-sm-2{padding-left:.5rem!important}.ps-sm-3{padding-left:1rem!important}.ps-sm-4{padding-left:1.5rem!important}.ps-sm-5{padding-left:3rem!important}.text-sm-start{text-align:left!important}.text-sm-end{text-align:right!important}.text-sm-center{text-align:center!important}}@media (min-width:768px){.float-md-start{float:left!important}.float-md-end{float:right!important}.float-md-none{float:none!important}.d-md-inline{display:inline!important}.d-md-inline-block{display:inline-block!important}.d-md-block{display:block!important}.d-md-grid{display:grid!important}.d-md-table{display:table!important}.d-md-table-row{display:table-row!important}.d-md-table-cell{display:table-cell!important}.d-md-flex{display:flex!important}.d-md-inline-flex{display:inline-flex!important}.d-md-none{display:none!important}.flex-md-fill{flex:1 1 auto!important}.flex-md-row{flex-direction:row!important}.flex-md-column{flex-direction:column!important}.flex-md-row-reverse{flex-direction:row-reverse!important}.flex-md-column-reverse{flex-direction:column-reverse!important}.flex-md-grow-0{flex-grow:0!important}.flex-md-grow-1{flex-grow:1!important}.flex-md-shrink-0{flex-shrink:0!important}.flex-md-shrink-1{flex-shrink:1!important}.flex-md-wrap{flex-wrap:wrap!important}.flex-md-nowrap{flex-wrap:nowrap!important}.flex-md-wrap-reverse{flex-wrap:wrap-reverse!important}.gap-md-0{gap:0!important}.gap-md-1{gap:.25rem!important}.gap-md-2{gap:.5rem!important}.gap-md-3{gap:1rem!important}.gap-md-4{gap:1.5rem!important}.gap-md-5{gap:3rem!important}.justify-content-md-start{justify-content:flex-start!important}.justify-content-md-end{justify-content:flex-end!important}.justify-content-md-center{justify-content:center!important}.justify-content-md-between{justify-content:space-between!important}.justify-content-md-around{justify-content:space-around!important}.justify-content-md-evenly{justify-content:space-evenly!important}.align-items-md-start{align-items:flex-start!important}.align-items-md-end{align-items:flex-end!important}.align-items-md-center{align-items:center!important}.align-items-md-baseline{align-items:baseline!important}.align-items-md-stretch{align-items:stretch!important}.align-content-md-start{align-content:flex-start!important}.align-content-md-end{align-content:flex-end!important}.align-content-md-center{align-content:center!important}.align-content-md-between{align-content:space-between!important}.align-content-md-around{align-content:space-around!important}.align-content-md-stretch{align-content:stretch!important}.align-self-md-auto{align-self:auto!important}.align-self-md-start{align-self:flex-start!important}.align-self-md-end{align-self:flex-end!important}.align-self-md-center{align-self:center!important}.align-self-md-baseline{align-self:baseline!important}.align-self-md-stretch{align-self:stretch!important}.order-md-first{order:-1!important}.order-md-0{order:0!important}.order-md-1{order:1!important}.order-md-2{order:2!important}.order-md-3{order:3!important}.order-md-4{order:4!important}.order-md-5{order:5!important}.order-md-last{order:6!important}.m-md-0{margin:0!important}.m-md-1{margin:.25rem!important}.m-md-2{margin:.5rem!important}.m-md-3{margin:1rem!important}.m-md-4{margin:1.5rem!important}.m-md-5{margin:3rem!important}.m-md-auto{margin:auto!important}.mx-md-0{margin-right:0!important;margin-left:0!important}.mx-md-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-md-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-md-3{margin-right:1rem!important;margin-left:1rem!important}.mx-md-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-md-5{margin-right:3rem!important;margin-left:3rem!important}.mx-md-auto{margin-right:auto!important;margin-left:auto!important}.my-md-0{margin-top:0!important;margin-bottom:0!important}.my-md-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-md-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-md-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-md-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-md-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-md-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-md-0{margin-top:0!important}.mt-md-1{margin-top:.25rem!important}.mt-md-2{margin-top:.5rem!important}.mt-md-3{margin-top:1rem!important}.mt-md-4{margin-top:1.5rem!important}.mt-md-5{margin-top:3rem!important}.mt-md-auto{margin-top:auto!important}.me-md-0{margin-right:0!important}.me-md-1{margin-right:.25rem!important}.me-md-2{margin-right:.5rem!important}.me-md-3{margin-right:1rem!important}.me-md-4{margin-right:1.5rem!important}.me-md-5{margin-right:3rem!important}.me-md-auto{margin-right:auto!important}.mb-md-0{margin-bottom:0!important}.mb-md-1{margin-bottom:.25rem!important}.mb-md-2{margin-bottom:.5rem!important}.mb-md-3{margin-bottom:1rem!important}.mb-md-4{margin-bottom:1.5rem!important}.mb-md-5{margin-bottom:3rem!important}.mb-md-auto{margin-bottom:auto!important}.ms-md-0{margin-left:0!important}.ms-md-1{margin-left:.25rem!important}.ms-md-2{margin-left:.5rem!important}.ms-md-3{margin-left:1rem!important}.ms-md-4{margin-left:1.5rem!important}.ms-md-5{margin-left:3rem!important}.ms-md-auto{margin-left:auto!important}.p-md-0{padding:0!important}.p-md-1{padding:.25rem!important}.p-md-2{padding:.5rem!important}.p-md-3{padding:1rem!important}.p-md-4{padding:1.5rem!important}.p-md-5{padding:3rem!important}.px-md-0{padding-right:0!important;padding-left:0!important}.px-md-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-md-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-md-3{padding-right:1rem!important;padding-left:1rem!important}.px-md-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-md-5{padding-right:3rem!important;padding-left:3rem!important}.py-md-0{padding-top:0!important;padding-bottom:0!important}.py-md-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-md-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-md-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-md-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-md-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-md-0{padding-top:0!important}.pt-md-1{padding-top:.25rem!important}.pt-md-2{padding-top:.5rem!important}.pt-md-3{padding-top:1rem!important}.pt-md-4{padding-top:1.5rem!important}.pt-md-5{padding-top:3rem!important}.pe-md-0{padding-right:0!important}.pe-md-1{padding-right:.25rem!important}.pe-md-2{padding-right:.5rem!important}.pe-md-3{padding-right:1rem!important}.pe-md-4{padding-right:1.5rem!important}.pe-md-5{padding-right:3rem!important}.pb-md-0{padding-bottom:0!important}.pb-md-1{padding-bottom:.25rem!important}.pb-md-2{padding-bottom:.5rem!important}.pb-md-3{padding-bottom:1rem!important}.pb-md-4{padding-bottom:1.5rem!important}.pb-md-5{padding-bottom:3rem!important}.ps-md-0{padding-left:0!important}.ps-md-1{padding-left:.25rem!important}.ps-md-2{padding-left:.5rem!important}.ps-md-3{padding-left:1rem!important}.ps-md-4{padding-left:1.5rem!important}.ps-md-5{padding-left:3rem!important}.text-md-start{text-align:left!important}.text-md-end{text-align:right!important}.text-md-center{text-align:center!important}}@media (min-width:992px){.float-lg-start{float:left!important}.float-lg-end{float:right!important}.float-lg-none{float:none!important}.d-lg-inline{display:inline!important}.d-lg-inline-block{display:inline-block!important}.d-lg-block{display:block!important}.d-lg-grid{display:grid!important}.d-lg-table{display:table!important}.d-lg-table-row{display:table-row!important}.d-lg-table-cell{display:table-cell!important}.d-lg-flex{display:flex!important}.d-lg-inline-flex{display:inline-flex!important}.d-lg-none{display:none!important}.flex-lg-fill{flex:1 1 auto!important}.flex-lg-row{flex-direction:row!important}.flex-lg-column{flex-direction:column!important}.flex-lg-row-reverse{flex-direction:row-reverse!important}.flex-lg-column-reverse{flex-direction:column-reverse!important}.flex-lg-grow-0{flex-grow:0!important}.flex-lg-grow-1{flex-grow:1!important}.flex-lg-shrink-0{flex-shrink:0!important}.flex-lg-shrink-1{flex-shrink:1!important}.flex-lg-wrap{flex-wrap:wrap!important}.flex-lg-nowrap{flex-wrap:nowrap!important}.flex-lg-wrap-reverse{flex-wrap:wrap-reverse!important}.gap-lg-0{gap:0!important}.gap-lg-1{gap:.25rem!important}.gap-lg-2{gap:.5rem!important}.gap-lg-3{gap:1rem!important}.gap-lg-4{gap:1.5rem!important}.gap-lg-5{gap:3rem!important}.justify-content-lg-start{justify-content:flex-start!important}.justify-content-lg-end{justify-content:flex-end!important}.justify-content-lg-center{justify-content:center!important}.justify-content-lg-between{justify-content:space-between!important}.justify-content-lg-around{justify-content:space-around!important}.justify-content-lg-evenly{justify-content:space-evenly!important}.align-items-lg-start{align-items:flex-start!important}.align-items-lg-end{align-items:flex-end!important}.align-items-lg-center{align-items:center!important}.align-items-lg-baseline{align-items:baseline!important}.align-items-lg-stretch{align-items:stretch!important}.align-content-lg-start{align-content:flex-start!important}.align-content-lg-end{align-content:flex-end!important}.align-content-lg-center{align-content:center!important}.align-content-lg-between{align-content:space-between!important}.align-content-lg-around{align-content:space-around!important}.align-content-lg-stretch{align-content:stretch!important}.align-self-lg-auto{align-self:auto!important}.align-self-lg-start{align-self:flex-start!important}.align-self-lg-end{align-self:flex-end!important}.align-self-lg-center{align-self:center!important}.align-self-lg-baseline{align-self:baseline!important}.align-self-lg-stretch{align-self:stretch!important}.order-lg-first{order:-1!important}.order-lg-0{order:0!important}.order-lg-1{order:1!important}.order-lg-2{order:2!important}.order-lg-3{order:3!important}.order-lg-4{order:4!important}.order-lg-5{order:5!important}.order-lg-last{order:6!important}.m-lg-0{margin:0!important}.m-lg-1{margin:.25rem!important}.m-lg-2{margin:.5rem!important}.m-lg-3{margin:1rem!important}.m-lg-4{margin:1.5rem!important}.m-lg-5{margin:3rem!important}.m-lg-auto{margin:auto!important}.mx-lg-0{margin-right:0!important;margin-left:0!important}.mx-lg-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-lg-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-lg-3{margin-right:1rem!important;margin-left:1rem!important}.mx-lg-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-lg-5{margin-right:3rem!important;margin-left:3rem!important}.mx-lg-auto{margin-right:auto!important;margin-left:auto!important}.my-lg-0{margin-top:0!important;margin-bottom:0!important}.my-lg-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-lg-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-lg-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-lg-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-lg-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-lg-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-lg-0{margin-top:0!important}.mt-lg-1{margin-top:.25rem!important}.mt-lg-2{margin-top:.5rem!important}.mt-lg-3{margin-top:1rem!important}.mt-lg-4{margin-top:1.5rem!important}.mt-lg-5{margin-top:3rem!important}.mt-lg-auto{margin-top:auto!important}.me-lg-0{margin-right:0!important}.me-lg-1{margin-right:.25rem!important}.me-lg-2{margin-right:.5rem!important}.me-lg-3{margin-right:1rem!important}.me-lg-4{margin-right:1.5rem!important}.me-lg-5{margin-right:3rem!important}.me-lg-auto{margin-right:auto!important}.mb-lg-0{margin-bottom:0!important}.mb-lg-1{margin-bottom:.25rem!important}.mb-lg-2{margin-bottom:.5rem!important}.mb-lg-3{margin-bottom:1rem!important}.mb-lg-4{margin-bottom:1.5rem!important}.mb-lg-5{margin-bottom:3rem!important}.mb-lg-auto{margin-bottom:auto!important}.ms-lg-0{margin-left:0!important}.ms-lg-1{margin-left:.25rem!important}.ms-lg-2{margin-left:.5rem!important}.ms-lg-3{margin-left:1rem!important}.ms-lg-4{margin-left:1.5rem!important}.ms-lg-5{margin-left:3rem!important}.ms-lg-auto{margin-left:auto!important}.p-lg-0{padding:0!important}.p-lg-1{padding:.25rem!important}.p-lg-2{padding:.5rem!important}.p-lg-3{padding:1rem!important}.p-lg-4{padding:1.5rem!important}.p-lg-5{padding:3rem!important}.px-lg-0{padding-right:0!important;padding-left:0!important}.px-lg-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-lg-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-lg-3{padding-right:1rem!important;padding-left:1rem!important}.px-lg-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-lg-5{padding-right:3rem!important;padding-left:3rem!important}.py-lg-0{padding-top:0!important;padding-bottom:0!important}.py-lg-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-lg-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-lg-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-lg-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-lg-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-lg-0{padding-top:0!important}.pt-lg-1{padding-top:.25rem!important}.pt-lg-2{padding-top:.5rem!important}.pt-lg-3{padding-top:1rem!important}.pt-lg-4{padding-top:1.5rem!important}.pt-lg-5{padding-top:3rem!important}.pe-lg-0{padding-right:0!important}.pe-lg-1{padding-right:.25rem!important}.pe-lg-2{padding-right:.5rem!important}.pe-lg-3{padding-right:1rem!important}.pe-lg-4{padding-right:1.5rem!important}.pe-lg-5{padding-right:3rem!important}.pb-lg-0{padding-bottom:0!important}.pb-lg-1{padding-bottom:.25rem!important}.pb-lg-2{padding-bottom:.5rem!important}.pb-lg-3{padding-bottom:1rem!important}.pb-lg-4{padding-bottom:1.5rem!important}.pb-lg-5{padding-bottom:3rem!important}.ps-lg-0{padding-left:0!important}.ps-lg-1{padding-left:.25rem!important}.ps-lg-2{padding-left:.5rem!important}.ps-lg-3{padding-left:1rem!important}.ps-lg-4{padding-left:1.5rem!important}.ps-lg-5{padding-left:3rem!important}.text-lg-start{text-align:left!important}.text-lg-end{text-align:right!important}.text-lg-center{text-align:center!important}}@media (min-width:1200px){.float-xl-start{float:left!important}.float-xl-end{float:right!important}.float-xl-none{float:none!important}.d-xl-inline{display:inline!important}.d-xl-inline-block{display:inline-block!important}.d-xl-block{display:block!important}.d-xl-grid{display:grid!important}.d-xl-table{display:table!important}.d-xl-table-row{display:table-row!important}.d-xl-table-cell{display:table-cell!important}.d-xl-flex{display:flex!important}.d-xl-inline-flex{display:inline-flex!important}.d-xl-none{display:none!important}.flex-xl-fill{flex:1 1 auto!important}.flex-xl-row{flex-direction:row!important}.flex-xl-column{flex-direction:column!important}.flex-xl-row-reverse{flex-direction:row-reverse!important}.flex-xl-column-reverse{flex-direction:column-reverse!important}.flex-xl-grow-0{flex-grow:0!important}.flex-xl-grow-1{flex-grow:1!important}.flex-xl-shrink-0{flex-shrink:0!important}.flex-xl-shrink-1{flex-shrink:1!important}.flex-xl-wrap{flex-wrap:wrap!important}.flex-xl-nowrap{flex-wrap:nowrap!important}.flex-xl-wrap-reverse{flex-wrap:wrap-reverse!important}.gap-xl-0{gap:0!important}.gap-xl-1{gap:.25rem!important}.gap-xl-2{gap:.5rem!important}.gap-xl-3{gap:1rem!important}.gap-xl-4{gap:1.5rem!important}.gap-xl-5{gap:3rem!important}.justify-content-xl-start{justify-content:flex-start!important}.justify-content-xl-end{justify-content:flex-end!important}.justify-content-xl-center{justify-content:center!important}.justify-content-xl-between{justify-content:space-between!important}.justify-content-xl-around{justify-content:space-around!important}.justify-content-xl-evenly{justify-content:space-evenly!important}.align-items-xl-start{align-items:flex-start!important}.align-items-xl-end{align-items:flex-end!important}.align-items-xl-center{align-items:center!important}.align-items-xl-baseline{align-items:baseline!important}.align-items-xl-stretch{align-items:stretch!important}.align-content-xl-start{align-content:flex-start!important}.align-content-xl-end{align-content:flex-end!important}.align-content-xl-center{align-content:center!important}.align-content-xl-between{align-content:space-between!important}.align-content-xl-around{align-content:space-around!important}.align-content-xl-stretch{align-content:stretch!important}.align-self-xl-auto{align-self:auto!important}.align-self-xl-start{align-self:flex-start!important}.align-self-xl-end{align-self:flex-end!important}.align-self-xl-center{align-self:center!important}.align-self-xl-baseline{align-self:baseline!important}.align-self-xl-stretch{align-self:stretch!important}.order-xl-first{order:-1!important}.order-xl-0{order:0!important}.order-xl-1{order:1!important}.order-xl-2{order:2!important}.order-xl-3{order:3!important}.order-xl-4{order:4!important}.order-xl-5{order:5!important}.order-xl-last{order:6!important}.m-xl-0{margin:0!important}.m-xl-1{margin:.25rem!important}.m-xl-2{margin:.5rem!important}.m-xl-3{margin:1rem!important}.m-xl-4{margin:1.5rem!important}.m-xl-5{margin:3rem!important}.m-xl-auto{margin:auto!important}.mx-xl-0{margin-right:0!important;margin-left:0!important}.mx-xl-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-xl-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-xl-3{margin-right:1rem!important;margin-left:1rem!important}.mx-xl-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-xl-5{margin-right:3rem!important;margin-left:3rem!important}.mx-xl-auto{margin-right:auto!important;margin-left:auto!important}.my-xl-0{margin-top:0!important;margin-bottom:0!important}.my-xl-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-xl-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-xl-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-xl-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-xl-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-xl-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-xl-0{margin-top:0!important}.mt-xl-1{margin-top:.25rem!important}.mt-xl-2{margin-top:.5rem!important}.mt-xl-3{margin-top:1rem!important}.mt-xl-4{margin-top:1.5rem!important}.mt-xl-5{margin-top:3rem!important}.mt-xl-auto{margin-top:auto!important}.me-xl-0{margin-right:0!important}.me-xl-1{margin-right:.25rem!important}.me-xl-2{margin-right:.5rem!important}.me-xl-3{margin-right:1rem!important}.me-xl-4{margin-right:1.5rem!important}.me-xl-5{margin-right:3rem!important}.me-xl-auto{margin-right:auto!important}.mb-xl-0{margin-bottom:0!important}.mb-xl-1{margin-bottom:.25rem!important}.mb-xl-2{margin-bottom:.5rem!important}.mb-xl-3{margin-bottom:1rem!important}.mb-xl-4{margin-bottom:1.5rem!important}.mb-xl-5{margin-bottom:3rem!important}.mb-xl-auto{margin-bottom:auto!important}.ms-xl-0{margin-left:0!important}.ms-xl-1{margin-left:.25rem!important}.ms-xl-2{margin-left:.5rem!important}.ms-xl-3{margin-left:1rem!important}.ms-xl-4{margin-left:1.5rem!important}.ms-xl-5{margin-left:3rem!important}.ms-xl-auto{margin-left:auto!important}.p-xl-0{padding:0!important}.p-xl-1{padding:.25rem!important}.p-xl-2{padding:.5rem!important}.p-xl-3{padding:1rem!important}.p-xl-4{padding:1.5rem!important}.p-xl-5{padding:3rem!important}.px-xl-0{padding-right:0!important;padding-left:0!important}.px-xl-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-xl-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-xl-3{padding-right:1rem!important;padding-left:1rem!important}.px-xl-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-xl-5{padding-right:3rem!important;padding-left:3rem!important}.py-xl-0{padding-top:0!important;padding-bottom:0!important}.py-xl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-xl-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-xl-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-xl-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-xl-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-xl-0{padding-top:0!important}.pt-xl-1{padding-top:.25rem!important}.pt-xl-2{padding-top:.5rem!important}.pt-xl-3{padding-top:1rem!important}.pt-xl-4{padding-top:1.5rem!important}.pt-xl-5{padding-top:3rem!important}.pe-xl-0{padding-right:0!important}.pe-xl-1{padding-right:.25rem!important}.pe-xl-2{padding-right:.5rem!important}.pe-xl-3{padding-right:1rem!important}.pe-xl-4{padding-right:1.5rem!important}.pe-xl-5{padding-right:3rem!important}.pb-xl-0{padding-bottom:0!important}.pb-xl-1{padding-bottom:.25rem!important}.pb-xl-2{padding-bottom:.5rem!important}.pb-xl-3{padding-bottom:1rem!important}.pb-xl-4{padding-bottom:1.5rem!important}.pb-xl-5{padding-bottom:3rem!important}.ps-xl-0{padding-left:0!important}.ps-xl-1{padding-left:.25rem!important}.ps-xl-2{padding-left:.5rem!important}.ps-xl-3{padding-left:1rem!important}.ps-xl-4{padding-left:1.5rem!important}.ps-xl-5{padding-left:3rem!important}.text-xl-start{text-align:left!important}.text-xl-end{text-align:right!important}.text-xl-center{text-align:center!important}}@media (min-width:1400px){.float-xxl-start{float:left!important}.float-xxl-end{float:right!important}.float-xxl-none{float:none!important}.d-xxl-inline{display:inline!important}.d-xxl-inline-block{display:inline-block!important}.d-xxl-block{display:block!important}.d-xxl-grid{display:grid!important}.d-xxl-table{display:table!important}.d-xxl-table-row{display:table-row!important}.d-xxl-table-cell{display:table-cell!important}.d-xxl-flex{display:flex!important}.d-xxl-inline-flex{display:inline-flex!important}.d-xxl-none{display:none!important}.flex-xxl-fill{flex:1 1 auto!important}.flex-xxl-row{flex-direction:row!important}.flex-xxl-column{flex-direction:column!important}.flex-xxl-row-reverse{flex-direction:row-reverse!important}.flex-xxl-column-reverse{flex-direction:column-reverse!important}.flex-xxl-grow-0{flex-grow:0!important}.flex-xxl-grow-1{flex-grow:1!important}.flex-xxl-shrink-0{flex-shrink:0!important}.flex-xxl-shrink-1{flex-shrink:1!important}.flex-xxl-wrap{flex-wrap:wrap!important}.flex-xxl-nowrap{flex-wrap:nowrap!important}.flex-xxl-wrap-reverse{flex-wrap:wrap-reverse!important}.gap-xxl-0{gap:0!important}.gap-xxl-1{gap:.25rem!important}.gap-xxl-2{gap:.5rem!important}.gap-xxl-3{gap:1rem!important}.gap-xxl-4{gap:1.5rem!important}.gap-xxl-5{gap:3rem!important}.justify-content-xxl-start{justify-content:flex-start!important}.justify-content-xxl-end{justify-content:flex-end!important}.justify-content-xxl-center{justify-content:center!important}.justify-content-xxl-between{justify-content:space-between!important}.justify-content-xxl-around{justify-content:space-around!important}.justify-content-xxl-evenly{justify-content:space-evenly!important}.align-items-xxl-start{align-items:flex-start!important}.align-items-xxl-end{align-items:flex-end!important}.align-items-xxl-center{align-items:center!important}.align-items-xxl-baseline{align-items:baseline!important}.align-items-xxl-stretch{align-items:stretch!important}.align-content-xxl-start{align-content:flex-start!important}.align-content-xxl-end{align-content:flex-end!important}.align-content-xxl-center{align-content:center!important}.align-content-xxl-between{align-content:space-between!important}.align-content-xxl-around{align-content:space-around!important}.align-content-xxl-stretch{align-content:stretch!important}.align-self-xxl-auto{align-self:auto!important}.align-self-xxl-start{align-self:flex-start!important}.align-self-xxl-end{align-self:flex-end!important}.align-self-xxl-center{align-self:center!important}.align-self-xxl-baseline{align-self:baseline!important}.align-self-xxl-stretch{align-self:stretch!important}.order-xxl-first{order:-1!important}.order-xxl-0{order:0!important}.order-xxl-1{order:1!important}.order-xxl-2{order:2!important}.order-xxl-3{order:3!important}.order-xxl-4{order:4!important}.order-xxl-5{order:5!important}.order-xxl-last{order:6!important}.m-xxl-0{margin:0!important}.m-xxl-1{margin:.25rem!important}.m-xxl-2{margin:.5rem!important}.m-xxl-3{margin:1rem!important}.m-xxl-4{margin:1.5rem!important}.m-xxl-5{margin:3rem!important}.m-xxl-auto{margin:auto!important}.mx-xxl-0{margin-right:0!important;margin-left:0!important}.mx-xxl-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-xxl-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-xxl-3{margin-right:1rem!important;margin-left:1rem!important}.mx-xxl-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-xxl-5{margin-right:3rem!important;margin-left:3rem!important}.mx-xxl-auto{margin-right:auto!important;margin-left:auto!important}.my-xxl-0{margin-top:0!important;margin-bottom:0!important}.my-xxl-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-xxl-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-xxl-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-xxl-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-xxl-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-xxl-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-xxl-0{margin-top:0!important}.mt-xxl-1{margin-top:.25rem!important}.mt-xxl-2{margin-top:.5rem!important}.mt-xxl-3{margin-top:1rem!important}.mt-xxl-4{margin-top:1.5rem!important}.mt-xxl-5{margin-top:3rem!important}.mt-xxl-auto{margin-top:auto!important}.me-xxl-0{margin-right:0!important}.me-xxl-1{margin-right:.25rem!important}.me-xxl-2{margin-right:.5rem!important}.me-xxl-3{margin-right:1rem!important}.me-xxl-4{margin-right:1.5rem!important}.me-xxl-5{margin-right:3rem!important}.me-xxl-auto{margin-right:auto!important}.mb-xxl-0{margin-bottom:0!important}.mb-xxl-1{margin-bottom:.25rem!important}.mb-xxl-2{margin-bottom:.5rem!important}.mb-xxl-3{margin-bottom:1rem!important}.mb-xxl-4{margin-bottom:1.5rem!important}.mb-xxl-5{margin-bottom:3rem!important}.mb-xxl-auto{margin-bottom:auto!important}.ms-xxl-0{margin-left:0!important}.ms-xxl-1{margin-left:.25rem!important}.ms-xxl-2{margin-left:.5rem!important}.ms-xxl-3{margin-left:1rem!important}.ms-xxl-4{margin-left:1.5rem!important}.ms-xxl-5{margin-left:3rem!important}.ms-xxl-auto{margin-left:auto!important}.p-xxl-0{padding:0!important}.p-xxl-1{padding:.25rem!important}.p-xxl-2{padding:.5rem!important}.p-xxl-3{padding:1rem!important}.p-xxl-4{padding:1.5rem!important}.p-xxl-5{padding:3rem!important}.px-xxl-0{padding-right:0!important;padding-left:0!important}.px-xxl-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-xxl-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-xxl-3{padding-right:1rem!important;padding-left:1rem!important}.px-xxl-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-xxl-5{padding-right:3rem!important;padding-left:3rem!important}.py-xxl-0{padding-top:0!important;padding-bottom:0!important}.py-xxl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-xxl-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-xxl-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-xxl-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-xxl-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-xxl-0{padding-top:0!important}.pt-xxl-1{padding-top:.25rem!important}.pt-xxl-2{padding-top:.5rem!important}.pt-xxl-3{padding-top:1rem!important}.pt-xxl-4{padding-top:1.5rem!important}.pt-xxl-5{padding-top:3rem!important}.pe-xxl-0{padding-right:0!important}.pe-xxl-1{padding-right:.25rem!important}.pe-xxl-2{padding-right:.5rem!important}.pe-xxl-3{padding-right:1rem!important}.pe-xxl-4{padding-right:1.5rem!important}.pe-xxl-5{padding-right:3rem!important}.pb-xxl-0{padding-bottom:0!important}.pb-xxl-1{padding-bottom:.25rem!important}.pb-xxl-2{padding-bottom:.5rem!important}.pb-xxl-3{padding-bottom:1rem!important}.pb-xxl-4{padding-bottom:1.5rem!important}.pb-xxl-5{padding-bottom:3rem!important}.ps-xxl-0{padding-left:0!important}.ps-xxl-1{padding-left:.25rem!important}.ps-xxl-2{padding-left:.5rem!important}.ps-xxl-3{padding-left:1rem!important}.ps-xxl-4{padding-left:1.5rem!important}.ps-xxl-5{padding-left:3rem!important}.text-xxl-start{text-align:left!important}.text-xxl-end{text-align:right!important}.text-xxl-center{text-align:center!important}}@media (min-width:1200px){.fs-1{font-size:2.5rem!important}.fs-2{font-size:2rem!important}.fs-3{font-size:1.75rem!important}.fs-4{font-size:1.5rem!important}}@media print{.d-print-inline{display:inline!important}.d-print-inline-block{display:inline-block!important}.d-print-block{display:block!important}.d-print-grid{display:grid!important}.d-print-table{display:table!important}.d-print-table-row{display:table-row!important}.d-print-table-cell{display:table-cell!important}.d-print-flex{display:flex!important}.d-print-inline-flex{display:inline-flex!important}.d-print-none{display:none!important}} + */:root{--bs-blue:#0d6efd;--bs-indigo:#6610f2;--bs-purple:#6f42c1;--bs-pink:#d63384;--bs-red:#dc3545;--bs-orange:#fd7e14;--bs-yellow:#ffc107;--bs-green:#198754;--bs-teal:#20c997;--bs-cyan:#0dcaf0;--bs-white:#fff;--bs-gray:#6c757d;--bs-gray-dark:#343a40;--bs-primary:#0d6efd;--bs-secondary:#6c757d;--bs-success:#198754;--bs-info:#0dcaf0;--bs-warning:#ffc107;--bs-danger:#dc3545;--bs-light:#f8f9fa;--bs-dark:#212529;--bs-font-sans-serif:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","Liberation Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--bs-font-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--bs-gradient:linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0))}*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:var(--bs-font-sans-serif);font-size:1rem;font-weight:400;line-height:1.5;color:#212529;background-color:#fff;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;background-color:currentColor;border:0;opacity:.25}hr:not([size]){height:1px}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2}.h1,h1{font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){.h1,h1{font-size:2.5rem}}.h2,h2{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){.h2,h2{font-size:2rem}}.h3,h3{font-size:calc(1.3rem + .6vw)}@media (min-width:1200px){.h3,h3{font-size:1.75rem}}.h4,h4{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){.h4,h4{font-size:1.5rem}}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[data-bs-original-title],abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}.small,small{font-size:.875em}.mark,mark{padding:.2em;background-color:#fcf8e3}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#0d6efd;text-decoration:underline}a:hover{color:#0a58ca}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:var(--bs-font-monospace);font-size:1em;direction:ltr;unicode-bidi:bidi-override}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:#d63384;word-wrap:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:.875em;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:1em;font-weight:700}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:#6c757d;text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]::-webkit-calendar-picker-indicator{display:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + .3vw);line-height:inherit}@media (min-width:1200px){legend{font-size:1.5rem}}legend+*{clear:left}::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-text,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:textfield}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::file-selector-button{font:inherit}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none!important}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:calc(1.625rem + 4.5vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-1{font-size:5rem}}.display-2{font-size:calc(1.575rem + 3.9vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-2{font-size:4.5rem}}.display-3{font-size:calc(1.525rem + 3.3vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-3{font-size:4rem}}.display-4{font-size:calc(1.475rem + 2.7vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-4{font-size:3.5rem}}.display-5{font-size:calc(1.425rem + 2.1vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-5{font-size:3rem}}.display-6{font-size:calc(1.375rem + 1.5vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-6{font-size:2.5rem}}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:.875em;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote>:last-child{margin-bottom:0}.blockquote-footer{margin-top:-1rem;margin-bottom:1rem;font-size:.875em;color:#6c757d}.blockquote-footer::before{content:"— "}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:#fff;border:1px solid #dee2e6;border-radius:.25rem;max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:.875em;color:#6c757d}.container,.container-fluid,.container-lg,.container-md,.container-sm,.container-xl,.container-xxl{width:100%;padding-right:var(--bs-gutter-x,.75rem);padding-left:var(--bs-gutter-x,.75rem);margin-right:auto;margin-left:auto}@media (min-width:576px){.container,.container-sm{max-width:540px}}@media (min-width:768px){.container,.container-md,.container-sm{max-width:720px}}@media (min-width:992px){.container,.container-lg,.container-md,.container-sm{max-width:960px}}@media (min-width:1200px){.container,.container-lg,.container-md,.container-sm,.container-xl{max-width:1140px}}@media (min-width:1400px){.container,.container-lg,.container-md,.container-sm,.container-xl,.container-xxl{max-width:1340px}}.row{--bs-gutter-x:1.5rem;--bs-gutter-y:0;display:flex;flex-wrap:wrap;margin-top:calc(var(--bs-gutter-y) * -1);margin-right:calc(var(--bs-gutter-x) * -.5);margin-left:calc(var(--bs-gutter-x) * -.5)}.row>*{flex-shrink:0;width:100%;max-width:100%;padding-right:calc(var(--bs-gutter-x) * .5);padding-left:calc(var(--bs-gutter-x) * .5);margin-top:var(--bs-gutter-y)}.col{flex:1 0 0%}.row-cols-auto>*{flex:0 0 auto;width:auto}.row-cols-1>*{flex:0 0 auto;width:100%}.row-cols-2>*{flex:0 0 auto;width:50%}.row-cols-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-4>*{flex:0 0 auto;width:25%}.row-cols-5>*{flex:0 0 auto;width:20%}.row-cols-6>*{flex:0 0 auto;width:16.6666666667%}@media (min-width:576px){.col-sm{flex:1 0 0%}.row-cols-sm-auto>*{flex:0 0 auto;width:auto}.row-cols-sm-1>*{flex:0 0 auto;width:100%}.row-cols-sm-2>*{flex:0 0 auto;width:50%}.row-cols-sm-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-sm-4>*{flex:0 0 auto;width:25%}.row-cols-sm-5>*{flex:0 0 auto;width:20%}.row-cols-sm-6>*{flex:0 0 auto;width:16.6666666667%}}@media (min-width:768px){.col-md{flex:1 0 0%}.row-cols-md-auto>*{flex:0 0 auto;width:auto}.row-cols-md-1>*{flex:0 0 auto;width:100%}.row-cols-md-2>*{flex:0 0 auto;width:50%}.row-cols-md-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-md-4>*{flex:0 0 auto;width:25%}.row-cols-md-5>*{flex:0 0 auto;width:20%}.row-cols-md-6>*{flex:0 0 auto;width:16.6666666667%}}@media (min-width:992px){.col-lg{flex:1 0 0%}.row-cols-lg-auto>*{flex:0 0 auto;width:auto}.row-cols-lg-1>*{flex:0 0 auto;width:100%}.row-cols-lg-2>*{flex:0 0 auto;width:50%}.row-cols-lg-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-lg-4>*{flex:0 0 auto;width:25%}.row-cols-lg-5>*{flex:0 0 auto;width:20%}.row-cols-lg-6>*{flex:0 0 auto;width:16.6666666667%}}@media (min-width:1200px){.col-xl{flex:1 0 0%}.row-cols-xl-auto>*{flex:0 0 auto;width:auto}.row-cols-xl-1>*{flex:0 0 auto;width:100%}.row-cols-xl-2>*{flex:0 0 auto;width:50%}.row-cols-xl-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-xl-4>*{flex:0 0 auto;width:25%}.row-cols-xl-5>*{flex:0 0 auto;width:20%}.row-cols-xl-6>*{flex:0 0 auto;width:16.6666666667%}}@media (min-width:1400px){.col-xxl{flex:1 0 0%}.row-cols-xxl-auto>*{flex:0 0 auto;width:auto}.row-cols-xxl-1>*{flex:0 0 auto;width:100%}.row-cols-xxl-2>*{flex:0 0 auto;width:50%}.row-cols-xxl-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-xxl-4>*{flex:0 0 auto;width:25%}.row-cols-xxl-5>*{flex:0 0 auto;width:20%}.row-cols-xxl-6>*{flex:0 0 auto;width:16.6666666667%}}.col-auto{flex:0 0 auto;width:auto}.col-1{flex:0 0 auto;width:8.33333333%}.col-2{flex:0 0 auto;width:16.66666667%}.col-3{flex:0 0 auto;width:25%}.col-4{flex:0 0 auto;width:33.33333333%}.col-5{flex:0 0 auto;width:41.66666667%}.col-6{flex:0 0 auto;width:50%}.col-7{flex:0 0 auto;width:58.33333333%}.col-8{flex:0 0 auto;width:66.66666667%}.col-9{flex:0 0 auto;width:75%}.col-10{flex:0 0 auto;width:83.33333333%}.col-11{flex:0 0 auto;width:91.66666667%}.col-12{flex:0 0 auto;width:100%}.offset-1{margin-left:8.33333333%}.offset-2{margin-left:16.66666667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.33333333%}.offset-5{margin-left:41.66666667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.33333333%}.offset-8{margin-left:66.66666667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.33333333%}.offset-11{margin-left:91.66666667%}.g-0,.gx-0{--bs-gutter-x:0}.g-0,.gy-0{--bs-gutter-y:0}.g-1,.gx-1{--bs-gutter-x:0.25rem}.g-1,.gy-1{--bs-gutter-y:0.25rem}.g-2,.gx-2{--bs-gutter-x:0.5rem}.g-2,.gy-2{--bs-gutter-y:0.5rem}.g-3,.gx-3{--bs-gutter-x:1rem}.g-3,.gy-3{--bs-gutter-y:1rem}.g-4,.gx-4{--bs-gutter-x:1.5rem}.g-4,.gy-4{--bs-gutter-y:1.5rem}.g-5,.gx-5{--bs-gutter-x:3rem}.g-5,.gy-5{--bs-gutter-y:3rem}@media (min-width:576px){.col-sm-auto{flex:0 0 auto;width:auto}.col-sm-1{flex:0 0 auto;width:8.33333333%}.col-sm-2{flex:0 0 auto;width:16.66666667%}.col-sm-3{flex:0 0 auto;width:25%}.col-sm-4{flex:0 0 auto;width:33.33333333%}.col-sm-5{flex:0 0 auto;width:41.66666667%}.col-sm-6{flex:0 0 auto;width:50%}.col-sm-7{flex:0 0 auto;width:58.33333333%}.col-sm-8{flex:0 0 auto;width:66.66666667%}.col-sm-9{flex:0 0 auto;width:75%}.col-sm-10{flex:0 0 auto;width:83.33333333%}.col-sm-11{flex:0 0 auto;width:91.66666667%}.col-sm-12{flex:0 0 auto;width:100%}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.33333333%}.offset-sm-2{margin-left:16.66666667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.33333333%}.offset-sm-5{margin-left:41.66666667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.33333333%}.offset-sm-8{margin-left:66.66666667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.33333333%}.offset-sm-11{margin-left:91.66666667%}.g-sm-0,.gx-sm-0{--bs-gutter-x:0}.g-sm-0,.gy-sm-0{--bs-gutter-y:0}.g-sm-1,.gx-sm-1{--bs-gutter-x:0.25rem}.g-sm-1,.gy-sm-1{--bs-gutter-y:0.25rem}.g-sm-2,.gx-sm-2{--bs-gutter-x:0.5rem}.g-sm-2,.gy-sm-2{--bs-gutter-y:0.5rem}.g-sm-3,.gx-sm-3{--bs-gutter-x:1rem}.g-sm-3,.gy-sm-3{--bs-gutter-y:1rem}.g-sm-4,.gx-sm-4{--bs-gutter-x:1.5rem}.g-sm-4,.gy-sm-4{--bs-gutter-y:1.5rem}.g-sm-5,.gx-sm-5{--bs-gutter-x:3rem}.g-sm-5,.gy-sm-5{--bs-gutter-y:3rem}}@media (min-width:768px){.col-md-auto{flex:0 0 auto;width:auto}.col-md-1{flex:0 0 auto;width:8.33333333%}.col-md-2{flex:0 0 auto;width:16.66666667%}.col-md-3{flex:0 0 auto;width:25%}.col-md-4{flex:0 0 auto;width:33.33333333%}.col-md-5{flex:0 0 auto;width:41.66666667%}.col-md-6{flex:0 0 auto;width:50%}.col-md-7{flex:0 0 auto;width:58.33333333%}.col-md-8{flex:0 0 auto;width:66.66666667%}.col-md-9{flex:0 0 auto;width:75%}.col-md-10{flex:0 0 auto;width:83.33333333%}.col-md-11{flex:0 0 auto;width:91.66666667%}.col-md-12{flex:0 0 auto;width:100%}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.33333333%}.offset-md-2{margin-left:16.66666667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.33333333%}.offset-md-5{margin-left:41.66666667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.33333333%}.offset-md-8{margin-left:66.66666667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.33333333%}.offset-md-11{margin-left:91.66666667%}.g-md-0,.gx-md-0{--bs-gutter-x:0}.g-md-0,.gy-md-0{--bs-gutter-y:0}.g-md-1,.gx-md-1{--bs-gutter-x:0.25rem}.g-md-1,.gy-md-1{--bs-gutter-y:0.25rem}.g-md-2,.gx-md-2{--bs-gutter-x:0.5rem}.g-md-2,.gy-md-2{--bs-gutter-y:0.5rem}.g-md-3,.gx-md-3{--bs-gutter-x:1rem}.g-md-3,.gy-md-3{--bs-gutter-y:1rem}.g-md-4,.gx-md-4{--bs-gutter-x:1.5rem}.g-md-4,.gy-md-4{--bs-gutter-y:1.5rem}.g-md-5,.gx-md-5{--bs-gutter-x:3rem}.g-md-5,.gy-md-5{--bs-gutter-y:3rem}}@media (min-width:992px){.col-lg-auto{flex:0 0 auto;width:auto}.col-lg-1{flex:0 0 auto;width:8.33333333%}.col-lg-2{flex:0 0 auto;width:16.66666667%}.col-lg-3{flex:0 0 auto;width:25%}.col-lg-4{flex:0 0 auto;width:33.33333333%}.col-lg-5{flex:0 0 auto;width:41.66666667%}.col-lg-6{flex:0 0 auto;width:50%}.col-lg-7{flex:0 0 auto;width:58.33333333%}.col-lg-8{flex:0 0 auto;width:66.66666667%}.col-lg-9{flex:0 0 auto;width:75%}.col-lg-10{flex:0 0 auto;width:83.33333333%}.col-lg-11{flex:0 0 auto;width:91.66666667%}.col-lg-12{flex:0 0 auto;width:100%}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.33333333%}.offset-lg-2{margin-left:16.66666667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.33333333%}.offset-lg-5{margin-left:41.66666667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.33333333%}.offset-lg-8{margin-left:66.66666667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.33333333%}.offset-lg-11{margin-left:91.66666667%}.g-lg-0,.gx-lg-0{--bs-gutter-x:0}.g-lg-0,.gy-lg-0{--bs-gutter-y:0}.g-lg-1,.gx-lg-1{--bs-gutter-x:0.25rem}.g-lg-1,.gy-lg-1{--bs-gutter-y:0.25rem}.g-lg-2,.gx-lg-2{--bs-gutter-x:0.5rem}.g-lg-2,.gy-lg-2{--bs-gutter-y:0.5rem}.g-lg-3,.gx-lg-3{--bs-gutter-x:1rem}.g-lg-3,.gy-lg-3{--bs-gutter-y:1rem}.g-lg-4,.gx-lg-4{--bs-gutter-x:1.5rem}.g-lg-4,.gy-lg-4{--bs-gutter-y:1.5rem}.g-lg-5,.gx-lg-5{--bs-gutter-x:3rem}.g-lg-5,.gy-lg-5{--bs-gutter-y:3rem}}@media (min-width:1200px){.col-xl-auto{flex:0 0 auto;width:auto}.col-xl-1{flex:0 0 auto;width:8.33333333%}.col-xl-2{flex:0 0 auto;width:16.66666667%}.col-xl-3{flex:0 0 auto;width:25%}.col-xl-4{flex:0 0 auto;width:33.33333333%}.col-xl-5{flex:0 0 auto;width:41.66666667%}.col-xl-6{flex:0 0 auto;width:50%}.col-xl-7{flex:0 0 auto;width:58.33333333%}.col-xl-8{flex:0 0 auto;width:66.66666667%}.col-xl-9{flex:0 0 auto;width:75%}.col-xl-10{flex:0 0 auto;width:83.33333333%}.col-xl-11{flex:0 0 auto;width:91.66666667%}.col-xl-12{flex:0 0 auto;width:100%}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.33333333%}.offset-xl-2{margin-left:16.66666667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.33333333%}.offset-xl-5{margin-left:41.66666667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.33333333%}.offset-xl-8{margin-left:66.66666667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.33333333%}.offset-xl-11{margin-left:91.66666667%}.g-xl-0,.gx-xl-0{--bs-gutter-x:0}.g-xl-0,.gy-xl-0{--bs-gutter-y:0}.g-xl-1,.gx-xl-1{--bs-gutter-x:0.25rem}.g-xl-1,.gy-xl-1{--bs-gutter-y:0.25rem}.g-xl-2,.gx-xl-2{--bs-gutter-x:0.5rem}.g-xl-2,.gy-xl-2{--bs-gutter-y:0.5rem}.g-xl-3,.gx-xl-3{--bs-gutter-x:1rem}.g-xl-3,.gy-xl-3{--bs-gutter-y:1rem}.g-xl-4,.gx-xl-4{--bs-gutter-x:1.5rem}.g-xl-4,.gy-xl-4{--bs-gutter-y:1.5rem}.g-xl-5,.gx-xl-5{--bs-gutter-x:3rem}.g-xl-5,.gy-xl-5{--bs-gutter-y:3rem}}@media (min-width:1400px){.col-xxl-auto{flex:0 0 auto;width:auto}.col-xxl-1{flex:0 0 auto;width:8.33333333%}.col-xxl-2{flex:0 0 auto;width:16.66666667%}.col-xxl-3{flex:0 0 auto;width:25%}.col-xxl-4{flex:0 0 auto;width:33.33333333%}.col-xxl-5{flex:0 0 auto;width:41.66666667%}.col-xxl-6{flex:0 0 auto;width:50%}.col-xxl-7{flex:0 0 auto;width:58.33333333%}.col-xxl-8{flex:0 0 auto;width:66.66666667%}.col-xxl-9{flex:0 0 auto;width:75%}.col-xxl-10{flex:0 0 auto;width:83.33333333%}.col-xxl-11{flex:0 0 auto;width:91.66666667%}.col-xxl-12{flex:0 0 auto;width:100%}.offset-xxl-0{margin-left:0}.offset-xxl-1{margin-left:8.33333333%}.offset-xxl-2{margin-left:16.66666667%}.offset-xxl-3{margin-left:25%}.offset-xxl-4{margin-left:33.33333333%}.offset-xxl-5{margin-left:41.66666667%}.offset-xxl-6{margin-left:50%}.offset-xxl-7{margin-left:58.33333333%}.offset-xxl-8{margin-left:66.66666667%}.offset-xxl-9{margin-left:75%}.offset-xxl-10{margin-left:83.33333333%}.offset-xxl-11{margin-left:91.66666667%}.g-xxl-0,.gx-xxl-0{--bs-gutter-x:0}.g-xxl-0,.gy-xxl-0{--bs-gutter-y:0}.g-xxl-1,.gx-xxl-1{--bs-gutter-x:0.25rem}.g-xxl-1,.gy-xxl-1{--bs-gutter-y:0.25rem}.g-xxl-2,.gx-xxl-2{--bs-gutter-x:0.5rem}.g-xxl-2,.gy-xxl-2{--bs-gutter-y:0.5rem}.g-xxl-3,.gx-xxl-3{--bs-gutter-x:1rem}.g-xxl-3,.gy-xxl-3{--bs-gutter-y:1rem}.g-xxl-4,.gx-xxl-4{--bs-gutter-x:1.5rem}.g-xxl-4,.gy-xxl-4{--bs-gutter-y:1.5rem}.g-xxl-5,.gx-xxl-5{--bs-gutter-x:3rem}.g-xxl-5,.gy-xxl-5{--bs-gutter-y:3rem}}.table{--bs-table-bg:transparent;--bs-table-accent-bg:transparent;--bs-table-striped-color:#212529;--bs-table-striped-bg:rgba(0, 0, 0, 0.05);--bs-table-active-color:#212529;--bs-table-active-bg:rgba(0, 0, 0, 0.1);--bs-table-hover-color:#212529;--bs-table-hover-bg:rgba(0, 0, 0, 0.075);width:100%;margin-bottom:1rem;color:#212529;vertical-align:top;border-color:#dee2e6}.table>:not(caption)>*>*{padding:.5rem .5rem;background-color:var(--bs-table-bg);border-bottom-width:1px;box-shadow:inset 0 0 0 9999px var(--bs-table-accent-bg)}.table>tbody{vertical-align:inherit}.table>thead{vertical-align:bottom}.table>:not(:last-child)>:last-child>*{border-bottom-color:currentColor}.caption-top{caption-side:top}.table-sm>:not(caption)>*>*{padding:.25rem .25rem}.table-bordered>:not(caption)>*{border-width:1px 0}.table-bordered>:not(caption)>*>*{border-width:0 1px}.table-borderless>:not(caption)>*>*{border-bottom-width:0}.table-striped>tbody>tr:nth-of-type(odd){--bs-table-accent-bg:var(--bs-table-striped-bg);color:var(--bs-table-striped-color)}.table-active{--bs-table-accent-bg:var(--bs-table-active-bg);color:var(--bs-table-active-color)}.table-hover>tbody>tr:hover{--bs-table-accent-bg:var(--bs-table-hover-bg);color:var(--bs-table-hover-color)}.table-primary{--bs-table-bg:#cfe2ff;--bs-table-striped-bg:#c5d7f2;--bs-table-striped-color:#000;--bs-table-active-bg:#bacbe6;--bs-table-active-color:#000;--bs-table-hover-bg:#bfd1ec;--bs-table-hover-color:#000;color:#000;border-color:#bacbe6}.table-secondary{--bs-table-bg:#e2e3e5;--bs-table-striped-bg:#d7d8da;--bs-table-striped-color:#000;--bs-table-active-bg:#cbccce;--bs-table-active-color:#000;--bs-table-hover-bg:#d1d2d4;--bs-table-hover-color:#000;color:#000;border-color:#cbccce}.table-success{--bs-table-bg:#d1e7dd;--bs-table-striped-bg:#c7dbd2;--bs-table-striped-color:#000;--bs-table-active-bg:#bcd0c7;--bs-table-active-color:#000;--bs-table-hover-bg:#c1d6cc;--bs-table-hover-color:#000;color:#000;border-color:#bcd0c7}.table-info{--bs-table-bg:#cff4fc;--bs-table-striped-bg:#c5e8ef;--bs-table-striped-color:#000;--bs-table-active-bg:#badce3;--bs-table-active-color:#000;--bs-table-hover-bg:#bfe2e9;--bs-table-hover-color:#000;color:#000;border-color:#badce3}.table-warning{--bs-table-bg:#fff3cd;--bs-table-striped-bg:#f2e7c3;--bs-table-striped-color:#000;--bs-table-active-bg:#e6dbb9;--bs-table-active-color:#000;--bs-table-hover-bg:#ece1be;--bs-table-hover-color:#000;color:#000;border-color:#e6dbb9}.table-danger{--bs-table-bg:#f8d7da;--bs-table-striped-bg:#eccccf;--bs-table-striped-color:#000;--bs-table-active-bg:#dfc2c4;--bs-table-active-color:#000;--bs-table-hover-bg:#e5c7ca;--bs-table-hover-color:#000;color:#000;border-color:#dfc2c4}.table-light{--bs-table-bg:#f8f9fa;--bs-table-striped-bg:#ecedee;--bs-table-striped-color:#000;--bs-table-active-bg:#dfe0e1;--bs-table-active-color:#000;--bs-table-hover-bg:#e5e6e7;--bs-table-hover-color:#000;color:#000;border-color:#dfe0e1}.table-dark{--bs-table-bg:#212529;--bs-table-striped-bg:#2c3034;--bs-table-striped-color:#fff;--bs-table-active-bg:#373b3e;--bs-table-active-color:#fff;--bs-table-hover-bg:#323539;--bs-table-hover-color:#fff;color:#fff;border-color:#373b3e}.table-responsive{overflow-x:auto;-webkit-overflow-scrolling:touch}@media (max-width:575.98px){.table-responsive-sm{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:767.98px){.table-responsive-md{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:991.98px){.table-responsive-lg{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:1199.98px){.table-responsive-xl{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:1399.98px){.table-responsive-xxl{overflow-x:auto;-webkit-overflow-scrolling:touch}}.form-label{margin-bottom:.5rem}.col-form-label{padding-top:calc(.375rem + 1px);padding-bottom:calc(.375rem + 1px);margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(.5rem + 1px);padding-bottom:calc(.5rem + 1px);font-size:1.25rem}.col-form-label-sm{padding-top:calc(.25rem + 1px);padding-bottom:calc(.25rem + 1px);font-size:.875rem}.form-text{margin-top:.25rem;font-size:.875em;color:#6c757d}.form-control{display:block;width:100%;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#212529;background-color:#fff;background-clip:padding-box;border:1px solid #ced4da;-webkit-appearance:none;-moz-appearance:none;appearance:none;border-radius:.25rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control{transition:none}}.form-control[type=file]{overflow:hidden}.form-control[type=file]:not(:disabled):not([readonly]){cursor:pointer}.form-control:focus{color:#212529;background-color:#fff;border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-control::-webkit-date-and-time-value{height:1.5em}.form-control::-moz-placeholder{color:#6c757d;opacity:1}.form-control::placeholder{color:#6c757d;opacity:1}.form-control:disabled,.form-control[readonly]{background-color:#e9ecef;opacity:1}.form-control::file-selector-button{padding:.375rem .75rem;margin:-.375rem -.75rem;-webkit-margin-end:.75rem;margin-inline-end:.75rem;color:#212529;background-color:#e9ecef;pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:1px;border-radius:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control::file-selector-button{transition:none}}.form-control:hover:not(:disabled):not([readonly])::file-selector-button{background-color:#dde0e3}.form-control::-webkit-file-upload-button{padding:.375rem .75rem;margin:-.375rem -.75rem;-webkit-margin-end:.75rem;margin-inline-end:.75rem;color:#212529;background-color:#e9ecef;pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:1px;border-radius:0;-webkit-transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control::-webkit-file-upload-button{-webkit-transition:none;transition:none}}.form-control:hover:not(:disabled):not([readonly])::-webkit-file-upload-button{background-color:#dde0e3}.form-control-plaintext{display:block;width:100%;padding:.375rem 0;margin-bottom:0;line-height:1.5;color:#212529;background-color:transparent;border:solid transparent;border-width:1px 0}.form-control-plaintext.form-control-lg,.form-control-plaintext.form-control-sm{padding-right:0;padding-left:0}.form-control-sm{min-height:calc(1.5em + (.5rem + 2px));padding:.25rem .5rem;font-size:.875rem;border-radius:.2rem}.form-control-sm::file-selector-button{padding:.25rem .5rem;margin:-.25rem -.5rem;-webkit-margin-end:.5rem;margin-inline-end:.5rem}.form-control-sm::-webkit-file-upload-button{padding:.25rem .5rem;margin:-.25rem -.5rem;-webkit-margin-end:.5rem;margin-inline-end:.5rem}.form-control-lg{min-height:calc(1.5em + (1rem + 2px));padding:.5rem 1rem;font-size:1.25rem;border-radius:.3rem}.form-control-lg::file-selector-button{padding:.5rem 1rem;margin:-.5rem -1rem;-webkit-margin-end:1rem;margin-inline-end:1rem}.form-control-lg::-webkit-file-upload-button{padding:.5rem 1rem;margin:-.5rem -1rem;-webkit-margin-end:1rem;margin-inline-end:1rem}textarea.form-control{min-height:calc(1.5em + (.75rem + 2px))}textarea.form-control-sm{min-height:calc(1.5em + (.5rem + 2px))}textarea.form-control-lg{min-height:calc(1.5em + (1rem + 2px))}.form-control-color{max-width:3rem;height:auto;padding:.375rem}.form-control-color:not(:disabled):not([readonly]){cursor:pointer}.form-control-color::-moz-color-swatch{height:1.5em;border-radius:.25rem}.form-control-color::-webkit-color-swatch{height:1.5em;border-radius:.25rem}.form-select{display:block;width:100%;padding:.375rem 2.25rem .375rem .75rem;-moz-padding-start:calc(0.75rem - 3px);font-size:1rem;font-weight:400;line-height:1.5;color:#212529;background-color:#fff;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right .75rem center;background-size:16px 12px;border:1px solid #ced4da;border-radius:.25rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out;-webkit-appearance:none;-moz-appearance:none;appearance:none}@media (prefers-reduced-motion:reduce){.form-select{transition:none}}.form-select:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-select[multiple],.form-select[size]:not([size="1"]){padding-right:.75rem;background-image:none}.form-select:disabled{background-color:#e9ecef}.form-select:-moz-focusring{color:transparent;text-shadow:0 0 0 #212529}.form-select-sm{padding-top:.25rem;padding-bottom:.25rem;padding-left:.5rem;font-size:.875rem}.form-select-lg{padding-top:.5rem;padding-bottom:.5rem;padding-left:1rem;font-size:1.25rem}.form-check{display:block;min-height:1.5rem;padding-left:1.5em;margin-bottom:.125rem}.form-check .form-check-input{float:left;margin-left:-1.5em}.form-check-input{width:1em;height:1em;margin-top:.25em;vertical-align:top;background-color:#fff;background-repeat:no-repeat;background-position:center;background-size:contain;border:1px solid rgba(0,0,0,.25);-webkit-appearance:none;-moz-appearance:none;appearance:none;-webkit-print-color-adjust:exact;color-adjust:exact}.form-check-input[type=checkbox]{border-radius:.25em}.form-check-input[type=radio]{border-radius:50%}.form-check-input:active{filter:brightness(90%)}.form-check-input:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-check-input:checked{background-color:#0d6efd;border-color:#0d6efd}.form-check-input:checked[type=checkbox]{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10l3 3l6-6'/%3e%3c/svg%3e")}.form-check-input:checked[type=radio]{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%23fff'/%3e%3c/svg%3e")}.form-check-input[type=checkbox]:indeterminate{background-color:#0d6efd;border-color:#0d6efd;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/%3e%3c/svg%3e")}.form-check-input:disabled{pointer-events:none;filter:none;opacity:.5}.form-check-input:disabled~.form-check-label,.form-check-input[disabled]~.form-check-label{opacity:.5}.form-switch{padding-left:2.5em}.form-switch .form-check-input{width:2em;margin-left:-2.5em;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%280, 0, 0, 0.25%29'/%3e%3c/svg%3e");background-position:left center;border-radius:2em;transition:background-position .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-switch .form-check-input{transition:none}}.form-switch .form-check-input:focus{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%2386b7fe'/%3e%3c/svg%3e")}.form-switch .form-check-input:checked{background-position:right center;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e")}.form-check-inline{display:inline-block;margin-right:1rem}.btn-check{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.btn-check:disabled+.btn,.btn-check[disabled]+.btn{pointer-events:none;filter:none;opacity:.65}.form-range{width:100%;height:1.5rem;padding:0;background-color:transparent;-webkit-appearance:none;-moz-appearance:none;appearance:none}.form-range:focus{outline:0}.form-range:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(13,110,253,.25)}.form-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(13,110,253,.25)}.form-range::-moz-focus-outer{border:0}.form-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-.25rem;background-color:#0d6efd;border:0;border-radius:1rem;-webkit-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;-webkit-appearance:none;appearance:none}@media (prefers-reduced-motion:reduce){.form-range::-webkit-slider-thumb{-webkit-transition:none;transition:none}}.form-range::-webkit-slider-thumb:active{background-color:#b6d4fe}.form-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem}.form-range::-moz-range-thumb{width:1rem;height:1rem;background-color:#0d6efd;border:0;border-radius:1rem;-moz-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;-moz-appearance:none;appearance:none}@media (prefers-reduced-motion:reduce){.form-range::-moz-range-thumb{-moz-transition:none;transition:none}}.form-range::-moz-range-thumb:active{background-color:#b6d4fe}.form-range::-moz-range-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem}.form-range:disabled{pointer-events:none}.form-range:disabled::-webkit-slider-thumb{background-color:#adb5bd}.form-range:disabled::-moz-range-thumb{background-color:#adb5bd}.form-floating{position:relative}.form-floating>.form-control,.form-floating>.form-select{height:calc(3.5rem + 2px);line-height:1.25}.form-floating>label{position:absolute;top:0;left:0;height:100%;padding:1rem .75rem;pointer-events:none;border:1px solid transparent;transform-origin:0 0;transition:opacity .1s ease-in-out,transform .1s ease-in-out}@media (prefers-reduced-motion:reduce){.form-floating>label{transition:none}}.form-floating>.form-control{padding:1rem .75rem}.form-floating>.form-control::-moz-placeholder{color:transparent}.form-floating>.form-control::placeholder{color:transparent}.form-floating>.form-control:not(:-moz-placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:focus,.form-floating>.form-control:not(:placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:-webkit-autofill{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-select{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:not(:-moz-placeholder-shown)~label{opacity:.65;transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.form-floating>.form-control:focus~label,.form-floating>.form-control:not(:placeholder-shown)~label,.form-floating>.form-select~label{opacity:.65;transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.form-floating>.form-control:-webkit-autofill~label{opacity:.65;transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.input-group{position:relative;display:flex;flex-wrap:wrap;align-items:stretch;width:100%}.input-group>.form-control,.input-group>.form-select{position:relative;flex:1 1 auto;width:1%;min-width:0}.input-group>.form-control:focus,.input-group>.form-select:focus{z-index:3}.input-group .btn{position:relative;z-index:2}.input-group .btn:focus{z-index:3}.input-group-text{display:flex;align-items:center;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:center;white-space:nowrap;background-color:#e9ecef;border:1px solid #ced4da;border-radius:.25rem}.input-group-lg>.btn,.input-group-lg>.form-control,.input-group-lg>.form-select,.input-group-lg>.input-group-text{padding:.5rem 1rem;font-size:1.25rem;border-radius:.3rem}.input-group-sm>.btn,.input-group-sm>.form-control,.input-group-sm>.form-select,.input-group-sm>.input-group-text{padding:.25rem .5rem;font-size:.875rem;border-radius:.2rem}.input-group-lg>.form-select,.input-group-sm>.form-select{padding-right:3rem}.input-group:not(.has-validation)>.dropdown-toggle:nth-last-child(n+3),.input-group:not(.has-validation)>:not(:last-child):not(.dropdown-toggle):not(.dropdown-menu){border-top-right-radius:0;border-bottom-right-radius:0}.input-group.has-validation>.dropdown-toggle:nth-last-child(n+4),.input-group.has-validation>:nth-last-child(n+3):not(.dropdown-toggle):not(.dropdown-menu){border-top-right-radius:0;border-bottom-right-radius:0}.input-group>:not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback){margin-left:-1px;border-top-left-radius:0;border-bottom-left-radius:0}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:.875em;color:#198754}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;color:#fff;background-color:rgba(25,135,84,.9);border-radius:.25rem}.is-valid~.valid-feedback,.is-valid~.valid-tooltip,.was-validated :valid~.valid-feedback,.was-validated :valid~.valid-tooltip{display:block}.form-control.is-valid,.was-validated .form-control:valid{border-color:#198754;padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-valid:focus,.was-validated .form-control:valid:focus{border-color:#198754;box-shadow:0 0 0 .25rem rgba(25,135,84,.25)}.was-validated textarea.form-control:valid,textarea.form-control.is-valid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.form-select.is-valid,.was-validated .form-select:valid{border-color:#198754}.form-select.is-valid:not([multiple]):not([size]),.form-select.is-valid:not([multiple])[size="1"],.was-validated .form-select:valid:not([multiple]):not([size]),.was-validated .form-select:valid:not([multiple])[size="1"]{padding-right:4.125rem;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e"),url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(.75em + .375rem) calc(.75em + .375rem)}.form-select.is-valid:focus,.was-validated .form-select:valid:focus{border-color:#198754;box-shadow:0 0 0 .25rem rgba(25,135,84,.25)}.form-check-input.is-valid,.was-validated .form-check-input:valid{border-color:#198754}.form-check-input.is-valid:checked,.was-validated .form-check-input:valid:checked{background-color:#198754}.form-check-input.is-valid:focus,.was-validated .form-check-input:valid:focus{box-shadow:0 0 0 .25rem rgba(25,135,84,.25)}.form-check-input.is-valid~.form-check-label,.was-validated .form-check-input:valid~.form-check-label{color:#198754}.form-check-inline .form-check-input~.valid-feedback{margin-left:.5em}.input-group .form-control.is-valid,.input-group .form-select.is-valid,.was-validated .input-group .form-control:valid,.was-validated .input-group .form-select:valid{z-index:1}.input-group .form-control.is-valid:focus,.input-group .form-select.is-valid:focus,.was-validated .input-group .form-control:valid:focus,.was-validated .input-group .form-select:valid:focus{z-index:3}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:.875em;color:#dc3545}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;color:#fff;background-color:rgba(220,53,69,.9);border-radius:.25rem}.is-invalid~.invalid-feedback,.is-invalid~.invalid-tooltip,.was-validated :invalid~.invalid-feedback,.was-validated :invalid~.invalid-tooltip{display:block}.form-control.is-invalid,.was-validated .form-control:invalid{border-color:#dc3545;padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-invalid:focus,.was-validated .form-control:invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .25rem rgba(220,53,69,.25)}.was-validated textarea.form-control:invalid,textarea.form-control.is-invalid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.form-select.is-invalid,.was-validated .form-select:invalid{border-color:#dc3545}.form-select.is-invalid:not([multiple]):not([size]),.form-select.is-invalid:not([multiple])[size="1"],.was-validated .form-select:invalid:not([multiple]):not([size]),.was-validated .form-select:invalid:not([multiple])[size="1"]{padding-right:4.125rem;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e"),url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(.75em + .375rem) calc(.75em + .375rem)}.form-select.is-invalid:focus,.was-validated .form-select:invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .25rem rgba(220,53,69,.25)}.form-check-input.is-invalid,.was-validated .form-check-input:invalid{border-color:#dc3545}.form-check-input.is-invalid:checked,.was-validated .form-check-input:invalid:checked{background-color:#dc3545}.form-check-input.is-invalid:focus,.was-validated .form-check-input:invalid:focus{box-shadow:0 0 0 .25rem rgba(220,53,69,.25)}.form-check-input.is-invalid~.form-check-label,.was-validated .form-check-input:invalid~.form-check-label{color:#dc3545}.form-check-inline .form-check-input~.invalid-feedback{margin-left:.5em}.input-group .form-control.is-invalid,.input-group .form-select.is-invalid,.was-validated .input-group .form-control:invalid,.was-validated .input-group .form-select:invalid{z-index:2}.input-group .form-control.is-invalid:focus,.input-group .form-select.is-invalid:focus,.was-validated .input-group .form-control:invalid:focus,.was-validated .input-group .form-select:invalid:focus{z-index:3}.btn{display:inline-block;font-weight:400;line-height:1.5;color:#212529;text-align:center;text-decoration:none;vertical-align:middle;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none;background-color:transparent;border:1px solid transparent;padding:.375rem .75rem;font-size:1rem;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.btn{transition:none}}.btn:hover{color:#212529}.btn-check:focus+.btn,.btn:focus{outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.btn.disabled,.btn:disabled,fieldset:disabled .btn{pointer-events:none;opacity:.65}.btn-primary{color:#fff;background-color:#0d6efd;border-color:#0d6efd}.btn-primary:hover{color:#fff;background-color:#0b5ed7;border-color:#0a58ca}.btn-check:focus+.btn-primary,.btn-primary:focus{color:#fff;background-color:#0b5ed7;border-color:#0a58ca;box-shadow:0 0 0 .25rem rgba(49,132,253,.5)}.btn-check:active+.btn-primary,.btn-check:checked+.btn-primary,.btn-primary.active,.btn-primary:active,.show>.btn-primary.dropdown-toggle{color:#fff;background-color:#0a58ca;border-color:#0a53be}.btn-check:active+.btn-primary:focus,.btn-check:checked+.btn-primary:focus,.btn-primary.active:focus,.btn-primary:active:focus,.show>.btn-primary.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(49,132,253,.5)}.btn-primary.disabled,.btn-primary:disabled{color:#fff;background-color:#0d6efd;border-color:#0d6efd}.btn-secondary{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-secondary:hover{color:#fff;background-color:#5c636a;border-color:#565e64}.btn-check:focus+.btn-secondary,.btn-secondary:focus{color:#fff;background-color:#5c636a;border-color:#565e64;box-shadow:0 0 0 .25rem rgba(130,138,145,.5)}.btn-check:active+.btn-secondary,.btn-check:checked+.btn-secondary,.btn-secondary.active,.btn-secondary:active,.show>.btn-secondary.dropdown-toggle{color:#fff;background-color:#565e64;border-color:#51585e}.btn-check:active+.btn-secondary:focus,.btn-check:checked+.btn-secondary:focus,.btn-secondary.active:focus,.btn-secondary:active:focus,.show>.btn-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(130,138,145,.5)}.btn-secondary.disabled,.btn-secondary:disabled{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-success{color:#fff;background-color:#198754;border-color:#198754}.btn-success:hover{color:#fff;background-color:#157347;border-color:#146c43}.btn-check:focus+.btn-success,.btn-success:focus{color:#fff;background-color:#157347;border-color:#146c43;box-shadow:0 0 0 .25rem rgba(60,153,110,.5)}.btn-check:active+.btn-success,.btn-check:checked+.btn-success,.btn-success.active,.btn-success:active,.show>.btn-success.dropdown-toggle{color:#fff;background-color:#146c43;border-color:#13653f}.btn-check:active+.btn-success:focus,.btn-check:checked+.btn-success:focus,.btn-success.active:focus,.btn-success:active:focus,.show>.btn-success.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(60,153,110,.5)}.btn-success.disabled,.btn-success:disabled{color:#fff;background-color:#198754;border-color:#198754}.btn-info{color:#000;background-color:#0dcaf0;border-color:#0dcaf0}.btn-info:hover{color:#000;background-color:#31d2f2;border-color:#25cff2}.btn-check:focus+.btn-info,.btn-info:focus{color:#000;background-color:#31d2f2;border-color:#25cff2;box-shadow:0 0 0 .25rem rgba(11,172,204,.5)}.btn-check:active+.btn-info,.btn-check:checked+.btn-info,.btn-info.active,.btn-info:active,.show>.btn-info.dropdown-toggle{color:#000;background-color:#3dd5f3;border-color:#25cff2}.btn-check:active+.btn-info:focus,.btn-check:checked+.btn-info:focus,.btn-info.active:focus,.btn-info:active:focus,.show>.btn-info.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(11,172,204,.5)}.btn-info.disabled,.btn-info:disabled{color:#000;background-color:#0dcaf0;border-color:#0dcaf0}.btn-warning{color:#000;background-color:#ffc107;border-color:#ffc107}.btn-warning:hover{color:#000;background-color:#ffca2c;border-color:#ffc720}.btn-check:focus+.btn-warning,.btn-warning:focus{color:#000;background-color:#ffca2c;border-color:#ffc720;box-shadow:0 0 0 .25rem rgba(217,164,6,.5)}.btn-check:active+.btn-warning,.btn-check:checked+.btn-warning,.btn-warning.active,.btn-warning:active,.show>.btn-warning.dropdown-toggle{color:#000;background-color:#ffcd39;border-color:#ffc720}.btn-check:active+.btn-warning:focus,.btn-check:checked+.btn-warning:focus,.btn-warning.active:focus,.btn-warning:active:focus,.show>.btn-warning.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(217,164,6,.5)}.btn-warning.disabled,.btn-warning:disabled{color:#000;background-color:#ffc107;border-color:#ffc107}.btn-danger{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-danger:hover{color:#fff;background-color:#bb2d3b;border-color:#b02a37}.btn-check:focus+.btn-danger,.btn-danger:focus{color:#fff;background-color:#bb2d3b;border-color:#b02a37;box-shadow:0 0 0 .25rem rgba(225,83,97,.5)}.btn-check:active+.btn-danger,.btn-check:checked+.btn-danger,.btn-danger.active,.btn-danger:active,.show>.btn-danger.dropdown-toggle{color:#fff;background-color:#b02a37;border-color:#a52834}.btn-check:active+.btn-danger:focus,.btn-check:checked+.btn-danger:focus,.btn-danger.active:focus,.btn-danger:active:focus,.show>.btn-danger.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(225,83,97,.5)}.btn-danger.disabled,.btn-danger:disabled{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-light{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:hover{color:#000;background-color:#f9fafb;border-color:#f9fafb}.btn-check:focus+.btn-light,.btn-light:focus{color:#000;background-color:#f9fafb;border-color:#f9fafb;box-shadow:0 0 0 .25rem rgba(211,212,213,.5)}.btn-check:active+.btn-light,.btn-check:checked+.btn-light,.btn-light.active,.btn-light:active,.show>.btn-light.dropdown-toggle{color:#000;background-color:#f9fafb;border-color:#f9fafb}.btn-check:active+.btn-light:focus,.btn-check:checked+.btn-light:focus,.btn-light.active:focus,.btn-light:active:focus,.show>.btn-light.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(211,212,213,.5)}.btn-light.disabled,.btn-light:disabled{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-dark{color:#fff;background-color:#212529;border-color:#212529}.btn-dark:hover{color:#fff;background-color:#1c1f23;border-color:#1a1e21}.btn-check:focus+.btn-dark,.btn-dark:focus{color:#fff;background-color:#1c1f23;border-color:#1a1e21;box-shadow:0 0 0 .25rem rgba(66,70,73,.5)}.btn-check:active+.btn-dark,.btn-check:checked+.btn-dark,.btn-dark.active,.btn-dark:active,.show>.btn-dark.dropdown-toggle{color:#fff;background-color:#1a1e21;border-color:#191c1f}.btn-check:active+.btn-dark:focus,.btn-check:checked+.btn-dark:focus,.btn-dark.active:focus,.btn-dark:active:focus,.show>.btn-dark.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(66,70,73,.5)}.btn-dark.disabled,.btn-dark:disabled{color:#fff;background-color:#212529;border-color:#212529}.btn-outline-primary{color:#0d6efd;border-color:#0d6efd}.btn-outline-primary:hover{color:#fff;background-color:#0d6efd;border-color:#0d6efd}.btn-check:focus+.btn-outline-primary,.btn-outline-primary:focus{box-shadow:0 0 0 .25rem rgba(13,110,253,.5)}.btn-check:active+.btn-outline-primary,.btn-check:checked+.btn-outline-primary,.btn-outline-primary.active,.btn-outline-primary.dropdown-toggle.show,.btn-outline-primary:active{color:#fff;background-color:#0d6efd;border-color:#0d6efd}.btn-check:active+.btn-outline-primary:focus,.btn-check:checked+.btn-outline-primary:focus,.btn-outline-primary.active:focus,.btn-outline-primary.dropdown-toggle.show:focus,.btn-outline-primary:active:focus{box-shadow:0 0 0 .25rem rgba(13,110,253,.5)}.btn-outline-primary.disabled,.btn-outline-primary:disabled{color:#0d6efd;background-color:transparent}.btn-outline-secondary{color:#6c757d;border-color:#6c757d}.btn-outline-secondary:hover{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-check:focus+.btn-outline-secondary,.btn-outline-secondary:focus{box-shadow:0 0 0 .25rem rgba(108,117,125,.5)}.btn-check:active+.btn-outline-secondary,.btn-check:checked+.btn-outline-secondary,.btn-outline-secondary.active,.btn-outline-secondary.dropdown-toggle.show,.btn-outline-secondary:active{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-check:active+.btn-outline-secondary:focus,.btn-check:checked+.btn-outline-secondary:focus,.btn-outline-secondary.active:focus,.btn-outline-secondary.dropdown-toggle.show:focus,.btn-outline-secondary:active:focus{box-shadow:0 0 0 .25rem rgba(108,117,125,.5)}.btn-outline-secondary.disabled,.btn-outline-secondary:disabled{color:#6c757d;background-color:transparent}.btn-outline-success{color:#198754;border-color:#198754}.btn-outline-success:hover{color:#fff;background-color:#198754;border-color:#198754}.btn-check:focus+.btn-outline-success,.btn-outline-success:focus{box-shadow:0 0 0 .25rem rgba(25,135,84,.5)}.btn-check:active+.btn-outline-success,.btn-check:checked+.btn-outline-success,.btn-outline-success.active,.btn-outline-success.dropdown-toggle.show,.btn-outline-success:active{color:#fff;background-color:#198754;border-color:#198754}.btn-check:active+.btn-outline-success:focus,.btn-check:checked+.btn-outline-success:focus,.btn-outline-success.active:focus,.btn-outline-success.dropdown-toggle.show:focus,.btn-outline-success:active:focus{box-shadow:0 0 0 .25rem rgba(25,135,84,.5)}.btn-outline-success.disabled,.btn-outline-success:disabled{color:#198754;background-color:transparent}.btn-outline-info{color:#0dcaf0;border-color:#0dcaf0}.btn-outline-info:hover{color:#000;background-color:#0dcaf0;border-color:#0dcaf0}.btn-check:focus+.btn-outline-info,.btn-outline-info:focus{box-shadow:0 0 0 .25rem rgba(13,202,240,.5)}.btn-check:active+.btn-outline-info,.btn-check:checked+.btn-outline-info,.btn-outline-info.active,.btn-outline-info.dropdown-toggle.show,.btn-outline-info:active{color:#000;background-color:#0dcaf0;border-color:#0dcaf0}.btn-check:active+.btn-outline-info:focus,.btn-check:checked+.btn-outline-info:focus,.btn-outline-info.active:focus,.btn-outline-info.dropdown-toggle.show:focus,.btn-outline-info:active:focus{box-shadow:0 0 0 .25rem rgba(13,202,240,.5)}.btn-outline-info.disabled,.btn-outline-info:disabled{color:#0dcaf0;background-color:transparent}.btn-outline-warning{color:#ffc107;border-color:#ffc107}.btn-outline-warning:hover{color:#000;background-color:#ffc107;border-color:#ffc107}.btn-check:focus+.btn-outline-warning,.btn-outline-warning:focus{box-shadow:0 0 0 .25rem rgba(255,193,7,.5)}.btn-check:active+.btn-outline-warning,.btn-check:checked+.btn-outline-warning,.btn-outline-warning.active,.btn-outline-warning.dropdown-toggle.show,.btn-outline-warning:active{color:#000;background-color:#ffc107;border-color:#ffc107}.btn-check:active+.btn-outline-warning:focus,.btn-check:checked+.btn-outline-warning:focus,.btn-outline-warning.active:focus,.btn-outline-warning.dropdown-toggle.show:focus,.btn-outline-warning:active:focus{box-shadow:0 0 0 .25rem rgba(255,193,7,.5)}.btn-outline-warning.disabled,.btn-outline-warning:disabled{color:#ffc107;background-color:transparent}.btn-outline-danger{color:#dc3545;border-color:#dc3545}.btn-outline-danger:hover{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-check:focus+.btn-outline-danger,.btn-outline-danger:focus{box-shadow:0 0 0 .25rem rgba(220,53,69,.5)}.btn-check:active+.btn-outline-danger,.btn-check:checked+.btn-outline-danger,.btn-outline-danger.active,.btn-outline-danger.dropdown-toggle.show,.btn-outline-danger:active{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-check:active+.btn-outline-danger:focus,.btn-check:checked+.btn-outline-danger:focus,.btn-outline-danger.active:focus,.btn-outline-danger.dropdown-toggle.show:focus,.btn-outline-danger:active:focus{box-shadow:0 0 0 .25rem rgba(220,53,69,.5)}.btn-outline-danger.disabled,.btn-outline-danger:disabled{color:#dc3545;background-color:transparent}.btn-outline-light{color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light:hover{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-check:focus+.btn-outline-light,.btn-outline-light:focus{box-shadow:0 0 0 .25rem rgba(248,249,250,.5)}.btn-check:active+.btn-outline-light,.btn-check:checked+.btn-outline-light,.btn-outline-light.active,.btn-outline-light.dropdown-toggle.show,.btn-outline-light:active{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-check:active+.btn-outline-light:focus,.btn-check:checked+.btn-outline-light:focus,.btn-outline-light.active:focus,.btn-outline-light.dropdown-toggle.show:focus,.btn-outline-light:active:focus{box-shadow:0 0 0 .25rem rgba(248,249,250,.5)}.btn-outline-light.disabled,.btn-outline-light:disabled{color:#f8f9fa;background-color:transparent}.btn-outline-dark{color:#212529;border-color:#212529}.btn-outline-dark:hover{color:#fff;background-color:#212529;border-color:#212529}.btn-check:focus+.btn-outline-dark,.btn-outline-dark:focus{box-shadow:0 0 0 .25rem rgba(33,37,41,.5)}.btn-check:active+.btn-outline-dark,.btn-check:checked+.btn-outline-dark,.btn-outline-dark.active,.btn-outline-dark.dropdown-toggle.show,.btn-outline-dark:active{color:#fff;background-color:#212529;border-color:#212529}.btn-check:active+.btn-outline-dark:focus,.btn-check:checked+.btn-outline-dark:focus,.btn-outline-dark.active:focus,.btn-outline-dark.dropdown-toggle.show:focus,.btn-outline-dark:active:focus{box-shadow:0 0 0 .25rem rgba(33,37,41,.5)}.btn-outline-dark.disabled,.btn-outline-dark:disabled{color:#212529;background-color:transparent}.btn-link{font-weight:400;color:#0d6efd;text-decoration:underline}.btn-link:hover{color:#0a58ca}.btn-link.disabled,.btn-link:disabled{color:#6c757d}.btn-group-lg>.btn,.btn-lg{padding:.5rem 1rem;font-size:1.25rem;border-radius:.3rem}.btn-group-sm>.btn,.btn-sm{padding:.25rem .5rem;font-size:.875rem;border-radius:.2rem}.fade{transition:opacity .15s linear}@media (prefers-reduced-motion:reduce){.fade{transition:none}}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{height:0;overflow:hidden;transition:height .35s ease}@media (prefers-reduced-motion:reduce){.collapsing{transition:none}}.dropdown,.dropend,.dropstart,.dropup{position:relative}.dropdown-toggle{white-space:nowrap}.dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-bottom:0;border-left:.3em solid transparent}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{position:absolute;z-index:1000;display:none;min-width:10rem;padding:.5rem 0;margin:0;font-size:1rem;color:#212529;text-align:left;list-style:none;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.15);border-radius:.25rem}.dropdown-menu[data-bs-popper]{top:100%;left:0;margin-top:.125rem}.dropdown-menu-start{--bs-position:start}.dropdown-menu-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-end{--bs-position:end}.dropdown-menu-end[data-bs-popper]{right:0;left:auto}@media (min-width:576px){.dropdown-menu-sm-start{--bs-position:start}.dropdown-menu-sm-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-sm-end{--bs-position:end}.dropdown-menu-sm-end[data-bs-popper]{right:0;left:auto}}@media (min-width:768px){.dropdown-menu-md-start{--bs-position:start}.dropdown-menu-md-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-md-end{--bs-position:end}.dropdown-menu-md-end[data-bs-popper]{right:0;left:auto}}@media (min-width:992px){.dropdown-menu-lg-start{--bs-position:start}.dropdown-menu-lg-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-lg-end{--bs-position:end}.dropdown-menu-lg-end[data-bs-popper]{right:0;left:auto}}@media (min-width:1200px){.dropdown-menu-xl-start{--bs-position:start}.dropdown-menu-xl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xl-end{--bs-position:end}.dropdown-menu-xl-end[data-bs-popper]{right:0;left:auto}}@media (min-width:1400px){.dropdown-menu-xxl-start{--bs-position:start}.dropdown-menu-xxl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xxl-end{--bs-position:end}.dropdown-menu-xxl-end[data-bs-popper]{right:0;left:auto}}.dropup .dropdown-menu[data-bs-popper]{top:auto;bottom:100%;margin-top:0;margin-bottom:.125rem}.dropup .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid transparent;border-bottom:.3em solid;border-left:.3em solid transparent}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-menu[data-bs-popper]{top:0;right:auto;left:100%;margin-top:0;margin-left:.125rem}.dropend .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:0;border-bottom:.3em solid transparent;border-left:.3em solid}.dropend .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-toggle::after{vertical-align:0}.dropstart .dropdown-menu[data-bs-popper]{top:0;right:100%;left:auto;margin-top:0;margin-right:.125rem}.dropstart .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:""}.dropstart .dropdown-toggle::after{display:none}.dropstart .dropdown-toggle::before{display:inline-block;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:.3em solid;border-bottom:.3em solid transparent}.dropstart .dropdown-toggle:empty::after{margin-left:0}.dropstart .dropdown-toggle::before{vertical-align:0}.dropdown-divider{height:0;margin:.5rem 0;overflow:hidden;border-top:1px solid rgba(0,0,0,.15)}.dropdown-item{display:block;width:100%;padding:.25rem 1rem;clear:both;font-weight:400;color:#212529;text-align:inherit;text-decoration:none;white-space:nowrap;background-color:transparent;border:0}.dropdown-item:focus,.dropdown-item:hover{color:#1e2125;background-color:#e9ecef}.dropdown-item.active,.dropdown-item:active{color:#fff;text-decoration:none;background-color:#0d6efd}.dropdown-item.disabled,.dropdown-item:disabled{color:#adb5bd;pointer-events:none;background-color:transparent}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:.5rem 1rem;margin-bottom:0;font-size:.875rem;color:#6c757d;white-space:nowrap}.dropdown-item-text{display:block;padding:.25rem 1rem;color:#212529}.dropdown-menu-dark{color:#dee2e6;background-color:#343a40;border-color:rgba(0,0,0,.15)}.dropdown-menu-dark .dropdown-item{color:#dee2e6}.dropdown-menu-dark .dropdown-item:focus,.dropdown-menu-dark .dropdown-item:hover{color:#fff;background-color:rgba(255,255,255,.15)}.dropdown-menu-dark .dropdown-item.active,.dropdown-menu-dark .dropdown-item:active{color:#fff;background-color:#0d6efd}.dropdown-menu-dark .dropdown-item.disabled,.dropdown-menu-dark .dropdown-item:disabled{color:#adb5bd}.dropdown-menu-dark .dropdown-divider{border-color:rgba(0,0,0,.15)}.dropdown-menu-dark .dropdown-item-text{color:#dee2e6}.dropdown-menu-dark .dropdown-header{color:#adb5bd}.btn-group,.btn-group-vertical{position:relative;display:inline-flex;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;flex:1 1 auto}.btn-group-vertical>.btn-check:checked+.btn,.btn-group-vertical>.btn-check:focus+.btn,.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn-check:checked+.btn,.btn-group>.btn-check:focus+.btn,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:1}.btn-toolbar{display:flex;flex-wrap:wrap;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group>.btn-group:not(:first-child),.btn-group>.btn:not(:first-child){margin-left:-1px}.btn-group>.btn-group:not(:last-child)>.btn,.btn-group>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:not(:first-child)>.btn,.btn-group>.btn:nth-child(n+3),.btn-group>:not(.btn-check)+.btn{border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.dropdown-toggle-split::after,.dropend .dropdown-toggle-split::after,.dropup .dropdown-toggle-split::after{margin-left:0}.dropstart .dropdown-toggle-split::before{margin-right:0}.btn-group-sm>.btn+.dropdown-toggle-split,.btn-sm+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-group-lg>.btn+.dropdown-toggle-split,.btn-lg+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{flex-direction:column;align-items:flex-start;justify-content:center}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{width:100%}.btn-group-vertical>.btn-group:not(:first-child),.btn-group-vertical>.btn:not(:first-child){margin-top:-1px}.btn-group-vertical>.btn-group:not(:last-child)>.btn,.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child)>.btn,.btn-group-vertical>.btn~.btn{border-top-left-radius:0;border-top-right-radius:0}.nav{display:flex;flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:.5rem 1rem;color:#0d6efd;text-decoration:none;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out}@media (prefers-reduced-motion:reduce){.nav-link{transition:none}}.nav-link:focus,.nav-link:hover{color:#0a58ca}.nav-link.disabled{color:#6c757d;pointer-events:none;cursor:default}.nav-tabs{border-bottom:1px solid #dee2e6}.nav-tabs .nav-link{margin-bottom:-1px;background:0 0;border:1px solid transparent;border-top-left-radius:.25rem;border-top-right-radius:.25rem}.nav-tabs .nav-link:focus,.nav-tabs .nav-link:hover{border-color:#e9ecef #e9ecef #dee2e6;isolation:isolate}.nav-tabs .nav-link.disabled{color:#6c757d;background-color:transparent;border-color:transparent}.nav-tabs .nav-item.show .nav-link,.nav-tabs .nav-link.active{color:#495057;background-color:#fff;border-color:#dee2e6 #dee2e6 #fff}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.nav-pills .nav-link{background:0 0;border:0;border-radius:.25rem}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:#fff;background-color:#0d6efd}.nav-fill .nav-item,.nav-fill>.nav-link{flex:1 1 auto;text-align:center}.nav-justified .nav-item,.nav-justified>.nav-link{flex-basis:0;flex-grow:1;text-align:center}.nav-fill .nav-item .nav-link,.nav-justified .nav-item .nav-link{width:100%}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{position:relative;display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;padding-top:.5rem;padding-bottom:.5rem}.navbar>.container,.navbar>.container-fluid,.navbar>.container-lg,.navbar>.container-md,.navbar>.container-sm,.navbar>.container-xl,.navbar>.container-xxl{display:flex;flex-wrap:inherit;align-items:center;justify-content:space-between}.navbar-brand{padding-top:.3125rem;padding-bottom:.3125rem;margin-right:1rem;font-size:1.25rem;text-decoration:none;white-space:nowrap}.navbar-nav{display:flex;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link{padding-right:0;padding-left:0}.navbar-nav .dropdown-menu{position:static}.navbar-text{padding-top:.5rem;padding-bottom:.5rem}.navbar-collapse{flex-basis:100%;flex-grow:1;align-items:center}.navbar-toggler{padding:.25rem .75rem;font-size:1.25rem;line-height:1;background-color:transparent;border:1px solid transparent;border-radius:.25rem;transition:box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.navbar-toggler{transition:none}}.navbar-toggler:hover{text-decoration:none}.navbar-toggler:focus{text-decoration:none;outline:0;box-shadow:0 0 0 .25rem}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;background-repeat:no-repeat;background-position:center;background-size:100%}.navbar-nav-scroll{max-height:var(--bs-scroll-height,75vh);overflow-y:auto}@media (min-width:576px){.navbar-expand-sm{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-sm .navbar-nav{flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-sm .navbar-nav-scroll{overflow:visible}.navbar-expand-sm .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}}@media (min-width:768px){.navbar-expand-md{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-md .navbar-nav{flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-md .navbar-nav-scroll{overflow:visible}.navbar-expand-md .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}}@media (min-width:992px){.navbar-expand-lg{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-lg .navbar-nav{flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-lg .navbar-nav-scroll{overflow:visible}.navbar-expand-lg .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}}@media (min-width:1200px){.navbar-expand-xl{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-xl .navbar-nav{flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-xl .navbar-nav-scroll{overflow:visible}.navbar-expand-xl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}}@media (min-width:1400px){.navbar-expand-xxl{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-xxl .navbar-nav{flex-direction:row}.navbar-expand-xxl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xxl .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-xxl .navbar-nav-scroll{overflow:visible}.navbar-expand-xxl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xxl .navbar-toggler{display:none}}.navbar-expand{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand .navbar-nav{flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand .navbar-nav-scroll{overflow:visible}.navbar-expand .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-light .navbar-brand{color:rgba(0,0,0,.9)}.navbar-light .navbar-brand:focus,.navbar-light .navbar-brand:hover{color:rgba(0,0,0,.9)}.navbar-light .navbar-nav .nav-link{color:rgba(0,0,0,.55)}.navbar-light .navbar-nav .nav-link:focus,.navbar-light .navbar-nav .nav-link:hover{color:rgba(0,0,0,.7)}.navbar-light .navbar-nav .nav-link.disabled{color:rgba(0,0,0,.3)}.navbar-light .navbar-nav .nav-link.active,.navbar-light .navbar-nav .show>.nav-link{color:rgba(0,0,0,.9)}.navbar-light .navbar-toggler{color:rgba(0,0,0,.55);border-color:rgba(0,0,0,.1)}.navbar-light .navbar-toggler-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%280, 0, 0, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.navbar-light .navbar-text{color:rgba(0,0,0,.55)}.navbar-light .navbar-text a,.navbar-light .navbar-text a:focus,.navbar-light .navbar-text a:hover{color:rgba(0,0,0,.9)}.navbar-dark .navbar-brand{color:#fff}.navbar-dark .navbar-brand:focus,.navbar-dark .navbar-brand:hover{color:#fff}.navbar-dark .navbar-nav .nav-link{color:rgba(255,255,255,.55)}.navbar-dark .navbar-nav .nav-link:focus,.navbar-dark .navbar-nav .nav-link:hover{color:rgba(255,255,255,.75)}.navbar-dark .navbar-nav .nav-link.disabled{color:rgba(255,255,255,.25)}.navbar-dark .navbar-nav .nav-link.active,.navbar-dark .navbar-nav .show>.nav-link{color:#fff}.navbar-dark .navbar-toggler{color:rgba(255,255,255,.55);border-color:rgba(255,255,255,.1)}.navbar-dark .navbar-toggler-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.navbar-dark .navbar-text{color:rgba(255,255,255,.55)}.navbar-dark .navbar-text a,.navbar-dark .navbar-text a:focus,.navbar-dark .navbar-text a:hover{color:#fff}.card{position:relative;display:flex;flex-direction:column;min-width:0;word-wrap:break-word;background-color:#fff;background-clip:border-box;border:1px solid rgba(0,0,0,.125);border-radius:.25rem}.card>hr{margin-right:0;margin-left:0}.card>.list-group{border-top:inherit;border-bottom:inherit}.card>.list-group:first-child{border-top-width:0;border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.card>.list-group:last-child{border-bottom-width:0;border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.card>.card-header+.list-group,.card>.list-group+.card-footer{border-top:0}.card-body{flex:1 1 auto;padding:1rem 1rem}.card-title{margin-bottom:.5rem}.card-subtitle{margin-top:-.25rem;margin-bottom:0}.card-text:last-child{margin-bottom:0}.card-link:hover{text-decoration:none}.card-link+.card-link{margin-left:1rem}.card-header{padding:.5rem 1rem;margin-bottom:0;background-color:rgba(0,0,0,.03);border-bottom:1px solid rgba(0,0,0,.125)}.card-header:first-child{border-radius:calc(.25rem - 1px) calc(.25rem - 1px) 0 0}.card-footer{padding:.5rem 1rem;background-color:rgba(0,0,0,.03);border-top:1px solid rgba(0,0,0,.125)}.card-footer:last-child{border-radius:0 0 calc(.25rem - 1px) calc(.25rem - 1px)}.card-header-tabs{margin-right:-.5rem;margin-bottom:-.5rem;margin-left:-.5rem;border-bottom:0}.card-header-pills{margin-right:-.5rem;margin-left:-.5rem}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1rem;border-radius:calc(.25rem - 1px)}.card-img,.card-img-bottom,.card-img-top{width:100%}.card-img,.card-img-top{border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.card-img,.card-img-bottom{border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.card-group>.card{margin-bottom:.75rem}@media (min-width:576px){.card-group{display:flex;flex-flow:row wrap}.card-group>.card{flex:1 0 0%;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}.card-group>.card:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.card-group>.card:not(:last-child) .card-header,.card-group>.card:not(:last-child) .card-img-top{border-top-right-radius:0}.card-group>.card:not(:last-child) .card-footer,.card-group>.card:not(:last-child) .card-img-bottom{border-bottom-right-radius:0}.card-group>.card:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.card-group>.card:not(:first-child) .card-header,.card-group>.card:not(:first-child) .card-img-top{border-top-left-radius:0}.card-group>.card:not(:first-child) .card-footer,.card-group>.card:not(:first-child) .card-img-bottom{border-bottom-left-radius:0}}.accordion-button{position:relative;display:flex;align-items:center;width:100%;padding:1rem 1.25rem;font-size:1rem;color:#212529;text-align:left;background-color:#fff;border:0;border-radius:0;overflow-anchor:none;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out,border-radius .15s ease}@media (prefers-reduced-motion:reduce){.accordion-button{transition:none}}.accordion-button:not(.collapsed){color:#0c63e4;background-color:#e7f1ff;box-shadow:inset 0 -1px 0 rgba(0,0,0,.125)}.accordion-button:not(.collapsed)::after{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%230c63e4'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");transform:rotate(-180deg)}.accordion-button::after{flex-shrink:0;width:1.25rem;height:1.25rem;margin-left:auto;content:"";background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23212529'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");background-repeat:no-repeat;background-size:1.25rem;transition:transform .2s ease-in-out}@media (prefers-reduced-motion:reduce){.accordion-button::after{transition:none}}.accordion-button:hover{z-index:2}.accordion-button:focus{z-index:3;border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.accordion-header{margin-bottom:0}.accordion-item{background-color:#fff;border:1px solid rgba(0,0,0,.125)}.accordion-item:first-of-type{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.accordion-item:first-of-type .accordion-button{border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.accordion-item:not(:first-of-type){border-top:0}.accordion-item:last-of-type{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.accordion-item:last-of-type .accordion-button.collapsed{border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.accordion-item:last-of-type .accordion-collapse{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.accordion-body{padding:1rem 1.25rem}.accordion-flush .accordion-collapse{border-width:0}.accordion-flush .accordion-item{border-right:0;border-left:0;border-radius:0}.accordion-flush .accordion-item:first-child{border-top:0}.accordion-flush .accordion-item:last-child{border-bottom:0}.accordion-flush .accordion-item .accordion-button{border-radius:0}.breadcrumb{display:flex;flex-wrap:wrap;padding:0 0;margin-bottom:1rem;list-style:none}.breadcrumb-item+.breadcrumb-item{padding-left:.5rem}.breadcrumb-item+.breadcrumb-item::before{float:left;padding-right:.5rem;color:#6c757d;content:var(--bs-breadcrumb-divider, "/")}.breadcrumb-item.active{color:#6c757d}.pagination{display:flex;padding-left:0;list-style:none}.page-link{position:relative;display:block;color:#0d6efd;text-decoration:none;background-color:#fff;border:1px solid #dee2e6;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.page-link{transition:none}}.page-link:hover{z-index:2;color:#0a58ca;background-color:#e9ecef;border-color:#dee2e6}.page-link:focus{z-index:3;color:#0a58ca;background-color:#e9ecef;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.page-item:not(:first-child) .page-link{margin-left:-1px}.page-item.active .page-link{z-index:3;color:#fff;background-color:#0d6efd;border-color:#0d6efd}.page-item.disabled .page-link{color:#6c757d;pointer-events:none;background-color:#fff;border-color:#dee2e6}.page-link{padding:.375rem .75rem}.page-item:first-child .page-link{border-top-left-radius:.25rem;border-bottom-left-radius:.25rem}.page-item:last-child .page-link{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.pagination-lg .page-link{padding:.75rem 1.5rem;font-size:1.25rem}.pagination-lg .page-item:first-child .page-link{border-top-left-radius:.3rem;border-bottom-left-radius:.3rem}.pagination-lg .page-item:last-child .page-link{border-top-right-radius:.3rem;border-bottom-right-radius:.3rem}.pagination-sm .page-link{padding:.25rem .5rem;font-size:.875rem}.pagination-sm .page-item:first-child .page-link{border-top-left-radius:.2rem;border-bottom-left-radius:.2rem}.pagination-sm .page-item:last-child .page-link{border-top-right-radius:.2rem;border-bottom-right-radius:.2rem}.badge{display:inline-block;padding:.35em .65em;font-size:.75em;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.alert{position:relative;padding:1rem 1rem;margin-bottom:1rem;border:1px solid transparent;border-radius:.25rem}.alert-heading{color:inherit}.alert-link{font-weight:700}.alert-dismissible{padding-right:3rem}.alert-dismissible .btn-close{position:absolute;top:0;right:0;z-index:2;padding:1.25rem 1rem}.alert-primary{color:#084298;background-color:#cfe2ff;border-color:#b6d4fe}.alert-primary .alert-link{color:#06357a}.alert-secondary{color:#41464b;background-color:#e2e3e5;border-color:#d3d6d8}.alert-secondary .alert-link{color:#34383c}.alert-success{color:#0f5132;background-color:#d1e7dd;border-color:#badbcc}.alert-success .alert-link{color:#0c4128}.alert-info{color:#055160;background-color:#cff4fc;border-color:#b6effb}.alert-info .alert-link{color:#04414d}.alert-warning{color:#664d03;background-color:#fff3cd;border-color:#ffecb5}.alert-warning .alert-link{color:#523e02}.alert-danger{color:#842029;background-color:#f8d7da;border-color:#f5c2c7}.alert-danger .alert-link{color:#6a1a21}.alert-light{color:#636464;background-color:#fefefe;border-color:#fdfdfe}.alert-light .alert-link{color:#4f5050}.alert-dark{color:#141619;background-color:#d3d3d4;border-color:#bcbebf}.alert-dark .alert-link{color:#101214}@-webkit-keyframes progress-bar-stripes{0%{background-position-x:1rem}}@keyframes progress-bar-stripes{0%{background-position-x:1rem}}.progress{display:flex;height:1rem;overflow:hidden;font-size:.75rem;background-color:#e9ecef;border-radius:.25rem}.progress-bar{display:flex;flex-direction:column;justify-content:center;overflow:hidden;color:#fff;text-align:center;white-space:nowrap;background-color:#0d6efd;transition:width .6s ease}@media (prefers-reduced-motion:reduce){.progress-bar{transition:none}}.progress-bar-striped{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:1rem 1rem}.progress-bar-animated{-webkit-animation:1s linear infinite progress-bar-stripes;animation:1s linear infinite progress-bar-stripes}@media (prefers-reduced-motion:reduce){.progress-bar-animated{-webkit-animation:none;animation:none}}.list-group{display:flex;flex-direction:column;padding-left:0;margin-bottom:0;border-radius:.25rem}.list-group-numbered{list-style-type:none;counter-reset:section}.list-group-numbered>li::before{content:counters(section, ".") ". ";counter-increment:section}.list-group-item-action{width:100%;color:#495057;text-align:inherit}.list-group-item-action:focus,.list-group-item-action:hover{z-index:1;color:#495057;text-decoration:none;background-color:#f8f9fa}.list-group-item-action:active{color:#212529;background-color:#e9ecef}.list-group-item{position:relative;display:block;padding:.5rem 1rem;color:#212529;text-decoration:none;background-color:#fff;border:1px solid rgba(0,0,0,.125)}.list-group-item:first-child{border-top-left-radius:inherit;border-top-right-radius:inherit}.list-group-item:last-child{border-bottom-right-radius:inherit;border-bottom-left-radius:inherit}.list-group-item.disabled,.list-group-item:disabled{color:#6c757d;pointer-events:none;background-color:#fff}.list-group-item.active{z-index:2;color:#fff;background-color:#0d6efd;border-color:#0d6efd}.list-group-item+.list-group-item{border-top-width:0}.list-group-item+.list-group-item.active{margin-top:-1px;border-top-width:1px}.list-group-horizontal{flex-direction:row}.list-group-horizontal>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal>.list-group-item.active{margin-top:0}.list-group-horizontal>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}@media (min-width:576px){.list-group-horizontal-sm{flex-direction:row}.list-group-horizontal-sm>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-sm>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-sm>.list-group-item.active{margin-top:0}.list-group-horizontal-sm>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-sm>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width:768px){.list-group-horizontal-md{flex-direction:row}.list-group-horizontal-md>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-md>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-md>.list-group-item.active{margin-top:0}.list-group-horizontal-md>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-md>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width:992px){.list-group-horizontal-lg{flex-direction:row}.list-group-horizontal-lg>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-lg>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-lg>.list-group-item.active{margin-top:0}.list-group-horizontal-lg>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-lg>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width:1200px){.list-group-horizontal-xl{flex-direction:row}.list-group-horizontal-xl>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-xl>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-xl>.list-group-item.active{margin-top:0}.list-group-horizontal-xl>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-xl>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width:1400px){.list-group-horizontal-xxl{flex-direction:row}.list-group-horizontal-xxl>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-xxl>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-xxl>.list-group-item.active{margin-top:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}.list-group-flush{border-radius:0}.list-group-flush>.list-group-item{border-width:0 0 1px}.list-group-flush>.list-group-item:last-child{border-bottom-width:0}.list-group-item-primary{color:#084298;background-color:#cfe2ff}.list-group-item-primary.list-group-item-action:focus,.list-group-item-primary.list-group-item-action:hover{color:#084298;background-color:#bacbe6}.list-group-item-primary.list-group-item-action.active{color:#fff;background-color:#084298;border-color:#084298}.list-group-item-secondary{color:#41464b;background-color:#e2e3e5}.list-group-item-secondary.list-group-item-action:focus,.list-group-item-secondary.list-group-item-action:hover{color:#41464b;background-color:#cbccce}.list-group-item-secondary.list-group-item-action.active{color:#fff;background-color:#41464b;border-color:#41464b}.list-group-item-success{color:#0f5132;background-color:#d1e7dd}.list-group-item-success.list-group-item-action:focus,.list-group-item-success.list-group-item-action:hover{color:#0f5132;background-color:#bcd0c7}.list-group-item-success.list-group-item-action.active{color:#fff;background-color:#0f5132;border-color:#0f5132}.list-group-item-info{color:#055160;background-color:#cff4fc}.list-group-item-info.list-group-item-action:focus,.list-group-item-info.list-group-item-action:hover{color:#055160;background-color:#badce3}.list-group-item-info.list-group-item-action.active{color:#fff;background-color:#055160;border-color:#055160}.list-group-item-warning{color:#664d03;background-color:#fff3cd}.list-group-item-warning.list-group-item-action:focus,.list-group-item-warning.list-group-item-action:hover{color:#664d03;background-color:#e6dbb9}.list-group-item-warning.list-group-item-action.active{color:#fff;background-color:#664d03;border-color:#664d03}.list-group-item-danger{color:#842029;background-color:#f8d7da}.list-group-item-danger.list-group-item-action:focus,.list-group-item-danger.list-group-item-action:hover{color:#842029;background-color:#dfc2c4}.list-group-item-danger.list-group-item-action.active{color:#fff;background-color:#842029;border-color:#842029}.list-group-item-light{color:#636464;background-color:#fefefe}.list-group-item-light.list-group-item-action:focus,.list-group-item-light.list-group-item-action:hover{color:#636464;background-color:#e5e5e5}.list-group-item-light.list-group-item-action.active{color:#fff;background-color:#636464;border-color:#636464}.list-group-item-dark{color:#141619;background-color:#d3d3d4}.list-group-item-dark.list-group-item-action:focus,.list-group-item-dark.list-group-item-action:hover{color:#141619;background-color:#bebebf}.list-group-item-dark.list-group-item-action.active{color:#fff;background-color:#141619;border-color:#141619}.btn-close{box-sizing:content-box;width:1em;height:1em;padding:.25em .25em;color:#000;background:transparent url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 011.414 0L8 6.586 14.293.293a1 1 0 111.414 1.414L9.414 8l6.293 6.293a1 1 0 01-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 01-1.414-1.414L6.586 8 .293 1.707a1 1 0 010-1.414z'/%3e%3c/svg%3e") center/1em auto no-repeat;border:0;border-radius:.25rem;opacity:.5}.btn-close:hover{color:#000;text-decoration:none;opacity:.75}.btn-close:focus{outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25);opacity:1}.btn-close.disabled,.btn-close:disabled{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;opacity:.25}.btn-close-white{filter:invert(1) grayscale(100%) brightness(200%)}.toast{width:350px;max-width:100%;font-size:.875rem;pointer-events:auto;background-color:rgba(255,255,255,.85);background-clip:padding-box;border:1px solid rgba(0,0,0,.1);box-shadow:0 .5rem 1rem rgba(0,0,0,.15);border-radius:.25rem}.toast:not(.showing):not(.show){opacity:0}.toast.hide{display:none}.toast-container{width:-webkit-max-content;width:-moz-max-content;width:max-content;max-width:100%;pointer-events:none}.toast-container>:not(:last-child){margin-bottom:.75rem}.toast-header{display:flex;align-items:center;padding:.5rem .75rem;color:#6c757d;background-color:rgba(255,255,255,.85);background-clip:padding-box;border-bottom:1px solid rgba(0,0,0,.05);border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.toast-header .btn-close{margin-right:-.375rem;margin-left:.75rem}.toast-body{padding:.75rem;word-wrap:break-word}.modal{position:fixed;top:0;left:0;z-index:1060;display:none;width:100%;height:100%;overflow-x:hidden;overflow-y:auto;outline:0}.modal-dialog{position:relative;width:auto;margin:.5rem;pointer-events:none}.modal.fade .modal-dialog{transition:transform .3s ease-out;transform:translate(0,-50px)}@media (prefers-reduced-motion:reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{transform:none}.modal.modal-static .modal-dialog{transform:scale(1.02)}.modal-dialog-scrollable{height:calc(100% - 1rem)}.modal-dialog-scrollable .modal-content{max-height:100%;overflow:hidden}.modal-dialog-scrollable .modal-body{overflow-y:auto}.modal-dialog-centered{display:flex;align-items:center;min-height:calc(100% - 1rem)}.modal-content{position:relative;display:flex;flex-direction:column;width:100%;pointer-events:auto;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem;outline:0}.modal-backdrop{position:fixed;top:0;left:0;z-index:1040;width:100vw;height:100vh;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:.5}.modal-header{display:flex;flex-shrink:0;align-items:center;justify-content:space-between;padding:1rem 1rem;border-bottom:1px solid #dee2e6;border-top-left-radius:calc(.3rem - 1px);border-top-right-radius:calc(.3rem - 1px)}.modal-header .btn-close{padding:.5rem .5rem;margin:-.5rem -.5rem -.5rem auto}.modal-title{margin-bottom:0;line-height:1.5}.modal-body{position:relative;flex:1 1 auto;padding:1rem}.modal-footer{display:flex;flex-wrap:wrap;flex-shrink:0;align-items:center;justify-content:flex-end;padding:.75rem;border-top:1px solid #dee2e6;border-bottom-right-radius:calc(.3rem - 1px);border-bottom-left-radius:calc(.3rem - 1px)}.modal-footer>*{margin:.25rem}@media (min-width:576px){.modal-dialog{max-width:500px;margin:1.75rem auto}.modal-dialog-scrollable{height:calc(100% - 3.5rem)}.modal-dialog-centered{min-height:calc(100% - 3.5rem)}.modal-sm{max-width:300px}}@media (min-width:992px){.modal-lg,.modal-xl{max-width:600px}}@media (min-width:1200px){.modal-xl{max-width:1140px}}.modal-fullscreen{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen .modal-header{border-radius:0}.modal-fullscreen .modal-body{overflow-y:auto}.modal-fullscreen .modal-footer{border-radius:0}@media (max-width:575.98px){.modal-fullscreen-sm-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-sm-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-sm-down .modal-header{border-radius:0}.modal-fullscreen-sm-down .modal-body{overflow-y:auto}.modal-fullscreen-sm-down .modal-footer{border-radius:0}}@media (max-width:767.98px){.modal-fullscreen-md-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-md-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-md-down .modal-header{border-radius:0}.modal-fullscreen-md-down .modal-body{overflow-y:auto}.modal-fullscreen-md-down .modal-footer{border-radius:0}}@media (max-width:991.98px){.modal-fullscreen-lg-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-lg-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-lg-down .modal-header{border-radius:0}.modal-fullscreen-lg-down .modal-body{overflow-y:auto}.modal-fullscreen-lg-down .modal-footer{border-radius:0}}@media (max-width:1199.98px){.modal-fullscreen-xl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xl-down .modal-header{border-radius:0}.modal-fullscreen-xl-down .modal-body{overflow-y:auto}.modal-fullscreen-xl-down .modal-footer{border-radius:0}}@media (max-width:1399.98px){.modal-fullscreen-xxl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xxl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xxl-down .modal-header{border-radius:0}.modal-fullscreen-xxl-down .modal-body{overflow-y:auto}.modal-fullscreen-xxl-down .modal-footer{border-radius:0}}.tooltip{position:absolute;z-index:1080;display:block;margin:0;font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;opacity:0}.tooltip.show{opacity:.9}.tooltip .tooltip-arrow{position:absolute;display:block;width:.8rem;height:.4rem}.tooltip .tooltip-arrow::before{position:absolute;content:"";border-color:transparent;border-style:solid}.bs-tooltip-auto[data-popper-placement^=top],.bs-tooltip-top{padding:.4rem 0}.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow,.bs-tooltip-top .tooltip-arrow{bottom:0}.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow::before,.bs-tooltip-top .tooltip-arrow::before{top:-1px;border-width:.4rem .4rem 0;border-top-color:#000}.bs-tooltip-auto[data-popper-placement^=right],.bs-tooltip-end{padding:0 .4rem}.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow,.bs-tooltip-end .tooltip-arrow{left:0;width:.4rem;height:.8rem}.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow::before,.bs-tooltip-end .tooltip-arrow::before{right:-1px;border-width:.4rem .4rem .4rem 0;border-right-color:#000}.bs-tooltip-auto[data-popper-placement^=bottom],.bs-tooltip-bottom{padding:.4rem 0}.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow,.bs-tooltip-bottom .tooltip-arrow{top:0}.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow::before,.bs-tooltip-bottom .tooltip-arrow::before{bottom:-1px;border-width:0 .4rem .4rem;border-bottom-color:#000}.bs-tooltip-auto[data-popper-placement^=left],.bs-tooltip-start{padding:0 .4rem}.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow,.bs-tooltip-start .tooltip-arrow{right:0;width:.4rem;height:.8rem}.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow::before,.bs-tooltip-start .tooltip-arrow::before{left:-1px;border-width:.4rem 0 .4rem .4rem;border-left-color:#000}.tooltip-inner{max-width:200px;padding:.25rem .5rem;color:#fff;text-align:center;background-color:#000;border-radius:.25rem}.popover{position:absolute;top:0;left:0;z-index:1070;display:block;max-width:276px;font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem}.popover .popover-arrow{position:absolute;display:block;width:1rem;height:.5rem}.popover .popover-arrow::after,.popover .popover-arrow::before{position:absolute;display:block;content:"";border-color:transparent;border-style:solid}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow,.bs-popover-top>.popover-arrow{bottom:calc(-.5rem - 1px)}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::before,.bs-popover-top>.popover-arrow::before{bottom:0;border-width:.5rem .5rem 0;border-top-color:rgba(0,0,0,.25)}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::after,.bs-popover-top>.popover-arrow::after{bottom:1px;border-width:.5rem .5rem 0;border-top-color:#fff}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow,.bs-popover-end>.popover-arrow{left:calc(-.5rem - 1px);width:.5rem;height:1rem}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::before,.bs-popover-end>.popover-arrow::before{left:0;border-width:.5rem .5rem .5rem 0;border-right-color:rgba(0,0,0,.25)}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::after,.bs-popover-end>.popover-arrow::after{left:1px;border-width:.5rem .5rem .5rem 0;border-right-color:#fff}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow,.bs-popover-bottom>.popover-arrow{top:calc(-.5rem - 1px)}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::before,.bs-popover-bottom>.popover-arrow::before{top:0;border-width:0 .5rem .5rem .5rem;border-bottom-color:rgba(0,0,0,.25)}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::after,.bs-popover-bottom>.popover-arrow::after{top:1px;border-width:0 .5rem .5rem .5rem;border-bottom-color:#fff}.bs-popover-auto[data-popper-placement^=bottom] .popover-header::before,.bs-popover-bottom .popover-header::before{position:absolute;top:0;left:50%;display:block;width:1rem;margin-left:-.5rem;content:"";border-bottom:1px solid #f0f0f0}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow,.bs-popover-start>.popover-arrow{right:calc(-.5rem - 1px);width:.5rem;height:1rem}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::before,.bs-popover-start>.popover-arrow::before{right:0;border-width:.5rem 0 .5rem .5rem;border-left-color:rgba(0,0,0,.25)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::after,.bs-popover-start>.popover-arrow::after{right:1px;border-width:.5rem 0 .5rem .5rem;border-left-color:#fff}.popover-header{padding:.5rem 1rem;margin-bottom:0;font-size:1rem;background-color:#f0f0f0;border-bottom:1px solid rgba(0,0,0,.2);border-top-left-radius:calc(.3rem - 1px);border-top-right-radius:calc(.3rem - 1px)}.popover-header:empty{display:none}.popover-body{padding:1rem 1rem;color:#212529}.carousel{position:relative}.carousel.pointer-event{touch-action:pan-y}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner::after{display:block;clear:both;content:""}.carousel-item{position:relative;display:none;float:left;width:100%;margin-right:-100%;-webkit-backface-visibility:hidden;backface-visibility:hidden;transition:transform .6s ease-in-out}@media (prefers-reduced-motion:reduce){.carousel-item{transition:none}}.carousel-item-next,.carousel-item-prev,.carousel-item.active{display:block}.active.carousel-item-end,.carousel-item-next:not(.carousel-item-start){transform:translateX(100%)}.active.carousel-item-start,.carousel-item-prev:not(.carousel-item-end){transform:translateX(-100%)}.carousel-fade .carousel-item{opacity:0;transition-property:opacity;transform:none}.carousel-fade .carousel-item-next.carousel-item-start,.carousel-fade .carousel-item-prev.carousel-item-end,.carousel-fade .carousel-item.active{z-index:1;opacity:1}.carousel-fade .active.carousel-item-end,.carousel-fade .active.carousel-item-start{z-index:0;opacity:0;transition:opacity 0s .6s}@media (prefers-reduced-motion:reduce){.carousel-fade .active.carousel-item-end,.carousel-fade .active.carousel-item-start{transition:none}}.carousel-control-next,.carousel-control-prev{position:absolute;top:0;bottom:0;z-index:1;display:flex;align-items:center;justify-content:center;width:15%;padding:0;color:#fff;text-align:center;background:0 0;border:0;opacity:.5;transition:opacity .15s ease}@media (prefers-reduced-motion:reduce){.carousel-control-next,.carousel-control-prev{transition:none}}.carousel-control-next:focus,.carousel-control-next:hover,.carousel-control-prev:focus,.carousel-control-prev:hover{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-next-icon,.carousel-control-prev-icon{display:inline-block;width:2rem;height:2rem;background-repeat:no-repeat;background-position:50%;background-size:100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'/%3e%3c/svg%3e")}.carousel-control-next-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e")}.carousel-indicators{position:absolute;right:0;bottom:0;left:0;z-index:2;display:flex;justify-content:center;padding:0;margin-right:15%;margin-bottom:1rem;margin-left:15%;list-style:none}.carousel-indicators [data-bs-target]{box-sizing:content-box;flex:0 1 auto;width:30px;height:3px;padding:0;margin-right:3px;margin-left:3px;text-indent:-999px;cursor:pointer;background-color:#fff;background-clip:padding-box;border:0;border-top:10px solid transparent;border-bottom:10px solid transparent;opacity:.5;transition:opacity .6s ease}@media (prefers-reduced-motion:reduce){.carousel-indicators [data-bs-target]{transition:none}}.carousel-indicators .active{opacity:1}.carousel-caption{position:absolute;right:15%;bottom:1.25rem;left:15%;padding-top:1.25rem;padding-bottom:1.25rem;color:#fff;text-align:center}.carousel-dark .carousel-control-next-icon,.carousel-dark .carousel-control-prev-icon{filter:invert(1) grayscale(100)}.carousel-dark .carousel-indicators [data-bs-target]{background-color:#000}.carousel-dark .carousel-caption{color:#000}@-webkit-keyframes spinner-border{to{transform:rotate(360deg)}}@keyframes spinner-border{to{transform:rotate(360deg)}}.spinner-border{display:inline-block;width:2rem;height:2rem;vertical-align:-.125em;border:.25em solid currentColor;border-right-color:transparent;border-radius:50%;-webkit-animation:.75s linear infinite spinner-border;animation:.75s linear infinite spinner-border}.spinner-border-sm{width:1rem;height:1rem;border-width:.2em}@-webkit-keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}@keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}.spinner-grow{display:inline-block;width:2rem;height:2rem;vertical-align:-.125em;background-color:currentColor;border-radius:50%;opacity:0;-webkit-animation:.75s linear infinite spinner-grow;animation:.75s linear infinite spinner-grow}.spinner-grow-sm{width:1rem;height:1rem}@media (prefers-reduced-motion:reduce){.spinner-border,.spinner-grow{-webkit-animation-duration:1.5s;animation-duration:1.5s}}.offcanvas{position:fixed;bottom:0;z-index:1050;display:flex;flex-direction:column;max-width:100%;visibility:hidden;background-color:#fff;background-clip:padding-box;outline:0;transition:transform .3s ease-in-out}@media (prefers-reduced-motion:reduce){.offcanvas{transition:none}}.offcanvas-header{display:flex;align-items:center;justify-content:space-between;padding:1rem 1rem}.offcanvas-header .btn-close{padding:.5rem .5rem;margin-top:-.5rem;margin-right:-.5rem;margin-bottom:-.5rem}.offcanvas-title{margin-bottom:0;line-height:1.5}.offcanvas-body{flex-grow:1;padding:1rem 1rem;overflow-y:auto}.offcanvas-start{top:0;left:0;width:400px;border-right:1px solid rgba(0,0,0,.2);transform:translateX(-100%)}.offcanvas-end{top:0;right:0;width:400px;border-left:1px solid rgba(0,0,0,.2);transform:translateX(100%)}.offcanvas-top{top:0;right:0;left:0;height:30vh;max-height:100%;border-bottom:1px solid rgba(0,0,0,.2);transform:translateY(-100%)}.offcanvas-bottom{right:0;left:0;height:30vh;max-height:100%;border-top:1px solid rgba(0,0,0,.2);transform:translateY(100%)}.offcanvas.show{transform:none}.clearfix::after{display:block;clear:both;content:""}.link-primary{color:#0d6efd}.link-primary:focus,.link-primary:hover{color:#0a58ca}.link-secondary{color:#6c757d}.link-secondary:focus,.link-secondary:hover{color:#565e64}.link-success{color:#198754}.link-success:focus,.link-success:hover{color:#146c43}.link-info{color:#0dcaf0}.link-info:focus,.link-info:hover{color:#3dd5f3}.link-warning{color:#ffc107}.link-warning:focus,.link-warning:hover{color:#ffcd39}.link-danger{color:#dc3545}.link-danger:focus,.link-danger:hover{color:#b02a37}.link-light{color:#f8f9fa}.link-light:focus,.link-light:hover{color:#f9fafb}.link-dark{color:#212529}.link-dark:focus,.link-dark:hover{color:#1a1e21}.ratio{position:relative;width:100%}.ratio::before{display:block;padding-top:var(--bs-aspect-ratio);content:""}.ratio>*{position:absolute;top:0;left:0;width:100%;height:100%}.ratio-1x1{--bs-aspect-ratio:100%}.ratio-4x3{--bs-aspect-ratio:calc(3 / 4 * 100%)}.ratio-16x9{--bs-aspect-ratio:calc(9 / 16 * 100%)}.ratio-21x9{--bs-aspect-ratio:calc(9 / 21 * 100%)}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}.sticky-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}@media (min-width:576px){.sticky-sm-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}@media (min-width:768px){.sticky-md-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}@media (min-width:992px){.sticky-lg-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}@media (min-width:1200px){.sticky-xl-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}@media (min-width:1400px){.sticky-xxl-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}.visually-hidden,.visually-hidden-focusable:not(:focus):not(:focus-within){position:absolute!important;width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important}.stretched-link::after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;content:""}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.align-baseline{vertical-align:baseline!important}.align-top{vertical-align:top!important}.align-middle{vertical-align:middle!important}.align-bottom{vertical-align:bottom!important}.align-text-bottom{vertical-align:text-bottom!important}.align-text-top{vertical-align:text-top!important}.float-start{float:left!important}.float-end{float:right!important}.float-none{float:none!important}.overflow-auto{overflow:auto!important}.overflow-hidden{overflow:hidden!important}.overflow-visible{overflow:visible!important}.overflow-scroll{overflow:scroll!important}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-grid{display:grid!important}.d-table{display:table!important}.d-table-row{display:table-row!important}.d-table-cell{display:table-cell!important}.d-flex{display:flex!important}.d-inline-flex{display:inline-flex!important}.d-none{display:none!important}.shadow{box-shadow:0 .5rem 1rem rgba(0,0,0,.15)!important}.shadow-sm{box-shadow:0 .125rem .25rem rgba(0,0,0,.075)!important}.shadow-lg{box-shadow:0 1rem 3rem rgba(0,0,0,.175)!important}.shadow-none{box-shadow:none!important}.position-static{position:static!important}.position-relative{position:relative!important}.position-absolute{position:absolute!important}.position-fixed{position:fixed!important}.position-sticky{position:-webkit-sticky!important;position:sticky!important}.top-0{top:0!important}.top-50{top:50%!important}.top-100{top:100%!important}.bottom-0{bottom:0!important}.bottom-50{bottom:50%!important}.bottom-100{bottom:100%!important}.start-0{left:0!important}.start-50{left:50%!important}.start-100{left:100%!important}.end-0{right:0!important}.end-50{right:50%!important}.end-100{right:100%!important}.translate-middle{transform:translate(-50%,-50%)!important}.translate-middle-x{transform:translateX(-50%)!important}.translate-middle-y{transform:translateY(-50%)!important}.border{border:1px solid #dee2e6!important}.border-0{border:0!important}.border-top{border-top:1px solid #dee2e6!important}.border-top-0{border-top:0!important}.border-end{border-right:1px solid #dee2e6!important}.border-end-0{border-right:0!important}.border-bottom{border-bottom:1px solid #dee2e6!important}.border-bottom-0{border-bottom:0!important}.border-start{border-left:1px solid #dee2e6!important}.border-start-0{border-left:0!important}.border-primary{border-color:#0d6efd!important}.border-secondary{border-color:#6c757d!important}.border-success{border-color:#198754!important}.border-info{border-color:#0dcaf0!important}.border-warning{border-color:#ffc107!important}.border-danger{border-color:#dc3545!important}.border-light{border-color:#f8f9fa!important}.border-dark{border-color:#212529!important}.border-white{border-color:#fff!important}.border-1{border-width:1px!important}.border-2{border-width:2px!important}.border-3{border-width:3px!important}.border-4{border-width:4px!important}.border-5{border-width:5px!important}.w-25{width:25%!important}.w-50{width:50%!important}.w-75{width:75%!important}.w-100{width:100%!important}.w-auto{width:auto!important}.mw-100{max-width:100%!important}.vw-100{width:100vw!important}.min-vw-100{min-width:100vw!important}.h-25{height:25%!important}.h-50{height:50%!important}.h-75{height:75%!important}.h-100{height:100%!important}.h-auto{height:auto!important}.mh-100{max-height:100%!important}.vh-100{height:100vh!important}.min-vh-100{min-height:100vh!important}.flex-fill{flex:1 1 auto!important}.flex-row{flex-direction:row!important}.flex-column{flex-direction:column!important}.flex-row-reverse{flex-direction:row-reverse!important}.flex-column-reverse{flex-direction:column-reverse!important}.flex-grow-0{flex-grow:0!important}.flex-grow-1{flex-grow:1!important}.flex-shrink-0{flex-shrink:0!important}.flex-shrink-1{flex-shrink:1!important}.flex-wrap{flex-wrap:wrap!important}.flex-nowrap{flex-wrap:nowrap!important}.flex-wrap-reverse{flex-wrap:wrap-reverse!important}.gap-0{gap:0!important}.gap-1{gap:.25rem!important}.gap-2{gap:.5rem!important}.gap-3{gap:1rem!important}.gap-4{gap:1.5rem!important}.gap-5{gap:3rem!important}.justify-content-start{justify-content:flex-start!important}.justify-content-end{justify-content:flex-end!important}.justify-content-center{justify-content:center!important}.justify-content-between{justify-content:space-between!important}.justify-content-around{justify-content:space-around!important}.justify-content-evenly{justify-content:space-evenly!important}.align-items-start{align-items:flex-start!important}.align-items-end{align-items:flex-end!important}.align-items-center{align-items:center!important}.align-items-baseline{align-items:baseline!important}.align-items-stretch{align-items:stretch!important}.align-content-start{align-content:flex-start!important}.align-content-end{align-content:flex-end!important}.align-content-center{align-content:center!important}.align-content-between{align-content:space-between!important}.align-content-around{align-content:space-around!important}.align-content-stretch{align-content:stretch!important}.align-self-auto{align-self:auto!important}.align-self-start{align-self:flex-start!important}.align-self-end{align-self:flex-end!important}.align-self-center{align-self:center!important}.align-self-baseline{align-self:baseline!important}.align-self-stretch{align-self:stretch!important}.order-first{order:-1!important}.order-0{order:0!important}.order-1{order:1!important}.order-2{order:2!important}.order-3{order:3!important}.order-4{order:4!important}.order-5{order:5!important}.order-last{order:6!important}.m-0{margin:0!important}.m-1{margin:.25rem!important}.m-2{margin:.5rem!important}.m-3{margin:1rem!important}.m-4{margin:1.5rem!important}.m-5{margin:3rem!important}.m-auto{margin:auto!important}.mx-0{margin-right:0!important;margin-left:0!important}.mx-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-3{margin-right:1rem!important;margin-left:1rem!important}.mx-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-5{margin-right:3rem!important;margin-left:3rem!important}.mx-auto{margin-right:auto!important;margin-left:auto!important}.my-0{margin-top:0!important;margin-bottom:0!important}.my-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-0{margin-top:0!important}.mt-1{margin-top:.25rem!important}.mt-2{margin-top:.5rem!important}.mt-3{margin-top:1rem!important}.mt-4{margin-top:1.5rem!important}.mt-5{margin-top:3rem!important}.mt-auto{margin-top:auto!important}.me-0{margin-right:0!important}.me-1{margin-right:.25rem!important}.me-2{margin-right:.5rem!important}.me-3{margin-right:1rem!important}.me-4{margin-right:1.5rem!important}.me-5{margin-right:3rem!important}.me-auto{margin-right:auto!important}.mb-0{margin-bottom:0!important}.mb-1{margin-bottom:.25rem!important}.mb-2{margin-bottom:.5rem!important}.mb-3{margin-bottom:1rem!important}.mb-4{margin-bottom:1.5rem!important}.mb-5{margin-bottom:3rem!important}.mb-auto{margin-bottom:auto!important}.ms-0{margin-left:0!important}.ms-1{margin-left:.25rem!important}.ms-2{margin-left:.5rem!important}.ms-3{margin-left:1rem!important}.ms-4{margin-left:1.5rem!important}.ms-5{margin-left:3rem!important}.ms-auto{margin-left:auto!important}.p-0{padding:0!important}.p-1{padding:.25rem!important}.p-2{padding:.5rem!important}.p-3{padding:1rem!important}.p-4{padding:1.5rem!important}.p-5{padding:3rem!important}.px-0{padding-right:0!important;padding-left:0!important}.px-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-3{padding-right:1rem!important;padding-left:1rem!important}.px-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-5{padding-right:3rem!important;padding-left:3rem!important}.py-0{padding-top:0!important;padding-bottom:0!important}.py-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-0{padding-top:0!important}.pt-1{padding-top:.25rem!important}.pt-2{padding-top:.5rem!important}.pt-3{padding-top:1rem!important}.pt-4{padding-top:1.5rem!important}.pt-5{padding-top:3rem!important}.pe-0{padding-right:0!important}.pe-1{padding-right:.25rem!important}.pe-2{padding-right:.5rem!important}.pe-3{padding-right:1rem!important}.pe-4{padding-right:1.5rem!important}.pe-5{padding-right:3rem!important}.pb-0{padding-bottom:0!important}.pb-1{padding-bottom:.25rem!important}.pb-2{padding-bottom:.5rem!important}.pb-3{padding-bottom:1rem!important}.pb-4{padding-bottom:1.5rem!important}.pb-5{padding-bottom:3rem!important}.ps-0{padding-left:0!important}.ps-1{padding-left:.25rem!important}.ps-2{padding-left:.5rem!important}.ps-3{padding-left:1rem!important}.ps-4{padding-left:1.5rem!important}.ps-5{padding-left:3rem!important}.font-monospace{font-family:var(--bs-font-monospace)!important}.fs-1{font-size:calc(1.375rem + 1.5vw)!important}.fs-2{font-size:calc(1.325rem + .9vw)!important}.fs-3{font-size:calc(1.3rem + .6vw)!important}.fs-4{font-size:calc(1.275rem + .3vw)!important}.fs-5{font-size:1.25rem!important}.fs-6{font-size:1rem!important}.fst-italic{font-style:italic!important}.fst-normal{font-style:normal!important}.fw-light{font-weight:300!important}.fw-lighter{font-weight:lighter!important}.fw-normal{font-weight:400!important}.fw-bold{font-weight:700!important}.fw-bolder{font-weight:bolder!important}.lh-1{line-height:1!important}.lh-sm{line-height:1.25!important}.lh-base{line-height:1.5!important}.lh-lg{line-height:2!important}.text-start{text-align:left!important}.text-end{text-align:right!important}.text-center{text-align:center!important}.text-decoration-none{text-decoration:none!important}.text-decoration-underline{text-decoration:underline!important}.text-decoration-line-through{text-decoration:line-through!important}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.text-wrap{white-space:normal!important}.text-nowrap{white-space:nowrap!important}.text-break{word-wrap:break-word!important;word-break:break-word!important}.text-primary{color:#0d6efd!important}.text-secondary{color:#6c757d!important}.text-success{color:#198754!important}.text-info{color:#0dcaf0!important}.text-warning{color:#ffc107!important}.text-danger{color:#dc3545!important}.text-light{color:#f8f9fa!important}.text-dark{color:#212529!important}.text-white{color:#fff!important}.text-body{color:#212529!important}.text-muted{color:#6c757d!important}.text-black-50{color:rgba(0,0,0,.5)!important}.text-white-50{color:rgba(255,255,255,.5)!important}.text-reset{color:inherit!important}.bg-primary{background-color:#0d6efd!important}.bg-secondary{background-color:#6c757d!important}.bg-success{background-color:#198754!important}.bg-info{background-color:#0dcaf0!important}.bg-warning{background-color:#ffc107!important}.bg-danger{background-color:#dc3545!important}.bg-light{background-color:#f8f9fa!important}.bg-dark{background-color:#212529!important}.bg-body{background-color:#fff!important}.bg-white{background-color:#fff!important}.bg-transparent{background-color:transparent!important}.bg-gradient{background-image:var(--bs-gradient)!important}.user-select-all{-webkit-user-select:all!important;-moz-user-select:all!important;user-select:all!important}.user-select-auto{-webkit-user-select:auto!important;-moz-user-select:auto!important;user-select:auto!important}.user-select-none{-webkit-user-select:none!important;-moz-user-select:none!important;user-select:none!important}.pe-none{pointer-events:none!important}.pe-auto{pointer-events:auto!important}.rounded{border-radius:.25rem!important}.rounded-0{border-radius:0!important}.rounded-1{border-radius:.2rem!important}.rounded-2{border-radius:.25rem!important}.rounded-3{border-radius:.3rem!important}.rounded-circle{border-radius:50%!important}.rounded-pill{border-radius:50rem!important}.rounded-top{border-top-left-radius:.25rem!important;border-top-right-radius:.25rem!important}.rounded-end{border-top-right-radius:.25rem!important;border-bottom-right-radius:.25rem!important}.rounded-bottom{border-bottom-right-radius:.25rem!important;border-bottom-left-radius:.25rem!important}.rounded-start{border-bottom-left-radius:.25rem!important;border-top-left-radius:.25rem!important}.visible{visibility:visible!important}.invisible{visibility:hidden!important}@media (min-width:576px){.float-sm-start{float:left!important}.float-sm-end{float:right!important}.float-sm-none{float:none!important}.d-sm-inline{display:inline!important}.d-sm-inline-block{display:inline-block!important}.d-sm-block{display:block!important}.d-sm-grid{display:grid!important}.d-sm-table{display:table!important}.d-sm-table-row{display:table-row!important}.d-sm-table-cell{display:table-cell!important}.d-sm-flex{display:flex!important}.d-sm-inline-flex{display:inline-flex!important}.d-sm-none{display:none!important}.flex-sm-fill{flex:1 1 auto!important}.flex-sm-row{flex-direction:row!important}.flex-sm-column{flex-direction:column!important}.flex-sm-row-reverse{flex-direction:row-reverse!important}.flex-sm-column-reverse{flex-direction:column-reverse!important}.flex-sm-grow-0{flex-grow:0!important}.flex-sm-grow-1{flex-grow:1!important}.flex-sm-shrink-0{flex-shrink:0!important}.flex-sm-shrink-1{flex-shrink:1!important}.flex-sm-wrap{flex-wrap:wrap!important}.flex-sm-nowrap{flex-wrap:nowrap!important}.flex-sm-wrap-reverse{flex-wrap:wrap-reverse!important}.gap-sm-0{gap:0!important}.gap-sm-1{gap:.25rem!important}.gap-sm-2{gap:.5rem!important}.gap-sm-3{gap:1rem!important}.gap-sm-4{gap:1.5rem!important}.gap-sm-5{gap:3rem!important}.justify-content-sm-start{justify-content:flex-start!important}.justify-content-sm-end{justify-content:flex-end!important}.justify-content-sm-center{justify-content:center!important}.justify-content-sm-between{justify-content:space-between!important}.justify-content-sm-around{justify-content:space-around!important}.justify-content-sm-evenly{justify-content:space-evenly!important}.align-items-sm-start{align-items:flex-start!important}.align-items-sm-end{align-items:flex-end!important}.align-items-sm-center{align-items:center!important}.align-items-sm-baseline{align-items:baseline!important}.align-items-sm-stretch{align-items:stretch!important}.align-content-sm-start{align-content:flex-start!important}.align-content-sm-end{align-content:flex-end!important}.align-content-sm-center{align-content:center!important}.align-content-sm-between{align-content:space-between!important}.align-content-sm-around{align-content:space-around!important}.align-content-sm-stretch{align-content:stretch!important}.align-self-sm-auto{align-self:auto!important}.align-self-sm-start{align-self:flex-start!important}.align-self-sm-end{align-self:flex-end!important}.align-self-sm-center{align-self:center!important}.align-self-sm-baseline{align-self:baseline!important}.align-self-sm-stretch{align-self:stretch!important}.order-sm-first{order:-1!important}.order-sm-0{order:0!important}.order-sm-1{order:1!important}.order-sm-2{order:2!important}.order-sm-3{order:3!important}.order-sm-4{order:4!important}.order-sm-5{order:5!important}.order-sm-last{order:6!important}.m-sm-0{margin:0!important}.m-sm-1{margin:.25rem!important}.m-sm-2{margin:.5rem!important}.m-sm-3{margin:1rem!important}.m-sm-4{margin:1.5rem!important}.m-sm-5{margin:3rem!important}.m-sm-auto{margin:auto!important}.mx-sm-0{margin-right:0!important;margin-left:0!important}.mx-sm-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-sm-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-sm-3{margin-right:1rem!important;margin-left:1rem!important}.mx-sm-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-sm-5{margin-right:3rem!important;margin-left:3rem!important}.mx-sm-auto{margin-right:auto!important;margin-left:auto!important}.my-sm-0{margin-top:0!important;margin-bottom:0!important}.my-sm-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-sm-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-sm-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-sm-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-sm-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-sm-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-sm-0{margin-top:0!important}.mt-sm-1{margin-top:.25rem!important}.mt-sm-2{margin-top:.5rem!important}.mt-sm-3{margin-top:1rem!important}.mt-sm-4{margin-top:1.5rem!important}.mt-sm-5{margin-top:3rem!important}.mt-sm-auto{margin-top:auto!important}.me-sm-0{margin-right:0!important}.me-sm-1{margin-right:.25rem!important}.me-sm-2{margin-right:.5rem!important}.me-sm-3{margin-right:1rem!important}.me-sm-4{margin-right:1.5rem!important}.me-sm-5{margin-right:3rem!important}.me-sm-auto{margin-right:auto!important}.mb-sm-0{margin-bottom:0!important}.mb-sm-1{margin-bottom:.25rem!important}.mb-sm-2{margin-bottom:.5rem!important}.mb-sm-3{margin-bottom:1rem!important}.mb-sm-4{margin-bottom:1.5rem!important}.mb-sm-5{margin-bottom:3rem!important}.mb-sm-auto{margin-bottom:auto!important}.ms-sm-0{margin-left:0!important}.ms-sm-1{margin-left:.25rem!important}.ms-sm-2{margin-left:.5rem!important}.ms-sm-3{margin-left:1rem!important}.ms-sm-4{margin-left:1.5rem!important}.ms-sm-5{margin-left:3rem!important}.ms-sm-auto{margin-left:auto!important}.p-sm-0{padding:0!important}.p-sm-1{padding:.25rem!important}.p-sm-2{padding:.5rem!important}.p-sm-3{padding:1rem!important}.p-sm-4{padding:1.5rem!important}.p-sm-5{padding:3rem!important}.px-sm-0{padding-right:0!important;padding-left:0!important}.px-sm-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-sm-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-sm-3{padding-right:1rem!important;padding-left:1rem!important}.px-sm-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-sm-5{padding-right:3rem!important;padding-left:3rem!important}.py-sm-0{padding-top:0!important;padding-bottom:0!important}.py-sm-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-sm-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-sm-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-sm-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-sm-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-sm-0{padding-top:0!important}.pt-sm-1{padding-top:.25rem!important}.pt-sm-2{padding-top:.5rem!important}.pt-sm-3{padding-top:1rem!important}.pt-sm-4{padding-top:1.5rem!important}.pt-sm-5{padding-top:3rem!important}.pe-sm-0{padding-right:0!important}.pe-sm-1{padding-right:.25rem!important}.pe-sm-2{padding-right:.5rem!important}.pe-sm-3{padding-right:1rem!important}.pe-sm-4{padding-right:1.5rem!important}.pe-sm-5{padding-right:3rem!important}.pb-sm-0{padding-bottom:0!important}.pb-sm-1{padding-bottom:.25rem!important}.pb-sm-2{padding-bottom:.5rem!important}.pb-sm-3{padding-bottom:1rem!important}.pb-sm-4{padding-bottom:1.5rem!important}.pb-sm-5{padding-bottom:3rem!important}.ps-sm-0{padding-left:0!important}.ps-sm-1{padding-left:.25rem!important}.ps-sm-2{padding-left:.5rem!important}.ps-sm-3{padding-left:1rem!important}.ps-sm-4{padding-left:1.5rem!important}.ps-sm-5{padding-left:3rem!important}.text-sm-start{text-align:left!important}.text-sm-end{text-align:right!important}.text-sm-center{text-align:center!important}}@media (min-width:768px){.float-md-start{float:left!important}.float-md-end{float:right!important}.float-md-none{float:none!important}.d-md-inline{display:inline!important}.d-md-inline-block{display:inline-block!important}.d-md-block{display:block!important}.d-md-grid{display:grid!important}.d-md-table{display:table!important}.d-md-table-row{display:table-row!important}.d-md-table-cell{display:table-cell!important}.d-md-flex{display:flex!important}.d-md-inline-flex{display:inline-flex!important}.d-md-none{display:none!important}.flex-md-fill{flex:1 1 auto!important}.flex-md-row{flex-direction:row!important}.flex-md-column{flex-direction:column!important}.flex-md-row-reverse{flex-direction:row-reverse!important}.flex-md-column-reverse{flex-direction:column-reverse!important}.flex-md-grow-0{flex-grow:0!important}.flex-md-grow-1{flex-grow:1!important}.flex-md-shrink-0{flex-shrink:0!important}.flex-md-shrink-1{flex-shrink:1!important}.flex-md-wrap{flex-wrap:wrap!important}.flex-md-nowrap{flex-wrap:nowrap!important}.flex-md-wrap-reverse{flex-wrap:wrap-reverse!important}.gap-md-0{gap:0!important}.gap-md-1{gap:.25rem!important}.gap-md-2{gap:.5rem!important}.gap-md-3{gap:1rem!important}.gap-md-4{gap:1.5rem!important}.gap-md-5{gap:3rem!important}.justify-content-md-start{justify-content:flex-start!important}.justify-content-md-end{justify-content:flex-end!important}.justify-content-md-center{justify-content:center!important}.justify-content-md-between{justify-content:space-between!important}.justify-content-md-around{justify-content:space-around!important}.justify-content-md-evenly{justify-content:space-evenly!important}.align-items-md-start{align-items:flex-start!important}.align-items-md-end{align-items:flex-end!important}.align-items-md-center{align-items:center!important}.align-items-md-baseline{align-items:baseline!important}.align-items-md-stretch{align-items:stretch!important}.align-content-md-start{align-content:flex-start!important}.align-content-md-end{align-content:flex-end!important}.align-content-md-center{align-content:center!important}.align-content-md-between{align-content:space-between!important}.align-content-md-around{align-content:space-around!important}.align-content-md-stretch{align-content:stretch!important}.align-self-md-auto{align-self:auto!important}.align-self-md-start{align-self:flex-start!important}.align-self-md-end{align-self:flex-end!important}.align-self-md-center{align-self:center!important}.align-self-md-baseline{align-self:baseline!important}.align-self-md-stretch{align-self:stretch!important}.order-md-first{order:-1!important}.order-md-0{order:0!important}.order-md-1{order:1!important}.order-md-2{order:2!important}.order-md-3{order:3!important}.order-md-4{order:4!important}.order-md-5{order:5!important}.order-md-last{order:6!important}.m-md-0{margin:0!important}.m-md-1{margin:.25rem!important}.m-md-2{margin:.5rem!important}.m-md-3{margin:1rem!important}.m-md-4{margin:1.5rem!important}.m-md-5{margin:3rem!important}.m-md-auto{margin:auto!important}.mx-md-0{margin-right:0!important;margin-left:0!important}.mx-md-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-md-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-md-3{margin-right:1rem!important;margin-left:1rem!important}.mx-md-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-md-5{margin-right:3rem!important;margin-left:3rem!important}.mx-md-auto{margin-right:auto!important;margin-left:auto!important}.my-md-0{margin-top:0!important;margin-bottom:0!important}.my-md-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-md-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-md-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-md-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-md-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-md-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-md-0{margin-top:0!important}.mt-md-1{margin-top:.25rem!important}.mt-md-2{margin-top:.5rem!important}.mt-md-3{margin-top:1rem!important}.mt-md-4{margin-top:1.5rem!important}.mt-md-5{margin-top:3rem!important}.mt-md-auto{margin-top:auto!important}.me-md-0{margin-right:0!important}.me-md-1{margin-right:.25rem!important}.me-md-2{margin-right:.5rem!important}.me-md-3{margin-right:1rem!important}.me-md-4{margin-right:1.5rem!important}.me-md-5{margin-right:3rem!important}.me-md-auto{margin-right:auto!important}.mb-md-0{margin-bottom:0!important}.mb-md-1{margin-bottom:.25rem!important}.mb-md-2{margin-bottom:.5rem!important}.mb-md-3{margin-bottom:1rem!important}.mb-md-4{margin-bottom:1.5rem!important}.mb-md-5{margin-bottom:3rem!important}.mb-md-auto{margin-bottom:auto!important}.ms-md-0{margin-left:0!important}.ms-md-1{margin-left:.25rem!important}.ms-md-2{margin-left:.5rem!important}.ms-md-3{margin-left:1rem!important}.ms-md-4{margin-left:1.5rem!important}.ms-md-5{margin-left:3rem!important}.ms-md-auto{margin-left:auto!important}.p-md-0{padding:0!important}.p-md-1{padding:.25rem!important}.p-md-2{padding:.5rem!important}.p-md-3{padding:1rem!important}.p-md-4{padding:1.5rem!important}.p-md-5{padding:3rem!important}.px-md-0{padding-right:0!important;padding-left:0!important}.px-md-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-md-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-md-3{padding-right:1rem!important;padding-left:1rem!important}.px-md-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-md-5{padding-right:3rem!important;padding-left:3rem!important}.py-md-0{padding-top:0!important;padding-bottom:0!important}.py-md-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-md-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-md-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-md-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-md-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-md-0{padding-top:0!important}.pt-md-1{padding-top:.25rem!important}.pt-md-2{padding-top:.5rem!important}.pt-md-3{padding-top:1rem!important}.pt-md-4{padding-top:1.5rem!important}.pt-md-5{padding-top:3rem!important}.pe-md-0{padding-right:0!important}.pe-md-1{padding-right:.25rem!important}.pe-md-2{padding-right:.5rem!important}.pe-md-3{padding-right:1rem!important}.pe-md-4{padding-right:1.5rem!important}.pe-md-5{padding-right:3rem!important}.pb-md-0{padding-bottom:0!important}.pb-md-1{padding-bottom:.25rem!important}.pb-md-2{padding-bottom:.5rem!important}.pb-md-3{padding-bottom:1rem!important}.pb-md-4{padding-bottom:1.5rem!important}.pb-md-5{padding-bottom:3rem!important}.ps-md-0{padding-left:0!important}.ps-md-1{padding-left:.25rem!important}.ps-md-2{padding-left:.5rem!important}.ps-md-3{padding-left:1rem!important}.ps-md-4{padding-left:1.5rem!important}.ps-md-5{padding-left:3rem!important}.text-md-start{text-align:left!important}.text-md-end{text-align:right!important}.text-md-center{text-align:center!important}}@media (min-width:992px){.float-lg-start{float:left!important}.float-lg-end{float:right!important}.float-lg-none{float:none!important}.d-lg-inline{display:inline!important}.d-lg-inline-block{display:inline-block!important}.d-lg-block{display:block!important}.d-lg-grid{display:grid!important}.d-lg-table{display:table!important}.d-lg-table-row{display:table-row!important}.d-lg-table-cell{display:table-cell!important}.d-lg-flex{display:flex!important}.d-lg-inline-flex{display:inline-flex!important}.d-lg-none{display:none!important}.flex-lg-fill{flex:1 1 auto!important}.flex-lg-row{flex-direction:row!important}.flex-lg-column{flex-direction:column!important}.flex-lg-row-reverse{flex-direction:row-reverse!important}.flex-lg-column-reverse{flex-direction:column-reverse!important}.flex-lg-grow-0{flex-grow:0!important}.flex-lg-grow-1{flex-grow:1!important}.flex-lg-shrink-0{flex-shrink:0!important}.flex-lg-shrink-1{flex-shrink:1!important}.flex-lg-wrap{flex-wrap:wrap!important}.flex-lg-nowrap{flex-wrap:nowrap!important}.flex-lg-wrap-reverse{flex-wrap:wrap-reverse!important}.gap-lg-0{gap:0!important}.gap-lg-1{gap:.25rem!important}.gap-lg-2{gap:.5rem!important}.gap-lg-3{gap:1rem!important}.gap-lg-4{gap:1.5rem!important}.gap-lg-5{gap:3rem!important}.justify-content-lg-start{justify-content:flex-start!important}.justify-content-lg-end{justify-content:flex-end!important}.justify-content-lg-center{justify-content:center!important}.justify-content-lg-between{justify-content:space-between!important}.justify-content-lg-around{justify-content:space-around!important}.justify-content-lg-evenly{justify-content:space-evenly!important}.align-items-lg-start{align-items:flex-start!important}.align-items-lg-end{align-items:flex-end!important}.align-items-lg-center{align-items:center!important}.align-items-lg-baseline{align-items:baseline!important}.align-items-lg-stretch{align-items:stretch!important}.align-content-lg-start{align-content:flex-start!important}.align-content-lg-end{align-content:flex-end!important}.align-content-lg-center{align-content:center!important}.align-content-lg-between{align-content:space-between!important}.align-content-lg-around{align-content:space-around!important}.align-content-lg-stretch{align-content:stretch!important}.align-self-lg-auto{align-self:auto!important}.align-self-lg-start{align-self:flex-start!important}.align-self-lg-end{align-self:flex-end!important}.align-self-lg-center{align-self:center!important}.align-self-lg-baseline{align-self:baseline!important}.align-self-lg-stretch{align-self:stretch!important}.order-lg-first{order:-1!important}.order-lg-0{order:0!important}.order-lg-1{order:1!important}.order-lg-2{order:2!important}.order-lg-3{order:3!important}.order-lg-4{order:4!important}.order-lg-5{order:5!important}.order-lg-last{order:6!important}.m-lg-0{margin:0!important}.m-lg-1{margin:.25rem!important}.m-lg-2{margin:.5rem!important}.m-lg-3{margin:1rem!important}.m-lg-4{margin:1.5rem!important}.m-lg-5{margin:3rem!important}.m-lg-auto{margin:auto!important}.mx-lg-0{margin-right:0!important;margin-left:0!important}.mx-lg-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-lg-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-lg-3{margin-right:1rem!important;margin-left:1rem!important}.mx-lg-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-lg-5{margin-right:3rem!important;margin-left:3rem!important}.mx-lg-auto{margin-right:auto!important;margin-left:auto!important}.my-lg-0{margin-top:0!important;margin-bottom:0!important}.my-lg-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-lg-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-lg-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-lg-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-lg-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-lg-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-lg-0{margin-top:0!important}.mt-lg-1{margin-top:.25rem!important}.mt-lg-2{margin-top:.5rem!important}.mt-lg-3{margin-top:1rem!important}.mt-lg-4{margin-top:1.5rem!important}.mt-lg-5{margin-top:3rem!important}.mt-lg-auto{margin-top:auto!important}.me-lg-0{margin-right:0!important}.me-lg-1{margin-right:.25rem!important}.me-lg-2{margin-right:.5rem!important}.me-lg-3{margin-right:1rem!important}.me-lg-4{margin-right:1.5rem!important}.me-lg-5{margin-right:3rem!important}.me-lg-auto{margin-right:auto!important}.mb-lg-0{margin-bottom:0!important}.mb-lg-1{margin-bottom:.25rem!important}.mb-lg-2{margin-bottom:.5rem!important}.mb-lg-3{margin-bottom:1rem!important}.mb-lg-4{margin-bottom:1.5rem!important}.mb-lg-5{margin-bottom:3rem!important}.mb-lg-auto{margin-bottom:auto!important}.ms-lg-0{margin-left:0!important}.ms-lg-1{margin-left:.25rem!important}.ms-lg-2{margin-left:.5rem!important}.ms-lg-3{margin-left:1rem!important}.ms-lg-4{margin-left:1.5rem!important}.ms-lg-5{margin-left:3rem!important}.ms-lg-auto{margin-left:auto!important}.p-lg-0{padding:0!important}.p-lg-1{padding:.25rem!important}.p-lg-2{padding:.5rem!important}.p-lg-3{padding:1rem!important}.p-lg-4{padding:1.5rem!important}.p-lg-5{padding:3rem!important}.px-lg-0{padding-right:0!important;padding-left:0!important}.px-lg-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-lg-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-lg-3{padding-right:1rem!important;padding-left:1rem!important}.px-lg-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-lg-5{padding-right:3rem!important;padding-left:3rem!important}.py-lg-0{padding-top:0!important;padding-bottom:0!important}.py-lg-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-lg-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-lg-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-lg-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-lg-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-lg-0{padding-top:0!important}.pt-lg-1{padding-top:.25rem!important}.pt-lg-2{padding-top:.5rem!important}.pt-lg-3{padding-top:1rem!important}.pt-lg-4{padding-top:1.5rem!important}.pt-lg-5{padding-top:3rem!important}.pe-lg-0{padding-right:0!important}.pe-lg-1{padding-right:.25rem!important}.pe-lg-2{padding-right:.5rem!important}.pe-lg-3{padding-right:1rem!important}.pe-lg-4{padding-right:1.5rem!important}.pe-lg-5{padding-right:3rem!important}.pb-lg-0{padding-bottom:0!important}.pb-lg-1{padding-bottom:.25rem!important}.pb-lg-2{padding-bottom:.5rem!important}.pb-lg-3{padding-bottom:1rem!important}.pb-lg-4{padding-bottom:1.5rem!important}.pb-lg-5{padding-bottom:3rem!important}.ps-lg-0{padding-left:0!important}.ps-lg-1{padding-left:.25rem!important}.ps-lg-2{padding-left:.5rem!important}.ps-lg-3{padding-left:1rem!important}.ps-lg-4{padding-left:1.5rem!important}.ps-lg-5{padding-left:3rem!important}.text-lg-start{text-align:left!important}.text-lg-end{text-align:right!important}.text-lg-center{text-align:center!important}}@media (min-width:1200px){.float-xl-start{float:left!important}.float-xl-end{float:right!important}.float-xl-none{float:none!important}.d-xl-inline{display:inline!important}.d-xl-inline-block{display:inline-block!important}.d-xl-block{display:block!important}.d-xl-grid{display:grid!important}.d-xl-table{display:table!important}.d-xl-table-row{display:table-row!important}.d-xl-table-cell{display:table-cell!important}.d-xl-flex{display:flex!important}.d-xl-inline-flex{display:inline-flex!important}.d-xl-none{display:none!important}.flex-xl-fill{flex:1 1 auto!important}.flex-xl-row{flex-direction:row!important}.flex-xl-column{flex-direction:column!important}.flex-xl-row-reverse{flex-direction:row-reverse!important}.flex-xl-column-reverse{flex-direction:column-reverse!important}.flex-xl-grow-0{flex-grow:0!important}.flex-xl-grow-1{flex-grow:1!important}.flex-xl-shrink-0{flex-shrink:0!important}.flex-xl-shrink-1{flex-shrink:1!important}.flex-xl-wrap{flex-wrap:wrap!important}.flex-xl-nowrap{flex-wrap:nowrap!important}.flex-xl-wrap-reverse{flex-wrap:wrap-reverse!important}.gap-xl-0{gap:0!important}.gap-xl-1{gap:.25rem!important}.gap-xl-2{gap:.5rem!important}.gap-xl-3{gap:1rem!important}.gap-xl-4{gap:1.5rem!important}.gap-xl-5{gap:3rem!important}.justify-content-xl-start{justify-content:flex-start!important}.justify-content-xl-end{justify-content:flex-end!important}.justify-content-xl-center{justify-content:center!important}.justify-content-xl-between{justify-content:space-between!important}.justify-content-xl-around{justify-content:space-around!important}.justify-content-xl-evenly{justify-content:space-evenly!important}.align-items-xl-start{align-items:flex-start!important}.align-items-xl-end{align-items:flex-end!important}.align-items-xl-center{align-items:center!important}.align-items-xl-baseline{align-items:baseline!important}.align-items-xl-stretch{align-items:stretch!important}.align-content-xl-start{align-content:flex-start!important}.align-content-xl-end{align-content:flex-end!important}.align-content-xl-center{align-content:center!important}.align-content-xl-between{align-content:space-between!important}.align-content-xl-around{align-content:space-around!important}.align-content-xl-stretch{align-content:stretch!important}.align-self-xl-auto{align-self:auto!important}.align-self-xl-start{align-self:flex-start!important}.align-self-xl-end{align-self:flex-end!important}.align-self-xl-center{align-self:center!important}.align-self-xl-baseline{align-self:baseline!important}.align-self-xl-stretch{align-self:stretch!important}.order-xl-first{order:-1!important}.order-xl-0{order:0!important}.order-xl-1{order:1!important}.order-xl-2{order:2!important}.order-xl-3{order:3!important}.order-xl-4{order:4!important}.order-xl-5{order:5!important}.order-xl-last{order:6!important}.m-xl-0{margin:0!important}.m-xl-1{margin:.25rem!important}.m-xl-2{margin:.5rem!important}.m-xl-3{margin:1rem!important}.m-xl-4{margin:1.5rem!important}.m-xl-5{margin:3rem!important}.m-xl-auto{margin:auto!important}.mx-xl-0{margin-right:0!important;margin-left:0!important}.mx-xl-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-xl-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-xl-3{margin-right:1rem!important;margin-left:1rem!important}.mx-xl-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-xl-5{margin-right:3rem!important;margin-left:3rem!important}.mx-xl-auto{margin-right:auto!important;margin-left:auto!important}.my-xl-0{margin-top:0!important;margin-bottom:0!important}.my-xl-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-xl-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-xl-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-xl-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-xl-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-xl-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-xl-0{margin-top:0!important}.mt-xl-1{margin-top:.25rem!important}.mt-xl-2{margin-top:.5rem!important}.mt-xl-3{margin-top:1rem!important}.mt-xl-4{margin-top:1.5rem!important}.mt-xl-5{margin-top:3rem!important}.mt-xl-auto{margin-top:auto!important}.me-xl-0{margin-right:0!important}.me-xl-1{margin-right:.25rem!important}.me-xl-2{margin-right:.5rem!important}.me-xl-3{margin-right:1rem!important}.me-xl-4{margin-right:1.5rem!important}.me-xl-5{margin-right:3rem!important}.me-xl-auto{margin-right:auto!important}.mb-xl-0{margin-bottom:0!important}.mb-xl-1{margin-bottom:.25rem!important}.mb-xl-2{margin-bottom:.5rem!important}.mb-xl-3{margin-bottom:1rem!important}.mb-xl-4{margin-bottom:1.5rem!important}.mb-xl-5{margin-bottom:3rem!important}.mb-xl-auto{margin-bottom:auto!important}.ms-xl-0{margin-left:0!important}.ms-xl-1{margin-left:.25rem!important}.ms-xl-2{margin-left:.5rem!important}.ms-xl-3{margin-left:1rem!important}.ms-xl-4{margin-left:1.5rem!important}.ms-xl-5{margin-left:3rem!important}.ms-xl-auto{margin-left:auto!important}.p-xl-0{padding:0!important}.p-xl-1{padding:.25rem!important}.p-xl-2{padding:.5rem!important}.p-xl-3{padding:1rem!important}.p-xl-4{padding:1.5rem!important}.p-xl-5{padding:3rem!important}.px-xl-0{padding-right:0!important;padding-left:0!important}.px-xl-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-xl-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-xl-3{padding-right:1rem!important;padding-left:1rem!important}.px-xl-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-xl-5{padding-right:3rem!important;padding-left:3rem!important}.py-xl-0{padding-top:0!important;padding-bottom:0!important}.py-xl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-xl-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-xl-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-xl-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-xl-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-xl-0{padding-top:0!important}.pt-xl-1{padding-top:.25rem!important}.pt-xl-2{padding-top:.5rem!important}.pt-xl-3{padding-top:1rem!important}.pt-xl-4{padding-top:1.5rem!important}.pt-xl-5{padding-top:3rem!important}.pe-xl-0{padding-right:0!important}.pe-xl-1{padding-right:.25rem!important}.pe-xl-2{padding-right:.5rem!important}.pe-xl-3{padding-right:1rem!important}.pe-xl-4{padding-right:1.5rem!important}.pe-xl-5{padding-right:3rem!important}.pb-xl-0{padding-bottom:0!important}.pb-xl-1{padding-bottom:.25rem!important}.pb-xl-2{padding-bottom:.5rem!important}.pb-xl-3{padding-bottom:1rem!important}.pb-xl-4{padding-bottom:1.5rem!important}.pb-xl-5{padding-bottom:3rem!important}.ps-xl-0{padding-left:0!important}.ps-xl-1{padding-left:.25rem!important}.ps-xl-2{padding-left:.5rem!important}.ps-xl-3{padding-left:1rem!important}.ps-xl-4{padding-left:1.5rem!important}.ps-xl-5{padding-left:3rem!important}.text-xl-start{text-align:left!important}.text-xl-end{text-align:right!important}.text-xl-center{text-align:center!important}}@media (min-width:1400px){.float-xxl-start{float:left!important}.float-xxl-end{float:right!important}.float-xxl-none{float:none!important}.d-xxl-inline{display:inline!important}.d-xxl-inline-block{display:inline-block!important}.d-xxl-block{display:block!important}.d-xxl-grid{display:grid!important}.d-xxl-table{display:table!important}.d-xxl-table-row{display:table-row!important}.d-xxl-table-cell{display:table-cell!important}.d-xxl-flex{display:flex!important}.d-xxl-inline-flex{display:inline-flex!important}.d-xxl-none{display:none!important}.flex-xxl-fill{flex:1 1 auto!important}.flex-xxl-row{flex-direction:row!important}.flex-xxl-column{flex-direction:column!important}.flex-xxl-row-reverse{flex-direction:row-reverse!important}.flex-xxl-column-reverse{flex-direction:column-reverse!important}.flex-xxl-grow-0{flex-grow:0!important}.flex-xxl-grow-1{flex-grow:1!important}.flex-xxl-shrink-0{flex-shrink:0!important}.flex-xxl-shrink-1{flex-shrink:1!important}.flex-xxl-wrap{flex-wrap:wrap!important}.flex-xxl-nowrap{flex-wrap:nowrap!important}.flex-xxl-wrap-reverse{flex-wrap:wrap-reverse!important}.gap-xxl-0{gap:0!important}.gap-xxl-1{gap:.25rem!important}.gap-xxl-2{gap:.5rem!important}.gap-xxl-3{gap:1rem!important}.gap-xxl-4{gap:1.5rem!important}.gap-xxl-5{gap:3rem!important}.justify-content-xxl-start{justify-content:flex-start!important}.justify-content-xxl-end{justify-content:flex-end!important}.justify-content-xxl-center{justify-content:center!important}.justify-content-xxl-between{justify-content:space-between!important}.justify-content-xxl-around{justify-content:space-around!important}.justify-content-xxl-evenly{justify-content:space-evenly!important}.align-items-xxl-start{align-items:flex-start!important}.align-items-xxl-end{align-items:flex-end!important}.align-items-xxl-center{align-items:center!important}.align-items-xxl-baseline{align-items:baseline!important}.align-items-xxl-stretch{align-items:stretch!important}.align-content-xxl-start{align-content:flex-start!important}.align-content-xxl-end{align-content:flex-end!important}.align-content-xxl-center{align-content:center!important}.align-content-xxl-between{align-content:space-between!important}.align-content-xxl-around{align-content:space-around!important}.align-content-xxl-stretch{align-content:stretch!important}.align-self-xxl-auto{align-self:auto!important}.align-self-xxl-start{align-self:flex-start!important}.align-self-xxl-end{align-self:flex-end!important}.align-self-xxl-center{align-self:center!important}.align-self-xxl-baseline{align-self:baseline!important}.align-self-xxl-stretch{align-self:stretch!important}.order-xxl-first{order:-1!important}.order-xxl-0{order:0!important}.order-xxl-1{order:1!important}.order-xxl-2{order:2!important}.order-xxl-3{order:3!important}.order-xxl-4{order:4!important}.order-xxl-5{order:5!important}.order-xxl-last{order:6!important}.m-xxl-0{margin:0!important}.m-xxl-1{margin:.25rem!important}.m-xxl-2{margin:.5rem!important}.m-xxl-3{margin:1rem!important}.m-xxl-4{margin:1.5rem!important}.m-xxl-5{margin:3rem!important}.m-xxl-auto{margin:auto!important}.mx-xxl-0{margin-right:0!important;margin-left:0!important}.mx-xxl-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-xxl-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-xxl-3{margin-right:1rem!important;margin-left:1rem!important}.mx-xxl-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-xxl-5{margin-right:3rem!important;margin-left:3rem!important}.mx-xxl-auto{margin-right:auto!important;margin-left:auto!important}.my-xxl-0{margin-top:0!important;margin-bottom:0!important}.my-xxl-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-xxl-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-xxl-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-xxl-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-xxl-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-xxl-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-xxl-0{margin-top:0!important}.mt-xxl-1{margin-top:.25rem!important}.mt-xxl-2{margin-top:.5rem!important}.mt-xxl-3{margin-top:1rem!important}.mt-xxl-4{margin-top:1.5rem!important}.mt-xxl-5{margin-top:3rem!important}.mt-xxl-auto{margin-top:auto!important}.me-xxl-0{margin-right:0!important}.me-xxl-1{margin-right:.25rem!important}.me-xxl-2{margin-right:.5rem!important}.me-xxl-3{margin-right:1rem!important}.me-xxl-4{margin-right:1.5rem!important}.me-xxl-5{margin-right:3rem!important}.me-xxl-auto{margin-right:auto!important}.mb-xxl-0{margin-bottom:0!important}.mb-xxl-1{margin-bottom:.25rem!important}.mb-xxl-2{margin-bottom:.5rem!important}.mb-xxl-3{margin-bottom:1rem!important}.mb-xxl-4{margin-bottom:1.5rem!important}.mb-xxl-5{margin-bottom:3rem!important}.mb-xxl-auto{margin-bottom:auto!important}.ms-xxl-0{margin-left:0!important}.ms-xxl-1{margin-left:.25rem!important}.ms-xxl-2{margin-left:.5rem!important}.ms-xxl-3{margin-left:1rem!important}.ms-xxl-4{margin-left:1.5rem!important}.ms-xxl-5{margin-left:3rem!important}.ms-xxl-auto{margin-left:auto!important}.p-xxl-0{padding:0!important}.p-xxl-1{padding:.25rem!important}.p-xxl-2{padding:.5rem!important}.p-xxl-3{padding:1rem!important}.p-xxl-4{padding:1.5rem!important}.p-xxl-5{padding:3rem!important}.px-xxl-0{padding-right:0!important;padding-left:0!important}.px-xxl-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-xxl-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-xxl-3{padding-right:1rem!important;padding-left:1rem!important}.px-xxl-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-xxl-5{padding-right:3rem!important;padding-left:3rem!important}.py-xxl-0{padding-top:0!important;padding-bottom:0!important}.py-xxl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-xxl-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-xxl-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-xxl-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-xxl-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-xxl-0{padding-top:0!important}.pt-xxl-1{padding-top:.25rem!important}.pt-xxl-2{padding-top:.5rem!important}.pt-xxl-3{padding-top:1rem!important}.pt-xxl-4{padding-top:1.5rem!important}.pt-xxl-5{padding-top:3rem!important}.pe-xxl-0{padding-right:0!important}.pe-xxl-1{padding-right:.25rem!important}.pe-xxl-2{padding-right:.5rem!important}.pe-xxl-3{padding-right:1rem!important}.pe-xxl-4{padding-right:1.5rem!important}.pe-xxl-5{padding-right:3rem!important}.pb-xxl-0{padding-bottom:0!important}.pb-xxl-1{padding-bottom:.25rem!important}.pb-xxl-2{padding-bottom:.5rem!important}.pb-xxl-3{padding-bottom:1rem!important}.pb-xxl-4{padding-bottom:1.5rem!important}.pb-xxl-5{padding-bottom:3rem!important}.ps-xxl-0{padding-left:0!important}.ps-xxl-1{padding-left:.25rem!important}.ps-xxl-2{padding-left:.5rem!important}.ps-xxl-3{padding-left:1rem!important}.ps-xxl-4{padding-left:1.5rem!important}.ps-xxl-5{padding-left:3rem!important}.text-xxl-start{text-align:left!important}.text-xxl-end{text-align:right!important}.text-xxl-center{text-align:center!important}}@media (min-width:1200px){.fs-1{font-size:2.5rem!important}.fs-2{font-size:2rem!important}.fs-3{font-size:1.75rem!important}.fs-4{font-size:1.5rem!important}}@media print{.d-print-inline{display:inline!important}.d-print-inline-block{display:inline-block!important}.d-print-block{display:block!important}.d-print-grid{display:grid!important}.d-print-table{display:table!important}.d-print-table-row{display:table-row!important}.d-print-table-cell{display:table-cell!important}.d-print-flex{display:flex!important}.d-print-inline-flex{display:inline-flex!important}.d-print-none{display:none!important}} /*# sourceMappingURL=bootstrap.min.css.map */ \ No newline at end of file diff --git a/src/main/resources/static/css/multi-tool.css b/src/main/resources/static/css/multi-tool.css index 29565908..9687470a 100644 --- a/src/main/resources/static/css/multi-tool.css +++ b/src/main/resources/static/css/multi-tool.css @@ -77,7 +77,7 @@ label { flex-direction: column; padding: 1rem; border-radius: 25px; - overflow-y: hidden; + overflow-y: auto; overflow-x: auto; min-height: 275px; margin: 0 0 30px 0; diff --git a/src/main/resources/static/css/navbar.css b/src/main/resources/static/css/navbar.css index 7db82462..659940b9 100644 --- a/src/main/resources/static/css/navbar.css +++ b/src/main/resources/static/css/navbar.css @@ -89,6 +89,14 @@ width: 80%; } +.close-icon { + color: var(--md-sys-color-secondary); +} + +.close-icon:hover { + transform: scale(1.15); +} + span.icon-text::after { content: attr(data-text); content: attr(data-text) / ""; @@ -320,3 +328,26 @@ span.icon-text::after { display: none; } } + + .go-pro-link { + position: relative; + padding: 0.5rem 1rem; + transition: all 0.3s ease; + } + +.go-pro-badge { + display: inline-block; + padding: 0.25rem 0.5rem; + font-size: 0.75rem; + font-weight: bold; + color: #ffffff; + background-color: #007bff; + border-radius: 0.25rem; + text-transform: uppercase; + transition: all 0.3s ease; +} + +.go-pro-link:hover .go-pro-badge { + background-color: #0056b3; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); +} \ No newline at end of file diff --git a/src/main/resources/static/css/rotate-pdf.css b/src/main/resources/static/css/rotate-pdf.css index 57a30024..19024e20 100644 --- a/src/main/resources/static/css/rotate-pdf.css +++ b/src/main/resources/static/css/rotate-pdf.css @@ -27,3 +27,16 @@ display: flex; justify-content: space-around; } + +#pdf-preview-large { + margin: 0 auto; + display: block; + max-width: calc(100% - 30px); + max-height: calc(100% - 30px); + box-shadow: 0 0 4px rgba(100, 100, 100, 0.25); + transition: rotate 0.3s; + position: absolute; + top: 50%; + left: 50%; + translate: -50% -50%; +} diff --git a/src/main/resources/static/js/downloader.js b/src/main/resources/static/js/downloader.js index 46e6a948..bbe16ba5 100644 --- a/src/main/resources/static/js/downloader.js +++ b/src/main/resources/static/js/downloader.js @@ -5,6 +5,22 @@ function showErrorBanner(message, stackTrace) { document.querySelector("#errorContainer p").textContent = message; document.querySelector("#traceContent").textContent = stackTrace; } + +function showSessionExpiredPrompt() { + const errorContainer = document.getElementById("errorContainer"); + errorContainer.style.display = "block"; + document.querySelector("#errorContainer .alert-heading").textContent = sessionExpired; + document.querySelector("#errorContainer p").textContent = sessionExpired; + document.querySelector("#traceContent").textContent = ""; + + // Optional: Add a refresh button + const refreshButton = document.createElement("button"); + refreshButton.textContent = "Refresh Page"; + refreshButton.className = "btn btn-primary mt-3"; + refreshButton.onclick = () => location.reload(); + errorContainer.appendChild(refreshButton); +} + let firstErrorOccurred = false; $(document).ready(function () { @@ -79,6 +95,11 @@ async function handleSingleDownload(url, formData, isMulti = false, isZip = fals const contentType = response.headers.get("content-type"); if (!response.ok) { + if (response.status === 401) { + // Handle 401 Unauthorized error + showSessionExpiredPrompt(); + return; + } if (contentType && contentType.includes("application/json")) { console.error("Throwing error banner, response was not okay"); return handleJsonResponse(response); @@ -97,7 +118,7 @@ async function handleSingleDownload(url, formData, isMulti = false, isZip = fals } } catch (error) { console.error("Error in handleSingleDownload:", error); - throw error; // Re-throw the error if you want it to be handled higher up. + throw error; } } diff --git a/src/main/resources/static/js/favourites.js b/src/main/resources/static/js/favourites.js index dbecd013..16e219f7 100644 --- a/src/main/resources/static/js/favourites.js +++ b/src/main/resources/static/js/favourites.js @@ -1,45 +1,73 @@ function updateFavoritesDropdown() { var dropdown = document.querySelector("#favoritesDropdown"); - // Check if dropdown exists if (!dropdown) { console.error('Dropdown element with ID "favoritesDropdown" not found!'); - return; // Exit the function + return; } - dropdown.innerHTML = ""; // Clear the current favorites + dropdown.innerHTML = ""; var hasFavorites = false; + var addedFeatures = new Set(); for (var i = 0; i < localStorage.length; i++) { var key = localStorage.key(i); - if (localStorage.getItem(key) === "favorite") { - // Find the corresponding navbar entry + var value = localStorage.getItem(key); + + if (value === "favorite") { var navbarEntry = document.querySelector(`a[href='${key}']`); if (navbarEntry) { - // Create a new dropdown entry - var dropdownItem = document.createElement("a"); - dropdownItem.className = "dropdown-item"; - dropdownItem.href = navbarEntry.href; - dropdownItem.innerHTML = navbarEntry.innerHTML; - dropdown.appendChild(dropdownItem); - hasFavorites = true; + var featureName = navbarEntry.textContent.trim(); + + if (!addedFeatures.has(featureName)) { + var dropdownItem = document.createElement("div"); + dropdownItem.className = "dropdown-item d-flex justify-content-between align-items-center"; + + // Create a wrapper for the original content + var contentWrapper = document.createElement("div"); + contentWrapper.className = "d-flex align-items-center flex-grow-1"; + contentWrapper.style.textDecoration = "none"; + contentWrapper.style.color = "inherit"; + + // Clone the original content + var originalContent = navbarEntry.querySelector('div').cloneNode(true); + contentWrapper.appendChild(originalContent); + + // Create the remove button + var removeButton = document.createElement("button"); + removeButton.className = "btn btn-sm btn-link p-0 ml-2"; + removeButton.innerHTML = 'close'; + removeButton.onclick = function(itemKey, event) { + event.preventDefault(); + event.stopPropagation(); + localStorage.removeItem(itemKey); + updateFavoritesSection(); + updateFavoritesDropdown(); + filterCards(); + }.bind(null, key); + + // Add click event to the content wrapper + contentWrapper.onclick = function(itemHref, event) { + event.preventDefault(); + window.location.href = itemHref; + }.bind(null, navbarEntry.href); + + dropdownItem.appendChild(contentWrapper); + dropdownItem.appendChild(removeButton); + dropdown.appendChild(dropdownItem); + hasFavorites = true; + addedFeatures.add(featureName); + } } else { console.warn(`Navbar entry not found for key: ${key}`); } } } - // Show or hide the default item based on whether there are any favorites if (!hasFavorites) { var defaultItem = document.createElement("a"); defaultItem.className = "dropdown-item"; - defaultItem.textContent = noFavourites; + defaultItem.textContent = noFavourites || "No favorites added"; dropdown.appendChild(defaultItem); } } - -// Ensure that the DOM content has been fully loaded before calling the function -document.addEventListener("DOMContentLoaded", function () { - console.log("DOMContentLoaded event fired"); - updateFavoritesDropdown(); -}); diff --git a/src/main/resources/static/js/homecard.js b/src/main/resources/static/js/homecard.js index d4dfd7ea..efc5314e 100644 --- a/src/main/resources/static/js/homecard.js +++ b/src/main/resources/static/js/homecard.js @@ -25,29 +25,38 @@ function filterCards() { function updateFavoritesSection() { const favoritesContainer = document.getElementById("groupFavorites").querySelector(".feature-group-container"); favoritesContainer.style.maxHeight = "none"; - favoritesContainer.innerHTML = ""; - const cards = Array.from(document.querySelectorAll(".feature-card")); + favoritesContainer.innerHTML = ""; // Clear the container first + const cards = Array.from(document.querySelectorAll(".feature-card:not(.duplicate)")); + const addedCardIds = new Set(); // To keep track of added card IDs let favoritesAmount = 0; + cards.forEach(card => { - if (localStorage.getItem(card.id) === "favorite") { + if (localStorage.getItem(card.id) === "favorite" && !addedCardIds.has(card.id)) { const duplicate = card.cloneNode(true); + duplicate.classList.add("duplicate"); favoritesContainer.appendChild(duplicate); + addedCardIds.add(card.id); // Mark this card as added favoritesAmount++; } }); + if (favoritesAmount === 0) { document.getElementById("groupFavorites").style.display = "none"; } else { document.getElementById("groupFavorites").style.display = "flex"; - }; + } reorderCards(favoritesContainer); favoritesContainer.style.maxHeight = favoritesContainer.scrollHeight + "px"; -}; +} function toggleFavorite(element) { var span = element.querySelector("span.material-symbols-rounded"); var card = element.closest(".feature-card"); var cardId = card.id; + + // Prevent the event from bubbling up to parent elements + event.stopPropagation(); + if (span.classList.contains("no-fill")) { span.classList.remove("no-fill"); span.classList.add("fill"); @@ -59,7 +68,31 @@ function toggleFavorite(element) { card.classList.remove("favorite"); localStorage.removeItem(cardId); } - reorderCards(card.parentNode); + + // Use setTimeout to ensure this runs after the current call stack is clear + setTimeout(() => { + reorderCards(card.parentNode); + updateFavoritesSection(); + updateFavoritesDropdown(); + filterCards(); + }, 0); +} + +function syncFavorites() { + const cards = Array.from(document.querySelectorAll(".feature-card")); + cards.forEach(card => { + const isFavorite = localStorage.getItem(card.id) === "favorite"; + const starIcon = card.querySelector(".favorite-icon span.material-symbols-rounded"); + if (isFavorite) { + starIcon.classList.remove("no-fill"); + starIcon.classList.add("fill"); + card.classList.add("favorite"); + } else { + starIcon.classList.remove("fill"); + starIcon.classList.add("no-fill"); + card.classList.remove("favorite"); + } + }); updateFavoritesSection(); updateFavoritesDropdown(); filterCards(); @@ -181,7 +214,10 @@ function expandCollapseAll(expandAll) { }) } -window.onload = initializeCards; +window.onload = function() { + initializeCards(); + syncFavorites(); // Ensure everything is in sync on page load +}; document.addEventListener("DOMContentLoaded", function () { const materialIcons = new FontFaceObserver('Material Symbols Rounded'); @@ -223,7 +259,5 @@ document.addEventListener("DOMContentLoaded", function () { }) }, 500); - - showFavoritesOnly(); -}); +}); \ No newline at end of file diff --git a/src/main/resources/static/js/multitool/PdfActionsManager.js b/src/main/resources/static/js/multitool/PdfActionsManager.js index 3701266e..033b3991 100644 --- a/src/main/resources/static/js/multitool/PdfActionsManager.js +++ b/src/main/resources/static/js/multitool/PdfActionsManager.js @@ -192,6 +192,7 @@ class PdfActionsManager { return div; } + } export default PdfActionsManager; diff --git a/src/main/resources/static/js/multitool/PdfContainer.js b/src/main/resources/static/js/multitool/PdfContainer.js index 55635c69..0cc1a110 100644 --- a/src/main/resources/static/js/multitool/PdfContainer.js +++ b/src/main/resources/static/js/multitool/PdfContainer.js @@ -117,6 +117,7 @@ class PdfContainer { const newAngle = lastAngle + deg; element.style.rotate = newAngle + "deg"; + } async addPdfFile(file, nextSiblingElement) { @@ -326,6 +327,9 @@ class PdfContainer { page.setRotation(PDFLib.degrees(page.getRotation().angle + rotationAngle)); } } + pdfDoc.setCreator(stirlingPDFLabel); + pdfDoc.setProducer(stirlingPDFLabel); + const pdfBytes = await pdfDoc.save(); const pdfBlob = new Blob([pdfBytes], { type: "application/pdf" }); diff --git a/src/main/resources/static/js/multitool/horizontalScroll.js b/src/main/resources/static/js/multitool/horizontalScroll.js index 2d20fd7b..28ec42f5 100644 --- a/src/main/resources/static/js/multitool/horizontalScroll.js +++ b/src/main/resources/static/js/multitool/horizontalScroll.js @@ -1,27 +1,32 @@ const scrollDivHorizontally = (id) => { - var scrollDelta = 0; // variable to store the accumulated scroll delta + var scrollDeltaX = 0; // variable to store the accumulated horizontal scroll delta + var scrollDeltaY = 0; // variable to store the accumulated vertical scroll delta var isScrolling = false; // variable to track if scroll is already in progress - const divToScrollHorizontally = document.getElementById(id); + const divToScroll = document.getElementById(id); + function scrollLoop() { - // Scroll the div horizontally by a fraction of the accumulated scroll delta - divToScrollHorizontally.scrollLeft += scrollDelta * 0.1; + // Scroll the div horizontally and vertically by a fraction of the accumulated scroll delta + divToScroll.scrollLeft += scrollDeltaX * 0.1; + divToScroll.scrollTop += scrollDeltaY * 0.1; // Reduce the accumulated scroll delta by a fraction - scrollDelta *= 0.9; + scrollDeltaX *= 0.9; + scrollDeltaY *= 0.9; // If scroll delta is still significant, continue the scroll loop - if (Math.abs(scrollDelta) > 0.1) { + if (Math.abs(scrollDeltaX) > 0.1 || Math.abs(scrollDeltaY) > 0.1) { requestAnimationFrame(scrollLoop); } else { isScrolling = false; // Reset scroll in progress flag } } - divToScrollHorizontally.addEventListener("wheel", function (e) { + divToScroll.addEventListener("wheel", function (e) { e.preventDefault(); // prevent default mousewheel behavior - // Accumulate the horizontal scroll delta - scrollDelta -= e.deltaX || e.wheelDeltaX || -e.deltaY || -e.wheelDeltaY; + // Accumulate the horizontal and vertical scroll delta + scrollDeltaX -= e.deltaX || e.wheelDeltaX || -e.deltaY || -e.wheelDeltaY; + scrollDeltaY -= e.deltaY || e.wheelDeltaY || -e.deltaX || -e.wheelDeltaX; // If scroll is not already in progress, start the scroll loop if (!isScrolling) { @@ -31,4 +36,4 @@ const scrollDivHorizontally = (id) => { }); }; -export default scrollDivHorizontally; +export default scrollDivHorizontally; \ No newline at end of file diff --git a/src/main/resources/templates/account.html b/src/main/resources/templates/account.html index a0e54397..c9d08723 100644 --- a/src/main/resources/templates/account.html +++ b/src/main/resources/templates/account.html @@ -278,7 +278,7 @@ let allKeys = new Set([...Object.keys(accountSettings), ...Object.keys(localStorage)]); allKeys.forEach(key => { - if(key === 'debug' || key === '0' || key === '1') return; // Ignoring specific keys + if(key === 'debug' || key === '0' || key === '1' || key.includes('pdfjs') || key.includes('posthog') || key.includes('pageViews')) return; // Ignoring specific keys const accountValue = accountSettings[key] || '-'; const browserValue = localStorage.getItem(key) || '-'; @@ -299,7 +299,7 @@ // Then, set the account settings to local storage for (let key in accountSettings) { - if(key !== 'debug' && key !== '0' && key !== '1') { // Only sync non-ignored keys + if(key !== 'debug' && key !== '0' && key !== '1' && !key.includes('pdfjs') && !key.includes('posthog') && !key.includes('pageViews')) { // Only sync non-ignored keys localStorage.setItem(key, accountSettings[key]); } } @@ -316,7 +316,7 @@ for (let i = 0; i < localStorage.length; i++) { const key = localStorage.key(i); - if(key !== 'debug' && key !== '0' && key !== '1') { // Only send non-ignored keys + if(key !== 'debug' && key !== '0' && key !== '1' && !key.includes('pdfjs') && !key.includes('posthog') && !key.includes('pageViews')) { // Only send non-ignored keys let hiddenField = document.createElement("input"); hiddenField.type = "hidden"; hiddenField.name = key; diff --git a/src/main/resources/templates/addUsers.html b/src/main/resources/templates/addUsers.html index a91f0e46..18bfb7d2 100644 --- a/src/main/resources/templates/addUsers.html +++ b/src/main/resources/templates/addUsers.html @@ -101,6 +101,8 @@ +

+ + + + + @@ -148,6 +191,7 @@ const multipleInputsForSingleRequest = /*[[${multipleInputsForSingleRequest}]]*/ false; const disableMultipleFiles = /*[[${disableMultipleFiles}]]*/ false; const remoteCall = /*[[${remoteCall}]]*/ true; + const sessionExpired = /*[[#{session.expired}]]*/ ''; diff --git a/src/main/resources/templates/fragments/footer.html b/src/main/resources/templates/fragments/footer.html index 40f64419..6cf37fd4 100644 --- a/src/main/resources/templates/fragments/footer.html +++ b/src/main/resources/templates/fragments/footer.html @@ -4,7 +4,7 @@
  • Licenses
  • -
  • Survey
  • +
  • Survey
  • privacyPolicy
  • termsAndConditions
  • accessibilityStatement
  • diff --git a/src/main/resources/templates/fragments/navbar.html b/src/main/resources/templates/fragments/navbar.html index fe0c8842..24a2ca57 100644 --- a/src/main/resources/templates/fragments/navbar.html +++ b/src/main/resources/templates/fragments/navbar.html @@ -229,6 +229,9 @@
    +
    +
    @@ -357,6 +360,12 @@
+ +