diff --git a/ASVS/README.md b/ASVS/README.md new file mode 100644 index 0000000..ed65620 --- /dev/null +++ b/ASVS/README.md @@ -0,0 +1,40 @@ +# OWASP ASVS 5.0.0 Compliance Tracker + +This directory contains compliance tracking for OWASP Application Security Verification Standard 5.0.0. + +## Status Legend + +- **Compliant**: Requirement is fully implemented +- **Partial**: Requirement is partially implemented +- **N/A**: Requirement is not applicable to this project +- *(empty)*: Not yet assessed or not compliant + +## Level Legend + +- **1**: Basic security — every application should meet +- **2**: Standard security — recommended for most applications +- **3**: Advanced security — for critical applications + +## Chapters + +| Chapter | Title | Requirements | +|---------|-------|--------------| +| [V1](V01-Encoding-and-Sanitization.md) | Encoding and Sanitization | 30 | +| [V2](V02-Validation-and-Business-Logic.md) | Validation and Business Logic | 13 | +| [V3](V03-Web-Frontend-Security.md) | Web Frontend Security | 31 | +| [V4](V04-API-and-Web-Service.md) | API and Web Service | 16 | +| [V5](V05-File-Handling.md) | File Handling | 13 | +| [V6](V06-Authentication.md) | Authentication | 47 | +| [V7](V07-Session-Management.md) | Session Management | 19 | +| [V8](V08-Authorization.md) | Authorization | 13 | +| [V9](V09-Self-contained-Tokens.md) | Self‑contained Tokens | 7 | +| [V10](V10-OAuth-and-OIDC.md) | OAuth and OIDC | 36 | +| [V11](V11-Cryptography.md) | Cryptography | 24 | +| [V12](V12-Secure-Communication.md) | Secure Communication | 12 | +| [V13](V13-Configuration.md) | Configuration | 21 | +| [V14](V14-Data-Protection.md) | Data Protection | 13 | +| [V15](V15-Secure-Coding-and-Architecture.md) | Secure Coding and Architecture | 21 | +| [V16](V16-Security-Logging-and-Error-Handling.md) | Security Logging and Error Handling | 17 | +| [V17](V17-WebRTC.md) | WebRTC | 12 | + +**Total requirements: 345** diff --git a/ASVS/V01-Encoding-and-Sanitization.md b/ASVS/V01-Encoding-and-Sanitization.md new file mode 100644 index 0000000..1d66ff2 --- /dev/null +++ b/ASVS/V01-Encoding-and-Sanitization.md @@ -0,0 +1,75 @@ +# V1 Encoding and Sanitization + +OWASP Application Security Verification Standard 5.0.0 + +## V1.1 Encoding and Sanitization Architecture + +In the sections below, syntax‑specific or interpreter‑specific requirements for safely processing un‑ safe content to avoid security vulnerabilities are provided. The requirements in this section cover the order in which this processing should occur and where it should take place. They also aim to ensure that whenever data is stored, it remains in its original state and is not stored in an encoded or escaped form (e.g., HTML encoding), to prevent double encoding issues. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 1.1.1 | 2 | Verify that input is decoded or unescaped into a canonical form only once, it is only decoded when encoded data in that form is expected, and that this is done before processing the input further, for example it is not performed after input validation or sanitization. | Compliant | Nette framework handles URL decoding at router level. Latte auto-escapes output. No double-decoding vulnerabilities. | — | +| 1.1.2 | 2 | Verify that the application performs output encoding and escaping either as a final step before being used by the interpreter for which it is intended or by the interpreter itself. | Compliant | Latte templating engine performs context-aware output encoding (HTML, JS, URL, CSS contexts) automatically. | — | + +## V1.2 Injection Prevention + +Output encoding or escaping, performed close to or adjacent to a potentially dangerous context, is critical to the security of any application. Typically, output encoding and escaping are not persisted, but are instead used to render output safe for immediate use in the appropriate interpreter. Attempt‑ ing to perform this too early may result in malformed content or render the encoding or escaping ineffective. In many cases, software libraries include safe or safer functions that perform this automatically, although it is necessary to ensure that they are correct for the current context. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 1.2.1 | 1 | Verify that output encoding for an HTTP response, HTML document, or XML document is relevant for the context required, such as encoding the relevant characters for HTML elements, HTML attributes, HTML comments, CSS, or HTTP header fields, to avoid changing the message or document structure. | Compliant | Latte templating engine auto-escapes output by context (HTML, JS, URL). Nette framework handles context-aware encoding. | — | +| 1.2.2 | 1 | Verify that when dynamically building URLs, untrusted data is encoded according to its context (e.g., URL encoding or base64url encoding for query or path parameters). Ensure that only safe URL protocols are permitted (e.g., disallow javascript: or data:). | Compliant | Nette\Application\LinkGenerator handles URL building with proper encoding. Latte uses context-aware escaping for URLs. | — | +| 1.2.3 | 1 | Verify that output encoding or escaping is used when dynamically building JavaScript content (including JSON), to avoid changing the message or document structure (to avoid JavaScript and JSON injection). | Compliant | Latte engine escapes JS context. Nette\Utils\Json for JSON encoding. | — | +| 1.2.4 | 1 | Verify that data selection or database queries (e.g., SQL, HQL, NoSQL, Cypher) use parameterized queries, ORMs, entity frameworks, or are otherwise protected from SQL Injection and other database injection attacks. This is also relevant when writing stored procedures. | Compliant | Doctrine ORM with parameterized queries (DQL, QueryBuilder). No raw SQL. | — | +| 1.2.5 | 1 | Verify that the application protects against OS command injection and that operating system calls use parameterized OS queries or use contextual command line output encoding. | Compliant | Doctrine ORM parameterized queries handle all database interactions. | — | +| 1.2.6 | 2 | Verify that the application protects against LDAP injection vulnerabilities, or that specific security controls to prevent LDAP injection have been implemented. | Compliant | No OS command execution in the application code. | — | +| 1.2.7 | 2 | Verify that the application is protected against XPath injection attacks by using query parameterization or precompiled queries. | Out of scope | Application does not use XPath or XML queries. | — | +| 1.2.8 | 2 | Verify that LaTeX processors are configured securely (such as not using the "– shell‑escape"flag) and an allowlist of commands is used to prevent LaTeX injection attacks. | Compliant | Latte auto-escaping prevents XSS. Content rendered through Latte templates. | — | +| 1.2.9 | 2 | Verify that the application escapes special characters in regular expressions (typically using a backslash) to prevent them from being misinterpreted as metacharacters. | Compliant | HTTP response headers set via Nette\Http\Response with proper encoding. | — | +| 1.2.10 | 3 | Verify that the application is protected against CSV and Formula Injection. The application must follow the escaping rules defined in RFC 4180 sections 2.6 and 2.7 when exporting CSV content. Additionally, when exporting to CSV or other spreadsheet formats (such as XLS, XLSX, or ODF), special characters (including '=', '+', '‑', '@', '\t'(tab), and '\0'(null character)) must be escaped with a single quote if they appear as the first character in a field value. Note: Using parameterized queries or escaping SQL is not always sufficient. Query parts such as table and column names (including "ORDER BY"column names) cannot be escaped. Including escaped user‑supplied data in these fields results in failed queries or SQL injection. | | | | + +## V1.3 Sanitization + +The ideal protection against using untrusted content in an unsafe context is to use context‑specific encoding or escaping, which maintains the same semantic meaning of the unsafe content but renders it safe for use in that particular context, as discussed in more detail in the previous section. Where this is not possible, sanitization becomes necessary, removing potentially dangerous charac‑ ters or content. In some cases, this may change the semantic meaning of the input, but for security reasons, there may be no alternative. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 1.3.1 | 1 | Verify that all untrusted HTML input from WYSIWYG editors or similar is sanitized using a well‑known and secure HTML sanitization library or framework feature. | Out of scope | Application does not use WYSIWYG editors or accept HTML input. | — | +| 1.3.2 | 1 | Verify that the application avoids the use of eval() or other dynamic code execution features such as Spring Expression Language (SpEL). Where there is no alternative, any user input being included must be sanitized before being executed. | Compliant | No eval() or dynamic code execution in application code. Latte templates are compiled, not evaluated at runtime. | — | +| 1.3.3 | 2 | Verify that data being passed to a potentially dangerous context is sanitized beforehand to enforce safety measures, such as only allowing characters which are safe for this context and trimming input which is too long. | Partial | Server-side Latte auto-escapes. Client-side JS uses minimal DOM manipulation. No comprehensive audit of client-side code yet. | Per-project: audit client-side JS. Use `textContent`/`createTextNode` instead of `innerHTML` for DOM manipulation. | +| 1.3.4 | 2 | Verify that user‑supplied Scalable Vector Graphics (SVG) scriptable content is validated or sanitized to contain only tags and attributes (such as draw graphics) that are safe for the application, e.g., do not contain scripts and foreignObject. | Out of scope | Application does not accept user-supplied SVG content. | — | +| 1.3.5 | 2 | Verify that the application sanitizes or disables user‑supplied scriptable or expression template language content, such as Markdown, CSS or XSL stylesheets, BBCode, or similar. | Out of scope | Application does not accept user-supplied scriptable or embedded content (no markdown, template syntax in user input). | — | +| 1.3.6 | 2 | Verify that the application protects against Server‑side Request Forgery (SSRF) attacks, by validating untrusted data against an allowlist of protocols, domains, paths and ports and sanitizing potentially dangerous characters before using the data to call another service. | Compliant | Application does not make HTTP requests based on user-supplied URLs. No SSRF vectors. | — | +| 1.3.7 | 2 | Verify that the application protects against template injection attacks by not allowing templates to be built based on untrusted input. Where there is no alternative, any untrusted input being included dynamically during template creation must be sanitized or strictly validated. | Compliant | Latte templates are pre-compiled. User input is never used in template compilation. No SSTI vectors. | — | +| 1.3.8 | 2 | Verify that the application appropriately sanitizes untrusted input before use in Java Naming and Directory Interface (JNDI) queries and that JNDI is configured securely to prevent JNDI injection attacks. | Compliant | No untrusted content passed to system interpreters. Doctrine ORM handles database queries via parameterized DQL. | — | +| 1.3.9 | 2 | Verify that the application sanitizes content before it is sent to memcache to prevent injection attacks. | Compliant | No OS command execution with user input in the application. | — | +| 1.3.10 | 2 | Verify that format strings which might resolve in an unexpected or malicious way when used are sanitized before being processed. | Compliant | PHP is not susceptible to traditional format string attacks. sprintf() calls use controlled format strings. | — | +| 1.3.11 | 2 | Verify that the application sanitizes user input before passing to mail systems to protect against SMTP or IMAP injection. | Compliant | No user input used in regex patterns. All regex patterns are hardcoded. | — | +| 1.3.12 | 3 | Verify that regular expressions are free from elements causing exponential backtracking, and ensure untrusted input is sanitized to mitigate ReDoS or Runaway Regex attacks. | | | | + +## V1.4 Memory, String, and Unmanaged Code + +The following requirements address risks associated with unsafe memory use, which generally apply when the application uses a systems language or unmanaged code. In some cases, it may be possible to achieve this by setting compiler flags that enable buffer overflow protections and warnings, including stack randomization and data execution prevention, and that break the build if unsafe pointer, memory, format string, integer, or string operations are found. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 1.4.1 | 2 | Verify that the application uses memory‑safe string, safer memory copy and pointer arithmetic to detect or prevent stack, buffer, or heap overflows. | Out of scope | PHP is a memory-managed language. No manual memory management. | — | +| 1.4.2 | 2 | Verify that sign, range, and input validation techniques are used to prevent integer overflows. | Out of scope | PHP handles integer overflow/underflow automatically. No C/C++ style issues. | — | +| 1.4.3 | 2 | Verify that dynamically allocated memory and resources are released, and that references or pointers to freed memory are removed or set to null to prevent dangling pointers and use‑after‑free vulnerabilities. | Out of scope | PHP handles memory allocation/deallocation automatically via garbage collector. | — | + +## V1.5 Safe Deserialization + +The conversion of data from a stored or transmitted representation into actual application objects (deserialization) has historically been the cause of various code injection vulnerabilities. It is impor‑ tant to perform this process carefully and safely to avoid these types of issues. In particular, certain methods of deserialization have been identified by programming language or framework documentation as insecure and cannot be made safe with untrusted data. For each mech‑ anism in use, careful due diligence should be performed. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 1.5.1 | 1 | Verify that the application configures XML parsers to use a restrictive configuration and that unsafe features such as resolving external entities are disabled to prevent XML eXternal Entity (XXE) attacks. | Compliant | No custom deserialization of untrusted data. Nette\Utils\Json used for JSON parsing. | — | +| 1.5.2 | 2 | Verify that deserialization of untrusted data enforces safe input handling, such as using an allowlist of object types or restricting client‑defined object types, to prevent deserialization attacks. Deserialization mechanisms that are explicitly defined as insecure must not be used with untrusted input. | Compliant | No deserialization of untrusted data. JSON parsing via Nette\Utils\Json. No unserialize() on user input. | — | +| 1.5.3 | 3 | Verify that different parsers used in the application for the same data type (e.g., JSON parsers, XML parsers, URL parsers), perform parsing in a consistent way and use the same character encoding mechanism to avoid issues such as JSON Interoperability vulnerabilities or different URI or file parsing behavior being exploited in Remote File Inclusion (RFI) or Server‑side Request Forgery (SSRF) attacks. | | | | + +--- + +**Total requirements in this chapter: 30** +- Level 1: 8 +- Level 2: 19 +- Level 3: 3 diff --git a/ASVS/V02-Validation-and-Business-Logic.md b/ASVS/V02-Validation-and-Business-Logic.md new file mode 100644 index 0000000..dc13ee2 --- /dev/null +++ b/ASVS/V02-Validation-and-Business-Logic.md @@ -0,0 +1,51 @@ +# V2 Validation and Business Logic + +OWASP Application Security Verification Standard 5.0.0 + +## V2.1 Validation and Business Logic Documentation + +Validation and business logic documentation should clearly define business logic limits, validation rules, and contextual consistency of combined data items, so it is clear what needs to be implemented in the application. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 2.1.1 | 1 | Verify that the application's documentation defines input validation rules for how to check the validity of data items against an expected structure. This could be common data formats such as credit card numbers, email addresses, telephone numbers, or it could be an internal data format. | Partial | No formal documentation of input validation strategy. Nette Forms handle validation rules per-form. | Per-project: document validation rules for all form inputs — which `addRule()` rules apply to which fields. | +| 2.1.2 | 2 | Verify that the application's documentation defines how to validate the logical and contextual consistency of combined data items, such as checking that suburb and ZIP code match. | Partial | No formal documentation of unexpected input handling. Nette framework returns 400/404 for invalid requests. | Per-project: document cross-field/contextual validation rules (e.g., date ranges, related selects). | +| 2.1.3 | 2 | Verify that expectations for business logic limits and validations are documented, including both per‑user and globally across the application. | Partial | No formal documentation of business logic limits. Limits enforced in code but not documented. | Per-project: document business logic limits (rate limits via `setLoginAttemptProtection()`, quotas, max records). | + +## V2.2 Input Validation + +Effective input validation controls enforce business or functional expectations around the type of data the application expects to receive. This ensures good data quality and reduces the attack sur‑ face. However, it does not remove or replace the need to use correct encoding, parameterization, or sanitization when using the data in another component or for presenting it for output. In this context, "input"could come from a wide variety of sources, including HTML form fields, REST requests, URL parameters, HTTP header fields, cookies, files on disk, databases, and external APIs. A business logic control might check that a particular input is a number less than 100. A functional expectation might check that a number is below a certain threshold, as that number controls how many times a particular loop will take place, and a high number could lead to excessive processing and a potential denial of service condition. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 2.2.1 | 1 | Verify that input is validated to enforce business or functional expectations for that input. This should either use positive validation against an allow list of values, patterns, and ranges, or be based on comparing the input to an expected structure and logical limits according to predefined rules. For L1, this can focus on input which is used to make specific business or security decisions. For L2 and up, this should apply to all input. | Partial | Nette Forms provide server-side validation with rules. Not all inputs have business-level validation. | Per-project: audit all Nette form inputs — ensure every input has appropriate `addRule()` business validation. | +| 2.2.2 | 1 | Verify that the application is designed to enforce input validation at a trusted service layer. While client‑side validation improves usability and should be encouraged, it must not be relied upon as a security control. | Compliant | Nette Forms enforce server-side validation via addRule(). All form inputs validated on the trusted backend. | — | +| 2.2.3 | 2 | Verify that the application ensures that combinations of related data items are reasonable according to the pre‑defined rules. | Partial | Related input validation (e.g., password + password confirmation) handled in form validation. No comprehensive cross-field validation audit. | Per-project: audit cross-field validation in forms using `addConditionOn()` or custom `addRule()` callbacks. | + +## V2.3 Business Logic Security + +This section considers key requirements to ensure that the application enforces business logic pro‑ cesses in the correct way and is not vulnerable to attacks that exploit the logic and flow of the appli‑ cation. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 2.3.1 | 1 | Verify that the application will only process business logic flows for the same user in the expected sequential step order and without skipping steps. | Compliant | Business logic only processes authenticated, authorized requests. Presenter authorization checks via ACL. | — | +| 2.3.2 | 2 | Verify that business logic limits are implemented per the application's documentation to avoid business logic flaws being exploited. | Partial | Business logic limits enforced in code. Not formally documented per application documentation. | Per-project: document business logic limits formally (max records, max file count, operation quotas). | +| 2.3.3 | 2 | Verify that transactions are being used at the business logic level such that either a business logic operation succeeds in its entirety or it is rolled back to the previous correct state. | Compliant | Doctrine ORM uses database transactions for multi-step operations. | — | +| 2.3.4 | 2 | Verify that business logic level locking mechanisms are used to ensure that limited quantity resources (such as theater seats or delivery slots) cannot be double‑booked by manipulating the application's logic. | Partial | Database-level locking (SELECT FOR UPDATE) used where needed. No formal TOCTOU audit across all operations. | Per-project: audit for TOCTOU race conditions. Use Doctrine `LOCK_PESSIMISTIC_WRITE` for critical operations. | +| 2.3.5 | 3 | Verify that high‑value business logic flows require multi‑user approval to prevent unauthorized or accidental actions. This could include but is not limited to large monetary transfers, contract approvals, access to classified information, or safety overrides in manufacturing. | | | | + +## V2.4 Anti‑automation + +This section includes anti‑automation controls to ensure that human‑like interactions are required and excessive automated requests are prevented. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 2.4.1 | 2 | Verify that anti‑automation controls are in place to protect against excessive calls to application functions that could lead to data exfiltration, garbage‑data creation, quota exhaustion, rate‑limit breaches, denial‑of‑service, or overuse of costly resources. | Compliant | IP-based rate limiting via DoctrineAuthenticator::setLoginAttemptProtection(). Configurable max attempts and timeout. | — | +| 2.4.2 | 3 | Verify that business logic flows require realistic human timing, preventing excessively rapid transaction submissions. | | | | + +--- + +**Total requirements in this chapter: 13** +- Level 1: 4 +- Level 2: 7 +- Level 3: 2 diff --git a/ASVS/V03-Web-Frontend-Security.md b/ASVS/V03-Web-Frontend-Security.md new file mode 100644 index 0000000..c8c917e --- /dev/null +++ b/ASVS/V03-Web-Frontend-Security.md @@ -0,0 +1,90 @@ +# V3 Web Frontend Security + +OWASP Application Security Verification Standard 5.0.0 + +## V3.1 Web Frontend Security Documentation + +This section outlines the browser security features that should be specified in the application's doc‑ umentation. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 3.1.1 | 3 | Verify that application documentation states the expected security features that browsers using the application must support (such as HTTPS, HTTP Strict Transport Security (HSTS), Content Security Policy (CSP), and other relevant HTTP security mechanisms). It must also define how the application must behave when some of these features are not available (such as warning the user or blocking access). | | | | + +## V3.2 Unintended Content Interpretation + +Rendering content or functionality in an incorrect context can result in malicious content being ex‑ ecuted or displayed. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 3.2.1 | 1 | Verify that security controls are in place to prevent browsers from rendering content or functionality in HTTP responses in an incorrect context (e.g., when an API, a user‑uploaded file or other resource is requested directly). Possible controls could include: not serving the content unless HTTP request header fields (such as Sec‑Fetch‑*) indicate it is the correct context, using the sandbox directive of the Content‑Security‑Policy header field or using the attachment disposition type in the Content‑Disposition header field. | Partial | X-Content-Type-Options: nosniff prevents MIME sniffing. No explicit Sec-Fetch-* validation or Content-Disposition for API responses. | Per-project: add `Content-Disposition: attachment` header in file download responses. Validate `Sec-Fetch-Dest` for API endpoints. | +| 3.2.2 | 1 | Verify that content intended to be displayed as text, rather than rendered as HTML, is handled using safe rendering functions (such as createTextNode or textContent) to prevent unintended execution of content such as HTML or JavaScript. | Compliant | Latte templating engine auto-escapes all output as text by default, preventing HTML injection. | — | +| 3.2.3 | 3 | Verify that the application avoids DOM clobbering when using client‑side JavaScript by employing explicit variable declarations, performing strict type checking, avoiding storing global variables on the document object, and implementing namespace isolation. | | | | + +## V3.3 Cookie Setup + +This section outlines requirements for securely configuring sensitive cookies to provide a higher level of assurance that they were created by the application itself and to prevent their contents from leaking or being inappropriately modified. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 3.3.1 | 1 | Verify that cookies have the 'Secure'attribute set, and if the '__Host‑'prefix is not used for the cookie name, the '__Secure‑'prefix must be used for the cookie name. | Compliant | Secure attribute set via cookieSecure: auto. Auth cookie uses __Host-userid prefix (configured in fancyadmin config/security.neon). | — | +| 3.3.2 | 2 | Verify that each cookie's 'SameSite'attribute value is set according to the purpose of the cookie, to limit exposure to user interface redress attacks and browser‑based request forgery attacks, commonly known as cross‑site request forgery (CSRF). | Compliant | CookieStorage defaults to SameSite=Lax. Session cookies configured with `cookieSamesite: Lax` in common.neon. | — | +| 3.3.3 | 2 | Verify that cookies have the '__Host‑'prefix for the cookie name unless they are explicitly designed to be shared with other hosts. | Compliant | Auth cookie named __Host-userid via fancyadmin config/security.neon. Path=/, Secure=auto, no Domain attribute. Not shared with other hosts. | — | +| 3.3.4 | 2 | Verify that if the value of a cookie is not meant to be accessible to client‑side scripts (such as a session token), the cookie must have the 'HttpOnly' attribute set and the same value (e. g. session token) must only be transferred to the client via the 'Set‑Cookie'header field. | Compliant | CookieStorage hardcodes httpOnly: true. Session cookies configured with `cookieHttponly: true` in common.neon. Token only transferred via Set-Cookie header. | — | +| 3.3.5 | 3 | Verify that when the application writes a cookie, the cookie name and value length combined are not over 4096 bytes. Overly large cookies will not be stored by the browser and therefore not sent with requests, preventing the user from using application functionality which relies on that cookie. | | | | + +## V3.4 Browser Security Mechanism Headers + +This section describes which security headers should be set on HTTP responses to enable browser security features and restrictions when handling responses from the application. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 3.4.1 | 1 | Verify that a Strict‑Transport‑Security header field is included on all responses to enforce an HTTP Strict Transport Security (HSTS) policy. A maximum age of at least 1 year must be defined, and for L2 and up, the policy must apply to all subdomains as well. | Compliant | HSTS configured at nginx reverse proxy level with appropriate max-age and includeSubDomains. | — | +| 3.4.2 | 1 | Verify that the Cross‑Origin Resource Sharing (CORS) Access‑Control‑Allow‑Origin header field is a fixed value by the application, or if the Origin HTTP request header field value is used, it is validated against an allowlist of trusted origins. When 'Access‑Control‑Allow‑Origin: *'needs to be used, verify that the response does not include any sensitive information. | Compliant | Application does not set CORS headers. No Access-Control-Allow-Origin configured. Same-origin only. | — | +| 3.4.3 | 2 | Verify that HTTP responses include a Content‑Security‑Policy response header field which defines directives to ensure the browser only loads and executes trusted content or resources, in order to limit execution of malicious JavaScript. As a minimum, a global policy must be used which includes the directives object‑src 'none'and base‑uri 'none'and defines either an allowlist or uses nonces or hashes. For an L3 application, a per‑response policy with nonces or hashes must be defined. | Partial | CSP configured in fancyadmin config/security.neon with object-src 'none' and base-uri 'none'. Uses 'unsafe-inline' and 'unsafe-eval' in project overrides (needed for Vite/legacy). Nonces/hashes not yet used for scripts. | Per-project: remove `'unsafe-inline'`/`'unsafe-eval'` from CSP overrides in `common.neon`. Move inline JS to external files or use Latte `n:nonce`. | +| 3.4.4 | 2 | Verify that all HTTP responses contain an 'X‑Content‑Type‑Options: nosniff' header field. This instructs browsers not to use content sniffing and MIME type guessing for the given response, and to require the response's Content‑Type header field value to match the destination resource. For example, the response to a request for a style is only accepted if the response's Content‑Type is 'text/css'. This also enables the use of the Cross‑Origin Read Blocking (CORB) functionality by the browser. | Compliant | X-Content-Type-Options: nosniff set in common.neon `http: headers:` section. | — | +| 3.4.5 | 2 | Verify that the application sets a referrer policy to prevent leakage of technically sensitive data to third‑party services via the 'Referer'HTTP request header field. This can be done using the Referrer‑Policy HTTP response header field or via HTML element attributes. Sensitive data could include path and query data in the URL, and for internal non‑public applications also the hostname. | Compliant | Referrer-Policy: strict-origin-when-cross-origin set in fancyadmin config/security.neon via http: headers:. | — | +| 3.4.6 | 2 | Verify that the web application uses the frame‑ancestors directive of the Content‑Security‑Policy header field for every HTTP response to ensure that it cannot be embedded by default and that embedding of specific resources is allowed only when necessary. Note that the X‑Frame‑Options header field, although supported by browsers, is obsolete and may not be relied upon. | Compliant | frame-ancestors: 'none' in CSP config. X-Frame-Options: DENY also set as fallback. | — | +| 3.4.7 | 3 | Verify that the Content‑Security‑Policy header field specifies a location to report violations. | | | | +| 3.4.8 | 3 | Verify that all HTTP responses that initiate a document rendering (such as responses with Content‑Type text/html), include the Cross‑Origin‑Opener‑Policy header field with the same‑origin directive or the same‑origin‑allow‑popups directive as required. This prevents attacks that abuse shared access to Window objects, such as tabnabbing and frame counting. | | | | + +## V3.5 Browser Origin Separation + +When accepting a request to sensitive functionality on the server side, the application needs to ensure the request is initiated by the application itself or by a trusted party and has not been forged by an attacker. Sensitive functionality in this context could include accepting form posts for authenticated and non‑authenticated users (such as an authentication request), state‑changing operations, or resource‑demanding functionality (such as data export). The key protections here are browser security policies like Same Origin Policy for JavaScript and also SameSite logic for cookies. Another common protection is the CORS preflight mechanism. This mechanism will be critical for endpoints designed to be called from a different origin, but it can also be a useful request forgery prevention mechanism for endpoints which are not designed to be called from a different origin. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 3.5.1 | 1 | Verify that, if the application does not rely on the CORS preflight mechanism to prevent disallowed cross‑origin requests to use sensitive functionality, these requests are validated to ensure they originate from the application itself. This may be done by using and validating anti‑forgery tokens or requiring extra HTTP header fields that are not CORS‑safelisted request‑header fields. This is to defend against browser‑based request forgery attacks, commonly known as cross‑site request forgery (CSRF). | Compliant | CSRF protection via Nette form addProtection() in BaseFormTrait. All forms automatically include anti-forgery tokens. | — | +| 3.5.2 | 1 | Verify that, if the application relies on the CORS preflight mechanism to prevent disallowed cross‑origin use of sensitive functionality, it is not possible to call the functionality with a request which does not trigger a CORS‑preflight request. This may require checking the values of the 'Origin' and 'Content‑Type'request header fields or using an extra header field that is not a CORS‑safelisted header‑field. | Compliant | Application does not rely on CORS preflight. Uses CSRF tokens (addProtection) and POST methods for state-changing operations. | — | +| 3.5.3 | 1 | Verify that HTTP requests to sensitive functionality use appropriate HTTP methods such as POST, PUT, PATCH, or DELETE, and not methods defined by the HTTP specification as "safe"such as HEAD, OPTIONS, or GET. Alternatively, strict validation of the Sec‑Fetch‑* request header fields can be used to ensure that the request did not originate from an inappropriate cross‑origin call, a navigation request, or a resource load (such as an image source) where this is not expected. | Compliant | Nette forms use POST method. State-changing operations use POST/PUT/DELETE. | — | +| 3.5.4 | 2 | Verify that separate applications are hosted on different hostnames to leverage the restrictions provided by same‑origin policy, including how documents or scripts loaded by one origin can interact with resources from another origin and hostname‑based restrictions on cookies. | Compliant | Single application per hostname. No cross-origin resource sharing needed. | — | +| 3.5.5 | 2 | Verify that messages received by the postMessage interface are discarded if the origin of the message is not trusted, or if the syntax of the message is invalid. | Out of scope | Application does not use postMessage API. | — | +| 3.5.6 | 3 | Verify that JSONP functionality is not enabled anywhere across the application to avoid Cross‑Site Script Inclusion (XSSI) attacks. | | | | +| 3.5.7 | 3 | Verify that data requiring authorization is not included in script resource responses, like JavaScript files, to prevent Cross‑Site Script Inclusion (XSSI) attacks. | | | | +| 3.5.8 | 3 | Verify that authenticated resources (such as images, videos, scripts, and other documents) can be loaded or embedded on behalf of the user only when intended. This can be accomplished by strict validation of the Sec‑Fetch‑* HTTP request header fields to ensure that the request did not originate from an inappropriate cross‑origin call, or by setting a restrictive Cross‑Origin‑Resource‑Policy HTTP response header field to instruct the browser to block returned content. | | | | + +## V3.6 External Resource Integrity + +This section provides guidance for the safe hosting of content on third‑party sites. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 3.6.1 | 3 | Verify that client‑side assets, such as JavaScript libraries, CSS, or web fonts, are only hosted externally (e.g., on a Content Delivery Network) if the resource is static and versioned and Subresource Integrity (SRI) is used to validate the integrity of the asset. If this is not possible, there should be a documented security decision to justify this for each resource. | | | | + +## V3.7 Other Browser Security Considerations + +This section includes various other security controls and modern browser security features required for client‑side browser security. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 3.7.1 | 2 | Verify that the application only uses client‑side technologies which are still supported and considered secure. Examples of technologies which do not meet this requirement include NSAPI plugins, Flash, Shockwave, ActiveX, Silverlight, NACL, or client‑side Java applets. | Compliant | No legacy plugins (Flash, Silverlight, etc.). Modern JS/CSS stack with Vite. | — | +| 3.7.2 | 2 | Verify that the application will only automatically redirect the user to a different hostname or domain (which is not controlled by the application) where the destination appears on an allowlist. | Compliant | Application does not perform automatic redirects to external domains. Nette routing handles internal redirects only. | — | +| 3.7.3 | 3 | Verify that the application shows a notification when the user is being redirected to a URL outside of the application's control, with an option to cancel the navigation. | | | | +| 3.7.4 | 3 | Verify that the application's top‑level domain (e.g., site.tld) is added to the public preload list for HTTP Strict Transport Security (HSTS). This ensures that the use of TLS for the application is built directly into the main browsers, rather than relying only on the Strict‑Transport‑Security response header field. | | | | +| 3.7.5 | 3 | Verify that the application behaves as documented (such as warning the user or blocking access) if the browser used to access the application does not support the expected security features. | | | | + +--- + +**Total requirements in this chapter: 31** +- Level 1: 8 +- Level 2: 11 +- Level 3: 12 diff --git a/ASVS/V04-API-and-Web-Service.md b/ASVS/V04-API-and-Web-Service.md new file mode 100644 index 0000000..2b0d3d2 --- /dev/null +++ b/ASVS/V04-API-and-Web-Service.md @@ -0,0 +1,54 @@ +# V4 API and Web Service + +OWASP Application Security Verification Standard 5.0.0 + +## V4.1 Generic Web Service Security + +This section addresses general web service security considerations and, consequently, basic web service hygiene practices. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 4.1.1 | 1 | Verify that every HTTP response with a message body contains a Content‑Type header field that matches the actual content of the response, including the charset parameter to specify safe character encoding (e.g., UTF‑8, ISO‑8859‑1) according to IANA Media Types, such as "text/", "/+xml" and "/xml". | Compliant | Nette framework handles Content-Type validation. JSON APIs use Nette\Utils\Json. | — | +| 4.1.2 | 2 | Verify that only user‑facing endpoints (intended for manual web‑browser access) automatically redirect from HTTP to HTTPS, while other services or endpoints do not implement transparent redirects. This is to avoid a situation where a client is erroneously sending unencrypted HTTP requests, but since the requests are being automatically redirected to HTTPS, the leakage of sensitive data goes undiscovered. | Compliant | Application uses Nette presenters for user-facing endpoints. No separate machine-to-machine API endpoints exposed to users. | — | +| 4.1.3 | 2 | Verify that any HTTP header field used by the application and set by an intermediary layer, such as a load balancer, a web proxy, or a backend‑for‑frontend service, cannot be overridden by the end‑user. Example headers might include X‑Real‑IP, X‑Forwarded‑*, or X‑User‑ID. | Compliant | Standard HTTP headers used. Custom headers validated by Nette framework. | — | +| 4.1.4 | 3 | Verify that only HTTP methods that are explicitly supported by the application or its API (including OPTIONS during preflight requests) can be used and that unused methods are blocked. | | | | +| 4.1.5 | 3 | Verify that per‑message digital signatures are used to provide additional assurance on top of transport protections for requests or transactions which are highly sensitive or which traverse a number of systems. | | | | + +## V4.2 HTTP Message Structure Validation + +This section explains how the structure and header fields of an HTTP message should be validated to prevent attacks such as request smuggling, response splitting, header injection, and denial of service via overly long HTTP messages. These requirements are relevant for general HTTP message processing and generation, but are es‑ pecially important when converting HTTP messages between different HTTP versions. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 4.2.1 | 2 | Verify that all application components (including load balancers, firewalls, and application servers) determine boundaries of incoming HTTP messages using the appropriate mechanism for the HTTP version to prevent HTTP request smuggling. In HTTP/1.x, if a Transfer‑Encoding header field is present, the Content‑Length header must be ignored per RFC 2616. When using HTTP/2 or HTTP/3, if a Content‑Length header field is present, the receiver must ensure that it is consistent with the length of the DATA frames. | Compliant | Single Nette application. No mixed HTTP method interpretation. Nette router consistently handles methods. | — | +| 4.2.2 | 3 | Verify that when generating HTTP messages, the Content‑Length header field does not conflict with the length of the content as determined by the framing of the HTTP protocol, in order to prevent request smuggling attacks. | | | | +| 4.2.3 | 3 | Verify that the application does not send nor accept HTTP/2 or HTTP/3 messages with connection‑specific header fields such as Transfer‑Encoding to prevent response splitting and header injection attacks. | | | | +| 4.2.4 | 3 | Verify that the application only accepts HTTP/2 and HTTP/3 requests where the header fields and values do not contain any CR (\r), LF (\n), or CRLF (\r\n) sequences, to prevent header injection attacks. | | | | +| 4.2.5 | 3 | Verify that, if the application (backend or frontend) builds and sends requests, it uses validation, sanitization, or other mechanisms to avoid creating URIs (such as for API calls) or HTTP request header fields (such as Authorization or Cookie), which are too long to be accepted by the receiving component. This could cause a denial of service, such as when sending an overly long request (e.g., a long cookie header field), which results in the server always responding with an error status. | | | | + +## V4.3 GraphQL + +GraphQL is becoming more common as a way of creating data‑rich clients that are not tightly coupled to a variety of backend services. This section covers security considerations for GraphQL. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 4.3.1 | 2 | Verify that a query allowlist, depth limiting, amount limiting, or query cost analysis is used to prevent GraphQL or data layer expression Denial of Service (DoS) as a result of expensive, nested queries. | Out of scope | Application does not use GraphQL. | — | +| 4.3.2 | 2 | Verify that GraphQL introspection queries are disabled in the production environment unless the GraphQL API is meant to be used by other parties. | Out of scope | Application does not use GraphQL. | — | + +## V4.4 WebSocket + +WebSocket is a communications protocol that provides a simultaneous two‑way communication channel over a single TCP connection. It was standardized by the IETF as RFC 6455 in 2011 and is distinct from HTTP, even though it is designed to work over HTTP ports 443 and 80. This section provides key security requirements to prevent attacks related to communication security and session management that specifically exploit this real‑time communication channel. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 4.4.1 | 1 | Verify that WebSocket over TLS (WSS) is used for all WebSocket connections. | Out of scope | WebSocket usage is project-specific, not part of fancyadmin framework. | — | +| 4.4.2 | 2 | Verify that, during the initial HTTP WebSocket handshake, the Origin header field is checked against a list of origins allowed for the application. | Out of scope | WebSocket usage is project-specific, not part of fancyadmin framework. | — | +| 4.4.3 | 2 | Verify that, if the application's standard session management cannot be used, dedicated tokens are being used for this, which comply with the relevant Session Management security requirements. | Out of scope | WebSocket usage is project-specific, not part of fancyadmin framework. | — | +| 4.4.4 | 2 | Verify that dedicated WebSocket session management tokens are initially obtained or validated through the previously authenticated HTTPS session when transitioning an existing HTTPS session to a WebSocket channel. | Out of scope | WebSocket usage is project-specific, not part of fancyadmin framework. | — | + +--- + +**Total requirements in this chapter: 16** +- Level 1: 2 +- Level 2: 8 +- Level 3: 6 diff --git a/ASVS/V05-File-Handling.md b/ASVS/V05-File-Handling.md new file mode 100644 index 0000000..c0daf73 --- /dev/null +++ b/ASVS/V05-File-Handling.md @@ -0,0 +1,51 @@ +# V5 File Handling + +OWASP Application Security Verification Standard 5.0.0 + +## V5.1 File Handling Documentation + +This section includes a requirement to document the expected characteristics of files accepted by the application, as a necessary precondition for developing and verifying relevant security checks. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 5.1.1 | 2 | Verify that the documentation defines the permitted file types, expected file extensions, and maximum size (including unpacked size) for each upload feature. Additionally, ensure that the documentation specifies how files are made safe for end‑users to download and process, such as how the application behaves when a malicious file is detected. | Partial | No formal documentation of permitted file types, sizes, or frequency. Validation depends on per-project configuration. | Per-project: document allowed MIME types (reference `FileUploadRules::ALLOWED_MIME_TYPES`), file extensions, and max sizes per upload feature. | + +## V5.2 File Upload and Content + +File upload functionality is a primary source of untrusted files. This section outlines the require‑ ments for ensuring that the presence, volume, or content of these files cannot harm the applica‑ tion. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 5.2.1 | 1 | Verify that the application will only accept files of a size which it can process without causing a loss of performance or a denial of service attack. | Compliant | BaseForm asserts every UploadControl has Form::MaxFileSize rule (throws LogicException if missing). Summernote handler checks size against FileUploadRules::MAX_FILE_SIZE. | — | +| 5.2.2 | 1 | Verify that when the application accepts a file, either on its own or within an archive such as a zip file, it checks if the file extension matches an expected file extension and validates that the contents correspond to the type represented by the extension. This includes, but is not limited to, checking the initial 'magic bytes', performing image re‑writing, and using specialized libraries for file content validation. For L1, this can focus just on files which are used to make specific business or security decisions. For L2 and up, this must apply to all files being accepted. | Compliant | BaseForm asserts every UploadControl has Form::MimeType or Form::Image rule (throws LogicException if missing). Nette validates MIME via finfo magic bytes. Summernote handler checks against FileUploadRules::ALLOWED_MIME_TYPES. | — | +| 5.2.3 | 2 | Verify that the application checks compressed files (e.g., zip, gz, docx, odt) against maximum allowed uncompressed size and against maximum number of files before uncompressing the file. | Partial | No compressed file (zip bomb) validation. Needs implementation if compressed files are accepted. | Per-project: if accepting .zip/.docx/.odt uploads, add decompression size and file count limits before extraction. | +| 5.2.4 | 3 | Verify that a file size quota and maximum number of files per user are enforced to ensure that a single user cannot fill up the storage with too many files, or excessively large files. | | | | +| 5.2.5 | 3 | Verify that the application does not allow uploading compressed files containing symlinks unless this is specifically required (in which case it will be necessary to enforce an allowlist of the files that can be symlinked to). | | | | +| 5.2.6 | 3 | Verify that the application rejects uploaded images with a pixel size larger than the maximum allowed, to prevent pixel flood attacks. | | | | + +## V5.3 File Storage + +This section includes requirements to prevent files from being inappropriately executed after upload, to detect dangerous content, and to avoid untrusted data being used to control where files are being stored. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 5.3.1 | 1 | Verify that files uploaded or generated by untrusted input and stored in a public folder, are not executed as server‑side program code when accessed directly with an HTTP request. | Compliant | Nginx snippet provided in config/nginx/uploads.conf blocks PHP execution in upload directory. Private files stored outside webroot. Filenames randomized with hash. | Include `vendor/adt/fancyadmin/config/nginx/uploads.conf` in your nginx server block. Adjust the location path to match your FileListener dataDir. | +| 5.3.2 | 1 | Verify that when the application creates file paths for file operations, instead of user‑submitted filenames, it uses internally generated or trusted data, or if user‑submitted filenames or file metadata must be used, strict validation and sanitization must be applied. This is to protect against path traversal, local or remote file inclusion (LFI, RFI), and server‑side request forgery (SSRF) attacks. | Compliant | Filenames are generated by adt/files with ID-based directory structure and random hash. Original filename is webalized and sanitized. No user input in filesystem paths. | — | +| 5.3.3 | 3 | Verify that server‑side file processing, such as file decompression, ignores user‑provided path information to prevent vulnerabilities such as zip slip. | | | | + +## V5.4 File Download + +This section contains requirements to mitigate risks when serving files to be downloaded, including path traversal and injection attacks. This also includes making sure they don't contain dangerous content. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 5.4.1 | 2 | Verify that the application validates or ignores user‑submitted filenames, including in a JSON, JSONP, or URL parameter and specifies a filename in the Content‑Disposition header field in the response. | Partial | No explicit metadata stripping. Original EXIF data preserved in uploaded images. | Per-project: strip EXIF metadata from uploaded images using PHP `gd` (re-process via `imagecreatefrom*`) or `imagick`. | +| 5.4.2 | 2 | Verify that file names served (e.g., in HTTP response header fields or email attachments) are encoded or sanitized (e.g., following RFC 6266) to preserve document structure and prevent injection attacks. | Compliant | Filenames served are generated by the system (webalized + random hash). No user-controlled filename in HTTP responses. | — | +| 5.4.3 | 2 | Verify that files obtained from untrusted sources are scanned by antivirus scanners to prevent serving of known malicious content. | Partial | No antivirus scanning of uploaded files. Needs implementation (e.g., ClamAV integration). | Per-project: integrate ClamAV scanning via PHP socket (`/var/run/clamav/clamd.ctl`) before persisting uploaded files. | + +--- + +**Total requirements in this chapter: 13** +- Level 1: 4 +- Level 2: 5 +- Level 3: 4 diff --git a/ASVS/V06-Authentication.md b/ASVS/V06-Authentication.md new file mode 100644 index 0000000..85f9e33 --- /dev/null +++ b/ASVS/V06-Authentication.md @@ -0,0 +1,113 @@ +# V6 Authentication + +OWASP Application Security Verification Standard 5.0.0 + +## V6.1 Authentication Documentation + +This section contains requirements detailing the authentication documentation that should be main‑ tained for an application. This is crucial for implementing and assessing how the relevant authenti‑ cation controls should be configured. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 6.1.1 | 1 | Verify that application documentation defines how controls such as rate limiting, anti‑automation, and adaptive response, are used to defend against attacks such as credential stuffing and password brute force. The documentation must make clear how these controls are configured and prevent malicious account lockout. | Partial | Rate limiting configured via setLoginAttemptProtection(). Documentation of controls not yet formalized in ASVS format. | Per-project: document `setLoginAttemptProtection($maxAttempts, $timeout)` values and rationale in project security docs. | +| 6.1.2 | 2 | Verify that a list of context‑specific words is documented in order to prevent their use in passwords. The list could include permutations of organization names, product names, system identifiers, project codenames, department or role names, and similar. | Partial | Context-specific word list not yet documented or implemented. | Per-project: create context-specific word list (org name, product name, domain) for password deny list. | +| 6.1.3 | 2 | Verify that, if the application includes multiple authentication pathways, these are all documented together with the security controls and authentication strength which must be consistently enforced across them. | Compliant | Single authentication pathway (email/username + password). No multiple pathways. | — | + +## V6.2 Password Security + +Passwords, called "Memorized Secrets"by NIST SP 800‑63, include passwords, passphrases, PINs, unlock patterns, and picking the correct kitten or another image element. They are generally con‑ sidered "something you know"and are often used as a single‑factor authentication mechanism. As such, this section contains requirements for making sure that passwords are created and handled securely. Most of the requirements are L1 as they are most important at that level. From L2 on‑ wards, multi‑factor authentication mechanisms are required, where passwords may be one of those factors. The requirements in this section mostly relate to § 5.1.1.2 of NIST's Guidance. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 6.2.1 | 1 | Verify that user set passwords are at least 8 characters in length although a minimum of 15 characters is strongly recommended. | Compliant | Configurable password policy stored in Configuration table. Minimum length enforced (default 8, configurable). NewPasswordFormTrait validates against policy. | — | +| 6.2.2 | 1 | Verify that users can change their password. | Compliant | Password change available via NewPassword form (Account page / admin-initiated reset). | — | +| 6.2.3 | 1 | Verify that password change functionality requires the user's current and new password. | Compliant | ChangePasswordFormTrait on Account page requires current password + new password. Password recovery via email token (NewPasswordFormTrait) does not require current password by design — recovery flow for users who lost access. | — | +| 6.2.4 | 1 | Verify that passwords submitted during account registration or password change are checked against an available set of, at least, the top 3000 passwords which match the application's password policy, e.g. minimum length. | Compliant | BreachedPasswordChecker checks against local top 10k common passwords list (resources/common-passwords.txt). Integrated into NewPasswordFormTrait::validateForm(). | — | +| 6.2.5 | 1 | Verify that passwords of any composition can be used, without rules limiting the type of characters permitted. There must be no requirement for a minimum number of upper or lower case characters, numbers, or special characters. | Compliant | Password policy is disabled by default (enabled: false in Configuration). No composition rules enforced — passwords of any composition accepted. Only minimum length (8 chars) required at form level. | — | +| 6.2.6 | 1 | Verify that password input fields use type=password to mask the entry. Applications may allow the user to temporarily view the entire masked password, or the last typed character of the password. | Compliant | Password input fields use type=password. Nette forms default behavior. | — | +| 6.2.7 | 1 | Verify that "paste"functionality, browser password helpers, and external password managers are permitted. | Compliant | No restrictions on paste functionality or password managers. Standard HTML inputs. | — | +| 6.2.8 | 1 | Verify that the application verifies the user's password exactly as received from the user, without any modifications such as truncation or case transformation. | Compliant | Passwords verified as-is using password_verify(). No truncation or case transformation. | — | +| 6.2.9 | 2 | Verify that passwords of at least 64 characters are permitted. | Compliant | No maximum password length limit enforced by the application. | — | +| 6.2.10 | 2 | Verify that a user's password stays valid until it is discovered to be compromised or the user rotates it. The application must not require periodic credential rotation. | Compliant | No periodic credential rotation required. Passwords valid until user changes them. | — | +| 6.2.11 | 2 | Verify that the documented list of context specific words is used to prevent easy to guess passwords being created. | Partial | Context-specific word list not yet implemented. | Pending fancyadmin: add `setContextWordList(array)` to `BreachedPasswordChecker`. Per-project: configure via DI `setup:` in `common.neon`. | +| 6.2.12 | 2 | Verify that passwords submitted during account registration or password changes are checked against a set of breached passwords. | Compliant | BreachedPasswordChecker checks against local top 10k common passwords list and HaveIBeenPwned Pwned Passwords API (k-Anonymity, 500ms timeout, fail-open). Checked during password change in NewPasswordFormTrait::validateForm(). | — | + +## V6.3 General Authentication Security + +This section contains general requirements for the security of authentication mechanisms as well as setting out the different expectations for levels. L2 applications must force the use of multi‑factor authentication (MFA). L3 applications must use hardware‑based authentication, performed in an at‑ tested and trusted execution environment (TEE). This could include device‑bound passkeys, eIDAS Level of Assurance (LoA) High enforced authenticators, authenticators with NIST Authenticator As‑ surance Level 3 (AAL3) assurance, or an equivalent mechanism. While this is a relatively aggressive stance on MFA, it is critical to raise the bar around this to protect users, and any attempt to relax these requirements should be accompanied by a clear plan on how the risks around authentication will be mitigated, taking into account NIST's guidance and research on the topic. Note that at the time of release, NIST SP 800‑63 considers email as not acceptable as an authentication mechanism (archived copy). The requirements in this section relate to a variety of sections of NIST's Guidance, including: § 4.2.1, § 4.3.1, § 5.2.2, and § 6.1.2. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 6.3.1 | 1 | Verify that controls to prevent attacks such as credential stuffing and password brute force are implemented according to the application's security documentation. | Compliant | IP-based rate limiting via DoctrineAuthenticator. Configurable maxLoginAttempts and loginAttemptTimeout. | — | +| 6.3.2 | 1 | Verify that default user accounts (e.g., "root", "admin", or "sa") are not present in the application or are disabled. | Compliant | No default user accounts. All accounts created through application flows. | — | +| 6.3.3 | 2 | Verify that either a multi‑factor authentication mechanism or a combination of single‑factor authentication mechanisms, must be used in order to access the application. For L3, one of the factors must be a hardware‑based authentication mechanism which provides compromise and impersonation resistance against phishing attacks while verifying the intent to authenticate by requiring a user‑initiated action (such as a button press on a FIDO hardware key or a mobile phone). Relaxing any of the considerations in this requirement requires a fully documented rationale and a comprehensive set of mitigating controls. | Partial | MFA not yet implemented. Single-factor authentication (password) only. MFA is required for L2 compliance. | Pending fancyadmin: implement TOTP MFA. `IdentityTrait` already uses `DoctrineAuthenticator\OTP\IdentityTrait` as foundation. | +| 6.3.4 | 2 | Verify that, if the application includes multiple authentication pathways, there are no undocumented pathways and that security controls and authentication strength are enforced consistently. | Compliant | Single authentication pathway (email + password). No undocumented pathways. | — | +| 6.3.5 | 3 | Verify that users are notified of suspicious authentication attempts (successful or unsuccessful). This may include authentication attempts from an unusual location or client, partially successful authentication (only one of multiple factors), an authentication attempt after a long period of inactivity or a successful authentication after several unsuccessful attempts. | | | | +| 6.3.6 | 3 | Verify that email is not used as either a single‑factor or multi‑factor authentication mechanism. | | | | +| 6.3.7 | 3 | Verify that users are notified after updates to authentication details, such as credential resets or modification of the username or email address. | | | | +| 6.3.8 | 3 | Verify that valid users cannot be deduced from failed authentication challenges, such as by basing on error messages, HTTP response codes, or different response times. Registration and forgot password functionality must also have this protection. | Compliant | Generic error message 'wrongEmailOrPassword' for all auth failures. No user enumeration via error messages. | — | + +## V6.4 Authentication Factor Lifecycle and Recovery + +Authentication factors may include passwords, soft tokens, hardware tokens, and biometric devices. Securely handling the lifecycle of these mechanisms is critical to the security of an application, and this section includes requirements related to this. The requirements in this section mostly relate to § 5.1.1.2 or § 6.1.2.3 of NIST's Guidance. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 6.4.1 | 1 | Verify that system generated initial passwords or activation codes are securely randomly generated, follow the existing password policy, and expire after a short period of time or after they are initially used. These initial secrets must not be permitted to become the long term password. | Compliant | Initial passwords set via secure email link with token (OnetimeTokenService). Token expires. User must set their own password. | — | +| 6.4.2 | 1 | Verify that password hints or knowledge‑based authentication (so‑called "secret questions") are not present. | Compliant | No password hints or secret questions in the application. | — | +| 6.4.3 | 2 | Verify that a secure process for resetting a forgotten password is implemented, that does not bypass any enabled multi‑factor authentication mechanisms. | Compliant | Password reset via secure email link using OnetimeTokenService. Token-based recovery flow. | — | +| 6.4.4 | 2 | Verify that if a multi‑factor authentication factor is lost, evidence of identity proofing is performed at the same level as during enrollment. | Out of scope | MFA not yet implemented. | — | +| 6.4.5 | 3 | Verify that renewal instructions for authentication mechanisms which expire are sent with enough time to be carried out before the old authentication mechanism expires, configuring automated reminders if necessary. | | | | +| 6.4.6 | 3 | Verify that administrative users can initiate the password reset process for the user, but that this does not allow them to change or choose the user's password. This prevents a situation where they know the user's password. | Compliant | Admin initiates password reset which sends email to user. Admin cannot set or see the password. | — | + +## V6.5 General Multi‑factor authentication requirements + +This section provides general guidance that will be relevant to various different multi‑factor authen‑ tication methods. The mechanisms include: • Lookup Secrets • Time based One‑time Passwords (TOTPs) • Out‑of‑Band mechanisms Lookup secrets are pre‑generated lists of secret codes, similar to Transaction Authorization Num‑ bers (TAN), social media recovery codes, or a grid containing a set of random values. This type of authentication mechanism is considered "something you have"because the codes are deliberately not memorable so will need to be stored somewhere. Time based One‑time Passwords (TOTPs) are physical or soft tokens that display a continually changing pseudo‑random one‑time challenge. This type of authentication mechanism is considered "something you have". Multi‑factor TOTPs are similar to single‑factor TOTPs, but require a valid PIN code, biometric unlocking, USB insertion or NFC pairing, or some additional value (such as transaction signing calculators) to be entered to create the final One‑time Password (OTP). + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 6.5.1 | 2 | Verify that lookup secrets, out‑of‑band authentication requests or codes, and time‑based one‑time passwords (TOTPs) are only successfully usable once. | Out of scope | MFA not yet implemented. These requirements apply when MFA is added. | — | +| 6.5.2 | 2 | Verify that, when being stored in the application's backend, lookup secrets with less than 112 bits of entropy (19 random alphanumeric characters or 34 random digits) are hashed with an approved password storage hashing algorithm that incorporates a 32‑bit random salt. A standard hash function can be used if the secret has 112 bits of entropy or more. | Out of scope | MFA not yet implemented. These requirements apply when MFA is added. | — | +| 6.5.3 | 2 | Verify that lookup secrets, out‑of‑band authentication code, and time‑based one‑time password seeds, are generated using a Cryptographically Secure Pseudorandom Number Generator (CSPRNG) to avoid predictable values. | Out of scope | MFA not yet implemented. These requirements apply when MFA is added. | — | +| 6.5.4 | 2 | Verify that lookup secrets and out‑of‑band authentication codes have a minimum of 20 bits of entropy (typically 4 random alphanumeric characters or 6 random digits is sufficient). | Out of scope | MFA not yet implemented. These requirements apply when MFA is added. | — | +| 6.5.5 | 2 | Verify that out‑of‑band authentication requests, codes, or tokens, as well as time‑based one‑time passwords (TOTPs) have a defined lifetime. Out of band requests must have a maximum lifetime of 10 minutes and for TOTP a maximum lifetime of 30 seconds. | Out of scope | MFA not yet implemented. These requirements apply when MFA is added. | — | +| 6.5.6 | 3 | Verify that any authentication factor (including physical devices) can be revoked in case of theft or other loss. | | | | +| 6.5.7 | 3 | Verify that biometric authentication mechanisms are only used as secondary factors together with either something you have or something you know. | | | | +| 6.5.8 | 3 | Verify that time‑based one‑time passwords (TOTPs) are checked based on a time source from a trusted service and not from an untrusted or client provided time. | | | | + +## V6.6 Out‑of‑Band authentication mechanisms + +This usually involves the authentication server communicating with a physical device over a secure secondary channel. For example, sending push notifications to mobile devices. This type of authen‑ tication mechanism is considered "something you have". Unsafe out‑of‑band authentication mechanisms such as e‑mail and VOIP are not permitted. PSTN and SMS authentication are currently considered to be "restricted"authentication mechanisms by + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 6.6.1 | 2 | Verify that authentication mechanisms using the Public Switched Telephone Network (PSTN) to deliver One‑time Passwords (OTPs) via phone or SMS are offered only when the phone number has previously been validated, alternate stronger methods (such as Time based One‑time Passwords) are also offered, and the service provides information on their security risks to users. For L3 applications, phone and SMS must not be available as options. | Out of scope | MFA not yet implemented. These requirements apply when MFA is added. | — | +| 6.6.2 | 2 | Verify that out‑of‑band authentication requests, codes, or tokens are bound to the original authentication request for which they were generated and are not usable for a previous or subsequent one. | Out of scope | MFA not yet implemented. These requirements apply when MFA is added. | — | +| 6.6.3 | 2 | Verify that a code based out‑of‑band authentication mechanism is protected against brute force attacks by using rate limiting. Consider also using a code with at least 64 bits of entropy. | Out of scope | MFA not yet implemented. These requirements apply when MFA is added. | — | +| 6.6.4 | 3 | Verify that, where push notifications are used for multi‑factor authentication, rate limiting is used to prevent push bombing attacks. Number matching may also mitigate this risk. | | | | + +## V6.7 Cryptographic authentication mechanism + +Cryptographic authentication mechanisms include smart cards or FIDO keys, where the user has to plug in or pair the cryptographic device to the computer to complete authentication. The authenti‑ cation server will send a challenge nonce to the cryptographic device or software, and the device or software calculates a response based upon a securely stored cryptographic key. The requirements in this section provide implementation‑specific guidance for these mechanisms, with guidance on cryptographic algorithms being covered in the "Cryptography"chapter. Where shared or secret keys are used for cryptographic authentication, these should be stored using the same mechanisms as other system secrets, as documented in the "Secret Management"section in the "Configuration"chapter. The requirements in this section mostly relate to § 5.1.7.2 of NIST's Guidance. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 6.7.1 | 3 | Verify that the certificates used to verify cryptographic authentication assertions are stored in a way protects them from modification. | | | | +| 6.7.2 | 3 | Verify that the challenge nonce is at least 64 bits in length, and statistically unique or unique over the lifetime of the cryptographic device. | | | | + +## V6.8 Authentication with an Identity Provider + +Identity Providers (IdPs) provide federated identity for users. Users will often have more than one identity with multiple IdPs, such as an enterprise identity using Azure AD, Okta, Ping Identity, or Google, or consumer identity using Facebook, Twitter, Google, or WeChat, to name just a few com‑ mon alternatives. This list is not an endorsement of these companies or services, but simply an encouragement for developers to consider the reality that many users have many established identi‑ ties. Organizations should consider integrating with existing user identities, as per the risk profile of the IdP's strength of identity proofing. For example, it is unlikely a government organization would accept a social media identity as a login for sensitive systems, as it is easy to create fake or throw‑ away identities, whereas a mobile game company may well need to integrate with major social media platforms to grow their active player base. Secure use of external identity providers requires careful configuration and verification to prevent identity spoofing or forged assertions. This section provides requirements to address these risks. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 6.8.1 | 2 | Verify that, if the application supports multiple identity providers (IdPs), the user's identity cannot be spoofed via another supported identity provider (eg. by using the same user identifier). The standard mitigation would be for the application to register and identify the user using a combination of the IdP ID (serving as a namespace) and the user's ID in the IdP. | Out of scope | Application does not use external identity providers. | — | +| 6.8.2 | 2 | Verify that the presence and integrity of digital signatures on authentication assertions (for example on JWTs or SAML assertions) are always validated, rejecting any assertions that are unsigned or have invalid signatures. | Out of scope | Application does not use external identity providers. | — | +| 6.8.3 | 2 | Verify that SAML assertions are uniquely processed and used only once within the validity period to prevent replay attacks. | Out of scope | Application does not use external identity providers. | — | +| 6.8.4 | 2 | Verify that, if an application uses a separate Identity Provider (IdP) and expects specific authentication strength, methods, or recentness for specific functions, the application verifies this using the information returned by the IdP. For example, if OIDC is used, this might be achieved by validating ID Token claims such as 'acr', 'amr', and 'auth_time'(if present). If the IdP does not provide this information, the application must have a documented fallback approach that assumes that the minimum strength authentication mechanism was used (for example, single‑factor authentication using username and password). | Out of scope | Application does not use external identity providers. | — | + +--- + +**Total requirements in this chapter: 47** +- Level 1: 13 +- Level 2: 22 +- Level 3: 12 diff --git a/ASVS/V07-Session-Management.md b/ASVS/V07-Session-Management.md new file mode 100644 index 0000000..48a1c16 --- /dev/null +++ b/ASVS/V07-Session-Management.md @@ -0,0 +1,71 @@ +# V7 Session Management + +OWASP Application Security Verification Standard 5.0.0 + +## V7.1 Session Management Documentation + +There is no single pattern that suits all applications. Therefore, it is not feasible to define universal boundaries and limits that suit all cases. A risk analysis with documented security decisions related to session handling must be conducted as a prerequisite to implementation and testing. This ensures that the session management system is tailored to the specific requirements of the application. Regardless of whether a stateful or "stateless"session mechanism is chosen, the analysis must be complete and documented to demonstrate that the selected solution is capable of satisfying all rel‑ evant security requirements. Interaction with any Single Sign‑on (SSO) mechanisms in use should also be considered. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 7.1.1 | 2 | Verify that the user's session inactivity timeout and absolute maximum session lifetime are documented, are appropriate in combination with other controls, and that the documentation includes justification for any deviations from NIST SP 800‑63B re‑authentication requirements. | Partial | Inactivity timeout: 14 days (configurable via SessionExpirationCallback). Absolute lifetime: same as inactivity (extended on each request). Documentation not yet formalized. | Per-project: document `sessionExpirationMinutes` values in `password.policy.admin`/`password.policy.backoffice` Configuration entities with justification. | +| 7.1.2 | 2 | Verify that the documentation defines how many concurrent (parallel) sessions are allowed for one account as well as the intended behaviors and actions to be taken when the maximum number of active sessions is reached. | Partial | No limit on concurrent sessions. Documentation not yet formalized. | Per-project: document concurrent session policy. Currently unlimited — decide if limit needed and configure in `DoctrineAuthenticator`. | +| 7.1.3 | 2 | Verify that all systems that create and manage user sessions as part of a federated identity management ecosystem (such as SSO systems) are documented along with controls to coordinate session lifetimes, termination, and any other conditions that require re‑authentication. | Out of scope | No federated identity management / SSO in use. | — | + +## V7.2 Fundamental Session Management Security + +This section satisfies the essential requirements of secure sessions by verifying that session tokens are securely generated and validated. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 7.2.1 | 1 | Verify that the application performs all session token verification using a trusted, backend service. | Compliant | All session token verification in DoctrineAuthenticator backend. Token looked up via SHA-256 hash in database. | — | +| 7.2.2 | 1 | Verify that the application uses either self‑contained or reference tokens that are dynamically generated for session management, i.e. not using static API secrets and keys. | Compliant | Reference tokens dynamically generated per session via Nette\Utils\Random::generate(32). | — | +| 7.2.3 | 1 | Verify that if reference tokens are used to represent user sessions, they are unique and generated using a cryptographically secure pseudo‑random number generator (CSPRNG) and possess at least 128 bits of entropy. | Compliant | 32-character random tokens generated via CSPRNG (Random::generate). 128+ bits of entropy. | — | +| 7.2.4 | 1 | Verify that the application generates a new session token on user authentication, including re‑authentication, and terminates the current session token. | Compliant | New session token generated on each authentication via sleepIdentity(). Previous token not reused. | — | + +## V7.3 Session Timeout + +Session timeout mechanisms serve to minimize the window of opportunity for session hijacking and other forms of session abuse. Timeouts must satisfy documented security decisions. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 7.3.1 | 2 | Verify that there is an inactivity timeout such that re‑authentication is enforced according to risk analysis and documented security decisions. | Compliant | Session inactivity managed via validUntil on StorageEntity. Extended on each request. Configurable expiration (default 14 days). | — | +| 7.3.2 | 2 | Verify that there is an absolute maximum session lifetime such that re‑authentication is enforced according to risk analysis and documented security decisions. | Compliant | Absolute session lifetime via validUntil field. SessionExpirationCallback allows per-identity expiration. | — | + +## V7.4 Session Termination + +Session termination may be handled either by the application itself or by the SSO provider if the SSO provider is handling session management instead of the application. It may be necessary to decide whether the SSO provider is in scope when considering the requirements in this section as some may be controlled by the provider. Session termination should result in requiring re‑authentication and be effective across the applica‑ tion, federated login (if present), and any relying parties. For stateful session mechanisms, termination typically involves invalidating the session on the back‑ end. In the case of self‑contained tokens, additional measures are required to revoke or block these tokens, as they may otherwise remain valid until expiration. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 7.4.1 | 1 | Verify that when session termination is triggered (such as logout or expiration), the application disallows any further use of the session. For reference tokens or stateful sessions, this means invalidating the session data at the application backend. Applications using self‑contained tokens will need a solution such as maintaining a list of terminated tokens, disallowing tokens produced before a per‑user date and time or rotating a per‑user signing key. | Compliant | Logout sets validUntil to now via clearIdentity(). Token invalidated in database. Further use blocked by validUntil check in wakeupIdentity(). | — | +| 7.4.2 | 1 | Verify that the application terminates all active sessions when a user account is disabled or deleted (such as an employee leaving the company). | Compliant | clearIdentity(objectId) invalidates all sessions for a user by setting validUntil to now. | — | +| 7.4.3 | 2 | Verify that the application gives the option to terminate all other active sessions after a successful change or removal of any authentication factor (including password change via reset or recovery and, if present, an MFA settings update). | Compliant | Password change in NewPasswordFormTrait calls clearIdentity() which invalidates all sessions, then creates a new session for the current user. 'Logout all devices' also available on Account page. | — | +| 7.4.4 | 2 | Verify that all pages that require authentication have easy and visible access to logout functionality. | Compliant | Logout button in profile dropdown menu and side menu, visible on all authenticated pages. | — | +| 7.4.5 | 2 | Verify that application administrators are able to terminate active sessions for an individual user or for all users. | Compliant | Admin can manage sessions via clearIdentity(objectId). clearSession(sessionId) for individual session termination. | — | + +## V7.5 Defenses Against Session Abuse + +This section provides requirements to mitigate the risk posed by active sessions that are either hi‑ jacked or abused through vectors that rely on the existence and capabilities of active user sessions. For example, using malicious content execution to force an authenticated victim browser to perform an action using the victim's session. Note that the level‑specific guidance in the "Authentication"chapter should be taken into account when considering requirements in this section. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 7.5.1 | 2 | Verify that the application requires full re‑authentication before allowing modifications to sensitive account attributes which may affect authentication such as email address, phone number, MFA configuration, or other information used in account recovery. | Partial | No re-authentication required before changing email or other sensitive attributes. | Pending fancyadmin: add re-authentication dialog (password confirmation) before sensitive changes (email, password). Reference `ChangePasswordFormTrait`. | +| 7.5.2 | 2 | Verify that users are able to view and (having authenticated again with at least one factor) terminate any or all currently active sessions. | Compliant | Active sessions visible on Account page with IP, User-Agent, creation date, validity. Users can terminate individual sessions via clearSession(). | — | +| 7.5.3 | 3 | Verify that the application requires further authentication with at least one factor or secondary verification before performing highly sensitive transactions or operations. | | | | + +## V7.6 Federated Re‑authentication + +This section relates to those writing Relying Party (RP) or Identity Provider (IdP) code. These re‑ quirements are derived from the NIST SP 800‑63C for Federation & Assertions. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 7.6.1 | 2 | Verify that session lifetime and termination between Relying Parties (RPs) and Identity Providers (IdPs) behave as documented, requiring re‑authentication as necessary such as when the maximum time between IdP authentication events is reached. | Out of scope | No federated identity management / SSO in use. | — | +| 7.6.2 | 2 | Verify that creation of a session requires either the user's consent or an explicit action, preventing the creation of new application sessions without user interaction. | Compliant | Session is only created after explicit user login action (form submission with credentials). | — | + +--- + +**Total requirements in this chapter: 19** +- Level 1: 6 +- Level 2: 12 +- Level 3: 1 diff --git a/ASVS/V08-Authorization.md b/ASVS/V08-Authorization.md new file mode 100644 index 0000000..1ce8377 --- /dev/null +++ b/ASVS/V08-Authorization.md @@ -0,0 +1,51 @@ +# V8 Authorization + +OWASP Application Security Verification Standard 5.0.0 + +## V8.1 Authorization Documentation + +Comprehensive authorization documentation is essential to ensure that security decisions are con‑ sistently applied, auditable, and aligned with organizational policies. This reduces the risk of unau‑ thorized access by making security requirements clear and actionable for developers, administra‑ tors, and testers. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 8.1.1 | 1 | Verify that authorization documentation defines rules for restricting function‑level and data‑specific access based on consumer permissions and resource attributes. | Partial | ACL resources and roles documented in code. No formal authorization documentation. | Per-project: document all `AclResource` entries and which `AclRole` has access. Use `Permission` class as reference. | +| 8.1.2 | 2 | Verify that authorization documentation defines rules for field‑level access restrictions (both read and write) based on consumer permissions and resource attributes. Note that these rules might depend on other attribute values of the relevant data object, such as state or status. | Partial | Field-level access not formally documented. ACL handles resource-level access. | Per-project: document field-level access restrictions per `AclRole` for sensitive entity fields. | +| 8.1.3 | 3 | Verify that the application's documentation defines the environmental and contextual attributes (including but not limited to, time of day, user location, IP address, or device) that are used in the application to make security decisions, including those pertaining to authentication and authorization. | | | | +| 8.1.4 | 3 | Verify that authentication and authorization documentation defines how environmental and contextual factors are used in decision‑making, in addition to function‑level, data‑specific, and field‑level authorization. This should include the attributes evaluated, thresholds for risk, and actions taken (e.g., allow, challenge, deny, step‑up authentication). | | | | + +## V8.2 General Authorization Design + +Implementing granular authorization controls at the function, data, and field levels ensures that con‑ sumers can access only what has been explicitly granted to them. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 8.2.1 | 1 | Verify that the application ensures that function‑level access is restricted to consumers with explicit permissions. | Compliant | Nette Security with ACL-based authorization. Permission checks via SecurityUser and AclResource system. | — | +| 8.2.2 | 1 | Verify that the application ensures that data‑specific access is restricted to consumers with explicit permissions to specific data items to mitigate insecure direct object reference (IDOR) and broken object level authorization (BOLA). | Compliant | Doctrine security filters enforce data-specific access control per Account (tenant). Users only see data belonging to their Account. | — | +| 8.2.3 | 2 | Verify that the application ensures that field‑level access is restricted to consumers with explicit permissions to specific fields to mitigate broken object property level authorization (BOPLA). | Partial | Field-level access control not systematically implemented. ACL works at resource/action level. | Pending fancyadmin: implement field-level ACL. Currently `#[SecurityCheckAttribute]` and `Permission` work at resource/action level only. | +| 8.2.4 | 3 | Verify that adaptive security controls based on a consumer's environmental and contextual attributes (such as time of day, location, IP address, or device) are implemented for authentication and authorization decisions, as defined in the application's documentation. These controls must be applied when the consumer tries to start a new session and also during an existing session. | | | | + +## V8.3 Operation Level Authorization + +The immediate application of authorization changes in the appropriate tier of an application's archi‑ tecture is crucial to preventing unauthorized actions, especially in dynamic environments. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 8.3.1 | 1 | Verify that the application enforces authorization rules at a trusted service layer and doesn't rely on controls that an untrusted consumer could manipulate, such as client‑side JavaScript. | Compliant | Presenter-level authorization checks. ACL resources mapped to presenter actions. | — | +| 8.3.2 | 3 | Verify that changes to values on which authorization decisions are made are applied immediately. Where changes cannot be applied immediately, (such as when relying on data in self‑contained tokens), there must be mitigating controls to alert when a consumer performs an action when they are no longer authorized to do so and revert the change. Note that this alternative would not mitigate information leakage. | | | | +| 8.3.3 | 3 | Verify that access to an object is based on the originating subject's (e.g. consumer's) permissions, not on the permissions of any intermediary or service acting on their behalf. For example, if a consumer calls a web service using a self‑contained token for authentication, and the service then requests data from a different service, the second service will use the consumer's token, rather than a machine‑to‑machine token from the first service, to make permission decisions. | | | | + +## V8.4 Other Authorization Considerations + +Additional considerations for authorization, particularly for administrative interfaces and multi‑ tenant environments, help prevent unauthorized access. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 8.4.1 | 2 | Verify that multi‑tenant applications use cross‑tenant controls to ensure consumer operations will never affect tenants with which they do not have permissions to interact. | Compliant | Multi-tenant data isolation via Doctrine security filters. Queries automatically scoped to current Account. Cross-tenant access prevented at ORM level. | — | +| 8.4.2 | 3 | Verify that access to administrative interfaces incorporates multiple layers of security, including continuous consumer identity verification, device security posture assessment, and contextual risk analysis, ensuring that network location or trusted endpoints are not the sole factors for authorization even though they may reduce the likelihood of unauthorized access. | | | | + +--- + +**Total requirements in this chapter: 13** +- Level 1: 4 +- Level 2: 3 +- Level 3: 6 diff --git a/ASVS/V09-Self-contained-Tokens.md b/ASVS/V09-Self-contained-Tokens.md new file mode 100644 index 0000000..6436363 --- /dev/null +++ b/ASVS/V09-Self-contained-Tokens.md @@ -0,0 +1,31 @@ +# V9 Self‑contained Tokens + +OWASP Application Security Verification Standard 5.0.0 + +## V9.1 Token source and integrity + +This section includes requirements to ensure that the token has been produced by a trusted party and has not been tampered with. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 9.1.1 | 1 | Verify that self‑contained tokens are validated using their digital signature or MAC to protect against tampering before accepting the token's contents. | Out of scope | Application uses reference tokens (DoctrineAuthenticator), not self-contained tokens like JWT/SAML. | — | +| 9.1.2 | 1 | Verify that only algorithms on an allowlist can be used to create and verify self‑contained tokens, for a given context. The allowlist must include the permitted algorithms, ideally only either symmetric or asymmetric algorithms, and must not include the 'None'algorithm. If both symmetric and asymmetric must be supported, additional controls will be needed to prevent key confusion. | Out of scope | Application uses reference tokens (DoctrineAuthenticator), not self-contained tokens like JWT/SAML. | — | +| 9.1.3 | 1 | Verify that key material that is used to validate self‑contained tokens is from trusted pre‑configured sources for the token issuer, preventing attackers from specifying untrusted sources and keys. For JWTs and other JWS structures, headers such as 'jku', 'x5u', and 'jwk'must be validated against an allowlist of trusted sources. | Out of scope | Application uses reference tokens (DoctrineAuthenticator), not self-contained tokens like JWT/SAML. | — | + +## V9.2 Token content + +Before making security decisions based on the content of a self‑contained token, it is necessary to validate that the token has been presented within its validity period and that it is intended for use by the receiving service and for the purpose for which it was presented. This helps avoid insecure cross‑usage between different services or with different token types from the same issuer. Specific requirements for OAuth and OIDC are covered in the dedicated chapter. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 9.2.1 | 1 | Verify that, if a validity time span is present in the token data, the token and its content are accepted only if the verification time is within this validity time span. For example, for JWTs, the claims 'nbf'and 'exp'must be verified. | Out of scope | Application uses reference tokens (DoctrineAuthenticator), not self-contained tokens like JWT/SAML. | — | +| 9.2.2 | 2 | Verify that the service receiving a token validates the token to be the correct type and is meant for the intended purpose before accepting the token's contents. For example, only access tokens can be accepted for authorization decisions and only ID Tokens can be used for proving user authentication. | Out of scope | Application uses reference tokens (DoctrineAuthenticator), not self-contained tokens like JWT/SAML. | — | +| 9.2.3 | 2 | Verify that the service only accepts tokens which are intended for use with that service (audience). For JWTs, this can be achieved by validating the 'aud' claim against an allowlist defined in the service. | Out of scope | Application uses reference tokens (DoctrineAuthenticator), not self-contained tokens like JWT/SAML. | — | +| 9.2.4 | 2 | Verify that, if a token issuer uses the same private key for issuing tokens to different audiences, the issued tokens contain an audience restriction that uniquely identifies the intended audiences. This will prevent a token from being reused with an unintended audience. If the audience identifier is dynamically provisioned, the token issuer must validate these audiences in order to make sure that they do not result in audience impersonation. | Out of scope | Application uses reference tokens (DoctrineAuthenticator), not self-contained tokens like JWT/SAML. | — | + +--- + +**Total requirements in this chapter: 7** +- Level 1: 4 +- Level 2: 3 +- Level 3: 0 diff --git a/ASVS/V10-OAuth-and-OIDC.md b/ASVS/V10-OAuth-and-OIDC.md new file mode 100644 index 0000000..8264ef1 --- /dev/null +++ b/ASVS/V10-OAuth-and-OIDC.md @@ -0,0 +1,95 @@ +# V10 OAuth and OIDC + +OWASP Application Security Verification Standard 5.0.0 + +## V10.1 Generic OAuth and OIDC Security + +This section covers generic architectural requirements that apply to all applications using OAuth or OIDC. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 10.1.1 | 2 | Verify that tokens are only sent to components that strictly need them. For example, when using a backend‑for‑frontend pattern for browser‑based JavaScript applications, access and refresh tokens shall only be accessible for the backend. | Out of scope | Application does not use OAuth/OIDC. | — | +| 10.1.2 | 2 | Verify that the client only accepts values from the authorization server (such as the authorization code or ID Token) if these values result from an authorization flow that was initiated by the same user agent session and transaction. This requires that client‑generated secrets, such as the proof key for code exchange (PKCE) 'code_verifier', 'state'or OIDC 'nonce', are not guessable, are specific to the transaction, and are securely bound to both the client and the user agent session in which the transaction was started. | Out of scope | Application does not use OAuth/OIDC. | — | + +## V10.2 OAuth Client + +These requirements detail the responsibilities for OAuth client applications. The client can be, for example, a web server backend (often acting as a Backend For Frontend, BFF), a backend service integration, or a frontend Single Page Application (SPA, aka browser‑based application). In general, backend clients are regarded as confidential clients and frontend clients are regarded as public clients. However, native applications running on the end‑user device can be regarded as confidential when using OAuth dynamic client registration. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 10.2.1 | 2 | Verify that, if the code flow is used, the OAuth client has protection against browser‑based request forgery attacks, commonly known as cross‑site request forgery (CSRF), which trigger token requests, either by using proof key for code exchange (PKCE) functionality or checking the 'state'parameter that was sent in the authorization request. | Out of scope | Application does not use OAuth/OIDC. | — | +| 10.2.2 | 2 | Verify that, if the OAuth client can interact with more than one authorization server, it has a defense against mix‑up attacks. For example, it could require that the authorization server return the 'iss'parameter value and validate it in the authorization response and the token response. | Out of scope | Application does not use OAuth/OIDC. | — | +| 10.2.3 | 3 | Verify that the OAuth client only requests the required scopes (or other authorization parameters) in requests to the authorization server. | | | | + +## V10.3 OAuth Resource Server + +In the context of ASVS and this chapter, the resource server is an API. To provide secure access, the resource server must: • Validate the access token, according to the token format and relevant protocol specifications, e.g., JWT‑validation or OAuth token introspection. • If valid, enforce authorization decisions based on the information from the access token and permissions which have been granted. For example, the resource server needs to verify that the client (acting on behalf of RO) is authorized to access the requested resource. Therefore, the requirements listed here are OAuth or OIDC specific and should be performed after token validation and before performing authorization based on information from the token. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 10.3.1 | 2 | Verify that the resource server only accepts access tokens that are intended for use with that service (audience). The audience may be included in a structured access token (such as the 'aud'claim in JWT), or it can be checked using the token introspection endpoint. | Out of scope | Application does not use OAuth/OIDC. | — | +| 10.3.2 | 2 | Verify that the resource server enforces authorization decisions based on claims from the access token that define delegated authorization. If claims such as 'sub', 'scope', and 'authorization_details'are present, they must be part of the decision. | Out of scope | Application does not use OAuth/OIDC. | — | +| 10.3.3 | 2 | Verify that if an access control decision requires identifying a unique user from an access token (JWT or related token introspection response), the resource server identifies the user from claims that cannot be reassigned to other users. Typically, it means using a combination of 'iss'and 'sub'claims. | Out of scope | Application does not use OAuth/OIDC. | — | +| 10.3.4 | 2 | Verify that, if the resource server requires specific authentication strength, methods, or recentness, it verifies that the presented access token satisfies these constraints. For example, if present, using the OIDC 'acr', 'amr'and 'auth_time'claims respectively. | Out of scope | Application does not use OAuth/OIDC. | — | +| 10.3.5 | 3 | Verify that the resource server prevents the use of stolen access tokens or replay of access tokens (from unauthorized parties) by requiring sender‑constrained access tokens, either Mutual TLS for OAuth 2 or OAuth 2 Demonstration of Proof of Possession (DPoP). | | | | + +## V10.4 OAuth Authorization Server + +These requirements detail the responsibilities for OAuth authorization servers, including OpenID Providers. For client authentication, the 'self_signed_tls_client_auth'method is allowed with the prerequisites required by section 2.2 of RFC 8705. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 10.4.1 | 1 | Verify that the authorization server validates redirect URIs based on a client‑specific allowlist of pre‑registered URIs using exact string comparison. | Out of scope | Application does not use OAuth/OIDC. | — | +| 10.4.2 | 1 | Verify that, if the authorization server returns the authorization code in the authorization response, it can be used only once for a token request. For the second valid request with an authorization code that has already been used to issue an access token, the authorization server must reject a token request and revoke any issued tokens related to the authorization code. | Out of scope | Application does not use OAuth/OIDC. | — | +| 10.4.3 | 1 | Verify that the authorization code is short‑lived. The maximum lifetime can be up to 10 minutes for L1 and L2 applications and up to 1 minute for L3 applications. | Out of scope | Application does not use OAuth/OIDC. | — | +| 10.4.4 | 1 | Verify that for a given client, the authorization server only allows the usage of grants that this client needs to use. Note that the grants 'token'(Implicit flow) and 'password'(Resource Owner Password Credentials flow) must no longer be used. | Out of scope | Application does not use OAuth/OIDC. | — | +| 10.4.5 | 1 | Verify that the authorization server mitigates refresh token replay attacks for public clients, preferably using sender‑constrained refresh tokens, i.e., Demonstrating Proof of Possession (DPoP) or Certificate‑Bound Access Tokens using mutual TLS (mTLS). For L1 and L2 applications, refresh token rotation may be used. If refresh token rotation is used, the authorization server must invalidate the refresh token after usage, and revoke all refresh tokens for that authorization if an already used and invalidated refresh token is provided. | Out of scope | Application does not use OAuth/OIDC. | — | +| 10.4.6 | 2 | Verify that, if the code grant is used, the authorization server mitigates authorization code interception attacks by requiring proof key for code exchange (PKCE). For authorization requests, the authorization server must require a valid 'code_challenge'value and must not accept a 'code_challenge_method'value of 'plain'. For a token request, it must require validation of the 'code_verifier'parameter. | Out of scope | Application does not use OAuth/OIDC. | — | +| 10.4.7 | 2 | Verify that if the authorization server supports unauthenticated dynamic client registration, it mitigates the risk of malicious client applications. It must validate client metadata such as any registered URIs, ensure the user's consent, and warn the user before processing an authorization request with an untrusted client application. | Out of scope | Application does not use OAuth/OIDC. | — | +| 10.4.8 | 2 | Verify that refresh tokens have an absolute expiration, including if sliding refresh token expiration is applied. | Out of scope | Application does not use OAuth/OIDC. | — | +| 10.4.9 | 2 | Verify that refresh tokens and reference access tokens can be revoked by an authorized user using the authorization server user interface, to mitigate the risk of malicious clients or stolen tokens. | Out of scope | Application does not use OAuth/OIDC. | — | +| 10.4.10 | 2 | Verify that confidential client is authenticated for client‑to‑authorized server backchannel requests such as token requests, pushed authorization requests (PAR), and token revocation requests. | Out of scope | Application does not use OAuth/OIDC. | — | +| 10.4.11 | 2 | Verify that the authorization server configuration only assigns the required scopes to the OAuth client. | Out of scope | Application does not use OAuth/OIDC. | — | +| 10.4.12 | 3 | Verify that for a given client, the authorization server only allows the 'response_mode'value that this client needs to use. For example, by having the authorization server validate this value against the expected values or by using pushed authorization request (PAR) or JWT‑secured Authorization Request (JAR). | | | | +| 10.4.13 | 3 | Verify that grant type 'code'is always used together with pushed authorization requests (PAR). | | | | +| 10.4.14 | 3 | Verify that the authorization server issues only sender‑constrained (Proof‑of‑Possession) access tokens, either with certificate‑bound access tokens using mutual TLS (mTLS) or DPoP‑bound access tokens (Demonstration of Proof of Possession). | | | | +| 10.4.15 | 3 | Verify that, for a server‑side client (which is not executed on the end‑user device), the authorization server ensures that the 'authorization_details' parameter value is from the client backend and that the user has not tampered with it. For example, by requiring the usage of pushed authorization request (PAR) or JWT‑secured Authorization Request (JAR). | | | | +| 10.4.16 | 3 | Verify that the client is confidential and the authorization server requires the use of strong client authentication methods (based on public‑key cryptography and resistant to replay attacks), such as mutual TLS ( 'tls_client_auth', 'self_signed_tls_client_auth') or private key JWT ( 'private_key_jwt'). | | | | + +## V10.5 OIDC Client + +As the OIDC relying party acts as an OAuth client, the requirements from the section "OAuth Client" apply as well. Note that the "Authentication with an Identity Provider"section in the "Authentication"chapter also contains relevant general requirements. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 10.5.1 | 2 | Verify that the client (as the relying party) mitigates ID Token replay attacks. For example, by ensuring that the 'nonce'claim in the ID Token matches the 'nonce'value sent in the authentication request to the OpenID Provider (in OAuth2 refereed to as the authorization request sent to the authorization server). | Out of scope | Application does not use OAuth/OIDC. | — | +| 10.5.2 | 2 | Verify that the client uniquely identifies the user from ID Token claims, usually the 'sub'claim, which cannot be reassigned to other users (for the scope of an identity provider). | Out of scope | Application does not use OAuth/OIDC. | — | +| 10.5.3 | 2 | Verify that the client rejects attempts by a malicious authorization server to impersonate another authorization server through authorization server metadata. The client must reject authorization server metadata if the issuer URL in the authorization server metadata does not exactly match the pre‑configured issuer URL expected by the client. | Out of scope | Application does not use OAuth/OIDC. | — | +| 10.5.4 | 2 | Verify that the client validates that the ID Token is intended to be used for that client (audience) by checking that the 'aud'claim from the token is equal to the 'client_id'value for the client. | Out of scope | Application does not use OAuth/OIDC. | — | +| 10.5.5 | 2 | Verify that, when using OIDC back‑channel logout, the relying party mitigates denial of service through forced logout and cross‑JWT confusion in the logout flow. The client must verify that the logout token is correctly typed with a value of 'logout+jwt', contains the 'event'claim with the correct member name, and does not contain a 'nonce'claim. Note that it is also recommended to have a short expiration (e.g., 2 minutes). | Out of scope | Application does not use OAuth/OIDC. | — | + +## V10.6 OpenID Provider + +As OpenID Providers act as OAuth authorization servers, the requirements from the section "OAuth Authorization Server"apply as well. Note that if using the ID Token flow (not the code flow), no access tokens are issued, and many of the requirements for OAuth AS are not applicable. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 10.6.1 | 2 | Verify that the OpenID Provider only allows values 'code', 'ciba', 'id_token', or 'id_token code'for response mode. Note that 'code'is preferred over 'id_token code'(the OIDC Hybrid flow), and 'token'(any Implicit flow) must not be used. | Out of scope | Application does not use OAuth/OIDC. | — | +| 10.6.2 | 2 | Verify that the OpenID Provider mitigates denial of service through forced logout. By obtaining explicit confirmation from the end‑user or, if present, validating parameters in the logout request (initiated by the relying party), such as the 'id_token_hint'. | Out of scope | Application does not use OAuth/OIDC. | — | + +## V10.7 Consent Management + +These requirements cover the verification of the user's consent by the authorization server. With‑ out proper user consent verification, a malicious actor may obtain permissions on the user's behalf through spoofing or social‑engineering. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 10.7.1 | 2 | Verify that the authorization server ensures that the user consents to each authorization request. If the identity of the client cannot be assured, the authorization server must always explicitly prompt the user for consent. | Out of scope | Application does not use OAuth/OIDC. | — | +| 10.7.2 | 2 | Verify that when the authorization server prompts for user consent, it presents sufficient and clear information about what is being consented to. When applicable, this should include the nature of the requested authorizations (typically based on scope, resource server, Rich Authorization Requests (RAR) authorization details), the identity of the authorized application, and the lifetime of these authorizations. | Out of scope | Application does not use OAuth/OIDC. | — | +| 10.7.3 | 2 | Verify that the user can review, modify, and revoke consents which the user has granted through the authorization server. | Out of scope | Application does not use OAuth/OIDC. | — | + +--- + +**Total requirements in this chapter: 36** +- Level 1: 5 +- Level 2: 24 +- Level 3: 7 diff --git a/ASVS/V11-Cryptography.md b/ASVS/V11-Cryptography.md new file mode 100644 index 0000000..60f75a9 --- /dev/null +++ b/ASVS/V11-Cryptography.md @@ -0,0 +1,83 @@ +# V11 Cryptography + +OWASP Application Security Verification Standard 5.0.0 + +## V11.1 Cryptographic Inventory and Documentation + +Applications need to be designed with strong cryptographic architecture to protect data assets ac‑ cording to their classification. Encrypting everything is wasteful; not encrypting anything is legally negligent. A balance must be struck, usually during architectural or high‑level design, design sprints, or architectural spikes. Designing cryptography "on the fly"or retrofitting it will inevitably cost much more to implement securely than simply building it in from the start. It is important to ensure that all cryptographic assets are regularly discovered, inventoried, and as‑ sessed. Please see the appendix for more information on how this can be done. The need to future‑proof cryptographic systems against the eventual rise of quantum computing is also critical. Post‑Quantum Cryptography (PQC) refers to cryptographic algorithms designed to + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 11.1.1 | 2 | Verify that there is a documented policy for management of cryptographic keys and a cryptographic key lifecycle that follows a key management standard such as NIST SP 800‑57. This should include ensuring that keys are not overshared (for example, with more than two entities for shared secrets and more than one entity for private keys). | Partial | No formal documented policy for cryptographic key management. Keys managed implicitly by framework and infrastructure. | Per-project: document crypto key management: bcrypt cost factor, session token entropy (`Random::generate(32)`), TLS cert rotation schedule. | +| 11.1.2 | 2 | Verify that a cryptographic inventory is performed, maintained, regularly updated, and includes all cryptographic keys, algorithms, and certificates used by the application. It must also document where keys can and cannot be used in the system, and the types of data that can and cannot be protected using the keys. | Partial | No cryptographic inventory maintained. Crypto usage: bcrypt (passwords), SHA-256 (session tokens), TLS (transport). | Per-project: document crypto inventory: `password_hash(PASSWORD_DEFAULT)` (bcrypt), `hash('sha256')` (session tokens), TLS (transport). | +| 11.1.3 | 3 | Verify that cryptographic discovery mechanisms are employed to identify all instances of cryptography in the system, including encryption, hashing, and signing operations. | | | | +| 11.1.4 | 3 | Verify that a cryptographic inventory is maintained. This must include a documented plan that outlines the migration path to new cryptographic standards, such as post‑quantum cryptography, in order to react to future threats. | | | | + +## V11.2 Secure Cryptography Implementation + +This section defines the requirements for the selection, implementation, and ongoing management of core cryptographic algorithms for an application. The objective is to ensure that only robust, industry‑accepted cryptographic primitives are deployed, in alignment with current standards (e.g., NIST, ISO/IEC) and best practices. Organizations must ensure that each cryptographic component is selected based on peer‑reviewed evidence and practical security testing. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 11.2.1 | 2 | Verify that industry‑validated implementations (including libraries and hardware‑accelerated implementations) are used for cryptographic operations. | Compliant | Using PHP built-in password_hash (bcrypt), hash('sha256') for tokens, and OpenSSL for TLS. All industry-validated implementations. | — | +| 11.2.2 | 2 | Verify that the application is designed with crypto agility such that random number, authenticated encryption, MAC, or hashing algorithms, key lengths, rounds, ciphers and modes can be reconfigured, upgraded, or swapped at any time, to protect against cryptographic breaks. Similarly, it must also be possible to replace keys and passwords and re‑encrypt data. This will allow for seamless upgrades to post‑quantum cryptography (PQC), once high‑assurance implementations of approved PQC schemes or standards are widely available. | Partial | No explicit crypto agility design. Changing algorithms would require code changes. | Pending fancyadmin: make hash algorithms configurable. Currently hardcoded: `PASSWORD_DEFAULT` in `IdentityTrait::setPassword()`, `sha256` in `DoctrineAuthenticator`. | +| 11.2.3 | 2 | Verify that all cryptographic primitives utilize a minimum of 128‑bits of security based on the algorithm, key size, and configuration. For example, a 256‑bit ECC key provides roughly 128 bits of security where RSA requires a 3072‑bit key to achieve 128 bits of security. | Compliant | bcrypt (128-bit security), SHA-256 (256-bit), TLS 1.2+ (128-bit minimum). All meet 112-bit minimum. | — | +| 11.2.4 | 3 | Verify that all cryptographic operations are constant‑time, with no 'short‑circuit'operations in comparisons, calculations, or returns, to avoid leaking information. | | | | +| 11.2.5 | 3 | Verify that all cryptographic modules fail securely, and errors are handled in a way that does not enable vulnerabilities, such as Padding Oracle attacks. | | | | + +## V11.3 Encryption Algorithms + +Authenticated encryption algorithms built on AES and CHACHA20 form the backbone of modern cryptographic practice. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 11.3.1 | 1 | Verify that insecure block modes (e.g., ECB) and weak padding schemes (e.g., PKCS#1 v1.5) are not used. | Out of scope | Application does not use block cipher modes directly. Encryption handled by TLS at transport layer. | — | +| 11.3.2 | 1 | Verify that only approved ciphers and modes such as AES with GCM are used. | Out of scope | Application does not perform application-level encryption. TLS cipher suite configured at nginx level. | — | +| 11.3.3 | 2 | Verify that encrypted data is protected against unauthorized modification preferably by using an approved authenticated encryption method or by combining an approved encryption method with an approved MAC algorithm. | Out of scope | No application-level encryption of stored data. Sensitive data protected by access control, not encryption at rest. | — | +| 11.3.4 | 3 | Verify that nonces, initialization vectors, and other single‑use numbers are not used for more than one encryption key and data‑element pair. The method of generation must be appropriate for the algorithm being used. | | | | +| 11.3.5 | 3 | Verify that any combination of an encryption algorithm and a MAC algorithm is operating in encrypt‑then‑MAC mode. | | | | + +## V11.4 Hashing and Hash‑based Functions + +Cryptographic hashes are used in a wide variety of cryptographic protocols, such as digital signatures, HMAC, key derivation functions (KDF), random bit generation, and password storage. The security of the cryptographic system is only as strong as the underlying hash functions used. This section outlines the requirements for using secure hash functions in cryptographic operations. For password storage, as well as the cryptography appendix, the OWASP Password Storage Cheat Sheet will also provide useful context and guidance. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 11.4.1 | 1 | Verify that only approved hash functions are used for general cryptographic use cases, including digital signatures, HMAC, KDF, and random bit generation. Disallowed hash functions, such as MD5, must not be used for any cryptographic purpose. | Compliant | Passwords hashed using bcrypt via PHP password_hash(). Nette Security default. | — | +| 11.4.2 | 2 | Verify that passwords are stored using an approved, computationally intensive, key derivation function (also known as a "password hashing function"), with parameter settings configured based on current guidance. The settings should balance security and performance to make brute‑force attacks sufficiently challenging for the required level of security. | Compliant | Passwords stored using bcrypt via PHP password_hash(PASSWORD_DEFAULT). Approved algorithm with automatic cost factor. | — | +| 11.4.3 | 2 | Verify that hash functions used in digital signatures, as part of data authentication or data integrity are collision resistant and have appropriate bit‑lengths. If collision resistance is required, the output length must be at least 256 bits. If only resistance to second pre‑image attacks is required, the output length must be at least 128 bits. | Compliant | SHA-256 used for session token hashing. Approved hash function for this use case. | — | +| 11.4.4 | 2 | Verify that the application uses approved key derivation functions with key stretching parameters when deriving secret keys from passwords. The parameters in use must balance security and performance to prevent brute‑force attacks from compromising the resulting cryptographic key. | Out of scope | No application-level key derivation. password_hash handles password KDF internally. | — | + +## V11.5 Random Values + +Cryptographically secure Pseudo‑random Number Generation (CSPRNG) is incredibly difficult to get right. Generally, good sources of entropy within a system will be quickly depleted if over‑used, but + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 11.5.1 | 2 | Verify that all random numbers and strings which are intended to be non‑guessable must be generated using a cryptographically secure pseudo‑random number generator (CSPRNG) and have at least 128 bits of entropy. Note that UUIDs do not respect this condition. | Compliant | Session tokens generated via Nette\Utils\Random::generate(32) which uses random_bytes() (CSPRNG). OTP tokens also use secure random generation. | — | +| 11.5.2 | 3 | Verify that the random number generation mechanism in use is designed to work securely, even under heavy demand. | | | | + +## V11.6 Public Key Cryptography + +Public Key Cryptography will be used where it is not possible or not desirable to share a secret key between multiple parties. As part of this, there exists a need for approved key exchange mechanisms, such as Diffie‑Hellman and Elliptic Curve Diffie‑Hellman (ECDH) to ensure that the cryptosystem remains secure against modern threats. The "Secure Communication"chapter provides requirements for TLS so the require‑ ments in this section are intended for situations where Public Key Cryptography is being used in use cases other than TLS. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 11.6.1 | 2 | Verify that only approved cryptographic algorithms and modes of operation are used for key generation and seeding, and digital signature generation and verification. Key generation algorithms must not generate insecure keys vulnerable to known attacks, for example, RSA keys which are vulnerable to Fermat factorization. | Out of scope | No application-level public key cryptography. TLS handled at infrastructure level. | — | +| 11.6.2 | 3 | Verify that approved cryptographic algorithms are used for key exchange (such as Diffie‑Hellman) with a focus on ensuring that key exchange mechanisms use secure parameters. This will prevent attacks on the key establishment process which could lead to adversary‑in‑the‑middle attacks or cryptographic breaks. | | | | + +## V11.7 In‑Use Data Cryptography + +Protecting data while it is being processed is paramount. Techniques such as full memory encryp‑ tion, encryption of data in transit, and ensuring data is encrypted as quickly as possible after use is recommended. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 11.7.1 | 3 | Verify that full memory encryption is in use that protects sensitive data while it is in use, preventing access by unauthorized users or processes. | | | | +| 11.7.2 | 3 | Verify that data minimization ensures the minimal amount of data is exposed during processing, and ensure that data is encrypted immediately after use or as soon as feasible. | | | | + +--- + +**Total requirements in this chapter: 24** +- Level 1: 3 +- Level 2: 11 +- Level 3: 10 diff --git a/ASVS/V12-Secure-Communication.md b/ASVS/V12-Secure-Communication.md new file mode 100644 index 0000000..7c88f29 --- /dev/null +++ b/ASVS/V12-Secure-Communication.md @@ -0,0 +1,43 @@ +# V12 Secure Communication + +OWASP Application Security Verification Standard 5.0.0 + +## V12.1 General TLS Security Guidance + +This section provides initial guidance on how to secure TLS communications. Up‑to‑date tools should be used to review TLS configuration on an ongoing basis. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 12.1.1 | 1 | Verify that only the latest recommended versions of the TLS protocol are enabled, such as TLS 1.2 and TLS 1.3. The latest version of the TLS protocol must be the preferred option. | Compliant | HTTPS enforced via nginx proxy. HSTS configured at proxy level. | — | +| 12.1.2 | 2 | Verify that only recommended cipher suites are enabled, with the strongest cipher suites set as preferred. L3 applications must only support cipher suites which provide forward secrecy. | Compliant | Cipher suite configuration managed at nginx reverse proxy level. Only modern cipher suites enabled. | — | +| 12.1.3 | 2 | Verify that the application validates that mTLS client certificates are trusted before using the certificate identity for authentication or authorization. | Out of scope | Application does not use mTLS client certificates. | — | +| 12.1.4 | 3 | Verify that proper certification revocation, such as Online Certificate Status Protocol (OCSP) Stapling, is enabled and configured. | | | | +| 12.1.5 | 3 | Verify that Encrypted Client Hello (ECH) is enabled in the application's TLS settings to prevent exposure of sensitive metadata, such as the Server Name Indication (SNI), during TLS handshake processes. | | | | + +## V12.2 HTTPS Communication with External Facing Services + +Ensure all HTTP traffic to external‑facing services which the application exposes is sent encrypted, with publicly trusted certificates. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 12.2.1 | 1 | Verify that TLS is used for all connectivity between a client and external facing, HTTP‑based services, and does not fall back to insecure or unencrypted communications. | Compliant | All external-facing communication over HTTPS. Enforced at nginx level. | — | +| 12.2.2 | 1 | Verify that external facing services use publicly trusted TLS certificates. | Compliant | Publicly trusted TLS certificates from Let's Encrypt / CA. Managed at infrastructure level. | — | + +## V12.3 General Service to Service Communication Security + +Server communications (both internal and external) involve more than just HTTP. Connections to and from other systems must also be secure, ideally using TLS. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 12.3.1 | 2 | Verify that an encrypted protocol such as TLS is used for all inbound and outbound connections to and from the application, including monitoring systems, management tools, remote access and SSH, middleware, databases, mainframes, partner systems, or external APIs. The server must not fall back to insecure or unencrypted protocols. | Compliant | All backend communication uses TLS-encrypted connections. Database accessed via internal network. | — | +| 12.3.2 | 2 | Verify that TLS clients validate certificates received before communicating with a TLS server. | Compliant | PHP cURL and HTTP clients validate TLS certificates by default. Certificate verification not disabled. | — | +| 12.3.3 | 2 | Verify that TLS or another appropriate transport encryption mechanism used for all connectivity between internal, HTTP‑based services within the application, and does not fall back to insecure or unencrypted communications. | Compliant | Database connections use TLS or are on localhost/internal network. No unencrypted external connections. | — | +| 12.3.4 | 2 | Verify that TLS connections between internal services use trusted certificates. Where internally generated or self‑signed certificates are used, the consuming service must be configured to only trust specific internal CAs and specific self‑signed certificates. | Partial | Internal service communication uses TLS where available. Some internal connections may use unencrypted localhost. | Per-project: set `sslmode=require` in Doctrine DBAL DSN for database. Verify all internal service connections use TLS. | +| 12.3.5 | 3 | Verify that services communicating internally within a system (intra‑service communications) use strong authentication to ensure that each endpoint is verified. Strong authentication methods, such as TLS client authentication, must be employed to ensure identity, using public‑key infrastructure and mechanisms that are resistant to replay attacks. For microservice architectures, consider using a service mesh to simplify certificate management and enhance security. | | | | + +--- + +**Total requirements in this chapter: 12** +- Level 1: 3 +- Level 2: 6 +- Level 3: 3 diff --git a/ASVS/V13-Configuration.md b/ASVS/V13-Configuration.md new file mode 100644 index 0000000..0794a1c --- /dev/null +++ b/ASVS/V13-Configuration.md @@ -0,0 +1,59 @@ +# V13 Configuration + +OWASP Application Security Verification Standard 5.0.0 + +## V13.1 Configuration Documentation + +This section outlines documentation requirements for how the application communicates with in‑ ternal and external services, as well as techniques to prevent loss of availability due to service inac‑ cessibility. It also addresses documentation related to secrets. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 13.1.1 | 2 | Verify that all communication needs for the application are documented. This must include external services which the application relies upon and cases where an end user might be able to provide an external location to which the application will then connect. | Partial | No formal documentation of all communication needs. HTTPS enforced for all external communication. | Per-project: document external dependencies (mail API, HaveIBeenPwned, database) with endpoints and auth methods. | +| 13.1.2 | 3 | Verify that for each service the application uses, the documentation defines the maximum number of concurrent connections (e.g., connection pool limits) and how the application behaves when that limit is reached, including any fallback or recovery mechanisms, to prevent denial of service conditions. | | | | +| 13.1.3 | 3 | Verify that the application documentation defines resource‑management strategies for every external system or service it uses (e.g., databases, file handles, threads, HTTP connections). This should include resource‑release procedures, timeout settings, failure handling, and where retry logic is implemented, specifying retry limits, delays, and back‑off algorithms. For synchronous HTTP request–response operations it should mandate short timeouts and either disable retries or strictly limit retries to prevent cascading delays and resource exhaustion. | | | | +| 13.1.4 | 3 | Verify that the application's documentation defines the secrets that are critical for the security of the application and a schedule for rotating them, based on the organization's threat model and business requirements. | | | | + +## V13.2 Backend Communication Configuration + +Applications interact with multiple services, including APIs, databases, or other components. These may be considered internal to the application but not included in the application's standard access control mechanisms, or they may be entirely external. In either case, it is necessary to configure the application to interact securely with these components and, if required, protect that configuration. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 13.2.1 | 2 | Verify that communications between backend application components that don't support the application's standard user session mechanism, including APIs, middleware, and data layers, are authenticated. Authentication must use individual service accounts, short‑term tokens, or certificate‑based authentication and not unchanging credentials such as passwords, API keys, or shared accounts with privileged access. | Compliant | Backend components communicate via authenticated database connections and internal HTTP APIs. | — | +| 13.2.2 | 2 | Verify that communications between backend application components, including local or operating system services, APIs, middleware, and data layers, are performed with accounts assigned the least necessary privileges. | Compliant | All backend communication uses encrypted connections (TLS or internal network). | — | +| 13.2.3 | 2 | Verify that if a credential has to be used for service authentication, the credential being used by the consumer is not a default credential (e.g., root/root or admin/admin). | Compliant | Service authentication uses environment variables (%env.BROKER_PASSWORD%, %env.MAILAPI_KEY%). Not hardcoded. | — | +| 13.2.4 | 2 | Verify that an allowlist is used to define the external resources or systems with which the application is permitted to communicate (e.g., for outbound requests, data loads, or file access). This allowlist can be implemented at the application layer, web server, firewall, or a combination of different layers. | Partial | No explicit allowlist of external resources. External connections limited to mail API and specific third-party services. | Per-project: define external resource allowlist (API endpoints, CDN). Optionally enforce via CSP `connect-src` in `common.neon`. | +| 13.2.5 | 2 | Verify that the web or application server is configured with an allowlist of resources or systems to which the server can send requests or load data or files from. | Compliant | Nette framework restricts allowed HTTP methods. Nginx configured with appropriate limits. | — | +| 13.2.6 | 3 | Verify that where the application connects to separate services, it follows the documented configuration for each connection, such as maximum parallel connections, behavior when maximum allowed connections is reached, connection timeouts, and retry strategies. | | | | + +## V13.3 Secret Management + +Secret management is an essential configuration task to ensure the protection of data used in the application. Specific requirements for cryptography can be found in the "Cryptography"chapter, but this section focuses on the management and handling aspects of secrets. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 13.3.1 | 2 | Verify that a secrets management solution, such as a key vault, is used to securely create, store, control access to, and destroy backend secrets. These could include passwords, key material, integrations with databases and third‑party systems, keys and seeds for time‑based tokens, other internal secrets, and API keys. Secrets must not be included in application source code or included in build artifacts. For an L3 application, this must involve a hardware‑backed solution such as an HSM. | Compliant | Secrets stored in environment variables (%env.BROKER_PASSWORD%, %env.MAILAPI_KEY%, etc.). Not in source code. | — | +| 13.3.2 | 2 | Verify that access to secret assets adheres to the principle of least privilege. | Compliant | Secrets accessible only to application runtime. Environment variables not exposed to frontend. Nette DI container restricts access. | — | +| 13.3.3 | 3 | Verify that all cryptographic operations are performed using an isolated security module (such as a vault or hardware security module) to securely manage and protect key material from exposure outside of the security module. | | | | +| 13.3.4 | 3 | Verify that secrets are configured to expire and be rotated based on the application's documentation. | | | | + +## V13.4 Unintended Information Leakage + +Production configurations should be hardened to avoid disclosing unnecessary data. Many of these issues are rarely rated as significant risks but are often chained with other vulnerabilities. If these issues are not present by default, it raises the bar for attacking an application. For example, hiding the version of server‑side components does not eliminate the need to patch all components, and disabling folder listing does not remove the need to use authorization controls or keep files away from the public folder, but it raises the bar. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 13.4.1 | 1 | Verify that the application is deployed either without any source control metadata, including the .git or .svn folders, or in a way that these folders are inaccessible both externally and to the application itself. | Compliant | Debug mode disabled in production (Tracy debugger). Error details not exposed to users. | — | +| 13.4.2 | 2 | Verify that debug modes are disabled for all components in production environments to prevent exposure of debugging features and information leakage. | Compliant | Nette framework default error handling. Stack traces only in debug mode. | — | +| 13.4.3 | 2 | Verify that web servers do not expose directory listings to clients unless explicitly intended. | Compliant | Nginx configured to deny directory listings. No autoindex enabled. | — | +| 13.4.4 | 2 | Verify that using the HTTP TRACE method is not supported in production environments, to avoid potential information leakage. | Compliant | HTTP TRACE method disabled at nginx level. | — | +| 13.4.5 | 2 | Verify that documentation (such as for internal APIs) and monitoring endpoints are not exposed unless explicitly intended. | Partial | No public API documentation or monitoring dashboards exposed. Internal docs should be access-controlled. | Per-project: verify Tracy debugger, Adminer, and monitoring endpoints are not publicly accessible in production. | +| 13.4.6 | 3 | Verify that the application does not expose detailed version information of backend components. | | | | +| 13.4.7 | 3 | Verify that the web tier is configured to only serve files with specific file extensions to prevent unintentional information, configuration, and source code leakage. | | | | + +--- + +**Total requirements in this chapter: 21** +- Level 1: 1 +- Level 2: 12 +- Level 3: 8 diff --git a/ASVS/V14-Data-Protection.md b/ASVS/V14-Data-Protection.md new file mode 100644 index 0000000..8314040 --- /dev/null +++ b/ASVS/V14-Data-Protection.md @@ -0,0 +1,44 @@ +# V14 Data Protection + +OWASP Application Security Verification Standard 5.0.0 + +## V14.1 Data Protection Documentation + +A key prerequisite for being able to protect data is to categorize what data should be considered sensitive. There are likely to be several different levels of sensitivity, and for each level, the controls required to protect data at that level will be different. There are various privacy regulations and laws that affect how applications must approach the stor‑ age, use, and transmission of sensitive personal information. This section no longer tries to duplicate + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 14.1.1 | 2 | Verify that all sensitive data created and processed by the application has been identified and classified into protection levels. This includes data that is only encoded and therefore easily decoded, such as Base64 strings or the plaintext payload inside a JWT. Protection levels need to take into account any data protection and privacy regulations and standards which the application is required to comply with. | Partial | No formal data classification document. Sensitive data identified implicitly (passwords, tokens, personal data). | Per-project: classify data: passwords (critical — bcrypt), session tokens (critical — SHA-256+DB), PII/email (high — ACL), business data (medium). | +| 14.1.2 | 2 | Verify that all sensitive data protection levels have a documented set of protection requirements. This must include (but not be limited to) requirements related to general encryption, integrity verification, retention, how the data is to be logged, access controls around sensitive data in logs, database‑level encryption, privacy and privacy‑enhancing technologies to be used, and other confidentiality requirements. | Partial | No documented protection levels per data classification. Protection applied based on development practices. | Per-project: for each classification level, document: encryption method, retention period, logging rules, access controls. | + +## V14.2 General Data Protection + +This section contains various practical requirements related to the protection of data. Most are spe‑ cific to particular issues such as unintended data leakage, but there is also a general requirement to implement protection controls based on the protection level required for each data item. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 14.2.1 | 1 | Verify that sensitive data is only sent to the server in the HTTP message body or header fields, and that the URL and query string do not contain sensitive information, such as an API key or session token. | Compliant | HTTPS only. Sensitive data transmitted over TLS. | — | +| 14.2.2 | 2 | Verify that the application prevents sensitive data from being cached in server components, such as load balancers and application caches, or ensures that the data is securely purged after use. | Compliant | Latte templates do not expose sensitive data in HTML. Server-side rendering with access control. | — | +| 14.2.3 | 2 | Verify that defined sensitive data is not sent to untrusted parties (e.g., user trackers) to prevent unwanted collection of data outside of the application's control. | Compliant | Sensitive data not sent to untrusted third parties. Only necessary data sent to mail API. | — | +| 14.2.4 | 2 | Verify that controls around sensitive data related to encryption, integrity verification, retention, how the data is to be logged, access controls around sensitive data in logs, privacy and privacy‑enhancing technologies, are implemented as defined in the documentation for the specific data's protection level. | Partial | No formal verification of encryption controls per data classification. TLS protects data in transit. | Per-project: verify each data classification has matching technical controls (TLS, bcrypt, Doctrine security filters, log masking). | +| 14.2.5 | 3 | Verify that caching mechanisms are configured to only cache responses which have the expected content type for that resource and do not contain sensitive, dynamic content. The web server should return a 404 or 302 response when a non‑existent file is accessed rather than returning a different, valid file. This should prevent Web Cache Deception attacks. | | | | +| 14.2.6 | 3 | Verify that the application only returns the minimum required sensitive data for the application's functionality. For example, only returning some of the digits of a credit card number and not the full number. If the complete data is required, it should be masked in the user interface unless the user specifically views it. | | | | +| 14.2.7 | 3 | Verify that sensitive information is subject to data retention classification, ensuring that outdated or unnecessary data is deleted automatically, on a defined schedule, or as the situation requires. | | | | +| 14.2.8 | 3 | Verify that sensitive information is removed from the metadata of user‑submitted files unless storage is consented to by the user. | | | | + +## V14.3 Client‑side Data Protection + +This section contains requirements preventing data from leaking in specific ways at the client or user agent side of an application. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 14.3.1 | 1 | Verify that authenticated data is cleared from client storage, such as the browser DOM, after the client or session is terminated. The 'Clear‑Site‑Data' HTTP response header field may be able to help with this but the client‑side should also be able to clear up if the server connection is not available when the session is terminated. | Compliant | Logout clears authentication cookie via CookieStorage::clearAuthentication(). Session invalidated server-side. | — | +| 14.3.2 | 2 | Verify that the application sets sufficient anti‑caching HTTP response header fields (i.e., Cache‑Control: no‑store) so that sensitive data is not cached in browsers. | Compliant | Cache-Control: no-store set globally via fancyadmin config/security.neon http: headers:. Prevents browser caching of sensitive responses. | — | +| 14.3.3 | 2 | Verify that data stored in browser storage (such as localStorage, sessionStorage, IndexedDB, or cookies) does not contain sensitive data, with the exception of session tokens. | Partial | No audit of client-side storage (localStorage, sessionStorage) for sensitive data. Minimal client-side storage used. | Per-project: audit `localStorage`/`sessionStorage`/`IndexedDB`. Ensure no PII or tokens stored beyond `__Host-userid` cookie. | + +--- + +**Total requirements in this chapter: 13** +- Level 1: 2 +- Level 2: 7 +- Level 3: 4 diff --git a/ASVS/V15-Secure-Coding-and-Architecture.md b/ASVS/V15-Secure-Coding-and-Architecture.md new file mode 100644 index 0000000..c636a95 --- /dev/null +++ b/ASVS/V15-Secure-Coding-and-Architecture.md @@ -0,0 +1,59 @@ +# V15 Secure Coding and Architecture + +OWASP Application Security Verification Standard 5.0.0 + +## V15.1 Secure Coding and Architecture Documentation + +Many requirements for establishing a secure and defensible architecture depend on clear documen‑ tation of decisions made regarding the implementation of specific security controls and the compo‑ nents used within the application. This section outlines the documentation requirements, including identifying components consid‑ ered to contain "dangerous functionality"or to be "risky components." + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 15.1.1 | 1 | Verify that application documentation defines risk based remediation time frames for 3rd party component versions with vulnerabilities and for updating libraries in general, to minimize the risk from these components. | Partial | No formal vulnerability remediation policy. Composer dependencies updated periodically. | Per-project: define vulnerability remediation SLA (e.g., critical: 48h, high: 7d, medium: 30d) in project security policy. | +| 15.1.2 | 2 | Verify that an inventory catalog, such as software bill of materials (SBOM), is maintained of all third‑party libraries in use, including verifying that components come from pre‑defined, trusted, and continually maintained repositories. | Partial | composer.lock serves as dependency inventory. No formal SBOM generated. | Run `composer require --dev cyclonedx/cyclonedx-php-composer` and add SBOM generation to CI/CD pipeline. | +| 15.1.3 | 2 | Verify that the application documentation identifies functionality which is time‑consuming or resource‑demanding. This must include how to prevent a loss of availability due to overusing this functionality and how to avoid a situation where building a response takes longer than the consumer's timeout. Potential defenses may include asynchronous processing, using queues, and limiting parallel processes per user and per application. | Partial | Sensitive data flows not formally documented. Known flows: authentication, password reset, personal data editing. | Per-project: document resource-intensive features (bulk imports, exports, large queries) and mitigations (queues, rate limits). | +| 15.1.4 | 3 | Verify that application documentation highlights third‑party libraries which are considered to be "risky components". | | | | +| 15.1.5 | 3 | Verify that application documentation highlights parts of the application where "dangerous functionality"is being used. | | | | + +## V15.2 Security Architecture and Dependencies + +This section includes requirements for handling risky, outdated, or insecure dependencies and com‑ ponents through dependency management. It also includes using architectural‑level techniques such as sandboxing, encapsulation, container‑ ization, and network isolation to reduce the impact of using "dangerous operations"or "risky compo‑ + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 15.2.1 | 1 | Verify that the application only contains components which have not breached the documented update and remediation time frames. | Compliant | All dependencies managed via Composer with known versions. No abandoned packages in use. | — | +| 15.2.2 | 2 | Verify that the application has implemented defenses against loss of availability due to functionality which is time‑consuming or resource‑demanding, based on the documented security decisions and strategies for this. | Partial | No automated dependency vulnerability scanning (e.g., composer audit). Should be added to CI/CD. | Add `composer audit` step to CI/CD pipeline. Fail build on known vulnerabilities. | +| 15.2.3 | 2 | Verify that the production environment only includes functionality that is required for the application to function, and does not expose extraneous functionality such as test code, sample snippets, and development functionality. | Compliant | Production environment only includes production dependencies. Dev dependencies excluded via composer install --no-dev. | — | +| 15.2.4 | 3 | Verify that third‑party components and all of their transitive dependencies are included from the expected repository, whether internally owned or an external source, and that there is no risk of a dependency confusion attack. | | | | +| 15.2.5 | 3 | Verify that the application implements additional protections around parts of the application which are documented as containing "dangerous functionality"or using third‑party libraries considered to be "risky components". This could include techniques such as sandboxing, encapsulation, containerization or network level isolation to delay and deter attackers who compromise one part of an application from pivoting elsewhere in the application. | | | | + +## V15.3 Defensive Coding + +This section covers vulnerability types, including type juggling, prototype pollution, and others, which result from using insecure coding patterns in a particular language. Some may not be relevant to all languages, whereas others will have language‑specific fixes or may relate to how a particular language or framework handles a feature such as HTTP parameters. It also considers the risk of not cryptographically validating application updates. It also considers the risks associated with using objects to represent data items and accepting and returning these via external APIs. In this case, the application must ensure that data fields that should not be writable are not modified by user input (mass assignment) and that the API is selective about what data fields get returned. Where field access depends on a user's permissions, this should be considered in the context of the field‑level access control requirement in the Authorization chapter. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 15.3.1 | 1 | Verify that the application only returns the required subset of fields from a data object. For example, it should not return an entire data object, as some individual fields should not be accessible to users. | Compliant | Doctrine queries return only requested fields. Presenters pass only needed data to templates. | — | +| 15.3.2 | 2 | Verify that where the application backend makes calls to external URLs, it is configured to not follow redirects unless it is intended functionality. | Compliant | External API calls (mail service) use validated, hardcoded endpoints. No SSRF vectors. | — | +| 15.3.3 | 2 | Verify that the application has countermeasures to protect against mass assignment attacks by limiting allowed fields per controller and action, e.g., it is not possible to insert or update a field value when it was not intended to be part of that action. | Partial | No explicit mass assignment protection beyond Nette form validation. Doctrine entities set properties individually. | Per-project: ensure entities are only updated via `$form->getValues()` fields. Never use `$httpRequest->getPost()` directly on entities. | +| 15.3.4 | 2 | Verify that all proxying and middleware components transfer the user's original IP address correctly using trusted data fields that cannot be manipulated by the end user, and the application and web server use this correct value for logging and security decisions such as rate limiting, taking into account that even the original IP address may not be reliable due to dynamic IPs, VPNs, or corporate firewalls. | Out of scope | No proxying or middleware components that transfer client info. | — | +| 15.3.5 | 2 | Verify that the application explicitly ensures that variables are of the correct type and performs strict equality and comparator operations. This is to avoid type juggling or type confusion vulnerabilities caused by the application code making an assumption about a variable type. | Compliant | PHP initializes variables explicitly. Nette framework uses strict types throughout. | — | +| 15.3.6 | 2 | Verify that JavaScript code is written in a way that prevents prototype pollution, for example, by using Set() or Map() instead of object literals. | Partial | Client-side JS uses standard patterns. No comprehensive prototype pollution audit. | Per-project: audit client-side JS. Use `Object.create(null)` or `Map`/`Set` instead of `{}` for user-influenced data. | +| 15.3.7 | 2 | Verify that the application has defenses against HTTP parameter pollution attacks, particularly if the application framework makes no distinction about the source of request parameters (query string, body parameters, cookies, or header fields). | Compliant | Nette framework handles HTTP parameter parsing. No duplicate parameter vulnerability. | — | + +## V15.4 Safe Concurrency + +Concurrency issues such as race conditions, time‑of‑check to time‑of‑use (TOCTOU) vulnerabilities, deadlocks, livelocks, thread starvation, and improper synchronization can lead to unpredictable be‑ havior and security risks. This section includes various techniques and strategies to help mitigate these risks. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 15.4.1 | 3 | Verify that shared objects in multi‑threaded code (such as caches, files, or in‑memory objects accessed by multiple threads) are accessed safely by using thread‑safe types and synchronization mechanisms like locks or semaphores to avoid race conditions and data corruption. | | | | +| 15.4.2 | 3 | Verify that checks on a resource's state, such as its existence or permissions, and the actions that depend on them are performed as a single atomic operation to prevent time‑of‑check to time‑of‑use (TOCTOU) race conditions. For example, checking if a file exists before opening it, or verifying a user's access before granting it. | | | | +| 15.4.3 | 3 | Verify that locks are used consistently to avoid threads getting stuck, whether by waiting on each other or retrying endlessly, and that locking logic stays within the code responsible for managing the resource to ensure locks cannot be inadvertently or maliciously modified by external classes or code. | | | | +| 15.4.4 | 3 | Verify that resource allocation policies prevent thread starvation by ensuring fair access to resources, such as by leveraging thread pools, allowing lower‑priority threads to proceed within a reasonable timeframe. | | | | + +--- + +**Total requirements in this chapter: 21** +- Level 1: 3 +- Level 2: 10 +- Level 3: 8 diff --git a/ASVS/V16-Security-Logging-and-Error-Handling.md b/ASVS/V16-Security-Logging-and-Error-Handling.md new file mode 100644 index 0000000..dc9cacb --- /dev/null +++ b/ASVS/V16-Security-Logging-and-Error-Handling.md @@ -0,0 +1,62 @@ +# V16 Security Logging and Error Handling + +OWASP Application Security Verification Standard 5.0.0 + +## V16.1 Security Logging Documentation + +This section ensures a clear and complete inventory of logging across the application stack. This is essential for effective security monitoring, incident response, and compliance. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 16.1.1 | 2 | Verify that an inventory exists documenting the logging performed at each layer of the application's technology stack, what events are being logged, log formats, where that logging is stored, how it is used, how access to it is controlled, and for how long logs are kept. | Partial | No formal logging inventory. Tracy logger handles errors. Application-level security logging not comprehensive. | Per-project: document logging inventory: Tracy error logs, `DoctrineLoggable` ChangeLog table, `LoginAttempt` table, `StorageEntity` sessions. | + +## V16.2 General Logging + +This section provides requirements to ensure that security logs are consistently structured and con‑ tain the expected metadata. The goal is to make logs machine‑readable and analyzable across dis‑ tributed systems and tools. Naturally, security events often involve sensitive data. If such data is logged without consideration, the logs themselves become classified and therefore subject to encryption requirements, stricter re‑ tention policies, and potential disclosure during audits. Therefore, it is critical to log only what is necessary and to treat log data with the same care as other sensitive assets. The requirements below establish foundational requirements for logging metadata, synchroniza‑ tion, format, and control. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 16.2.1 | 2 | Verify that each log entry includes necessary metadata (such as when, where, who, what) that would allow for a detailed investigation of the timeline when an event happens. | Partial | Tracy log entries include timestamp, file, line. Missing: user ID, IP address, request context in application logs. | Pending fancyadmin: enrich security logs with `$identity->getId()`, `$httpRequest->getRemoteAddress()`, and request context. | +| 16.2.2 | 2 | Verify that time sources for all logging components are synchronized, and that timestamps in security event metadata use UTC or include an explicit time zone offset. UTC is recommended to ensure consistency across distributed systems and to prevent confusion during daylight saving time transitions. | Compliant | Server time synchronized via NTP. Single timezone used consistently. | — | +| 16.2.3 | 2 | Verify that the application only stores or broadcasts logs to the files and services that are documented in the log inventory. | Compliant | Tracy logs stored on server filesystem. Nette does not broadcast logs to untrusted services. | — | +| 16.2.4 | 2 | Verify that logs can be read and correlated by the log processor that is in use, preferably by using a common logging format. | Partial | Tracy logs are text files. No structured logging format (JSON) for automated processing. | Per-project: consider Monolog with JSON formatter instead of Tracy file-based logs for machine-readable structured logging. | +| 16.2.5 | 2 | Verify that when logging sensitive data, the application enforces logging based on the data's protection level. For example, it may not be allowed to log certain data, such as credentials or payment details. Other data, such as session tokens, may only be logged by being hashed or masked, either in full or partially. | Partial | No explicit PII masking in logs. Passwords not logged, but user emails may appear in error context. | Per-project: register custom Tracy log processor to redact emails and PII from error context before writing to logs. | + +## V16.3 Security Events + +This section defines requirements for logging security‑relevant events within the application. Cap‑ turing these events is critical for detecting suspicious behavior, supporting investigations, and ful‑ filling compliance obligations. This section outlines the types of events that should be logged but does not attempt to provide ex‑ haustive detail. Each application has unique risk factors and operational context. Note that while ASVS includes logging of security events in scope, alerting and correlation (e.g., SIEM rules or monitoring infrastructure) are considered out of scope and are handled by operational and monitoring systems. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 16.3.1 | 2 | Verify that all authentication operations are logged, including successful and unsuccessful attempts. Additional metadata, such as the type of authentication or factors used, should also be collected. | Compliant | Failed login attempts logged via LoginAttempt entity (IP, timestamp). Successful logins logged via StorageEntity (session table) with createdAt, objectId, IP, userAgent, context. Password changes logged via DoctrineLoggable (ChangeLog table). | — | +| 16.3.2 | 2 | Verify that failed authorization attempts are logged. For L3, this must include logging all authorization decisions, including logging when sensitive data is accessed (without logging the sensitive data itself). | Partial | Authorization failures result in HTTP 403 via Nette ACL. Not explicitly logged as security events. | Pending fancyadmin: log `$user->isAllowed()` failures in `AuthPresenterTrait::checkRequirements()` as security events. | +| 16.3.3 | 2 | Verify that the application logs the security events that are defined in the documentation and also logs attempts to bypass the security controls, such as input validation, business logic, and anti‑automation. | Partial | No comprehensive security event logging. Fraud detection logged via onFraudDetection callback. Most security events not explicitly logged. | Pending fancyadmin: add security event logging for: rate limit triggers, session invalidation, password changes, CSRF failures. | +| 16.3.4 | 2 | Verify that the application logs unexpected errors and security control failures such as backend TLS failures. | Compliant | Tracy logger captures all uncaught exceptions and errors. Error details logged server-side, generic message shown to user. | — | + +## V16.4 Log Protection + +Logs are valuable forensic artifacts and must be protected. If logs can be easily modified or deleted, they lose their integrity and become unreliable for incident investigations or legal proceedings. Logs may expose internal application behavior or sensitive metadata, making them an attractive target for attackers. This section defines requirements to ensure that logs are protected from unauthorized access, tam‑ pering, and disclosure, and that they are safely transmitted and stored in secure, isolated systems. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 16.4.1 | 2 | Verify that all logging components appropriately encode data to prevent log injection. | Compliant | Tracy logger encodes output. Log injection not a risk with file-based logging. | — | +| 16.4.2 | 2 | Verify that logs are protected from unauthorized access and cannot be modified. | Compliant | Log files stored on server filesystem with restricted permissions. Not accessible via web. | — | +| 16.4.3 | 2 | Verify that logs are securely transmitted to a logically separate system for analysis, detection, alerting, and escalation. The aim is to ensure that if the application is breached, the logs are not compromised. | Partial | Logs stored locally on application server. No centralized logging (SIEM) or log forwarding configured. | Per-project: set up log forwarding (syslog/ELK/Monolog handler) to a system separate from the application server. | + +## V16.5 Error Handling + +This section defines requirements to ensure that applications fail gracefully and securely without disclosing sensitive internal details. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 16.5.1 | 2 | Verify that a generic message is returned to the consumer when an unexpected or security‑sensitive error occurs, ensuring no exposure of sensitive internal system data such as stack traces, queries, secret keys, and tokens. | Compliant | Nette framework catches exceptions globally. Tracy logger for error recording. No sensitive data in error responses. | — | +| 16.5.2 | 2 | Verify that the application continues to operate securely when external resource access fails, for example, by using patterns such as circuit breakers or graceful degradation. | Compliant | Tracy logger handles exceptions. No stack traces exposed in production. | — | +| 16.5.3 | 2 | Verify that the application fails gracefully and securely, including when an exception occurs, preventing fail‑open conditions such as processing a transaction despite errors resulting from validation logic. | Compliant | Tracy error handler catches all exceptions. Application fails gracefully with generic error page in production. No sensitive data in error responses. | — | +| 16.5.4 | 3 | Verify that a "last resort"error handler is defined which will catch all unhandled exceptions. This is both to avoid losing error details that must go to log files and to ensure that an error does not take down the entire application process, leading to a loss of availability. Note: Certain languages, (including Swift, Go, and through common design practice, many func‑ tional languages,) do not support exceptions or last‑resort event handlers. In this case, architects and developers should use a pattern, language, or framework‑friendly way to ensure that applica‑ tions can securely handle exceptional, unexpected, or security‑related events. | | | | + +--- + +**Total requirements in this chapter: 17** +- Level 1: 0 +- Level 2: 16 +- Level 3: 1 diff --git a/ASVS/V17-WebRTC.md b/ASVS/V17-WebRTC.md new file mode 100644 index 0000000..cf2f103 --- /dev/null +++ b/ASVS/V17-WebRTC.md @@ -0,0 +1,43 @@ +# V17 WebRTC + +OWASP Application Security Verification Standard 5.0.0 + +## V17.1 TURN Server + +This section defines security requirements for systems that operate their own TURN (Traversal Us‑ ing Relays around NAT) servers. TURN servers assist in relaying media in restrictive network envi‑ ronments but can pose risks if misconfigured. These controls focus on secure address filtering and protection against resource exhaustion. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 17.1.1 | 2 | Verify that the Traversal Using Relays around NAT (TURN) service only allows access to IP addresses that are not reserved for special purposes (e.g., internal networks, broadcast, loopback). Note that this applies to both IPv4 and IPv6 addresses. | Out of scope | Application does not use WebRTC. WebSocket connections are project-specific, out of fancyadmin scope. | — | +| 17.1.2 | 3 | Verify that the Traversal Using Relays around NAT (TURN) service is not susceptible to resource exhaustion when legitimate users attempt to open a large number of ports on the TURN server. | Out of scope | Application does not use WebRTC. | — | + +## V17.2 Media + +These requirements only apply to systems that host their own WebRTC media servers, such as Selec‑ tive Forwarding Units (SFUs), Multipoint Control Units (MCUs), recording servers, or gateway servers. Media servers handle and distribute media streams, making their security critical to protect commu‑ nication between peers. Safeguarding media streams is paramount in WebRTC applications to pre‑ vent eavesdropping, tampering, and denial‑of‑service attacks that could compromise user privacy and communication quality. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 17.2.1 | 2 | Verify that the key for the Datagram Transport Layer Security (DTLS) certificate is managed and protected based on the documented policy for management of cryptographic keys. | Out of scope | Application does not use WebRTC. | — | +| 17.2.2 | 2 | Verify that the media server is configured to use and support approved Datagram Transport Layer Security (DTLS) cipher suites and a secure protection profile for the DTLS Extension for establishing keys for the Secure Real‑time Transport Protocol (DTLS‑SRTP). | Out of scope | Application does not use WebRTC. | — | +| 17.2.3 | 2 | Verify that Secure Real‑time Transport Protocol (SRTP) authentication is checked at the media server to prevent Real‑time Transport Protocol (RTP) injection attacks from leading to either a Denial of Service condition or audio or video media insertion into media streams. | Out of scope | Application does not use WebRTC. | — | +| 17.2.4 | 2 | Verify that the media server is able to continue processing incoming media traffic when encountering malformed Secure Real‑time Transport Protocol (SRTP) packets. | Out of scope | Application does not use WebRTC. | — | +| 17.2.5 | 3 | Verify that the media server is able to continue processing incoming media traffic during a flood of Secure Real‑time Transport Protocol (SRTP) packets from legitimate users. | Out of scope | Application does not use WebRTC. | — | +| 17.2.6 | 3 | Verify that the media server is not susceptible to the "ClientHello"Race Condition vulnerability in Datagram Transport Layer Security (DTLS) by checking if the media server is publicly known to be vulnerable or by performing the race condition test. | Out of scope | Application does not use WebRTC. | — | +| 17.2.7 | 3 | Verify that any audio or video recording mechanisms associated with the media server are able to continue processing incoming media traffic during a flood of Secure Real‑time Transport Protocol (SRTP) packets from legitimate users. | Out of scope | Application does not use WebRTC. | — | +| 17.2.8 | 3 | Verify that the Datagram Transport Layer Security (DTLS) certificate is checked against the Session Description Protocol (SDP) fingerprint attribute, terminating the media stream if the check fails, to ensure the authenticity of the media stream. | Out of scope | Application does not use WebRTC. | — | + +## V17.3 Signaling + +This section defines requirements for systems that operate their own WebRTC signaling servers. Sig‑ naling coordinates peer‑to‑peer communication and must be resilient against attacks that could dis‑ rupt session establishment or control. To ensure secure signaling, systems must handle malformed inputs gracefully and remain available under load. + +| # | Level | Requirement | Status | How We Comply | What to Do | +|---|-------|-------------|--------|---------------|------------| +| 17.3.1 | 2 | Verify that the signaling server is able to continue processing legitimate incoming signaling messages during a flood attack. This should be achieved by implementing rate limiting at the signaling level. | Out of scope | Application does not use WebRTC. | — | +| 17.3.2 | 2 | Verify that the signaling server is able to continue processing legitimate signaling messages when encountering malformed signaling message that could cause a denial of service condition. This could include implementing input validation, safely handling integer overflows, preventing buffer overflows, and employing other robust error‑handling techniques. | Out of scope | Application does not use WebRTC. | — | + +--- + +**Total requirements in this chapter: 12** +- Level 1: 0 +- Level 2: 7 +- Level 3: 5 diff --git a/README.md b/README.md index 42f24ec..de2083b 100644 --- a/README.md +++ b/README.md @@ -1 +1,1229 @@ -# fancyadmin \ No newline at end of file +# Integrace adt/fancyadmin do Nette projektu + +Tento dokument popisuje krok za krokem, jak integrovat balíček `adt/fancyadmin` do nového Nette 3.x projektu. + +--- + +## Předpoklady + +Projekt musí mít nainstalováno: +- PHP >= 8.4 +- Nette 3.1+ +- Nettrine ORM (`nettrine/orm ^0.10`, `nettrine/dbal ^0.10`) +- Nettrine Migrations (`nettrine/migrations ^0.10`) +- `kdyby/autowired ^3.1` +- `contributte/console ^0.10` +- MySQL 8.0 + +--- + +## 1. Composer require + +```bash +composer require adt/fancyadmin:^1.0 +``` + +Fancyadmin automaticky stáhne tyto závislosti: +- `adt/doctrine-authenticator` — autentizace přes Doctrine +- `adt/doctrine-components` — BaseEntity, QueryObject, EntityManager +- `adt/doctrine-forms` — formuláře napojené na Doctrine entity +- `adt/nette-forms-components` — rozšířené formulářové prvky +- `adt/datagrid-components` — datagridy +- `adt/files` — správa souborů +- `adt/doctrine-loggable` — audit log +- `contributte/translation` — překlady +- `nette/forms`, `nette/security`, `nette/mail` +- `ublaboo/datagrid` + +Doplňkově doporučeno: +```bash +composer require adt/doctrine-components:^3.2 adt/query-object-data-source:^3.0 +``` + +--- + +## 2. BaseEntity + +Vytvořte abstraktní BaseEntity, od které budou dědit všechny entity: + +```php +// app/Model/Entities/Abstract/BaseEntity.php +accounts = new ArrayCollection(); + } +} +``` + +**AccountTrait poskytuje:** `name`, `parent` (self-ref), `accounts` (sub-accounts), timestamps + +### 3.3 Profile + +```php +// app/Model/Entities/Profile.php +value; + } +} +``` + +--- + +## 5. Query třídy + +Fancyadmin vyžaduje QueryObject pattern z `adt/doctrine-components`. Každý query objekt: +- dědí z BaseQuery (rozšiřuje `ADT\DoctrineComponents\QueryObject\QueryObject`) +- implementuje interface z fancyadmin +- používá odpovídající trait z fancyadmin + +### 5.1 BaseQuery + +```php +// app/Model/Queries/Abstract/BaseQuery.php + + * @template TEntity of object + */ +abstract class BaseQuery extends QueryObject implements OrByIdFilterInterface, \ADT\FancyAdmin\Model\Queries\Abstract\BaseQuery +{ + use BaseQueryTrait; +} +``` + +### 5.2 Konkrétní Query třídy + +Vzor je pro všechny stejný — implementovat interface, použít trait, přidat stub metody: + +```php +// app/Model/Queries/IdentityQuery.php + + */ +class IdentityQuery extends Abstract\BaseQuery + implements \ADT\FancyAdmin\Model\Queries\IdentityQuery, + \ADT\DoctrineAuthenticator\OTP\IdentityQuery +{ + use IdentityQueryTrait; + + protected function applySecurityFilter(): void {} + protected function applyAccountFilter(QueryBuilder $qb, Account $account): void {} + protected function setDefaultOrder(): void {} +} +``` + +Stejný vzor pro: +- **AccountQuery** — `use AccountQueryTrait; implements \ADT\FancyAdmin\Model\Queries\AccountQuery` +- **ProfileQuery** — `use ProfileQueryTrait; implements \ADT\FancyAdmin\Model\Queries\ProfileQuery` +- **AclRoleQuery** — `use AclRoleQueryTrait; implements \ADT\FancyAdmin\Model\Queries\AclRoleQuery` (+ `applyAccountFilter`) +- **ConfigurationQuery** — `use ConfigurationQueryTrait; implements \ADT\FancyAdmin\Model\Queries\ConfigurationQuery` +- **GridFilterQuery** — `use \ADT\Datagrid\Model\Queries\GridFilterQueryTrait; implements \ADT\Datagrid\Model\Queries\GridFilterQuery` + +### 5.3 DefaultFilters trait + +```php +// app/Model/Queries/Filters/DefaultFilters.php +getRouteList(); + + // Web module routes + $webModule = new RouteList('Web'); + $webModule->addRoute('/[/]', [ + 'presenter' => 'Home', + 'action' => 'default', + ]); + $router[] = $webModule; + + return $router; + } +} +``` + +--- + +## 14. Portal Presentery + +Fancyadmin poskytuje presenter traity pro portálovou část (admin): + +### BasePresenter + +```php +// app/UI/Portal/Presenters/BasePresenter.php + **Důležité:** import musí být eager (ne přes `AdtJsComponents.init`, který modul načítá lazy až +> když je formulář na stránce). Modul si při importu naváže delegovaný `change` listener na `document`, +> takže funguje i pro login formulář vložený přes AJAX (např. po odhlášení), aniž by se musel +> reinicializovat. Při lazy načtení by se po AJAX přepnutí na `/sign/in` listener nenavázal. + +**Závislost:** Projekt musí mít nainstalovaný npm balíček `keycloak-js`: +```bash +yarn add keycloak-js +``` + +### 18.7 Co se děje automaticky + +Po zapnutí Keycloak konfigurace fancyadmin automaticky: + +- **Registruje routy** `keycloak-auth/` a `keycloak-log/` v Portal modulu +- **Login formulář** — přidá `data-keycloak-check-url` atribut na email input; po zadání emailu JS zjistí SSO instanci z identity/role a přesměruje na odpovídající Keycloak +- **Logout** — `Sign:out` automaticky odhlásí i z Keycloaku (pokud se uživatel přihlásil přes SSO) +- **Frontend** — do layoutu injektuje `window.__keycloakSettings` pro keycloak-js adapter (silent SSO check, token refresh) +- **Registrace při SSO** — pokud se přes Keycloak přihlásí uživatel, který v aplikaci neexistuje, automaticky se mu vytvoří identita s vazbou na SSO instanci a `defaultRole` (pokud je nakonfigurovaná) + +### 18.8 Keycloak služba — správa uživatelů + +Keycloak instance jsou dostupné přes `KeycloakManager`: + +```php +$manager = $this->_fancyAdmin->getKeycloakManager(); // null pokud je Keycloak vypnutý + +// Získat konkrétní instanci podle názvu +$keycloak = $manager->getInstance('hlavni'); + +// Získat instanci podle identity (z identity.sso nebo role.sso) +$keycloak = $manager->getInstanceForIdentity($identity); + +// Získat instanci, přes kterou je přihlášen aktuální uživatel (ze session) +$keycloak = $manager->getInstanceFromSession(); +``` + +Každá instance poskytuje metody pro správu uživatelů přes Admin API: + +```php +// Registrace uživatele v Keycloaku (vrací existujícího pokud už existuje) +$keycloakUser = $keycloak->registerUser($identity, 'heslo', temporaryPassword: false); + +// Aktualizace údajů (email, jméno, příjmení) +$keycloakUser = $keycloak->updateUser($identity); + +// Deaktivace / aktivace +$keycloak->disableUser($identity); +$keycloak->enableUser($identity); + +// Nastavení hesla +$keycloak->setUserPassword($identity, 'noveHeslo', temporary: true); + +// Vyhledání uživatele podle emailu +$keycloakUser = $keycloak->findUser('user@example.com'); +``` + +### 18.9 Backchannel logout + +Keycloak podporuje backchannel logout — při ukončení session v Keycloaku (odhlášení, expirace, deaktivace uživatele) Keycloak pošle POST request na aplikaci, která invaliduje lokální session uživatele. + +#### Nastavení v Keycloaku + +V Keycloak admin panelu → **Clients** → váš confidential client → **Settings**: + +1. **Backchannel logout URL**: + ``` + https://admin.muj-projekt.cz/keycloak-auth/backchannel-logout?instance=nazev-sso + ``` + Kde `nazev-sso` odpovídá hodnotě `name` v tabulce `sso`. + +2. **Backchannel logout session required**: **On** + +Opakujte pro každou SSO instanci s odpovídajícím `?instance=` parametrem. + +#### Co se děje + +1. Keycloak pošle POST s `logout_token` (JWT) na backchannel URL +2. Aplikace dekóduje token, získá `sub` (Keycloak user ID) +3. Přes Admin API zjistí email uživatele +4. Najde lokální identitu podle emailu +5. Invaliduje všechny její sessions (`Authenticator::clearIdentity`) + +Tím je zajištěno, že: +- Uživatel odhlášený z Keycloaku je automaticky odhlášen i z aplikace +- Uživatel deaktivovaný v Keycloaku ztrácí přístup okamžitě (session je ukončena a nové SSO přihlášení selže) + +### 18.10 Přidání nové Keycloak instance + +Postup pro přidání další SSO instance do existujícího projektu: + +1. **DB** — vytvořte nový záznam v tabulce `sso` s kompletní konfigurací (realm, URL, credentials) +2. **DB** — u příslušných rolí/identit nastavte vazbu na nové SSO +3. **Keycloak** — v novém clientu nastavte backchannel logout URL (viz 18.9) + +Žádná změna PHP kódu, `.env` ani neon konfigurace není potřeba. Instance se vytváří dynamicky z databáze. + +### 18.11 Rozšíření chování + +Keycloak službu lze rozšířit v projektu — např. pro úpravu logiky vytváření identity při SSO loginu: + +```php +class MyKeycloak extends \ADT\FancyAdmin\Model\Security\Keycloak\Keycloak +{ + protected function createIdentity(array $userInfo): Identity + { + $identity = parent::createIdentity($userInfo); + // vlastní logika — přiřazení kontextu, notifikace, atd. + return $identity; + } +} +``` + +Pro použití vlastní třídy je potřeba rozšířit `KeycloakManager::createInstanceFromSso()` v projektu. + +--- + +## Shrnutí + +| Krok | Co | Proč | +|---|---|---| +| BaseEntity | Abstraktní třída s Identifier trait | Sdílený základ pro všechny entity | +| 9 entit | Identity, Account, Profile, AclRole, AclResource, Acl, Configuration, File, GridFilter | Fancyadmin vyžaduje všechny pro funkční ACL, auth, grid filtry, konfiguraci | +| AclResourceNameEnum | Enum implementující Nette\Security\Resource | Definice ACL resources pro fancyadmin config | +| BaseQuery + 6 Query tříd | QueryObject pattern s fancyadmin traits | Fancyadmin interně používá query factories pro přístup k datům | +| 6 QueryFactory interfaces | Rozšiřují fancyadmin factory interfaces | DI autowiring pro query třídy | +| Authenticator | Rozšiřuje OnetimeTokenAuthenticator | Autentizace přes Doctrine (email + heslo, OTP) | +| SecurityUser | Rozšiřuje ADT\DoctrineAuthenticator\SecurityUser | Session management, isAllowed(), isAdmin() | +| Permission | Rozšiřuje fancyadmin Permission | ACL authorizátor | +| EntityManager | Rozšiřuje ADT\DoctrineComponents\EntityManager | Rozšířený EntityManager s helper metodami | +| 3 Listeners | CreatedBy, AccountField, SelectAccount | Automatické nastavování created_by, account polí při persistu | +| Translator | Rozšiřuje Contributte\Translation\Translator | Překlady | +| RouterFactory | Integruje FancyAdminRouter | Sign routes, portal routes | +| Portal presentery | BasePresenter + AuthPresenter s fancyadmin traits | Admin layout, auth check, side panel | diff --git a/assets/js/_jquery-global.js b/assets/js/_jquery-global.js new file mode 100644 index 0000000..7fe6d68 --- /dev/null +++ b/assets/js/_jquery-global.js @@ -0,0 +1,12 @@ +// jQuery must be exposed as a global BEFORE any legacy jQuery plugin (jquery-ui-bundle, +// @regru/jquery-menu-aim, nette.ajax.js, …) is evaluated. ES module imports are hoisted +// and evaluated depth-first in source order, so importing this module FIRST guarantees +// the globals exist before those plugin modules run. +import jQuery from 'jquery'; + +window.$ = jQuery; +window.jquery = jQuery; +window.jQuery = jQuery; +globalThis.jQuery = jQuery; + +export default jQuery; diff --git a/assets/js/_registerFancyadminComponents.js b/assets/js/_registerFancyadminComponents.js new file mode 100644 index 0000000..48159b1 --- /dev/null +++ b/assets/js/_registerFancyadminComponents.js @@ -0,0 +1,13 @@ +// Registers FancyAdmin's own JS components (referenced as "~UI/..." in +// AdtJsComponents.init() calls), so each consuming project doesn't have to. +// +// Imported first by app.js — runs before app.js's init() calls, and merges into +// the shared registry (see ComponentLoader.registerModules), so the consumer can +// still register its own 'app' components and 'builtin' allowlist separately. +// +// The glob is relative to this file (assets/js/) → resolves to the package's src/UI. +import AdtJsComponents from 'adt-js-components'; + +AdtJsComponents.registerModules({ + fancyadmin: import.meta.glob('../../src/UI/**/index.js'), +}); diff --git a/assets/js/_registerStandaloneBuiltins.js b/assets/js/_registerStandaloneBuiltins.js new file mode 100644 index 0000000..da9d605 --- /dev/null +++ b/assets/js/_registerStandaloneBuiltins.js @@ -0,0 +1,10 @@ +// Built-in adt-js-components used by FancyAdmin's own standalone build (admin.js). +// In a real consuming project this allowlist lives in the project; here it's only +// for the package's standalone build. Separate module so it's evaluated before +// app.js's init() calls (static imports are hoisted, so a registerModules() call in +// admin.js's body would run too late). +import AdtJsComponents from 'adt-js-components'; + +AdtJsComponents.registerModules({ + builtin: import.meta.glob('../../node_modules/adt-js-components/src/{Messaging,Notifications,Translate}/index.js'), +}); diff --git a/assets/js/admin.js b/assets/js/admin.js new file mode 100644 index 0000000..704b7ff --- /dev/null +++ b/assets/js/admin.js @@ -0,0 +1,8 @@ +// Standalone Vite entry for the FancyAdmin package — the equivalent of the old +// webpack 'admin' build (which bundled assets/js/app.js). +// +// app.js self-registers FancyAdmin's own components ('fancyadmin' scope). For the +// standalone build we additionally register the built-ins it uses, first, so the +// registration runs before app.js's init() calls (imports are hoisted). +import './_registerStandaloneBuiltins'; +import './app'; diff --git a/assets/js/app.js b/assets/js/app.js index 9f746fe..55f609a 100644 --- a/assets/js/app.js +++ b/assets/js/app.js @@ -1,28 +1,31 @@ +// +// jQuery as a global — MUST be first so it is set before the legacy plugins below +// (and bundled deps like nette.ajax.js) are evaluated. Imports are hoisted. +// +import $ from './_jquery-global'; + +// +// Register FancyAdmin's own JS components (before the init() calls below). +// +import './_registerFancyadminComponents'; + // // SCSS styles // import '../scss/app.scss'; // -// Old non-modular JS vendor files +// Legacy non-modular jQuery plugins (rely on the global set above). // -// import jQuery from 'jquery'; -import $ from 'jquery'; import 'jquery-ui-bundle'; import '@regru/jquery-menu-aim'; -window.$ = $; -window.jquery = $; -window.jQuery = $; - -global.jQuery = $; - -import {Chart} from "chart.js/auto"; +// import {Chart} from "chart.js/auto"; import Nette from 'nette-forms'; import './dependentSelectBox' Nette.initOnLoad(); window.Nette = Nette; -window.Chart = Chart; +// window.Chart = Chart; import 'nette.ajax.js'; $.nette.init({ @@ -53,7 +56,7 @@ $.nette.ext('live').after(function($el) { $('[data-dependentselectbox]').dependentSelectBox(); }); -import 'daterangepicker'; +// import 'daterangepicker'; // // Modular vendor JS files @@ -80,20 +83,22 @@ import AdtJsComponents from 'adt-js-components'; // // AdtJsComponents.init('components-panels-base-baseChartPanel', 'UI/Portal/Components/Panels/Base/BaseChartPanelControl'); AdtJsComponents.init('select-account-form', '~UI/Components/Forms/SelectAccount'); +AdtJsComponents.init('portal-components-grids-traits-signInAsIdentity', '~UI/Components/Grids/Traits/SignInAsIdentity'); // AdtJsComponents.init('portal-components-forms-dashboardFilter', 'UI/Portal/Components/Forms/DashboardFilter'); // AdtJsComponents.init('portal-components-forms-changeLicenceForm', 'UI/Portal/Components/Forms/ChangeLicence'); // AdtJsComponents.init('portal-components-forms-warehouseOperationForm', 'UI/Portal/Components/Forms/WarehouseOperation'); // AdtJsComponents.init('companySitePlanDetail', 'UI/Portal/Presenters/CompanySitePlans'); // AdtJsComponents.init('dashboard', 'UI/Portal/Presenters/Dashboard'); // AdtJsComponents.init('dashboard', 'assets/js/dashboard'); -// AdtJsComponents.init('messaging', 'assets/js/messaging'); -// AdtJsComponents.init('notifications', 'assets/js/notifications'); -// AdtJsComponents.init('translate', 'assets/js/translate'); +AdtJsComponents.init('messaging', 'Messaging'); +AdtJsComponents.init('notifications', 'Notifications'); +AdtJsComponents.init('translate', 'Translate'); + // AdtJsComponents.init('print-dashboard', 'assets/js/printDashboard'); // AdtJsComponents.init('safari-support', 'assets/js/safariSupport'); // // import './netteForm'; -// import './flashes'; +import './flashes'; // import './userDropdown'; // import './tableActionsShadow'; // import './_datagrid'; @@ -106,5 +111,6 @@ AdtJsComponents.init('select-account-form', '~UI/Components/Forms/SelectAccount' // import 'forms-replicator'; import './sideMenu' +import './datagrid/datagrid' import './datagrid' -import './summernote' \ No newline at end of file +import './sidePanel' diff --git a/assets/js/datagrid.js b/assets/js/datagrid.js index cfd9526..f349ac8 100644 --- a/assets/js/datagrid.js +++ b/assets/js/datagrid.js @@ -1,4 +1,6 @@ -datagridSortable = function($el) { +// Explicit global: ublaboo renders inline scripts that call datagridSortable(). +// ESM modules are strict, so the previous implicit global assignment threw. +window.datagridSortable = function($el) { if (typeof $.fn.sortable === 'undefined') { return; } @@ -46,10 +48,58 @@ datagridSortable = function($el) { }); }; -$(function() { +$.nette.ext('live').after(function (el) { + return datagridSortable(el); +}); +$(document).on('hidden.bs.collapse', '.datagrid form > .collapse', (e) => { + $(e.currentTarget).closest('form').find('.reset-filter').click(); }); -$.nette.ext('live').after(function (el) { - return datagridSortable(el); +/** + * Funkce zajistuje proklik na detail, pokud je na radku jenom jeden sloupec s odkazem ve sloupci col-name (musime mit + * name pokazde i kdyby slo o id nebo jiny identifikator) Je klikatelny cely radek az na bunky obsahujici tlacitka, selecty + * nebo inputy, stejne tak ignoruje sloupec col-action + */ +$(document).on('click', '.click-line-detail table tbody td:not(.col-action):not(:has(button, input, select))', (e) => { + $(e.currentTarget).closest('tr').find('.col-name > a').click(); +}); + +/** + * Funkce zajistuje proklik na detail kery je uvedeny ve sloupci col-name (musime mit name pokazde i kdyby slo + * o id nebo jiny identifikator) a ignoruje kliknuti na bunky obsahujici odkaz, select, tlacitka ci inputy, steje tak + * ignoruje sloupec col-action. Sloupcum s odkazem (i col-name) je treba pridat tridu click-line-detail-no-link-im-the-link. + */ +$(document).on('click', '.click-line-detail-no-link table tbody td:not(.col-action):not(:has(a, button, input, select))', (e) => { + $(e.currentTarget).closest('tr').find('.col-name > a').click(); +}); + +/** + * Funkce slouzi k prokliku pres bunku, ktera obsahuje link. Napriklad pokud budeme mit moznost se prokliknout jak na detail + * zarizeni, tak platby. Musime ale na bunku dat classu click-line-detail-no-link-im-the-link + */ +$(document).on('click', '.click-line-detail-no-link-im-the-link', (e) => { + $(e.currentTarget).find('a').click(); +}); + +$(document).on('click', 'a.link-confirmation', function (e) { + if (!confirm($(this).data('confirm-text'))){ + event.preventDefault(); + } +}); + +$(document).on('click', 'tbody tr:not(.row-item-detail) td:not(.col-action)', function (event) { + if (event.target.tagName.toLowerCase() === 'a' || $(event.target).hasClass('menu-open-button')) { + return; // Klik byl na odkaz, takže nevyvoláváme žádnou akci. + } + + let $tr = $(this).parent(); + + if ($tr.next().hasClass('toggled')) { + $tr.next().removeClass('toggled'); + $tr.next().find('.item-detail-content').css('display', 'none'); + } else { + $tr.next().addClass('toggled'); + $tr.next().find('.item-detail-content').css('display', 'block'); + } }); \ No newline at end of file diff --git a/assets/js/datagrid/datagrid-instant-url-refresh.js b/assets/js/datagrid/datagrid-instant-url-refresh.js new file mode 100644 index 0000000..f4ae43c --- /dev/null +++ b/assets/js/datagrid/datagrid-instant-url-refresh.js @@ -0,0 +1,30 @@ +var dataGridRegisterAjaxCall; + +if (typeof naja !== "undefined") { + dataGridRegisterAjaxCall = function (params) { + var method = params.type || 'GET'; + var data = params.data || null; + + naja.makeRequest(method, params.url, data, { + history: 'replace' + }) + .then(params.success) + .catch(params.error); + }; + +} else { + dataGridRegisterAjaxCall = function (params) { + $.nette.ajax(params); + }; +} + +document.addEventListener('DOMContentLoaded', function () { + var element = document.querySelector('.datagrid'); + + if (element !== null) { + return dataGridRegisterAjaxCall({ + type: 'GET', + url: element.getAttribute('data-refresh-state') + }); + } +}); diff --git a/assets/js/datagrid/datagrid-spinners.css b/assets/js/datagrid/datagrid-spinners.css new file mode 100755 index 0000000..818714d --- /dev/null +++ b/assets/js/datagrid/datagrid-spinners.css @@ -0,0 +1,118 @@ +@keyframes ublaboo-spinner-icon { + 0% { + transform: rotate(0); } + 50% { + transform: rotate(180deg); } + 100% { + transform: rotate(360deg); } } + +@-webkit-keyframes ublaboo-spinner-icon { + 0% { + transform: rotate(0); } + 50% { + transform: rotate(180deg); } + 100% { + transform: rotate(360deg); } } + +.ublaboo-spinner-icon > span { + animation-duration: 2s; + animation-delay: 0; + animation-iteration-count: infinite; + animation-timing-function: ease; + animation-name: ublaboo-spinner-icon; } + +@keyframes ublaboo-spinner-small { + 0% { + transform: translate(21.3px, 2.2px); } + 11.1% { + transform: translate(8.1px, 25.2px); } + 22.2% { + transform: translate(12.7px, -0.7px); } + 33.3% { + transform: translate(17.2px, 25.2px); } + 44.4% { + transform: translate(4.2px, 2.2px); } + 55.5% { + transform: translate(24.1px, 19.5px); } + 66.6% { + transform: translate(-0.3px, 10.3px); } + 77.7% { + transform: translate(25.8px, 10.3px); } + 88.8% { + transform: translate(1.2px, 19.3px); } + 100% { + transform: translate(21.3px, 2.2px); } } + +@-webkit-keyframes ublaboo-spinner-small { + 0% { + transform: translate(21.3px, 2.2px); } + 11.1% { + transform: translate(8.1px, 25.2px); } + 22.2% { + transform: translate(12.7px, -0.7px); } + 33.3% { + transform: translate(17.2px, 25.2px); } + 44.4% { + transform: translate(4.2px, 2.2px); } + 55.5% { + transform: translate(24.1px, 19.5px); } + 66.6% { + transform: translate(-0.3px, 10.3px); } + 77.7% { + transform: translate(25.8px, 10.3px); } + 88.8% { + transform: translate(1.2px, 19.3px); } + 100% { + transform: translate(21.3px, 2.2px); } } + +@keyframes ublaboo-spinner-in { + 0% { + opacity: 0; } + 100% { + opacity: 1; } } + +@-webkit-keyframes ublaboo-spinner-in { + 0% { + opacity: 0; } + 100% { + opacity: 1; } } + +.ublaboo-spinner { + line-height: 0; + display: inline-block; + margin: auto; + position: relative; + margin: 0 1em -11px 1em; + top: 1px; + opacity: 0; + animation-duration: 150ms; + animation-delay: 0; + animation-iteration-count: 1; + animation-timing-function: ease-in; + animation-name: ublaboo-spinner-in; + animation-fill-mode: forwards; } + .ublaboo-spinner > i { + position: absolute; + background-color: #37434f; + left: 0; + top: 0; + animation-duration: 6s; + animation-delay: 0; + animation-iteration-count: infinite; + animation-timing-function: ease; } + .ublaboo-spinner > i:nth-of-type(2) { + animation-delay: -1.5s; } + .ublaboo-spinner > i:nth-of-type(3) { + animation-delay: -3s; } + .ublaboo-spinner > i:nth-of-type(4) { + animation-delay: -4.5s; } + .ublaboo-spinner.ublaboo-spinner-small { + width: 28.0px; + height: 28.0px; } + .ublaboo-spinner.ublaboo-spinner-small > i { + width: 4.0px; + height: 4.0px; + border-radius: 2px; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + animation-name: ublaboo-spinner-small; } diff --git a/assets/js/datagrid/datagrid-spinners.js b/assets/js/datagrid/datagrid-spinners.js new file mode 100644 index 0000000..b6a0b2b --- /dev/null +++ b/assets/js/datagrid/datagrid-spinners.js @@ -0,0 +1,89 @@ +var dataGridRegisterExtension; + +if (typeof naja !== "undefined") { + var isNaja2 = function () { return naja && naja.VERSION && naja.VERSION >= 2 }; + var najaEventParams = function (params) { return isNaja2() ? params.detail : params }; + var najaRequest = function (params) { return isNaja2() ? params.detail.request : params.xhr }; + dataGridRegisterExtension = function (name, extension) { + var init = extension.init; + var success = extension.success; + var before = extension.before; + var complete = extension.complete; + + + var NewExtension = function NewExtension(naja, name) { + this.name = name; + + this.initialize = function (naja) { + if(init) { + naja.addEventListener('init', function (params) { + init(najaEventParams(params).defaultOptions); + }); + } + + if(success) { + naja.addEventListener('success', function (params) { + var payload = isNaja2() ? params.detail.payload : params.response; + success(payload, najaEventParams(params).options); + }); + } + + if(before) { + naja.addEventListener('before', function (params) { + before(najaRequest(params), najaEventParams(params).options); + }); + } + + if(complete) { + naja.addEventListener('complete', function (params) { + complete(najaRequest(params), najaEventParams(params).options); + }); + } + } + if (!isNaja2()) { + this.initialize(naja); + } + return this; + } + + if (isNaja2()) { + naja.registerExtension(new NewExtension(null, name)); + } else { + naja.registerExtension(NewExtension, name); + } + }; +} else if ($.nette) { + dataGridRegisterExtension = function (name, extension) { + $.nette.ext(name, extension); + }; +} + +dataGridRegisterExtension('ublaboo-spinners', { + before: function(xhr, settings) { + var el, id, row_detail, spinner_template, grid_fullname; + if (settings.nette) { + el = settings.nette.el; + spinner_template = $('
'); + if (el.is('.datagrid [name="group_action[submit]"]')) { + return el.after(spinner_template); + } else if (el.is('.datagrid a') && el.data('toggle-detail')) { + id = settings.nette.el.attr('data-toggle-detail'); + grid_fullname = settings.nette.el.attr('data-toggle-detail-grid-fullname'); + row_detail = $('.item-detail-' + grid_fullname + '-id-' + id); + if (!row_detail.hasClass('loaded')) { + return el.addClass('ublaboo-spinner-icon'); + } + } else if (el.is('.datagrid .col-pagination a')) { + return el.closest('.row-grid-bottom').find('.col-per-page').prepend(spinner_template); + } else if (el.is('.datagrid .datagrid-per-page-submit')) { + return el.closest('.row-grid-bottom').find('.col-per-page').prepend(spinner_template); + } else if (el.is('.datagrid .reset-filter')) { + return el.closest('.row-grid-bottom').find('.col-per-page').prepend(spinner_template); + } + } + }, + complete: function() { + $('.ublaboo-spinner').remove(); + return $('.ublaboo-spinner-icon').removeClass('ublaboo-spinner-icon'); + } +}); diff --git a/assets/js/datagrid/datagrid.css b/assets/js/datagrid/datagrid.css new file mode 100755 index 0000000..30c58a6 --- /dev/null +++ b/assets/js/datagrid/datagrid.css @@ -0,0 +1,641 @@ +@keyframes edited { + 0% { + background-color: #A6E2A9 + } + + 100% { + background-color: transparent + } + +} + +@keyframes edited-error { + 0% { + background-color: #E8AAA4 + } + + 100% { + background-color: transparent + } + +} + +.datagrid { + background-color: #fff; + padding: 1em; + box-sizing: border-box +} + +.datagrid .datagrid-input-group-full-width { + width: 100% +} + +.datagrid .hidden { + display: none !important +} + +.datagrid .datagrid-collapse-filters-button-row { + margin-bottom: 0.5em +} + +.datagrid .col-action .dropdown { + display: inline-block +} + +.datagrid .datagrid-row-inline-add.datagrid-row-inline-add-hidden { + display: none +} + +.datagrid .datagrid-row-columns-summary td { + border-top: 2px solid #bbb; + border-left: 1px solid #eee; + border-right: 1px solid #eee; + font-weight: bold +} + +.datagrid .datagrid-row-columns-summary td:first-child { + border-left: 1px solid #ddd +} + +.datagrid .datagrid-row-columns-summary td:last-child { + border-right: 1px solid #ddd +} + +.datagrid .datagrid-toolbar { + margin-top: .35em; + float: right; + display: inline-block +} + +.datagrid .datagrid-toolbar > div > span { + margin-left: 1em +} + +.datagrid .datagrid-toolbar > div > span > a { + margin-left: 0.5em +} + +.datagrid .datagrid-toolbar > div { + display: inline-block +} + +.datagrid-toolbar .fa-square, .datagrid-toolbar .fa-check-square { + font-weight: normal; +} + +.datagrid .datagrid-exports .btn { + margin-left: 0.5em +} + +.datagrid .datagrid-exports .btn:first-child { + margin-left: 0 +} + +.datagrid .datagrid-settings { + display: inline-block +} + +.datagrid .datagrid-settings .dropdown-menu--grid { + font-size: 12px +} + +.datagrid .datagrid-settings .dropdown-menu--grid li .fa { + margin-right: 0.5em +} + +.datagrid .row-reset-filter { + text-align: right; + margin-bottom: 0.5em +} + +.datagrid .row-filters .datagrid-row-outer-filters-group { + margin-bottom: 0.5em +} + +.datagrid .datagrid-manual-submit { + margin-bottom: 0.5em +} + +.datagrid .filter-range-delimiter { + text-align: center +} + +.datagrid .bootstrap-select.input-sm > .btn { + padding: 5px 25px 5px 10px; + font-size: 12px; + line-height: 1.5; + border-radius: 3px +} + +.datagrid table { + margin: 0 +} + +.datagrid table thead tr .bootstrap-select:not([class*=col-]):not(.input-group-btn) { + width: auto +} + +.datagrid table thead tr .bootstrap-select:not([class*=col-]):not(.input-group-btn) > .btn { + width: auto +} + +.datagrid table thead tr .bootstrap-select:not([class*=col-]):not(.input-group-btn) .dropdown-menu li { + font-size: 13px +} + +.datagrid table thead tr.row-group-actions th { + border-bottom-width: 0 !important; + background-color: #f9f9f9 +} + +.datagrid table thead tr.row-group-actions .datagrid-selected-rows-count { + margin-left: 0.3em +} + +.datagrid table thead tr th { + font-size: 90%; + vertical-align: top +} + +.datagrid table thead tr th hr { + margin: 8px -8px +} + +.datagrid table thead tr th .datagrid-column-header-additions { + float: right +} + +.datagrid table thead tr th .datagrid-column-header-additions a[data-datagrid-reset-filter-by-column] { + margin-left: 0.3em; + color: #858585 +} + +.datagrid table thead tr th .datagrid-column-header-additions .column-settings-menu { + opacity: 0; + cursor: pointer; + margin-left: 0.3em; + display: inline-block +} + +.datagrid table thead tr th .datagrid-column-header-additions .column-settings-menu .dropdown-menu { + font-size: 12px +} + +.datagrid table thead tr th .datagrid-column-header-additions .column-settings-menu .dropdown-menu li .fa { + margin-right: 0.5em +} + +.datagrid table thead tr th .datagrid-column-header-additions .column-settings-menu .dropdown-toggle::after { + display: none !important +} + +.datagrid .datagrid-col-filter-date-range { + width: auto; + position: relative; + display: flex; + flex-wrap: wrap; + align-items: stretch; +} + +.datagrid .datagrid-col-filter-date-range > .input-group { + position: relative; + -ms-flex: 1 1 auto; + flex: 1 1 auto; + width: 1%; + margin-bottom: 0; +} + +.datagrid .datagrid-col-filter-datte-range-delimiter { + background-color: inherit; + border: none; + padding: .25rem .5rem +} + +.datagrid table thead tr th .datagrid-col-filter-range .form-control { + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px +} + +.datagrid table thead tr th:hover .column-settings-menu { + opacity: 1 +} + +.datagrid table tbody td { + vertical-align: middle +} + +.datagrid table tbody tr.ui-sortable-helper { + display: table +} + +.datagrid table tbody tr.row-item-detail { + display: none +} + +.datagrid table tbody tr.row-item-detail.toggled { + display: table-row +} + +.datagrid table tbody tr.row-item-detail .item-detail-content { + display: none +} + +.datagrid table tbody tr.row-item-detail-helper { + display: none +} + +.datagrid table tbody tr .datagrid-inline-edit .form-control { + margin: -3px; + padding-bottom: 4px; + padding-top: 4px; + height: 28px +} + +.datagrid table tbody tr td[data-datagrid-editable-url].editing textarea { + padding: 2px; + margin: -3px +} + +.datagrid table tbody tr td.edited { + animation-name: edited; + animation-duration: 1.2s; + animation-delay: 0 +} + +.datagrid table tbody tr td.edited-error { + animation-name: edited-error; + animation-duration: 1.6s; + animation-delay: 0 +} + +.datagrid table th.col-checkbox, .datagrid table td.col-checkbox { + padding: 0; + width: 2.1em; + text-align: center; + vertical-align: middle +} + +.datagrid table th.col-checkbox .happy-checkbox, .datagrid table td.col-checkbox .happy-checkbox { + margin-right: 0 +} + +.datagrid table th.col-checkbox.col-checkbox-first, .datagrid table td.col-checkbox.col-checkbox-first { + border-top-color: transparent +} + +.datagrid table th.col-checkbox { + background-color: #f9f9f9 +} + +.datagrid table th.col-action, .datagrid table td.col-action { + white-space: nowrap; + width: 10px +} + +.datagrid table th.col-action { + text-align: center +} + +.datagrid table td.col-action { + text-align: right +} + +.datagrid table th.datagrid-fit-content, .datagrid table td.datagrid-fit-content { + width: 1%; + white-space: nowrap +} + +.datagrid .datagrid-tree > .datagrid-tree-header .datagrid-tree-item-right-actions-action { + opacity: 0 +} + +.datagrid .datagrid-tree > .datagrid-tree-item { + margin-left: 20px +} + +.datagrid .datagrid-tree .datagrid-tree-item { + position: relative +} + +.datagrid .datagrid-tree .datagrid-tree-item.ui-sortable-placeholder { + visibility: visible !important; + background-color: rgba(70, 83, 93, 0.1) +} + +.datagrid .datagrid-tree .datagrid-tree-item .datagrid-tree-item-content { + position: relative; + display: flex; + flex-direction: row; + flex-wrap: nowrap; + justify-content: space-between; + box-sizing: border-box; + height: 37px; + box-shadow: inset 0px -1px 1px -1px #9B9B9B +} + +.datagrid .datagrid-tree .datagrid-tree-item .datagrid-tree-item-content .datagrid-tree-item-left, .datagrid .datagrid-tree .datagrid-tree-item .datagrid-tree-item-content .datagrid-tree-item-right { + display: flex; + flex-direction: row; + flex-wrap: nowrap; + justify-content: space-between; + align-items: center +} + +.datagrid .datagrid-tree .datagrid-tree-item .datagrid-tree-item-content .datagrid-tree-item-left { + order: 1 +} + +.datagrid .datagrid-tree .datagrid-tree-item .datagrid-tree-item-content .datagrid-tree-item-left > .chevron { + -webkit-border-radius: 11px; + -moz-border-radius: 11px; + border-radius: 11px; + width: 22px; + height: 22px; + line-height: 20px; + vertical-align: middle; + background-color: #fff; + display: inline-block; + text-align: center; + position: relative; + margin: 0 5px 0 -27px; + transition: transform 0.2s ease-in-out +} + +.datagrid .datagrid-tree .datagrid-tree-item .datagrid-tree-item-content .datagrid-tree-item-left > .chevron:hover { + -webkit-box-shadow: 0px 0px 3px 0px #b4b4b4; + -moz-box-shadow: 0px 0px 3px 0px #b4b4b4; + box-shadow: 0px 0px 3px 0px #b4b4b4 +} + +.datagrid .datagrid-tree .datagrid-tree-item .datagrid-tree-item-content .datagrid-tree-item-left > .chevron.toggle-rotate { + transform: rotate(90deg) +} + +.datagrid .datagrid-tree .datagrid-tree-item .datagrid-tree-item-content .datagrid-tree-item-left > .chevron .fa { + font-size: 10px; + transform: translate(1px, 0) +} + +.datagrid .datagrid-tree .datagrid-tree-item .datagrid-tree-item-content .datagrid-tree-item-right { + position: relative; + order: 2; + flex-basis: 50%; + display: flex; + flex-wrap: nowrap; + justify-content: flex-end; + flex-direction: row +} + +.datagrid .datagrid-tree .datagrid-tree-item .datagrid-tree-item-content .datagrid-tree-item-right .btn { + margin-top: -3px +} + +.datagrid .datagrid-tree .datagrid-tree-item .datagrid-tree-item-content .datagrid-tree-item-right .datagrid-tree-item-right-columns { + white-space: nowrap; + display: flex; + flex-basis: 70%; + flex-direction: row; + flex-wrap: nowrap; + justify-content: flex-end +} + +.datagrid .datagrid-tree .datagrid-tree-item .datagrid-tree-item-content .datagrid-tree-item-right .datagrid-tree-item-right-columns .datagrid-tree-item-right-columns-column { + padding: 0 7px; + margin-right: 4px; + flex-basis: 25% +} + +.datagrid .datagrid-tree .datagrid-tree-item .datagrid-tree-item-content .datagrid-tree-item-right .datagrid-tree-item-right-columns .datagrid-tree-item-right-columns-column:last-child { + margin-right: 0 +} + +.datagrid .datagrid-tree .datagrid-tree-item .datagrid-tree-item-content .datagrid-tree-item-right .datagrid-tree-item-right-actions { + margin-left: 7px; + display: flex; + flex-direction: row; + flex-wrap: nowrap; + justify-content: space-between; + align-items: center +} + +.datagrid .datagrid-tree .datagrid-tree-item .datagrid-tree-item-content .datagrid-tree-item-right .datagrid-tree-item-right-actions .datagrid-tree-item-right-actions-action { + margin-right: 4px +} + +.datagrid .datagrid-tree .datagrid-tree-item .datagrid-tree-item-content .datagrid-tree-item-right .datagrid-tree-item-right-actions .datagrid-tree-item-right-actions-action:last-child { + margin-right: 0 +} + +.datagrid .datagrid-tree .datagrid-tree-item .datagrid-tree-item-children:not(.datagrid-tree) { + margin-left: 28px +} + +.datagrid .datagrid-tree .datagrid-tree-item:not(.has-children) > .datagrid-tree-item-children { + box-sizing: border-box; + position: relative; + width: calc(100% - 28px); + min-height: 9px; + margin-top: -9px +} + +.datagrid .datagrid-tree .datagrid-tree-item.has-children > .datagrid-tree-item-children { + display: none +} + +.datagrid .datagrid-tree .datagrid-tree-item.has-children > .datagrid-tree-item-children .datagrid-tree-item-right { + flex-basis: calc(50% + 14px) +} + +.datagrid .datagrid-tree-item-children .datagrid-tree-item-right { + flex-basis: calc(50% + 14px) +} + +.datagrid .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-right { + flex-basis: calc(50% + 28px) !important +} + +.datagrid .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-right { + flex-basis: calc(50% + 42px) !important +} + +.datagrid .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-right { + flex-basis: calc(50% + 56px) !important +} + +.datagrid .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-right { + flex-basis: calc(50% + 74px) !important +} + +.datagrid .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-right { + flex-basis: calc(50% + 88px) !important +} + +.datagrid .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-right { + flex-basis: calc(50% + 102px) !important +} + +.datagrid .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-children .datagrid-tree-item-right { + flex-basis: calc(50% + 116px) !important +} + +.datagrid .btn { + transition: all 0.1s ease-in-out; + white-space: nowrap +} + +.datagrid select { + padding: 0; + text-transform: none +} + +.datagrid .row-grid-bottom { + font-size: 0; + padding: 8px; + background-color: #f9f9f9; + border: 1px solid #ddd; + border-top: 0 +} + +.datagrid .row-grid-bottom .col-items { + font-size: 14px; + display: inline-block; + width: 25% +} + +.datagrid .row-grid-bottom .col-pagination { + font-size: 14px; + display: inline-block; + width: 50% +} + +.datagrid .row-grid-bottom .col-per-page { + font-size: 14px; + display: inline-block; + width: 25% +} + +.datagrid .row-grid-bottom .col-per-page form { + display: inline-block +} + +.datagrid .row-grid-bottom .col-per-page .form-control { + width: auto; + display: inline-block +} + +.datagrid .row-grid-bottom .datagrid-per-page-submit { + position: absolute; + visibility: hidden; + width: 0; + top: -200px +} + +.datagrid .pagination.active > span { + color: #fff +} + +.datagrid .pagination > a.disabled { + color: #989898; + cursor: not-allowed +} + +.datagrid .pagination > a.active { + pointer-events: none; + cursor: default +} + +.datagrid .row-group-actions th { + font-weight: normal +} + +.datagrid .col-checkbox { + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none +} + +.datagrid .col-checkbox .happy-checkbox { + margin-top: 2px +} + +.datagrid .datagrid-column-status-option-icon { + float: right +} + +@media (min-width:768px) { + .datagrid .ublaboo-datagrid-th-form-inline .form-group { + display: inline-block; + margin-bottom: 0; + vertical-align: middle + } + + .datagrid .ublaboo-datagrid-th-form-inline .form-control { + display: inline-block; + width: auto; + vertical-align: middle + } + + .datagrid .ublaboo-datagrid-th-form-inline .form-control[hidden] { + display:none; + } + + .ublaboo-datagrid-th-form-inline .form-control[hidden] { + display: none; + } + + .datagrid .ublaboo-datagrid-th-form-inline .input-group { + display: inline-table; + vertical-align: middle + } + + .datagrid .ublaboo-datagrid-th-form-inline .input-group .form-control { + width: auto + } + + .datagrid .ublaboo-datagrid-th-form-inline .input-group > .form-control { + width: 100% + } + + .datagrid .input-group-text { + height: calc(1.5em + 0.5rem + 2px); + } + + .datagrid .ublaboo-datagrid-th-form-inline .control-label { + margin-bottom: 0; + vertical-align: middle + } + + .datagrid .ublaboo-datagrid-th-form-inline .radio, .datagrid .ublaboo-datagrid-th-form-inline .checkbox { + display: inline-block; + margin-top: 0; + margin-bottom: 0; + vertical-align: middle + } + + .datagrid .ublaboo-datagrid-th-form-inline .radio label, .datagrid .ublaboo-datagrid-th-form-inline .checkbox label { + padding-left: 0 + } + + .datagrid .ublaboo-datagrid-th-form-inline .radio input[type="radio"], .datagrid .ublaboo-datagrid-th-form-inline .checkbox input[type="checkbox"] { + position: relative; + margin-left: 0 + } + +} + +.datagrid .btn-xs, .datagrid .btn-group-xs > .btn { + padding: 1px 5px; + font-size: 12px; + line-height: 1.5; + border-radius: 3px +} + +.datagrid .dropdown-item { + padding: 3px 20px; + line-height: 1.42857143; + font-size: 12px; +} diff --git a/assets/js/datagrid/datagrid.js b/assets/js/datagrid/datagrid.js new file mode 100644 index 0000000..83d9f80 --- /dev/null +++ b/assets/js/datagrid/datagrid.js @@ -0,0 +1,928 @@ +var dataGridRegisterExtension, dataGridRegisterAjaxCall, dataGridLoad, dataGridSubmitForm; + +if (typeof naja !== "undefined") { + var isNaja2 = function () { return naja && naja.VERSION && naja.VERSION >= 2 }; + var najaEventParams = function (params) { return isNaja2() ? params.detail : params }; + var najaRequest = function (params) { return isNaja2() ? params.detail.request : params.xhr }; + dataGridRegisterExtension = function (name, extension) { + var init = extension.init; + var success = extension.success; + var before = extension.before; + var complete = extension.complete; + var interaction = extension.interaction; + + + var NewExtension = function NewExtension(naja, name) { + this.name = name; + + this.initialize = function (naja) { + if(init) { + naja.addEventListener('init', function (params) { + init(najaEventParams(params).defaultOptions); + }); + } + + if(success) { + naja.addEventListener('success', function (params) { + var payload = isNaja2() ? params.detail.payload : params.response; + success(payload, najaEventParams(params).options); + }); + } + + var interactionTarget = naja; + if (isNaja2()) { + interactionTarget = interactionTarget.uiHandler; + } + + interactionTarget.addEventListener('interaction', function (params) { + if (isNaja2()) { + params.detail.options.nette = { + el: $(params.detail.element) + } + } else { + params.options.nette = { + el: $(params.element) + } + } + if (interaction) { + if (!interaction(najaEventParams(params).options)){ + params.preventDefault(); + } + } + }); + + if(before) { + naja.addEventListener('before', function (params) { + if (!before(najaRequest(params), najaEventParams(params).options)) + params.preventDefault(); + }); + } + + if(complete) { + naja.addEventListener('complete', function (params) { + complete(najaRequest(params), najaEventParams(params).options); + }); + } + } + if (!isNaja2()) { + this.initialize(naja); + } + return this; + } + + if (isNaja2()) { + naja.registerExtension(new NewExtension(null, name)); + } else { + naja.registerExtension(NewExtension, name); + } + }; + + + dataGridRegisterAjaxCall = function (params) { + var method = params.type || 'GET'; + var data = params.data || null; + + naja.makeRequest(method, params.url, data, {}) + .then(params.success) + .catch(params.error); + }; + + dataGridLoad = function () { + naja.load(); + }; + + dataGridSubmitForm = function (form) { + return naja.uiHandler.submitForm(form.get(0)); + }; +} else if ($.nette) { + dataGridRegisterExtension = function (name, extension) { + $.nette.ext(name, extension); + }; + dataGridRegisterAjaxCall = function (params) { + $.nette.ajax(params); + }; + dataGridLoad = function () { + $.nette.load(); + }; + dataGridSubmitForm = function (form) { + return form.submit(); + }; +} else { + throw new Error("Include Naja.js or nette.ajax for datagrids to work!") +} + + +var datagridFitlerMultiSelect, datagridGroupActionMultiSelect, datagridShiftGroupSelection, datagridSortable, datagridSortableTree, getEventDomPath, + indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; + +$(document).on('click', '[data-datagrid-confirm]:not(.ajax)', function(e) { + if (!confirm($(e.target).closest('a').attr('data-datagrid-confirm'))) { + e.stopPropagation(); + return e.preventDefault(); + } +}); + +if (typeof naja !== "undefined") { + dataGridRegisterExtension('datagrid.confirm', { + interaction: function(settings) { + var confirm_message; + if (settings.nette) { + confirm_message = settings.nette.el.data('datagrid-confirm'); + if (confirm_message) { + return confirm(confirm_message); + } + } + return true; + } + }); +} else { + dataGridRegisterExtension('datagrid.confirm', { + before: function(xhr, settings) { + var confirm_message; + if (settings.nette) { + confirm_message = settings.nette.el.data('datagrid-confirm'); + if (confirm_message) { + return confirm(confirm_message); + } + } + return true; + } + }); +} + + +$(document).on('change', 'select[data-autosubmit-per-page]', function() { + var button; + button = $(this).parent().find('input[type=submit]'); + if (button.length === 0) { + button = $(this).parent().find('button[type=submit]'); + } + return button.click(); +}).on('change', 'select[data-autosubmit]', function() { + return dataGridSubmitForm($(this).closest('form').first()); +}).on('change', 'input[data-autosubmit][data-autosubmit-change]', function(e) { + var $this, code; + code = e.which || e.keyCode || 0; + clearTimeout(window.datagrid_autosubmit_timer); + $this = $(this); + return window.datagrid_autosubmit_timer = setTimeout((function(_this) { + return function() { + return dataGridSubmitForm($this.closest('form').first()); + }; + })(this), 200); +}).on('keyup', 'input[data-autosubmit]', function(e) { + var $this, code; + code = e.which || e.keyCode || 0; + if ((code !== 13) && ((code >= 9 && code <= 40) || (code >= 112 && code <= 123))) { + return; + } + clearTimeout(window.datagrid_autosubmit_timer); + $this = $(this); + return window.datagrid_autosubmit_timer = setTimeout((function(_this) { + return function() { + return dataGridSubmitForm($this.closest('form').first()); + }; + })(this), 200); +}).on('keydown', '.datagrid-inline-edit input', function(e) { + var code; + code = e.which || e.keyCode || 0; + if (code === 13) { + e.stopPropagation(); + e.preventDefault(); + return $(this).closest('tr').find('.col-action-inline-edit [name="inline_edit[submit]"]').click(); + } +}); + +$(document).on('keydown', 'input[data-datagrid-manualsubmit]', function(e) { + var code; + code = e.which || e.keyCode || 0; + if (code === 13) { + e.stopPropagation(); + e.preventDefault(); + return dataGridSubmitForm($(this).closest('form').first()); + } +}); + +getEventDomPath = function(e) { + var node, path; + if (indexOf.call(e, path) >= 0) { + return e.path; + } + path = []; + node = e.target; + while (node !== document.body) { + if (node === null) { + break; + } + path.push(node); + node = node.parentNode; + } + return path; +}; + +datagridShiftGroupSelection = function() { + var last_checkbox; + last_checkbox = null; + return document.addEventListener('click', function(e) { + var checkboxes_rows, current_checkbox_row, el, event, i, ie, input, j, k, last_checkbox_row, last_checkbox_tbody, len, len1, len2, ref, ref1, results, row, rows; + ref = getEventDomPath(e); + for (i = 0, len = ref.length; i < len; i++) { + el = ref[i]; + if ($(el).is('.col-checkbox') && last_checkbox && e.shiftKey) { + current_checkbox_row = $(el).closest('tr'); + last_checkbox_row = last_checkbox.closest('tr'); + last_checkbox_tbody = last_checkbox_row.closest('tbody'); + checkboxes_rows = last_checkbox_tbody.find('tr').toArray(); + if (current_checkbox_row.index() > last_checkbox_row.index()) { + rows = checkboxes_rows.slice(last_checkbox_row.index(), current_checkbox_row.index()); + } else if (current_checkbox_row.index() < last_checkbox_row.index()) { + rows = checkboxes_rows.slice(current_checkbox_row.index() + 1, last_checkbox_row.index()); + } + if (!rows) { + return; + } + for (j = 0, len1 = rows.length; j < len1; j++) { + row = rows[j]; + input = $(row).find('.col-checkbox input[type=checkbox]')[0]; + if (input) { + input.checked = true; + ie = window.navigator.userAgent.indexOf("MSIE "); + if (ie) { + event = document.createEvent('Event'); + event.initEvent('change', true, true); + } else { + event = new Event('change', { + 'bubbles': true + }); + } + input.dispatchEvent(event); + } + } + } + } + ref1 = getEventDomPath(e); + results = []; + for (k = 0, len2 = ref1.length; k < len2; k++) { + el = ref1[k]; + if ($(el).is('.col-checkbox')) { + results.push(last_checkbox = $(el)); + } else { + results.push(void 0); + } + } + return results; + }); +}; + +datagridShiftGroupSelection(); + +document.addEventListener('change', function(e) { + var buttons, checked_inputs, counter, event, grid, i, ie, input, inputs, len, results, select, total; + grid = e.target.getAttribute('data-check'); + if (grid) { + checked_inputs = document.querySelectorAll('input[data-check-all-' + grid + ']:checked'); + select = document.querySelector('.datagrid-' + grid + ' select[name="group_action[group_action]"]'); + buttons = document.querySelectorAll('.datagrid-' + grid + ' .row-group-actions *[type="submit"]'); + counter = document.querySelector('.datagrid-' + grid + ' .datagrid-selected-rows-count'); + + if (checked_inputs.length) { + if (buttons) { + buttons.forEach(function (button) { + button.disabled = false; + }); + } + if (select) { + select.disabled = false; + } + total = document.querySelectorAll('input[data-check-all-' + grid + ']').length; + if (counter) { + counter.innerHTML = checked_inputs.length + '/' + total; + } + } else { + if (buttons) { + buttons.forEach(function (button) { + button.disabled = true; + }); + } + if (select) { + select.disabled = true; + select.value = ""; + } + if (counter) { + counter.innerHTML = ""; + } + } + ie = window.navigator.userAgent.indexOf("MSIE "); + if (ie) { + event = document.createEvent('Event'); + event.initEvent('change', true, true); + } else { + event = new Event('change', { + 'bubbles': true + }); + } + if (select) { + select.dispatchEvent(event); + } + } + grid = e.target.getAttribute('data-check-all'); + if (grid) { + inputs = document.querySelectorAll('input[type=checkbox][data-check-all-' + grid + ']'); + results = []; + for (i = 0, len = inputs.length; i < len; i++) { + input = inputs[i]; + input.checked = e.target.checked; + ie = window.navigator.userAgent.indexOf("MSIE "); + if (ie) { + event = document.createEvent('Event'); + event.initEvent('change', true, true); + } else { + event = new Event('change', { + 'bubbles': true + }); + } + results.push(input.dispatchEvent(event)); + } + return results; + } +}); + + +window.datagridSerializeUrl = function(obj, prefix) { +var str = []; +for(var p in obj) { + if (obj.hasOwnProperty(p)) { + var k = prefix ? prefix + "[" + p + "]" : p, v = obj[p]; + if (v !== null && v !== "") { + if (typeof v == "object") { + var r = window.datagridSerializeUrl(v, k); + if (r) { + str.push(r); + } + } else { + str.push(encodeURIComponent(k) + "=" + encodeURIComponent(v)); + } + } + } +} +return str.join("&"); +} +; + +datagridSortable = function() { + if (typeof $.fn.sortable === 'undefined') { + return; + } + return $('.datagrid [data-sortable]').sortable({ + handle: '.handle-sort', + items: 'tr', + axis: 'y', + update: function(event, ui) { + var component_prefix, data, item_id, next_id, prev_id, row, url; + row = ui.item.closest('tr[data-id]'); + item_id = row.data('id'); + prev_id = null; + next_id = null; + if (row.prev().length) { + prev_id = row.prev().data('id'); + } + if (row.next().length) { + next_id = row.next().data('id'); + } + url = $(this).data('sortable-url'); + data = {}; + component_prefix = row.closest('.datagrid').find('tbody').attr('data-sortable-parent-path'); + data[(component_prefix + '-item_id').replace(/^-/, '')] = item_id; + if (prev_id !== null) { + data[(component_prefix + '-prev_id').replace(/^-/, '')] = prev_id; + } + if (next_id !== null) { + data[(component_prefix + '-next_id').replace(/^-/, '')] = next_id; + } + return dataGridRegisterAjaxCall({ + type: 'GET', + url: url, + data: data, + error: function(jqXHR, textStatus, errorThrown) { + return alert(jqXHR.statusText); + } + }); + }, + helper: function(e, ui) { + ui.children().each(function() { + return $(this).width($(this).width()); + }); + return ui; + } + }); +}; + +$(function() { + return datagridSortable(); +}); + +if (typeof datagridSortableTree === 'undefined') { + datagridSortableTree = function() { + if (typeof $('.datagrid-tree-item-children').sortable === 'undefined') { + return; + } + return $('.datagrid-tree-item-children').sortable({ + handle: '.handle-sort', + items: '.datagrid-tree-item:not(.datagrid-tree-header)', + toleranceElement: '> .datagrid-tree-item-content', + connectWith: '.datagrid-tree-item-children', + update: function(event, ui) { + var component_prefix, data, item_id, next_id, parent, parent_id, prev_id, row, url; + $('.toggle-tree-to-delete').remove(); + row = ui.item.closest('.datagrid-tree-item[data-id]'); + item_id = row.data('id'); + prev_id = null; + next_id = null; + parent_id = null; + if (row.prev().length) { + prev_id = row.prev().data('id'); + } + if (row.next().length) { + next_id = row.next().data('id'); + } + parent = row.parent().closest('.datagrid-tree-item'); + if (parent.length) { + parent.find('.datagrid-tree-item-children').first().css({ + display: 'block' + }); + parent.addClass('has-children'); + parent_id = parent.data('id'); + } + url = $(this).data('sortable-url'); + if (!url) { + return; + } + parent.find('[data-toggle-tree]').first().removeClass('hidden'); + component_prefix = row.closest('.datagrid-tree').attr('data-sortable-parent-path'); + data = {}; + data[(component_prefix + '-item_id').replace(/^-/, '')] = item_id; + if (prev_id !== null) { + data[(component_prefix + '-prev_id').replace(/^-/, '')] = prev_id; + } + if (next_id !== null) { + data[(component_prefix + '-next_id').replace(/^-/, '')] = next_id; + } + data[(component_prefix + '-parent_id').replace(/^-/, '')] = parent_id; + return dataGridRegisterAjaxCall({ + type: 'GET', + url: url, + data: data, + error: function(jqXHR, textStatus, errorThrown) { + if (errorThrown !== 'abort') { + return alert(jqXHR.statusText); + } + } + }); + }, + stop: function(event, ui) { + return $('.toggle-tree-to-delete').removeClass('toggle-tree-to-delete'); + }, + start: function(event, ui) { + var parent; + parent = ui.item.parent().closest('.datagrid-tree-item'); + if (parent.length) { + if (parent.find('.datagrid-tree-item').length === 2) { + return parent.find('[data-toggle-tree]').addClass('toggle-tree-to-delete'); + } + } + } + }); + }; +} + +$(function() { + return datagridSortableTree(); +}); + +dataGridRegisterExtension('datagrid.happy', { + success: function() { + var c, checked_rows, class_selector, classes, event, grid, grids, i, ie, input, j, len, len1, results; + if (window.happy) { + window.happy.reset(); + } + grids = $('.datagrid'); + results = []; + for (i = 0, len = grids.length; i < len; i++) { + grid = grids[i]; + classes = grid.classList; + class_selector = ''; + for (j = 0, len1 = classes.length; j < len1; j++) { + c = classes[j]; + class_selector = class_selector + '.' + c; + } + checked_rows = document.querySelectorAll(class_selector + ' ' + 'input[data-check]:checked'); + if (checked_rows.length === 1 && checked_rows[0].getAttribute('name') === 'toggle-all') { + input = document.querySelector(class_selector + ' input[name=toggle-all]'); + if (input) { + input.checked = false; + ie = window.navigator.userAgent.indexOf("MSIE "); + if (ie) { + event = document.createEvent('Event'); + event.initEvent('change', true, true); + } else { + event = new Event('change', { + 'bubbles': true + }); + } + results.push(input.dispatchEvent(event)); + } else { + results.push(void 0); + } + } else { + results.push(void 0); + } + } + return results; + } +}); + +dataGridRegisterExtension('datagrid.sortable', { + success: function() { + return datagridSortable(); + } +}); + +dataGridRegisterExtension('datagrid.forms', { + success: function() { + return $('.datagrid').find('form').each(function() { + return window.Nette.initForm(this); + }); + } +}); + +dataGridRegisterExtension('datagrid.url', { + success: function(payload) { + var host, path, query, url; + if (payload._datagrid_url) { + if (window.history.replaceState) { + host = window.location.protocol + "//" + window.location.host; + path = window.location.pathname; + query = window.datagridSerializeUrl(payload.state).replace(/&+$/gm, ''); + if (query) { + url = host + path + "?" + query.replace(/\&*$/, ''); + } else { + url = host + path; + } + url += window.location.hash; + if (window.location.href !== url) { + return window.history.replaceState({ + path: url + }, '', url); + } + } + } + } +}); + +dataGridRegisterExtension('datagrid.sort', { + success: function(payload) { + var href, key, ref, results; + if (payload._datagrid_sort) { + ref = payload._datagrid_sort; + results = []; + for (key in ref) { + href = ref[key]; + results.push($('#datagrid-sort-' + key).attr('href', href)); + } + return results; + } + } +}); + +dataGridRegisterExtension('datargid.item_detail', { + before: function(xhr, settings) { + var id, row_detail, grid_fullname; + if (settings.nette && settings.nette.el.attr('data-toggle-detail')) { + id = settings.nette.el.attr('data-toggle-detail'); + grid_fullname = settings.nette.el.attr('data-toggle-detail-grid-fullname'); + row_detail = $('.item-detail-' + grid_fullname + '-id-' + id); + if (row_detail.hasClass('loaded')) { + if (!row_detail.find('.item-detail-content').length) { + row_detail.removeClass('toggled'); + return true; + } + if (row_detail.hasClass('toggled')) { + row_detail.find('.item-detail-content').slideToggle('fast', (function(_this) { + return function() { + return row_detail.toggleClass('toggled'); + }; + })(this)); + } else { + row_detail.toggleClass('toggled'); + row_detail.find('.item-detail-content').slideToggle('fast'); + } + return false; + } else { + return row_detail.addClass('loaded'); + } + } + return true; + }, + success: function(payload) { + var id, row_detail, grid_fullname; + if (payload._datagrid_toggle_detail && payload._datagrid_name) { + id = payload._datagrid_toggle_detail; + grid_fullname = payload._datagrid_name; + row_detail = $('.item-detail-' + grid_fullname + '-id-' + id); + row_detail.toggleClass('toggled'); + return row_detail.find('.item-detail-content').slideToggle('fast'); + } + } +}); + +dataGridRegisterExtension('datagrid.tree', { + before: function(xhr, settings) { + var children_block; + if (settings.nette && settings.nette.el.attr('data-toggle-tree')) { + settings.nette.el.toggleClass('toggle-rotate'); + children_block = settings.nette.el.closest('.datagrid-tree-item').find('.datagrid-tree-item-children').first(); + if (children_block.hasClass('loaded')) { + children_block.slideToggle('fast'); + return false; + } + } + return true; + }, + success: function(payload) { + var children_block, content, id, name, ref, snippet, template; + if (payload._datagrid_tree) { + id = payload._datagrid_tree; + children_block = $('.datagrid-tree-item[data-id="' + id + '"]').find('.datagrid-tree-item-children').first(); + children_block.addClass('loaded'); + ref = payload.snippets; + for (name in ref) { + snippet = ref[name]; + content = $(snippet); + template = $('
'); + template.attr('data-id', content.attr('data-id')); + template.append(content); + if (content.data('has-children')) { + template.addClass('has-children'); + } + children_block.append(template); + } + children_block.addClass('loaded'); + children_block.slideToggle('fast'); + dataGridLoad(); + } + return datagridSortableTree(); + } +}); + +$(document).on('click', '[data-datagrid-editable-url]', function(event) { + var attr_name, attr_value, attrs, cell, cellValue, cell_height, cell_lines, cell_padding, input, line_height, submit, valueToEdit; + cell = $(this); + if (event.target.tagName.toLowerCase() === 'a') { + return; + } + if (cell.hasClass('datagrid-inline-edit')) { + return; + } + if (!cell.hasClass('editing')) { + cell.addClass('editing'); + cellValue = cell.html().trim().replace('
', '\n'); + if (cell.attr('data-datagrid-editable-value')) { + valueToEdit = String(cell.data('datagrid-editable-value')); + } else { + valueToEdit = cellValue; + } + cell.data('originalValue', cellValue); + cell.data('valueToEdit', valueToEdit); + if (cell.data('datagrid-editable-type') === 'textarea') { + input = $(''); + cell_padding = parseInt(cell.css('padding').replace(/[^-\d\.]/g, ''), 10); + cell_height = cell.outerHeight(); + line_height = Math.round(parseFloat(cell.css('line-height'))); + cell_lines = (cell_height - (2 * cell_padding)) / line_height; + input.attr('rows', Math.round(cell_lines)); + } else if (cell.data('datagrid-editable-type') === 'select') { + input = $(cell.data('datagrid-editable-element')); + input.find("option[value='" + valueToEdit + "']").prop('selected', true); + } else { + input = $(''); + input.val(valueToEdit); + } + attrs = cell.data('datagrid-editable-attrs'); + for (attr_name in attrs) { + attr_value = attrs[attr_name]; + input.attr(attr_name, attr_value); + } + cell.removeClass('edited'); + cell.html(input); + submit = function(cell, el) { + var value; + value = el.val(); + if (value !== cell.data('valueToEdit')) { + dataGridRegisterAjaxCall({ + url: cell.data('datagrid-editable-url'), + data: { + value: value + }, + type: 'POST', + success: function(payload) { + if (cell.data('datagrid-editable-type') === 'select') { + cell.html(input.find("option[value='" + value + "']").html()); + } else { + if (payload._datagrid_editable_new_value) { + value = payload._datagrid_editable_new_value; + } + cell.html(value); + } + return cell.addClass('edited'); + }, + error: function() { + cell.html(cell.data('originalValue')); + return cell.addClass('edited-error'); + } + }); + } else { + cell.html(cell.data('originalValue')); + } + return setTimeout(function() { + return cell.removeClass('editing'); + }, 1200); + }; + cell.find('input,textarea,select').focus().on('blur', function() { + return submit(cell, $(this)); + }).on('keydown', function(e) { + if (cell.data('datagrid-editable-type') !== 'textarea') { + if (e.which === 13) { + e.stopPropagation(); + e.preventDefault(); + return submit(cell, $(this)); + } + } + if (e.which === 27) { + e.stopPropagation(); + e.preventDefault(); + cell.removeClass('editing'); + return cell.html(cell.data('originalValue')); + } + }); + return cell.find('select').on('change', function() { + return submit(cell, $(this)); + }); + } +}); + +dataGridRegisterExtension('datagrid.after_inline_edit', { + success: function(payload) { + var grid = $('.datagrid-' + payload._datagrid_name); + + if (payload._datagrid_inline_edited) { + grid.find('tr[data-id="' + payload._datagrid_inline_edited + '"] > td').addClass('edited'); + return grid.find('.datagrid-inline-edit-trigger').removeClass('hidden'); + } else if (payload._datagrid_inline_edit_cancel) { + return grid.find('.datagrid-inline-edit-trigger').removeClass('hidden'); + } + } +}); + +$(document).on('mouseup', '[data-datagrid-cancel-inline-add]', function(e) { + var code = e.which || e.keyCode || 0; + if (code === 1) { + e.stopPropagation(); + e.preventDefault(); + return $('.datagrid-row-inline-add').addClass('datagrid-row-inline-add-hidden'); + } +}); + +dataGridRegisterExtension('datagrid-toggle-inline-add', { + success: function(payload) { + var grid = $('.datagrid-' + payload._datagrid_name); + + if (payload._datagrid_inline_adding) { + var row = grid.find('.datagrid-row-inline-add'); + + if (row.hasClass('datagrid-row-inline-add-hidden')) { + row.removeClass('datagrid-row-inline-add-hidden'); + } + + row.find('input:not([readonly]),textarea:not([readonly])').first().focus(); + } + } +}); + +datagridFitlerMultiSelect = function() { + var select = $('.selectpicker').first(); + + if ($.fn.selectpicker) { + return $.fn.selectpicker.defaults = { + countSelectedText: select.data('i18n-selected'), + iconBase: '', + tickIcon: select.data('selected-icon-check') + }; + } +}; + +$(function() { + return datagridFitlerMultiSelect(); +}); + +datagridGroupActionMultiSelect = function() { + var selects; + + if (!$.fn.selectpicker) { + return; + } + + selects = $('[data-datagrid-multiselect-id]'); + + return selects.each(function() { + var id; + if ($(this).hasClass('selectpicker')) { + $(this).removeAttr('id'); + id = $(this).data('datagrid-multiselect-id'); + $(this).on('loaded.bs.select', function(e) { + $(this).parent().attr('style', 'display:none;'); + return $(this).parent().find('.hidden').removeClass('hidden').addClass('btn-default btn-secondary'); + }); + return $(this).on('rendered.bs.select', function(e) { + return $(this).parent().attr('id', id); + }); + } + }); +}; + +$(function() { + return datagridGroupActionMultiSelect(); +}); + +dataGridRegisterExtension('datagrid.fitlerMultiSelect', { + success: function() { + datagridFitlerMultiSelect(); + if ($.fn.selectpicker) { + return $('.selectpicker').selectpicker({ + iconBase: 'fa' + }); + } + } +}); + +dataGridRegisterExtension('datagrid.groupActionMultiSelect', { + success: function() { + return datagridGroupActionMultiSelect(); + } +}); + +dataGridRegisterExtension('datagrid.inline-editing', { + success: function(payload) { + var grid; + if (payload._datagrid_inline_editing) { + grid = $('.datagrid-' + payload._datagrid_name); + return grid.find('.datagrid-inline-edit-trigger').addClass('hidden'); + } + } +}); + +dataGridRegisterExtension('datagrid.redraw-item', { + success: function(payload) { + var row; + if (payload._datagrid_redraw_item_class) { + row = $('tr[data-id="' + payload._datagrid_redraw_item_id + '"]'); + return row.attr('class', payload._datagrid_redraw_item_class); + } + } +}); + +dataGridRegisterExtension('datagrid.reset-filter-by-column', { + success: function(payload) { + var grid, href, i, key, len, ref; + if (!payload._datagrid_name) { + return; + } + grid = $('.datagrid-' + payload._datagrid_name); + grid.find('[data-datagrid-reset-filter-by-column]').addClass('hidden'); + if (payload.non_empty_filters && payload.non_empty_filters.length) { + ref = payload.non_empty_filters; + for (i = 0, len = ref.length; i < len; i++) { + key = ref[i]; + grid.find('[data-datagrid-reset-filter-by-column="' + key + '"]').removeClass('hidden'); + } + href = grid.find('.reset-filter').attr('href'); + return grid.find('[data-datagrid-reset-filter-by-column]').each(function() { + var new_href; + key = $(this).attr('data-datagrid-reset-filter-by-column'); + new_href = href.replace('do=' + payload._datagrid_name + '-resetFilter', 'do=' + payload._datagrid_name + '-resetColumnFilter'); + new_href += '&' + payload._datagrid_name + '-key=' + key; + return $(this).attr('href', new_href); + }); + } + } +}); + +// Expose datagrid helpers as globals for ublaboo's inline scripts. Under webpack these +// top-level `var`s were implicit globals; ESM modules are scoped, so expose explicitly. +window.datagridFitlerMultiSelect = datagridFitlerMultiSelect; +window.datagridGroupActionMultiSelect = datagridGroupActionMultiSelect; +window.datagridShiftGroupSelection = datagridShiftGroupSelection; +window.datagridSortableTree = datagridSortableTree; +window.getEventDomPath = getEventDomPath; +if (typeof datagridSortable !== 'undefined') { + window.datagridSortable = datagridSortable; +} diff --git a/assets/js/flashes.js b/assets/js/flashes.js new file mode 100644 index 0000000..263ee0e --- /dev/null +++ b/assets/js/flashes.js @@ -0,0 +1,30 @@ +import $ from 'jquery'; + +const scheduleAutoClose = (root) => { + $(root).find('.alert[data-close-duration]').each(function () { + const $alert = $(this); + if ($alert.data('auto-close-scheduled')) { + return; + } + const duration = parseInt($alert.attr('data-close-duration'), 10); + if (!duration) { + return; + } + $alert.data('auto-close-scheduled', true); + setTimeout(() => $alert.fadeOut(200, () => $alert.remove()), duration); + }); +}; + +$(document).on('click', '.alert .alert-close-btn', function () { + $(this).closest('.alert').remove(); +}); + +$(document).ready(() => scheduleAutoClose(document)); + +if (window.$ && window.$.nette) { + $.nette.ext('flashes', { + success: function () { + scheduleAutoClose(document); + } + }); +} diff --git a/assets/js/history.ajax.js b/assets/js/history.ajax.js index f16ffb7..03eab95 100644 --- a/assets/js/history.ajax.js +++ b/assets/js/history.ajax.js @@ -168,3 +168,44 @@ }); })(jQuery); + +(function ($, undefined) { + + var getScrollContainer = function () { + var $container = $('[data-app-container]'); + return $container.length ? $container.get(0) : (document.scrollingElement || document.documentElement); + }; + + var pendingScroll = null; + var inFlight = 0; + + $.nette.ext('scrollRestore', { + before: function (xhr, settings) { + if (settings.nette && settings.nette.form) { + var container = getScrollContainer(); + pendingScroll = { + top: container.scrollTop, + left: container.scrollLeft + }; + } + }, + start: function () { + inFlight++; + }, + complete: function () { + inFlight = Math.max(0, inFlight - 1); + if (inFlight === 0 && pendingScroll !== null) { + var scroll = pendingScroll; + pendingScroll = null; + var restore = function () { + var container = getScrollContainer(); + container.scrollTop = scroll.top; + container.scrollLeft = scroll.left; + }; + restore(); + window.requestAnimationFrame(restore); + } + } + }); + +})(jQuery); diff --git a/assets/js/keycloak.js b/assets/js/keycloak.js new file mode 100644 index 0000000..caec52f --- /dev/null +++ b/assets/js/keycloak.js @@ -0,0 +1,63 @@ +/** + * Keycloak session management pro přihlášené uživatele. + * + * - Inicializuje keycloak-js adapter s check-sso + * - Periodicky refreshuje token (každých 30s) + * - Při ztrátě session (expirovaný token, odhlášení z KC) odhlásí uživatele z aplikace + * + * Nastavení se čtou z window.__keycloakSettings (injektováno v @layout.latte). + * Vyžaduje npm balíček `keycloak-js` v projektu. + */ +export async function keycloakLoginSync() { + const settings = window.__keycloakSettings; + + if (!settings) { + return; + } + + delete window.__keycloakSettings; + + const TOKEN_REFRESH_INTERVAL = 30; + const TOKEN_MIN_VALIDITY = 60; + + try { + const { default: Keycloak } = await import('keycloak-js'); + + const keycloak = new Keycloak({ + url: settings.url, + realm: settings.realm, + clientId: settings.clientId + }); + + keycloak.onTokenExpired = () => { + keycloak.updateToken(TOKEN_MIN_VALIDITY).catch(() => { + window.location.href = settings.logoutUrl || '/sign/out'; + }); + }; + + keycloak.onAuthLogout = () => { + window.location.href = settings.logoutUrl || '/sign/out'; + }; + + const authenticated = await keycloak.init({ + onLoad: 'check-sso', + silentCheckSsoRedirectUri: settings.silentCheckSsoUrl, + responseMode: 'query', + checkLoginIframe: true, + checkLoginIframeInterval: 30, + }); + + if (!authenticated) { + return; + } + + setInterval(() => { + keycloak.updateToken(TOKEN_MIN_VALIDITY).catch(() => { + window.location.href = settings.logoutUrl || '/sign/out'; + }); + }, TOKEN_REFRESH_INTERVAL * 1000); + + } catch (error) { + console.error('Failed to initialize Keycloak adapter:', error); + } +} diff --git a/assets/js/sidePanel.js b/assets/js/sidePanel.js new file mode 100644 index 0000000..db30434 --- /dev/null +++ b/assets/js/sidePanel.js @@ -0,0 +1,38 @@ +$(function () { + let isDirty = false; + + function closeSidePanel() { + $('#snippet--sidePanel').html(''); + isDirty = false; + } + + function tryClose() { + const confirmMessage = $('#snippet--sidePanel .side-panel-config').data('close-confirm') || 'Close without saving?'; + if (isDirty && !confirm(confirmMessage)) return; + closeSidePanel(); + } + + // Po AJAX odpovědi: reset dirty jen při úspěšném save + // payload.hasErrors = true nastavuje BootstrapFormRenderer při validační chybě + $.nette.ext('sidePanelDirty', { + success: function (payload) { + if (payload.hasErrors) return; // validace selhala → dirty zůstane + if (payload.snippets && ('snippet--sidePanel' in payload.snippets)) { + isDirty = false; // save OK nebo panel se otevřel → čisté + } + } + }); + + // Změna hodnoty v inputu → dirty + $(document).on('change input', '#snippet--sidePanel form :input', () => { + isDirty = true; + }); + + // Přidání / odebrání řádku replikátorem → dirty + $(document).on('click', '#snippet--sidePanel [data-adt-replicator-add], #snippet--sidePanel [data-adt-replicator-remove]', () => { + isDirty = true; + }); + + $(document).on('click', '.side-panel-template-backdrop', tryClose); + $(document).on('click', '.side-panel-template-container .btn-close', tryClose); +}); \ No newline at end of file diff --git a/assets/js/signInKeycloak.js b/assets/js/signInKeycloak.js new file mode 100644 index 0000000..62c981f --- /dev/null +++ b/assets/js/signInKeycloak.js @@ -0,0 +1,81 @@ +/** + * SignInForm — Keycloak email check. + * + * Po opuštění emailového pole ověří, zda email existuje v Keycloaku. + * Pokud ano, přesměruje na Keycloak login stránku s předvyplněným emailem. + * Pokud ne, nechá formulář normálně fungovat pro password login. + * + * Aktivuje se pro každý email input s atributem `data-keycloak-check-url`. + * + * Listener je navázaný delegovaně na `document`, takže funguje i pro formulář + * vložený přes AJAX (naja snippet), aniž by se musel znovu inicializovat. + */ +const EMAIL_INPUT_ID = 'login-form-input-email'; +const PASSWORD_INPUT_ID = 'login-form-input-password'; + +let bound = false; + +async function handleEmailChange(event) { + const emailInput = event.target; + + if (!(emailInput instanceof HTMLElement) || emailInput.id !== EMAIL_INPUT_ID) { + return; + } + + const checkUrl = emailInput.getAttribute('data-keycloak-check-url'); + if (!checkUrl) { + return; + } + + const email = emailInput.value.trim(); + if (!email || emailInput.dataset.keycloakChecking === '1') { + return; + } + + const form = emailInput.closest('form'); + const passwordInput = document.getElementById(PASSWORD_INPUT_ID); + const submitButton = form ? form.querySelector('[type="submit"]') : null; + + // Disable form while checking + emailInput.dataset.keycloakChecking = '1'; + emailInput.readOnly = true; + if (passwordInput) passwordInput.readOnly = true; + if (submitButton) submitButton.disabled = true; + + try { + const url = checkUrl.replace('__EMAIL__', encodeURIComponent(email)); + const response = await fetch(url); + const data = await response.json(); + + if (data.loginUrl) { + // User exists in Keycloak → redirect to KC login + window.location.href = data.loginUrl; + return; + } + } catch (e) { + // Fetch failed, fall through to normal login + } + + // Re-enable form for normal password login + emailInput.readOnly = false; + if (passwordInput) { + passwordInput.readOnly = false; + passwordInput.focus(); + } + if (submitButton) submitButton.disabled = false; + emailInput.dataset.keycloakChecking = ''; +} + +const run = () => { + if (bound) { + return; + } + bound = true; + document.addEventListener('change', handleEmailChange); +}; + +// Naváže listener hned při importu modulu, aby fungoval i bez explicitního volání run() +// (např. když je formulář na stránce vložen až AJAXem po prvotním načtení). +run(); + +export default { run }; diff --git a/assets/js/summernote.js b/assets/js/summernote.js index d4a5238..fd5c2ae 100644 --- a/assets/js/summernote.js +++ b/assets/js/summernote.js @@ -3,14 +3,94 @@ import 'summernote/dist/summernote-bs5'; import 'summernote/dist/lang/summernote-cs-CZ'; import '@emericklaw/summernote-cleaner' +import 'codemirror/lib/codemirror.css'; +import CodeMirror from 'codemirror/lib/codemirror'; +import 'codemirror/mode/xml/xml'; +import 'codemirror/mode/htmlmixed/htmlmixed'; +window.CodeMirror = CodeMirror; + +// HTML tagy bez obsahu (nezvyšují úroveň zanoření). +const CODEVIEW_VOID_TAGS = new Set([ + 'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', + 'link', 'meta', 'param', 'source', 'track', 'wbr', +]); + +function codeviewTokenType(token) { + if (token[0] !== '<') return 'text'; + if (token.startsWith('\s*$/.test(token)) return 'void'; // self-closing tag + const name = token.match(/^<\s*([a-zA-Z0-9:-]+)/); + if (name && CODEVIEW_VOID_TAGS.has(name[1].toLowerCase())) return 'void'; + return 'open'; +} + +/** + * Zformátuje HTML pro čitelné zobrazení v codeview – každý tag na vlastní řádek + * a s odsazením podle zanoření (včetně inline tagů jako , , ...). + * + * Zalomení (\n + odsazení) se vkládá VÝHRADNĚ mezi dva sousedící tagy (`><`). + * Nikdy nezasahuje mezi tag a text ani tam, kde už mezi tagy je mezera – + * díky tomu je deformatHtmlFromCodeview() přesnou inverzí a obsah se nemění. + */ +function formatHtmlForCodeview(html, unit = ' ') { + const tokens = html.match(/|<[^>]+>|[^<]+/g) || []; + let depth = 0; + let out = ''; + + for (const token of tokens) { + const type = codeviewTokenType(token); + + if (type === 'text') { + out += token; + continue; + } + + if (type === 'close') { + depth = Math.max(0, depth - 1); + } + + // Zalomit jen pokud výstup končí tagem (tj. dva sousedící tagy `><`). + if (/>$/.test(out)) { + out += '\n' + unit.repeat(depth); + } + + out += token; + + if (type === 'open') { + depth += 1; + } + } + + return out; +} + +/** + * Přesná inverze formatHtmlForCodeview() – odstraní zalomení a odsazení vložené + * mezi tagy, takže uložené HTML zůstává kompaktní a beze změny obsahu. + */ +function deformatHtmlFromCodeview(html) { + return html.replace(/>\n[ \t]*<'); +} + $.nette.ext('live').after(function (el) { $(el).find('.summernote').each((i, el) => { $(el).summernote({ + dialogsInBody: true, height: null, minHeight: 200, maxHeight: null, linkTargetBlank: false, lang: 'cs-CZ', + // prettifyHtml musí zůstat vypnuté – formátování i jeho zrušení + // si plně řídíme sami (viz formatHtmlForCodeview / deformatHtmlFromCodeview). + prettifyHtml: false, + codemirror: { + mode: 'text/html', + htmlMode: true, + lineNumbers: true, + theme: 'default', + }, callbacks: { onInit: function () { $(this).next().find('.note-editable').addClass('portal-collapse-detail-content'); @@ -18,6 +98,23 @@ $.nette.ext('live').after(function (el) { onFileUpload: function (file) { myOwnCallBack(file[0], el); }, + onCodeviewToggled: function () { + const $note = $(this); + const $editor = $note.next(); + + if ($editor.hasClass('codeview')) { + // Otevření codeview – zformátujeme zdroj pro čitelnost. + const cmElement = $editor.find('.CodeMirror')[0]; + if (cmElement && cmElement.CodeMirror) { + const cm = cmElement.CodeMirror; + cm.setValue(formatHtmlForCodeview(cm.getValue())); + cm.refresh(); + } + } else { + // Zavření codeview – vrátíme kompaktní HTML, aby se do obsahu nedostalo odsazení vložené jen kvůli zobrazení. + $note.summernote('code', deformatHtmlFromCodeview($note.summernote('code'))); + } + }, }, styleTags: [ 'p', @@ -64,7 +161,7 @@ $.nette.ext('live').after(function (el) { keepHtml: true, keepTagContents: ['span'], //Remove tags and keep the contents badTags: ['applet', 'col', 'colgroup', 'embed', 'noframes', 'noscript', 'script', 'style', 'title', 'meta', 'link', 'head'], //Remove full tags with contents - badAttributes: ['bgcolor', 'height', 'lang', 'start', 'valign', 'data-(.*?)', 'class'], //Remove attributes from remaining tags + badAttributes: ['bgcolor', 'border', 'cellpadding', 'cellspacing', 'height', 'lang', 'start', 'style', 'valign', 'width', 'data-(.*?)', 'class'], //Remove attributes from remaining tags limitChars: 0, // 0|# 0 disables option limitDisplay: 'both', // none|text|html|both limitStop: false, // true/false diff --git a/assets/scss/_datagrid.scss b/assets/scss/_datagrid.scss index 0f47865..cf6a082 100644 --- a/assets/scss/_datagrid.scss +++ b/assets/scss/_datagrid.scss @@ -85,7 +85,7 @@ position: initial; } - > div { + > div:not(.item-detail-content) { width: 300px; max-width: min(30vw, 300px); white-space: normal; @@ -247,7 +247,7 @@ z-index: 99; } - tr:hover { + tr:not(.row-item-detail):hover { td { background-color: $background-dark; } @@ -407,4 +407,20 @@ form:has(> .table-responsive-wrapper) { display: inline-flex; justify-content: center; align-items: center; +} + +.datagrid table tbody tr.row-item-detail { + display: none +} + +.datagrid table tbody tr.row-item-detail.toggled { + display: table-row +} + +.datagrid table tbody tr.row-item-detail .item-detail-content { + display: none +} + +.datagrid table tbody tr:has(+ tr.row-item-detail) { + cursor: pointer; } \ No newline at end of file diff --git a/assets/scss/_fontawesome.scss b/assets/scss/_fontawesome.scss index b08e7b7..0cf975b 100644 --- a/assets/scss/_fontawesome.scss +++ b/assets/scss/_fontawesome.scss @@ -1,5 +1,5 @@ -$fa-font-path: '~@fortawesome/fontawesome-pro/webfonts'; - -@import '~@fortawesome/fontawesome-pro/scss/fontawesome'; -@import '~@fortawesome/fontawesome-pro/scss/solid'; -@import '~@fortawesome/fontawesome-pro/scss/sharp-solid'; \ No newline at end of file +// FontAwesome's own $fa-font-path default ("../webfonts") is used as-is; the build +// copies the webfonts to that location relative to the emitted CSS. +@import '@fortawesome/fontawesome-pro/scss/fontawesome'; +@import '@fortawesome/fontawesome-pro/scss/solid'; +@import '@fortawesome/fontawesome-pro/scss/sharp-solid'; \ No newline at end of file diff --git a/assets/scss/_fonts.scss b/assets/scss/_fonts.scss index 842f7e8..192b8c0 100644 --- a/assets/scss/_fonts.scss +++ b/assets/scss/_fonts.scss @@ -4,18 +4,18 @@ @font-face { font-family: "Roboto"; - src: url("adt-fancyadmin/assets/fonts/Roboto-Regular.ttf"); + src: url("../fonts/Roboto-Regular.ttf"); font-weight: 400; } @font-face { font-family: "Roboto"; - src: url("adt-fancyadmin/assets/fonts/Roboto-Medium.ttf"); + src: url("../fonts/Roboto-Medium.ttf"); font-weight: 500; } @font-face { font-family: "Roboto"; - src: url("adt-fancyadmin/assets/fonts/Roboto-Black.ttf"); + src: url("../fonts/Roboto-Black.ttf"); font-weight: 900; } diff --git a/assets/scss/_layout.scss b/assets/scss/_layout.scss index 41645fc..ad57920 100644 --- a/assets/scss/_layout.scss +++ b/assets/scss/_layout.scss @@ -220,6 +220,12 @@ body:has(.side-panel-template-container form) { &:has(.side-panel-config[data-size="full-except-menu"]) { --width: calc(100vw - var(--side-panel-width)); } + + .note-editor .note-editable table { + tr, td { + border-width: 1px; + } + } } span.empty { diff --git a/assets/scss/_login.scss b/assets/scss/_login.scss index 892084c..79dabb1 100644 --- a/assets/scss/_login.scss +++ b/assets/scss/_login.scss @@ -51,7 +51,7 @@ justify-content: center; align-items: stretch; gap: 50px; - background-color: rgba($login-background, 0.3); + background-color: $login-background; border-radius: $br-container; padding: 80px 40px; @@ -100,16 +100,16 @@ //box-shadow: 0 calc(10px + 2 * $padding-input + $fs-body) 0 $bg-whitish-30-no-alpha inset; //-webkit-box-shadow: 0 calc(10px + 2 * $padding-input + $fs-body) 0 $bg-whitish-30-no-alpha inset; outline: none; // firefox fix - background-color: rgba($login-background, 0.3); - color: $tertiary-text; - -webkit-text-fill-color: $tertiary-text; + background-color: var(--loginBackgroundInput); + color: var(--loginInputTextColor); + -webkit-text-fill-color: var(--loginInputTextColor); &::placeholder { - color: $tertiary-text; + color: var(--loginInputTextColor); } &:focus { //box-shadow: 0 calc(10px + 2 * $padding-input + $fs-body) 0 $bg-whitish-30-no-alpha inset !important; //-webkit-box-shadow: 0 calc(10px + 2 * $padding-input + $fs-body) 0 $bg-whitish-30-no-alpha inset !important; - background-color: rgba($login-background, 0.4) !important; + background-color: var(--loginBackgroundInputFocus) !important; } //&:autofill, diff --git a/assets/scss/_navbar.scss b/assets/scss/_navbar.scss index fadd210..f9c302c 100644 --- a/assets/scss/_navbar.scss +++ b/assets/scss/_navbar.scss @@ -105,4 +105,37 @@ nav { width: 100%; margin: 0 10px 0 0px; } + + form { + display: flex; + align-items: center; + gap: 15px; + min-width: 100%; + } + + .mb-3 { + margin-bottom: 0 !important; + } + + .select2-selection .select2-selection__rendered { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + + @include media-breakpoint-down(sm) { + max-width: calc(100vw - 120px); + } + } + +} + +.select2-dropdown.select2-primary-dropdown { + @include media-breakpoint-down(md) { + max-width: 100vw !important; + width: calc(100vw - 2rem) !important; + + .select2-results__option { + text-wrap: wrap !important; + } + } } \ No newline at end of file diff --git a/assets/scss/_sidepanel.scss b/assets/scss/_sidepanel.scss index 4c4fbbb..307d303 100644 --- a/assets/scss/_sidepanel.scss +++ b/assets/scss/_sidepanel.scss @@ -62,6 +62,7 @@ font-style: normal; font-weight: 400; line-height: normal; + text-align: center; } > .submenu { diff --git a/assets/scss/_theme.scss b/assets/scss/_theme.scss index 7559749..5270253 100644 --- a/assets/scss/_theme.scss +++ b/assets/scss/_theme.scss @@ -1,8 +1,8 @@ body { --inputBackground: var(--secondaryColor); --inputFocusBackground: var(--secondaryColorDark); - --inputBorder: 0; - --inputFocusBorder: 0; + //--inputBorder: 0; + //--inputFocusBorder: 0; } a { diff --git a/assets/scss/_variables.scss b/assets/scss/_variables.scss index 678d9e2..f92ed4a 100644 --- a/assets/scss/_variables.scss +++ b/assets/scss/_variables.scss @@ -1,9 +1,9 @@ -@import '~bootstrap/scss/functions'; +@import 'bootstrap/scss/functions'; // Default variable overrides come here -@import "~bootstrap/scss/variables"; -@import "~bootstrap/scss/mixins"; +@import "bootstrap/scss/variables"; +@import "bootstrap/scss/mixins"; /* ==================== @@ -29,7 +29,7 @@ $background: white; $background-dark: darken($background, 5); $background-darker: darken($background, 10); -$login-background: rgb(255, 255, 255); +$login-background: var(--loginBackground); $heading-color: #333333; $body-color: #333333; diff --git a/assets/scss/app.scss b/assets/scss/app.scss index e3a03fc..fb7c557 100644 --- a/assets/scss/app.scss +++ b/assets/scss/app.scss @@ -1,10 +1,10 @@ @import 'variables'; -@import '~bootstrap/scss/bootstrap'; +@import 'bootstrap/scss/bootstrap'; -@import '~select2/src/scss/core'; -//@import '~select2-bootstrap-5-theme/src/include-all'; +//@import 'select2/src/scss/core'; +//@import 'select2-bootstrap-5-theme/src/include-all'; @import 'fontawesome'; -@import 'daterangepicker'; +//@import 'daterangepicker'; @import 'jquery-ui/datepicker'; @import 'base'; diff --git a/composer.json b/composer.json index bdd461e..b60b5bb 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,11 @@ "kdyby/autowired": "^3.1", "adt/datagrid-components": "^1.0", "nettrine/orm": "^0.10", - "adt/route-port": "^3.0" + "adt/route-port": "^3.0", + "adt/doctrine-loggable": "^3.0" + }, + "suggest": { + "guzzlehttp/guzzle": "Required for Keycloak SSO integration" }, "autoload": { "psr-4": { diff --git a/config/common.neon b/config/common.neon new file mode 100644 index 0000000..112d0cc --- /dev/null +++ b/config/common.neon @@ -0,0 +1,25 @@ +# FancyAdmin common configuration +# Include this file in your project's common.neon: +# includes: +# - ../vendor/adt/fancyadmin/config/common.neon +# +# Override any values in your project config as needed. + +services: + security.userStorage: Nette\Bridges\SecurityHttp\CookieStorage + security.authorizator: ADT\FancyAdmin\Model\Security\Permission + - ADT\DoctrineAuthenticator\OTP\OnetimeTokenService + - ADT\FancyAdmin\Model\Security\BreachedPasswordChecker + fancyadmin.sessionExpirationCallback: ADT\FancyAdmin\Model\Security\SessionExpirationCallback + +session: + autoStart: false + cookieSecure: auto + cookieHttponly: true + cookieSamesite: Lax + +latte: + strictTypes: false + strictParsing: false + extensions: + - ADT\Forms\LatteExtension diff --git a/config/nginx/uploads.conf b/config/nginx/uploads.conf new file mode 100644 index 0000000..3012837 --- /dev/null +++ b/config/nginx/uploads.conf @@ -0,0 +1,11 @@ +# FancyAdmin: Prevent server-side execution of uploaded files (ASVS 5.3.1) +# +# Include this in your nginx server block: +# include /path/to/vendor/adt/fancyadmin/config/nginx/uploads.conf; +# +# Adjust the location path to match your FileListener dataDir/dataUrl configuration. + +location ~* ^/files/.*\.php$ { + deny all; + return 403; +} diff --git a/config/security.neon b/config/security.neon new file mode 100644 index 0000000..cf9fc5b --- /dev/null +++ b/config/security.neon @@ -0,0 +1,50 @@ +# FancyAdmin recommended security configuration +# FancyAdmin configuration files: +# includes: +# - ../vendor/adt/fancyadmin/config/common.neon +# - ../vendor/adt/fancyadmin/config/security.neon +# +# Override any values in your project config as needed. +# Project-specific CSP sources (e.g. HMR dev server) should be added in project config. + +extensions: + doctrineLoggable: ADT\DoctrineLoggable\DI\LoggableExtension + +nettrine.orm: + managers: + default: + mapping: + doctrineLoggable: + namespace: ADT\DoctrineLoggable\Entity + directories: + - %appDir%/../vendor/adt/doctrine-loggable/src/Entity + +security: + authentication: + cookieName: __Host-userid + +http: + cookieSecure: auto + headers: + X-Content-Type-Options: nosniff + X-Frame-Options: DENY + Referrer-Policy: strict-origin-when-cross-origin + Cache-Control: no-store + csp: + script-src: "'self'" + style-src: "'self' 'unsafe-inline'" + img-src: "'self' data:" + font-src: "'self'" + connect-src: "'self'" + frame-ancestors: "'none'" + object-src: "'none'" + base-uri: "'none'" + +services: + - ADT\FancyAdmin\Model\Security\BreachedPasswordChecker + +session: + autoStart: no + cookieSecure: auto + cookieHttponly: true + cookieSamesite: Lax diff --git a/dist/admin/89937b93a1c3ac41f5a9.otf b/dist/admin/89937b93a1c3ac41f5a9.otf deleted file mode 100644 index cf83f01..0000000 Binary files a/dist/admin/89937b93a1c3ac41f5a9.otf and /dev/null differ diff --git a/dist/admin/css/admin.css b/dist/admin/css/admin.css deleted file mode 100644 index c89f35b..0000000 --- a/dist/admin/css/admin.css +++ /dev/null @@ -1,17 +0,0 @@ -/*! - * Bootstrap v5.3.3 (https://getbootstrap.com/) - * Copyright 2011-2024 The Bootstrap Authors - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) - */:root,[data-bs-theme=light]{--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-black: #000;--bs-white: #fff;--bs-gray: #6c757d;--bs-gray-dark: #343a40;--bs-gray-100: #f8f9fa;--bs-gray-200: #e9ecef;--bs-gray-300: #dee2e6;--bs-gray-400: #ced4da;--bs-gray-500: #adb5bd;--bs-gray-600: #6c757d;--bs-gray-700: #495057;--bs-gray-800: #343a40;--bs-gray-900: #212529;--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-primary-rgb: 13, 110, 253;--bs-secondary-rgb: 108, 117, 125;--bs-success-rgb: 25, 135, 84;--bs-info-rgb: 13, 202, 240;--bs-warning-rgb: 255, 193, 7;--bs-danger-rgb: 220, 53, 69;--bs-light-rgb: 248, 249, 250;--bs-dark-rgb: 33, 37, 41;--bs-primary-text-emphasis: rgb(5.2, 44, 101.2);--bs-secondary-text-emphasis: rgb(43.2, 46.8, 50);--bs-success-text-emphasis: rgb(10, 54, 33.6);--bs-info-text-emphasis: rgb(5.2, 80.8, 96);--bs-warning-text-emphasis: rgb(102, 77.2, 2.8);--bs-danger-text-emphasis: rgb(88, 21.2, 27.6);--bs-light-text-emphasis: #495057;--bs-dark-text-emphasis: #495057;--bs-primary-bg-subtle: rgb(206.6, 226, 254.6);--bs-secondary-bg-subtle: rgb(225.6, 227.4, 229);--bs-success-bg-subtle: rgb(209, 231, 220.8);--bs-info-bg-subtle: rgb(206.6, 244.4, 252);--bs-warning-bg-subtle: rgb(255, 242.6, 205.4);--bs-danger-bg-subtle: rgb(248, 214.6, 217.8);--bs-light-bg-subtle: rgb(251.5, 252, 252.5);--bs-dark-bg-subtle: #ced4da;--bs-primary-border-subtle: rgb(158.2, 197, 254.2);--bs-secondary-border-subtle: rgb(196.2, 199.8, 203);--bs-success-border-subtle: rgb(163, 207, 186.6);--bs-info-border-subtle: rgb(158.2, 233.8, 249);--bs-warning-border-subtle: rgb(255, 230.2, 155.8);--bs-danger-border-subtle: rgb(241, 174.2, 180.6);--bs-light-border-subtle: #e9ecef;--bs-dark-border-subtle: #adb5bd;--bs-white-rgb: 255, 255, 255;--bs-black-rgb: 51, 51, 51;--bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, 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));--bs-body-font-family: var(--bs-font-sans-serif);--bs-body-font-size:1rem;--bs-body-font-weight: 400;--bs-body-line-height: 1.5;--bs-body-color: #333333;--bs-body-color-rgb: 51, 51, 51;--bs-body-bg: #fff;--bs-body-bg-rgb: 255, 255, 255;--bs-emphasis-color: #000;--bs-emphasis-color-rgb: 0, 0, 0;--bs-secondary-color: rgba(33, 37, 41, 0.75);--bs-secondary-color-rgb: 33, 37, 41;--bs-secondary-bg: #e9ecef;--bs-secondary-bg-rgb: 233, 236, 239;--bs-tertiary-color: rgba(33, 37, 41, 0.5);--bs-tertiary-color-rgb: 33, 37, 41;--bs-tertiary-bg: #f8f9fa;--bs-tertiary-bg-rgb: 248, 249, 250;--bs-heading-color: inherit;--bs-link-color: #0d6efd;--bs-link-color-rgb: 13, 110, 253;--bs-link-decoration: underline;--bs-link-hover-color: rgb(10.4, 88, 202.4);--bs-link-hover-color-rgb: 10, 88, 202;--bs-code-color: #d63384;--bs-highlight-color: #212529;--bs-highlight-bg: rgb(255, 242.6, 205.4);--bs-border-width: 1px;--bs-border-style: solid;--bs-border-color: #dee2e6;--bs-border-color-translucent: rgba(0, 0, 0, 0.175);--bs-border-radius: 0.375rem;--bs-border-radius-sm: 0.25rem;--bs-border-radius-lg: 0.5rem;--bs-border-radius-xl: 1rem;--bs-border-radius-xxl: 2rem;--bs-border-radius-2xl: var(--bs-border-radius-xxl);--bs-border-radius-pill: 50rem;--bs-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);--bs-box-shadow-sm: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);--bs-box-shadow-lg: 0 1rem 3rem rgba(0, 0, 0, 0.175);--bs-box-shadow-inset: inset 0 1px 2px rgba(0, 0, 0, 0.075);--bs-focus-ring-width: 0.25rem;--bs-focus-ring-opacity: 0.25;--bs-focus-ring-color: rgba(13, 110, 253, 0.25);--bs-form-valid-color: #198754;--bs-form-valid-border-color: #198754;--bs-form-invalid-color: #dc3545;--bs-form-invalid-border-color: #dc3545}[data-bs-theme=dark]{color-scheme:dark;--bs-body-color: #dee2e6;--bs-body-color-rgb: 222, 226, 230;--bs-body-bg: #212529;--bs-body-bg-rgb: 33, 37, 41;--bs-emphasis-color: #fff;--bs-emphasis-color-rgb: 255, 255, 255;--bs-secondary-color: rgba(222, 226, 230, 0.75);--bs-secondary-color-rgb: 222, 226, 230;--bs-secondary-bg: #343a40;--bs-secondary-bg-rgb: 52, 58, 64;--bs-tertiary-color: rgba(222, 226, 230, 0.5);--bs-tertiary-color-rgb: 222, 226, 230;--bs-tertiary-bg: rgb(42.5, 47.5, 52.5);--bs-tertiary-bg-rgb: 43, 48, 53;--bs-primary-text-emphasis: rgb(109.8, 168, 253.8);--bs-secondary-text-emphasis: rgb(166.8, 172.2, 177);--bs-success-text-emphasis: rgb(117, 183, 152.4);--bs-info-text-emphasis: rgb(109.8, 223.2, 246);--bs-warning-text-emphasis: rgb(255, 217.8, 106.2);--bs-danger-text-emphasis: rgb(234, 133.8, 143.4);--bs-light-text-emphasis: #f8f9fa;--bs-dark-text-emphasis: #dee2e6;--bs-primary-bg-subtle: rgb(2.6, 22, 50.6);--bs-secondary-bg-subtle: rgb(21.6, 23.4, 25);--bs-success-bg-subtle: rgb(5, 27, 16.8);--bs-info-bg-subtle: rgb(2.6, 40.4, 48);--bs-warning-bg-subtle: rgb(51, 38.6, 1.4);--bs-danger-bg-subtle: rgb(44, 10.6, 13.8);--bs-light-bg-subtle: #343a40;--bs-dark-bg-subtle: #1a1d20;--bs-primary-border-subtle: rgb(7.8, 66, 151.8);--bs-secondary-border-subtle: rgb(64.8, 70.2, 75);--bs-success-border-subtle: rgb(15, 81, 50.4);--bs-info-border-subtle: rgb(7.8, 121.2, 144);--bs-warning-border-subtle: rgb(153, 115.8, 4.2);--bs-danger-border-subtle: rgb(132, 31.8, 41.4);--bs-light-border-subtle: #495057;--bs-dark-border-subtle: #343a40;--bs-heading-color: inherit;--bs-link-color: rgb(109.8, 168, 253.8);--bs-link-hover-color: rgb(138.84, 185.4, 254.04);--bs-link-color-rgb: 110, 168, 254;--bs-link-hover-color-rgb: 139, 185, 254;--bs-code-color: rgb(230.4, 132.6, 181.2);--bs-highlight-color: #dee2e6;--bs-highlight-bg: rgb(102, 77.2, 2.8);--bs-border-color: #495057;--bs-border-color-translucent: rgba(255, 255, 255, 0.15);--bs-form-valid-color: rgb(117, 183, 152.4);--bs-form-valid-border-color: rgb(117, 183, 152.4);--bs-form-invalid-color: rgb(234, 133.8, 143.4);--bs-form-invalid-border-color: rgb(234, 133.8, 143.4)}*,*::before,*::after{box-sizing:border-box}@media(prefers-reduced-motion: no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:rgba(51,51,51,0)}hr{margin:1rem 0;color:inherit;border:0;border-top:var(--bs-border-width) solid;opacity:.25}h6,.h6,h5,.h5,h4,.h4,h3,.h3,h2,.h2,h1,.h1{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2;color:var(--bs-heading-color)}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 + 0.9vw)}@media(min-width: 1200px){h2,.h2{font-size:2rem}}h3,.h3{font-size:calc(1.3rem + 0.6vw)}@media(min-width: 1200px){h3,.h3{font-size:1.75rem}}h4,.h4{font-size:calc(1.275rem + 0.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[title]{text-decoration:underline dotted;cursor:help;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}ol,ul,dl{margin-top:0;margin-bottom:1rem}ol ol,ul ul,ol ul,ul ol{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:0.875em}mark,.mark{padding:.1875em;color:var(--bs-highlight-color);background-color:var(--bs-highlight-bg)}sub,sup{position:relative;font-size:0.75em;line-height:0;vertical-align:baseline}sub{bottom:-0.25em}sup{top:-0.5em}a{color:rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 1));text-decoration:underline}a:hover{--bs-link-color-rgb: var(--bs-link-hover-color-rgb)}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}pre,code,kbd,samp{font-family:var(--bs-font-monospace);font-size:1em}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:0.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:0.875em;color:var(--bs-code-color);word-wrap:break-word}a>code{color:inherit}kbd{padding:.1875rem .375rem;font-size:0.875em;color:var(--bs-body-bg);background-color:var(--bs-body-color);border-radius:.25rem}kbd kbd{padding:0;font-size:1em}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:var(--bs-secondary-color);text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}thead,tbody,tfoot,tr,td,th{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}input,button,select,optgroup,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]:not([type=date]):not([type=datetime-local]):not([type=month]):not([type=week]):not([type=time])::-webkit-calendar-picker-indicator{display:none !important}button,[type=button],[type=reset],[type=submit]{-webkit-appearance:button}button:not(:disabled),[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]: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 + 0.3vw);line-height:inherit}@media(min-width: 1200px){legend{font-size:1.5rem}}legend+*{clear:left}::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-text,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::file-selector-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:0.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:0.875em;color:#6c757d}.blockquote-footer::before{content:"— "}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:var(--bs-body-bg);border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius);max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:0.875em;color:var(--bs-secondary-color)}.container,.container-fluid,.container-xxl,.container-xl,.container-lg,.container-md,.container-sm{--bs-gutter-x: 1.5rem;--bs-gutter-y: 0;width:100%;padding-right:calc(var(--bs-gutter-x)*.5);padding-left:calc(var(--bs-gutter-x)*.5);margin-right:auto;margin-left:auto}@media(min-width: 576px){.container-sm,.container{max-width:540px}}@media(min-width: 768px){.container-md,.container-sm,.container{max-width:720px}}@media(min-width: 992px){.container-lg,.container-md,.container-sm,.container{max-width:960px}}@media(min-width: 1200px){.container-xl,.container-lg,.container-md,.container-sm,.container{max-width:1140px}}@media(min-width: 1400px){.container-xxl,.container-xl,.container-lg,.container-md,.container-sm,.container{max-width:1320px}}:root{--bs-breakpoint-xs: 0;--bs-breakpoint-sm: 576px;--bs-breakpoint-md: 768px;--bs-breakpoint-lg: 992px;--bs-breakpoint-xl: 1200px;--bs-breakpoint-xxl: 1400px}.row{--bs-gutter-x: 1.5rem;--bs-gutter-y: 0;display:flex;flex-wrap:wrap;margin-top:calc(-1*var(--bs-gutter-y));margin-right:calc(-0.5*var(--bs-gutter-x));margin-left:calc(-0.5*var(--bs-gutter-x))}.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.33333333%}.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.66666667%}.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{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.33333333%}.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.66666667%}.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{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.33333333%}.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.66666667%}.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{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.33333333%}.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.66666667%}.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{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.33333333%}.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.66666667%}.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{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.33333333%}.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.66666667%}.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-color-type: initial;--bs-table-bg-type: initial;--bs-table-color-state: initial;--bs-table-bg-state: initial;--bs-table-color: var(--bs-emphasis-color);--bs-table-bg: var(--bs-body-bg);--bs-table-border-color: var(--bs-border-color);--bs-table-accent-bg: transparent;--bs-table-striped-color: var(--bs-emphasis-color);--bs-table-striped-bg: rgba(var(--bs-emphasis-color-rgb), 0.05);--bs-table-active-color: var(--bs-emphasis-color);--bs-table-active-bg: rgba(var(--bs-emphasis-color-rgb), 0.1);--bs-table-hover-color: var(--bs-emphasis-color);--bs-table-hover-bg: rgba(var(--bs-emphasis-color-rgb), 0.075);width:100%;margin-bottom:1rem;vertical-align:top;border-color:var(--bs-table-border-color)}.table>:not(caption)>*>*{padding:.5rem .5rem;color:var(--bs-table-color-state, var(--bs-table-color-type, var(--bs-table-color)));background-color:var(--bs-table-bg);border-bottom-width:var(--bs-border-width);box-shadow:inset 0 0 0 9999px var(--bs-table-bg-state, var(--bs-table-bg-type, var(--bs-table-accent-bg)))}.table>tbody{vertical-align:inherit}.table>thead{vertical-align:bottom}.table-group-divider{border-top:calc(var(--bs-border-width)*2) solid currentcolor}.caption-top{caption-side:top}.table-sm>:not(caption)>*>*{padding:.25rem .25rem}.table-bordered>:not(caption)>*{border-width:var(--bs-border-width) 0}.table-bordered>:not(caption)>*>*{border-width:0 var(--bs-border-width)}.table-borderless>:not(caption)>*>*{border-bottom-width:0}.table-borderless>:not(:first-child){border-top-width:0}.table-striped>tbody>tr:nth-of-type(odd)>*{--bs-table-color-type: var(--bs-table-striped-color);--bs-table-bg-type: var(--bs-table-striped-bg)}.table-striped-columns>:not(caption)>tr>:nth-child(even){--bs-table-color-type: var(--bs-table-striped-color);--bs-table-bg-type: var(--bs-table-striped-bg)}.table-active{--bs-table-color-state: var(--bs-table-active-color);--bs-table-bg-state: var(--bs-table-active-bg)}.table-hover>tbody>tr:hover>*{--bs-table-color-state: var(--bs-table-hover-color);--bs-table-bg-state: var(--bs-table-hover-bg)}.table-primary{--bs-table-color: #000;--bs-table-bg: rgb(206.6, 226, 254.6);--bs-table-border-color: rgb(165.28, 180.8, 203.68);--bs-table-striped-bg: rgb(196.27, 214.7, 241.87);--bs-table-striped-color: #000;--bs-table-active-bg: rgb(185.94, 203.4, 229.14);--bs-table-active-color: #000;--bs-table-hover-bg: rgb(191.105, 209.05, 235.505);--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-secondary{--bs-table-color: #000;--bs-table-bg: rgb(225.6, 227.4, 229);--bs-table-border-color: rgb(180.48, 181.92, 183.2);--bs-table-striped-bg: rgb(214.32, 216.03, 217.55);--bs-table-striped-color: #000;--bs-table-active-bg: rgb(203.04, 204.66, 206.1);--bs-table-active-color: #000;--bs-table-hover-bg: rgb(208.68, 210.345, 211.825);--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-success{--bs-table-color: #000;--bs-table-bg: rgb(209, 231, 220.8);--bs-table-border-color: rgb(167.2, 184.8, 176.64);--bs-table-striped-bg: rgb(198.55, 219.45, 209.76);--bs-table-striped-color: #000;--bs-table-active-bg: rgb(188.1, 207.9, 198.72);--bs-table-active-color: #000;--bs-table-hover-bg: rgb(193.325, 213.675, 204.24);--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-info{--bs-table-color: #000;--bs-table-bg: rgb(206.6, 244.4, 252);--bs-table-border-color: rgb(165.28, 195.52, 201.6);--bs-table-striped-bg: rgb(196.27, 232.18, 239.4);--bs-table-striped-color: #000;--bs-table-active-bg: rgb(185.94, 219.96, 226.8);--bs-table-active-color: #000;--bs-table-hover-bg: rgb(191.105, 226.07, 233.1);--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-warning{--bs-table-color: #000;--bs-table-bg: rgb(255, 242.6, 205.4);--bs-table-border-color: rgb(204, 194.08, 164.32);--bs-table-striped-bg: rgb(242.25, 230.47, 195.13);--bs-table-striped-color: #000;--bs-table-active-bg: rgb(229.5, 218.34, 184.86);--bs-table-active-color: #000;--bs-table-hover-bg: rgb(235.875, 224.405, 189.995);--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-danger{--bs-table-color: #000;--bs-table-bg: rgb(248, 214.6, 217.8);--bs-table-border-color: rgb(198.4, 171.68, 174.24);--bs-table-striped-bg: rgb(235.6, 203.87, 206.91);--bs-table-striped-color: #000;--bs-table-active-bg: rgb(223.2, 193.14, 196.02);--bs-table-active-color: #000;--bs-table-hover-bg: rgb(229.4, 198.505, 201.465);--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-light{--bs-table-color: #000;--bs-table-bg: #f8f9fa;--bs-table-border-color: rgb(198.4, 199.2, 200);--bs-table-striped-bg: rgb(235.6, 236.55, 237.5);--bs-table-striped-color: #000;--bs-table-active-bg: rgb(223.2, 224.1, 225);--bs-table-active-color: #000;--bs-table-hover-bg: rgb(229.4, 230.325, 231.25);--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-dark{--bs-table-color: #fff;--bs-table-bg: #212529;--bs-table-border-color: rgb(77.4, 80.6, 83.8);--bs-table-striped-bg: rgb(44.1, 47.9, 51.7);--bs-table-striped-color: #fff;--bs-table-active-bg: rgb(55.2, 58.8, 62.4);--bs-table-active-color: #fff;--bs-table-hover-bg: rgb(49.65, 53.35, 57.05);--bs-table-hover-color: #fff;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.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(0.375rem + var(--bs-border-width));padding-bottom:calc(0.375rem + var(--bs-border-width));margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(0.5rem + var(--bs-border-width));padding-bottom:calc(0.5rem + var(--bs-border-width));font-size:1.25rem}.col-form-label-sm{padding-top:calc(0.25rem + var(--bs-border-width));padding-bottom:calc(0.25rem + var(--bs-border-width));font-size:0.875rem}.form-text{margin-top:.25rem;font-size:0.875em;color:var(--bs-secondary-color)}.form-control{display:block;width:100%;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:var(--bs-body-color);appearance:none;background-color:var(--bs-body-bg);background-clip:padding-box;border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius);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:var(--bs-body-color);background-color:var(--bs-body-bg);border-color:rgb(134,182.5,254);outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-control::-webkit-date-and-time-value{min-width:85px;height:1.5em;margin:0}.form-control::-webkit-datetime-edit{display:block;padding:0}.form-control::placeholder{color:var(--bs-secondary-color);opacity:1}.form-control:disabled{background-color:var(--bs-secondary-bg);opacity:1}.form-control::file-selector-button{padding:.375rem .75rem;margin:-0.375rem -0.75rem;margin-inline-end:.75rem;color:var(--bs-body-color);background-color:var(--bs-tertiary-bg);pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:var(--bs-border-width);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:var(--bs-secondary-bg)}.form-control-plaintext{display:block;width:100%;padding:.375rem 0;margin-bottom:0;line-height:1.5;color:var(--bs-body-color);background-color:rgba(0,0,0,0);border:solid rgba(0,0,0,0);border-width:var(--bs-border-width) 0}.form-control-plaintext:focus{outline:0}.form-control-plaintext.form-control-sm,.form-control-plaintext.form-control-lg{padding-right:0;padding-left:0}.form-control-sm{min-height:calc(1.5em + 0.5rem + calc(var(--bs-border-width) * 2));padding:.25rem .5rem;font-size:0.875rem;border-radius:var(--bs-border-radius-sm)}.form-control-sm::file-selector-button{padding:.25rem .5rem;margin:-0.25rem -0.5rem;margin-inline-end:.5rem}.form-control-lg{min-height:calc(1.5em + 1rem + calc(var(--bs-border-width) * 2));padding:.5rem 1rem;font-size:1.25rem;border-radius:var(--bs-border-radius-lg)}.form-control-lg::file-selector-button{padding:.5rem 1rem;margin:-0.5rem -1rem;margin-inline-end:1rem}textarea.form-control{min-height:calc(1.5em + 0.75rem + calc(var(--bs-border-width) * 2))}textarea.form-control-sm{min-height:calc(1.5em + 0.5rem + calc(var(--bs-border-width) * 2))}textarea.form-control-lg{min-height:calc(1.5em + 1rem + calc(var(--bs-border-width) * 2))}.form-control-color{width:3rem;height:calc(1.5em + 0.75rem + calc(var(--bs-border-width) * 2));padding:.375rem}.form-control-color:not(:disabled):not([readonly]){cursor:pointer}.form-control-color::-moz-color-swatch{border:0 !important;border-radius:var(--bs-border-radius)}.form-control-color::-webkit-color-swatch{border:0 !important;border-radius:var(--bs-border-radius)}.form-control-color.form-control-sm{height:calc(1.5em + 0.5rem + calc(var(--bs-border-width) * 2))}.form-control-color.form-control-lg{height:calc(1.5em + 1rem + calc(var(--bs-border-width) * 2))}.form-select{--bs-form-select-bg-img: url("data:image/svg+xml,%3csvg xmlns=%27http://www.w3.org/2000/svg%27 viewBox=%270 0 16 16%27%3e%3cpath fill=%27none%27 stroke=%27%23343a40%27 stroke-linecap=%27round%27 stroke-linejoin=%27round%27 stroke-width=%272%27 d=%27m2 5 6 6 6-6%27/%3e%3c/svg%3e");display:block;width:100%;padding:.375rem 2.25rem .375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:var(--bs-body-color);appearance:none;background-color:var(--bs-body-bg);background-image:var(--bs-form-select-bg-img),var(--bs-form-select-bg-icon, none);background-repeat:no-repeat;background-position:right .75rem center;background-size:16px 12px;border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius);transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-select{transition:none}}.form-select:focus{border-color:rgb(134,182.5,254);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:var(--bs-secondary-bg)}.form-select:-moz-focusring{color:rgba(0,0,0,0);text-shadow:0 0 0 var(--bs-body-color)}.form-select-sm{padding-top:.25rem;padding-bottom:.25rem;padding-left:.5rem;font-size:0.875rem;border-radius:var(--bs-border-radius-sm)}.form-select-lg{padding-top:.5rem;padding-bottom:.5rem;padding-left:1rem;font-size:1.25rem;border-radius:var(--bs-border-radius-lg)}[data-bs-theme=dark] .form-select{--bs-form-select-bg-img: url("data:image/svg+xml,%3csvg xmlns=%27http://www.w3.org/2000/svg%27 viewBox=%270 0 16 16%27%3e%3cpath fill=%27none%27 stroke=%27%23dee2e6%27 stroke-linecap=%27round%27 stroke-linejoin=%27round%27 stroke-width=%272%27 d=%27m2 5 6 6 6-6%27/%3e%3c/svg%3e")}.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-reverse{padding-right:1.5em;padding-left:0;text-align:right}.form-check-reverse .form-check-input{float:right;margin-right:-1.5em;margin-left:0}.form-check-input{--bs-form-check-bg: var(--bs-body-bg);flex-shrink:0;width:1em;height:1em;margin-top:.25em;vertical-align:top;appearance:none;background-color:var(--bs-form-check-bg);background-image:var(--bs-form-check-bg-image);background-repeat:no-repeat;background-position:center;background-size:contain;border:var(--bs-border-width) solid var(--bs-border-color);print-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:rgb(134,182.5,254);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]{--bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns=%27http://www.w3.org/2000/svg%27 viewBox=%270 0 20 20%27%3e%3cpath fill=%27none%27 stroke=%27%23fff%27 stroke-linecap=%27round%27 stroke-linejoin=%27round%27 stroke-width=%273%27 d=%27m6 10 3 3 6-6%27/%3e%3c/svg%3e")}.form-check-input:checked[type=radio]{--bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns=%27http://www.w3.org/2000/svg%27 viewBox=%27-4 -4 8 8%27%3e%3ccircle r=%272%27 fill=%27%23fff%27/%3e%3c/svg%3e")}.form-check-input[type=checkbox]:indeterminate{background-color:#0d6efd;border-color:#0d6efd;--bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns=%27http://www.w3.org/2000/svg%27 viewBox=%270 0 20 20%27%3e%3cpath fill=%27none%27 stroke=%27%23fff%27 stroke-linecap=%27round%27 stroke-linejoin=%27round%27 stroke-width=%273%27 d=%27M6 10h8%27/%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{cursor:default;opacity:.5}.form-switch{padding-left:2.5em}.form-switch .form-check-input{--bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns=%27http://www.w3.org/2000/svg%27 viewBox=%27-4 -4 8 8%27%3e%3ccircle r=%273%27 fill=%27rgba%280, 0, 0, 0.25%29%27/%3e%3c/svg%3e");width:2em;margin-left:-2.5em;background-image:var(--bs-form-switch-bg);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{--bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns=%27http://www.w3.org/2000/svg%27 viewBox=%27-4 -4 8 8%27%3e%3ccircle r=%273%27 fill=%27rgb%28134, 182.5, 254%29%27/%3e%3c/svg%3e")}.form-switch .form-check-input:checked{background-position:right center;--bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns=%27http://www.w3.org/2000/svg%27 viewBox=%27-4 -4 8 8%27%3e%3ccircle r=%273%27 fill=%27%23fff%27/%3e%3c/svg%3e")}.form-switch.form-check-reverse{padding-right:2.5em;padding-left:0}.form-switch.form-check-reverse .form-check-input{margin-right:-2.5em;margin-left:0}.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}[data-bs-theme=dark] .form-switch .form-check-input:not(:checked):not(:focus){--bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns=%27http://www.w3.org/2000/svg%27 viewBox=%27-4 -4 8 8%27%3e%3ccircle r=%273%27 fill=%27rgba%28255, 255, 255, 0.25%29%27/%3e%3c/svg%3e")}.form-range{width:100%;height:1.5rem;padding:0;appearance:none;background-color:rgba(0,0,0,0)}.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:-0.25rem;appearance:none;background-color:#0d6efd;border:0;border-radius:1rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-range::-webkit-slider-thumb{transition:none}}.form-range::-webkit-slider-thumb:active{background-color:rgb(182.4,211.5,254.4)}.form-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:rgba(0,0,0,0);cursor:pointer;background-color:var(--bs-secondary-bg);border-color:rgba(0,0,0,0);border-radius:1rem}.form-range::-moz-range-thumb{width:1rem;height:1rem;appearance:none;background-color:#0d6efd;border:0;border-radius:1rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-range::-moz-range-thumb{transition:none}}.form-range::-moz-range-thumb:active{background-color:rgb(182.4,211.5,254.4)}.form-range::-moz-range-track{width:100%;height:.5rem;color:rgba(0,0,0,0);cursor:pointer;background-color:var(--bs-secondary-bg);border-color:rgba(0,0,0,0);border-radius:1rem}.form-range:disabled{pointer-events:none}.form-range:disabled::-webkit-slider-thumb{background-color:var(--bs-secondary-color)}.form-range:disabled::-moz-range-thumb{background-color:var(--bs-secondary-color)}.form-floating{position:relative}.form-floating>.form-control,.form-floating>.form-control-plaintext,.form-floating>.form-select{height:calc(3.5rem + calc(var(--bs-border-width) * 2));min-height:calc(3.5rem + calc(var(--bs-border-width) * 2));line-height:1.25}.form-floating>label{position:absolute;top:0;left:0;z-index:2;height:100%;padding:1rem .75rem;overflow:hidden;text-align:start;text-overflow:ellipsis;white-space:nowrap;pointer-events:none;border:var(--bs-border-width) solid rgba(0,0,0,0);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,.form-floating>.form-control-plaintext{padding:1rem .75rem}.form-floating>.form-control::placeholder,.form-floating>.form-control-plaintext::placeholder{color:rgba(0,0,0,0)}.form-floating>.form-control:focus,.form-floating>.form-control:not(:placeholder-shown),.form-floating>.form-control-plaintext:focus,.form-floating>.form-control-plaintext:not(:placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:-webkit-autofill,.form-floating>.form-control-plaintext:-webkit-autofill{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-select{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:focus~label,.form-floating>.form-control:not(:placeholder-shown)~label,.form-floating>.form-control-plaintext~label,.form-floating>.form-select~label{color:rgba(var(--bs-body-color-rgb), 0.65);transform:scale(0.85) translateY(-0.5rem) translateX(0.15rem)}.form-floating>.form-control:focus~label::after,.form-floating>.form-control:not(:placeholder-shown)~label::after,.form-floating>.form-control-plaintext~label::after,.form-floating>.form-select~label::after{position:absolute;inset:1rem .375rem;z-index:-1;height:1.5em;content:"";background-color:var(--bs-body-bg);border-radius:var(--bs-border-radius)}.form-floating>.form-control:-webkit-autofill~label{color:rgba(var(--bs-body-color-rgb), 0.65);transform:scale(0.85) translateY(-0.5rem) translateX(0.15rem)}.form-floating>.form-control-plaintext~label{border-width:var(--bs-border-width) 0}.form-floating>:disabled~label,.form-floating>.form-control:disabled~label{color:#6c757d}.form-floating>:disabled~label::after,.form-floating>.form-control:disabled~label::after{background-color:var(--bs-secondary-bg)}.input-group{position:relative;display:flex;flex-wrap:wrap;align-items:stretch;width:100%}.input-group>.form-control,.input-group>.form-select,.input-group>.form-floating{position:relative;flex:1 1 auto;width:1%;min-width:0}.input-group>.form-control:focus,.input-group>.form-select:focus,.input-group>.form-floating:focus-within{z-index:5}.input-group .btn{position:relative;z-index:2}.input-group .btn:focus{z-index:5}.input-group-text{display:flex;align-items:center;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:var(--bs-body-color);text-align:center;white-space:nowrap;background-color:var(--bs-tertiary-bg);border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius)}.input-group-lg>.form-control,.input-group-lg>.form-select,.input-group-lg>.input-group-text,.input-group-lg>.btn{padding:.5rem 1rem;font-size:1.25rem;border-radius:var(--bs-border-radius-lg)}.input-group-sm>.form-control,.input-group-sm>.form-select,.input-group-sm>.input-group-text,.input-group-sm>.btn{padding:.25rem .5rem;font-size:0.875rem;border-radius:var(--bs-border-radius-sm)}.input-group-lg>.form-select,.input-group-sm>.form-select{padding-right:3rem}.input-group:not(.has-validation)>:not(:last-child):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating),.input-group:not(.has-validation)>.dropdown-toggle:nth-last-child(n+3),.input-group:not(.has-validation)>.form-floating:not(:last-child)>.form-control,.input-group:not(.has-validation)>.form-floating:not(:last-child)>.form-select{border-top-right-radius:0;border-bottom-right-radius:0}.input-group.has-validation>:nth-last-child(n+3):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating),.input-group.has-validation>.dropdown-toggle:nth-last-child(n+4),.input-group.has-validation>.form-floating:nth-last-child(n+3)>.form-control,.input-group.has-validation>.form-floating:nth-last-child(n+3)>.form-select{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:calc(var(--bs-border-width)*-1);border-top-left-radius:0;border-bottom-left-radius:0}.input-group>.form-floating:not(:first-child)>.form-control,.input-group>.form-floating:not(:first-child)>.form-select{border-top-left-radius:0;border-bottom-left-radius:0}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:0.875em;color:var(--bs-form-valid-color)}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:0.875rem;color:#fff;background-color:var(--bs-success);border-radius:var(--bs-border-radius)}.was-validated :valid~.valid-feedback,.was-validated :valid~.valid-tooltip,.is-valid~.valid-feedback,.is-valid~.valid-tooltip{display:block}.was-validated .form-control:valid,.form-control.is-valid{border-color:var(--bs-form-valid-border-color);padding-right:calc(1.5em + 0.75rem);background-image:url("data:image/svg+xml,%3csvg xmlns=%27http://www.w3.org/2000/svg%27 viewBox=%270 0 8 8%27%3e%3cpath fill=%27%23198754%27 d=%27M2.3 6.73.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%27/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(0.375em + 0.1875rem) center;background-size:calc(0.75em + 0.375rem) calc(0.75em + 0.375rem)}.was-validated .form-control:valid:focus,.form-control.is-valid:focus{border-color:var(--bs-form-valid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-success-rgb), 0.25)}.was-validated textarea.form-control:valid,textarea.form-control.is-valid{padding-right:calc(1.5em + 0.75rem);background-position:top calc(0.375em + 0.1875rem) right calc(0.375em + 0.1875rem)}.was-validated .form-select:valid,.form-select.is-valid{border-color:var(--bs-form-valid-border-color)}.was-validated .form-select:valid:not([multiple]):not([size]),.was-validated .form-select:valid:not([multiple])[size="1"],.form-select.is-valid:not([multiple]):not([size]),.form-select.is-valid:not([multiple])[size="1"]{--bs-form-select-bg-icon: url("data:image/svg+xml,%3csvg xmlns=%27http://www.w3.org/2000/svg%27 viewBox=%270 0 8 8%27%3e%3cpath fill=%27%23198754%27 d=%27M2.3 6.73.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%27/%3e%3c/svg%3e");padding-right:4.125rem;background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(0.75em + 0.375rem) calc(0.75em + 0.375rem)}.was-validated .form-select:valid:focus,.form-select.is-valid:focus{border-color:var(--bs-form-valid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-success-rgb), 0.25)}.was-validated .form-control-color:valid,.form-control-color.is-valid{width:calc(3rem + calc(1.5em + 0.75rem))}.was-validated .form-check-input:valid,.form-check-input.is-valid{border-color:var(--bs-form-valid-border-color)}.was-validated .form-check-input:valid:checked,.form-check-input.is-valid:checked{background-color:var(--bs-form-valid-color)}.was-validated .form-check-input:valid:focus,.form-check-input.is-valid:focus{box-shadow:0 0 0 .25rem rgba(var(--bs-success-rgb), 0.25)}.was-validated .form-check-input:valid~.form-check-label,.form-check-input.is-valid~.form-check-label{color:var(--bs-form-valid-color)}.form-check-inline .form-check-input~.valid-feedback{margin-left:.5em}.was-validated .input-group>.form-control:not(:focus):valid,.input-group>.form-control:not(:focus).is-valid,.was-validated .input-group>.form-select:not(:focus):valid,.input-group>.form-select:not(:focus).is-valid,.was-validated .input-group>.form-floating:not(:focus-within):valid,.input-group>.form-floating:not(:focus-within).is-valid{z-index:3}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:0.875em;color:var(--bs-form-invalid-color)}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:0.875rem;color:#fff;background-color:var(--bs-danger);border-radius:var(--bs-border-radius)}.was-validated :invalid~.invalid-feedback,.was-validated :invalid~.invalid-tooltip,.is-invalid~.invalid-feedback,.is-invalid~.invalid-tooltip{display:block}.was-validated .form-control:invalid,.form-control.is-invalid{border-color:var(--bs-form-invalid-border-color);padding-right:calc(1.5em + 0.75rem);background-image:url("data:image/svg+xml,%3csvg xmlns=%27http://www.w3.org/2000/svg%27 viewBox=%270 0 12 12%27 width=%2712%27 height=%2712%27 fill=%27none%27 stroke=%27%23dc3545%27%3e%3ccircle cx=%276%27 cy=%276%27 r=%274.5%27/%3e%3cpath stroke-linejoin=%27round%27 d=%27M5.8 3.6h.4L6 6.5z%27/%3e%3ccircle cx=%276%27 cy=%278.2%27 r=%27.6%27 fill=%27%23dc3545%27 stroke=%27none%27/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(0.375em + 0.1875rem) center;background-size:calc(0.75em + 0.375rem) calc(0.75em + 0.375rem)}.was-validated .form-control:invalid:focus,.form-control.is-invalid:focus{border-color:var(--bs-form-invalid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-danger-rgb), 0.25)}.was-validated textarea.form-control:invalid,textarea.form-control.is-invalid{padding-right:calc(1.5em + 0.75rem);background-position:top calc(0.375em + 0.1875rem) right calc(0.375em + 0.1875rem)}.was-validated .form-select:invalid,.form-select.is-invalid{border-color:var(--bs-form-invalid-border-color)}.was-validated .form-select:invalid:not([multiple]):not([size]),.was-validated .form-select:invalid:not([multiple])[size="1"],.form-select.is-invalid:not([multiple]):not([size]),.form-select.is-invalid:not([multiple])[size="1"]{--bs-form-select-bg-icon: url("data:image/svg+xml,%3csvg xmlns=%27http://www.w3.org/2000/svg%27 viewBox=%270 0 12 12%27 width=%2712%27 height=%2712%27 fill=%27none%27 stroke=%27%23dc3545%27%3e%3ccircle cx=%276%27 cy=%276%27 r=%274.5%27/%3e%3cpath stroke-linejoin=%27round%27 d=%27M5.8 3.6h.4L6 6.5z%27/%3e%3ccircle cx=%276%27 cy=%278.2%27 r=%27.6%27 fill=%27%23dc3545%27 stroke=%27none%27/%3e%3c/svg%3e");padding-right:4.125rem;background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(0.75em + 0.375rem) calc(0.75em + 0.375rem)}.was-validated .form-select:invalid:focus,.form-select.is-invalid:focus{border-color:var(--bs-form-invalid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-danger-rgb), 0.25)}.was-validated .form-control-color:invalid,.form-control-color.is-invalid{width:calc(3rem + calc(1.5em + 0.75rem))}.was-validated .form-check-input:invalid,.form-check-input.is-invalid{border-color:var(--bs-form-invalid-border-color)}.was-validated .form-check-input:invalid:checked,.form-check-input.is-invalid:checked{background-color:var(--bs-form-invalid-color)}.was-validated .form-check-input:invalid:focus,.form-check-input.is-invalid:focus{box-shadow:0 0 0 .25rem rgba(var(--bs-danger-rgb), 0.25)}.was-validated .form-check-input:invalid~.form-check-label,.form-check-input.is-invalid~.form-check-label{color:var(--bs-form-invalid-color)}.form-check-inline .form-check-input~.invalid-feedback{margin-left:.5em}.was-validated .input-group>.form-control:not(:focus):invalid,.input-group>.form-control:not(:focus).is-invalid,.was-validated .input-group>.form-select:not(:focus):invalid,.input-group>.form-select:not(:focus).is-invalid,.was-validated .input-group>.form-floating:not(:focus-within):invalid,.input-group>.form-floating:not(:focus-within).is-invalid{z-index:4}.btn{--bs-btn-padding-x: 25px;--bs-btn-padding-y: 15px;--bs-btn-font-family: ;--bs-btn-font-size:0.9rem;--bs-btn-font-weight: 400;--bs-btn-line-height: normal;--bs-btn-color: var(--bs-body-color);--bs-btn-bg: transparent;--bs-btn-border-width: var(--bs-border-width);--bs-btn-border-color: transparent;--bs-btn-border-radius: 20px;--bs-btn-hover-border-color: transparent;--bs-btn-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);--bs-btn-disabled-opacity: 0.65;--bs-btn-focus-box-shadow: 0 0 0 0.25rem rgba(var(--bs-btn-focus-shadow-rgb), .5);display:inline-block;padding:var(--bs-btn-padding-y) var(--bs-btn-padding-x);font-family:var(--bs-btn-font-family);font-size:var(--bs-btn-font-size);font-weight:var(--bs-btn-font-weight);line-height:var(--bs-btn-line-height);color:var(--bs-btn-color);text-align:center;text-decoration:none;vertical-align:middle;cursor:pointer;user-select:none;border:var(--bs-btn-border-width) solid var(--bs-btn-border-color);border-radius:var(--bs-btn-border-radius);background-color:var(--bs-btn-bg);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:var(--bs-btn-hover-color);background-color:var(--bs-btn-hover-bg);border-color:var(--bs-btn-hover-border-color)}.btn-check+.btn:hover{color:var(--bs-btn-color);background-color:var(--bs-btn-bg);border-color:var(--bs-btn-border-color)}.btn:focus-visible{color:var(--bs-btn-hover-color);background-color:var(--bs-btn-hover-bg);border-color:var(--bs-btn-hover-border-color);outline:0;box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:focus-visible+.btn{border-color:var(--bs-btn-hover-border-color);outline:0;box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:checked+.btn,:not(.btn-check)+.btn:active,.btn:first-child:active,.btn.active,.btn.show{color:var(--bs-btn-active-color);background-color:var(--bs-btn-active-bg);border-color:var(--bs-btn-active-border-color)}.btn-check:checked+.btn:focus-visible,:not(.btn-check)+.btn:active:focus-visible,.btn:first-child:active:focus-visible,.btn.active:focus-visible,.btn.show:focus-visible{box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:checked:focus-visible+.btn{box-shadow:var(--bs-btn-focus-box-shadow)}.btn:disabled,.btn.disabled,fieldset:disabled .btn{color:var(--bs-btn-disabled-color);pointer-events:none;background-color:var(--bs-btn-disabled-bg);border-color:var(--bs-btn-disabled-border-color);opacity:var(--bs-btn-disabled-opacity)}.btn-primary{--bs-btn-color: #fff;--bs-btn-bg: #0d6efd;--bs-btn-border-color: #0d6efd;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: rgb(11.05, 93.5, 215.05);--bs-btn-hover-border-color: rgb(10.4, 88, 202.4);--bs-btn-focus-shadow-rgb: 49, 132, 253;--bs-btn-active-color: #fff;--bs-btn-active-bg: rgb(10.4, 88, 202.4);--bs-btn-active-border-color: rgb(9.75, 82.5, 189.75);--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #fff;--bs-btn-disabled-bg: #0d6efd;--bs-btn-disabled-border-color: #0d6efd}.btn-secondary{--bs-btn-color: #fff;--bs-btn-bg: #6c757d;--bs-btn-border-color: #6c757d;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: rgb(91.8, 99.45, 106.25);--bs-btn-hover-border-color: rgb(86.4, 93.6, 100);--bs-btn-focus-shadow-rgb: 130, 138, 145;--bs-btn-active-color: #fff;--bs-btn-active-bg: rgb(86.4, 93.6, 100);--bs-btn-active-border-color: rgb(81, 87.75, 93.75);--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #fff;--bs-btn-disabled-bg: #6c757d;--bs-btn-disabled-border-color: #6c757d}.btn-success{--bs-btn-color: #fff;--bs-btn-bg: #198754;--bs-btn-border-color: #198754;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: rgb(21.25, 114.75, 71.4);--bs-btn-hover-border-color: rgb(20, 108, 67.2);--bs-btn-focus-shadow-rgb: 60, 153, 110;--bs-btn-active-color: #fff;--bs-btn-active-bg: rgb(20, 108, 67.2);--bs-btn-active-border-color: rgb(18.75, 101.25, 63);--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #fff;--bs-btn-disabled-bg: #198754;--bs-btn-disabled-border-color: #198754}.btn-info{--bs-btn-color: #000;--bs-btn-bg: #0dcaf0;--bs-btn-border-color: #0dcaf0;--bs-btn-hover-color: #000;--bs-btn-hover-bg: rgb(49.3, 209.95, 242.25);--bs-btn-hover-border-color: rgb(37.2, 207.3, 241.5);--bs-btn-focus-shadow-rgb: 11, 172, 204;--bs-btn-active-color: #000;--bs-btn-active-bg: rgb(61.4, 212.6, 243);--bs-btn-active-border-color: rgb(37.2, 207.3, 241.5);--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #000;--bs-btn-disabled-bg: #0dcaf0;--bs-btn-disabled-border-color: #0dcaf0}.btn-warning{--bs-btn-color: #000;--bs-btn-bg: #ffc107;--bs-btn-border-color: #ffc107;--bs-btn-hover-color: #000;--bs-btn-hover-bg: rgb(255, 202.3, 44.2);--bs-btn-hover-border-color: rgb(255, 199.2, 31.8);--bs-btn-focus-shadow-rgb: 217, 164, 6;--bs-btn-active-color: #000;--bs-btn-active-bg: rgb(255, 205.4, 56.6);--bs-btn-active-border-color: rgb(255, 199.2, 31.8);--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #000;--bs-btn-disabled-bg: #ffc107;--bs-btn-disabled-border-color: #ffc107}.btn-danger{--bs-btn-color: #fff;--bs-btn-bg: #dc3545;--bs-btn-border-color: #dc3545;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: rgb(187, 45.05, 58.65);--bs-btn-hover-border-color: rgb(176, 42.4, 55.2);--bs-btn-focus-shadow-rgb: 225, 83, 97;--bs-btn-active-color: #fff;--bs-btn-active-bg: rgb(176, 42.4, 55.2);--bs-btn-active-border-color: rgb(165, 39.75, 51.75);--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #fff;--bs-btn-disabled-bg: #dc3545;--bs-btn-disabled-border-color: #dc3545}.btn-light{--bs-btn-color: #000;--bs-btn-bg: #f8f9fa;--bs-btn-border-color: #f8f9fa;--bs-btn-hover-color: #000;--bs-btn-hover-bg: rgb(210.8, 211.65, 212.5);--bs-btn-hover-border-color: rgb(198.4, 199.2, 200);--bs-btn-focus-shadow-rgb: 211, 212, 213;--bs-btn-active-color: #000;--bs-btn-active-bg: rgb(198.4, 199.2, 200);--bs-btn-active-border-color: rgb(186, 186.75, 187.5);--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #000;--bs-btn-disabled-bg: #f8f9fa;--bs-btn-disabled-border-color: #f8f9fa}.btn-dark{--bs-btn-color: #fff;--bs-btn-bg: #212529;--bs-btn-border-color: #212529;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: rgb(66.3, 69.7, 73.1);--bs-btn-hover-border-color: rgb(55.2, 58.8, 62.4);--bs-btn-focus-shadow-rgb: 66, 70, 73;--bs-btn-active-color: #fff;--bs-btn-active-bg: rgb(77.4, 80.6, 83.8);--bs-btn-active-border-color: rgb(55.2, 58.8, 62.4);--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #fff;--bs-btn-disabled-bg: #212529;--bs-btn-disabled-border-color: #212529}.btn-outline-primary{--bs-btn-color: #0d6efd;--bs-btn-border-color: #0d6efd;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #0d6efd;--bs-btn-hover-border-color: #0d6efd;--bs-btn-focus-shadow-rgb: 13, 110, 253;--bs-btn-active-color: #fff;--bs-btn-active-bg: #0d6efd;--bs-btn-active-border-color: #0d6efd;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #0d6efd;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #0d6efd;--bs-gradient: none}.btn-outline-secondary{--bs-btn-color: #6c757d;--bs-btn-border-color: #6c757d;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #6c757d;--bs-btn-hover-border-color: #6c757d;--bs-btn-focus-shadow-rgb: 108, 117, 125;--bs-btn-active-color: #fff;--bs-btn-active-bg: #6c757d;--bs-btn-active-border-color: #6c757d;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #6c757d;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #6c757d;--bs-gradient: none}.btn-outline-success{--bs-btn-color: #198754;--bs-btn-border-color: #198754;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #198754;--bs-btn-hover-border-color: #198754;--bs-btn-focus-shadow-rgb: 25, 135, 84;--bs-btn-active-color: #fff;--bs-btn-active-bg: #198754;--bs-btn-active-border-color: #198754;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #198754;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #198754;--bs-gradient: none}.btn-outline-info{--bs-btn-color: #0dcaf0;--bs-btn-border-color: #0dcaf0;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #0dcaf0;--bs-btn-hover-border-color: #0dcaf0;--bs-btn-focus-shadow-rgb: 13, 202, 240;--bs-btn-active-color: #000;--bs-btn-active-bg: #0dcaf0;--bs-btn-active-border-color: #0dcaf0;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #0dcaf0;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #0dcaf0;--bs-gradient: none}.btn-outline-warning{--bs-btn-color: #ffc107;--bs-btn-border-color: #ffc107;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #ffc107;--bs-btn-hover-border-color: #ffc107;--bs-btn-focus-shadow-rgb: 255, 193, 7;--bs-btn-active-color: #000;--bs-btn-active-bg: #ffc107;--bs-btn-active-border-color: #ffc107;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #ffc107;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #ffc107;--bs-gradient: none}.btn-outline-danger{--bs-btn-color: #dc3545;--bs-btn-border-color: #dc3545;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #dc3545;--bs-btn-hover-border-color: #dc3545;--bs-btn-focus-shadow-rgb: 220, 53, 69;--bs-btn-active-color: #fff;--bs-btn-active-bg: #dc3545;--bs-btn-active-border-color: #dc3545;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #dc3545;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #dc3545;--bs-gradient: none}.btn-outline-light{--bs-btn-color: #f8f9fa;--bs-btn-border-color: #f8f9fa;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #f8f9fa;--bs-btn-hover-border-color: #f8f9fa;--bs-btn-focus-shadow-rgb: 248, 249, 250;--bs-btn-active-color: #000;--bs-btn-active-bg: #f8f9fa;--bs-btn-active-border-color: #f8f9fa;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #f8f9fa;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #f8f9fa;--bs-gradient: none}.btn-outline-dark{--bs-btn-color: #212529;--bs-btn-border-color: #212529;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #212529;--bs-btn-hover-border-color: #212529;--bs-btn-focus-shadow-rgb: 33, 37, 41;--bs-btn-active-color: #fff;--bs-btn-active-bg: #212529;--bs-btn-active-border-color: #212529;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color: #212529;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #212529;--bs-gradient: none}.btn-link{--bs-btn-font-weight: 400;--bs-btn-color: var(--bs-link-color);--bs-btn-bg: transparent;--bs-btn-border-color: transparent;--bs-btn-hover-color: var(--bs-link-hover-color);--bs-btn-hover-border-color: transparent;--bs-btn-active-color: var(--bs-link-hover-color);--bs-btn-active-border-color: transparent;--bs-btn-disabled-color: #6c757d;--bs-btn-disabled-border-color: transparent;--bs-btn-box-shadow: 0 0 0 #000;--bs-btn-focus-shadow-rgb: 49, 132, 253;text-decoration:underline}.btn-link:focus-visible{color:var(--bs-btn-color)}.btn-link:hover{color:var(--bs-btn-hover-color)}.btn-lg,.btn-group-lg>.btn{--bs-btn-padding-y: 0.5rem;--bs-btn-padding-x: 1rem;--bs-btn-font-size:1.25rem;--bs-btn-border-radius: var(--bs-border-radius-lg)}.btn-sm,.btn-group-sm>.btn{--bs-btn-padding-y: 0.25rem;--bs-btn-padding-x: 0.5rem;--bs-btn-font-size:0.875rem;--bs-btn-border-radius: var(--bs-border-radius-sm)}.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}}.collapsing.collapse-horizontal{width:0;height:auto;transition:width .35s ease}@media(prefers-reduced-motion: reduce){.collapsing.collapse-horizontal{transition:none}}.dropup,.dropend,.dropdown,.dropstart,.dropup-center,.dropdown-center{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 rgba(0,0,0,0);border-bottom:0;border-left:.3em solid rgba(0,0,0,0)}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{--bs-dropdown-zindex: 1000;--bs-dropdown-min-width: 10rem;--bs-dropdown-padding-x: 0;--bs-dropdown-padding-y: 0.5rem;--bs-dropdown-spacer: 0.125rem;--bs-dropdown-font-size:1rem;--bs-dropdown-color: var(--bs-body-color);--bs-dropdown-bg: var(--bs-body-bg);--bs-dropdown-border-color: var(--bs-border-color-translucent);--bs-dropdown-border-radius: var(--bs-border-radius);--bs-dropdown-border-width: var(--bs-border-width);--bs-dropdown-inner-border-radius: calc(var(--bs-border-radius) - var(--bs-border-width));--bs-dropdown-divider-bg: var(--bs-border-color-translucent);--bs-dropdown-divider-margin-y: 0.5rem;--bs-dropdown-box-shadow: var(--bs-box-shadow);--bs-dropdown-link-color: var(--bs-body-color);--bs-dropdown-link-hover-color: var(--bs-body-color);--bs-dropdown-link-hover-bg: var(--bs-tertiary-bg);--bs-dropdown-link-active-color: #fff;--bs-dropdown-link-active-bg: #0d6efd;--bs-dropdown-link-disabled-color: var(--bs-tertiary-color);--bs-dropdown-item-padding-x: 1rem;--bs-dropdown-item-padding-y: 0.25rem;--bs-dropdown-header-color: #6c757d;--bs-dropdown-header-padding-x: 1rem;--bs-dropdown-header-padding-y: 0.5rem;position:absolute;z-index:var(--bs-dropdown-zindex);display:none;min-width:var(--bs-dropdown-min-width);padding:var(--bs-dropdown-padding-y) var(--bs-dropdown-padding-x);margin:0;font-size:var(--bs-dropdown-font-size);color:var(--bs-dropdown-color);text-align:left;list-style:none;background-color:var(--bs-dropdown-bg);background-clip:padding-box;border:var(--bs-dropdown-border-width) solid var(--bs-dropdown-border-color);border-radius:var(--bs-dropdown-border-radius)}.dropdown-menu[data-bs-popper]{top:100%;left:0;margin-top:var(--bs-dropdown-spacer)}.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:var(--bs-dropdown-spacer)}.dropup .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid rgba(0,0,0,0);border-bottom:.3em solid;border-left:.3em solid rgba(0,0,0,0)}.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:var(--bs-dropdown-spacer)}.dropend .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid rgba(0,0,0,0);border-right:0;border-bottom:.3em solid rgba(0,0,0,0);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:var(--bs-dropdown-spacer)}.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 rgba(0,0,0,0);border-right:.3em solid;border-bottom:.3em solid rgba(0,0,0,0)}.dropstart .dropdown-toggle:empty::after{margin-left:0}.dropstart .dropdown-toggle::before{vertical-align:0}.dropdown-divider{height:0;margin:var(--bs-dropdown-divider-margin-y) 0;overflow:hidden;border-top:1px solid var(--bs-dropdown-divider-bg);opacity:1}.dropdown-item{display:block;width:100%;padding:var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);clear:both;font-weight:400;color:var(--bs-dropdown-link-color);text-align:inherit;text-decoration:none;white-space:nowrap;background-color:rgba(0,0,0,0);border:0;border-radius:var(--bs-dropdown-item-border-radius, 0)}.dropdown-item:hover,.dropdown-item:focus{color:var(--bs-dropdown-link-hover-color);background-color:var(--bs-dropdown-link-hover-bg)}.dropdown-item.active,.dropdown-item:active{color:var(--bs-dropdown-link-active-color);text-decoration:none;background-color:var(--bs-dropdown-link-active-bg)}.dropdown-item.disabled,.dropdown-item:disabled{color:var(--bs-dropdown-link-disabled-color);pointer-events:none;background-color:rgba(0,0,0,0)}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:var(--bs-dropdown-header-padding-y) var(--bs-dropdown-header-padding-x);margin-bottom:0;font-size:0.875rem;color:var(--bs-dropdown-header-color);white-space:nowrap}.dropdown-item-text{display:block;padding:var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);color:var(--bs-dropdown-link-color)}.dropdown-menu-dark{--bs-dropdown-color: #dee2e6;--bs-dropdown-bg: #343a40;--bs-dropdown-border-color: var(--bs-border-color-translucent);--bs-dropdown-box-shadow: ;--bs-dropdown-link-color: #dee2e6;--bs-dropdown-link-hover-color: #fff;--bs-dropdown-divider-bg: var(--bs-border-color-translucent);--bs-dropdown-link-hover-bg: rgba(255, 255, 255, 0.15);--bs-dropdown-link-active-color: #fff;--bs-dropdown-link-active-bg: #0d6efd;--bs-dropdown-link-disabled-color: #adb5bd;--bs-dropdown-header-color: #adb5bd}.btn-group,.btn-group-vertical{position:relative;display:inline-flex;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;flex:1 1 auto}.btn-group>.btn-check:checked+.btn,.btn-group>.btn-check:focus+.btn,.btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn-check:checked+.btn,.btn-group-vertical>.btn-check:focus+.btn,.btn-group-vertical>.btn:hover,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn.active{z-index:1}.btn-toolbar{display:flex;flex-wrap:wrap;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group{border-radius:20px}.btn-group>:not(.btn-check:first-child)+.btn,.btn-group>.btn-group:not(:first-child){margin-left:calc(var(--bs-border-width)*-1)}.btn-group>.btn:not(:last-child):not(.dropdown-toggle),.btn-group>.btn.dropdown-toggle-split:first-child,.btn-group>.btn-group:not(:last-child)>.btn{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:nth-child(n+3),.btn-group>:not(.btn-check)+.btn,.btn-group>.btn-group:not(:first-child)>.btn{border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-toggle-split{padding-right:18.75px;padding-left:18.75px}.dropdown-toggle-split::after,.dropup .dropdown-toggle-split::after,.dropend .dropdown-toggle-split::after{margin-left:0}.dropstart .dropdown-toggle-split::before{margin-right:0}.btn-sm+.dropdown-toggle-split,.btn-group-sm>.btn+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-lg+.dropdown-toggle-split,.btn-group-lg>.btn+.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:not(:first-child),.btn-group-vertical>.btn-group:not(:first-child){margin-top:calc(var(--bs-border-width)*-1)}.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle),.btn-group-vertical>.btn-group:not(:last-child)>.btn{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn~.btn,.btn-group-vertical>.btn-group:not(:first-child)>.btn{border-top-left-radius:0;border-top-right-radius:0}.nav{--bs-nav-link-padding-x: 1rem;--bs-nav-link-padding-y: 0.5rem;--bs-nav-link-font-weight: ;--bs-nav-link-color: var(--bs-link-color);--bs-nav-link-hover-color: var(--bs-link-hover-color);--bs-nav-link-disabled-color: var(--bs-secondary-color);display:flex;flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:var(--bs-nav-link-padding-y) var(--bs-nav-link-padding-x);font-size:var(--bs-nav-link-font-size);font-weight:var(--bs-nav-link-font-weight);color:var(--bs-nav-link-color);text-decoration:none;background:none;border:0;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:hover,.nav-link:focus{color:var(--bs-nav-link-hover-color)}.nav-link:focus-visible{outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.nav-link.disabled,.nav-link:disabled{color:var(--bs-nav-link-disabled-color);pointer-events:none;cursor:default}.nav-tabs{--bs-nav-tabs-border-width: var(--bs-border-width);--bs-nav-tabs-border-color: var(--bs-border-color);--bs-nav-tabs-border-radius: var(--bs-border-radius);--bs-nav-tabs-link-hover-border-color: var(--bs-secondary-bg) var(--bs-secondary-bg) var(--bs-border-color);--bs-nav-tabs-link-active-color: var(--bs-emphasis-color);--bs-nav-tabs-link-active-bg: var(--bs-body-bg);--bs-nav-tabs-link-active-border-color: var(--bs-border-color) var(--bs-border-color) var(--bs-body-bg);border-bottom:var(--bs-nav-tabs-border-width) solid var(--bs-nav-tabs-border-color)}.nav-tabs .nav-link{margin-bottom:calc(-1*var(--bs-nav-tabs-border-width));border:var(--bs-nav-tabs-border-width) solid rgba(0,0,0,0);border-top-left-radius:var(--bs-nav-tabs-border-radius);border-top-right-radius:var(--bs-nav-tabs-border-radius)}.nav-tabs .nav-link:hover,.nav-tabs .nav-link:focus{isolation:isolate;border-color:var(--bs-nav-tabs-link-hover-border-color)}.nav-tabs .nav-link.active,.nav-tabs .nav-item.show .nav-link{color:var(--bs-nav-tabs-link-active-color);background-color:var(--bs-nav-tabs-link-active-bg);border-color:var(--bs-nav-tabs-link-active-border-color)}.nav-tabs .dropdown-menu{margin-top:calc(-1*var(--bs-nav-tabs-border-width));border-top-left-radius:0;border-top-right-radius:0}.nav-pills{--bs-nav-pills-border-radius: var(--bs-border-radius);--bs-nav-pills-link-active-color: #fff;--bs-nav-pills-link-active-bg: #0d6efd}.nav-pills .nav-link{border-radius:var(--bs-nav-pills-border-radius)}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:var(--bs-nav-pills-link-active-color);background-color:var(--bs-nav-pills-link-active-bg)}.nav-underline{--bs-nav-underline-gap: 1rem;--bs-nav-underline-border-width: 0.125rem;--bs-nav-underline-link-active-color: var(--bs-emphasis-color);gap:var(--bs-nav-underline-gap)}.nav-underline .nav-link{padding-right:0;padding-left:0;border-bottom:var(--bs-nav-underline-border-width) solid rgba(0,0,0,0)}.nav-underline .nav-link:hover,.nav-underline .nav-link:focus{border-bottom-color:currentcolor}.nav-underline .nav-link.active,.nav-underline .show>.nav-link{font-weight:700;color:var(--bs-nav-underline-link-active-color);border-bottom-color:currentcolor}.nav-fill>.nav-link,.nav-fill .nav-item{flex:1 1 auto;text-align:center}.nav-justified>.nav-link,.nav-justified .nav-item{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{--bs-navbar-padding-x: 0;--bs-navbar-padding-y: 0.5rem;--bs-navbar-color: rgba(var(--bs-emphasis-color-rgb), 0.65);--bs-navbar-hover-color: rgba(var(--bs-emphasis-color-rgb), 0.8);--bs-navbar-disabled-color: rgba(var(--bs-emphasis-color-rgb), 0.3);--bs-navbar-active-color: rgba(var(--bs-emphasis-color-rgb), 1);--bs-navbar-brand-padding-y: 0.3125rem;--bs-navbar-brand-margin-end: 1rem;--bs-navbar-brand-font-size: 1.25rem;--bs-navbar-brand-color: rgba(var(--bs-emphasis-color-rgb), 1);--bs-navbar-brand-hover-color: rgba(var(--bs-emphasis-color-rgb), 1);--bs-navbar-nav-link-padding-x: 0.5rem;--bs-navbar-toggler-padding-y: 0.25rem;--bs-navbar-toggler-padding-x: 0.75rem;--bs-navbar-toggler-font-size: 1.25rem;--bs-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns=%27http://www.w3.org/2000/svg%27 viewBox=%270 0 30 30%27%3e%3cpath stroke=%27rgba%2833, 37, 41, 0.75%29%27 stroke-linecap=%27round%27 stroke-miterlimit=%2710%27 stroke-width=%272%27 d=%27M4 7h22M4 15h22M4 23h22%27/%3e%3c/svg%3e");--bs-navbar-toggler-border-color: rgba(var(--bs-emphasis-color-rgb), 0.15);--bs-navbar-toggler-border-radius: var(--bs-border-radius);--bs-navbar-toggler-focus-width: 0.25rem;--bs-navbar-toggler-transition: box-shadow 0.15s ease-in-out;position:relative;display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;padding:var(--bs-navbar-padding-y) var(--bs-navbar-padding-x)}.navbar>.container,.navbar>.container-fluid,.navbar>.container-sm,.navbar>.container-md,.navbar>.container-lg,.navbar>.container-xl,.navbar>.container-xxl{display:flex;flex-wrap:inherit;align-items:center;justify-content:space-between}.navbar-brand{padding-top:var(--bs-navbar-brand-padding-y);padding-bottom:var(--bs-navbar-brand-padding-y);margin-right:var(--bs-navbar-brand-margin-end);font-size:var(--bs-navbar-brand-font-size);color:var(--bs-navbar-brand-color);text-decoration:none;white-space:nowrap}.navbar-brand:hover,.navbar-brand:focus{color:var(--bs-navbar-brand-hover-color)}.navbar-nav{--bs-nav-link-padding-x: 0;--bs-nav-link-padding-y: 0.5rem;--bs-nav-link-font-weight: ;--bs-nav-link-color: var(--bs-navbar-color);--bs-nav-link-hover-color: var(--bs-navbar-hover-color);--bs-nav-link-disabled-color: var(--bs-navbar-disabled-color);display:flex;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link.active,.navbar-nav .nav-link.show{color:var(--bs-navbar-active-color)}.navbar-nav .dropdown-menu{position:static}.navbar-text{padding-top:.5rem;padding-bottom:.5rem;color:var(--bs-navbar-color)}.navbar-text a,.navbar-text a:hover,.navbar-text a:focus{color:var(--bs-navbar-active-color)}.navbar-collapse{flex-basis:100%;flex-grow:1;align-items:center}.navbar-toggler{padding:var(--bs-navbar-toggler-padding-y) var(--bs-navbar-toggler-padding-x);font-size:var(--bs-navbar-toggler-font-size);line-height:1;color:var(--bs-navbar-color);background-color:rgba(0,0,0,0);border:var(--bs-border-width) solid var(--bs-navbar-toggler-border-color);border-radius:var(--bs-navbar-toggler-border-radius);transition:var(--bs-navbar-toggler-transition)}@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 var(--bs-navbar-toggler-focus-width)}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;background-image:var(--bs-navbar-toggler-icon-bg);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:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.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}.navbar-expand-sm .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important;transition:none}.navbar-expand-sm .offcanvas .offcanvas-header{display:none}.navbar-expand-sm .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@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:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.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}.navbar-expand-md .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important;transition:none}.navbar-expand-md .offcanvas .offcanvas-header{display:none}.navbar-expand-md .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@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:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.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}.navbar-expand-lg .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important;transition:none}.navbar-expand-lg .offcanvas .offcanvas-header{display:none}.navbar-expand-lg .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@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:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.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}.navbar-expand-xl .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important;transition:none}.navbar-expand-xl .offcanvas .offcanvas-header{display:none}.navbar-expand-xl .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@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:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.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-xxl .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important;transition:none}.navbar-expand-xxl .offcanvas .offcanvas-header{display:none}.navbar-expand-xxl .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}.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:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand .navbar-nav-scroll{overflow:visible}.navbar-expand .navbar-collapse{display:flex !important;flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-expand .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto !important;height:auto !important;visibility:visible !important;background-color:rgba(0,0,0,0) !important;border:0 !important;transform:none !important;transition:none}.navbar-expand .offcanvas .offcanvas-header{display:none}.navbar-expand .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}.navbar-dark,.navbar[data-bs-theme=dark]{--bs-navbar-color: rgba(255, 255, 255, 0.55);--bs-navbar-hover-color: rgba(255, 255, 255, 0.75);--bs-navbar-disabled-color: rgba(255, 255, 255, 0.25);--bs-navbar-active-color: #fff;--bs-navbar-brand-color: #fff;--bs-navbar-brand-hover-color: #fff;--bs-navbar-toggler-border-color: rgba(255, 255, 255, 0.1);--bs-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns=%27http://www.w3.org/2000/svg%27 viewBox=%270 0 30 30%27%3e%3cpath stroke=%27rgba%28255, 255, 255, 0.55%29%27 stroke-linecap=%27round%27 stroke-miterlimit=%2710%27 stroke-width=%272%27 d=%27M4 7h22M4 15h22M4 23h22%27/%3e%3c/svg%3e")}[data-bs-theme=dark] .navbar-toggler-icon{--bs-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns=%27http://www.w3.org/2000/svg%27 viewBox=%270 0 30 30%27%3e%3cpath stroke=%27rgba%28255, 255, 255, 0.55%29%27 stroke-linecap=%27round%27 stroke-miterlimit=%2710%27 stroke-width=%272%27 d=%27M4 7h22M4 15h22M4 23h22%27/%3e%3c/svg%3e")}.card{--bs-card-spacer-y: 1rem;--bs-card-spacer-x: 1rem;--bs-card-title-spacer-y: 0.5rem;--bs-card-title-color: ;--bs-card-subtitle-color: ;--bs-card-border-width: var(--bs-border-width);--bs-card-border-color: var(--bs-border-color-translucent);--bs-card-border-radius: var(--bs-border-radius);--bs-card-box-shadow: ;--bs-card-inner-border-radius: calc(var(--bs-border-radius) - (var(--bs-border-width)));--bs-card-cap-padding-y: 0.5rem;--bs-card-cap-padding-x: 1rem;--bs-card-cap-bg: rgba(var(--bs-body-color-rgb), 0.03);--bs-card-cap-color: ;--bs-card-height: ;--bs-card-color: ;--bs-card-bg: var(--bs-body-bg);--bs-card-img-overlay-padding: 1rem;--bs-card-group-margin: 0.75rem;position:relative;display:flex;flex-direction:column;min-width:0;height:var(--bs-card-height);color:var(--bs-body-color);word-wrap:break-word;background-color:var(--bs-card-bg);background-clip:border-box;border:var(--bs-card-border-width) solid var(--bs-card-border-color);border-radius:var(--bs-card-border-radius)}.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:var(--bs-card-inner-border-radius);border-top-right-radius:var(--bs-card-inner-border-radius)}.card>.list-group:last-child{border-bottom-width:0;border-bottom-right-radius:var(--bs-card-inner-border-radius);border-bottom-left-radius:var(--bs-card-inner-border-radius)}.card>.card-header+.list-group,.card>.list-group+.card-footer{border-top:0}.card-body{flex:1 1 auto;padding:var(--bs-card-spacer-y) var(--bs-card-spacer-x);color:var(--bs-card-color)}.card-title{margin-bottom:var(--bs-card-title-spacer-y);color:var(--bs-card-title-color)}.card-subtitle{margin-top:calc(-0.5*var(--bs-card-title-spacer-y));margin-bottom:0;color:var(--bs-card-subtitle-color)}.card-text:last-child{margin-bottom:0}.card-link+.card-link{margin-left:var(--bs-card-spacer-x)}.card-header{padding:var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x);margin-bottom:0;color:var(--bs-card-cap-color);background-color:var(--bs-card-cap-bg);border-bottom:var(--bs-card-border-width) solid var(--bs-card-border-color)}.card-header:first-child{border-radius:var(--bs-card-inner-border-radius) var(--bs-card-inner-border-radius) 0 0}.card-footer{padding:var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x);color:var(--bs-card-cap-color);background-color:var(--bs-card-cap-bg);border-top:var(--bs-card-border-width) solid var(--bs-card-border-color)}.card-footer:last-child{border-radius:0 0 var(--bs-card-inner-border-radius) var(--bs-card-inner-border-radius)}.card-header-tabs{margin-right:calc(-0.5*var(--bs-card-cap-padding-x));margin-bottom:calc(-1*var(--bs-card-cap-padding-y));margin-left:calc(-0.5*var(--bs-card-cap-padding-x));border-bottom:0}.card-header-tabs .nav-link.active{background-color:var(--bs-card-bg);border-bottom-color:var(--bs-card-bg)}.card-header-pills{margin-right:calc(-0.5*var(--bs-card-cap-padding-x));margin-left:calc(-0.5*var(--bs-card-cap-padding-x))}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:var(--bs-card-img-overlay-padding);border-radius:var(--bs-card-inner-border-radius)}.card-img,.card-img-top,.card-img-bottom{width:100%}.card-img,.card-img-top{border-top-left-radius:var(--bs-card-inner-border-radius);border-top-right-radius:var(--bs-card-inner-border-radius)}.card-img,.card-img-bottom{border-bottom-right-radius:var(--bs-card-inner-border-radius);border-bottom-left-radius:var(--bs-card-inner-border-radius)}.card-group>.card{margin-bottom:var(--bs-card-group-margin)}@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-img-top,.card-group>.card:not(:last-child) .card-header{border-top-right-radius:0}.card-group>.card:not(:last-child) .card-img-bottom,.card-group>.card:not(:last-child) .card-footer{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-img-top,.card-group>.card:not(:first-child) .card-header{border-top-left-radius:0}.card-group>.card:not(:first-child) .card-img-bottom,.card-group>.card:not(:first-child) .card-footer{border-bottom-left-radius:0}}.accordion{--bs-accordion-color: var(--bs-body-color);--bs-accordion-bg: var(--bs-body-bg);--bs-accordion-transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out, border-radius 0.15s ease;--bs-accordion-border-color: var(--bs-border-color);--bs-accordion-border-width: var(--bs-border-width);--bs-accordion-border-radius: var(--bs-border-radius);--bs-accordion-inner-border-radius: calc(var(--bs-border-radius) - (var(--bs-border-width)));--bs-accordion-btn-padding-x: 1.25rem;--bs-accordion-btn-padding-y: 1rem;--bs-accordion-btn-color: var(--bs-body-color);--bs-accordion-btn-bg: var(--bs-accordion-bg);--bs-accordion-btn-icon: url("data:image/svg+xml,%3csvg xmlns=%27http://www.w3.org/2000/svg%27 viewBox=%270 0 16 16%27 fill=%27none%27 stroke=%27%23212529%27 stroke-linecap=%27round%27 stroke-linejoin=%27round%27%3e%3cpath d=%27M2 5L8 11L14 5%27/%3e%3c/svg%3e");--bs-accordion-btn-icon-width: 1.25rem;--bs-accordion-btn-icon-transform: rotate(-180deg);--bs-accordion-btn-icon-transition: transform 0.2s ease-in-out;--bs-accordion-btn-active-icon: url("data:image/svg+xml,%3csvg xmlns=%27http://www.w3.org/2000/svg%27 viewBox=%270 0 16 16%27 fill=%27none%27 stroke=%27rgb%285.2, 44, 101.2%29%27 stroke-linecap=%27round%27 stroke-linejoin=%27round%27%3e%3cpath d=%27M2 5L8 11L14 5%27/%3e%3c/svg%3e");--bs-accordion-btn-focus-box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);--bs-accordion-body-padding-x: 1.25rem;--bs-accordion-body-padding-y: 1rem;--bs-accordion-active-color: var(--bs-primary-text-emphasis);--bs-accordion-active-bg: var(--bs-primary-bg-subtle)}.accordion-button{position:relative;display:flex;align-items:center;width:100%;padding:var(--bs-accordion-btn-padding-y) var(--bs-accordion-btn-padding-x);font-size:1rem;color:var(--bs-accordion-btn-color);text-align:left;background-color:var(--bs-accordion-btn-bg);border:0;border-radius:0;overflow-anchor:none;transition:var(--bs-accordion-transition)}@media(prefers-reduced-motion: reduce){.accordion-button{transition:none}}.accordion-button:not(.collapsed){color:var(--bs-accordion-active-color);background-color:var(--bs-accordion-active-bg);box-shadow:inset 0 calc(-1*var(--bs-accordion-border-width)) 0 var(--bs-accordion-border-color)}.accordion-button:not(.collapsed)::after{background-image:var(--bs-accordion-btn-active-icon);transform:var(--bs-accordion-btn-icon-transform)}.accordion-button::after{flex-shrink:0;width:var(--bs-accordion-btn-icon-width);height:var(--bs-accordion-btn-icon-width);margin-left:auto;content:"";background-image:var(--bs-accordion-btn-icon);background-repeat:no-repeat;background-size:var(--bs-accordion-btn-icon-width);transition:var(--bs-accordion-btn-icon-transition)}@media(prefers-reduced-motion: reduce){.accordion-button::after{transition:none}}.accordion-button:hover{z-index:2}.accordion-button:focus{z-index:3;outline:0;box-shadow:var(--bs-accordion-btn-focus-box-shadow)}.accordion-header{margin-bottom:0}.accordion-item{color:var(--bs-accordion-color);background-color:var(--bs-accordion-bg);border:var(--bs-accordion-border-width) solid var(--bs-accordion-border-color)}.accordion-item:first-of-type{border-top-left-radius:var(--bs-accordion-border-radius);border-top-right-radius:var(--bs-accordion-border-radius)}.accordion-item:first-of-type>.accordion-header .accordion-button{border-top-left-radius:var(--bs-accordion-inner-border-radius);border-top-right-radius:var(--bs-accordion-inner-border-radius)}.accordion-item:not(:first-of-type){border-top:0}.accordion-item:last-of-type{border-bottom-right-radius:var(--bs-accordion-border-radius);border-bottom-left-radius:var(--bs-accordion-border-radius)}.accordion-item:last-of-type>.accordion-header .accordion-button.collapsed{border-bottom-right-radius:var(--bs-accordion-inner-border-radius);border-bottom-left-radius:var(--bs-accordion-inner-border-radius)}.accordion-item:last-of-type>.accordion-collapse{border-bottom-right-radius:var(--bs-accordion-border-radius);border-bottom-left-radius:var(--bs-accordion-border-radius)}.accordion-body{padding:var(--bs-accordion-body-padding-y) var(--bs-accordion-body-padding-x)}.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-header .accordion-button,.accordion-flush>.accordion-item>.accordion-header .accordion-button.collapsed{border-radius:0}.accordion-flush>.accordion-item>.accordion-collapse{border-radius:0}[data-bs-theme=dark] .accordion-button::after{--bs-accordion-btn-icon: url("data:image/svg+xml,%3csvg xmlns=%27http://www.w3.org/2000/svg%27 viewBox=%270 0 16 16%27 fill=%27rgb%28109.8, 168, 253.8%29%27%3e%3cpath fill-rule=%27evenodd%27 d=%27M1.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%27/%3e%3c/svg%3e");--bs-accordion-btn-active-icon: url("data:image/svg+xml,%3csvg xmlns=%27http://www.w3.org/2000/svg%27 viewBox=%270 0 16 16%27 fill=%27rgb%28109.8, 168, 253.8%29%27%3e%3cpath fill-rule=%27evenodd%27 d=%27M1.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%27/%3e%3c/svg%3e")}.breadcrumb{--bs-breadcrumb-padding-x: 0;--bs-breadcrumb-padding-y: 0;--bs-breadcrumb-margin-bottom: 1rem;--bs-breadcrumb-bg: ;--bs-breadcrumb-border-radius: ;--bs-breadcrumb-divider-color: var(--bs-secondary-color);--bs-breadcrumb-item-padding-x: 0.5rem;--bs-breadcrumb-item-active-color: var(--bs-secondary-color);display:flex;flex-wrap:wrap;padding:var(--bs-breadcrumb-padding-y) var(--bs-breadcrumb-padding-x);margin-bottom:var(--bs-breadcrumb-margin-bottom);font-size:var(--bs-breadcrumb-font-size);list-style:none;background-color:var(--bs-breadcrumb-bg);border-radius:var(--bs-breadcrumb-border-radius)}.breadcrumb-item+.breadcrumb-item{padding-left:var(--bs-breadcrumb-item-padding-x)}.breadcrumb-item+.breadcrumb-item::before{float:left;padding-right:var(--bs-breadcrumb-item-padding-x);color:var(--bs-breadcrumb-divider-color);content:var(--bs-breadcrumb-divider, "/") /* rtl: var(--bs-breadcrumb-divider, "/") */}.breadcrumb-item.active{color:var(--bs-breadcrumb-item-active-color)}.pagination{--bs-pagination-padding-x: 0.75rem;--bs-pagination-padding-y: 0.375rem;--bs-pagination-font-size:1rem;--bs-pagination-color: var(--bs-link-color);--bs-pagination-bg: var(--bs-body-bg);--bs-pagination-border-width: var(--bs-border-width);--bs-pagination-border-color: var(--bs-border-color);--bs-pagination-border-radius: var(--bs-border-radius);--bs-pagination-hover-color: var(--bs-link-hover-color);--bs-pagination-hover-bg: var(--bs-tertiary-bg);--bs-pagination-hover-border-color: var(--bs-border-color);--bs-pagination-focus-color: var(--bs-link-hover-color);--bs-pagination-focus-bg: var(--bs-secondary-bg);--bs-pagination-focus-box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);--bs-pagination-active-color: #fff;--bs-pagination-active-bg: #0d6efd;--bs-pagination-active-border-color: #0d6efd;--bs-pagination-disabled-color: var(--bs-secondary-color);--bs-pagination-disabled-bg: var(--bs-secondary-bg);--bs-pagination-disabled-border-color: var(--bs-border-color);display:flex;padding-left:0;list-style:none}.page-link{position:relative;display:block;padding:var(--bs-pagination-padding-y) var(--bs-pagination-padding-x);font-size:var(--bs-pagination-font-size);color:var(--bs-pagination-color);text-decoration:none;background-color:var(--bs-pagination-bg);border:var(--bs-pagination-border-width) solid var(--bs-pagination-border-color);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:var(--bs-pagination-hover-color);background-color:var(--bs-pagination-hover-bg);border-color:var(--bs-pagination-hover-border-color)}.page-link:focus{z-index:3;color:var(--bs-pagination-focus-color);background-color:var(--bs-pagination-focus-bg);outline:0;box-shadow:var(--bs-pagination-focus-box-shadow)}.page-link.active,.active>.page-link{z-index:3;color:var(--bs-pagination-active-color);background-color:var(--bs-pagination-active-bg);border-color:var(--bs-pagination-active-border-color)}.page-link.disabled,.disabled>.page-link{color:var(--bs-pagination-disabled-color);pointer-events:none;background-color:var(--bs-pagination-disabled-bg);border-color:var(--bs-pagination-disabled-border-color)}.page-item:not(:first-child) .page-link{margin-left:calc(var(--bs-border-width)*-1)}.page-item:first-child .page-link{border-top-left-radius:var(--bs-pagination-border-radius);border-bottom-left-radius:var(--bs-pagination-border-radius)}.page-item:last-child .page-link{border-top-right-radius:var(--bs-pagination-border-radius);border-bottom-right-radius:var(--bs-pagination-border-radius)}.pagination-lg{--bs-pagination-padding-x: 1.5rem;--bs-pagination-padding-y: 0.75rem;--bs-pagination-font-size:1.25rem;--bs-pagination-border-radius: var(--bs-border-radius-lg)}.pagination-sm{--bs-pagination-padding-x: 0.5rem;--bs-pagination-padding-y: 0.25rem;--bs-pagination-font-size:0.875rem;--bs-pagination-border-radius: var(--bs-border-radius-sm)}.badge{--bs-badge-padding-x: 0.65em;--bs-badge-padding-y: 0.35em;--bs-badge-font-size:0.75em;--bs-badge-font-weight: 700;--bs-badge-color: #fff;--bs-badge-border-radius: var(--bs-border-radius);display:inline-block;padding:var(--bs-badge-padding-y) var(--bs-badge-padding-x);font-size:var(--bs-badge-font-size);font-weight:var(--bs-badge-font-weight);line-height:1;color:var(--bs-badge-color);text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:var(--bs-badge-border-radius)}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.alert{--bs-alert-bg: transparent;--bs-alert-padding-x: 1rem;--bs-alert-padding-y: 1rem;--bs-alert-margin-bottom: 1rem;--bs-alert-color: inherit;--bs-alert-border-color: transparent;--bs-alert-border: var(--bs-border-width) solid var(--bs-alert-border-color);--bs-alert-border-radius: var(--bs-border-radius);--bs-alert-link-color: inherit;position:relative;padding:var(--bs-alert-padding-y) var(--bs-alert-padding-x);margin-bottom:var(--bs-alert-margin-bottom);color:var(--bs-alert-color);background-color:var(--bs-alert-bg);border:var(--bs-alert-border);border-radius:var(--bs-alert-border-radius)}.alert-heading{color:inherit}.alert-link{font-weight:700;color:var(--bs-alert-link-color)}.alert-dismissible{padding-right:3rem}.alert-dismissible .btn-close{position:absolute;top:0;right:0;z-index:2;padding:1.25rem 1rem}.alert-primary{--bs-alert-color: var(--bs-primary-text-emphasis);--bs-alert-bg: var(--bs-primary-bg-subtle);--bs-alert-border-color: var(--bs-primary-border-subtle);--bs-alert-link-color: var(--bs-primary-text-emphasis)}.alert-secondary{--bs-alert-color: var(--bs-secondary-text-emphasis);--bs-alert-bg: var(--bs-secondary-bg-subtle);--bs-alert-border-color: var(--bs-secondary-border-subtle);--bs-alert-link-color: var(--bs-secondary-text-emphasis)}.alert-success{--bs-alert-color: var(--bs-success-text-emphasis);--bs-alert-bg: var(--bs-success-bg-subtle);--bs-alert-border-color: var(--bs-success-border-subtle);--bs-alert-link-color: var(--bs-success-text-emphasis)}.alert-info{--bs-alert-color: var(--bs-info-text-emphasis);--bs-alert-bg: var(--bs-info-bg-subtle);--bs-alert-border-color: var(--bs-info-border-subtle);--bs-alert-link-color: var(--bs-info-text-emphasis)}.alert-warning{--bs-alert-color: var(--bs-warning-text-emphasis);--bs-alert-bg: var(--bs-warning-bg-subtle);--bs-alert-border-color: var(--bs-warning-border-subtle);--bs-alert-link-color: var(--bs-warning-text-emphasis)}.alert-danger{--bs-alert-color: var(--bs-danger-text-emphasis);--bs-alert-bg: var(--bs-danger-bg-subtle);--bs-alert-border-color: var(--bs-danger-border-subtle);--bs-alert-link-color: var(--bs-danger-text-emphasis)}.alert-light{--bs-alert-color: var(--bs-light-text-emphasis);--bs-alert-bg: var(--bs-light-bg-subtle);--bs-alert-border-color: var(--bs-light-border-subtle);--bs-alert-link-color: var(--bs-light-text-emphasis)}.alert-dark{--bs-alert-color: var(--bs-dark-text-emphasis);--bs-alert-bg: var(--bs-dark-bg-subtle);--bs-alert-border-color: var(--bs-dark-border-subtle);--bs-alert-link-color: var(--bs-dark-text-emphasis)}@keyframes progress-bar-stripes{0%{background-position-x:1rem}}.progress,.progress-stacked{--bs-progress-height: 1rem;--bs-progress-font-size:0.75rem;--bs-progress-bg: var(--bs-secondary-bg);--bs-progress-border-radius: var(--bs-border-radius);--bs-progress-box-shadow: var(--bs-box-shadow-inset);--bs-progress-bar-color: #fff;--bs-progress-bar-bg: #0d6efd;--bs-progress-bar-transition: width 0.6s ease;display:flex;height:var(--bs-progress-height);overflow:hidden;font-size:var(--bs-progress-font-size);background-color:var(--bs-progress-bg);border-radius:var(--bs-progress-border-radius)}.progress-bar{display:flex;flex-direction:column;justify-content:center;overflow:hidden;color:var(--bs-progress-bar-color);text-align:center;white-space:nowrap;background-color:var(--bs-progress-bar-bg);transition:var(--bs-progress-bar-transition)}@media(prefers-reduced-motion: reduce){.progress-bar{transition:none}}.progress-bar-striped{background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-size:var(--bs-progress-height) var(--bs-progress-height)}.progress-stacked>.progress{overflow:visible}.progress-stacked>.progress>.progress-bar{width:100%}.progress-bar-animated{animation:1s linear infinite progress-bar-stripes}@media(prefers-reduced-motion: reduce){.progress-bar-animated{animation:none}}.list-group{--bs-list-group-color: var(--bs-body-color);--bs-list-group-bg: var(--bs-body-bg);--bs-list-group-border-color: var(--bs-border-color);--bs-list-group-border-width: var(--bs-border-width);--bs-list-group-border-radius: var(--bs-border-radius);--bs-list-group-item-padding-x: 1rem;--bs-list-group-item-padding-y: 0.5rem;--bs-list-group-action-color: var(--bs-secondary-color);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-tertiary-bg);--bs-list-group-action-active-color: var(--bs-body-color);--bs-list-group-action-active-bg: var(--bs-secondary-bg);--bs-list-group-disabled-color: var(--bs-secondary-color);--bs-list-group-disabled-bg: var(--bs-body-bg);--bs-list-group-active-color: #fff;--bs-list-group-active-bg: #0d6efd;--bs-list-group-active-border-color: #0d6efd;display:flex;flex-direction:column;padding-left:0;margin-bottom:0;border-radius:var(--bs-list-group-border-radius)}.list-group-numbered{list-style-type:none;counter-reset:section}.list-group-numbered>.list-group-item::before{content:counters(section, ".") ". ";counter-increment:section}.list-group-item-action{width:100%;color:var(--bs-list-group-action-color);text-align:inherit}.list-group-item-action:hover,.list-group-item-action:focus{z-index:1;color:var(--bs-list-group-action-hover-color);text-decoration:none;background-color:var(--bs-list-group-action-hover-bg)}.list-group-item-action:active{color:var(--bs-list-group-action-active-color);background-color:var(--bs-list-group-action-active-bg)}.list-group-item{position:relative;display:block;padding:var(--bs-list-group-item-padding-y) var(--bs-list-group-item-padding-x);color:var(--bs-list-group-color);text-decoration:none;background-color:var(--bs-list-group-bg);border:var(--bs-list-group-border-width) solid var(--bs-list-group-border-color)}.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:var(--bs-list-group-disabled-color);pointer-events:none;background-color:var(--bs-list-group-disabled-bg)}.list-group-item.active{z-index:2;color:var(--bs-list-group-active-color);background-color:var(--bs-list-group-active-bg);border-color:var(--bs-list-group-active-border-color)}.list-group-item+.list-group-item{border-top-width:0}.list-group-item+.list-group-item.active{margin-top:calc(-1*var(--bs-list-group-border-width));border-top-width:var(--bs-list-group-border-width)}.list-group-horizontal{flex-direction:row}.list-group-horizontal>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);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:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}@media(min-width: 576px){.list-group-horizontal-sm{flex-direction:row}.list-group-horizontal-sm>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-sm>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);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:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-sm>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media(min-width: 768px){.list-group-horizontal-md{flex-direction:row}.list-group-horizontal-md>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-md>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);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:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-md>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media(min-width: 992px){.list-group-horizontal-lg{flex-direction:row}.list-group-horizontal-lg>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-lg>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);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:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-lg>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media(min-width: 1200px){.list-group-horizontal-xl{flex-direction:row}.list-group-horizontal-xl>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-xl>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);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:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-xl>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media(min-width: 1400px){.list-group-horizontal-xxl{flex-direction:row}.list-group-horizontal-xxl>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-xxl>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);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:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item.active{margin-left:calc(-1*var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}.list-group-flush{border-radius:0}.list-group-flush>.list-group-item{border-width:0 0 var(--bs-list-group-border-width)}.list-group-flush>.list-group-item:last-child{border-bottom-width:0}.list-group-item-primary{--bs-list-group-color: var(--bs-primary-text-emphasis);--bs-list-group-bg: var(--bs-primary-bg-subtle);--bs-list-group-border-color: var(--bs-primary-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-primary-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-primary-border-subtle);--bs-list-group-active-color: var(--bs-primary-bg-subtle);--bs-list-group-active-bg: var(--bs-primary-text-emphasis);--bs-list-group-active-border-color: var(--bs-primary-text-emphasis)}.list-group-item-secondary{--bs-list-group-color: var(--bs-secondary-text-emphasis);--bs-list-group-bg: var(--bs-secondary-bg-subtle);--bs-list-group-border-color: var(--bs-secondary-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-secondary-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-secondary-border-subtle);--bs-list-group-active-color: var(--bs-secondary-bg-subtle);--bs-list-group-active-bg: var(--bs-secondary-text-emphasis);--bs-list-group-active-border-color: var(--bs-secondary-text-emphasis)}.list-group-item-success{--bs-list-group-color: var(--bs-success-text-emphasis);--bs-list-group-bg: var(--bs-success-bg-subtle);--bs-list-group-border-color: var(--bs-success-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-success-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-success-border-subtle);--bs-list-group-active-color: var(--bs-success-bg-subtle);--bs-list-group-active-bg: var(--bs-success-text-emphasis);--bs-list-group-active-border-color: var(--bs-success-text-emphasis)}.list-group-item-info{--bs-list-group-color: var(--bs-info-text-emphasis);--bs-list-group-bg: var(--bs-info-bg-subtle);--bs-list-group-border-color: var(--bs-info-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-info-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-info-border-subtle);--bs-list-group-active-color: var(--bs-info-bg-subtle);--bs-list-group-active-bg: var(--bs-info-text-emphasis);--bs-list-group-active-border-color: var(--bs-info-text-emphasis)}.list-group-item-warning{--bs-list-group-color: var(--bs-warning-text-emphasis);--bs-list-group-bg: var(--bs-warning-bg-subtle);--bs-list-group-border-color: var(--bs-warning-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-warning-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-warning-border-subtle);--bs-list-group-active-color: var(--bs-warning-bg-subtle);--bs-list-group-active-bg: var(--bs-warning-text-emphasis);--bs-list-group-active-border-color: var(--bs-warning-text-emphasis)}.list-group-item-danger{--bs-list-group-color: var(--bs-danger-text-emphasis);--bs-list-group-bg: var(--bs-danger-bg-subtle);--bs-list-group-border-color: var(--bs-danger-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-danger-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-danger-border-subtle);--bs-list-group-active-color: var(--bs-danger-bg-subtle);--bs-list-group-active-bg: var(--bs-danger-text-emphasis);--bs-list-group-active-border-color: var(--bs-danger-text-emphasis)}.list-group-item-light{--bs-list-group-color: var(--bs-light-text-emphasis);--bs-list-group-bg: var(--bs-light-bg-subtle);--bs-list-group-border-color: var(--bs-light-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-light-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-light-border-subtle);--bs-list-group-active-color: var(--bs-light-bg-subtle);--bs-list-group-active-bg: var(--bs-light-text-emphasis);--bs-list-group-active-border-color: var(--bs-light-text-emphasis)}.list-group-item-dark{--bs-list-group-color: var(--bs-dark-text-emphasis);--bs-list-group-bg: var(--bs-dark-bg-subtle);--bs-list-group-border-color: var(--bs-dark-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-dark-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-dark-border-subtle);--bs-list-group-active-color: var(--bs-dark-bg-subtle);--bs-list-group-active-bg: var(--bs-dark-text-emphasis);--bs-list-group-active-border-color: var(--bs-dark-text-emphasis)}.btn-close{--bs-btn-close-color: #000;--bs-btn-close-bg: url("data:image/svg+xml,%3csvg xmlns=%27http://www.w3.org/2000/svg%27 viewBox=%270 0 16 16%27 fill=%27%23000%27%3e%3cpath d=%27M.293.293a1 1 0 0 1 1.414 0L8 6.586 14.293.293a1 1 0 1 1 1.414 1.414L9.414 8l6.293 6.293a1 1 0 0 1-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 0 1-1.414-1.414L6.586 8 .293 1.707a1 1 0 0 1 0-1.414z%27/%3e%3c/svg%3e");--bs-btn-close-opacity: 0.5;--bs-btn-close-hover-opacity: 0.75;--bs-btn-close-focus-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);--bs-btn-close-focus-opacity: 1;--bs-btn-close-disabled-opacity: 0.25;--bs-btn-close-white-filter: invert(1) grayscale(100%) brightness(200%);box-sizing:content-box;width:1em;height:1em;padding:.25em .25em;color:var(--bs-btn-close-color);background:rgba(0,0,0,0) var(--bs-btn-close-bg) center/1em auto no-repeat;border:0;border-radius:.375rem;opacity:var(--bs-btn-close-opacity)}.btn-close:hover{color:var(--bs-btn-close-color);text-decoration:none;opacity:var(--bs-btn-close-hover-opacity)}.btn-close:focus{outline:0;box-shadow:var(--bs-btn-close-focus-shadow);opacity:var(--bs-btn-close-focus-opacity)}.btn-close:disabled,.btn-close.disabled{pointer-events:none;user-select:none;opacity:var(--bs-btn-close-disabled-opacity)}.btn-close-white{filter:var(--bs-btn-close-white-filter)}[data-bs-theme=dark] .btn-close{filter:var(--bs-btn-close-white-filter)}.toast{--bs-toast-zindex: 1090;--bs-toast-padding-x: 0.75rem;--bs-toast-padding-y: 0.5rem;--bs-toast-spacing: 1.5rem;--bs-toast-max-width: 350px;--bs-toast-font-size:0.875rem;--bs-toast-color: ;--bs-toast-bg: rgba(var(--bs-body-bg-rgb), 0.85);--bs-toast-border-width: var(--bs-border-width);--bs-toast-border-color: var(--bs-border-color-translucent);--bs-toast-border-radius: var(--bs-border-radius);--bs-toast-box-shadow: var(--bs-box-shadow);--bs-toast-header-color: var(--bs-secondary-color);--bs-toast-header-bg: rgba(var(--bs-body-bg-rgb), 0.85);--bs-toast-header-border-color: var(--bs-border-color-translucent);width:var(--bs-toast-max-width);max-width:100%;font-size:var(--bs-toast-font-size);color:var(--bs-toast-color);pointer-events:auto;background-color:var(--bs-toast-bg);background-clip:padding-box;border:var(--bs-toast-border-width) solid var(--bs-toast-border-color);box-shadow:var(--bs-toast-box-shadow);border-radius:var(--bs-toast-border-radius)}.toast.showing{opacity:0}.toast:not(.show){display:none}.toast-container{--bs-toast-zindex: 1090;position:absolute;z-index:var(--bs-toast-zindex);width:max-content;max-width:100%;pointer-events:none}.toast-container>:not(:last-child){margin-bottom:var(--bs-toast-spacing)}.toast-header{display:flex;align-items:center;padding:var(--bs-toast-padding-y) var(--bs-toast-padding-x);color:var(--bs-toast-header-color);background-color:var(--bs-toast-header-bg);background-clip:padding-box;border-bottom:var(--bs-toast-border-width) solid var(--bs-toast-header-border-color);border-top-left-radius:calc(var(--bs-toast-border-radius) - var(--bs-toast-border-width));border-top-right-radius:calc(var(--bs-toast-border-radius) - var(--bs-toast-border-width))}.toast-header .btn-close{margin-right:calc(-0.5*var(--bs-toast-padding-x));margin-left:var(--bs-toast-padding-x)}.toast-body{padding:var(--bs-toast-padding-x);word-wrap:break-word}.modal{--bs-modal-zindex: 1055;--bs-modal-width: 500px;--bs-modal-padding: 1rem;--bs-modal-margin: 0.5rem;--bs-modal-color: ;--bs-modal-bg: var(--bs-body-bg);--bs-modal-border-color: var(--bs-border-color-translucent);--bs-modal-border-width: var(--bs-border-width);--bs-modal-border-radius: var(--bs-border-radius-lg);--bs-modal-box-shadow: var(--bs-box-shadow-sm);--bs-modal-inner-border-radius: calc(var(--bs-border-radius-lg) - (var(--bs-border-width)));--bs-modal-header-padding-x: 1rem;--bs-modal-header-padding-y: 1rem;--bs-modal-header-padding: 1rem 1rem;--bs-modal-header-border-color: var(--bs-border-color);--bs-modal-header-border-width: var(--bs-border-width);--bs-modal-title-line-height: 1.5;--bs-modal-footer-gap: 0.5rem;--bs-modal-footer-bg: ;--bs-modal-footer-border-color: var(--bs-border-color);--bs-modal-footer-border-width: var(--bs-border-width);position:fixed;top:0;left:0;z-index:var(--bs-modal-zindex);display:none;width:100%;height:100%;overflow-x:hidden;overflow-y:auto;outline:0}.modal-dialog{position:relative;width:auto;margin:var(--bs-modal-margin);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% - var(--bs-modal-margin)*2)}.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% - var(--bs-modal-margin)*2)}.modal-content{position:relative;display:flex;flex-direction:column;width:100%;color:var(--bs-modal-color);pointer-events:auto;background-color:var(--bs-modal-bg);background-clip:padding-box;border:var(--bs-modal-border-width) solid var(--bs-modal-border-color);border-radius:var(--bs-modal-border-radius);outline:0}.modal-backdrop{--bs-backdrop-zindex: 1050;--bs-backdrop-bg: #000;--bs-backdrop-opacity: 0.5;position:fixed;top:0;left:0;z-index:var(--bs-backdrop-zindex);width:100vw;height:100vh;background-color:var(--bs-backdrop-bg)}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:var(--bs-backdrop-opacity)}.modal-header{display:flex;flex-shrink:0;align-items:center;padding:var(--bs-modal-header-padding);border-bottom:var(--bs-modal-header-border-width) solid var(--bs-modal-header-border-color);border-top-left-radius:var(--bs-modal-inner-border-radius);border-top-right-radius:var(--bs-modal-inner-border-radius)}.modal-header .btn-close{padding:calc(var(--bs-modal-header-padding-y)*.5) calc(var(--bs-modal-header-padding-x)*.5);margin:calc(-0.5*var(--bs-modal-header-padding-y)) calc(-0.5*var(--bs-modal-header-padding-x)) calc(-0.5*var(--bs-modal-header-padding-y)) auto}.modal-title{margin-bottom:0;line-height:var(--bs-modal-title-line-height)}.modal-body{position:relative;flex:1 1 auto;padding:var(--bs-modal-padding)}.modal-footer{display:flex;flex-shrink:0;flex-wrap:wrap;align-items:center;justify-content:flex-end;padding:calc(var(--bs-modal-padding) - var(--bs-modal-footer-gap)*.5);background-color:var(--bs-modal-footer-bg);border-top:var(--bs-modal-footer-border-width) solid var(--bs-modal-footer-border-color);border-bottom-right-radius:var(--bs-modal-inner-border-radius);border-bottom-left-radius:var(--bs-modal-inner-border-radius)}.modal-footer>*{margin:calc(var(--bs-modal-footer-gap)*.5)}@media(min-width: 576px){.modal{--bs-modal-margin: 1.75rem;--bs-modal-box-shadow: var(--bs-box-shadow)}.modal-dialog{max-width:var(--bs-modal-width);margin-right:auto;margin-left:auto}.modal-sm{--bs-modal-width: 300px}}@media(min-width: 992px){.modal-lg,.modal-xl{--bs-modal-width: 800px}}@media(min-width: 1200px){.modal-xl{--bs-modal-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,.modal-fullscreen .modal-footer{border-radius:0}.modal-fullscreen .modal-body{overflow-y:auto}@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,.modal-fullscreen-sm-down .modal-footer{border-radius:0}.modal-fullscreen-sm-down .modal-body{overflow-y:auto}}@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,.modal-fullscreen-md-down .modal-footer{border-radius:0}.modal-fullscreen-md-down .modal-body{overflow-y:auto}}@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,.modal-fullscreen-lg-down .modal-footer{border-radius:0}.modal-fullscreen-lg-down .modal-body{overflow-y:auto}}@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,.modal-fullscreen-xl-down .modal-footer{border-radius:0}.modal-fullscreen-xl-down .modal-body{overflow-y:auto}}@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,.modal-fullscreen-xxl-down .modal-footer{border-radius:0}.modal-fullscreen-xxl-down .modal-body{overflow-y:auto}}.tooltip{--bs-tooltip-zindex: 1080;--bs-tooltip-max-width: 200px;--bs-tooltip-padding-x: 0.5rem;--bs-tooltip-padding-y: 0.25rem;--bs-tooltip-margin: ;--bs-tooltip-font-size:0.875rem;--bs-tooltip-color: var(--bs-body-bg);--bs-tooltip-bg: var(--bs-emphasis-color);--bs-tooltip-border-radius: var(--bs-border-radius);--bs-tooltip-opacity: 0.9;--bs-tooltip-arrow-width: 0.8rem;--bs-tooltip-arrow-height: 0.4rem;z-index:var(--bs-tooltip-zindex);display:block;margin:var(--bs-tooltip-margin);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;white-space:normal;word-spacing:normal;line-break:auto;font-size:var(--bs-tooltip-font-size);word-wrap:break-word;opacity:0}.tooltip.show{opacity:var(--bs-tooltip-opacity)}.tooltip .tooltip-arrow{display:block;width:var(--bs-tooltip-arrow-width);height:var(--bs-tooltip-arrow-height)}.tooltip .tooltip-arrow::before{position:absolute;content:"";border-color:rgba(0,0,0,0);border-style:solid}.bs-tooltip-top .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow{bottom:calc(-1*var(--bs-tooltip-arrow-height))}.bs-tooltip-top .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow::before{top:-1px;border-width:var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width)*.5) 0;border-top-color:var(--bs-tooltip-bg)}.bs-tooltip-end .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow{left:calc(-1*var(--bs-tooltip-arrow-height));width:var(--bs-tooltip-arrow-height);height:var(--bs-tooltip-arrow-width)}.bs-tooltip-end .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow::before{right:-1px;border-width:calc(var(--bs-tooltip-arrow-width)*.5) var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width)*.5) 0;border-right-color:var(--bs-tooltip-bg)}.bs-tooltip-bottom .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow{top:calc(-1*var(--bs-tooltip-arrow-height))}.bs-tooltip-bottom .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow::before{bottom:-1px;border-width:0 calc(var(--bs-tooltip-arrow-width)*.5) var(--bs-tooltip-arrow-height);border-bottom-color:var(--bs-tooltip-bg)}.bs-tooltip-start .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow{right:calc(-1*var(--bs-tooltip-arrow-height));width:var(--bs-tooltip-arrow-height);height:var(--bs-tooltip-arrow-width)}.bs-tooltip-start .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow::before{left:-1px;border-width:calc(var(--bs-tooltip-arrow-width)*.5) 0 calc(var(--bs-tooltip-arrow-width)*.5) var(--bs-tooltip-arrow-height);border-left-color:var(--bs-tooltip-bg)}.tooltip-inner{max-width:var(--bs-tooltip-max-width);padding:var(--bs-tooltip-padding-y) var(--bs-tooltip-padding-x);color:var(--bs-tooltip-color);text-align:center;background-color:var(--bs-tooltip-bg);border-radius:var(--bs-tooltip-border-radius)}.popover{--bs-popover-zindex: 1070;--bs-popover-max-width: 276px;--bs-popover-font-size:0.875rem;--bs-popover-bg: var(--bs-body-bg);--bs-popover-border-width: var(--bs-border-width);--bs-popover-border-color: var(--bs-border-color-translucent);--bs-popover-border-radius: var(--bs-border-radius-lg);--bs-popover-inner-border-radius: calc(var(--bs-border-radius-lg) - var(--bs-border-width));--bs-popover-box-shadow: var(--bs-box-shadow);--bs-popover-header-padding-x: 1rem;--bs-popover-header-padding-y: 0.5rem;--bs-popover-header-font-size:1rem;--bs-popover-header-color: inherit;--bs-popover-header-bg: var(--bs-secondary-bg);--bs-popover-body-padding-x: 1rem;--bs-popover-body-padding-y: 1rem;--bs-popover-body-color: var(--bs-body-color);--bs-popover-arrow-width: 1rem;--bs-popover-arrow-height: 0.5rem;--bs-popover-arrow-border: var(--bs-popover-border-color);z-index:var(--bs-popover-zindex);display:block;max-width:var(--bs-popover-max-width);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;white-space:normal;word-spacing:normal;line-break:auto;font-size:var(--bs-popover-font-size);word-wrap:break-word;background-color:var(--bs-popover-bg);background-clip:padding-box;border:var(--bs-popover-border-width) solid var(--bs-popover-border-color);border-radius:var(--bs-popover-border-radius)}.popover .popover-arrow{display:block;width:var(--bs-popover-arrow-width);height:var(--bs-popover-arrow-height)}.popover .popover-arrow::before,.popover .popover-arrow::after{position:absolute;display:block;content:"";border-color:rgba(0,0,0,0);border-style:solid;border-width:0}.bs-popover-top>.popover-arrow,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow{bottom:calc(-1*(var(--bs-popover-arrow-height)) - var(--bs-popover-border-width))}.bs-popover-top>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::before,.bs-popover-top>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::after{border-width:var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width)*.5) 0}.bs-popover-top>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::before{bottom:0;border-top-color:var(--bs-popover-arrow-border)}.bs-popover-top>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::after{bottom:var(--bs-popover-border-width);border-top-color:var(--bs-popover-bg)}.bs-popover-end>.popover-arrow,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow{left:calc(-1*(var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));width:var(--bs-popover-arrow-height);height:var(--bs-popover-arrow-width)}.bs-popover-end>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::before,.bs-popover-end>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::after{border-width:calc(var(--bs-popover-arrow-width)*.5) var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width)*.5) 0}.bs-popover-end>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::before{left:0;border-right-color:var(--bs-popover-arrow-border)}.bs-popover-end>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::after{left:var(--bs-popover-border-width);border-right-color:var(--bs-popover-bg)}.bs-popover-bottom>.popover-arrow,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow{top:calc(-1*(var(--bs-popover-arrow-height)) - var(--bs-popover-border-width))}.bs-popover-bottom>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::before,.bs-popover-bottom>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::after{border-width:0 calc(var(--bs-popover-arrow-width)*.5) var(--bs-popover-arrow-height)}.bs-popover-bottom>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::before{top:0;border-bottom-color:var(--bs-popover-arrow-border)}.bs-popover-bottom>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::after{top:var(--bs-popover-border-width);border-bottom-color:var(--bs-popover-bg)}.bs-popover-bottom .popover-header::before,.bs-popover-auto[data-popper-placement^=bottom] .popover-header::before{position:absolute;top:0;left:50%;display:block;width:var(--bs-popover-arrow-width);margin-left:calc(-0.5*var(--bs-popover-arrow-width));content:"";border-bottom:var(--bs-popover-border-width) solid var(--bs-popover-header-bg)}.bs-popover-start>.popover-arrow,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow{right:calc(-1*(var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));width:var(--bs-popover-arrow-height);height:var(--bs-popover-arrow-width)}.bs-popover-start>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::before,.bs-popover-start>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::after{border-width:calc(var(--bs-popover-arrow-width)*.5) 0 calc(var(--bs-popover-arrow-width)*.5) var(--bs-popover-arrow-height)}.bs-popover-start>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::before{right:0;border-left-color:var(--bs-popover-arrow-border)}.bs-popover-start>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::after{right:var(--bs-popover-border-width);border-left-color:var(--bs-popover-bg)}.popover-header{padding:var(--bs-popover-header-padding-y) var(--bs-popover-header-padding-x);margin-bottom:0;font-size:var(--bs-popover-header-font-size);color:var(--bs-popover-header-color);background-color:var(--bs-popover-header-bg);border-bottom:var(--bs-popover-border-width) solid var(--bs-popover-border-color);border-top-left-radius:var(--bs-popover-inner-border-radius);border-top-right-radius:var(--bs-popover-inner-border-radius)}.popover-header:empty{display:none}.popover-body{padding:var(--bs-popover-body-padding-y) var(--bs-popover-body-padding-x);color:var(--bs-popover-body-color)}.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%;backface-visibility:hidden;transition:transform .6s ease-in-out}@media(prefers-reduced-motion: reduce){.carousel-item{transition:none}}.carousel-item.active,.carousel-item-next,.carousel-item-prev{display:block}.carousel-item-next:not(.carousel-item-start),.active.carousel-item-end{transform:translateX(100%)}.carousel-item-prev:not(.carousel-item-end),.active.carousel-item-start{transform:translateX(-100%)}.carousel-fade .carousel-item{opacity:0;transition-property:opacity;transform:none}.carousel-fade .carousel-item.active,.carousel-fade .carousel-item-next.carousel-item-start,.carousel-fade .carousel-item-prev.carousel-item-end{z-index:1;opacity:1}.carousel-fade .active.carousel-item-start,.carousel-fade .active.carousel-item-end{z-index:0;opacity:0;transition:opacity 0s .6s}@media(prefers-reduced-motion: reduce){.carousel-fade .active.carousel-item-start,.carousel-fade .active.carousel-item-end{transition:none}}.carousel-control-prev,.carousel-control-next{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:none;border:0;opacity:.5;transition:opacity .15s ease}@media(prefers-reduced-motion: reduce){.carousel-control-prev,.carousel-control-next{transition:none}}.carousel-control-prev:hover,.carousel-control-prev:focus,.carousel-control-next:hover,.carousel-control-next:focus{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-prev-icon,.carousel-control-next-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=%27http://www.w3.org/2000/svg%27 viewBox=%270 0 16 16%27 fill=%27%23fff%27%3e%3cpath d=%27M11.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%27/%3e%3c/svg%3e") /*rtl: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-control-next-icon{background-image:url("data:image/svg+xml,%3csvg xmlns=%27http://www.w3.org/2000/svg%27 viewBox=%270 0 16 16%27 fill=%27%23fff%27%3e%3cpath d=%27M4.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%27/%3e%3c/svg%3e") /*rtl: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-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%}.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 rgba(0,0,0,0);border-bottom:10px solid rgba(0,0,0,0);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-prev-icon,.carousel-dark .carousel-control-next-icon{filter:invert(1) grayscale(100)}.carousel-dark .carousel-indicators [data-bs-target]{background-color:#000}.carousel-dark .carousel-caption{color:#000}[data-bs-theme=dark] .carousel .carousel-control-prev-icon,[data-bs-theme=dark] .carousel .carousel-control-next-icon,[data-bs-theme=dark].carousel .carousel-control-prev-icon,[data-bs-theme=dark].carousel .carousel-control-next-icon{filter:invert(1) grayscale(100)}[data-bs-theme=dark] .carousel .carousel-indicators [data-bs-target],[data-bs-theme=dark].carousel .carousel-indicators [data-bs-target]{background-color:#000}[data-bs-theme=dark] .carousel .carousel-caption,[data-bs-theme=dark].carousel .carousel-caption{color:#000}.spinner-grow,.spinner-border{display:inline-block;width:var(--bs-spinner-width);height:var(--bs-spinner-height);vertical-align:var(--bs-spinner-vertical-align);border-radius:50%;animation:var(--bs-spinner-animation-speed) linear infinite var(--bs-spinner-animation-name)}@keyframes spinner-border{to{transform:rotate(360deg) /* rtl:ignore */}}.spinner-border{--bs-spinner-width: 2rem;--bs-spinner-height: 2rem;--bs-spinner-vertical-align: -0.125em;--bs-spinner-border-width: 0.25em;--bs-spinner-animation-speed: 0.75s;--bs-spinner-animation-name: spinner-border;border:var(--bs-spinner-border-width) solid currentcolor;border-right-color:rgba(0,0,0,0)}.spinner-border-sm{--bs-spinner-width: 1rem;--bs-spinner-height: 1rem;--bs-spinner-border-width: 0.2em}@keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}.spinner-grow{--bs-spinner-width: 2rem;--bs-spinner-height: 2rem;--bs-spinner-vertical-align: -0.125em;--bs-spinner-animation-speed: 0.75s;--bs-spinner-animation-name: spinner-grow;background-color:currentcolor;opacity:0}.spinner-grow-sm{--bs-spinner-width: 1rem;--bs-spinner-height: 1rem}@media(prefers-reduced-motion: reduce){.spinner-border,.spinner-grow{--bs-spinner-animation-speed: 1.5s}}.offcanvas,.offcanvas-xxl,.offcanvas-xl,.offcanvas-lg,.offcanvas-md,.offcanvas-sm{--bs-offcanvas-zindex: 1045;--bs-offcanvas-width: 400px;--bs-offcanvas-height: 30vh;--bs-offcanvas-padding-x: 1rem;--bs-offcanvas-padding-y: 1rem;--bs-offcanvas-color: var(--bs-body-color);--bs-offcanvas-bg: var(--bs-body-bg);--bs-offcanvas-border-width: var(--bs-border-width);--bs-offcanvas-border-color: var(--bs-border-color-translucent);--bs-offcanvas-box-shadow: var(--bs-box-shadow-sm);--bs-offcanvas-transition: transform 0.3s ease-in-out;--bs-offcanvas-title-line-height: 1.5}@media(max-width: 575.98px){.offcanvas-sm{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media(max-width: 575.98px)and (prefers-reduced-motion: reduce){.offcanvas-sm{transition:none}}@media(max-width: 575.98px){.offcanvas-sm.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-sm.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-sm.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-sm.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-sm.showing,.offcanvas-sm.show:not(.hiding){transform:none}.offcanvas-sm.showing,.offcanvas-sm.hiding,.offcanvas-sm.show{visibility:visible}}@media(min-width: 576px){.offcanvas-sm{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:rgba(0,0,0,0) !important}.offcanvas-sm .offcanvas-header{display:none}.offcanvas-sm .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:rgba(0,0,0,0) !important}}@media(max-width: 767.98px){.offcanvas-md{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media(max-width: 767.98px)and (prefers-reduced-motion: reduce){.offcanvas-md{transition:none}}@media(max-width: 767.98px){.offcanvas-md.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-md.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-md.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-md.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-md.showing,.offcanvas-md.show:not(.hiding){transform:none}.offcanvas-md.showing,.offcanvas-md.hiding,.offcanvas-md.show{visibility:visible}}@media(min-width: 768px){.offcanvas-md{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:rgba(0,0,0,0) !important}.offcanvas-md .offcanvas-header{display:none}.offcanvas-md .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:rgba(0,0,0,0) !important}}@media(max-width: 991.98px){.offcanvas-lg{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media(max-width: 991.98px)and (prefers-reduced-motion: reduce){.offcanvas-lg{transition:none}}@media(max-width: 991.98px){.offcanvas-lg.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-lg.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-lg.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-lg.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-lg.showing,.offcanvas-lg.show:not(.hiding){transform:none}.offcanvas-lg.showing,.offcanvas-lg.hiding,.offcanvas-lg.show{visibility:visible}}@media(min-width: 992px){.offcanvas-lg{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:rgba(0,0,0,0) !important}.offcanvas-lg .offcanvas-header{display:none}.offcanvas-lg .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:rgba(0,0,0,0) !important}}@media(max-width: 1199.98px){.offcanvas-xl{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media(max-width: 1199.98px)and (prefers-reduced-motion: reduce){.offcanvas-xl{transition:none}}@media(max-width: 1199.98px){.offcanvas-xl.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-xl.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-xl.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-xl.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-xl.showing,.offcanvas-xl.show:not(.hiding){transform:none}.offcanvas-xl.showing,.offcanvas-xl.hiding,.offcanvas-xl.show{visibility:visible}}@media(min-width: 1200px){.offcanvas-xl{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:rgba(0,0,0,0) !important}.offcanvas-xl .offcanvas-header{display:none}.offcanvas-xl .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:rgba(0,0,0,0) !important}}@media(max-width: 1399.98px){.offcanvas-xxl{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media(max-width: 1399.98px)and (prefers-reduced-motion: reduce){.offcanvas-xxl{transition:none}}@media(max-width: 1399.98px){.offcanvas-xxl.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-xxl.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-xxl.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-xxl.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-xxl.showing,.offcanvas-xxl.show:not(.hiding){transform:none}.offcanvas-xxl.showing,.offcanvas-xxl.hiding,.offcanvas-xxl.show{visibility:visible}}@media(min-width: 1400px){.offcanvas-xxl{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:rgba(0,0,0,0) !important}.offcanvas-xxl .offcanvas-header{display:none}.offcanvas-xxl .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:rgba(0,0,0,0) !important}}.offcanvas{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}@media(prefers-reduced-motion: reduce){.offcanvas{transition:none}}.offcanvas.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas.showing,.offcanvas.show:not(.hiding){transform:none}.offcanvas.showing,.offcanvas.hiding,.offcanvas.show{visibility:visible}.offcanvas-backdrop{position:fixed;top:0;left:0;z-index:1040;width:100vw;height:100vh;background-color:#000}.offcanvas-backdrop.fade{opacity:0}.offcanvas-backdrop.show{opacity:.5}.offcanvas-header{display:flex;align-items:center;padding:var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x)}.offcanvas-header .btn-close{padding:calc(var(--bs-offcanvas-padding-y)*.5) calc(var(--bs-offcanvas-padding-x)*.5);margin:calc(-0.5*var(--bs-offcanvas-padding-y)) calc(-0.5*var(--bs-offcanvas-padding-x)) calc(-0.5*var(--bs-offcanvas-padding-y)) auto}.offcanvas-title{margin-bottom:0;line-height:var(--bs-offcanvas-title-line-height)}.offcanvas-body{flex-grow:1;padding:var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x);overflow-y:auto}.placeholder{display:inline-block;min-height:1em;vertical-align:middle;cursor:wait;background-color:currentcolor;opacity:.5}.placeholder.btn::before{display:inline-block;content:""}.placeholder-xs{min-height:.6em}.placeholder-sm{min-height:.8em}.placeholder-lg{min-height:1.2em}.placeholder-glow .placeholder{animation:placeholder-glow 2s ease-in-out infinite}@keyframes placeholder-glow{50%{opacity:.2}}.placeholder-wave{mask-image:linear-gradient(130deg, #333333 55%, rgba(0, 0, 0, 0.8) 75%, #333333 95%);mask-size:200% 100%;animation:placeholder-wave 2s linear infinite}@keyframes placeholder-wave{100%{mask-position:-200% 0%}}.clearfix::after{display:block;clear:both;content:""}.text-bg-primary{color:#fff !important;background-color:RGBA(var(--bs-primary-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-secondary{color:#fff !important;background-color:RGBA(var(--bs-secondary-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-success{color:#fff !important;background-color:RGBA(var(--bs-success-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-info{color:#000 !important;background-color:RGBA(var(--bs-info-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-warning{color:#000 !important;background-color:RGBA(var(--bs-warning-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-danger{color:#fff !important;background-color:RGBA(var(--bs-danger-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-light{color:#000 !important;background-color:RGBA(var(--bs-light-rgb), var(--bs-bg-opacity, 1)) !important}.text-bg-dark{color:#fff !important;background-color:RGBA(var(--bs-dark-rgb), var(--bs-bg-opacity, 1)) !important}.link-primary{color:RGBA(var(--bs-primary-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-primary-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-primary:hover,.link-primary:focus{color:RGBA(10, 88, 202, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(10, 88, 202, var(--bs-link-underline-opacity, 1)) !important}.link-secondary{color:RGBA(var(--bs-secondary-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-secondary-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-secondary:hover,.link-secondary:focus{color:RGBA(86, 94, 100, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(86, 94, 100, var(--bs-link-underline-opacity, 1)) !important}.link-success{color:RGBA(var(--bs-success-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-success-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-success:hover,.link-success:focus{color:RGBA(20, 108, 67, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(20, 108, 67, var(--bs-link-underline-opacity, 1)) !important}.link-info{color:RGBA(var(--bs-info-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-info-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-info:hover,.link-info:focus{color:RGBA(61, 213, 243, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(61, 213, 243, var(--bs-link-underline-opacity, 1)) !important}.link-warning{color:RGBA(var(--bs-warning-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-warning-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-warning:hover,.link-warning:focus{color:RGBA(255, 205, 57, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(255, 205, 57, var(--bs-link-underline-opacity, 1)) !important}.link-danger{color:RGBA(var(--bs-danger-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-danger-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-danger:hover,.link-danger:focus{color:RGBA(176, 42, 55, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(176, 42, 55, var(--bs-link-underline-opacity, 1)) !important}.link-light{color:RGBA(var(--bs-light-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-light-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-light:hover,.link-light:focus{color:RGBA(249, 250, 251, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(249, 250, 251, var(--bs-link-underline-opacity, 1)) !important}.link-dark{color:RGBA(var(--bs-dark-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-dark-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-dark:hover,.link-dark:focus{color:RGBA(26, 30, 33, var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(26, 30, 33, var(--bs-link-underline-opacity, 1)) !important}.link-body-emphasis{color:RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-opacity, 1)) !important;text-decoration-color:RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-body-emphasis:hover,.link-body-emphasis:focus{color:RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-opacity, 0.75)) !important;text-decoration-color:RGBA(var(--bs-emphasis-color-rgb), var(--bs-link-underline-opacity, 0.75)) !important}.focus-ring:focus{outline:0;box-shadow:var(--bs-focus-ring-x, 0) var(--bs-focus-ring-y, 0) var(--bs-focus-ring-blur, 0) var(--bs-focus-ring-width) var(--bs-focus-ring-color)}.icon-link{display:inline-flex;gap:.375rem;align-items:center;text-decoration-color:rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 0.5));text-underline-offset:.25em;backface-visibility:hidden}.icon-link>.bi{flex-shrink:0;width:1em;height:1em;fill:currentcolor;transition:.2s ease-in-out transform}@media(prefers-reduced-motion: reduce){.icon-link>.bi{transition:none}}.icon-link-hover:hover>.bi,.icon-link-hover:focus-visible>.bi{transform:var(--bs-icon-link-transform, translate3d(0.25em, 0, 0))}.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: 75%}.ratio-16x9{--bs-aspect-ratio: 56.25%}.ratio-21x9{--bs-aspect-ratio: 42.8571428571%}.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:sticky;top:0;z-index:1020}.sticky-bottom{position:sticky;bottom:0;z-index:1020}@media(min-width: 576px){.sticky-sm-top{position:sticky;top:0;z-index:1020}.sticky-sm-bottom{position:sticky;bottom:0;z-index:1020}}@media(min-width: 768px){.sticky-md-top{position:sticky;top:0;z-index:1020}.sticky-md-bottom{position:sticky;bottom:0;z-index:1020}}@media(min-width: 992px){.sticky-lg-top{position:sticky;top:0;z-index:1020}.sticky-lg-bottom{position:sticky;bottom:0;z-index:1020}}@media(min-width: 1200px){.sticky-xl-top{position:sticky;top:0;z-index:1020}.sticky-xl-bottom{position:sticky;bottom:0;z-index:1020}}@media(min-width: 1400px){.sticky-xxl-top{position:sticky;top:0;z-index:1020}.sticky-xxl-bottom{position:sticky;bottom:0;z-index:1020}}.hstack{display:flex;flex-direction:row;align-items:center;align-self:stretch}.vstack{display:flex;flex:1 1 auto;flex-direction:column;align-self:stretch}.visually-hidden,.visually-hidden-focusable:not(:focus):not(:focus-within){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}.visually-hidden:not(caption),.visually-hidden-focusable:not(:focus):not(:focus-within):not(caption){position:absolute !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}.vr{display:inline-block;align-self:stretch;width:var(--bs-border-width);min-height:1em;background-color:currentcolor;opacity:.25}.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}.object-fit-contain{object-fit:contain !important}.object-fit-cover{object-fit:cover !important}.object-fit-fill{object-fit:fill !important}.object-fit-scale{object-fit:scale-down !important}.object-fit-none{object-fit:none !important}.opacity-0{opacity:0 !important}.opacity-25{opacity:.25 !important}.opacity-50{opacity:.5 !important}.opacity-75{opacity:.75 !important}.opacity-100{opacity:1 !important}.overflow-auto{overflow:auto !important}.overflow-hidden{overflow:hidden !important}.overflow-visible{overflow:visible !important}.overflow-scroll{overflow:scroll !important}.overflow-x-auto{overflow-x:auto !important}.overflow-x-hidden{overflow-x:hidden !important}.overflow-x-visible{overflow-x:visible !important}.overflow-x-scroll{overflow-x:scroll !important}.overflow-y-auto{overflow-y:auto !important}.overflow-y-hidden{overflow-y:hidden !important}.overflow-y-visible{overflow-y:visible !important}.overflow-y-scroll{overflow-y: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-inline-grid{display:inline-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:var(--bs-box-shadow) !important}.shadow-sm{box-shadow:var(--bs-box-shadow-sm) !important}.shadow-lg{box-shadow:var(--bs-box-shadow-lg) !important}.shadow-none{box-shadow:none !important}.focus-ring-primary{--bs-focus-ring-color: rgba(var(--bs-primary-rgb), var(--bs-focus-ring-opacity))}.focus-ring-secondary{--bs-focus-ring-color: rgba(var(--bs-secondary-rgb), var(--bs-focus-ring-opacity))}.focus-ring-success{--bs-focus-ring-color: rgba(var(--bs-success-rgb), var(--bs-focus-ring-opacity))}.focus-ring-info{--bs-focus-ring-color: rgba(var(--bs-info-rgb), var(--bs-focus-ring-opacity))}.focus-ring-warning{--bs-focus-ring-color: rgba(var(--bs-warning-rgb), var(--bs-focus-ring-opacity))}.focus-ring-danger{--bs-focus-ring-color: rgba(var(--bs-danger-rgb), var(--bs-focus-ring-opacity))}.focus-ring-light{--bs-focus-ring-color: rgba(var(--bs-light-rgb), var(--bs-focus-ring-opacity))}.focus-ring-dark{--bs-focus-ring-color: rgba(var(--bs-dark-rgb), var(--bs-focus-ring-opacity))}.position-static{position:static !important}.position-relative{position:relative !important}.position-absolute{position:absolute !important}.position-fixed{position:fixed !important}.position-sticky{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:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important}.border-0{border:0 !important}.border-top{border-top:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important}.border-top-0{border-top:0 !important}.border-end{border-right:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important}.border-end-0{border-right:0 !important}.border-bottom{border-bottom:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important}.border-bottom-0{border-bottom:0 !important}.border-start{border-left:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important}.border-start-0{border-left:0 !important}.border-primary{--bs-border-opacity: 1;border-color:rgba(var(--bs-primary-rgb), var(--bs-border-opacity)) !important}.border-secondary{--bs-border-opacity: 1;border-color:rgba(var(--bs-secondary-rgb), var(--bs-border-opacity)) !important}.border-success{--bs-border-opacity: 1;border-color:rgba(var(--bs-success-rgb), var(--bs-border-opacity)) !important}.border-info{--bs-border-opacity: 1;border-color:rgba(var(--bs-info-rgb), var(--bs-border-opacity)) !important}.border-warning{--bs-border-opacity: 1;border-color:rgba(var(--bs-warning-rgb), var(--bs-border-opacity)) !important}.border-danger{--bs-border-opacity: 1;border-color:rgba(var(--bs-danger-rgb), var(--bs-border-opacity)) !important}.border-light{--bs-border-opacity: 1;border-color:rgba(var(--bs-light-rgb), var(--bs-border-opacity)) !important}.border-dark{--bs-border-opacity: 1;border-color:rgba(var(--bs-dark-rgb), var(--bs-border-opacity)) !important}.border-black{--bs-border-opacity: 1;border-color:rgba(var(--bs-black-rgb), var(--bs-border-opacity)) !important}.border-white{--bs-border-opacity: 1;border-color:rgba(var(--bs-white-rgb), var(--bs-border-opacity)) !important}.border-primary-subtle{border-color:var(--bs-primary-border-subtle) !important}.border-secondary-subtle{border-color:var(--bs-secondary-border-subtle) !important}.border-success-subtle{border-color:var(--bs-success-border-subtle) !important}.border-info-subtle{border-color:var(--bs-info-border-subtle) !important}.border-warning-subtle{border-color:var(--bs-warning-border-subtle) !important}.border-danger-subtle{border-color:var(--bs-danger-border-subtle) !important}.border-light-subtle{border-color:var(--bs-light-border-subtle) !important}.border-dark-subtle{border-color:var(--bs-dark-border-subtle) !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}.border-opacity-10{--bs-border-opacity: 0.1}.border-opacity-25{--bs-border-opacity: 0.25}.border-opacity-50{--bs-border-opacity: 0.5}.border-opacity-75{--bs-border-opacity: 0.75}.border-opacity-100{--bs-border-opacity: 1}.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}.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}.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}.row-gap-0{row-gap:0 !important}.row-gap-1{row-gap:.25rem !important}.row-gap-2{row-gap:.5rem !important}.row-gap-3{row-gap:1rem !important}.row-gap-4{row-gap:1.5rem !important}.row-gap-5{row-gap:3rem !important}.column-gap-0{column-gap:0 !important}.column-gap-1{column-gap:.25rem !important}.column-gap-2{column-gap:.5rem !important}.column-gap-3{column-gap:1rem !important}.column-gap-4{column-gap:1.5rem !important}.column-gap-5{column-gap: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 + 0.9vw) !important}.fs-3{font-size:calc(1.3rem + 0.6vw) !important}.fs-4{font-size:calc(1.275rem + 0.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-lighter{font-weight:lighter !important}.fw-light{font-weight:300 !important}.fw-normal{font-weight:400 !important}.fw-medium{font-weight:500 !important}.fw-semibold{font-weight:600 !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{--bs-text-opacity: 1;color:rgba(var(--bs-primary-rgb), var(--bs-text-opacity)) !important}.text-secondary{--bs-text-opacity: 1;color:rgba(var(--bs-secondary-rgb), var(--bs-text-opacity)) !important}.text-success{--bs-text-opacity: 1;color:rgba(var(--bs-success-rgb), var(--bs-text-opacity)) !important}.text-info{--bs-text-opacity: 1;color:rgba(var(--bs-info-rgb), var(--bs-text-opacity)) !important}.text-warning{--bs-text-opacity: 1;color:rgba(var(--bs-warning-rgb), var(--bs-text-opacity)) !important}.text-danger{--bs-text-opacity: 1;color:rgba(var(--bs-danger-rgb), var(--bs-text-opacity)) !important}.text-light{--bs-text-opacity: 1;color:rgba(var(--bs-light-rgb), var(--bs-text-opacity)) !important}.text-dark{--bs-text-opacity: 1;color:rgba(var(--bs-dark-rgb), var(--bs-text-opacity)) !important}.text-black{--bs-text-opacity: 1;color:rgba(var(--bs-black-rgb), var(--bs-text-opacity)) !important}.text-white{--bs-text-opacity: 1;color:rgba(var(--bs-white-rgb), var(--bs-text-opacity)) !important}.text-body{--bs-text-opacity: 1;color:rgba(var(--bs-body-color-rgb), var(--bs-text-opacity)) !important}.text-muted{--bs-text-opacity: 1;color:var(--bs-secondary-color) !important}.text-black-50{--bs-text-opacity: 1;color:rgba(51,51,51,.5) !important}.text-white-50{--bs-text-opacity: 1;color:hsla(0,0%,100%,.5) !important}.text-body-secondary{--bs-text-opacity: 1;color:var(--bs-secondary-color) !important}.text-body-tertiary{--bs-text-opacity: 1;color:var(--bs-tertiary-color) !important}.text-body-emphasis{--bs-text-opacity: 1;color:var(--bs-emphasis-color) !important}.text-reset{--bs-text-opacity: 1;color:inherit !important}.text-opacity-25{--bs-text-opacity: 0.25}.text-opacity-50{--bs-text-opacity: 0.5}.text-opacity-75{--bs-text-opacity: 0.75}.text-opacity-100{--bs-text-opacity: 1}.text-primary-emphasis{color:var(--bs-primary-text-emphasis) !important}.text-secondary-emphasis{color:var(--bs-secondary-text-emphasis) !important}.text-success-emphasis{color:var(--bs-success-text-emphasis) !important}.text-info-emphasis{color:var(--bs-info-text-emphasis) !important}.text-warning-emphasis{color:var(--bs-warning-text-emphasis) !important}.text-danger-emphasis{color:var(--bs-danger-text-emphasis) !important}.text-light-emphasis{color:var(--bs-light-text-emphasis) !important}.text-dark-emphasis{color:var(--bs-dark-text-emphasis) !important}.link-opacity-10{--bs-link-opacity: 0.1}.link-opacity-10-hover:hover{--bs-link-opacity: 0.1}.link-opacity-25{--bs-link-opacity: 0.25}.link-opacity-25-hover:hover{--bs-link-opacity: 0.25}.link-opacity-50{--bs-link-opacity: 0.5}.link-opacity-50-hover:hover{--bs-link-opacity: 0.5}.link-opacity-75{--bs-link-opacity: 0.75}.link-opacity-75-hover:hover{--bs-link-opacity: 0.75}.link-opacity-100{--bs-link-opacity: 1}.link-opacity-100-hover:hover{--bs-link-opacity: 1}.link-offset-1{text-underline-offset:.125em !important}.link-offset-1-hover:hover{text-underline-offset:.125em !important}.link-offset-2{text-underline-offset:.25em !important}.link-offset-2-hover:hover{text-underline-offset:.25em !important}.link-offset-3{text-underline-offset:.375em !important}.link-offset-3-hover:hover{text-underline-offset:.375em !important}.link-underline-primary{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-primary-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-secondary{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-secondary-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-success{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-success-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-info{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-info-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-warning{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-warning-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-danger{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-danger-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-light{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-light-rgb), var(--bs-link-underline-opacity)) !important}.link-underline-dark{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-dark-rgb), var(--bs-link-underline-opacity)) !important}.link-underline{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-link-color-rgb), var(--bs-link-underline-opacity, 1)) !important}.link-underline-opacity-0{--bs-link-underline-opacity: 0}.link-underline-opacity-0-hover:hover{--bs-link-underline-opacity: 0}.link-underline-opacity-10{--bs-link-underline-opacity: 0.1}.link-underline-opacity-10-hover:hover{--bs-link-underline-opacity: 0.1}.link-underline-opacity-25{--bs-link-underline-opacity: 0.25}.link-underline-opacity-25-hover:hover{--bs-link-underline-opacity: 0.25}.link-underline-opacity-50{--bs-link-underline-opacity: 0.5}.link-underline-opacity-50-hover:hover{--bs-link-underline-opacity: 0.5}.link-underline-opacity-75{--bs-link-underline-opacity: 0.75}.link-underline-opacity-75-hover:hover{--bs-link-underline-opacity: 0.75}.link-underline-opacity-100{--bs-link-underline-opacity: 1}.link-underline-opacity-100-hover:hover{--bs-link-underline-opacity: 1}.bg-primary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-primary-rgb), var(--bs-bg-opacity)) !important}.bg-secondary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-secondary-rgb), var(--bs-bg-opacity)) !important}.bg-success{--bs-bg-opacity: 1;background-color:rgba(var(--bs-success-rgb), var(--bs-bg-opacity)) !important}.bg-info{--bs-bg-opacity: 1;background-color:rgba(var(--bs-info-rgb), var(--bs-bg-opacity)) !important}.bg-warning{--bs-bg-opacity: 1;background-color:rgba(var(--bs-warning-rgb), var(--bs-bg-opacity)) !important}.bg-danger{--bs-bg-opacity: 1;background-color:rgba(var(--bs-danger-rgb), var(--bs-bg-opacity)) !important}.bg-light{--bs-bg-opacity: 1;background-color:rgba(var(--bs-light-rgb), var(--bs-bg-opacity)) !important}.bg-dark{--bs-bg-opacity: 1;background-color:rgba(var(--bs-dark-rgb), var(--bs-bg-opacity)) !important}.bg-black{--bs-bg-opacity: 1;background-color:rgba(var(--bs-black-rgb), var(--bs-bg-opacity)) !important}.bg-white{--bs-bg-opacity: 1;background-color:rgba(var(--bs-white-rgb), var(--bs-bg-opacity)) !important}.bg-body{--bs-bg-opacity: 1;background-color:rgba(var(--bs-body-bg-rgb), var(--bs-bg-opacity)) !important}.bg-transparent{--bs-bg-opacity: 1;background-color:rgba(0,0,0,0) !important}.bg-body-secondary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-secondary-bg-rgb), var(--bs-bg-opacity)) !important}.bg-body-tertiary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-tertiary-bg-rgb), var(--bs-bg-opacity)) !important}.bg-opacity-10{--bs-bg-opacity: 0.1}.bg-opacity-25{--bs-bg-opacity: 0.25}.bg-opacity-50{--bs-bg-opacity: 0.5}.bg-opacity-75{--bs-bg-opacity: 0.75}.bg-opacity-100{--bs-bg-opacity: 1}.bg-primary-subtle{background-color:var(--bs-primary-bg-subtle) !important}.bg-secondary-subtle{background-color:var(--bs-secondary-bg-subtle) !important}.bg-success-subtle{background-color:var(--bs-success-bg-subtle) !important}.bg-info-subtle{background-color:var(--bs-info-bg-subtle) !important}.bg-warning-subtle{background-color:var(--bs-warning-bg-subtle) !important}.bg-danger-subtle{background-color:var(--bs-danger-bg-subtle) !important}.bg-light-subtle{background-color:var(--bs-light-bg-subtle) !important}.bg-dark-subtle{background-color:var(--bs-dark-bg-subtle) !important}.bg-gradient{background-image:var(--bs-gradient) !important}.user-select-all{user-select:all !important}.user-select-auto{user-select:auto !important}.user-select-none{user-select:none !important}.pe-none{pointer-events:none !important}.pe-auto{pointer-events:auto !important}.rounded{border-radius:var(--bs-border-radius) !important}.rounded-0{border-radius:0 !important}.rounded-1{border-radius:var(--bs-border-radius-sm) !important}.rounded-2{border-radius:var(--bs-border-radius) !important}.rounded-3{border-radius:var(--bs-border-radius-lg) !important}.rounded-4{border-radius:var(--bs-border-radius-xl) !important}.rounded-5{border-radius:var(--bs-border-radius-xxl) !important}.rounded-circle{border-radius:50% !important}.rounded-pill{border-radius:var(--bs-border-radius-pill) !important}.rounded-top{border-top-left-radius:var(--bs-border-radius) !important;border-top-right-radius:var(--bs-border-radius) !important}.rounded-top-0{border-top-left-radius:0 !important;border-top-right-radius:0 !important}.rounded-top-1{border-top-left-radius:var(--bs-border-radius-sm) !important;border-top-right-radius:var(--bs-border-radius-sm) !important}.rounded-top-2{border-top-left-radius:var(--bs-border-radius) !important;border-top-right-radius:var(--bs-border-radius) !important}.rounded-top-3{border-top-left-radius:var(--bs-border-radius-lg) !important;border-top-right-radius:var(--bs-border-radius-lg) !important}.rounded-top-4{border-top-left-radius:var(--bs-border-radius-xl) !important;border-top-right-radius:var(--bs-border-radius-xl) !important}.rounded-top-5{border-top-left-radius:var(--bs-border-radius-xxl) !important;border-top-right-radius:var(--bs-border-radius-xxl) !important}.rounded-top-circle{border-top-left-radius:50% !important;border-top-right-radius:50% !important}.rounded-top-pill{border-top-left-radius:var(--bs-border-radius-pill) !important;border-top-right-radius:var(--bs-border-radius-pill) !important}.rounded-end{border-top-right-radius:var(--bs-border-radius) !important;border-bottom-right-radius:var(--bs-border-radius) !important}.rounded-end-0{border-top-right-radius:0 !important;border-bottom-right-radius:0 !important}.rounded-end-1{border-top-right-radius:var(--bs-border-radius-sm) !important;border-bottom-right-radius:var(--bs-border-radius-sm) !important}.rounded-end-2{border-top-right-radius:var(--bs-border-radius) !important;border-bottom-right-radius:var(--bs-border-radius) !important}.rounded-end-3{border-top-right-radius:var(--bs-border-radius-lg) !important;border-bottom-right-radius:var(--bs-border-radius-lg) !important}.rounded-end-4{border-top-right-radius:var(--bs-border-radius-xl) !important;border-bottom-right-radius:var(--bs-border-radius-xl) !important}.rounded-end-5{border-top-right-radius:var(--bs-border-radius-xxl) !important;border-bottom-right-radius:var(--bs-border-radius-xxl) !important}.rounded-end-circle{border-top-right-radius:50% !important;border-bottom-right-radius:50% !important}.rounded-end-pill{border-top-right-radius:var(--bs-border-radius-pill) !important;border-bottom-right-radius:var(--bs-border-radius-pill) !important}.rounded-bottom{border-bottom-right-radius:var(--bs-border-radius) !important;border-bottom-left-radius:var(--bs-border-radius) !important}.rounded-bottom-0{border-bottom-right-radius:0 !important;border-bottom-left-radius:0 !important}.rounded-bottom-1{border-bottom-right-radius:var(--bs-border-radius-sm) !important;border-bottom-left-radius:var(--bs-border-radius-sm) !important}.rounded-bottom-2{border-bottom-right-radius:var(--bs-border-radius) !important;border-bottom-left-radius:var(--bs-border-radius) !important}.rounded-bottom-3{border-bottom-right-radius:var(--bs-border-radius-lg) !important;border-bottom-left-radius:var(--bs-border-radius-lg) !important}.rounded-bottom-4{border-bottom-right-radius:var(--bs-border-radius-xl) !important;border-bottom-left-radius:var(--bs-border-radius-xl) !important}.rounded-bottom-5{border-bottom-right-radius:var(--bs-border-radius-xxl) !important;border-bottom-left-radius:var(--bs-border-radius-xxl) !important}.rounded-bottom-circle{border-bottom-right-radius:50% !important;border-bottom-left-radius:50% !important}.rounded-bottom-pill{border-bottom-right-radius:var(--bs-border-radius-pill) !important;border-bottom-left-radius:var(--bs-border-radius-pill) !important}.rounded-start{border-bottom-left-radius:var(--bs-border-radius) !important;border-top-left-radius:var(--bs-border-radius) !important}.rounded-start-0{border-bottom-left-radius:0 !important;border-top-left-radius:0 !important}.rounded-start-1{border-bottom-left-radius:var(--bs-border-radius-sm) !important;border-top-left-radius:var(--bs-border-radius-sm) !important}.rounded-start-2{border-bottom-left-radius:var(--bs-border-radius) !important;border-top-left-radius:var(--bs-border-radius) !important}.rounded-start-3{border-bottom-left-radius:var(--bs-border-radius-lg) !important;border-top-left-radius:var(--bs-border-radius-lg) !important}.rounded-start-4{border-bottom-left-radius:var(--bs-border-radius-xl) !important;border-top-left-radius:var(--bs-border-radius-xl) !important}.rounded-start-5{border-bottom-left-radius:var(--bs-border-radius-xxl) !important;border-top-left-radius:var(--bs-border-radius-xxl) !important}.rounded-start-circle{border-bottom-left-radius:50% !important;border-top-left-radius:50% !important}.rounded-start-pill{border-bottom-left-radius:var(--bs-border-radius-pill) !important;border-top-left-radius:var(--bs-border-radius-pill) !important}.visible{visibility:visible !important}.invisible{visibility:hidden !important}.z-n1{z-index:-1 !important}.z-0{z-index:0 !important}.z-1{z-index:1 !important}.z-2{z-index:2 !important}.z-3{z-index:3 !important}@media(min-width: 576px){.float-sm-start{float:left !important}.float-sm-end{float:right !important}.float-sm-none{float:none !important}.object-fit-sm-contain{object-fit:contain !important}.object-fit-sm-cover{object-fit:cover !important}.object-fit-sm-fill{object-fit:fill !important}.object-fit-sm-scale{object-fit:scale-down !important}.object-fit-sm-none{object-fit: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-inline-grid{display:inline-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}.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}.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}.row-gap-sm-0{row-gap:0 !important}.row-gap-sm-1{row-gap:.25rem !important}.row-gap-sm-2{row-gap:.5rem !important}.row-gap-sm-3{row-gap:1rem !important}.row-gap-sm-4{row-gap:1.5rem !important}.row-gap-sm-5{row-gap:3rem !important}.column-gap-sm-0{column-gap:0 !important}.column-gap-sm-1{column-gap:.25rem !important}.column-gap-sm-2{column-gap:.5rem !important}.column-gap-sm-3{column-gap:1rem !important}.column-gap-sm-4{column-gap:1.5rem !important}.column-gap-sm-5{column-gap: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}.object-fit-md-contain{object-fit:contain !important}.object-fit-md-cover{object-fit:cover !important}.object-fit-md-fill{object-fit:fill !important}.object-fit-md-scale{object-fit:scale-down !important}.object-fit-md-none{object-fit: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-inline-grid{display:inline-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}.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}.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}.row-gap-md-0{row-gap:0 !important}.row-gap-md-1{row-gap:.25rem !important}.row-gap-md-2{row-gap:.5rem !important}.row-gap-md-3{row-gap:1rem !important}.row-gap-md-4{row-gap:1.5rem !important}.row-gap-md-5{row-gap:3rem !important}.column-gap-md-0{column-gap:0 !important}.column-gap-md-1{column-gap:.25rem !important}.column-gap-md-2{column-gap:.5rem !important}.column-gap-md-3{column-gap:1rem !important}.column-gap-md-4{column-gap:1.5rem !important}.column-gap-md-5{column-gap: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}.object-fit-lg-contain{object-fit:contain !important}.object-fit-lg-cover{object-fit:cover !important}.object-fit-lg-fill{object-fit:fill !important}.object-fit-lg-scale{object-fit:scale-down !important}.object-fit-lg-none{object-fit: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-inline-grid{display:inline-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}.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}.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}.row-gap-lg-0{row-gap:0 !important}.row-gap-lg-1{row-gap:.25rem !important}.row-gap-lg-2{row-gap:.5rem !important}.row-gap-lg-3{row-gap:1rem !important}.row-gap-lg-4{row-gap:1.5rem !important}.row-gap-lg-5{row-gap:3rem !important}.column-gap-lg-0{column-gap:0 !important}.column-gap-lg-1{column-gap:.25rem !important}.column-gap-lg-2{column-gap:.5rem !important}.column-gap-lg-3{column-gap:1rem !important}.column-gap-lg-4{column-gap:1.5rem !important}.column-gap-lg-5{column-gap: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}.object-fit-xl-contain{object-fit:contain !important}.object-fit-xl-cover{object-fit:cover !important}.object-fit-xl-fill{object-fit:fill !important}.object-fit-xl-scale{object-fit:scale-down !important}.object-fit-xl-none{object-fit: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-inline-grid{display:inline-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}.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}.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}.row-gap-xl-0{row-gap:0 !important}.row-gap-xl-1{row-gap:.25rem !important}.row-gap-xl-2{row-gap:.5rem !important}.row-gap-xl-3{row-gap:1rem !important}.row-gap-xl-4{row-gap:1.5rem !important}.row-gap-xl-5{row-gap:3rem !important}.column-gap-xl-0{column-gap:0 !important}.column-gap-xl-1{column-gap:.25rem !important}.column-gap-xl-2{column-gap:.5rem !important}.column-gap-xl-3{column-gap:1rem !important}.column-gap-xl-4{column-gap:1.5rem !important}.column-gap-xl-5{column-gap: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}.object-fit-xxl-contain{object-fit:contain !important}.object-fit-xxl-cover{object-fit:cover !important}.object-fit-xxl-fill{object-fit:fill !important}.object-fit-xxl-scale{object-fit:scale-down !important}.object-fit-xxl-none{object-fit: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-inline-grid{display:inline-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}.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}.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}.row-gap-xxl-0{row-gap:0 !important}.row-gap-xxl-1{row-gap:.25rem !important}.row-gap-xxl-2{row-gap:.5rem !important}.row-gap-xxl-3{row-gap:1rem !important}.row-gap-xxl-4{row-gap:1.5rem !important}.row-gap-xxl-5{row-gap:3rem !important}.column-gap-xxl-0{column-gap:0 !important}.column-gap-xxl-1{column-gap:.25rem !important}.column-gap-xxl-2{column-gap:.5rem !important}.column-gap-xxl-3{column-gap:1rem !important}.column-gap-xxl-4{column-gap:1.5rem !important}.column-gap-xxl-5{column-gap: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-inline-grid{display:inline-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}}.select2-container{box-sizing:border-box;display:inline-block;margin:0;position:relative;vertical-align:middle}.select2-container .select2-selection--single{box-sizing:border-box;cursor:pointer;display:block;height:28px;user-select:none;-webkit-user-select:none}.select2-container .select2-selection--single .select2-selection__rendered{display:block;padding-left:8px;padding-right:20px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.select2-container .select2-selection--single .select2-selection__clear{position:relative}.select2-container[dir=rtl] .select2-selection--single .select2-selection__rendered{padding-right:8px;padding-left:20px}.select2-container .select2-selection--multiple{box-sizing:border-box;cursor:pointer;display:block;min-height:32px;user-select:none;-webkit-user-select:none}.select2-container .select2-selection--multiple .select2-selection__rendered{display:inline-block;overflow:hidden;padding-left:8px;text-overflow:ellipsis;white-space:nowrap}.select2-container .select2-search--inline{float:left}.select2-container .select2-search--inline .select2-search__field{box-sizing:border-box;border:none;font-size:100%;margin-top:5px;padding:0}.select2-container .select2-search--inline .select2-search__field::-webkit-search-cancel-button{-webkit-appearance:none}.select2-dropdown{background-color:#fff;border:1px solid #aaa;border-radius:4px;box-sizing:border-box;display:block;position:absolute;left:-100000px;width:100%;z-index:1051}.select2-results{display:block}.select2-results__options{list-style:none;margin:0;padding:0}.select2-results__option{padding:6px;user-select:none;-webkit-user-select:none}.select2-results__option[aria-selected]{cursor:pointer}.select2-container--open .select2-dropdown{left:0}.select2-container--open .select2-dropdown--above{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--open .select2-dropdown--below{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.select2-search--dropdown{display:block;padding:4px}.select2-search--dropdown .select2-search__field{padding:4px;width:100%;box-sizing:border-box}.select2-search--dropdown .select2-search__field::-webkit-search-cancel-button{-webkit-appearance:none}.select2-search--dropdown.select2-search--hide{display:none}.select2-close-mask{border:0;margin:0;padding:0;display:block;position:fixed;left:0;top:0;min-height:100%;min-width:100%;height:auto;width:auto;opacity:0;z-index:99;background-color:#fff;filter:alpha(opacity=0)}.select2-hidden-accessible{border:0 !important;clip:rect(0 0 0 0) !important;-webkit-clip-path:inset(50%) !important;clip-path:inset(50%) !important;height:1px !important;overflow:hidden !important;padding:0 !important;position:absolute !important;width:1px !important;white-space:nowrap !important}.select2-container--default .select2-selection--single{background-color:#fff;border:1px solid #aaa;border-radius:4px}.select2-container--default .select2-selection--single .select2-selection__rendered{color:#444;line-height:28px}.select2-container--default .select2-selection--single .select2-selection__clear{cursor:pointer;float:right;font-weight:bold}.select2-container--default .select2-selection--single .select2-selection__placeholder{color:#999}.select2-container--default .select2-selection--single .select2-selection__arrow{height:26px;position:absolute;top:1px;right:1px;width:20px}.select2-container--default .select2-selection--single .select2-selection__arrow b{border-color:#888 rgba(0,0,0,0) rgba(0,0,0,0) rgba(0,0,0,0);border-style:solid;border-width:5px 4px 0 4px;height:0;left:50%;margin-left:-4px;margin-top:-2px;position:absolute;top:50%;width:0}.select2-container--default[dir=rtl] .select2-selection--single .select2-selection__clear{float:left}.select2-container--default[dir=rtl] .select2-selection--single .select2-selection__arrow{left:1px;right:auto}.select2-container--default.select2-container--disabled .select2-selection--single{background-color:#eee;cursor:default}.select2-container--default.select2-container--disabled .select2-selection--single .select2-selection__clear{display:none}.select2-container--default.select2-container--open .select2-selection--single .select2-selection__arrow b{border-color:rgba(0,0,0,0) rgba(0,0,0,0) #888 rgba(0,0,0,0);border-width:0 4px 5px 4px}.select2-container--default .select2-selection--multiple{background-color:#fff;border:1px solid #aaa;border-radius:4px;cursor:text}.select2-container--default .select2-selection--multiple .select2-selection__rendered{box-sizing:border-box;list-style:none;margin:0;padding:0 5px;width:100%}.select2-container--default .select2-selection--multiple .select2-selection__rendered li{list-style:none}.select2-container--default .select2-selection--multiple .select2-selection__clear{cursor:pointer;float:right;font-weight:bold;margin-top:5px;margin-right:10px;padding:1px}.select2-container--default .select2-selection--multiple .select2-selection__choice{background-color:#e4e4e4;border:1px solid #aaa;border-radius:4px;cursor:default;float:left;margin-right:5px;margin-top:5px;padding:0 5px}.select2-container--default .select2-selection--multiple .select2-selection__choice__remove{color:#999;cursor:pointer;display:inline-block;font-weight:bold;margin-right:2px}.select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover{color:#333}.select2-container--default[dir=rtl] .select2-selection--multiple .select2-selection__choice,.select2-container--default[dir=rtl] .select2-selection--multiple .select2-search--inline{float:right}.select2-container--default[dir=rtl] .select2-selection--multiple .select2-selection__choice{margin-left:5px;margin-right:auto}.select2-container--default[dir=rtl] .select2-selection--multiple .select2-selection__choice__remove{margin-left:2px;margin-right:auto}.select2-container--default.select2-container--focus .select2-selection--multiple{border:solid #000 1px;outline:0}.select2-container--default.select2-container--disabled .select2-selection--multiple{background-color:#eee;cursor:default}.select2-container--default.select2-container--disabled .select2-selection__choice__remove{display:none}.select2-container--default.select2-container--open.select2-container--above .select2-selection--single,.select2-container--default.select2-container--open.select2-container--above .select2-selection--multiple{border-top-left-radius:0;border-top-right-radius:0}.select2-container--default.select2-container--open.select2-container--below .select2-selection--single,.select2-container--default.select2-container--open.select2-container--below .select2-selection--multiple{border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--default .select2-search--dropdown .select2-search__field{border:1px solid #aaa}.select2-container--default .select2-search--inline .select2-search__field{background:rgba(0,0,0,0);border:none;outline:0;box-shadow:none;-webkit-appearance:textfield}.select2-container--default .select2-results>.select2-results__options{max-height:200px;overflow-y:auto}.select2-container--default .select2-results__option[role=group]{padding:0}.select2-container--default .select2-results__option[aria-disabled=true]{color:#999}.select2-container--default .select2-results__option[aria-selected=true]{background-color:#ddd}.select2-container--default .select2-results__option .select2-results__option{padding-left:1em}.select2-container--default .select2-results__option .select2-results__option .select2-results__group{padding-left:0}.select2-container--default .select2-results__option .select2-results__option .select2-results__option{margin-left:-1em;padding-left:2em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-2em;padding-left:3em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-3em;padding-left:4em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-4em;padding-left:5em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-5em;padding-left:6em}.select2-container--default .select2-results__option--highlighted[aria-selected]{background-color:#5897fb;color:#fff}.select2-container--default .select2-results__group{cursor:default;display:block;padding:6px}.select2-container--classic .select2-selection--single{background-color:rgb(246.5,246.5,246.5);border:1px solid #dee2e6;border-radius:.375rem;outline:0;background-image:-webkit-linear-gradient(top, white 50%, #eeeeee 100%);background-image:-o-linear-gradient(top, white 50%, #eeeeee 100%);background-image:linear-gradient(to bottom, white 50%, #eeeeee 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#FFFFFFFF", endColorstr="#FFEEEEEE", GradientType=0)}.select2-container--classic .select2-selection--single:focus{border:1px solid #5897fb}.select2-container--classic .select2-selection--single .select2-selection__rendered{color:#444;line-height:28px}.select2-container--classic .select2-selection--single .select2-selection__clear{cursor:pointer;float:right;font-weight:bold;margin-right:10px}.select2-container--classic .select2-selection--single .select2-selection__placeholder{color:#999}.select2-container--classic .select2-selection--single .select2-selection__arrow{background-color:#ddd;border:none;border-left:1px solid #dee2e6;border-top-right-radius:.375rem;border-bottom-right-radius:.375rem;height:26px;position:absolute;top:1px;right:1px;width:20px;background-image:-webkit-linear-gradient(top, #eeeeee 50%, #cccccc 100%);background-image:-o-linear-gradient(top, #eeeeee 50%, #cccccc 100%);background-image:linear-gradient(to bottom, #eeeeee 50%, #cccccc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#FFEEEEEE", endColorstr="#FFCCCCCC", GradientType=0)}.select2-container--classic .select2-selection--single .select2-selection__arrow b{border-color:#888 rgba(0,0,0,0) rgba(0,0,0,0) rgba(0,0,0,0);border-style:solid;border-width:5px 4px 0 4px;height:0;left:50%;margin-left:-4px;margin-top:-2px;position:absolute;top:50%;width:0}.select2-container--classic[dir=rtl] .select2-selection--single .select2-selection__clear{float:left}.select2-container--classic[dir=rtl] .select2-selection--single .select2-selection__arrow{border:none;border-right:1px solid #dee2e6;border-radius:0;border-top-left-radius:.375rem;border-bottom-left-radius:.375rem;left:1px;right:auto}.select2-container--classic.select2-container--open .select2-selection--single{border:1px solid #5897fb}.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow{background:rgba(0,0,0,0);border:none}.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow b{border-color:rgba(0,0,0,0) rgba(0,0,0,0) #888 rgba(0,0,0,0);border-width:0 4px 5px 4px}.select2-container--classic.select2-container--open.select2-container--above .select2-selection--single{border-top:none;border-top-left-radius:0;border-top-right-radius:0;background-image:-webkit-linear-gradient(top, white 0%, #eeeeee 50%);background-image:-o-linear-gradient(top, white 0%, #eeeeee 50%);background-image:linear-gradient(to bottom, white 0%, #eeeeee 50%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#FFFFFFFF", endColorstr="#FFEEEEEE", GradientType=0)}.select2-container--classic.select2-container--open.select2-container--below .select2-selection--single{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0;background-image:-webkit-linear-gradient(top, #eeeeee 50%, white 100%);background-image:-o-linear-gradient(top, #eeeeee 50%, white 100%);background-image:linear-gradient(to bottom, #eeeeee 50%, white 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#FFEEEEEE", endColorstr="#FFFFFFFF", GradientType=0)}.select2-container--classic .select2-selection--multiple{background-color:#fff;border:1px solid #dee2e6;border-radius:.375rem;cursor:text;outline:0}.select2-container--classic .select2-selection--multiple:focus{border:1px solid #5897fb}.select2-container--classic .select2-selection--multiple .select2-selection__rendered{list-style:none;margin:0;padding:0 5px}.select2-container--classic .select2-selection--multiple .select2-selection__clear{display:none}.select2-container--classic .select2-selection--multiple .select2-selection__choice{background-color:#e4e4e4;border:1px solid #dee2e6;border-radius:.375rem;cursor:default;float:left;margin-right:5px;margin-top:5px;padding:0 5px}.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove{color:#888;cursor:pointer;display:inline-block;font-weight:bold;margin-right:2px}.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove:hover{color:#555}.select2-container--classic[dir=rtl] .select2-selection--multiple .select2-selection__choice{float:right;margin-left:5px;margin-right:auto}.select2-container--classic[dir=rtl] .select2-selection--multiple .select2-selection__choice__remove{margin-left:2px;margin-right:auto}.select2-container--classic.select2-container--open .select2-selection--multiple{border:1px solid #5897fb}.select2-container--classic.select2-container--open.select2-container--above .select2-selection--multiple{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.select2-container--classic.select2-container--open.select2-container--below .select2-selection--multiple{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--classic .select2-search--dropdown .select2-search__field{border:1px solid #dee2e6;outline:0}.select2-container--classic .select2-search--inline .select2-search__field{outline:0;box-shadow:none}.select2-container--classic .select2-dropdown{background-color:#fff;border:1px solid rgba(0,0,0,0)}.select2-container--classic .select2-dropdown--above{border-bottom:none}.select2-container--classic .select2-dropdown--below{border-top:none}.select2-container--classic .select2-results>.select2-results__options{max-height:200px;overflow-y:auto}.select2-container--classic .select2-results__option[role=group]{padding:0}.select2-container--classic .select2-results__option[aria-disabled=true]{color:gray}.select2-container--classic .select2-results__option--highlighted[aria-selected]{background-color:#3875d7;color:#fff}.select2-container--classic .select2-results__group{cursor:default;display:block;padding:6px}.select2-container--classic.select2-container--open .select2-dropdown{border-color:#5897fb}/*! - * Font Awesome Pro 6.6.0 by @fontawesome - https://fontawesome.com - * License - https://fontawesome.com/license (Commercial License) - * Copyright 2024 Fonticons, Inc. - */.fa{font-family:var(--fa-style-family, "Font Awesome 6 Pro");font-weight:var(--fa-style, 900)}.fa-solid,.fa-regular,.fa-brands,.fas,.far,.fab,.fal,.fat,.fad,.fass,.fasr,.fasl,.fast,.fasds,.fa-light,.fa-thin,.fa-duotone,.fa-sharp,.fa-sharp-duotone,.fa-sharp-solid,.fa-classic,.fa{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:var(--fa-display, inline-block);font-style:normal;font-variant:normal;line-height:1;text-rendering:auto}.fas,.far,.fal,.fat,.fa-solid,.fa-regular,.fa-light,.fa-thin,.fa-classic{font-family:"Font Awesome 6 Pro"}.fab,.fa-brands{font-family:"Font Awesome 6 Brands"}.fad,.fa-classic.fa-duotone,.fa-duotone{font-family:"Font Awesome 6 Duotone"}.fasds,.fa-sharp-duotone{font-family:"Font Awesome 6 Sharp Duotone"}.fasds,.fa-sharp-duotone{font-weight:900}.fass,.fasr,.fasl,.fast,.fa-sharp{font-family:"Font Awesome 6 Sharp"}.fass,.fa-sharp{font-weight:900}.fa-1x{font-size:1em}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-6x{font-size:6em}.fa-7x{font-size:7em}.fa-8x{font-size:8em}.fa-9x{font-size:9em}.fa-10x{font-size:10em}.fa-2xs{font-size:.625em;line-height:.1em;vertical-align:.225em}.fa-xs{font-size:.75em;line-height:.0833333337em;vertical-align:.125em}.fa-sm{font-size:.875em;line-height:.0714285718em;vertical-align:.0535714295em}.fa-lg{font-size:1.25em;line-height:.05em;vertical-align:-.075em}.fa-xl{font-size:1.5em;line-height:.0416666682em;vertical-align:-0.125em}.fa-2xl{font-size:2em;line-height:.03125em;vertical-align:-0.1875em}.fa-fw{text-align:center;width:1.25em}.fa-ul{list-style-type:none;margin-left:var(--fa-li-margin, 2.5em);padding-left:0}.fa-ul>li{position:relative}.fa-li{left:calc(-1*var(--fa-li-width, 2em));position:absolute;text-align:center;width:var(--fa-li-width, 2em);line-height:inherit}.fa-border{border-color:var(--fa-border-color, #eee);border-radius:var(--fa-border-radius, 0.1em);border-style:var(--fa-border-style, solid);border-width:var(--fa-border-width, 0.08em);padding:var(--fa-border-padding, 0.2em 0.25em 0.15em)}.fa-pull-left{float:left;margin-right:var(--fa-pull-margin, 0.3em)}.fa-pull-right{float:right;margin-left:var(--fa-pull-margin, 0.3em)}.fa-beat{animation-name:fa-beat;animation-delay:var(--fa-animation-delay, 0s);animation-direction:var(--fa-animation-direction, normal);animation-duration:var(--fa-animation-duration, 1s);animation-iteration-count:var(--fa-animation-iteration-count, infinite);animation-timing-function:var(--fa-animation-timing, ease-in-out)}.fa-bounce{animation-name:fa-bounce;animation-delay:var(--fa-animation-delay, 0s);animation-direction:var(--fa-animation-direction, normal);animation-duration:var(--fa-animation-duration, 1s);animation-iteration-count:var(--fa-animation-iteration-count, infinite);animation-timing-function:var(--fa-animation-timing, cubic-bezier(0.28, 0.84, 0.42, 1))}.fa-fade{animation-name:fa-fade;animation-delay:var(--fa-animation-delay, 0s);animation-direction:var(--fa-animation-direction, normal);animation-duration:var(--fa-animation-duration, 1s);animation-iteration-count:var(--fa-animation-iteration-count, infinite);animation-timing-function:var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1))}.fa-beat-fade{animation-name:fa-beat-fade;animation-delay:var(--fa-animation-delay, 0s);animation-direction:var(--fa-animation-direction, normal);animation-duration:var(--fa-animation-duration, 1s);animation-iteration-count:var(--fa-animation-iteration-count, infinite);animation-timing-function:var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1))}.fa-flip{animation-name:fa-flip;animation-delay:var(--fa-animation-delay, 0s);animation-direction:var(--fa-animation-direction, normal);animation-duration:var(--fa-animation-duration, 1s);animation-iteration-count:var(--fa-animation-iteration-count, infinite);animation-timing-function:var(--fa-animation-timing, ease-in-out)}.fa-shake{animation-name:fa-shake;animation-delay:var(--fa-animation-delay, 0s);animation-direction:var(--fa-animation-direction, normal);animation-duration:var(--fa-animation-duration, 1s);animation-iteration-count:var(--fa-animation-iteration-count, infinite);animation-timing-function:var(--fa-animation-timing, linear)}.fa-spin{animation-name:fa-spin;animation-delay:var(--fa-animation-delay, 0s);animation-direction:var(--fa-animation-direction, normal);animation-duration:var(--fa-animation-duration, 2s);animation-iteration-count:var(--fa-animation-iteration-count, infinite);animation-timing-function:var(--fa-animation-timing, linear)}.fa-spin-reverse{--fa-animation-direction: reverse}.fa-pulse,.fa-spin-pulse{animation-name:fa-spin;animation-direction:var(--fa-animation-direction, normal);animation-duration:var(--fa-animation-duration, 1s);animation-iteration-count:var(--fa-animation-iteration-count, infinite);animation-timing-function:var(--fa-animation-timing, steps(8))}@media(prefers-reduced-motion: reduce){.fa-beat,.fa-bounce,.fa-fade,.fa-beat-fade,.fa-flip,.fa-pulse,.fa-shake,.fa-spin,.fa-spin-pulse{animation-delay:-1ms;animation-duration:1ms;animation-iteration-count:1;transition-delay:0s;transition-duration:0s}}@keyframes fa-beat{0%,90%{transform:scale(1)}45%{transform:scale(var(--fa-beat-scale, 1.25))}}@keyframes fa-bounce{0%{transform:scale(1, 1) translateY(0)}10%{transform:scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0)}30%{transform:scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em))}50%{transform:scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0)}57%{transform:scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em))}64%{transform:scale(1, 1) translateY(0)}100%{transform:scale(1, 1) translateY(0)}}@keyframes fa-fade{50%{opacity:var(--fa-fade-opacity, 0.4)}}@keyframes fa-beat-fade{0%,100%{opacity:var(--fa-beat-fade-opacity, 0.4);transform:scale(1)}50%{opacity:1;transform:scale(var(--fa-beat-fade-scale, 1.125))}}@keyframes fa-flip{50%{transform:rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg))}}@keyframes fa-shake{0%{transform:rotate(-15deg)}4%{transform:rotate(15deg)}8%,24%{transform:rotate(-18deg)}12%,28%{transform:rotate(18deg)}16%{transform:rotate(-22deg)}20%{transform:rotate(22deg)}32%{transform:rotate(-12deg)}36%{transform:rotate(12deg)}40%,100%{transform:rotate(0deg)}}@keyframes fa-spin{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}.fa-rotate-90{transform:rotate(90deg)}.fa-rotate-180{transform:rotate(180deg)}.fa-rotate-270{transform:rotate(270deg)}.fa-flip-horizontal{transform:scale(-1, 1)}.fa-flip-vertical{transform:scale(1, -1)}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical{transform:scale(-1, -1)}.fa-rotate-by{transform:rotate(var(--fa-rotate-angle, 0))}.fa-stack{display:inline-block;height:2em;line-height:2em;position:relative;vertical-align:middle;width:2.5em}.fa-stack-1x,.fa-stack-2x{left:0;position:absolute;text-align:center;width:100%;z-index:var(--fa-stack-z-index, auto)}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:var(--fa-inverse, #fff)}.fa-0::before{content:"\30 "}.fa-1::before{content:"\31 "}.fa-2::before{content:"\32 "}.fa-3::before{content:"\33 "}.fa-4::before{content:"\34 "}.fa-5::before{content:"\35 "}.fa-6::before{content:"\36 "}.fa-7::before{content:"\37 "}.fa-8::before{content:"\38 "}.fa-9::before{content:"\39 "}.fa-fill-drip::before{content:""}.fa-arrows-to-circle::before{content:""}.fa-circle-chevron-right::before{content:""}.fa-chevron-circle-right::before{content:""}.fa-wagon-covered::before{content:""}.fa-line-height::before{content:""}.fa-bagel::before{content:""}.fa-transporter-7::before{content:""}.fa-at::before{content:"\@"}.fa-rectangles-mixed::before{content:""}.fa-phone-arrow-up-right::before{content:""}.fa-phone-arrow-up::before{content:""}.fa-phone-outgoing::before{content:""}.fa-trash-can::before{content:""}.fa-trash-alt::before{content:""}.fa-circle-l::before{content:""}.fa-head-side-goggles::before{content:""}.fa-head-vr::before{content:""}.fa-text-height::before{content:""}.fa-user-xmark::before{content:""}.fa-user-times::before{content:""}.fa-face-hand-yawn::before{content:""}.fa-gauge-simple-min::before{content:""}.fa-tachometer-slowest::before{content:""}.fa-stethoscope::before{content:""}.fa-coffin::before{content:""}.fa-message::before{content:""}.fa-comment-alt::before{content:""}.fa-salad::before{content:""}.fa-bowl-salad::before{content:""}.fa-info::before{content:""}.fa-robot-astromech::before{content:""}.fa-ring-diamond::before{content:""}.fa-fondue-pot::before{content:""}.fa-theta::before{content:""}.fa-face-hand-peeking::before{content:""}.fa-square-user::before{content:""}.fa-down-left-and-up-right-to-center::before{content:""}.fa-compress-alt::before{content:""}.fa-explosion::before{content:""}.fa-file-lines::before{content:""}.fa-file-alt::before{content:""}.fa-file-text::before{content:""}.fa-wave-square::before{content:""}.fa-ring::before{content:""}.fa-building-un::before{content:""}.fa-dice-three::before{content:""}.fa-tire-pressure-warning::before{content:""}.fa-wifi-fair::before{content:""}.fa-wifi-2::before{content:""}.fa-calendar-days::before{content:""}.fa-calendar-alt::before{content:""}.fa-mp3-player::before{content:""}.fa-anchor-circle-check::before{content:""}.fa-tally-4::before{content:""}.fa-rectangle-history::before{content:""}.fa-building-circle-arrow-right::before{content:""}.fa-volleyball::before{content:""}.fa-volleyball-ball::before{content:""}.fa-sun-haze::before{content:""}.fa-text-size::before{content:""}.fa-ufo::before{content:""}.fa-fork::before{content:""}.fa-utensil-fork::before{content:""}.fa-arrows-up-to-line::before{content:""}.fa-mobile-signal::before{content:""}.fa-barcode-scan::before{content:""}.fa-sort-down::before{content:""}.fa-sort-desc::before{content:""}.fa-folder-arrow-down::before{content:""}.fa-folder-download::before{content:""}.fa-circle-minus::before{content:""}.fa-minus-circle::before{content:""}.fa-face-icicles::before{content:""}.fa-shovel::before{content:""}.fa-door-open::before{content:""}.fa-films::before{content:""}.fa-right-from-bracket::before{content:""}.fa-sign-out-alt::before{content:""}.fa-face-glasses::before{content:""}.fa-nfc::before{content:""}.fa-atom::before{content:""}.fa-soap::before{content:""}.fa-icons::before{content:""}.fa-heart-music-camera-bolt::before{content:""}.fa-microphone-lines-slash::before{content:""}.fa-microphone-alt-slash::before{content:""}.fa-closed-captioning-slash::before{content:""}.fa-calculator-simple::before{content:""}.fa-calculator-alt::before{content:""}.fa-bridge-circle-check::before{content:""}.fa-sliders-up::before{content:""}.fa-sliders-v::before{content:""}.fa-location-minus::before{content:""}.fa-map-marker-minus::before{content:""}.fa-pump-medical::before{content:""}.fa-fingerprint::before{content:""}.fa-ski-boot::before{content:""}.fa-standard-definition::before{content:""}.fa-rectangle-sd::before{content:""}.fa-h1::before{content:""}.fa-hand-point-right::before{content:""}.fa-magnifying-glass-location::before{content:""}.fa-search-location::before{content:""}.fa-message-bot::before{content:""}.fa-forward-step::before{content:""}.fa-step-forward::before{content:""}.fa-face-smile-beam::before{content:""}.fa-smile-beam::before{content:""}.fa-light-ceiling::before{content:""}.fa-message-exclamation::before{content:""}.fa-comment-alt-exclamation::before{content:""}.fa-bowl-scoop::before{content:""}.fa-bowl-shaved-ice::before{content:""}.fa-square-x::before{content:""}.fa-building-memo::before{content:""}.fa-utility-pole-double::before{content:""}.fa-flag-checkered::before{content:""}.fa-chevrons-up::before{content:""}.fa-chevron-double-up::before{content:""}.fa-football::before{content:""}.fa-football-ball::before{content:""}.fa-user-vneck::before{content:""}.fa-school-circle-exclamation::before{content:""}.fa-crop::before{content:""}.fa-angles-down::before{content:""}.fa-angle-double-down::before{content:""}.fa-users-rectangle::before{content:""}.fa-people-roof::before{content:""}.fa-square-arrow-right::before{content:""}.fa-arrow-square-right::before{content:""}.fa-location-plus::before{content:""}.fa-map-marker-plus::before{content:""}.fa-lightbulb-exclamation-on::before{content:""}.fa-people-line::before{content:""}.fa-beer-mug-empty::before{content:""}.fa-beer::before{content:""}.fa-crate-empty::before{content:""}.fa-diagram-predecessor::before{content:""}.fa-transporter::before{content:""}.fa-calendar-circle-user::before{content:""}.fa-arrow-up-long::before{content:""}.fa-long-arrow-up::before{content:""}.fa-person-carry-box::before{content:""}.fa-person-carry::before{content:""}.fa-fire-flame-simple::before{content:""}.fa-burn::before{content:""}.fa-person::before{content:""}.fa-male::before{content:""}.fa-laptop::before{content:""}.fa-file-csv::before{content:""}.fa-menorah::before{content:""}.fa-union::before{content:""}.fa-chevrons-left::before{content:""}.fa-chevron-double-left::before{content:""}.fa-circle-heart::before{content:""}.fa-heart-circle::before{content:""}.fa-truck-plane::before{content:""}.fa-record-vinyl::before{content:""}.fa-bring-forward::before{content:""}.fa-square-p::before{content:""}.fa-face-grin-stars::before{content:""}.fa-grin-stars::before{content:""}.fa-sigma::before{content:""}.fa-camera-movie::before{content:""}.fa-bong::before{content:""}.fa-clarinet::before{content:""}.fa-truck-flatbed::before{content:""}.fa-spaghetti-monster-flying::before{content:""}.fa-pastafarianism::before{content:""}.fa-arrow-down-up-across-line::before{content:""}.fa-arrows-rotate-reverse::before{content:""}.fa-leaf-heart::before{content:""}.fa-house-building::before{content:""}.fa-cheese-swiss::before{content:""}.fa-spoon::before{content:""}.fa-utensil-spoon::before{content:""}.fa-jar-wheat::before{content:""}.fa-envelopes-bulk::before{content:""}.fa-mail-bulk::before{content:""}.fa-file-circle-exclamation::before{content:""}.fa-bow-arrow::before{content:""}.fa-cart-xmark::before{content:""}.fa-hexagon-xmark::before{content:""}.fa-times-hexagon::before{content:""}.fa-xmark-hexagon::before{content:""}.fa-circle-h::before{content:""}.fa-hospital-symbol::before{content:""}.fa-merge::before{content:""}.fa-pager::before{content:""}.fa-cart-minus::before{content:""}.fa-address-book::before{content:""}.fa-contact-book::before{content:""}.fa-pan-frying::before{content:""}.fa-grid::before{content:""}.fa-grid-3::before{content:""}.fa-football-helmet::before{content:""}.fa-hand-love::before{content:""}.fa-trees::before{content:""}.fa-strikethrough::before{content:""}.fa-page::before{content:""}.fa-k::before{content:"K"}.fa-diagram-previous::before{content:""}.fa-gauge-min::before{content:""}.fa-tachometer-alt-slowest::before{content:""}.fa-folder-grid::before{content:""}.fa-eggplant::before{content:""}.fa-excavator::before{content:""}.fa-ram::before{content:""}.fa-landmark-flag::before{content:""}.fa-lips::before{content:""}.fa-pencil::before{content:""}.fa-pencil-alt::before{content:""}.fa-backward::before{content:""}.fa-caret-right::before{content:""}.fa-comments::before{content:""}.fa-paste::before{content:""}.fa-file-clipboard::before{content:""}.fa-desktop-arrow-down::before{content:""}.fa-code-pull-request::before{content:""}.fa-pumpkin::before{content:""}.fa-clipboard-list::before{content:""}.fa-pen-field::before{content:""}.fa-blueberries::before{content:""}.fa-truck-ramp-box::before{content:""}.fa-truck-loading::before{content:""}.fa-note::before{content:""}.fa-arrow-down-to-square::before{content:""}.fa-user-check::before{content:""}.fa-cloud-xmark::before{content:""}.fa-vial-virus::before{content:""}.fa-book-blank::before{content:""}.fa-book-alt::before{content:""}.fa-golf-flag-hole::before{content:""}.fa-message-arrow-down::before{content:""}.fa-comment-alt-arrow-down::before{content:""}.fa-face-unamused::before{content:""}.fa-sheet-plastic::before{content:""}.fa-circle-9::before{content:""}.fa-blog::before{content:""}.fa-user-ninja::before{content:""}.fa-pencil-slash::before{content:""}.fa-bowling-pins::before{content:""}.fa-person-arrow-up-from-line::before{content:""}.fa-down-right::before{content:""}.fa-scroll-torah::before{content:""}.fa-torah::before{content:""}.fa-webhook::before{content:""}.fa-blinds-open::before{content:""}.fa-fence::before{content:""}.fa-up::before{content:""}.fa-arrow-alt-up::before{content:""}.fa-broom-ball::before{content:""}.fa-quidditch::before{content:""}.fa-quidditch-broom-ball::before{content:""}.fa-drumstick::before{content:""}.fa-square-v::before{content:""}.fa-face-awesome::before{content:""}.fa-gave-dandy::before{content:""}.fa-dial-off::before{content:""}.fa-toggle-off::before{content:""}.fa-face-smile-horns::before{content:""}.fa-box-archive::before{content:""}.fa-archive::before{content:""}.fa-grapes::before{content:""}.fa-person-drowning::before{content:""}.fa-dial-max::before{content:""}.fa-circle-m::before{content:""}.fa-calendar-image::before{content:""}.fa-circle-caret-down::before{content:""}.fa-caret-circle-down::before{content:""}.fa-arrow-down-9-1::before{content:""}.fa-sort-numeric-desc::before{content:""}.fa-sort-numeric-down-alt::before{content:""}.fa-face-grin-tongue-squint::before{content:""}.fa-grin-tongue-squint::before{content:""}.fa-shish-kebab::before{content:""}.fa-spray-can::before{content:""}.fa-alarm-snooze::before{content:""}.fa-scarecrow::before{content:""}.fa-truck-monster::before{content:""}.fa-gift-card::before{content:""}.fa-w::before{content:"W"}.fa-code-pull-request-draft::before{content:""}.fa-square-b::before{content:""}.fa-elephant::before{content:""}.fa-earth-africa::before{content:""}.fa-globe-africa::before{content:""}.fa-rainbow::before{content:""}.fa-circle-notch::before{content:""}.fa-tablet-screen-button::before{content:""}.fa-tablet-alt::before{content:""}.fa-paw::before{content:""}.fa-message-question::before{content:""}.fa-cloud::before{content:""}.fa-trowel-bricks::before{content:""}.fa-square-3::before{content:""}.fa-face-flushed::before{content:""}.fa-flushed::before{content:""}.fa-hospital-user::before{content:""}.fa-microwave::before{content:""}.fa-chf-sign::before{content:""}.fa-tent-arrow-left-right::before{content:""}.fa-cart-circle-arrow-up::before{content:""}.fa-trash-clock::before{content:""}.fa-reflect-both::before{content:""}.fa-gavel::before{content:""}.fa-legal::before{content:""}.fa-sprinkler-ceiling::before{content:""}.fa-browsers::before{content:""}.fa-trillium::before{content:""}.fa-table-cells-unlock::before{content:""}.fa-music-slash::before{content:""}.fa-truck-ramp::before{content:""}.fa-binoculars::before{content:""}.fa-microphone-slash::before{content:""}.fa-box-tissue::before{content:""}.fa-circle-c::before{content:""}.fa-star-christmas::before{content:""}.fa-chart-bullet::before{content:""}.fa-motorcycle::before{content:""}.fa-tree-christmas::before{content:""}.fa-tire-flat::before{content:""}.fa-sunglasses::before{content:""}.fa-badge::before{content:""}.fa-message-pen::before{content:""}.fa-comment-alt-edit::before{content:""}.fa-message-edit::before{content:""}.fa-bell-concierge::before{content:""}.fa-concierge-bell::before{content:""}.fa-pen-ruler::before{content:""}.fa-pencil-ruler::before{content:""}.fa-file-mp3::before{content:""}.fa-arrow-progress::before{content:""}.fa-chess-rook-piece::before{content:""}.fa-chess-rook-alt::before{content:""}.fa-square-root::before{content:""}.fa-album-collection-circle-plus::before{content:""}.fa-people-arrows::before{content:""}.fa-people-arrows-left-right::before{content:""}.fa-sign-post::before{content:""}.fa-face-angry-horns::before{content:""}.fa-mars-and-venus-burst::before{content:""}.fa-tombstone::before{content:""}.fa-square-caret-right::before{content:""}.fa-caret-square-right::before{content:""}.fa-scissors::before{content:""}.fa-cut::before{content:""}.fa-list-music::before{content:""}.fa-sun-plant-wilt::before{content:""}.fa-toilets-portable::before{content:""}.fa-hockey-puck::before{content:""}.fa-mustache::before{content:""}.fa-hyphen::before{content:"\-"}.fa-table::before{content:""}.fa-user-chef::before{content:""}.fa-message-image::before{content:""}.fa-comment-alt-image::before{content:""}.fa-users-medical::before{content:""}.fa-sensor-triangle-exclamation::before{content:""}.fa-sensor-alert::before{content:""}.fa-magnifying-glass-arrow-right::before{content:""}.fa-tachograph-digital::before{content:""}.fa-digital-tachograph::before{content:""}.fa-face-mask::before{content:""}.fa-pickleball::before{content:""}.fa-star-sharp-half::before{content:""}.fa-users-slash::before{content:""}.fa-clover::before{content:""}.fa-meat::before{content:""}.fa-reply::before{content:""}.fa-mail-reply::before{content:""}.fa-star-and-crescent::before{content:""}.fa-empty-set::before{content:""}.fa-house-fire::before{content:""}.fa-square-minus::before{content:""}.fa-minus-square::before{content:""}.fa-helicopter::before{content:""}.fa-bird::before{content:""}.fa-compass::before{content:""}.fa-square-caret-down::before{content:""}.fa-caret-square-down::before{content:""}.fa-heart-half-stroke::before{content:""}.fa-heart-half-alt::before{content:""}.fa-file-circle-question::before{content:""}.fa-truck-utensils::before{content:""}.fa-laptop-code::before{content:""}.fa-joystick::before{content:""}.fa-grill-fire::before{content:""}.fa-rectangle-vertical-history::before{content:""}.fa-swatchbook::before{content:""}.fa-prescription-bottle::before{content:""}.fa-bars::before{content:""}.fa-navicon::before{content:""}.fa-keyboard-left::before{content:""}.fa-people-group::before{content:""}.fa-hourglass-end::before{content:""}.fa-hourglass-3::before{content:""}.fa-heart-crack::before{content:""}.fa-heart-broken::before{content:""}.fa-face-beam-hand-over-mouth::before{content:""}.fa-droplet-percent::before{content:""}.fa-humidity::before{content:""}.fa-square-up-right::before{content:""}.fa-external-link-square-alt::before{content:""}.fa-face-kiss-beam::before{content:""}.fa-kiss-beam::before{content:""}.fa-corn::before{content:""}.fa-roller-coaster::before{content:""}.fa-photo-film-music::before{content:""}.fa-radar::before{content:""}.fa-sickle::before{content:""}.fa-film::before{content:""}.fa-coconut::before{content:""}.fa-ruler-horizontal::before{content:""}.fa-shield-cross::before{content:""}.fa-cassette-tape::before{content:""}.fa-square-terminal::before{content:""}.fa-people-robbery::before{content:""}.fa-lightbulb::before{content:""}.fa-caret-left::before{content:""}.fa-comment-middle::before{content:""}.fa-trash-can-list::before{content:""}.fa-block::before{content:""}.fa-circle-exclamation::before{content:""}.fa-exclamation-circle::before{content:""}.fa-school-circle-xmark::before{content:""}.fa-arrow-right-from-bracket::before{content:""}.fa-sign-out::before{content:""}.fa-face-frown-slight::before{content:""}.fa-circle-chevron-down::before{content:""}.fa-chevron-circle-down::before{content:""}.fa-sidebar-flip::before{content:""}.fa-unlock-keyhole::before{content:""}.fa-unlock-alt::before{content:""}.fa-temperature-list::before{content:""}.fa-cloud-showers-heavy::before{content:""}.fa-headphones-simple::before{content:""}.fa-headphones-alt::before{content:""}.fa-sitemap::before{content:""}.fa-pipe-section::before{content:""}.fa-space-station-moon-construction::before{content:""}.fa-space-station-moon-alt::before{content:""}.fa-circle-dollar-to-slot::before{content:""}.fa-donate::before{content:""}.fa-memory::before{content:""}.fa-face-sleeping::before{content:""}.fa-road-spikes::before{content:""}.fa-fire-burner::before{content:""}.fa-squirrel::before{content:""}.fa-arrow-up-to-line::before{content:""}.fa-arrow-to-top::before{content:""}.fa-flag::before{content:""}.fa-face-cowboy-hat::before{content:""}.fa-hanukiah::before{content:""}.fa-chart-scatter-3d::before{content:""}.fa-display-chart-up::before{content:""}.fa-square-code::before{content:""}.fa-feather::before{content:""}.fa-volume-low::before{content:""}.fa-volume-down::before{content:""}.fa-xmark-to-slot::before{content:""}.fa-times-to-slot::before{content:""}.fa-vote-nay::before{content:""}.fa-box-taped::before{content:""}.fa-box-alt::before{content:""}.fa-comment-slash::before{content:""}.fa-swords::before{content:""}.fa-cloud-sun-rain::before{content:""}.fa-album::before{content:""}.fa-circle-n::before{content:""}.fa-compress::before{content:""}.fa-wheat-awn::before{content:""}.fa-wheat-alt::before{content:""}.fa-ankh::before{content:""}.fa-hands-holding-child::before{content:""}.fa-asterisk::before{content:"\*"}.fa-key-skeleton-left-right::before{content:""}.fa-comment-lines::before{content:""}.fa-luchador-mask::before{content:""}.fa-luchador::before{content:""}.fa-mask-luchador::before{content:""}.fa-square-check::before{content:""}.fa-check-square::before{content:""}.fa-shredder::before{content:""}.fa-book-open-cover::before{content:""}.fa-book-open-alt::before{content:""}.fa-sandwich::before{content:""}.fa-peseta-sign::before{content:""}.fa-square-parking-slash::before{content:""}.fa-parking-slash::before{content:""}.fa-train-tunnel::before{content:""}.fa-heading::before{content:""}.fa-header::before{content:""}.fa-ghost::before{content:""}.fa-face-anguished::before{content:""}.fa-hockey-sticks::before{content:""}.fa-abacus::before{content:""}.fa-film-simple::before{content:""}.fa-film-alt::before{content:""}.fa-list::before{content:""}.fa-list-squares::before{content:""}.fa-tree-palm::before{content:""}.fa-square-phone-flip::before{content:""}.fa-phone-square-alt::before{content:""}.fa-user-beard-bolt::before{content:""}.fa-cart-plus::before{content:""}.fa-gamepad::before{content:""}.fa-border-center-v::before{content:""}.fa-circle-dot::before{content:""}.fa-dot-circle::before{content:""}.fa-clipboard-medical::before{content:""}.fa-face-dizzy::before{content:""}.fa-dizzy::before{content:""}.fa-egg::before{content:""}.fa-up-to-line::before{content:""}.fa-arrow-alt-to-top::before{content:""}.fa-house-medical-circle-xmark::before{content:""}.fa-watch-fitness::before{content:""}.fa-clock-nine-thirty::before{content:""}.fa-campground::before{content:""}.fa-folder-plus::before{content:""}.fa-jug::before{content:""}.fa-futbol::before{content:""}.fa-futbol-ball::before{content:""}.fa-soccer-ball::before{content:""}.fa-snow-blowing::before{content:""}.fa-paintbrush::before{content:""}.fa-paint-brush::before{content:""}.fa-lock::before{content:""}.fa-arrow-down-from-line::before{content:""}.fa-arrow-from-top::before{content:""}.fa-gas-pump::before{content:""}.fa-signal-bars-slash::before{content:""}.fa-signal-alt-slash::before{content:""}.fa-monkey::before{content:""}.fa-rectangle-pro::before{content:""}.fa-pro::before{content:""}.fa-house-night::before{content:""}.fa-hot-tub-person::before{content:""}.fa-hot-tub::before{content:""}.fa-globe-pointer::before{content:""}.fa-blanket::before{content:""}.fa-map-location::before{content:""}.fa-map-marked::before{content:""}.fa-house-flood-water::before{content:""}.fa-comments-question-check::before{content:""}.fa-tree::before{content:""}.fa-arrows-cross::before{content:""}.fa-backpack::before{content:""}.fa-square-small::before{content:""}.fa-folder-arrow-up::before{content:""}.fa-folder-upload::before{content:""}.fa-bridge-lock::before{content:""}.fa-crosshairs-simple::before{content:""}.fa-sack-dollar::before{content:""}.fa-pen-to-square::before{content:""}.fa-edit::before{content:""}.fa-square-sliders::before{content:""}.fa-sliders-h-square::before{content:""}.fa-car-side::before{content:""}.fa-message-middle-top::before{content:""}.fa-comment-middle-top-alt::before{content:""}.fa-lightbulb-on::before{content:""}.fa-knife::before{content:""}.fa-utensil-knife::before{content:""}.fa-share-nodes::before{content:""}.fa-share-alt::before{content:""}.fa-display-chart-up-circle-dollar::before{content:""}.fa-wave-sine::before{content:""}.fa-heart-circle-minus::before{content:""}.fa-circle-w::before{content:""}.fa-circle-calendar::before{content:""}.fa-calendar-circle::before{content:""}.fa-hourglass-half::before{content:""}.fa-hourglass-2::before{content:""}.fa-microscope::before{content:""}.fa-sunset::before{content:""}.fa-sink::before{content:""}.fa-calendar-exclamation::before{content:""}.fa-truck-container-empty::before{content:""}.fa-hand-heart::before{content:""}.fa-bag-shopping::before{content:""}.fa-shopping-bag::before{content:""}.fa-arrow-down-z-a::before{content:""}.fa-sort-alpha-desc::before{content:""}.fa-sort-alpha-down-alt::before{content:""}.fa-mitten::before{content:""}.fa-reply-clock::before{content:""}.fa-reply-time::before{content:""}.fa-person-rays::before{content:""}.fa-right::before{content:""}.fa-arrow-alt-right::before{content:""}.fa-circle-f::before{content:""}.fa-users::before{content:""}.fa-face-pleading::before{content:""}.fa-eye-slash::before{content:""}.fa-flask-vial::before{content:""}.fa-police-box::before{content:""}.fa-cucumber::before{content:""}.fa-head-side-brain::before{content:""}.fa-hand::before{content:""}.fa-hand-paper::before{content:""}.fa-person-biking-mountain::before{content:""}.fa-biking-mountain::before{content:""}.fa-utensils-slash::before{content:""}.fa-print-magnifying-glass::before{content:""}.fa-print-search::before{content:""}.fa-turn-right::before{content:""}.fa-folder-bookmark::before{content:""}.fa-arrow-turn-left-down::before{content:""}.fa-om::before{content:""}.fa-pi::before{content:""}.fa-flask-round-potion::before{content:""}.fa-flask-potion::before{content:""}.fa-face-shush::before{content:""}.fa-worm::before{content:""}.fa-house-circle-xmark::before{content:""}.fa-plug::before{content:""}.fa-calendar-circle-exclamation::before{content:""}.fa-square-i::before{content:""}.fa-chevron-up::before{content:""}.fa-face-saluting::before{content:""}.fa-gauge-simple-low::before{content:""}.fa-tachometer-slow::before{content:""}.fa-face-persevering::before{content:""}.fa-circle-camera::before{content:""}.fa-camera-circle::before{content:""}.fa-hand-spock::before{content:""}.fa-spider-web::before{content:""}.fa-circle-microphone::before{content:""}.fa-microphone-circle::before{content:""}.fa-book-arrow-up::before{content:""}.fa-popsicle::before{content:""}.fa-command::before{content:""}.fa-blinds::before{content:""}.fa-stopwatch::before{content:""}.fa-saxophone::before{content:""}.fa-square-2::before{content:""}.fa-field-hockey-stick-ball::before{content:""}.fa-field-hockey::before{content:""}.fa-arrow-up-square-triangle::before{content:""}.fa-sort-shapes-up-alt::before{content:""}.fa-face-scream::before{content:""}.fa-square-m::before{content:""}.fa-camera-web::before{content:""}.fa-webcam::before{content:""}.fa-comment-arrow-down::before{content:""}.fa-lightbulb-cfl::before{content:""}.fa-window-frame-open::before{content:""}.fa-face-kiss::before{content:""}.fa-kiss::before{content:""}.fa-bridge-circle-xmark::before{content:""}.fa-period::before{content:"\."}.fa-face-grin-tongue::before{content:""}.fa-grin-tongue::before{content:""}.fa-up-to-dotted-line::before{content:""}.fa-thought-bubble::before{content:""}.fa-skeleton-ribs::before{content:""}.fa-raygun::before{content:""}.fa-flute::before{content:""}.fa-acorn::before{content:""}.fa-video-arrow-up-right::before{content:""}.fa-grate-droplet::before{content:""}.fa-seal-exclamation::before{content:""}.fa-chess-bishop::before{content:""}.fa-message-sms::before{content:""}.fa-coffee-beans::before{content:""}.fa-hat-witch::before{content:""}.fa-face-grin-wink::before{content:""}.fa-grin-wink::before{content:""}.fa-clock-three-thirty::before{content:""}.fa-ear-deaf::before{content:""}.fa-deaf::before{content:""}.fa-deafness::before{content:""}.fa-hard-of-hearing::before{content:""}.fa-alarm-clock::before{content:""}.fa-eclipse::before{content:""}.fa-face-relieved::before{content:""}.fa-road-circle-check::before{content:""}.fa-dice-five::before{content:""}.fa-octagon-minus::before{content:""}.fa-minus-octagon::before{content:""}.fa-square-rss::before{content:""}.fa-rss-square::before{content:""}.fa-face-zany::before{content:""}.fa-tricycle::before{content:""}.fa-land-mine-on::before{content:""}.fa-square-arrow-up-left::before{content:""}.fa-i-cursor::before{content:""}.fa-chart-mixed-up-circle-dollar::before{content:""}.fa-salt-shaker::before{content:""}.fa-stamp::before{content:""}.fa-file-plus::before{content:""}.fa-draw-square::before{content:""}.fa-toilet-paper-under-slash::before{content:""}.fa-toilet-paper-reverse-slash::before{content:""}.fa-stairs::before{content:""}.fa-drone-front::before{content:""}.fa-drone-alt::before{content:""}.fa-glass-empty::before{content:""}.fa-dial-high::before{content:""}.fa-user-helmet-safety::before{content:""}.fa-user-construction::before{content:""}.fa-user-hard-hat::before{content:""}.fa-i::before{content:"I"}.fa-hryvnia-sign::before{content:""}.fa-hryvnia::before{content:""}.fa-arrow-down-left-and-arrow-up-right-to-center::before{content:""}.fa-pills::before{content:""}.fa-face-grin-wide::before{content:""}.fa-grin-alt::before{content:""}.fa-tooth::before{content:""}.fa-basketball-hoop::before{content:""}.fa-objects-align-bottom::before{content:""}.fa-v::before{content:"V"}.fa-sparkles::before{content:""}.fa-squid::before{content:""}.fa-leafy-green::before{content:""}.fa-circle-arrow-up-right::before{content:""}.fa-calendars::before{content:""}.fa-bangladeshi-taka-sign::before{content:""}.fa-bicycle::before{content:""}.fa-hammer-war::before{content:""}.fa-circle-d::before{content:""}.fa-spider-black-widow::before{content:""}.fa-staff-snake::before{content:""}.fa-rod-asclepius::before{content:""}.fa-rod-snake::before{content:""}.fa-staff-aesculapius::before{content:""}.fa-pear::before{content:""}.fa-head-side-cough-slash::before{content:""}.fa-file-mov::before{content:""}.fa-triangle::before{content:""}.fa-apartment::before{content:""}.fa-truck-medical::before{content:""}.fa-ambulance::before{content:""}.fa-pepper::before{content:""}.fa-piano::before{content:""}.fa-gun-squirt::before{content:""}.fa-wheat-awn-circle-exclamation::before{content:""}.fa-snowman::before{content:""}.fa-user-alien::before{content:""}.fa-shield-check::before{content:""}.fa-mortar-pestle::before{content:""}.fa-road-barrier::before{content:""}.fa-chart-candlestick::before{content:""}.fa-briefcase-blank::before{content:""}.fa-school::before{content:""}.fa-igloo::before{content:""}.fa-bracket-round::before{content:"\("}.fa-parenthesis::before{content:"\("}.fa-joint::before{content:""}.fa-horse-saddle::before{content:""}.fa-mug-marshmallows::before{content:""}.fa-filters::before{content:""}.fa-bell-on::before{content:""}.fa-angle-right::before{content:""}.fa-dial-med::before{content:""}.fa-horse::before{content:""}.fa-q::before{content:"Q"}.fa-monitor-waveform::before{content:""}.fa-monitor-heart-rate::before{content:""}.fa-link-simple::before{content:""}.fa-whistle::before{content:""}.fa-g::before{content:"G"}.fa-wine-glass-crack::before{content:""}.fa-fragile::before{content:""}.fa-slot-machine::before{content:""}.fa-notes-medical::before{content:""}.fa-car-wash::before{content:""}.fa-escalator::before{content:""}.fa-comment-image::before{content:""}.fa-temperature-half::before{content:""}.fa-temperature-2::before{content:""}.fa-thermometer-2::before{content:""}.fa-thermometer-half::before{content:""}.fa-dong-sign::before{content:""}.fa-donut::before{content:""}.fa-doughnut::before{content:""}.fa-capsules::before{content:""}.fa-poo-storm::before{content:""}.fa-poo-bolt::before{content:""}.fa-tally-1::before{content:""}.fa-file-vector::before{content:""}.fa-face-frown-open::before{content:""}.fa-frown-open::before{content:""}.fa-square-dashed::before{content:""}.fa-bag-shopping-plus::before{content:""}.fa-square-j::before{content:""}.fa-hand-point-up::before{content:""}.fa-money-bill::before{content:""}.fa-arrow-up-big-small::before{content:""}.fa-sort-size-up::before{content:""}.fa-barcode-read::before{content:""}.fa-baguette::before{content:""}.fa-bowl-soft-serve::before{content:""}.fa-face-holding-back-tears::before{content:""}.fa-square-up::before{content:""}.fa-arrow-alt-square-up::before{content:""}.fa-train-subway-tunnel::before{content:""}.fa-subway-tunnel::before{content:""}.fa-square-exclamation::before{content:""}.fa-exclamation-square::before{content:""}.fa-semicolon::before{content:"\;"}.fa-bookmark::before{content:""}.fa-fan-table::before{content:""}.fa-align-justify::before{content:""}.fa-battery-low::before{content:""}.fa-battery-1::before{content:""}.fa-credit-card-front::before{content:""}.fa-brain-arrow-curved-right::before{content:""}.fa-mind-share::before{content:""}.fa-umbrella-beach::before{content:""}.fa-helmet-un::before{content:""}.fa-location-smile::before{content:""}.fa-map-marker-smile::before{content:""}.fa-arrow-left-to-line::before{content:""}.fa-arrow-to-left::before{content:""}.fa-bullseye::before{content:""}.fa-sushi::before{content:""}.fa-nigiri::before{content:""}.fa-message-captions::before{content:""}.fa-comment-alt-captions::before{content:""}.fa-trash-list::before{content:""}.fa-bacon::before{content:""}.fa-option::before{content:""}.fa-raccoon::before{content:""}.fa-hand-point-down::before{content:""}.fa-arrow-up-from-bracket::before{content:""}.fa-head-side-gear::before{content:""}.fa-trash-plus::before{content:""}.fa-file-cad::before{content:""}.fa-objects-align-top::before{content:""}.fa-folder::before{content:""}.fa-folder-blank::before{content:""}.fa-face-anxious-sweat::before{content:""}.fa-credit-card-blank::before{content:""}.fa-file-waveform::before{content:""}.fa-file-medical-alt::before{content:""}.fa-microchip-ai::before{content:""}.fa-mug::before{content:""}.fa-plane-up-slash::before{content:""}.fa-radiation::before{content:""}.fa-pen-circle::before{content:""}.fa-bag-seedling::before{content:""}.fa-chart-simple::before{content:""}.fa-crutches::before{content:""}.fa-circle-parking::before{content:""}.fa-parking-circle::before{content:""}.fa-mars-stroke::before{content:""}.fa-leaf-oak::before{content:""}.fa-square-bolt::before{content:""}.fa-vial::before{content:""}.fa-gauge::before{content:""}.fa-dashboard::before{content:""}.fa-gauge-med::before{content:""}.fa-tachometer-alt-average::before{content:""}.fa-wand-magic-sparkles::before{content:""}.fa-magic-wand-sparkles::before{content:""}.fa-lambda::before{content:""}.fa-e::before{content:"E"}.fa-pizza::before{content:""}.fa-bowl-chopsticks-noodles::before{content:""}.fa-h3::before{content:""}.fa-pen-clip::before{content:""}.fa-pen-alt::before{content:""}.fa-bridge-circle-exclamation::before{content:""}.fa-badge-percent::before{content:""}.fa-rotate-reverse::before{content:""}.fa-user::before{content:""}.fa-sensor::before{content:""}.fa-comma::before{content:"\,"}.fa-school-circle-check::before{content:""}.fa-toilet-paper-under::before{content:""}.fa-toilet-paper-reverse::before{content:""}.fa-light-emergency::before{content:""}.fa-arrow-down-to-arc::before{content:""}.fa-dumpster::before{content:""}.fa-van-shuttle::before{content:""}.fa-shuttle-van::before{content:""}.fa-building-user::before{content:""}.fa-light-switch::before{content:""}.fa-square-caret-left::before{content:""}.fa-caret-square-left::before{content:""}.fa-highlighter::before{content:""}.fa-wave-pulse::before{content:""}.fa-heart-rate::before{content:""}.fa-key::before{content:""}.fa-arrow-left-to-bracket::before{content:""}.fa-hat-santa::before{content:""}.fa-tamale::before{content:""}.fa-box-check::before{content:""}.fa-bullhorn::before{content:""}.fa-steak::before{content:""}.fa-location-crosshairs-slash::before{content:""}.fa-location-slash::before{content:""}.fa-person-dolly::before{content:""}.fa-globe::before{content:""}.fa-synagogue::before{content:""}.fa-file-chart-column::before{content:""}.fa-file-chart-line::before{content:""}.fa-person-half-dress::before{content:""}.fa-folder-image::before{content:""}.fa-calendar-pen::before{content:""}.fa-calendar-edit::before{content:""}.fa-road-bridge::before{content:""}.fa-face-smile-tear::before{content:""}.fa-message-plus::before{content:""}.fa-comment-alt-plus::before{content:""}.fa-location-arrow::before{content:""}.fa-c::before{content:"C"}.fa-tablet-button::before{content:""}.fa-person-dress-fairy::before{content:""}.fa-rectangle-history-circle-user::before{content:""}.fa-building-lock::before{content:""}.fa-chart-line-up::before{content:""}.fa-mailbox::before{content:""}.fa-sign-posts::before{content:""}.fa-truck-bolt::before{content:""}.fa-pizza-slice::before{content:""}.fa-money-bill-wave::before{content:""}.fa-chart-area::before{content:""}.fa-area-chart::before{content:""}.fa-house-flag::before{content:""}.fa-circle-three-quarters-stroke::before{content:""}.fa-person-circle-minus::before{content:""}.fa-scalpel::before{content:""}.fa-ban::before{content:""}.fa-cancel::before{content:""}.fa-bell-exclamation::before{content:""}.fa-circle-bookmark::before{content:""}.fa-bookmark-circle::before{content:""}.fa-egg-fried::before{content:""}.fa-face-weary::before{content:""}.fa-uniform-martial-arts::before{content:""}.fa-camera-rotate::before{content:""}.fa-sun-dust::before{content:""}.fa-comment-text::before{content:""}.fa-spray-can-sparkles::before{content:""}.fa-air-freshener::before{content:""}.fa-signal-bars::before{content:""}.fa-signal-alt::before{content:""}.fa-signal-alt-4::before{content:""}.fa-signal-bars-strong::before{content:""}.fa-diamond-exclamation::before{content:""}.fa-star::before{content:""}.fa-dial-min::before{content:""}.fa-repeat::before{content:""}.fa-cross::before{content:""}.fa-page-caret-down::before{content:""}.fa-file-caret-down::before{content:""}.fa-box::before{content:""}.fa-venus-mars::before{content:""}.fa-clock-seven-thirty::before{content:""}.fa-arrow-pointer::before{content:""}.fa-mouse-pointer::before{content:""}.fa-clock-four-thirty::before{content:""}.fa-signal-bars-good::before{content:""}.fa-signal-alt-3::before{content:""}.fa-cactus::before{content:""}.fa-lightbulb-gear::before{content:""}.fa-maximize::before{content:""}.fa-expand-arrows-alt::before{content:""}.fa-charging-station::before{content:""}.fa-shapes::before{content:""}.fa-triangle-circle-square::before{content:""}.fa-plane-tail::before{content:""}.fa-gauge-simple-max::before{content:""}.fa-tachometer-fastest::before{content:""}.fa-circle-u::before{content:""}.fa-shield-slash::before{content:""}.fa-square-phone-hangup::before{content:""}.fa-phone-square-down::before{content:""}.fa-arrow-up-left::before{content:""}.fa-transporter-1::before{content:""}.fa-peanuts::before{content:""}.fa-shuffle::before{content:""}.fa-random::before{content:""}.fa-person-running::before{content:""}.fa-running::before{content:""}.fa-mobile-retro::before{content:""}.fa-grip-lines-vertical::before{content:""}.fa-bin-bottles-recycle::before{content:""}.fa-arrow-up-from-square::before{content:""}.fa-file-dashed-line::before{content:""}.fa-page-break::before{content:""}.fa-bracket-curly-right::before{content:"\}"}.fa-spider::before{content:""}.fa-clock-three::before{content:""}.fa-hands-bound::before{content:""}.fa-scalpel-line-dashed::before{content:""}.fa-scalpel-path::before{content:""}.fa-file-invoice-dollar::before{content:""}.fa-pipe-smoking::before{content:""}.fa-face-astonished::before{content:""}.fa-window::before{content:""}.fa-plane-circle-exclamation::before{content:""}.fa-ear::before{content:""}.fa-file-lock::before{content:""}.fa-diagram-venn::before{content:""}.fa-arrow-down-from-bracket::before{content:""}.fa-x-ray::before{content:""}.fa-goal-net::before{content:""}.fa-coffin-cross::before{content:""}.fa-octopus::before{content:""}.fa-spell-check::before{content:""}.fa-location-xmark::before{content:""}.fa-map-marker-times::before{content:""}.fa-map-marker-xmark::before{content:""}.fa-circle-quarter-stroke::before{content:""}.fa-lasso::before{content:""}.fa-slash::before{content:""}.fa-person-to-portal::before{content:""}.fa-portal-enter::before{content:""}.fa-calendar-star::before{content:""}.fa-computer-mouse::before{content:""}.fa-mouse::before{content:""}.fa-arrow-right-to-bracket::before{content:""}.fa-sign-in::before{content:""}.fa-pegasus::before{content:""}.fa-files-medical::before{content:""}.fa-cannon::before{content:""}.fa-nfc-lock::before{content:""}.fa-person-ski-lift::before{content:""}.fa-ski-lift::before{content:""}.fa-square-6::before{content:""}.fa-shop-slash::before{content:""}.fa-store-alt-slash::before{content:""}.fa-wind-turbine::before{content:""}.fa-sliders-simple::before{content:""}.fa-grid-round::before{content:""}.fa-badge-sheriff::before{content:""}.fa-server::before{content:""}.fa-virus-covid-slash::before{content:""}.fa-intersection::before{content:""}.fa-shop-lock::before{content:""}.fa-family::before{content:""}.fa-hourglass-start::before{content:""}.fa-hourglass-1::before{content:""}.fa-user-hair-buns::before{content:""}.fa-blender-phone::before{content:""}.fa-hourglass-clock::before{content:""}.fa-person-seat-reclined::before{content:""}.fa-paper-plane-top::before{content:""}.fa-paper-plane-alt::before{content:""}.fa-send::before{content:""}.fa-message-arrow-up::before{content:""}.fa-comment-alt-arrow-up::before{content:""}.fa-lightbulb-exclamation::before{content:""}.fa-layer-minus::before{content:""}.fa-layer-group-minus::before{content:""}.fa-chart-pie-simple-circle-currency::before{content:""}.fa-circle-e::before{content:""}.fa-building-wheat::before{content:""}.fa-gauge-max::before{content:""}.fa-tachometer-alt-fastest::before{content:""}.fa-person-breastfeeding::before{content:""}.fa-apostrophe::before{content:"\'"}.fa-file-png::before{content:""}.fa-fire-hydrant::before{content:""}.fa-right-to-bracket::before{content:""}.fa-sign-in-alt::before{content:""}.fa-video-plus::before{content:""}.fa-square-right::before{content:""}.fa-arrow-alt-square-right::before{content:""}.fa-comment-smile::before{content:""}.fa-venus::before{content:""}.fa-passport::before{content:""}.fa-thumbtack-slash::before{content:""}.fa-thumb-tack-slash::before{content:""}.fa-inbox-in::before{content:""}.fa-inbox-arrow-down::before{content:""}.fa-heart-pulse::before{content:""}.fa-heartbeat::before{content:""}.fa-circle-8::before{content:""}.fa-clouds-moon::before{content:""}.fa-clock-ten-thirty::before{content:""}.fa-people-carry-box::before{content:""}.fa-people-carry::before{content:""}.fa-folder-user::before{content:""}.fa-trash-can-xmark::before{content:""}.fa-temperature-high::before{content:""}.fa-microchip::before{content:""}.fa-left-long-to-line::before{content:""}.fa-crown::before{content:""}.fa-weight-hanging::before{content:""}.fa-xmarks-lines::before{content:""}.fa-file-prescription::before{content:""}.fa-table-cells-lock::before{content:""}.fa-calendar-range::before{content:""}.fa-flower-daffodil::before{content:""}.fa-hand-back-point-up::before{content:""}.fa-weight-scale::before{content:""}.fa-weight::before{content:""}.fa-arrow-up-to-arc::before{content:""}.fa-star-exclamation::before{content:""}.fa-books::before{content:""}.fa-user-group::before{content:""}.fa-user-friends::before{content:""}.fa-arrow-up-a-z::before{content:""}.fa-sort-alpha-up::before{content:""}.fa-layer-plus::before{content:""}.fa-layer-group-plus::before{content:""}.fa-play-pause::before{content:""}.fa-block-question::before{content:""}.fa-snooze::before{content:""}.fa-zzz::before{content:""}.fa-scanner-image::before{content:""}.fa-tv-retro::before{content:""}.fa-square-t::before{content:""}.fa-farm::before{content:""}.fa-barn-silo::before{content:""}.fa-chess-knight::before{content:""}.fa-bars-sort::before{content:""}.fa-pallet-boxes::before{content:""}.fa-palette-boxes::before{content:""}.fa-pallet-alt::before{content:""}.fa-face-laugh-squint::before{content:""}.fa-laugh-squint::before{content:""}.fa-code-simple::before{content:""}.fa-bolt-slash::before{content:""}.fa-panel-fire::before{content:""}.fa-binary-circle-check::before{content:""}.fa-comment-minus::before{content:""}.fa-burrito::before{content:""}.fa-violin::before{content:""}.fa-objects-column::before{content:""}.fa-square-chevron-down::before{content:""}.fa-chevron-square-down::before{content:""}.fa-comment-plus::before{content:""}.fa-triangle-instrument::before{content:""}.fa-triangle-music::before{content:""}.fa-wheelchair::before{content:""}.fa-user-pilot-tie::before{content:""}.fa-piano-keyboard::before{content:""}.fa-bed-empty::before{content:""}.fa-circle-arrow-up::before{content:""}.fa-arrow-circle-up::before{content:""}.fa-toggle-on::before{content:""}.fa-rectangle-vertical::before{content:""}.fa-rectangle-portrait::before{content:""}.fa-person-walking::before{content:""}.fa-walking::before{content:""}.fa-l::before{content:"L"}.fa-signal-stream::before{content:""}.fa-down-to-bracket::before{content:""}.fa-circle-z::before{content:""}.fa-stars::before{content:""}.fa-fire::before{content:""}.fa-bed-pulse::before{content:""}.fa-procedures::before{content:""}.fa-house-day::before{content:""}.fa-shuttle-space::before{content:""}.fa-space-shuttle::before{content:""}.fa-shirt-long-sleeve::before{content:""}.fa-chart-pie-simple::before{content:""}.fa-chart-pie-alt::before{content:""}.fa-face-laugh::before{content:""}.fa-laugh::before{content:""}.fa-folder-open::before{content:""}.fa-album-collection-circle-user::before{content:""}.fa-candy::before{content:""}.fa-bowl-hot::before{content:""}.fa-soup::before{content:""}.fa-flatbread::before{content:""}.fa-heart-circle-plus::before{content:""}.fa-code-fork::before{content:""}.fa-city::before{content:""}.fa-signal-bars-weak::before{content:""}.fa-signal-alt-1::before{content:""}.fa-microphone-lines::before{content:""}.fa-microphone-alt::before{content:""}.fa-clock-twelve::before{content:""}.fa-pepper-hot::before{content:""}.fa-citrus-slice::before{content:""}.fa-sheep::before{content:""}.fa-unlock::before{content:""}.fa-colon-sign::before{content:""}.fa-headset::before{content:""}.fa-badger-honey::before{content:""}.fa-h4::before{content:""}.fa-store-slash::before{content:""}.fa-road-circle-xmark::before{content:""}.fa-signal-slash::before{content:""}.fa-user-minus::before{content:""}.fa-mars-stroke-up::before{content:""}.fa-mars-stroke-v::before{content:""}.fa-champagne-glasses::before{content:""}.fa-glass-cheers::before{content:""}.fa-taco::before{content:""}.fa-hexagon-plus::before{content:""}.fa-plus-hexagon::before{content:""}.fa-clipboard::before{content:""}.fa-house-circle-exclamation::before{content:""}.fa-file-arrow-up::before{content:""}.fa-file-upload::before{content:""}.fa-wifi::before{content:""}.fa-wifi-3::before{content:""}.fa-wifi-strong::before{content:""}.fa-messages::before{content:""}.fa-comments-alt::before{content:""}.fa-bath::before{content:""}.fa-bathtub::before{content:""}.fa-umbrella-simple::before{content:""}.fa-umbrella-alt::before{content:""}.fa-rectangle-history-circle-plus::before{content:""}.fa-underline::before{content:""}.fa-prescription-bottle-pill::before{content:""}.fa-user-pen::before{content:""}.fa-user-edit::before{content:""}.fa-binary-slash::before{content:""}.fa-square-o::before{content:""}.fa-caduceus::before{content:""}.fa-signature::before{content:""}.fa-stroopwafel::before{content:""}.fa-bold::before{content:""}.fa-anchor-lock::before{content:""}.fa-building-ngo::before{content:""}.fa-transporter-3::before{content:""}.fa-engine-warning::before{content:""}.fa-engine-exclamation::before{content:""}.fa-circle-down-right::before{content:""}.fa-square-k::before{content:""}.fa-manat-sign::before{content:""}.fa-money-check-pen::before{content:""}.fa-money-check-edit::before{content:""}.fa-not-equal::before{content:""}.fa-border-top-left::before{content:""}.fa-border-style::before{content:""}.fa-map-location-dot::before{content:""}.fa-map-marked-alt::before{content:""}.fa-tilde::before{content:"\~"}.fa-jedi::before{content:""}.fa-square-poll-vertical::before{content:""}.fa-poll::before{content:""}.fa-arrow-down-square-triangle::before{content:""}.fa-sort-shapes-down-alt::before{content:""}.fa-mug-hot::before{content:""}.fa-dog-leashed::before{content:""}.fa-car-battery::before{content:""}.fa-battery-car::before{content:""}.fa-face-downcast-sweat::before{content:""}.fa-mailbox-flag-up::before{content:""}.fa-memo-circle-info::before{content:""}.fa-gift::before{content:""}.fa-dice-two::before{content:""}.fa-volume::before{content:""}.fa-volume-medium::before{content:""}.fa-transporter-5::before{content:""}.fa-gauge-circle-bolt::before{content:""}.fa-coin-front::before{content:""}.fa-file-slash::before{content:""}.fa-message-arrow-up-right::before{content:""}.fa-treasure-chest::before{content:""}.fa-chess-queen::before{content:""}.fa-paintbrush-fine::before{content:""}.fa-paint-brush-alt::before{content:""}.fa-paint-brush-fine::before{content:""}.fa-paintbrush-alt::before{content:""}.fa-glasses::before{content:""}.fa-hood-cloak::before{content:""}.fa-square-quote::before{content:""}.fa-up-left::before{content:""}.fa-bring-front::before{content:""}.fa-chess-board::before{content:""}.fa-burger-cheese::before{content:""}.fa-cheeseburger::before{content:""}.fa-building-circle-check::before{content:""}.fa-repeat-1::before{content:""}.fa-arrow-down-to-line::before{content:""}.fa-arrow-to-bottom::before{content:""}.fa-grid-5::before{content:""}.fa-swap-arrows::before{content:""}.fa-right-long-to-line::before{content:""}.fa-person-chalkboard::before{content:""}.fa-mars-stroke-right::before{content:""}.fa-mars-stroke-h::before{content:""}.fa-hand-back-fist::before{content:""}.fa-hand-rock::before{content:""}.fa-grid-round-5::before{content:""}.fa-tally::before{content:""}.fa-tally-5::before{content:""}.fa-square-caret-up::before{content:""}.fa-caret-square-up::before{content:""}.fa-cloud-showers-water::before{content:""}.fa-chart-bar::before{content:""}.fa-bar-chart::before{content:""}.fa-hands-bubbles::before{content:""}.fa-hands-wash::before{content:""}.fa-less-than-equal::before{content:""}.fa-train::before{content:""}.fa-up-from-dotted-line::before{content:""}.fa-eye-low-vision::before{content:""}.fa-low-vision::before{content:""}.fa-traffic-light-go::before{content:""}.fa-face-exhaling::before{content:""}.fa-sensor-fire::before{content:""}.fa-user-unlock::before{content:""}.fa-hexagon-divide::before{content:""}.fa-00::before{content:""}.fa-crow::before{content:""}.fa-cassette-betamax::before{content:""}.fa-betamax::before{content:""}.fa-sailboat::before{content:""}.fa-window-restore::before{content:""}.fa-nfc-magnifying-glass::before{content:""}.fa-file-binary::before{content:""}.fa-circle-v::before{content:""}.fa-square-plus::before{content:""}.fa-plus-square::before{content:""}.fa-bowl-scoops::before{content:""}.fa-mistletoe::before{content:""}.fa-custard::before{content:""}.fa-lacrosse-stick::before{content:""}.fa-hockey-mask::before{content:""}.fa-sunrise::before{content:""}.fa-subtitles::before{content:""}.fa-panel-ews::before{content:""}.fa-torii-gate::before{content:""}.fa-cloud-exclamation::before{content:""}.fa-message-lines::before{content:""}.fa-comment-alt-lines::before{content:""}.fa-frog::before{content:""}.fa-bucket::before{content:""}.fa-floppy-disk-pen::before{content:""}.fa-image::before{content:""}.fa-window-frame::before{content:""}.fa-microphone::before{content:""}.fa-cow::before{content:""}.fa-file-zip::before{content:""}.fa-square-ring::before{content:""}.fa-down-from-line::before{content:""}.fa-arrow-alt-from-top::before{content:""}.fa-caret-up::before{content:""}.fa-shield-xmark::before{content:""}.fa-shield-times::before{content:""}.fa-screwdriver::before{content:""}.fa-circle-sort-down::before{content:""}.fa-sort-circle-down::before{content:""}.fa-folder-closed::before{content:""}.fa-house-tsunami::before{content:""}.fa-square-nfi::before{content:""}.fa-forklift::before{content:""}.fa-arrow-up-from-ground-water::before{content:""}.fa-bracket-square-right::before{content:"\]"}.fa-martini-glass::before{content:""}.fa-glass-martini-alt::before{content:""}.fa-rotate-left::before{content:""}.fa-rotate-back::before{content:""}.fa-rotate-backward::before{content:""}.fa-undo-alt::before{content:""}.fa-table-columns::before{content:""}.fa-columns::before{content:""}.fa-square-a::before{content:""}.fa-tick::before{content:""}.fa-lemon::before{content:""}.fa-head-side-mask::before{content:""}.fa-handshake::before{content:""}.fa-gem::before{content:""}.fa-dolly::before{content:""}.fa-dolly-box::before{content:""}.fa-smoking::before{content:""}.fa-minimize::before{content:""}.fa-compress-arrows-alt::before{content:""}.fa-refrigerator::before{content:""}.fa-monument::before{content:""}.fa-octagon-xmark::before{content:""}.fa-times-octagon::before{content:""}.fa-xmark-octagon::before{content:""}.fa-align-slash::before{content:""}.fa-snowplow::before{content:""}.fa-angles-right::before{content:""}.fa-angle-double-right::before{content:""}.fa-truck-ramp-couch::before{content:""}.fa-truck-couch::before{content:""}.fa-cannabis::before{content:""}.fa-circle-play::before{content:""}.fa-play-circle::before{content:""}.fa-arrow-up-right-and-arrow-down-left-from-center::before{content:""}.fa-location-arrow-up::before{content:""}.fa-tablets::before{content:""}.fa-360-degrees::before{content:""}.fa-ethernet::before{content:""}.fa-euro-sign::before{content:""}.fa-eur::before{content:""}.fa-euro::before{content:""}.fa-chair::before{content:""}.fa-circle-check::before{content:""}.fa-check-circle::before{content:""}.fa-square-dashed-circle-plus::before{content:""}.fa-hand-holding-circle-dollar::before{content:""}.fa-money-simple-from-bracket::before{content:""}.fa-bat::before{content:""}.fa-circle-stop::before{content:""}.fa-stop-circle::before{content:""}.fa-head-side-headphones::before{content:""}.fa-phone-rotary::before{content:""}.fa-arrow-up-to-bracket::before{content:""}.fa-compass-drafting::before{content:""}.fa-drafting-compass::before{content:""}.fa-plate-wheat::before{content:""}.fa-calendar-circle-minus::before{content:""}.fa-chopsticks::before{content:""}.fa-car-wrench::before{content:""}.fa-car-mechanic::before{content:""}.fa-icicles::before{content:""}.fa-person-shelter::before{content:""}.fa-neuter::before{content:""}.fa-id-badge::before{content:""}.fa-kazoo::before{content:""}.fa-marker::before{content:""}.fa-bin-bottles::before{content:""}.fa-face-laugh-beam::before{content:""}.fa-laugh-beam::before{content:""}.fa-square-arrow-down-left::before{content:""}.fa-battery-bolt::before{content:""}.fa-tree-large::before{content:""}.fa-helicopter-symbol::before{content:""}.fa-aperture::before{content:""}.fa-universal-access::before{content:""}.fa-gear-complex::before{content:""}.fa-file-magnifying-glass::before{content:""}.fa-file-search::before{content:""}.fa-up-right::before{content:""}.fa-circle-chevron-up::before{content:""}.fa-chevron-circle-up::before{content:""}.fa-user-police::before{content:""}.fa-lari-sign::before{content:""}.fa-volcano::before{content:""}.fa-teddy-bear::before{content:""}.fa-stocking::before{content:""}.fa-person-walking-dashed-line-arrow-right::before{content:""}.fa-image-slash::before{content:""}.fa-mask-snorkel::before{content:""}.fa-smoke::before{content:""}.fa-sterling-sign::before{content:""}.fa-gbp::before{content:""}.fa-pound-sign::before{content:""}.fa-battery-exclamation::before{content:""}.fa-viruses::before{content:""}.fa-square-person-confined::before{content:""}.fa-user-tie::before{content:""}.fa-up-to-bracket::before{content:""}.fa-arrow-down-long::before{content:""}.fa-long-arrow-down::before{content:""}.fa-tent-arrow-down-to-line::before{content:""}.fa-certificate::before{content:""}.fa-crystal-ball::before{content:""}.fa-reply-all::before{content:""}.fa-mail-reply-all::before{content:""}.fa-suitcase::before{content:""}.fa-person-skating::before{content:""}.fa-skating::before{content:""}.fa-star-shooting::before{content:""}.fa-binary-lock::before{content:""}.fa-filter-circle-dollar::before{content:""}.fa-funnel-dollar::before{content:""}.fa-camera-retro::before{content:""}.fa-circle-arrow-down::before{content:""}.fa-arrow-circle-down::before{content:""}.fa-comment-pen::before{content:""}.fa-comment-edit::before{content:""}.fa-file-import::before{content:""}.fa-arrow-right-to-file::before{content:""}.fa-banjo::before{content:""}.fa-square-arrow-up-right::before{content:""}.fa-external-link-square::before{content:""}.fa-light-emergency-on::before{content:""}.fa-kerning::before{content:""}.fa-box-open::before{content:""}.fa-square-f::before{content:""}.fa-scroll::before{content:""}.fa-spa::before{content:""}.fa-arrow-left-from-line::before{content:""}.fa-arrow-from-right::before{content:""}.fa-strawberry::before{content:""}.fa-location-pin-lock::before{content:""}.fa-pause::before{content:""}.fa-clock-eight-thirty::before{content:""}.fa-plane-engines::before{content:""}.fa-plane-alt::before{content:""}.fa-hill-avalanche::before{content:""}.fa-temperature-empty::before{content:""}.fa-temperature-0::before{content:""}.fa-thermometer-0::before{content:""}.fa-thermometer-empty::before{content:""}.fa-bomb::before{content:""}.fa-gauge-low::before{content:""}.fa-tachometer-alt-slow::before{content:""}.fa-registered::before{content:""}.fa-trash-can-plus::before{content:""}.fa-address-card::before{content:""}.fa-contact-card::before{content:""}.fa-vcard::before{content:""}.fa-scale-unbalanced-flip::before{content:""}.fa-balance-scale-right::before{content:""}.fa-globe-snow::before{content:""}.fa-subscript::before{content:""}.fa-diamond-turn-right::before{content:""}.fa-directions::before{content:""}.fa-integral::before{content:""}.fa-burst::before{content:""}.fa-house-laptop::before{content:""}.fa-laptop-house::before{content:""}.fa-face-tired::before{content:""}.fa-tired::before{content:""}.fa-money-bills::before{content:""}.fa-blinds-raised::before{content:""}.fa-smog::before{content:""}.fa-ufo-beam::before{content:""}.fa-hydra::before{content:""}.fa-circle-caret-up::before{content:""}.fa-caret-circle-up::before{content:""}.fa-user-vneck-hair-long::before{content:""}.fa-square-a-lock::before{content:""}.fa-crutch::before{content:""}.fa-gas-pump-slash::before{content:""}.fa-cloud-arrow-up::before{content:""}.fa-cloud-upload::before{content:""}.fa-cloud-upload-alt::before{content:""}.fa-palette::before{content:""}.fa-transporter-4::before{content:""}.fa-chart-mixed-up-circle-currency::before{content:""}.fa-objects-align-right::before{content:""}.fa-arrows-turn-right::before{content:""}.fa-vest::before{content:""}.fa-pig::before{content:""}.fa-inbox-full::before{content:""}.fa-circle-envelope::before{content:""}.fa-envelope-circle::before{content:""}.fa-triangle-person-digging::before{content:""}.fa-construction::before{content:""}.fa-ferry::before{content:""}.fa-bullseye-arrow::before{content:""}.fa-arrows-down-to-people::before{content:""}.fa-seedling::before{content:""}.fa-sprout::before{content:""}.fa-clock-seven::before{content:""}.fa-left-right::before{content:""}.fa-arrows-alt-h::before{content:""}.fa-boxes-packing::before{content:""}.fa-circle-arrow-left::before{content:""}.fa-arrow-circle-left::before{content:""}.fa-flashlight::before{content:""}.fa-file-jpg::before{content:""}.fa-group-arrows-rotate::before{content:""}.fa-bowl-food::before{content:""}.fa-square-9::before{content:""}.fa-candy-cane::before{content:""}.fa-arrow-down-wide-short::before{content:""}.fa-sort-amount-asc::before{content:""}.fa-sort-amount-down::before{content:""}.fa-square-dollar::before{content:""}.fa-dollar-square::before{content:""}.fa-usd-square::before{content:""}.fa-phone-arrow-right::before{content:""}.fa-hand-holding-seedling::before{content:""}.fa-message-check::before{content:""}.fa-comment-alt-check::before{content:""}.fa-cloud-bolt::before{content:""}.fa-thunderstorm::before{content:""}.fa-chart-line-up-down::before{content:""}.fa-text-slash::before{content:""}.fa-remove-format::before{content:""}.fa-watch::before{content:""}.fa-circle-down-left::before{content:""}.fa-text::before{content:""}.fa-projector::before{content:""}.fa-face-smile-wink::before{content:""}.fa-smile-wink::before{content:""}.fa-tombstone-blank::before{content:""}.fa-tombstone-alt::before{content:""}.fa-chess-king-piece::before{content:""}.fa-chess-king-alt::before{content:""}.fa-circle-6::before{content:""}.fa-waves-sine::before{content:""}.fa-left::before{content:""}.fa-arrow-alt-left::before{content:""}.fa-file-word::before{content:""}.fa-file-powerpoint::before{content:""}.fa-square-down::before{content:""}.fa-arrow-alt-square-down::before{content:""}.fa-objects-align-center-vertical::before{content:""}.fa-arrows-left-right::before{content:""}.fa-arrows-h::before{content:""}.fa-house-lock::before{content:""}.fa-cloud-arrow-down::before{content:""}.fa-cloud-download::before{content:""}.fa-cloud-download-alt::before{content:""}.fa-wreath::before{content:""}.fa-children::before{content:""}.fa-meter-droplet::before{content:""}.fa-chalkboard::before{content:""}.fa-blackboard::before{content:""}.fa-user-large-slash::before{content:""}.fa-user-alt-slash::before{content:""}.fa-signal-strong::before{content:""}.fa-signal-4::before{content:""}.fa-lollipop::before{content:""}.fa-lollypop::before{content:""}.fa-list-tree::before{content:""}.fa-envelope-open::before{content:""}.fa-draw-circle::before{content:""}.fa-cat-space::before{content:""}.fa-handshake-simple-slash::before{content:""}.fa-handshake-alt-slash::before{content:""}.fa-rabbit-running::before{content:""}.fa-rabbit-fast::before{content:""}.fa-memo-pad::before{content:""}.fa-mattress-pillow::before{content:""}.fa-alarm-plus::before{content:""}.fa-alicorn::before{content:""}.fa-comment-question::before{content:""}.fa-gingerbread-man::before{content:""}.fa-guarani-sign::before{content:""}.fa-burger-fries::before{content:""}.fa-mug-tea::before{content:""}.fa-border-top::before{content:""}.fa-arrows-rotate::before{content:""}.fa-refresh::before{content:""}.fa-sync::before{content:""}.fa-circle-book-open::before{content:""}.fa-book-circle::before{content:""}.fa-arrows-to-dotted-line::before{content:""}.fa-fire-extinguisher::before{content:""}.fa-magnifying-glass-arrows-rotate::before{content:""}.fa-garage-open::before{content:""}.fa-shelves-empty::before{content:""}.fa-cruzeiro-sign::before{content:""}.fa-watch-apple::before{content:""}.fa-watch-calculator::before{content:""}.fa-list-dropdown::before{content:""}.fa-cabinet-filing::before{content:""}.fa-burger-soda::before{content:""}.fa-square-arrow-up::before{content:""}.fa-arrow-square-up::before{content:""}.fa-greater-than-equal::before{content:""}.fa-pallet-box::before{content:""}.fa-face-confounded::before{content:""}.fa-shield-halved::before{content:""}.fa-shield-alt::before{content:""}.fa-truck-plow::before{content:""}.fa-book-atlas::before{content:""}.fa-atlas::before{content:""}.fa-virus::before{content:""}.fa-grid-round-2::before{content:""}.fa-comment-middle-top::before{content:""}.fa-wave::before{content:""}.fa-envelope-circle-check::before{content:""}.fa-layer-group::before{content:""}.fa-restroom-simple::before{content:""}.fa-arrows-to-dot::before{content:""}.fa-border-outer::before{content:""}.fa-hashtag-lock::before{content:""}.fa-clock-two-thirty::before{content:""}.fa-archway::before{content:""}.fa-heart-circle-check::before{content:""}.fa-house-chimney-crack::before{content:""}.fa-house-damage::before{content:""}.fa-file-zipper::before{content:""}.fa-file-archive::before{content:""}.fa-ticket-perforated::before{content:""}.fa-heart-half::before{content:""}.fa-comment-check::before{content:""}.fa-square::before{content:""}.fa-memo::before{content:""}.fa-martini-glass-empty::before{content:""}.fa-glass-martini::before{content:""}.fa-couch::before{content:""}.fa-cedi-sign::before{content:""}.fa-italic::before{content:""}.fa-glass-citrus::before{content:""}.fa-calendar-lines-pen::before{content:""}.fa-table-cells-column-lock::before{content:""}.fa-church::before{content:""}.fa-person-snowmobiling::before{content:""}.fa-snowmobile::before{content:""}.fa-face-hushed::before{content:""}.fa-comments-dollar::before{content:""}.fa-tickets-simple::before{content:""}.fa-pickaxe::before{content:""}.fa-link-simple-slash::before{content:""}.fa-democrat::before{content:""}.fa-face-confused::before{content:""}.fa-pinball::before{content:""}.fa-z::before{content:"Z"}.fa-person-skiing::before{content:""}.fa-skiing::before{content:""}.fa-deer::before{content:""}.fa-input-pipe::before{content:""}.fa-road-lock::before{content:""}.fa-a::before{content:"A"}.fa-bookmark-slash::before{content:""}.fa-temperature-arrow-down::before{content:""}.fa-temperature-down::before{content:""}.fa-mace::before{content:""}.fa-feather-pointed::before{content:""}.fa-feather-alt::before{content:""}.fa-sausage::before{content:""}.fa-trash-can-clock::before{content:""}.fa-p::before{content:"P"}.fa-broom-wide::before{content:""}.fa-snowflake::before{content:""}.fa-stomach::before{content:""}.fa-newspaper::before{content:""}.fa-rectangle-ad::before{content:""}.fa-ad::before{content:""}.fa-guitar-electric::before{content:""}.fa-arrow-turn-down-right::before{content:""}.fa-moon-cloud::before{content:""}.fa-bread-slice-butter::before{content:""}.fa-circle-arrow-right::before{content:""}.fa-arrow-circle-right::before{content:""}.fa-user-group-crown::before{content:""}.fa-users-crown::before{content:""}.fa-circle-i::before{content:""}.fa-toilet-paper-check::before{content:""}.fa-filter-circle-xmark::before{content:""}.fa-locust::before{content:""}.fa-sort::before{content:""}.fa-unsorted::before{content:""}.fa-list-ol::before{content:""}.fa-list-1-2::before{content:""}.fa-list-numeric::before{content:""}.fa-chart-waterfall::before{content:""}.fa-sparkle::before{content:""}.fa-face-party::before{content:""}.fa-kidneys::before{content:""}.fa-wifi-exclamation::before{content:""}.fa-chart-network::before{content:""}.fa-person-dress-burst::before{content:""}.fa-dice-d4::before{content:""}.fa-money-check-dollar::before{content:""}.fa-money-check-alt::before{content:""}.fa-vector-square::before{content:""}.fa-bread-slice::before{content:""}.fa-language::before{content:""}.fa-wheat-awn-slash::before{content:""}.fa-face-kiss-wink-heart::before{content:""}.fa-kiss-wink-heart::before{content:""}.fa-dagger::before{content:""}.fa-podium::before{content:""}.fa-diamonds-4::before{content:""}.fa-memo-circle-check::before{content:""}.fa-route-highway::before{content:""}.fa-down-to-line::before{content:""}.fa-arrow-alt-to-bottom::before{content:""}.fa-filter::before{content:""}.fa-square-g::before{content:""}.fa-circle-phone::before{content:""}.fa-phone-circle::before{content:""}.fa-clipboard-prescription::before{content:""}.fa-user-nurse-hair::before{content:""}.fa-question::before{content:"\?"}.fa-file-signature::before{content:""}.fa-toggle-large-on::before{content:""}.fa-up-down-left-right::before{content:""}.fa-arrows-alt::before{content:""}.fa-dryer-heat::before{content:""}.fa-dryer-alt::before{content:""}.fa-house-chimney-user::before{content:""}.fa-hand-holding-heart::before{content:""}.fa-arrow-up-small-big::before{content:""}.fa-sort-size-up-alt::before{content:""}.fa-train-track::before{content:""}.fa-puzzle-piece::before{content:""}.fa-money-check::before{content:""}.fa-star-half-stroke::before{content:""}.fa-star-half-alt::before{content:""}.fa-file-exclamation::before{content:""}.fa-code::before{content:""}.fa-whiskey-glass::before{content:""}.fa-glass-whiskey::before{content:""}.fa-moon-stars::before{content:""}.fa-building-circle-exclamation::before{content:""}.fa-clothes-hanger::before{content:""}.fa-mobile-notch::before{content:""}.fa-mobile-iphone::before{content:""}.fa-magnifying-glass-chart::before{content:""}.fa-arrow-up-right-from-square::before{content:""}.fa-external-link::before{content:""}.fa-cubes-stacked::before{content:""}.fa-images-user::before{content:""}.fa-won-sign::before{content:""}.fa-krw::before{content:""}.fa-won::before{content:""}.fa-image-polaroid-user::before{content:""}.fa-virus-covid::before{content:""}.fa-square-ellipsis::before{content:""}.fa-pie::before{content:""}.fa-chess-knight-piece::before{content:""}.fa-chess-knight-alt::before{content:""}.fa-austral-sign::before{content:""}.fa-cloud-plus::before{content:""}.fa-f::before{content:"F"}.fa-leaf::before{content:""}.fa-bed-bunk::before{content:""}.fa-road::before{content:""}.fa-taxi::before{content:""}.fa-cab::before{content:""}.fa-person-circle-plus::before{content:""}.fa-chart-pie::before{content:""}.fa-pie-chart::before{content:""}.fa-bolt-lightning::before{content:""}.fa-clock-eight::before{content:""}.fa-sack-xmark::before{content:""}.fa-file-xls::before{content:""}.fa-file-excel::before{content:""}.fa-file-contract::before{content:""}.fa-fish-fins::before{content:""}.fa-circle-q::before{content:""}.fa-building-flag::before{content:""}.fa-face-grin-beam::before{content:""}.fa-grin-beam::before{content:""}.fa-object-ungroup::before{content:""}.fa-face-disguise::before{content:""}.fa-circle-arrow-down-right::before{content:""}.fa-alien-8bit::before{content:""}.fa-alien-monster::before{content:""}.fa-hand-point-ribbon::before{content:""}.fa-poop::before{content:""}.fa-object-exclude::before{content:""}.fa-telescope::before{content:""}.fa-location-pin::before{content:""}.fa-map-marker::before{content:""}.fa-square-list::before{content:""}.fa-kaaba::before{content:""}.fa-toilet-paper::before{content:""}.fa-helmet-safety::before{content:""}.fa-hard-hat::before{content:""}.fa-hat-hard::before{content:""}.fa-comment-code::before{content:""}.fa-sim-cards::before{content:""}.fa-starship::before{content:""}.fa-eject::before{content:""}.fa-circle-right::before{content:""}.fa-arrow-alt-circle-right::before{content:""}.fa-plane-circle-check::before{content:""}.fa-seal::before{content:""}.fa-user-cowboy::before{content:""}.fa-hexagon-vertical-nft::before{content:""}.fa-face-rolling-eyes::before{content:""}.fa-meh-rolling-eyes::before{content:""}.fa-bread-loaf::before{content:""}.fa-rings-wedding::before{content:""}.fa-object-group::before{content:""}.fa-french-fries::before{content:""}.fa-chart-line::before{content:""}.fa-line-chart::before{content:""}.fa-calendar-arrow-down::before{content:""}.fa-calendar-download::before{content:""}.fa-send-back::before{content:""}.fa-mask-ventilator::before{content:""}.fa-tickets::before{content:""}.fa-signature-lock::before{content:""}.fa-arrow-right::before{content:""}.fa-signs-post::before{content:""}.fa-map-signs::before{content:""}.fa-octagon-plus::before{content:""}.fa-plus-octagon::before{content:""}.fa-cash-register::before{content:""}.fa-person-circle-question::before{content:""}.fa-melon-slice::before{content:""}.fa-space-station-moon::before{content:""}.fa-message-smile::before{content:""}.fa-comment-alt-smile::before{content:""}.fa-cup-straw::before{content:""}.fa-left-from-line::before{content:""}.fa-arrow-alt-from-right::before{content:""}.fa-h::before{content:"H"}.fa-basket-shopping-simple::before{content:""}.fa-shopping-basket-alt::before{content:""}.fa-hands-holding-heart::before{content:""}.fa-hands-heart::before{content:""}.fa-clock-nine::before{content:""}.fa-hammer-brush::before{content:""}.fa-tarp::before{content:""}.fa-face-sleepy::before{content:""}.fa-hand-horns::before{content:""}.fa-screwdriver-wrench::before{content:""}.fa-tools::before{content:""}.fa-arrows-to-eye::before{content:""}.fa-circle-three-quarters::before{content:""}.fa-trophy-star::before{content:""}.fa-trophy-alt::before{content:""}.fa-plug-circle-bolt::before{content:""}.fa-face-thermometer::before{content:""}.fa-grid-round-4::before{content:""}.fa-sign-posts-wrench::before{content:""}.fa-shirt-running::before{content:""}.fa-book-circle-arrow-up::before{content:""}.fa-face-nauseated::before{content:""}.fa-heart::before{content:""}.fa-file-chart-pie::before{content:""}.fa-mars-and-venus::before{content:""}.fa-house-user::before{content:""}.fa-home-user::before{content:""}.fa-circle-arrow-down-left::before{content:""}.fa-dumpster-fire::before{content:""}.fa-hexagon-minus::before{content:""}.fa-minus-hexagon::before{content:""}.fa-left-to-line::before{content:""}.fa-arrow-alt-to-left::before{content:""}.fa-house-crack::before{content:""}.fa-paw-simple::before{content:""}.fa-paw-alt::before{content:""}.fa-arrow-left-long-to-line::before{content:""}.fa-brackets-round::before{content:""}.fa-parentheses::before{content:""}.fa-martini-glass-citrus::before{content:""}.fa-cocktail::before{content:""}.fa-user-shakespeare::before{content:""}.fa-arrow-right-to-arc::before{content:""}.fa-face-surprise::before{content:""}.fa-surprise::before{content:""}.fa-bottle-water::before{content:""}.fa-circle-pause::before{content:""}.fa-pause-circle::before{content:""}.fa-gauge-circle-plus::before{content:""}.fa-folders::before{content:""}.fa-angel::before{content:""}.fa-value-absolute::before{content:""}.fa-rabbit::before{content:""}.fa-toilet-paper-slash::before{content:""}.fa-circle-euro::before{content:""}.fa-apple-whole::before{content:""}.fa-apple-alt::before{content:""}.fa-kitchen-set::before{content:""}.fa-diamond-half::before{content:""}.fa-lock-keyhole::before{content:""}.fa-lock-alt::before{content:""}.fa-r::before{content:"R"}.fa-temperature-quarter::before{content:""}.fa-temperature-1::before{content:""}.fa-thermometer-1::before{content:""}.fa-thermometer-quarter::before{content:""}.fa-square-info::before{content:""}.fa-info-square::before{content:""}.fa-wifi-slash::before{content:""}.fa-toilet-paper-xmark::before{content:""}.fa-hands-holding-dollar::before{content:""}.fa-hands-usd::before{content:""}.fa-cube::before{content:""}.fa-arrow-down-triangle-square::before{content:""}.fa-sort-shapes-down::before{content:""}.fa-bitcoin-sign::before{content:""}.fa-shutters::before{content:""}.fa-shield-dog::before{content:""}.fa-solar-panel::before{content:""}.fa-lock-open::before{content:""}.fa-table-tree::before{content:""}.fa-house-chimney-heart::before{content:""}.fa-tally-3::before{content:""}.fa-elevator::before{content:""}.fa-money-bill-transfer::before{content:""}.fa-money-bill-trend-up::before{content:""}.fa-house-flood-water-circle-arrow-right::before{content:""}.fa-square-poll-horizontal::before{content:""}.fa-poll-h::before{content:""}.fa-circle::before{content:""}.fa-left-to-bracket::before{content:""}.fa-cart-circle-exclamation::before{content:""}.fa-sword::before{content:""}.fa-backward-fast::before{content:""}.fa-fast-backward::before{content:""}.fa-recycle::before{content:""}.fa-user-astronaut::before{content:""}.fa-interrobang::before{content:""}.fa-plane-slash::before{content:""}.fa-circle-dashed::before{content:""}.fa-trademark::before{content:""}.fa-basketball::before{content:""}.fa-basketball-ball::before{content:""}.fa-fork-knife::before{content:""}.fa-utensils-alt::before{content:""}.fa-satellite-dish::before{content:""}.fa-badge-check::before{content:""}.fa-circle-up::before{content:""}.fa-arrow-alt-circle-up::before{content:""}.fa-slider::before{content:""}.fa-mobile-screen-button::before{content:""}.fa-mobile-alt::before{content:""}.fa-clock-one-thirty::before{content:""}.fa-inbox-out::before{content:""}.fa-inbox-arrow-up::before{content:""}.fa-cloud-slash::before{content:""}.fa-volume-high::before{content:""}.fa-volume-up::before{content:""}.fa-users-rays::before{content:""}.fa-wallet::before{content:""}.fa-octagon-check::before{content:""}.fa-flatbread-stuffed::before{content:""}.fa-clipboard-check::before{content:""}.fa-cart-circle-plus::before{content:""}.fa-truck-clock::before{content:""}.fa-shipping-timed::before{content:""}.fa-pool-8-ball::before{content:""}.fa-file-audio::before{content:""}.fa-turn-down-left::before{content:""}.fa-lock-hashtag::before{content:""}.fa-chart-radar::before{content:""}.fa-staff::before{content:""}.fa-burger::before{content:""}.fa-hamburger::before{content:""}.fa-utility-pole::before{content:""}.fa-transporter-6::before{content:""}.fa-arrow-turn-left::before{content:""}.fa-wrench::before{content:""}.fa-bugs::before{content:""}.fa-vector-polygon::before{content:""}.fa-diagram-nested::before{content:""}.fa-rupee-sign::before{content:""}.fa-rupee::before{content:""}.fa-file-image::before{content:""}.fa-circle-question::before{content:""}.fa-question-circle::before{content:""}.fa-tickets-perforated::before{content:""}.fa-image-user::before{content:""}.fa-buoy::before{content:""}.fa-plane-departure::before{content:""}.fa-handshake-slash::before{content:""}.fa-book-bookmark::before{content:""}.fa-border-center-h::before{content:""}.fa-can-food::before{content:""}.fa-typewriter::before{content:""}.fa-arrow-right-from-arc::before{content:""}.fa-circle-k::before{content:""}.fa-face-hand-over-mouth::before{content:""}.fa-popcorn::before{content:""}.fa-house-water::before{content:""}.fa-house-flood::before{content:""}.fa-object-subtract::before{content:""}.fa-code-branch::before{content:""}.fa-warehouse-full::before{content:""}.fa-warehouse-alt::before{content:""}.fa-hat-cowboy::before{content:""}.fa-bridge::before{content:""}.fa-phone-flip::before{content:""}.fa-phone-alt::before{content:""}.fa-arrow-down-from-dotted-line::before{content:""}.fa-file-doc::before{content:""}.fa-square-quarters::before{content:""}.fa-truck-front::before{content:""}.fa-cat::before{content:""}.fa-trash-xmark::before{content:""}.fa-circle-caret-left::before{content:""}.fa-caret-circle-left::before{content:""}.fa-files::before{content:""}.fa-anchor-circle-exclamation::before{content:""}.fa-face-clouds::before{content:""}.fa-user-crown::before{content:""}.fa-basket-shopping-plus::before{content:""}.fa-truck-field::before{content:""}.fa-route::before{content:""}.fa-cart-circle-check::before{content:""}.fa-clipboard-question::before{content:""}.fa-panorama::before{content:""}.fa-comment-medical::before{content:""}.fa-teeth-open::before{content:""}.fa-user-tie-hair-long::before{content:""}.fa-file-circle-minus::before{content:""}.fa-head-side-medical::before{content:""}.fa-arrow-turn-right::before{content:""}.fa-tags::before{content:""}.fa-wine-glass::before{content:""}.fa-forward-fast::before{content:""}.fa-fast-forward::before{content:""}.fa-face-meh-blank::before{content:""}.fa-meh-blank::before{content:""}.fa-user-robot::before{content:""}.fa-square-parking::before{content:""}.fa-parking::before{content:""}.fa-card-diamond::before{content:""}.fa-face-zipper::before{content:""}.fa-face-raised-eyebrow::before{content:""}.fa-house-signal::before{content:""}.fa-square-chevron-up::before{content:""}.fa-chevron-square-up::before{content:""}.fa-bars-progress::before{content:""}.fa-tasks-alt::before{content:""}.fa-faucet-drip::before{content:""}.fa-arrows-to-line::before{content:""}.fa-dolphin::before{content:""}.fa-arrow-up-right::before{content:""}.fa-circle-r::before{content:""}.fa-cart-flatbed::before{content:""}.fa-dolly-flatbed::before{content:""}.fa-ban-smoking::before{content:""}.fa-smoking-ban::before{content:""}.fa-circle-sort-up::before{content:""}.fa-sort-circle-up::before{content:""}.fa-terminal::before{content:""}.fa-mobile-button::before{content:""}.fa-house-medical-flag::before{content:""}.fa-basket-shopping::before{content:""}.fa-shopping-basket::before{content:""}.fa-tape::before{content:""}.fa-chestnut::before{content:""}.fa-bus-simple::before{content:""}.fa-bus-alt::before{content:""}.fa-eye::before{content:""}.fa-face-sad-cry::before{content:""}.fa-sad-cry::before{content:""}.fa-heat::before{content:""}.fa-ticket-airline::before{content:""}.fa-ticket-perforated-plane::before{content:""}.fa-ticket-plane::before{content:""}.fa-boot-heeled::before{content:""}.fa-arrows-minimize::before{content:""}.fa-compress-arrows::before{content:""}.fa-audio-description::before{content:""}.fa-person-military-to-person::before{content:""}.fa-file-shield::before{content:""}.fa-hexagon::before{content:""}.fa-manhole::before{content:""}.fa-user-slash::before{content:""}.fa-pen::before{content:""}.fa-tower-observation::before{content:""}.fa-floppy-disks::before{content:""}.fa-toilet-paper-blank-under::before{content:""}.fa-toilet-paper-reverse-alt::before{content:""}.fa-file-code::before{content:""}.fa-signal::before{content:""}.fa-signal-5::before{content:""}.fa-signal-perfect::before{content:""}.fa-pump::before{content:""}.fa-bus::before{content:""}.fa-heart-circle-xmark::before{content:""}.fa-arrow-up-left-from-circle::before{content:""}.fa-house-chimney::before{content:""}.fa-home-lg::before{content:""}.fa-window-maximize::before{content:""}.fa-dryer::before{content:""}.fa-face-frown::before{content:""}.fa-frown::before{content:""}.fa-chess-bishop-piece::before{content:""}.fa-chess-bishop-alt::before{content:""}.fa-shirt-tank-top::before{content:""}.fa-diploma::before{content:""}.fa-scroll-ribbon::before{content:""}.fa-screencast::before{content:""}.fa-walker::before{content:""}.fa-prescription::before{content:""}.fa-shop::before{content:""}.fa-store-alt::before{content:""}.fa-floppy-disk::before{content:""}.fa-save::before{content:""}.fa-vihara::before{content:""}.fa-face-kiss-closed-eyes::before{content:""}.fa-scale-unbalanced::before{content:""}.fa-balance-scale-left::before{content:""}.fa-file-user::before{content:""}.fa-user-police-tie::before{content:""}.fa-face-tongue-money::before{content:""}.fa-tennis-ball::before{content:""}.fa-square-l::before{content:""}.fa-sort-up::before{content:""}.fa-sort-asc::before{content:""}.fa-calendar-arrow-up::before{content:""}.fa-calendar-upload::before{content:""}.fa-comment-dots::before{content:""}.fa-commenting::before{content:""}.fa-plant-wilt::before{content:""}.fa-scarf::before{content:""}.fa-album-circle-plus::before{content:""}.fa-user-nurse-hair-long::before{content:""}.fa-diamond::before{content:""}.fa-square-left::before{content:""}.fa-arrow-alt-square-left::before{content:""}.fa-face-grin-squint::before{content:""}.fa-grin-squint::before{content:""}.fa-circle-ellipsis-vertical::before{content:""}.fa-hand-holding-dollar::before{content:""}.fa-hand-holding-usd::before{content:""}.fa-grid-dividers::before{content:""}.fa-bacterium::before{content:""}.fa-hand-pointer::before{content:""}.fa-drum-steelpan::before{content:""}.fa-hand-scissors::before{content:""}.fa-hands-praying::before{content:""}.fa-praying-hands::before{content:""}.fa-face-pensive::before{content:""}.fa-user-music::before{content:""}.fa-arrow-rotate-right::before{content:""}.fa-arrow-right-rotate::before{content:""}.fa-arrow-rotate-forward::before{content:""}.fa-redo::before{content:""}.fa-messages-dollar::before{content:""}.fa-comments-alt-dollar::before{content:""}.fa-sensor-on::before{content:""}.fa-balloon::before{content:""}.fa-biohazard::before{content:""}.fa-chess-queen-piece::before{content:""}.fa-chess-queen-alt::before{content:""}.fa-location-crosshairs::before{content:""}.fa-location::before{content:""}.fa-mars-double::before{content:""}.fa-left-from-bracket::before{content:""}.fa-house-person-leave::before{content:""}.fa-house-leave::before{content:""}.fa-house-person-depart::before{content:""}.fa-ruler-triangle::before{content:""}.fa-card-club::before{content:""}.fa-child-dress::before{content:""}.fa-users-between-lines::before{content:""}.fa-lungs-virus::before{content:""}.fa-spinner-third::before{content:""}.fa-face-grin-tears::before{content:""}.fa-grin-tears::before{content:""}.fa-phone::before{content:""}.fa-computer-mouse-scrollwheel::before{content:""}.fa-mouse-alt::before{content:""}.fa-calendar-xmark::before{content:""}.fa-calendar-times::before{content:""}.fa-child-reaching::before{content:""}.fa-table-layout::before{content:""}.fa-narwhal::before{content:""}.fa-ramp-loading::before{content:""}.fa-calendar-circle-plus::before{content:""}.fa-toothbrush::before{content:""}.fa-border-inner::before{content:""}.fa-paw-claws::before{content:""}.fa-kiwi-fruit::before{content:""}.fa-traffic-light-slow::before{content:""}.fa-rectangle-code::before{content:""}.fa-head-side-virus::before{content:""}.fa-keyboard-brightness::before{content:""}.fa-books-medical::before{content:""}.fa-lightbulb-slash::before{content:""}.fa-house-blank::before{content:""}.fa-home-blank::before{content:""}.fa-square-5::before{content:""}.fa-square-heart::before{content:""}.fa-heart-square::before{content:""}.fa-puzzle::before{content:""}.fa-user-gear::before{content:""}.fa-user-cog::before{content:""}.fa-pipe-circle-check::before{content:""}.fa-arrow-up-1-9::before{content:""}.fa-sort-numeric-up::before{content:""}.fa-octagon-exclamation::before{content:""}.fa-dial-low::before{content:""}.fa-door-closed::before{content:""}.fa-laptop-mobile::before{content:""}.fa-phone-laptop::before{content:""}.fa-conveyor-belt-boxes::before{content:""}.fa-conveyor-belt-alt::before{content:""}.fa-shield-virus::before{content:""}.fa-starfighter-twin-ion-engine-advanced::before{content:""}.fa-starfighter-alt-advanced::before{content:""}.fa-dice-six::before{content:""}.fa-starfighter-twin-ion-engine::before{content:""}.fa-starfighter-alt::before{content:""}.fa-rocket-launch::before{content:""}.fa-mosquito-net::before{content:""}.fa-vent-damper::before{content:""}.fa-bridge-water::before{content:""}.fa-ban-bug::before{content:""}.fa-debug::before{content:""}.fa-person-booth::before{content:""}.fa-text-width::before{content:""}.fa-garage-car::before{content:""}.fa-square-kanban::before{content:""}.fa-hat-wizard::before{content:""}.fa-chart-kanban::before{content:""}.fa-pen-fancy::before{content:""}.fa-coffee-pot::before{content:""}.fa-mouse-field::before{content:""}.fa-person-digging::before{content:""}.fa-digging::before{content:""}.fa-shower-down::before{content:""}.fa-shower-alt::before{content:""}.fa-box-circle-check::before{content:""}.fa-brightness::before{content:""}.fa-car-side-bolt::before{content:""}.fa-file-xml::before{content:""}.fa-ornament::before{content:""}.fa-phone-arrow-down-left::before{content:""}.fa-phone-arrow-down::before{content:""}.fa-phone-incoming::before{content:""}.fa-cloud-word::before{content:""}.fa-hand-fingers-crossed::before{content:""}.fa-trash::before{content:""}.fa-gauge-simple::before{content:""}.fa-gauge-simple-med::before{content:""}.fa-tachometer-average::before{content:""}.fa-arrow-down-small-big::before{content:""}.fa-sort-size-down-alt::before{content:""}.fa-book-medical::before{content:""}.fa-face-melting::before{content:""}.fa-poo::before{content:""}.fa-pen-clip-slash::before{content:""}.fa-pen-alt-slash::before{content:""}.fa-quote-right::before{content:""}.fa-quote-right-alt::before{content:""}.fa-scroll-old::before{content:""}.fa-guitars::before{content:""}.fa-phone-xmark::before{content:""}.fa-hose::before{content:""}.fa-clock-six::before{content:""}.fa-shirt::before{content:""}.fa-t-shirt::before{content:""}.fa-tshirt::before{content:""}.fa-billboard::before{content:""}.fa-square-r::before{content:""}.fa-cubes::before{content:""}.fa-envelope-open-dollar::before{content:""}.fa-divide::before{content:""}.fa-sun-cloud::before{content:""}.fa-lamp-floor::before{content:""}.fa-square-7::before{content:""}.fa-tenge-sign::before{content:""}.fa-tenge::before{content:""}.fa-headphones::before{content:""}.fa-hands-holding::before{content:""}.fa-campfire::before{content:""}.fa-circle-ampersand::before{content:""}.fa-snowflakes::before{content:""}.fa-hands-clapping::before{content:""}.fa-republican::before{content:""}.fa-leaf-maple::before{content:""}.fa-arrow-left::before{content:""}.fa-person-circle-xmark::before{content:""}.fa-ruler::before{content:""}.fa-arrow-left-from-bracket::before{content:""}.fa-cup-straw-swoosh::before{content:""}.fa-temperature-sun::before{content:""}.fa-temperature-hot::before{content:""}.fa-align-left::before{content:""}.fa-dice-d6::before{content:""}.fa-restroom::before{content:""}.fa-high-definition::before{content:""}.fa-rectangle-hd::before{content:""}.fa-j::before{content:"J"}.fa-galaxy::before{content:""}.fa-users-viewfinder::before{content:""}.fa-file-video::before{content:""}.fa-cherries::before{content:""}.fa-up-right-from-square::before{content:""}.fa-external-link-alt::before{content:""}.fa-circle-sort::before{content:""}.fa-sort-circle::before{content:""}.fa-table-cells::before{content:""}.fa-th::before{content:""}.fa-bag-shopping-minus::before{content:""}.fa-file-pdf::before{content:""}.fa-siren::before{content:""}.fa-arrow-up-to-dotted-line::before{content:""}.fa-image-landscape::before{content:""}.fa-landscape::before{content:""}.fa-tank-water::before{content:""}.fa-curling-stone::before{content:""}.fa-curling::before{content:""}.fa-gamepad-modern::before{content:""}.fa-gamepad-alt::before{content:""}.fa-messages-question::before{content:""}.fa-book-bible::before{content:""}.fa-bible::before{content:""}.fa-o::before{content:"O"}.fa-suitcase-medical::before{content:""}.fa-medkit::before{content:""}.fa-briefcase-arrow-right::before{content:""}.fa-expand-wide::before{content:""}.fa-clock-eleven-thirty::before{content:""}.fa-rv::before{content:""}.fa-user-secret::before{content:""}.fa-otter::before{content:""}.fa-dreidel::before{content:""}.fa-person-dress::before{content:""}.fa-female::before{content:""}.fa-comment-dollar::before{content:""}.fa-business-time::before{content:""}.fa-briefcase-clock::before{content:""}.fa-flower-tulip::before{content:""}.fa-people-pants-simple::before{content:""}.fa-cloud-drizzle::before{content:""}.fa-table-cells-large::before{content:""}.fa-th-large::before{content:""}.fa-book-tanakh::before{content:""}.fa-tanakh::before{content:""}.fa-solar-system::before{content:""}.fa-seal-question::before{content:""}.fa-phone-volume::before{content:""}.fa-volume-control-phone::before{content:""}.fa-disc-drive::before{content:""}.fa-hat-cowboy-side::before{content:""}.fa-table-rows::before{content:""}.fa-rows::before{content:""}.fa-location-exclamation::before{content:""}.fa-map-marker-exclamation::before{content:""}.fa-face-fearful::before{content:""}.fa-clipboard-user::before{content:""}.fa-bus-school::before{content:""}.fa-film-slash::before{content:""}.fa-square-arrow-down-right::before{content:""}.fa-book-sparkles::before{content:""}.fa-book-spells::before{content:""}.fa-washing-machine::before{content:""}.fa-washer::before{content:""}.fa-child::before{content:""}.fa-lira-sign::before{content:""}.fa-user-visor::before{content:""}.fa-file-plus-minus::before{content:""}.fa-chess-clock-flip::before{content:""}.fa-chess-clock-alt::before{content:""}.fa-satellite::before{content:""}.fa-truck-fire::before{content:""}.fa-plane-lock::before{content:""}.fa-steering-wheel::before{content:""}.fa-tag::before{content:""}.fa-stretcher::before{content:""}.fa-book-section::before{content:""}.fa-book-law::before{content:""}.fa-inboxes::before{content:""}.fa-coffee-bean::before{content:""}.fa-circle-yen::before{content:""}.fa-brackets-curly::before{content:""}.fa-ellipsis-stroke-vertical::before{content:""}.fa-ellipsis-v-alt::before{content:""}.fa-comment::before{content:""}.fa-square-1::before{content:""}.fa-cake-candles::before{content:""}.fa-birthday-cake::before{content:""}.fa-cake::before{content:""}.fa-head-side::before{content:""}.fa-truck-ladder::before{content:""}.fa-envelope::before{content:""}.fa-dolly-empty::before{content:""}.fa-face-tissue::before{content:""}.fa-angles-up::before{content:""}.fa-angle-double-up::before{content:""}.fa-bin-recycle::before{content:""}.fa-paperclip::before{content:""}.fa-chart-line-down::before{content:""}.fa-arrow-right-to-city::before{content:""}.fa-lock-a::before{content:""}.fa-ribbon::before{content:""}.fa-lungs::before{content:""}.fa-person-pinball::before{content:""}.fa-arrow-up-9-1::before{content:""}.fa-sort-numeric-up-alt::before{content:""}.fa-apple-core::before{content:""}.fa-circle-y::before{content:""}.fa-h6::before{content:""}.fa-litecoin-sign::before{content:""}.fa-bottle-baby::before{content:""}.fa-circle-small::before{content:""}.fa-border-none::before{content:""}.fa-arrow-turn-down-left::before{content:""}.fa-circle-wifi-circle-wifi::before{content:""}.fa-circle-wifi-group::before{content:""}.fa-circle-nodes::before{content:""}.fa-parachute-box::before{content:""}.fa-reflect-horizontal::before{content:""}.fa-message-medical::before{content:""}.fa-comment-alt-medical::before{content:""}.fa-rugby-ball::before{content:""}.fa-comment-music::before{content:""}.fa-indent::before{content:""}.fa-tree-deciduous::before{content:""}.fa-tree-alt::before{content:""}.fa-puzzle-piece-simple::before{content:""}.fa-puzzle-piece-alt::before{content:""}.fa-truck-field-un::before{content:""}.fa-nfc-trash::before{content:""}.fa-hourglass::before{content:""}.fa-hourglass-empty::before{content:""}.fa-mountain::before{content:""}.fa-file-xmark::before{content:""}.fa-file-times::before{content:""}.fa-house-heart::before{content:""}.fa-home-heart::before{content:""}.fa-house-chimney-blank::before{content:""}.fa-meter-bolt::before{content:""}.fa-user-doctor::before{content:""}.fa-user-md::before{content:""}.fa-slash-back::before{content:"\\"}.fa-circle-info::before{content:""}.fa-info-circle::before{content:""}.fa-fishing-rod::before{content:""}.fa-hammer-crash::before{content:""}.fa-message-heart::before{content:""}.fa-cloud-meatball::before{content:""}.fa-camera-polaroid::before{content:""}.fa-camera::before{content:""}.fa-camera-alt::before{content:""}.fa-square-virus::before{content:""}.fa-cart-arrow-up::before{content:""}.fa-meteor::before{content:""}.fa-car-on::before{content:""}.fa-sleigh::before{content:""}.fa-arrow-down-1-9::before{content:""}.fa-sort-numeric-asc::before{content:""}.fa-sort-numeric-down::before{content:""}.fa-buoy-mooring::before{content:""}.fa-square-4::before{content:""}.fa-hand-holding-droplet::before{content:""}.fa-hand-holding-water::before{content:""}.fa-file-eps::before{content:""}.fa-tricycle-adult::before{content:""}.fa-waveform::before{content:""}.fa-water::before{content:""}.fa-star-sharp-half-stroke::before{content:""}.fa-star-sharp-half-alt::before{content:""}.fa-nfc-signal::before{content:""}.fa-plane-prop::before{content:""}.fa-calendar-check::before{content:""}.fa-clock-desk::before{content:""}.fa-calendar-clock::before{content:""}.fa-calendar-time::before{content:""}.fa-braille::before{content:""}.fa-prescription-bottle-medical::before{content:""}.fa-prescription-bottle-alt::before{content:""}.fa-plate-utensils::before{content:""}.fa-family-pants::before{content:""}.fa-hose-reel::before{content:""}.fa-house-window::before{content:""}.fa-landmark::before{content:""}.fa-truck::before{content:""}.fa-music-magnifying-glass::before{content:""}.fa-crosshairs::before{content:""}.fa-cloud-rainbow::before{content:""}.fa-person-cane::before{content:""}.fa-alien::before{content:""}.fa-tent::before{content:""}.fa-laptop-binary::before{content:""}.fa-vest-patches::before{content:""}.fa-people-dress-simple::before{content:""}.fa-check-double::before{content:""}.fa-arrow-down-a-z::before{content:""}.fa-sort-alpha-asc::before{content:""}.fa-sort-alpha-down::before{content:""}.fa-bowling-ball-pin::before{content:""}.fa-bell-school-slash::before{content:""}.fa-plus-large::before{content:""}.fa-money-bill-wheat::before{content:""}.fa-camera-viewfinder::before{content:""}.fa-screenshot::before{content:""}.fa-message-music::before{content:""}.fa-comment-alt-music::before{content:""}.fa-car-building::before{content:""}.fa-border-bottom-right::before{content:""}.fa-border-style-alt::before{content:""}.fa-octagon::before{content:""}.fa-comment-arrow-up-right::before{content:""}.fa-octagon-divide::before{content:""}.fa-cookie::before{content:""}.fa-arrow-rotate-left::before{content:""}.fa-arrow-left-rotate::before{content:""}.fa-arrow-rotate-back::before{content:""}.fa-arrow-rotate-backward::before{content:""}.fa-undo::before{content:""}.fa-tv-music::before{content:""}.fa-hard-drive::before{content:""}.fa-hdd::before{content:""}.fa-reel::before{content:""}.fa-face-grin-squint-tears::before{content:""}.fa-grin-squint-tears::before{content:""}.fa-dumbbell::before{content:""}.fa-rectangle-list::before{content:""}.fa-list-alt::before{content:""}.fa-tarp-droplet::before{content:""}.fa-alarm-exclamation::before{content:""}.fa-house-medical-circle-check::before{content:""}.fa-traffic-cone::before{content:""}.fa-grate::before{content:""}.fa-arrow-down-right::before{content:""}.fa-person-skiing-nordic::before{content:""}.fa-skiing-nordic::before{content:""}.fa-calendar-plus::before{content:""}.fa-person-from-portal::before{content:""}.fa-portal-exit::before{content:""}.fa-plane-arrival::before{content:""}.fa-cowbell-circle-plus::before{content:""}.fa-cowbell-more::before{content:""}.fa-circle-left::before{content:""}.fa-arrow-alt-circle-left::before{content:""}.fa-distribute-spacing-vertical::before{content:""}.fa-signal-bars-fair::before{content:""}.fa-signal-alt-2::before{content:""}.fa-sportsball::before{content:""}.fa-game-console-handheld-crank::before{content:""}.fa-train-subway::before{content:""}.fa-subway::before{content:""}.fa-chart-gantt::before{content:""}.fa-face-smile-upside-down::before{content:""}.fa-ball-pile::before{content:""}.fa-badge-dollar::before{content:""}.fa-money-bills-simple::before{content:""}.fa-money-bills-alt::before{content:""}.fa-list-timeline::before{content:""}.fa-indian-rupee-sign::before{content:""}.fa-indian-rupee::before{content:""}.fa-inr::before{content:""}.fa-crop-simple::before{content:""}.fa-crop-alt::before{content:""}.fa-money-bill-1::before{content:""}.fa-money-bill-alt::before{content:""}.fa-left-long::before{content:""}.fa-long-arrow-alt-left::before{content:""}.fa-keyboard-down::before{content:""}.fa-circle-up-right::before{content:""}.fa-cloud-bolt-moon::before{content:""}.fa-thunderstorm-moon::before{content:""}.fa-turn-left-up::before{content:""}.fa-dna::before{content:""}.fa-virus-slash::before{content:""}.fa-bracket-round-right::before{content:"\)"}.fa-circle-sterling::before{content:""}.fa-circle-5::before{content:""}.fa-minus::before{content:""}.fa-subtract::before{content:""}.fa-fire-flame::before{content:""}.fa-flame::before{content:""}.fa-right-to-line::before{content:""}.fa-arrow-alt-to-right::before{content:""}.fa-gif::before{content:""}.fa-chess::before{content:""}.fa-trash-slash::before{content:""}.fa-arrow-left-long::before{content:""}.fa-long-arrow-left::before{content:""}.fa-plug-circle-check::before{content:""}.fa-font-case::before{content:""}.fa-street-view::before{content:""}.fa-arrow-down-left::before{content:""}.fa-franc-sign::before{content:""}.fa-flask-round-poison::before{content:""}.fa-flask-poison::before{content:""}.fa-volume-off::before{content:""}.fa-book-circle-arrow-right::before{content:""}.fa-chart-user::before{content:""}.fa-user-chart::before{content:""}.fa-hands-asl-interpreting::before{content:""}.fa-american-sign-language-interpreting::before{content:""}.fa-asl-interpreting::before{content:""}.fa-hands-american-sign-language-interpreting::before{content:""}.fa-presentation-screen::before{content:""}.fa-presentation::before{content:""}.fa-circle-bolt::before{content:""}.fa-face-smile-halo::before{content:""}.fa-cart-circle-arrow-down::before{content:""}.fa-house-person-return::before{content:""}.fa-house-person-arrive::before{content:""}.fa-house-return::before{content:""}.fa-message-xmark::before{content:""}.fa-comment-alt-times::before{content:""}.fa-message-times::before{content:""}.fa-file-certificate::before{content:""}.fa-file-award::before{content:""}.fa-user-doctor-hair-long::before{content:""}.fa-camera-security::before{content:""}.fa-camera-home::before{content:""}.fa-gear::before{content:""}.fa-cog::before{content:""}.fa-droplet-slash::before{content:""}.fa-tint-slash::before{content:""}.fa-book-heart::before{content:""}.fa-mosque::before{content:""}.fa-duck::before{content:""}.fa-mosquito::before{content:""}.fa-star-of-david::before{content:""}.fa-flag-swallowtail::before{content:""}.fa-flag-alt::before{content:""}.fa-person-military-rifle::before{content:""}.fa-car-garage::before{content:""}.fa-cart-shopping::before{content:""}.fa-shopping-cart::before{content:""}.fa-book-font::before{content:""}.fa-shield-plus::before{content:""}.fa-vials::before{content:""}.fa-eye-dropper-full::before{content:""}.fa-distribute-spacing-horizontal::before{content:""}.fa-tablet-rugged::before{content:""}.fa-temperature-snow::before{content:""}.fa-temperature-frigid::before{content:""}.fa-moped::before{content:""}.fa-face-smile-plus::before{content:""}.fa-smile-plus::before{content:""}.fa-radio-tuner::before{content:""}.fa-radio-alt::before{content:""}.fa-face-swear::before{content:""}.fa-water-arrow-down::before{content:""}.fa-water-lower::before{content:""}.fa-scanner-touchscreen::before{content:""}.fa-circle-7::before{content:""}.fa-plug-circle-plus::before{content:""}.fa-person-ski-jumping::before{content:""}.fa-ski-jump::before{content:""}.fa-place-of-worship::before{content:""}.fa-water-arrow-up::before{content:""}.fa-water-rise::before{content:""}.fa-waveform-lines::before{content:""}.fa-waveform-path::before{content:""}.fa-split::before{content:""}.fa-film-canister::before{content:""}.fa-film-cannister::before{content:""}.fa-folder-xmark::before{content:""}.fa-folder-times::before{content:""}.fa-toilet-paper-blank::before{content:""}.fa-toilet-paper-alt::before{content:""}.fa-tablet-screen::before{content:""}.fa-tablet-android-alt::before{content:""}.fa-hexagon-vertical-nft-slanted::before{content:""}.fa-folder-music::before{content:""}.fa-display-medical::before{content:""}.fa-desktop-medical::before{content:""}.fa-share-all::before{content:""}.fa-peapod::before{content:""}.fa-chess-clock::before{content:""}.fa-axe::before{content:""}.fa-square-d::before{content:""}.fa-grip-vertical::before{content:""}.fa-mobile-signal-out::before{content:""}.fa-arrow-turn-up::before{content:""}.fa-level-up::before{content:""}.fa-u::before{content:"U"}.fa-arrow-up-from-dotted-line::before{content:""}.fa-square-root-variable::before{content:""}.fa-square-root-alt::before{content:""}.fa-light-switch-on::before{content:""}.fa-arrow-down-arrow-up::before{content:""}.fa-sort-alt::before{content:""}.fa-raindrops::before{content:""}.fa-dash::before{content:""}.fa-minus-large::before{content:""}.fa-clock::before{content:""}.fa-clock-four::before{content:""}.fa-input-numeric::before{content:""}.fa-truck-tow::before{content:""}.fa-backward-step::before{content:""}.fa-step-backward::before{content:""}.fa-pallet::before{content:""}.fa-car-bolt::before{content:""}.fa-arrows-maximize::before{content:""}.fa-expand-arrows::before{content:""}.fa-faucet::before{content:""}.fa-cloud-sleet::before{content:""}.fa-lamp-street::before{content:""}.fa-list-radio::before{content:""}.fa-pen-nib-slash::before{content:""}.fa-baseball-bat-ball::before{content:""}.fa-square-up-left::before{content:""}.fa-overline::before{content:""}.fa-s::before{content:"S"}.fa-timeline::before{content:""}.fa-keyboard::before{content:""}.fa-arrows-from-dotted-line::before{content:""}.fa-usb-drive::before{content:""}.fa-ballot::before{content:""}.fa-caret-down::before{content:""}.fa-location-dot-slash::before{content:""}.fa-map-marker-alt-slash::before{content:""}.fa-cards::before{content:""}.fa-house-chimney-medical::before{content:""}.fa-clinic-medical::before{content:""}.fa-boxing-glove::before{content:""}.fa-glove-boxing::before{content:""}.fa-temperature-three-quarters::before{content:""}.fa-temperature-3::before{content:""}.fa-thermometer-3::before{content:""}.fa-thermometer-three-quarters::before{content:""}.fa-bell-school::before{content:""}.fa-mobile-screen::before{content:""}.fa-mobile-android-alt::before{content:""}.fa-plane-up::before{content:""}.fa-folder-heart::before{content:""}.fa-circle-location-arrow::before{content:""}.fa-location-circle::before{content:""}.fa-face-head-bandage::before{content:""}.fa-sushi-roll::before{content:""}.fa-maki-roll::before{content:""}.fa-makizushi::before{content:""}.fa-car-bump::before{content:""}.fa-piggy-bank::before{content:""}.fa-racquet::before{content:""}.fa-car-mirrors::before{content:""}.fa-industry-windows::before{content:""}.fa-industry-alt::before{content:""}.fa-bolt-auto::before{content:""}.fa-battery-half::before{content:""}.fa-battery-3::before{content:""}.fa-flux-capacitor::before{content:""}.fa-mountain-city::before{content:""}.fa-coins::before{content:""}.fa-honey-pot::before{content:""}.fa-olive::before{content:""}.fa-khanda::before{content:""}.fa-filter-list::before{content:""}.fa-outlet::before{content:""}.fa-sliders::before{content:""}.fa-sliders-h::before{content:""}.fa-cauldron::before{content:""}.fa-people::before{content:""}.fa-folder-tree::before{content:""}.fa-network-wired::before{content:""}.fa-croissant::before{content:""}.fa-map-pin::before{content:""}.fa-hamsa::before{content:""}.fa-cent-sign::before{content:""}.fa-swords-laser::before{content:""}.fa-flask::before{content:""}.fa-person-pregnant::before{content:""}.fa-square-u::before{content:""}.fa-wand-sparkles::before{content:""}.fa-router::before{content:""}.fa-ellipsis-vertical::before{content:""}.fa-ellipsis-v::before{content:""}.fa-sword-laser-alt::before{content:""}.fa-ticket::before{content:""}.fa-power-off::before{content:""}.fa-coin::before{content:""}.fa-laptop-slash::before{content:""}.fa-right-long::before{content:""}.fa-long-arrow-alt-right::before{content:""}.fa-circle-b::before{content:""}.fa-person-dress-simple::before{content:""}.fa-pipe-collar::before{content:""}.fa-lights-holiday::before{content:""}.fa-citrus::before{content:""}.fa-flag-usa::before{content:""}.fa-laptop-file::before{content:""}.fa-tty::before{content:""}.fa-teletype::before{content:""}.fa-chart-tree-map::before{content:""}.fa-diagram-next::before{content:""}.fa-person-rifle::before{content:""}.fa-clock-five-thirty::before{content:""}.fa-pipe-valve::before{content:""}.fa-lightbulb-message::before{content:""}.fa-arrow-up-from-arc::before{content:""}.fa-face-spiral-eyes::before{content:""}.fa-compress-wide::before{content:""}.fa-circle-phone-hangup::before{content:""}.fa-phone-circle-down::before{content:""}.fa-gear-complex-code::before{content:""}.fa-house-medical-circle-exclamation::before{content:""}.fa-badminton::before{content:""}.fa-closed-captioning::before{content:""}.fa-person-hiking::before{content:""}.fa-hiking::before{content:""}.fa-right-from-line::before{content:""}.fa-arrow-alt-from-left::before{content:""}.fa-venus-double::before{content:""}.fa-images::before{content:""}.fa-calculator::before{content:""}.fa-shuttlecock::before{content:""}.fa-user-hair::before{content:""}.fa-eye-evil::before{content:""}.fa-people-pulling::before{content:""}.fa-n::before{content:"N"}.fa-swap::before{content:""}.fa-garage::before{content:""}.fa-cable-car::before{content:""}.fa-tram::before{content:""}.fa-shovel-snow::before{content:""}.fa-cloud-rain::before{content:""}.fa-face-lying::before{content:""}.fa-sprinkler::before{content:""}.fa-building-circle-xmark::before{content:""}.fa-person-sledding::before{content:""}.fa-sledding::before{content:""}.fa-game-console-handheld::before{content:""}.fa-ship::before{content:""}.fa-clock-six-thirty::before{content:""}.fa-battery-slash::before{content:""}.fa-tugrik-sign::before{content:""}.fa-arrows-down-to-line::before{content:""}.fa-download::before{content:""}.fa-angles-up-down::before{content:""}.fa-shelves::before{content:""}.fa-inventory::before{content:""}.fa-cloud-snow::before{content:""}.fa-face-grin::before{content:""}.fa-grin::before{content:""}.fa-delete-left::before{content:""}.fa-backspace::before{content:""}.fa-oven::before{content:""}.fa-cloud-binary::before{content:""}.fa-eye-dropper::before{content:""}.fa-eye-dropper-empty::before{content:""}.fa-eyedropper::before{content:""}.fa-comment-captions::before{content:""}.fa-comments-question::before{content:""}.fa-scribble::before{content:""}.fa-rotate-exclamation::before{content:""}.fa-file-circle-check::before{content:""}.fa-glass::before{content:""}.fa-loader::before{content:""}.fa-forward::before{content:""}.fa-user-pilot::before{content:""}.fa-mobile::before{content:""}.fa-mobile-android::before{content:""}.fa-mobile-phone::before{content:""}.fa-code-pull-request-closed::before{content:""}.fa-face-meh::before{content:""}.fa-meh::before{content:""}.fa-align-center::before{content:""}.fa-book-skull::before{content:""}.fa-book-dead::before{content:""}.fa-id-card::before{content:""}.fa-drivers-license::before{content:""}.fa-face-dotted::before{content:""}.fa-face-worried::before{content:""}.fa-outdent::before{content:""}.fa-dedent::before{content:""}.fa-court-sport::before{content:""}.fa-heart-circle-exclamation::before{content:""}.fa-house::before{content:""}.fa-home::before{content:""}.fa-home-alt::before{content:""}.fa-home-lg-alt::before{content:""}.fa-vector-circle::before{content:""}.fa-car-circle-bolt::before{content:""}.fa-calendar-week::before{content:""}.fa-flying-disc::before{content:""}.fa-laptop-medical::before{content:""}.fa-square-down-right::before{content:""}.fa-b::before{content:"B"}.fa-seat-airline::before{content:""}.fa-moon-over-sun::before{content:""}.fa-eclipse-alt::before{content:""}.fa-pipe::before{content:"\|"}.fa-file-medical::before{content:""}.fa-potato::before{content:""}.fa-dice-one::before{content:""}.fa-circle-a::before{content:""}.fa-helmet-battle::before{content:""}.fa-butter::before{content:""}.fa-blanket-fire::before{content:""}.fa-kiwi-bird::before{content:""}.fa-castle::before{content:""}.fa-golf-club::before{content:""}.fa-arrow-right-arrow-left::before{content:""}.fa-exchange::before{content:""}.fa-rotate-right::before{content:""}.fa-redo-alt::before{content:""}.fa-rotate-forward::before{content:""}.fa-utensils::before{content:""}.fa-cutlery::before{content:""}.fa-arrow-up-wide-short::before{content:""}.fa-sort-amount-up::before{content:""}.fa-chart-pie-simple-circle-dollar::before{content:""}.fa-balloons::before{content:""}.fa-mill-sign::before{content:""}.fa-bowl-rice::before{content:""}.fa-timeline-arrow::before{content:""}.fa-skull::before{content:""}.fa-game-board-simple::before{content:""}.fa-game-board-alt::before{content:""}.fa-circle-video::before{content:""}.fa-video-circle::before{content:""}.fa-chart-scatter-bubble::before{content:""}.fa-house-turret::before{content:""}.fa-banana::before{content:""}.fa-hand-holding-skull::before{content:""}.fa-people-dress::before{content:""}.fa-loveseat::before{content:""}.fa-couch-small::before{content:""}.fa-tower-broadcast::before{content:""}.fa-broadcast-tower::before{content:""}.fa-truck-pickup::before{content:""}.fa-block-quote::before{content:""}.fa-up-long::before{content:""}.fa-long-arrow-alt-up::before{content:""}.fa-stop::before{content:""}.fa-code-merge::before{content:""}.fa-money-check-dollar-pen::before{content:""}.fa-money-check-edit-alt::before{content:""}.fa-up-from-line::before{content:""}.fa-arrow-alt-from-bottom::before{content:""}.fa-upload::before{content:""}.fa-hurricane::before{content:""}.fa-grid-round-2-plus::before{content:""}.fa-people-pants::before{content:""}.fa-mound::before{content:""}.fa-windsock::before{content:""}.fa-circle-half::before{content:""}.fa-brake-warning::before{content:""}.fa-toilet-portable::before{content:""}.fa-compact-disc::before{content:""}.fa-file-arrow-down::before{content:""}.fa-file-download::before{content:""}.fa-saxophone-fire::before{content:""}.fa-sax-hot::before{content:""}.fa-camera-web-slash::before{content:""}.fa-webcam-slash::before{content:""}.fa-folder-medical::before{content:""}.fa-folder-gear::before{content:""}.fa-folder-cog::before{content:""}.fa-hand-wave::before{content:""}.fa-arrow-up-arrow-down::before{content:""}.fa-sort-up-down::before{content:""}.fa-caravan::before{content:""}.fa-shield-cat::before{content:""}.fa-message-slash::before{content:""}.fa-comment-alt-slash::before{content:""}.fa-bolt::before{content:""}.fa-zap::before{content:""}.fa-trash-can-check::before{content:""}.fa-glass-water::before{content:""}.fa-oil-well::before{content:""}.fa-table-cells-column-unlock::before{content:""}.fa-person-simple::before{content:""}.fa-arrow-turn-left-up::before{content:""}.fa-vault::before{content:""}.fa-mars::before{content:""}.fa-toilet::before{content:""}.fa-plane-circle-xmark::before{content:""}.fa-yen-sign::before{content:""}.fa-cny::before{content:""}.fa-jpy::before{content:""}.fa-rmb::before{content:""}.fa-yen::before{content:""}.fa-gear-code::before{content:""}.fa-notes::before{content:""}.fa-ruble-sign::before{content:""}.fa-rouble::before{content:""}.fa-rub::before{content:""}.fa-ruble::before{content:""}.fa-trash-undo::before{content:""}.fa-trash-arrow-turn-left::before{content:""}.fa-champagne-glass::before{content:""}.fa-glass-champagne::before{content:""}.fa-objects-align-center-horizontal::before{content:""}.fa-sun::before{content:""}.fa-trash-can-slash::before{content:""}.fa-trash-alt-slash::before{content:""}.fa-screen-users::before{content:""}.fa-users-class::before{content:""}.fa-guitar::before{content:""}.fa-square-arrow-left::before{content:""}.fa-arrow-square-left::before{content:""}.fa-square-8::before{content:""}.fa-face-smile-hearts::before{content:""}.fa-brackets-square::before{content:""}.fa-brackets::before{content:""}.fa-laptop-arrow-down::before{content:""}.fa-hockey-stick-puck::before{content:""}.fa-house-tree::before{content:""}.fa-signal-fair::before{content:""}.fa-signal-2::before{content:""}.fa-face-laugh-wink::before{content:""}.fa-laugh-wink::before{content:""}.fa-circle-dollar::before{content:""}.fa-dollar-circle::before{content:""}.fa-usd-circle::before{content:""}.fa-horse-head::before{content:""}.fa-arrows-repeat::before{content:""}.fa-repeat-alt::before{content:""}.fa-bore-hole::before{content:""}.fa-industry::before{content:""}.fa-image-polaroid::before{content:""}.fa-wave-triangle::before{content:""}.fa-turn-left-down::before{content:""}.fa-person-running-fast::before{content:""}.fa-circle-down::before{content:""}.fa-arrow-alt-circle-down::before{content:""}.fa-grill::before{content:""}.fa-arrows-turn-to-dots::before{content:""}.fa-chart-mixed::before{content:""}.fa-analytics::before{content:""}.fa-florin-sign::before{content:""}.fa-arrow-down-short-wide::before{content:""}.fa-sort-amount-desc::before{content:""}.fa-sort-amount-down-alt::before{content:""}.fa-less-than::before{content:"\<"}.fa-display-code::before{content:""}.fa-desktop-code::before{content:""}.fa-face-drooling::before{content:""}.fa-oil-temperature::before{content:""}.fa-oil-temp::before{content:""}.fa-square-question::before{content:""}.fa-question-square::before{content:""}.fa-air-conditioner::before{content:""}.fa-angle-down::before{content:""}.fa-mountains::before{content:""}.fa-omega::before{content:""}.fa-car-tunnel::before{content:""}.fa-person-dolly-empty::before{content:""}.fa-pan-food::before{content:""}.fa-head-side-cough::before{content:""}.fa-grip-lines::before{content:""}.fa-thumbs-down::before{content:""}.fa-user-lock::before{content:""}.fa-arrow-right-long::before{content:""}.fa-long-arrow-right::before{content:""}.fa-tickets-airline::before{content:""}.fa-tickets-perforated-plane::before{content:""}.fa-tickets-plane::before{content:""}.fa-tent-double-peak::before{content:""}.fa-anchor-circle-xmark::before{content:""}.fa-ellipsis::before{content:""}.fa-ellipsis-h::before{content:""}.fa-nfc-slash::before{content:""}.fa-chess-pawn::before{content:""}.fa-kit-medical::before{content:""}.fa-first-aid::before{content:""}.fa-grid-2-plus::before{content:""}.fa-bells::before{content:""}.fa-person-through-window::before{content:""}.fa-toolbox::before{content:""}.fa-globe-wifi::before{content:""}.fa-envelope-dot::before{content:""}.fa-envelope-badge::before{content:""}.fa-magnifying-glass-waveform::before{content:""}.fa-hands-holding-circle::before{content:""}.fa-bug::before{content:""}.fa-bowl-chopsticks::before{content:""}.fa-credit-card::before{content:""}.fa-credit-card-alt::before{content:""}.fa-circle-s::before{content:""}.fa-box-ballot::before{content:""}.fa-car::before{content:""}.fa-automobile::before{content:""}.fa-hand-holding-hand::before{content:""}.fa-user-tie-hair::before{content:""}.fa-podium-star::before{content:""}.fa-user-hair-mullet::before{content:""}.fa-business-front::before{content:""}.fa-party-back::before{content:""}.fa-trian-balbot::before{content:""}.fa-microphone-stand::before{content:""}.fa-book-open-reader::before{content:""}.fa-book-reader::before{content:""}.fa-family-dress::before{content:""}.fa-circle-x::before{content:""}.fa-cabin::before{content:""}.fa-mountain-sun::before{content:""}.fa-chart-simple-horizontal::before{content:""}.fa-arrows-left-right-to-line::before{content:""}.fa-hand-back-point-left::before{content:""}.fa-message-dots::before{content:""}.fa-comment-alt-dots::before{content:""}.fa-messaging::before{content:""}.fa-file-heart::before{content:""}.fa-beer-mug::before{content:""}.fa-beer-foam::before{content:""}.fa-dice-d20::before{content:""}.fa-drone::before{content:""}.fa-truck-droplet::before{content:""}.fa-file-circle-xmark::before{content:""}.fa-temperature-arrow-up::before{content:""}.fa-temperature-up::before{content:""}.fa-medal::before{content:""}.fa-person-fairy::before{content:""}.fa-bed::before{content:""}.fa-book-copy::before{content:""}.fa-square-h::before{content:""}.fa-h-square::before{content:""}.fa-square-c::before{content:""}.fa-clock-two::before{content:""}.fa-square-ellipsis-vertical::before{content:""}.fa-calendar-users::before{content:""}.fa-podcast::before{content:""}.fa-bee::before{content:""}.fa-temperature-full::before{content:""}.fa-temperature-4::before{content:""}.fa-thermometer-4::before{content:""}.fa-thermometer-full::before{content:""}.fa-bell::before{content:""}.fa-candy-bar::before{content:""}.fa-chocolate-bar::before{content:""}.fa-xmark-large::before{content:""}.fa-pinata::before{content:""}.fa-file-ppt::before{content:""}.fa-arrows-from-line::before{content:""}.fa-superscript::before{content:""}.fa-bowl-spoon::before{content:""}.fa-hexagon-check::before{content:""}.fa-plug-circle-xmark::before{content:""}.fa-star-of-life::before{content:""}.fa-phone-slash::before{content:""}.fa-traffic-light-stop::before{content:""}.fa-paint-roller::before{content:""}.fa-accent-grave::before{content:"\`"}.fa-handshake-angle::before{content:""}.fa-hands-helping::before{content:""}.fa-circle-0::before{content:""}.fa-dial-med-low::before{content:""}.fa-location-dot::before{content:""}.fa-map-marker-alt::before{content:""}.fa-crab::before{content:""}.fa-box-open-full::before{content:""}.fa-box-full::before{content:""}.fa-file::before{content:""}.fa-greater-than::before{content:"\>"}.fa-quotes::before{content:""}.fa-pretzel::before{content:""}.fa-t-rex::before{content:""}.fa-person-swimming::before{content:""}.fa-swimmer::before{content:""}.fa-arrow-down::before{content:""}.fa-user-robot-xmarks::before{content:""}.fa-message-quote::before{content:""}.fa-comment-alt-quote::before{content:""}.fa-candy-corn::before{content:""}.fa-folder-magnifying-glass::before{content:""}.fa-folder-search::before{content:""}.fa-notebook::before{content:""}.fa-circle-wifi::before{content:""}.fa-droplet::before{content:""}.fa-tint::before{content:""}.fa-bullseye-pointer::before{content:""}.fa-eraser::before{content:""}.fa-hexagon-image::before{content:""}.fa-earth-americas::before{content:""}.fa-earth::before{content:""}.fa-earth-america::before{content:""}.fa-globe-americas::before{content:""}.fa-file-svg::before{content:""}.fa-crate-apple::before{content:""}.fa-apple-crate::before{content:""}.fa-person-burst::before{content:""}.fa-game-board::before{content:""}.fa-hat-chef::before{content:""}.fa-hand-back-point-right::before{content:""}.fa-dove::before{content:""}.fa-snowflake-droplets::before{content:""}.fa-battery-empty::before{content:""}.fa-battery-0::before{content:""}.fa-grid-4::before{content:""}.fa-socks::before{content:""}.fa-face-sunglasses::before{content:""}.fa-inbox::before{content:""}.fa-square-0::before{content:""}.fa-section::before{content:""}.fa-square-this-way-up::before{content:""}.fa-box-up::before{content:""}.fa-gauge-high::before{content:""}.fa-tachometer-alt::before{content:""}.fa-tachometer-alt-fast::before{content:""}.fa-square-ampersand::before{content:""}.fa-envelope-open-text::before{content:""}.fa-lamp-desk::before{content:""}.fa-hospital::before{content:""}.fa-hospital-alt::before{content:""}.fa-hospital-wide::before{content:""}.fa-poll-people::before{content:""}.fa-whiskey-glass-ice::before{content:""}.fa-glass-whiskey-rocks::before{content:""}.fa-wine-bottle::before{content:""}.fa-chess-rook::before{content:""}.fa-user-bounty-hunter::before{content:""}.fa-bars-staggered::before{content:""}.fa-reorder::before{content:""}.fa-stream::before{content:""}.fa-diagram-sankey::before{content:""}.fa-cloud-hail-mixed::before{content:""}.fa-circle-up-left::before{content:""}.fa-dharmachakra::before{content:""}.fa-objects-align-left::before{content:""}.fa-oil-can-drip::before{content:""}.fa-face-smiling-hands::before{content:""}.fa-broccoli::before{content:""}.fa-route-interstate::before{content:""}.fa-ear-muffs::before{content:""}.fa-hotdog::before{content:""}.fa-transporter-empty::before{content:""}.fa-person-walking-with-cane::before{content:""}.fa-blind::before{content:""}.fa-angle-90::before{content:""}.fa-rectangle-terminal::before{content:""}.fa-kite::before{content:""}.fa-drum::before{content:""}.fa-scrubber::before{content:""}.fa-ice-cream::before{content:""}.fa-heart-circle-bolt::before{content:""}.fa-fish-bones::before{content:""}.fa-deer-rudolph::before{content:""}.fa-fax::before{content:""}.fa-paragraph::before{content:""}.fa-head-side-heart::before{content:""}.fa-square-e::before{content:""}.fa-meter-fire::before{content:""}.fa-cloud-hail::before{content:""}.fa-check-to-slot::before{content:""}.fa-vote-yea::before{content:""}.fa-money-from-bracket::before{content:""}.fa-star-half::before{content:""}.fa-car-bus::before{content:""}.fa-speaker::before{content:""}.fa-timer::before{content:""}.fa-boxes-stacked::before{content:""}.fa-boxes::before{content:""}.fa-boxes-alt::before{content:""}.fa-landmark-magnifying-glass::before{content:""}.fa-grill-hot::before{content:""}.fa-ballot-check::before{content:""}.fa-link::before{content:""}.fa-chain::before{content:""}.fa-ear-listen::before{content:""}.fa-assistive-listening-systems::before{content:""}.fa-file-minus::before{content:""}.fa-tree-city::before{content:""}.fa-play::before{content:""}.fa-font::before{content:""}.fa-cup-togo::before{content:""}.fa-coffee-togo::before{content:""}.fa-square-down-left::before{content:""}.fa-burger-lettuce::before{content:""}.fa-table-cells-row-lock::before{content:""}.fa-rupiah-sign::before{content:""}.fa-magnifying-glass::before{content:""}.fa-search::before{content:""}.fa-table-tennis-paddle-ball::before{content:""}.fa-ping-pong-paddle-ball::before{content:""}.fa-table-tennis::before{content:""}.fa-person-dots-from-line::before{content:""}.fa-diagnoses::before{content:""}.fa-chevrons-down::before{content:""}.fa-chevron-double-down::before{content:""}.fa-trash-can-arrow-up::before{content:""}.fa-trash-restore-alt::before{content:""}.fa-signal-good::before{content:""}.fa-signal-3::before{content:""}.fa-location-question::before{content:""}.fa-map-marker-question::before{content:""}.fa-floppy-disk-circle-xmark::before{content:""}.fa-floppy-disk-times::before{content:""}.fa-save-circle-xmark::before{content:""}.fa-save-times::before{content:""}.fa-naira-sign::before{content:""}.fa-peach::before{content:""}.fa-taxi-bus::before{content:""}.fa-bracket-curly::before{content:"\{"}.fa-bracket-curly-left::before{content:"\{"}.fa-lobster::before{content:""}.fa-cart-flatbed-empty::before{content:""}.fa-dolly-flatbed-empty::before{content:""}.fa-colon::before{content:"\:"}.fa-cart-arrow-down::before{content:""}.fa-wand::before{content:""}.fa-walkie-talkie::before{content:""}.fa-file-pen::before{content:""}.fa-file-edit::before{content:""}.fa-receipt::before{content:""}.fa-table-picnic::before{content:""}.fa-square-pen::before{content:""}.fa-pen-square::before{content:""}.fa-pencil-square::before{content:""}.fa-circle-microphone-lines::before{content:""}.fa-microphone-circle-alt::before{content:""}.fa-display-slash::before{content:""}.fa-desktop-slash::before{content:""}.fa-suitcase-rolling::before{content:""}.fa-person-circle-exclamation::before{content:""}.fa-transporter-2::before{content:""}.fa-user-hoodie::before{content:""}.fa-hands-holding-diamond::before{content:""}.fa-hand-receiving::before{content:""}.fa-money-bill-simple-wave::before{content:""}.fa-chevron-down::before{content:""}.fa-battery-full::before{content:""}.fa-battery::before{content:""}.fa-battery-5::before{content:""}.fa-bell-plus::before{content:""}.fa-book-arrow-right::before{content:""}.fa-hospitals::before{content:""}.fa-club::before{content:""}.fa-skull-crossbones::before{content:""}.fa-droplet-degree::before{content:""}.fa-dewpoint::before{content:""}.fa-code-compare::before{content:""}.fa-list-ul::before{content:""}.fa-list-dots::before{content:""}.fa-hand-holding-magic::before{content:""}.fa-watermelon-slice::before{content:""}.fa-circle-ellipsis::before{content:""}.fa-school-lock::before{content:""}.fa-tower-cell::before{content:""}.fa-sd-cards::before{content:""}.fa-jug-bottle::before{content:""}.fa-down-long::before{content:""}.fa-long-arrow-alt-down::before{content:""}.fa-envelopes::before{content:""}.fa-phone-office::before{content:""}.fa-ranking-star::before{content:""}.fa-chess-king::before{content:""}.fa-nfc-pen::before{content:""}.fa-person-harassing::before{content:""}.fa-magnifying-glass-play::before{content:""}.fa-hat-winter::before{content:""}.fa-brazilian-real-sign::before{content:""}.fa-landmark-dome::before{content:""}.fa-landmark-alt::before{content:""}.fa-bone-break::before{content:""}.fa-arrow-up::before{content:""}.fa-down-from-dotted-line::before{content:""}.fa-tv::before{content:""}.fa-television::before{content:""}.fa-tv-alt::before{content:""}.fa-border-left::before{content:""}.fa-circle-divide::before{content:""}.fa-shrimp::before{content:""}.fa-list-check::before{content:""}.fa-tasks::before{content:""}.fa-diagram-subtask::before{content:""}.fa-jug-detergent::before{content:""}.fa-circle-user::before{content:""}.fa-user-circle::before{content:""}.fa-square-y::before{content:""}.fa-user-doctor-hair::before{content:""}.fa-planet-ringed::before{content:""}.fa-mushroom::before{content:""}.fa-user-shield::before{content:""}.fa-megaphone::before{content:""}.fa-wreath-laurel::before{content:""}.fa-circle-exclamation-check::before{content:""}.fa-wind::before{content:""}.fa-box-dollar::before{content:""}.fa-box-usd::before{content:""}.fa-car-burst::before{content:""}.fa-car-crash::before{content:""}.fa-y::before{content:"Y"}.fa-user-headset::before{content:""}.fa-arrows-retweet::before{content:""}.fa-retweet-alt::before{content:""}.fa-person-snowboarding::before{content:""}.fa-snowboarding::before{content:""}.fa-square-chevron-right::before{content:""}.fa-chevron-square-right::before{content:""}.fa-lacrosse-stick-ball::before{content:""}.fa-truck-fast::before{content:""}.fa-shipping-fast::before{content:""}.fa-user-magnifying-glass::before{content:""}.fa-star-sharp::before{content:""}.fa-comment-heart::before{content:""}.fa-circle-1::before{content:""}.fa-circle-star::before{content:""}.fa-star-circle::before{content:""}.fa-fish::before{content:""}.fa-cloud-fog::before{content:""}.fa-fog::before{content:""}.fa-waffle::before{content:""}.fa-music-note::before{content:""}.fa-music-alt::before{content:""}.fa-hexagon-exclamation::before{content:""}.fa-cart-shopping-fast::before{content:""}.fa-object-union::before{content:""}.fa-user-graduate::before{content:""}.fa-starfighter::before{content:""}.fa-circle-half-stroke::before{content:""}.fa-adjust::before{content:""}.fa-arrow-right-long-to-line::before{content:""}.fa-square-arrow-down::before{content:""}.fa-arrow-square-down::before{content:""}.fa-diamond-half-stroke::before{content:""}.fa-clapperboard::before{content:""}.fa-square-chevron-left::before{content:""}.fa-chevron-square-left::before{content:""}.fa-phone-intercom::before{content:""}.fa-link-horizontal::before{content:""}.fa-chain-horizontal::before{content:""}.fa-mango::before{content:""}.fa-music-note-slash::before{content:""}.fa-music-alt-slash::before{content:""}.fa-circle-radiation::before{content:""}.fa-radiation-alt::before{content:""}.fa-face-tongue-sweat::before{content:""}.fa-globe-stand::before{content:""}.fa-baseball::before{content:""}.fa-baseball-ball::before{content:""}.fa-circle-p::before{content:""}.fa-award-simple::before{content:""}.fa-jet-fighter-up::before{content:""}.fa-diagram-project::before{content:""}.fa-project-diagram::before{content:""}.fa-pedestal::before{content:""}.fa-chart-pyramid::before{content:""}.fa-sidebar::before{content:""}.fa-snowman-head::before{content:""}.fa-frosty-head::before{content:""}.fa-copy::before{content:""}.fa-burger-glass::before{content:""}.fa-volume-xmark::before{content:""}.fa-volume-mute::before{content:""}.fa-volume-times::before{content:""}.fa-hand-sparkles::before{content:""}.fa-bars-filter::before{content:""}.fa-paintbrush-pencil::before{content:""}.fa-party-bell::before{content:""}.fa-user-vneck-hair::before{content:""}.fa-jack-o-lantern::before{content:""}.fa-grip::before{content:""}.fa-grip-horizontal::before{content:""}.fa-share-from-square::before{content:""}.fa-share-square::before{content:""}.fa-keynote::before{content:""}.fa-child-combatant::before{content:""}.fa-child-rifle::before{content:""}.fa-gun::before{content:""}.fa-square-phone::before{content:""}.fa-phone-square::before{content:""}.fa-hat-beach::before{content:""}.fa-plus::before{content:"\+"}.fa-add::before{content:"\+"}.fa-expand::before{content:""}.fa-computer::before{content:""}.fa-fort::before{content:""}.fa-cloud-check::before{content:""}.fa-xmark::before{content:""}.fa-close::before{content:""}.fa-multiply::before{content:""}.fa-remove::before{content:""}.fa-times::before{content:""}.fa-face-smirking::before{content:""}.fa-arrows-up-down-left-right::before{content:""}.fa-arrows::before{content:""}.fa-chalkboard-user::before{content:""}.fa-chalkboard-teacher::before{content:""}.fa-rhombus::before{content:""}.fa-claw-marks::before{content:""}.fa-peso-sign::before{content:""}.fa-face-smile-tongue::before{content:""}.fa-cart-circle-xmark::before{content:""}.fa-building-shield::before{content:""}.fa-circle-phone-flip::before{content:""}.fa-phone-circle-alt::before{content:""}.fa-baby::before{content:""}.fa-users-line::before{content:""}.fa-quote-left::before{content:""}.fa-quote-left-alt::before{content:""}.fa-tractor::before{content:""}.fa-down-from-bracket::before{content:""}.fa-key-skeleton::before{content:""}.fa-trash-arrow-up::before{content:""}.fa-trash-restore::before{content:""}.fa-arrow-down-up-lock::before{content:""}.fa-arrow-down-to-bracket::before{content:""}.fa-lines-leaning::before{content:""}.fa-square-q::before{content:""}.fa-ruler-combined::before{content:""}.fa-symbols::before{content:""}.fa-icons-alt::before{content:""}.fa-copyright::before{content:""}.fa-flask-gear::before{content:""}.fa-highlighter-line::before{content:""}.fa-bracket-square::before{content:"\["}.fa-bracket::before{content:"\["}.fa-bracket-left::before{content:"\["}.fa-island-tropical::before{content:""}.fa-island-tree-palm::before{content:""}.fa-arrow-right-from-line::before{content:""}.fa-arrow-from-left::before{content:""}.fa-h2::before{content:""}.fa-equals::before{content:"\="}.fa-cake-slice::before{content:""}.fa-shortcake::before{content:""}.fa-building-magnifying-glass::before{content:""}.fa-peanut::before{content:""}.fa-wrench-simple::before{content:""}.fa-blender::before{content:""}.fa-teeth::before{content:""}.fa-tally-2::before{content:""}.fa-shekel-sign::before{content:""}.fa-ils::before{content:""}.fa-shekel::before{content:""}.fa-sheqel::before{content:""}.fa-sheqel-sign::before{content:""}.fa-cars::before{content:""}.fa-axe-battle::before{content:""}.fa-user-hair-long::before{content:""}.fa-map::before{content:""}.fa-arrow-left-from-arc::before{content:""}.fa-file-circle-info::before{content:""}.fa-face-disappointed::before{content:""}.fa-lasso-sparkles::before{content:""}.fa-clock-eleven::before{content:""}.fa-rocket::before{content:""}.fa-siren-on::before{content:""}.fa-clock-ten::before{content:""}.fa-candle-holder::before{content:""}.fa-video-arrow-down-left::before{content:""}.fa-photo-film::before{content:""}.fa-photo-video::before{content:""}.fa-floppy-disk-circle-arrow-right::before{content:""}.fa-save-circle-arrow-right::before{content:""}.fa-folder-minus::before{content:""}.fa-planet-moon::before{content:""}.fa-face-eyes-xmarks::before{content:""}.fa-chart-scatter::before{content:""}.fa-circle-gf::before{content:""}.fa-display-arrow-down::before{content:""}.fa-store::before{content:""}.fa-arrow-trend-up::before{content:""}.fa-plug-circle-minus::before{content:""}.fa-olive-branch::before{content:""}.fa-angle::before{content:""}.fa-vacuum-robot::before{content:""}.fa-sign-hanging::before{content:""}.fa-sign::before{content:""}.fa-square-divide::before{content:""}.fa-folder-check::before{content:""}.fa-signal-stream-slash::before{content:""}.fa-bezier-curve::before{content:""}.fa-eye-dropper-half::before{content:""}.fa-store-lock::before{content:""}.fa-bell-slash::before{content:""}.fa-cloud-bolt-sun::before{content:""}.fa-thunderstorm-sun::before{content:""}.fa-camera-slash::before{content:""}.fa-comment-quote::before{content:""}.fa-tablet::before{content:""}.fa-tablet-android::before{content:""}.fa-school-flag::before{content:""}.fa-message-code::before{content:""}.fa-glass-half::before{content:""}.fa-glass-half-empty::before{content:""}.fa-glass-half-full::before{content:""}.fa-fill::before{content:""}.fa-message-minus::before{content:""}.fa-comment-alt-minus::before{content:""}.fa-angle-up::before{content:""}.fa-dinosaur::before{content:""}.fa-drumstick-bite::before{content:""}.fa-link-horizontal-slash::before{content:""}.fa-chain-horizontal-slash::before{content:""}.fa-holly-berry::before{content:""}.fa-nose::before{content:""}.fa-arrow-left-to-arc::before{content:""}.fa-chevron-left::before{content:""}.fa-bacteria::before{content:""}.fa-clouds::before{content:""}.fa-money-bill-simple::before{content:""}.fa-hand-lizard::before{content:""}.fa-table-pivot::before{content:""}.fa-filter-slash::before{content:""}.fa-trash-can-undo::before{content:""}.fa-trash-can-arrow-turn-left::before{content:""}.fa-trash-undo-alt::before{content:""}.fa-notdef::before{content:""}.fa-disease::before{content:""}.fa-person-to-door::before{content:""}.fa-turntable::before{content:""}.fa-briefcase-medical::before{content:""}.fa-genderless::before{content:""}.fa-chevron-right::before{content:""}.fa-signal-weak::before{content:""}.fa-signal-1::before{content:""}.fa-clock-five::before{content:""}.fa-retweet::before{content:""}.fa-car-rear::before{content:""}.fa-car-alt::before{content:""}.fa-pump-soap::before{content:""}.fa-computer-classic::before{content:""}.fa-frame::before{content:""}.fa-video-slash::before{content:""}.fa-battery-quarter::before{content:""}.fa-battery-2::before{content:""}.fa-ellipsis-stroke::before{content:""}.fa-ellipsis-h-alt::before{content:""}.fa-radio::before{content:""}.fa-baby-carriage::before{content:""}.fa-carriage-baby::before{content:""}.fa-face-expressionless::before{content:""}.fa-down-to-dotted-line::before{content:""}.fa-cloud-music::before{content:""}.fa-traffic-light::before{content:""}.fa-cloud-minus::before{content:""}.fa-thermometer::before{content:""}.fa-shield-minus::before{content:""}.fa-vr-cardboard::before{content:""}.fa-car-tilt::before{content:""}.fa-gauge-circle-minus::before{content:""}.fa-brightness-low::before{content:""}.fa-hand-middle-finger::before{content:""}.fa-percent::before{content:"\%"}.fa-percentage::before{content:"\%"}.fa-truck-moving::before{content:""}.fa-glass-water-droplet::before{content:""}.fa-conveyor-belt::before{content:""}.fa-location-check::before{content:""}.fa-map-marker-check::before{content:""}.fa-coin-vertical::before{content:""}.fa-display::before{content:""}.fa-person-sign::before{content:""}.fa-face-smile::before{content:""}.fa-smile::before{content:""}.fa-phone-hangup::before{content:""}.fa-signature-slash::before{content:""}.fa-thumbtack::before{content:""}.fa-thumb-tack::before{content:""}.fa-wheat-slash::before{content:""}.fa-trophy::before{content:""}.fa-clouds-sun::before{content:""}.fa-person-praying::before{content:""}.fa-pray::before{content:""}.fa-hammer::before{content:""}.fa-face-vomit::before{content:""}.fa-speakers::before{content:""}.fa-tty-answer::before{content:""}.fa-teletype-answer::before{content:""}.fa-mug-tea-saucer::before{content:""}.fa-diagram-lean-canvas::before{content:""}.fa-alt::before{content:""}.fa-dial::before{content:""}.fa-dial-med-high::before{content:""}.fa-hand-peace::before{content:""}.fa-circle-trash::before{content:""}.fa-trash-circle::before{content:""}.fa-rotate::before{content:""}.fa-sync-alt::before{content:""}.fa-circle-quarters::before{content:""}.fa-spinner::before{content:""}.fa-tower-control::before{content:""}.fa-arrow-up-triangle-square::before{content:""}.fa-sort-shapes-up::before{content:""}.fa-whale::before{content:""}.fa-robot::before{content:""}.fa-peace::before{content:""}.fa-party-horn::before{content:""}.fa-gears::before{content:""}.fa-cogs::before{content:""}.fa-sun-bright::before{content:""}.fa-sun-alt::before{content:""}.fa-warehouse::before{content:""}.fa-conveyor-belt-arm::before{content:""}.fa-lock-keyhole-open::before{content:""}.fa-lock-open-alt::before{content:""}.fa-square-fragile::before{content:""}.fa-box-fragile::before{content:""}.fa-square-wine-glass-crack::before{content:""}.fa-arrow-up-right-dots::before{content:""}.fa-square-n::before{content:""}.fa-splotch::before{content:""}.fa-face-grin-hearts::before{content:""}.fa-grin-hearts::before{content:""}.fa-meter::before{content:""}.fa-mandolin::before{content:""}.fa-dice-four::before{content:""}.fa-sim-card::before{content:""}.fa-transgender::before{content:""}.fa-transgender-alt::before{content:""}.fa-mercury::before{content:""}.fa-up-from-bracket::before{content:""}.fa-knife-kitchen::before{content:""}.fa-border-right::before{content:""}.fa-arrow-turn-down::before{content:""}.fa-level-down::before{content:""}.fa-spade::before{content:""}.fa-card-spade::before{content:""}.fa-line-columns::before{content:""}.fa-ant::before{content:""}.fa-arrow-right-to-line::before{content:""}.fa-arrow-to-right::before{content:""}.fa-person-falling-burst::before{content:""}.fa-flag-pennant::before{content:""}.fa-pennant::before{content:""}.fa-conveyor-belt-empty::before{content:""}.fa-user-group-simple::before{content:""}.fa-award::before{content:""}.fa-ticket-simple::before{content:""}.fa-ticket-alt::before{content:""}.fa-building::before{content:""}.fa-angles-left::before{content:""}.fa-angle-double-left::before{content:""}.fa-camcorder::before{content:""}.fa-video-handheld::before{content:""}.fa-pancakes::before{content:""}.fa-album-circle-user::before{content:""}.fa-subtitles-slash::before{content:""}.fa-qrcode::before{content:""}.fa-dice-d10::before{content:""}.fa-fireplace::before{content:""}.fa-browser::before{content:""}.fa-pen-paintbrush::before{content:""}.fa-pencil-paintbrush::before{content:""}.fa-fish-cooked::before{content:""}.fa-chair-office::before{content:""}.fa-magnifying-glass-music::before{content:""}.fa-nesting-dolls::before{content:""}.fa-clock-rotate-left::before{content:""}.fa-history::before{content:""}.fa-trumpet::before{content:""}.fa-face-grin-beam-sweat::before{content:""}.fa-grin-beam-sweat::before{content:""}.fa-fire-smoke::before{content:""}.fa-phone-missed::before{content:""}.fa-file-export::before{content:""}.fa-arrow-right-from-file::before{content:""}.fa-shield::before{content:""}.fa-shield-blank::before{content:""}.fa-arrow-up-short-wide::before{content:""}.fa-sort-amount-up-alt::before{content:""}.fa-arrows-repeat-1::before{content:""}.fa-repeat-1-alt::before{content:""}.fa-gun-slash::before{content:""}.fa-avocado::before{content:""}.fa-binary::before{content:""}.fa-glasses-round::before{content:""}.fa-glasses-alt::before{content:""}.fa-phone-plus::before{content:""}.fa-ditto::before{content:"\""}.fa-person-seat::before{content:""}.fa-house-medical::before{content:""}.fa-golf-ball-tee::before{content:""}.fa-golf-ball::before{content:""}.fa-circle-chevron-left::before{content:""}.fa-chevron-circle-left::before{content:""}.fa-house-chimney-window::before{content:""}.fa-scythe::before{content:""}.fa-pen-nib::before{content:""}.fa-ban-parking::before{content:""}.fa-parking-circle-slash::before{content:""}.fa-tent-arrow-turn-left::before{content:""}.fa-face-diagonal-mouth::before{content:""}.fa-diagram-cells::before{content:""}.fa-cricket-bat-ball::before{content:""}.fa-cricket::before{content:""}.fa-tents::before{content:""}.fa-wand-magic::before{content:""}.fa-magic::before{content:""}.fa-dog::before{content:""}.fa-pen-line::before{content:""}.fa-atom-simple::before{content:""}.fa-atom-alt::before{content:""}.fa-ampersand::before{content:"\&"}.fa-carrot::before{content:""}.fa-arrow-up-from-line::before{content:""}.fa-arrow-from-bottom::before{content:""}.fa-moon::before{content:""}.fa-pen-slash::before{content:""}.fa-wine-glass-empty::before{content:""}.fa-wine-glass-alt::before{content:""}.fa-square-star::before{content:""}.fa-cheese::before{content:""}.fa-send-backward::before{content:""}.fa-yin-yang::before{content:""}.fa-music::before{content:""}.fa-compass-slash::before{content:""}.fa-clock-one::before{content:""}.fa-file-music::before{content:""}.fa-code-commit::before{content:""}.fa-temperature-low::before{content:""}.fa-person-biking::before{content:""}.fa-biking::before{content:""}.fa-display-chart-up-circle-currency::before{content:""}.fa-skeleton::before{content:""}.fa-circle-g::before{content:""}.fa-circle-arrow-up-left::before{content:""}.fa-coin-blank::before{content:""}.fa-broom::before{content:""}.fa-vacuum::before{content:""}.fa-shield-heart::before{content:""}.fa-card-heart::before{content:""}.fa-lightbulb-cfl-on::before{content:""}.fa-melon::before{content:""}.fa-gopuram::before{content:""}.fa-earth-oceania::before{content:""}.fa-globe-oceania::before{content:""}.fa-container-storage::before{content:""}.fa-face-pouting::before{content:""}.fa-square-xmark::before{content:""}.fa-times-square::before{content:""}.fa-xmark-square::before{content:""}.fa-face-explode::before{content:""}.fa-exploding-head::before{content:""}.fa-hashtag::before{content:"\#"}.fa-up-right-and-down-left-from-center::before{content:""}.fa-expand-alt::before{content:""}.fa-oil-can::before{content:""}.fa-t::before{content:"T"}.fa-transformer-bolt::before{content:""}.fa-hippo::before{content:""}.fa-chart-column::before{content:""}.fa-cassette-vhs::before{content:""}.fa-vhs::before{content:""}.fa-infinity::before{content:""}.fa-vial-circle-check::before{content:""}.fa-chimney::before{content:""}.fa-object-intersect::before{content:""}.fa-person-arrow-down-to-line::before{content:""}.fa-voicemail::before{content:""}.fa-block-brick::before{content:""}.fa-wall-brick::before{content:""}.fa-fan::before{content:""}.fa-bags-shopping::before{content:""}.fa-paragraph-left::before{content:""}.fa-paragraph-rtl::before{content:""}.fa-person-walking-luggage::before{content:""}.fa-caravan-simple::before{content:""}.fa-caravan-alt::before{content:""}.fa-turtle::before{content:""}.fa-pencil-mechanical::before{content:""}.fa-up-down::before{content:""}.fa-arrows-alt-v::before{content:""}.fa-cloud-moon-rain::before{content:""}.fa-booth-curtain::before{content:""}.fa-calendar::before{content:""}.fa-box-heart::before{content:""}.fa-trailer::before{content:""}.fa-user-doctor-message::before{content:""}.fa-user-md-chat::before{content:""}.fa-bahai::before{content:""}.fa-haykal::before{content:""}.fa-lighthouse::before{content:""}.fa-amp-guitar::before{content:""}.fa-sd-card::before{content:""}.fa-volume-slash::before{content:""}.fa-border-bottom::before{content:""}.fa-wifi-weak::before{content:""}.fa-wifi-1::before{content:""}.fa-dragon::before{content:""}.fa-shoe-prints::before{content:""}.fa-circle-plus::before{content:""}.fa-plus-circle::before{content:""}.fa-face-grin-tongue-wink::before{content:""}.fa-grin-tongue-wink::before{content:""}.fa-hand-holding::before{content:""}.fa-plug-circle-exclamation::before{content:""}.fa-link-slash::before{content:""}.fa-chain-broken::before{content:""}.fa-chain-slash::before{content:""}.fa-unlink::before{content:""}.fa-clone::before{content:""}.fa-person-walking-arrow-loop-left::before{content:""}.fa-arrow-up-z-a::before{content:""}.fa-sort-alpha-up-alt::before{content:""}.fa-fire-flame-curved::before{content:""}.fa-fire-alt::before{content:""}.fa-tornado::before{content:""}.fa-file-circle-plus::before{content:""}.fa-delete-right::before{content:""}.fa-book-quran::before{content:""}.fa-quran::before{content:""}.fa-circle-quarter::before{content:""}.fa-anchor::before{content:""}.fa-border-all::before{content:""}.fa-function::before{content:""}.fa-face-angry::before{content:""}.fa-angry::before{content:""}.fa-people-simple::before{content:""}.fa-cookie-bite::before{content:""}.fa-arrow-trend-down::before{content:""}.fa-rss::before{content:""}.fa-feed::before{content:""}.fa-face-monocle::before{content:""}.fa-draw-polygon::before{content:""}.fa-scale-balanced::before{content:""}.fa-balance-scale::before{content:""}.fa-calendar-lines::before{content:""}.fa-calendar-note::before{content:""}.fa-arrow-down-big-small::before{content:""}.fa-sort-size-down::before{content:""}.fa-gauge-simple-high::before{content:""}.fa-tachometer::before{content:""}.fa-tachometer-fast::before{content:""}.fa-do-not-enter::before{content:""}.fa-shower::before{content:""}.fa-dice-d8::before{content:""}.fa-desktop::before{content:""}.fa-desktop-alt::before{content:""}.fa-m::before{content:"M"}.fa-spinner-scale::before{content:""}.fa-grip-dots-vertical::before{content:""}.fa-face-viewfinder::before{content:""}.fa-soft-serve::before{content:""}.fa-creemee::before{content:""}.fa-h5::before{content:""}.fa-hand-back-point-down::before{content:""}.fa-table-list::before{content:""}.fa-th-list::before{content:""}.fa-basket-shopping-minus::before{content:""}.fa-comment-sms::before{content:""}.fa-sms::before{content:""}.fa-rectangle::before{content:""}.fa-rectangle-landscape::before{content:""}.fa-clipboard-list-check::before{content:""}.fa-turkey::before{content:""}.fa-book::before{content:""}.fa-user-plus::before{content:""}.fa-ice-skate::before{content:""}.fa-check::before{content:""}.fa-battery-three-quarters::before{content:""}.fa-battery-4::before{content:""}.fa-tomato::before{content:""}.fa-sword-laser::before{content:""}.fa-house-circle-check::before{content:""}.fa-buildings::before{content:""}.fa-angle-left::before{content:""}.fa-cart-flatbed-boxes::before{content:""}.fa-dolly-flatbed-alt::before{content:""}.fa-diagram-successor::before{content:""}.fa-truck-arrow-right::before{content:""}.fa-square-w::before{content:""}.fa-arrows-split-up-and-left::before{content:""}.fa-lamp::before{content:""}.fa-airplay::before{content:""}.fa-hand-fist::before{content:""}.fa-fist-raised::before{content:""}.fa-shield-quartered::before{content:""}.fa-slash-forward::before{content:"\/"}.fa-location-pen::before{content:""}.fa-map-marker-edit::before{content:""}.fa-cloud-moon::before{content:""}.fa-pot-food::before{content:""}.fa-briefcase::before{content:""}.fa-person-falling::before{content:""}.fa-image-portrait::before{content:""}.fa-portrait::before{content:""}.fa-user-tag::before{content:""}.fa-rug::before{content:""}.fa-print-slash::before{content:""}.fa-earth-europe::before{content:""}.fa-globe-europe::before{content:""}.fa-cart-flatbed-suitcase::before{content:""}.fa-luggage-cart::before{content:""}.fa-hand-back-point-ribbon::before{content:""}.fa-rectangle-xmark::before{content:""}.fa-rectangle-times::before{content:""}.fa-times-rectangle::before{content:""}.fa-window-close::before{content:""}.fa-tire-rugged::before{content:""}.fa-lightbulb-dollar::before{content:""}.fa-cowbell::before{content:""}.fa-baht-sign::before{content:""}.fa-corner::before{content:""}.fa-chevrons-right::before{content:""}.fa-chevron-double-right::before{content:""}.fa-book-open::before{content:""}.fa-book-journal-whills::before{content:""}.fa-journal-whills::before{content:""}.fa-inhaler::before{content:""}.fa-handcuffs::before{content:""}.fa-snake::before{content:""}.fa-triangle-exclamation::before{content:""}.fa-exclamation-triangle::before{content:""}.fa-warning::before{content:""}.fa-note-medical::before{content:""}.fa-database::before{content:""}.fa-down-left::before{content:""}.fa-share::before{content:""}.fa-mail-forward::before{content:""}.fa-face-thinking::before{content:""}.fa-turn-down-right::before{content:""}.fa-bottle-droplet::before{content:""}.fa-mask-face::before{content:""}.fa-hill-rockslide::before{content:""}.fa-scanner-keyboard::before{content:""}.fa-circle-o::before{content:""}.fa-grid-horizontal::before{content:""}.fa-message-dollar::before{content:""}.fa-comment-alt-dollar::before{content:""}.fa-right-left::before{content:""}.fa-exchange-alt::before{content:""}.fa-columns-3::before{content:""}.fa-paper-plane::before{content:""}.fa-road-circle-exclamation::before{content:""}.fa-dungeon::before{content:""}.fa-hand-holding-box::before{content:""}.fa-input-text::before{content:""}.fa-window-flip::before{content:""}.fa-window-alt::before{content:""}.fa-align-right::before{content:""}.fa-scanner-gun::before{content:""}.fa-scanner::before{content:""}.fa-tire::before{content:""}.fa-engine::before{content:""}.fa-money-bill-1-wave::before{content:""}.fa-money-bill-wave-alt::before{content:""}.fa-life-ring::before{content:""}.fa-hands::before{content:""}.fa-sign-language::before{content:""}.fa-signing::before{content:""}.fa-circle-caret-right::before{content:""}.fa-caret-circle-right::before{content:""}.fa-turn-left::before{content:""}.fa-wheat::before{content:""}.fa-file-spreadsheet::before{content:""}.fa-audio-description-slash::before{content:""}.fa-bell-ring::before{content:""}.fa-calendar-day::before{content:""}.fa-water-ladder::before{content:""}.fa-ladder-water::before{content:""}.fa-swimming-pool::before{content:""}.fa-arrows-up-down::before{content:""}.fa-arrows-v::before{content:""}.fa-chess-pawn-piece::before{content:""}.fa-chess-pawn-alt::before{content:""}.fa-face-grimace::before{content:""}.fa-grimace::before{content:""}.fa-wheelchair-move::before{content:""}.fa-wheelchair-alt::before{content:""}.fa-turn-down::before{content:""}.fa-level-down-alt::before{content:""}.fa-square-s::before{content:""}.fa-rectangle-barcode::before{content:""}.fa-barcode-alt::before{content:""}.fa-person-walking-arrow-right::before{content:""}.fa-square-envelope::before{content:""}.fa-envelope-square::before{content:""}.fa-dice::before{content:""}.fa-unicorn::before{content:""}.fa-bowling-ball::before{content:""}.fa-pompebled::before{content:""}.fa-brain::before{content:""}.fa-watch-smart::before{content:""}.fa-book-user::before{content:""}.fa-sensor-cloud::before{content:""}.fa-sensor-smoke::before{content:""}.fa-clapperboard-play::before{content:""}.fa-bandage::before{content:""}.fa-band-aid::before{content:""}.fa-calendar-minus::before{content:""}.fa-circle-xmark::before{content:""}.fa-times-circle::before{content:""}.fa-xmark-circle::before{content:""}.fa-circle-4::before{content:""}.fa-gifts::before{content:""}.fa-album-collection::before{content:""}.fa-hotel::before{content:""}.fa-earth-asia::before{content:""}.fa-globe-asia::before{content:""}.fa-id-card-clip::before{content:""}.fa-id-card-alt::before{content:""}.fa-magnifying-glass-plus::before{content:""}.fa-search-plus::before{content:""}.fa-thumbs-up::before{content:""}.fa-cloud-showers::before{content:""}.fa-user-clock::before{content:""}.fa-onion::before{content:""}.fa-clock-twelve-thirty::before{content:""}.fa-arrow-down-to-dotted-line::before{content:""}.fa-hand-dots::before{content:""}.fa-allergies::before{content:""}.fa-file-invoice::before{content:""}.fa-window-minimize::before{content:""}.fa-rectangle-wide::before{content:""}.fa-comment-arrow-up::before{content:""}.fa-garlic::before{content:""}.fa-mug-saucer::before{content:""}.fa-coffee::before{content:""}.fa-brush::before{content:""}.fa-tree-decorated::before{content:""}.fa-mask::before{content:""}.fa-calendar-heart::before{content:""}.fa-magnifying-glass-minus::before{content:""}.fa-search-minus::before{content:""}.fa-flower::before{content:""}.fa-arrow-down-from-arc::before{content:""}.fa-right-left-large::before{content:""}.fa-ruler-vertical::before{content:""}.fa-circles-overlap::before{content:""}.fa-user-large::before{content:""}.fa-user-alt::before{content:""}.fa-starship-freighter::before{content:""}.fa-train-tram::before{content:""}.fa-bridge-suspension::before{content:""}.fa-trash-check::before{content:""}.fa-user-nurse::before{content:""}.fa-boombox::before{content:""}.fa-syringe::before{content:""}.fa-cloud-sun::before{content:""}.fa-shield-exclamation::before{content:""}.fa-stopwatch-20::before{content:""}.fa-square-full::before{content:""}.fa-grip-dots::before{content:""}.fa-comment-exclamation::before{content:""}.fa-pen-swirl::before{content:""}.fa-falafel::before{content:""}.fa-circle-2::before{content:""}.fa-magnet::before{content:""}.fa-jar::before{content:""}.fa-gramophone::before{content:""}.fa-dice-d12::before{content:""}.fa-note-sticky::before{content:""}.fa-sticky-note::before{content:""}.fa-down::before{content:""}.fa-arrow-alt-down::before{content:""}.fa-hundred-points::before{content:""}.fa-100::before{content:""}.fa-paperclip-vertical::before{content:""}.fa-wind-warning::before{content:""}.fa-wind-circle-exclamation::before{content:""}.fa-location-pin-slash::before{content:""}.fa-map-marker-slash::before{content:""}.fa-face-sad-sweat::before{content:""}.fa-bug-slash::before{content:""}.fa-cupcake::before{content:""}.fa-light-switch-off::before{content:""}.fa-toggle-large-off::before{content:""}.fa-pen-fancy-slash::before{content:""}.fa-truck-container::before{content:""}.fa-boot::before{content:""}.fa-arrow-up-from-water-pump::before{content:""}.fa-file-check::before{content:""}.fa-bone::before{content:""}.fa-cards-blank::before{content:""}.fa-circle-3::before{content:""}.fa-bench-tree::before{content:""}.fa-keyboard-brightness-low::before{content:""}.fa-ski-boot-ski::before{content:""}.fa-brain-circuit::before{content:""}.fa-table-cells-row-unlock::before{content:""}.fa-user-injured::before{content:""}.fa-block-brick-fire::before{content:""}.fa-firewall::before{content:""}.fa-face-sad-tear::before{content:""}.fa-sad-tear::before{content:""}.fa-plane::before{content:""}.fa-tent-arrows-down::before{content:""}.fa-exclamation::before{content:"\!"}.fa-arrows-spin::before{content:""}.fa-face-smile-relaxed::before{content:""}.fa-comment-xmark::before{content:""}.fa-comment-times::before{content:""}.fa-print::before{content:""}.fa-turkish-lira-sign::before{content:""}.fa-try::before{content:""}.fa-turkish-lira::before{content:""}.fa-face-nose-steam::before{content:""}.fa-circle-waveform-lines::before{content:""}.fa-waveform-circle::before{content:""}.fa-dollar-sign::before{content:"\$"}.fa-dollar::before{content:"\$"}.fa-usd::before{content:"\$"}.fa-ferris-wheel::before{content:""}.fa-computer-speaker::before{content:""}.fa-skull-cow::before{content:""}.fa-x::before{content:"X"}.fa-magnifying-glass-dollar::before{content:""}.fa-search-dollar::before{content:""}.fa-users-gear::before{content:""}.fa-users-cog::before{content:""}.fa-person-military-pointing::before{content:""}.fa-building-columns::before{content:""}.fa-bank::before{content:""}.fa-institution::before{content:""}.fa-museum::before{content:""}.fa-university::before{content:""}.fa-circle-t::before{content:""}.fa-sack::before{content:""}.fa-grid-2::before{content:""}.fa-camera-cctv::before{content:""}.fa-cctv::before{content:""}.fa-umbrella::before{content:""}.fa-trowel::before{content:""}.fa-horizontal-rule::before{content:""}.fa-bed-front::before{content:""}.fa-bed-alt::before{content:""}.fa-d::before{content:"D"}.fa-stapler::before{content:""}.fa-masks-theater::before{content:""}.fa-theater-masks::before{content:""}.fa-file-gif::before{content:""}.fa-kip-sign::before{content:""}.fa-face-woozy::before{content:""}.fa-cloud-question::before{content:""}.fa-pineapple::before{content:""}.fa-hand-point-left::before{content:""}.fa-gallery-thumbnails::before{content:""}.fa-circle-j::before{content:""}.fa-eyes::before{content:""}.fa-handshake-simple::before{content:""}.fa-handshake-alt::before{content:""}.fa-page-caret-up::before{content:""}.fa-file-caret-up::before{content:""}.fa-jet-fighter::before{content:""}.fa-fighter-jet::before{content:""}.fa-comet::before{content:""}.fa-square-share-nodes::before{content:""}.fa-share-alt-square::before{content:""}.fa-reflect-vertical::before{content:""}.fa-shield-keyhole::before{content:""}.fa-file-mp4::before{content:""}.fa-barcode::before{content:""}.fa-bulldozer::before{content:""}.fa-plus-minus::before{content:""}.fa-square-sliders-vertical::before{content:""}.fa-sliders-v-square::before{content:""}.fa-video::before{content:""}.fa-video-camera::before{content:""}.fa-message-middle::before{content:""}.fa-comment-middle-alt::before{content:""}.fa-graduation-cap::before{content:""}.fa-mortar-board::before{content:""}.fa-hand-holding-medical::before{content:""}.fa-person-circle-check::before{content:""}.fa-square-z::before{content:""}.fa-message-text::before{content:""}.fa-comment-alt-text::before{content:""}.fa-turn-up::before{content:""}.fa-level-up-alt::before{content:""}.sr-only,.fa-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border-width:0}.sr-only-focusable:not(:focus),.fa-sr-only-focusable:not(:focus){position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border-width:0}/*! - * Font Awesome Pro 6.6.0 by @fontawesome - https://fontawesome.com - * License - https://fontawesome.com/license (Commercial License) - * Copyright 2024 Fonticons, Inc. - */:root,:host{--fa-style-family-classic: "Font Awesome 6 Pro";--fa-font-solid: normal 900 1em/1 "Font Awesome 6 Pro"}@font-face{font-family:"Font Awesome 6 Pro";font-style:normal;font-weight:900;font-display:block;src:url(/dist/admin/fonts/e6f4e254e8b705435dd6.woff2) format("woff2"),url(/dist/admin/fonts/b65ac3b8da9f6efd3346.ttf) format("truetype")}.fas,.fa-solid{font-weight:900}/*! - * Font Awesome Pro 6.6.0 by @fontawesome - https://fontawesome.com - * License - https://fontawesome.com/license (Commercial License) - * Copyright 2024 Fonticons, Inc. - */:root,:host{--fa-style-family-sharp: "Font Awesome 6 Sharp";--fa-font-sharp-solid: normal 900 1em/1 "Font Awesome 6 Sharp"}@font-face{font-family:"Font Awesome 6 Sharp";font-style:normal;font-weight:900;font-display:block;src:url(/dist/admin/fonts/9fb9e3d1e42a353d678c.woff2) format("woff2"),url(/dist/admin/fonts/9a42f2741ca78a25feaa.ttf) format("truetype")}.fass,.fa-solid{font-weight:900}.daterangepicker{position:absolute;color:inherit;background-color:#fff;border-radius:4px;border:1px solid #ddd;width:278px;max-width:none;padding:0;margin-top:7px;top:100px;left:20px;z-index:3001;display:none;font-family:arial;font-size:15px;line-height:1em}.daterangepicker:before,.daterangepicker:after{position:absolute;display:inline-block;border-bottom-color:rgba(0, 0, 0, 0.2);content:""}.daterangepicker:before{top:-7px;border-right:7px solid transparent;border-left:7px solid transparent;border-bottom:7px solid #ccc}.daterangepicker:after{top:-6px;border-right:6px solid transparent;border-bottom:6px solid #fff;border-left:6px solid transparent}.daterangepicker.opensleft:before{right:9px}.daterangepicker.opensleft:after{right:10px}.daterangepicker.openscenter:before{left:0;right:0;width:0;margin-left:auto;margin-right:auto}.daterangepicker.openscenter:after{left:0;right:0;width:0;margin-left:auto;margin-right:auto}.daterangepicker.opensright:before{left:9px}.daterangepicker.opensright:after{left:10px}.daterangepicker.drop-up{margin-top:-7px}.daterangepicker.drop-up:before{top:initial;bottom:-7px;border-bottom:initial;border-top:7px solid #ccc}.daterangepicker.drop-up:after{top:initial;bottom:-6px;border-bottom:initial;border-top:6px solid #fff}.daterangepicker.single .daterangepicker .ranges,.daterangepicker.single .drp-calendar{float:none}.daterangepicker.single .drp-selected{display:none}.daterangepicker.show-calendar .drp-calendar{display:block}.daterangepicker.show-calendar .drp-buttons{display:block}.daterangepicker.auto-apply .drp-buttons{display:none}.daterangepicker .drp-calendar{display:none;max-width:270px}.daterangepicker .drp-calendar.left{padding:8px 0 8px 8px}.daterangepicker .drp-calendar.right{padding:8px}.daterangepicker .drp-calendar.single .calendar-table{border:none}.daterangepicker .calendar-table .next span,.daterangepicker .calendar-table .prev span{color:#fff;border:solid black;border-width:0 2px 2px 0;border-radius:0;display:inline-block;padding:3px}.daterangepicker .calendar-table .next span{transform:rotate(-45deg);-webkit-transform:rotate(-45deg)}.daterangepicker .calendar-table .prev span{transform:rotate(135deg);-webkit-transform:rotate(135deg)}.daterangepicker .calendar-table th,.daterangepicker .calendar-table td{white-space:nowrap;text-align:center;vertical-align:middle;min-width:32px;width:32px;height:24px;line-height:24px;font-size:12px;border-radius:4px;border:1px solid transparent;white-space:nowrap;cursor:pointer}.daterangepicker .calendar-table{border:1px solid #fff;border-radius:4px;background-color:#fff}.daterangepicker .calendar-table table{width:100%;margin:0;border-spacing:0;border-collapse:collapse}.daterangepicker td.available:hover,.daterangepicker th.available:hover{background-color:#eee;border-color:transparent;color:inherit}.daterangepicker td.week,.daterangepicker th.week{font-size:80%;color:#ccc}.daterangepicker td.off,.daterangepicker td.off.in-range,.daterangepicker td.off.start-date,.daterangepicker td.off.end-date{background-color:#fff;border-color:transparent;color:#999}.daterangepicker td.in-range{background-color:#ebf4f8;border-color:transparent;color:#000;border-radius:0}.daterangepicker td.start-date{border-radius:4px 0 0 4px}.daterangepicker td.end-date{border-radius:0 4px 4px 0}.daterangepicker td.start-date.end-date{border-radius:4px}.daterangepicker td.active,.daterangepicker td.active:hover{background-color:#357ebd;border-color:transparent;color:#fff}.daterangepicker th.month{width:auto}.daterangepicker td.disabled,.daterangepicker option.disabled{color:#999;cursor:not-allowed;text-decoration:line-through}.daterangepicker select.monthselect,.daterangepicker select.yearselect{font-size:12px;padding:1px;height:auto;margin:0;cursor:default}.daterangepicker select.monthselect{margin-right:2%;width:56%}.daterangepicker select.yearselect{width:40%}.daterangepicker select.hourselect,.daterangepicker select.minuteselect,.daterangepicker select.secondselect,.daterangepicker select.ampmselect{width:50px;margin:0 auto;background:#eee;border:1px solid #eee;padding:2px;outline:0;font-size:12px}.daterangepicker .calendar-time{text-align:center;margin:4px auto 0 auto;line-height:30px;position:relative}.daterangepicker .calendar-time select.disabled{color:#ccc;cursor:not-allowed}.daterangepicker .drp-buttons{clear:both;text-align:right;padding:8px;border-top:1px solid #ddd;display:none;line-height:12px;vertical-align:middle}.daterangepicker .drp-selected{display:inline-block;font-size:12px;padding-right:8px}.daterangepicker .drp-buttons .btn{margin-left:8px;font-size:12px;font-weight:bold;padding:4px 8px}.daterangepicker.show-ranges.single.rtl .drp-calendar.left{border-right:1px solid #ddd}.daterangepicker.show-ranges.single.ltr .drp-calendar.left{border-left:1px solid #ddd}.daterangepicker.show-ranges.rtl .drp-calendar.right{border-right:1px solid #ddd}.daterangepicker.show-ranges.ltr .drp-calendar.left{border-left:1px solid #ddd}.daterangepicker .ranges{float:none;text-align:left;margin:0}.daterangepicker.show-calendar .ranges{margin-top:8px}.daterangepicker .ranges ul{list-style:none;margin:0 auto;padding:0;width:100%}.daterangepicker .ranges li{font-size:12px;padding:8px 12px;cursor:pointer}.daterangepicker .ranges li:hover{background-color:#eee}.daterangepicker .ranges li.active{background-color:#08c;color:#fff}@media(min-width: 564px){.daterangepicker{width:auto}.daterangepicker .ranges ul{width:140px}.daterangepicker.single .ranges ul{width:100%}.daterangepicker.single .drp-calendar.left{clear:none}.daterangepicker.single .ranges,.daterangepicker.single .drp-calendar{float:left}.daterangepicker{direction:ltr;text-align:left}.daterangepicker .drp-calendar.left{clear:left;margin-right:0}.daterangepicker .drp-calendar.left .calendar-table{border-right:none;border-top-right-radius:0;border-bottom-right-radius:0}.daterangepicker .drp-calendar.right{margin-left:0}.daterangepicker .drp-calendar.right .calendar-table{border-left:none;border-top-left-radius:0;border-bottom-left-radius:0}.daterangepicker .drp-calendar.left .calendar-table{padding-right:8px}.daterangepicker .ranges,.daterangepicker .drp-calendar{float:left}}@media(min-width: 730px){.daterangepicker .ranges{width:auto}.daterangepicker .ranges{float:left}.daterangepicker.rtl .ranges{float:right}.daterangepicker .drp-calendar.left{clear:none !important}}.ui-datepicker{background-color:#fff;box-shadow:0 4px 10px -10px #000;border-bottom:5px solid var(--primaryColor);border-radius:4px;width:19em;padding:.2em 1.2em .2em;display:none}.ui-datepicker .ui-datepicker-header{position:relative;padding:.2em 0;margin:0 -1.2em;background-color:var(--primaryColor);color:#fff;border-top-right-radius:4px;border-top-left-radius:4px}.ui-datepicker .ui-datepicker-prev,.ui-datepicker .ui-datepicker-next{position:absolute;top:2px;width:1.8em;height:1.8em}.ui-datepicker .ui-datepicker-prev-hover,.ui-datepicker .ui-datepicker-next-hover{top:1px}.ui-datepicker .ui-datepicker-prev{left:2px}.ui-datepicker .ui-datepicker-next{right:2px}.ui-datepicker .ui-datepicker-prev-hover{left:1px}.ui-datepicker .ui-datepicker-next-hover{right:1px}.ui-datepicker .ui-datepicker-prev span,.ui-datepicker .ui-datepicker-next span{display:block;position:absolute;left:50%;margin-left:-15px;top:50%;margin-top:-8px;cursor:pointer;user-select:none}.ui-datepicker .ui-datepicker-prev span:before,.ui-datepicker .ui-datepicker-next span:before{font-family:"Font Awesome 6 Pro";position:absolute;top:0;right:0;width:20px;color:#fff}.ui-datepicker .ui-datepicker-prev{left:2px;left:auto}.ui-datepicker .ui-datepicker-prev>span:before{content:""}.ui-datepicker .ui-datepicker-next{right:2px;left:auto}.ui-datepicker .ui-datepicker-next>span:before{content:""}.ui-datepicker .ui-datepicker-title{margin:0 2.3em;line-height:1.8em;text-align:center}.ui-datepicker .ui-datepicker-title select{font-size:1em;margin:1px 0}.ui-datepicker select.ui-datepicker-month,.ui-datepicker select.ui-datepicker-year{width:45%}.ui-datepicker table{width:100%;font-size:.9em;border-collapse:collapse;margin:0 0 .4em}.ui-datepicker th{padding:.7em .3em;text-align:center;font-weight:bold;border:0}.ui-datepicker td{border:0;padding:1px}.ui-datepicker td span,.ui-datepicker td a{padding:.2em;text-align:right;text-decoration:none;background-color:#f7f7f7;width:30px;height:30px;display:flex;justify-content:center;align-items:center;float:right;border-radius:50%;margin-right:4px;margin-bottom:5px;font-size:13px}.ui-datepicker td span:hover,.ui-datepicker td a:hover{background-color:#f1f1f1}.ui-datepicker .ui-datepicker-buttonpane{background-image:none;margin:.7em 0 0 0;padding:0 .2em;border-left:0;border-right:0;border-bottom:0}.ui-datepicker .ui-datepicker-buttonpane button{float:right;margin:.5em .2em .4em;cursor:pointer;padding:.2em .6em .3em .6em;width:auto;overflow:visible}.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current{float:left}.ui-datepicker.ui-datepicker-multi{width:auto}.ui-datepicker-multi .ui-datepicker-group{float:left}.ui-datepicker-multi .ui-datepicker-group table{width:95%;margin:0 auto .4em}.ui-datepicker-multi-2 .ui-datepicker-group{width:50%}.ui-datepicker-multi-3 .ui-datepicker-group{width:33.3%}.ui-datepicker-multi-4 .ui-datepicker-group{width:25%}.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header{border-left-width:0}.ui-datepicker-multi .ui-datepicker-buttonpane{clear:left}.ui-datepicker-row-break{clear:both;width:100%;font-size:0}.ui-datepicker .ui-icon{display:block;overflow:hidden;background-repeat:no-repeat;left:.5em;top:.3em}.maxw-sm{max-width:540px}.maxw-md{max-width:720px}.maxw-lg{max-width:960px}.maxw-xl{max-width:1140px}.maxw-xxl{max-width:1320px}h1,.h1{font-size:40px;font-weight:500;margin-bottom:0}h2,.h2{font-size:30px;font-weight:500;margin-bottom:0}@media(max-width: 575.98px){h1,.h1{font-size:30px}h2,.h2{font-size:22px}}@property --button-primary-color{syntax:"";inherits:false;initial-value:#fff}.btn{display:inline-flex;justify-content:center;align-items:center;border:none;border-radius:20px;height:49px;font-size:16px}.btn.btn-primary{--button-primary-color: var(--primaryColor);background:linear-gradient(90deg, var(--primaryColorDark20) 0%, var(--button-primary-color) 100%);transition:--button-primary-color .5s;border:none;color:#fff}.btn.btn-primary:hover{--button-primary-color: var(--primaryColorDark20)}.btn.btn-secondary{color:#333;background-color:rgba(0,0,0,0);border-radius:20px;border:1px solid #d1e4e4}.btn.btn-secondary:active,.btn.btn-secondary:hover{border:1px solid #a8cccc}.btn.btn-danger{color:#fff;background-color:#bb2d3b}.btn.btn-danger:active,.btn.btn-danger:hover{background-color:rgb(145.8922413793,35.1077586207,46.0301724138)}@font-face{font-family:"Nunito",sans-serif;src:url(/dist/admin/fonts/9d7a6e03c6e3ed49c7ac.ttf);font-weight:normal}@font-face{font-family:"Nunito";src:url(/dist/admin/fonts/275dd55e10ba966bcb9b.ttf);font-weight:bold}@font-face{font-family:"TeXGyreHeros";src:url(/dist/admin/89937b93a1c3ac41f5a9.otf);font-weight:normal}@font-face{font-family:"Roboto";src:url(/dist/admin/fonts/fc2b5060f7accec5cf74.ttf);font-weight:400}@font-face{font-family:"Roboto";src:url(/dist/admin/fonts/7c8d04cd831df3033c8a.ttf);font-weight:500}@font-face{font-family:"Roboto";src:url(/dist/admin/fonts/cf56c1b149d0a5e8d7c6.ttf);font-weight:900}:root{--bs-bg-opacity: 1;--bs-dark-rgb: 16, 30, 42;--bs-body-font-size: $fs-body;--bs-font-sans-serif: "Roboto";--bs-link-color-rgb: 36, 21, 86;--bs-btn-bg: $datagrid-color;--side-panel-width: 70px}body{background-color:var(--secondaryColor);background-position:center;background-size:cover;background-repeat:no-repeat}body:has(.side-panel) .container{left:var(--side-panel-width);transition:left .5s ease}.header{display:flex;justify-content:space-between;align-items:center}.header-actions{display:flex;flex-direction:row;gap:10px}.header-actions .btn{padding:10px 18px;font-size:.9rem}.header-actions .btn-icon{border:0;border-radius:20px;border:solid 1px var(--secondaryColorDarker)}.header-actions .btn-icon:hover{background-color:#fff}.header-actions .btn-link{--bs-btn-font-weight: 500;color:#333;border:2px solid #d2d2d2;text-decoration:none}.snippet-flashes{position:fixed;bottom:30px;left:0;right:0;z-index:999;display:flex;align-items:center;justify-content:center;flex-direction:column;pointer-events:none}.snippet-flashes .alert{border-radius:20px;border:0;display:inline-flex;align-items:stretch;justify-content:center;font-size:16px;font-weight:500;line-height:normal;pointer-events:all;max-width:min(100vw - 50px,1300px);box-shadow:0px 0px 20px 0px rgba(109,109,109,.45);padding:20px 30px;gap:30px}.snippet-flashes .alert:before{margin:10px 0;font-size:30px;font-family:"Font Awesome 6 Pro"}.snippet-flashes .alert.alert-success{background-color:#28c885;color:#fff}.snippet-flashes .alert.alert-success .alert-close-btn{display:none}.snippet-flashes .alert.alert-success:before{content:""}.snippet-flashes .alert.alert-warning{background-color:#f9b300;color:#fff}.snippet-flashes .alert.alert-warning:before{content:""}.snippet-flashes .alert.alert-danger{background-color:#ff4242;color:#fff}.snippet-flashes .alert.alert-danger:before{content:""}.snippet-flashes .alert .alert-text{display:flex;align-items:center;height:100%;padding-top:17px;margin-bottom:10px}.snippet-flashes .alert .alert-close-btn{display:flex;width:161px;padding:10px 25px;flex-direction:column;justify-content:center;align-items:center;gap:10px;flex-shrink:0;border:0;margin-top:6px;border-radius:20px;background:#fff}.side-panel-template-backdrop{position:fixed;background-color:rgba(0,0,0,0);transition:all .4s ease;pointer-events:none;inset:0;z-index:9010}body:has(.side-panel-template-container form) .side-panel-template-backdrop{pointer-events:all;background-color:rgba(0,0,0,.3)}.side-panel-template-container{position:fixed;width:100vw;max-width:610px;right:-610px;top:0;bottom:0;padding:40px;overflow:auto;background-color:#fff;z-index:9020;box-shadow:0 0 0 0 #000;transition:right .4s ease}.side-panel-template-container:has(form){right:0;box-shadow:0 0 45px -10px #000}.side-panel-template-container .btn-close{position:absolute;top:20px;right:20px}.side-panel-template-container [type=submit]{width:100%}.side-panel-template-container form{display:flex;flex-direction:column}span.empty{font-style:italic;color:#999}.bg-primary-variant{background-color:var(--ternaryColor);color:var(--ternaryTextColor)}.bg-primary-variant::before{content:"";position:absolute;top:0;left:0;right:0;bottom:0;background-size:cover;opacity:.1}.container-login{width:100%;min-height:100dvh;display:flex;flex-direction:column;justify-content:center;align-items:center;padding:15px}@media(max-width: 575.98px){.container-login{padding:0}.container-login .wrap-login{background-color:initial}.container-login .wrap-login img{max-width:156px}.container-login .login-form{gap:0}}.wrap-login{position:relative;width:100%;max-width:500px;display:flex;flex-direction:column;justify-content:center;align-items:center;gap:50px;background-color:hsla(0,0%,100%,.3);border-radius:20px;padding:80px 40px}.wrap-login img{width:226px;height:auto}.login-form{display:flex;flex-direction:column;justify-content:center;align-items:flex-start;gap:60px;align-self:stretch}.login-form .inputs-wrap{display:flex;flex-direction:column;justify-content:center;align-items:flex-start;gap:20px;align-self:stretch}.login-form div:has(>.form-control),.login-form div:has(>.form-check){width:100%;margin-bottom:0 !important}.login-form div:has(>.form-control) label,.login-form div:has(>.form-check) label{font-size:.9rem;line-height:normal;color:#fff}.login-form div:has(>.form-control) .form-control,.login-form div:has(>.form-check) .form-control{width:100%;display:flex;padding:15px;align-items:center;gap:10px;font-size:.9rem;border:none;border-radius:20px;outline:none;background-color:hsla(0,0%,100%,.3);color:var(--ternaryTextColor);-webkit-text-fill-color:var(--ternaryTextColor)}.login-form div:has(>.form-control) .form-control::placeholder,.login-form div:has(>.form-check) .form-control::placeholder{color:var(--ternaryTextColor)}.login-form div:has(>.form-control) .form-control:focus,.login-form div:has(>.form-check) .form-control:focus{background-color:hsla(0,0%,100%,.4) !important}.login-form div:has(>.form-control) .form-control:-webkit-autofill,.login-form div:has(>.form-control) .form-control:-webkit-autofill:hover,.login-form div:has(>.form-control) .form-control:-webkit-autofill:focus,.login-form div:has(>.form-control) .form-control:-webkit-autofill:active,.login-form div:has(>.form-check) .form-control:-webkit-autofill,.login-form div:has(>.form-check) .form-control:-webkit-autofill:hover,.login-form div:has(>.form-check) .form-control:-webkit-autofill:focus,.login-form div:has(>.form-check) .form-control:-webkit-autofill:active{transition:background-color 5000s ease-in-out 0s}.login-form div:has(>.form-control) .form-control.input-company,.login-form div:has(>.form-check) .form-control.input-company{-webkit-text-fill-color:#8a8a8a;background:rgba(242,243,246,.8);box-shadow:none;outline:none}.login-form div:has(>.form-control) .form-control.input-company:focus,.login-form div:has(>.form-check) .form-control.input-company:focus{box-shadow:none !important}.login-form .linkInForm{color:var(--ternaryTextColor)}.side-panel{position:fixed;left:0;top:0;height:100%;width:var(--side-panel-width);display:flex;flex-direction:column;background-color:var(--secondaryColor)}.side-panel .menu{flex:1;display:flex;flex-direction:column;border-right:1px solid var(--secondaryColorDarker)}.side-panel .menu.bg{background-color:#fff;border-right:solid 1px hsl(0,0%,90%)}.side-panel .menu>.logo{height:70px;width:100%;display:flex;align-items:center;justify-content:center;margin-bottom:18px}.side-panel .menu>.item{height:60px;width:100%;display:flex;flex-direction:column;align-items:center;justify-content:center;color:#333;transition:width .5s ease;text-decoration:none}.side-panel .menu>.item>i{font-size:20px;transition:font-size .5s ease}.side-panel .menu>.item:hover{background-color:var(--secondaryColorDark)}.side-panel .menu>.item.active{color:var(--primaryColor);box-shadow:inset 5px 0 0 0 var(--primaryColor)}.side-panel .menu>.item .title{font-size:10px;font-style:normal;font-weight:400;line-height:normal}.side-panel .menu>.item>.submenu{background-color:#fff;left:var(--side-panel-width)}.side-panel .menu>.item>.submenu>.item>.submenu{left:var(--side-panel-width)200px}.side-panel .menu>.item>.submenu .item:has(.submenu):after{content:"";font-family:"Font Awesome 6 Pro";font-size:18px;margin-right:20px}.side-panel .menu .item.opened>.submenu{display:block !important}.side-panel .menu .item{cursor:pointer}.side-panel .menu .submenu{display:none;position:fixed;bottom:0;min-width:220px;top:0;box-shadow:4px 0 4px 0px rgba(0,0,0,.15)}.side-panel .menu .submenu .submenu-heading{width:100%;height:70px;line-height:70px;margin:0 20px;text-transform:uppercase;font-weight:500;font-size:15px;display:flex;align-items:center;color:#acacac}.side-panel .menu .submenu .item{padding:15px 20px;display:flex;justify-content:flex-start;flex-direction:row;text-decoration:none;color:#333;align-items:center;text-align:left;gap:10px}.side-panel .menu .submenu .item>.icon{display:flex;align-items:baseline;justify-content:center;width:20px;height:20px}.side-panel .menu .submenu .item.active{color:var(--primaryColorDark)}.side-panel .menu .submenu .item:hover{background:var(--secondaryColorDark)}.side-panel .bottom-menu{margin-top:auto}.navbar{position:fixed;top:0;left:var(--side-panel-width);right:0;height:80px;background-color:rgba(0,0,0,0) !important}.navbar .user{--bs-btn-hover-color: #fff;--bs-btn-active-color: #fff}.navbar .user .btn:active{border:0}@media(max-width: 575.98px){.navbar.hidden{top:-80px}}.navbar input[type=checkbox]{box-sizing:border-box;display:none;transition:all .25s}.menu-icon-toggle{box-sizing:border-box;cursor:pointer;height:17px;width:22px;transition:all .3s;margin:0 15px;opacity:1}.menu-icon-toggle:hover{opacity:.8}.hamb-line{box-sizing:border-box;position:absolute;height:3px;width:100%;background-color:#fff;transition:all .25s;border-radius:3px}.hor{transition:all .3s;box-sizing:border-box;position:relative;float:left;margin-top:3px}.dia.part-1{position:relative;box-sizing:border-box;float:left;transition:all .25s}.dia.part-2{box-sizing:border-box;position:relative;float:left;margin-top:3px;transition:all .25s}input[type=checkbox]:checked~.menu-icon-toggle>.hor{box-sizing:border-box;opacity:0;transition:all .25s}input[type=checkbox]:checked~.menu-icon-toggle>.dia.part-1{box-sizing:border-box;transform:rotate(135deg);margin-top:8px;transition:all .25s}input[type=checkbox]:checked~.menu-icon-toggle>.dia.part-2{box-sizing:border-box;transform:rotate(-135deg);margin-top:-9px;transition:all .25s}nav>div{display:flex;flex-wrap:inherit;align-items:center;justify-content:space-between;width:100%;margin:0 10px 0 0px}.table-responsive{overflow-x:auto;white-space:nowrap;border:1px solid var(--secondaryColorDarker);border-radius:20px;background-color:#fff;position:relative}.table-responsive::-webkit-scrollbar-track{border-radius:20px;background:rgba(0,0,0,0);display:none}.table-responsive::-webkit-scrollbar{border-radius:20px;background:rgba(0,0,0,0);height:0;display:none}.table-responsive::-webkit-scrollbar-thumb{border-radius:20px;background-color:#fff;border:23px solid rgba(0,0,0,0);display:none}.table-responsive::-webkit-scrollbar-corner{background:rgba(0,0,0,0);display:none}.table-responsive table{--actionShadowWidthLeft: 0px;--actionShadowWidthRight: 0px;background-color:#fff;height:100px;overflow:auto;width:auto;min-width:100%}.table-responsive table thead,.table-responsive table tbody{width:100%}.table-responsive table thead>tr:nth-child(1){z-index:9;position:sticky;top:0}.table-responsive table thead>tr:nth-child(2){z-index:9;position:sticky;top:33px}.table-responsive table th{padding:18px 30px;font-size:16px;font-weight:500;line-height:15px;background-color:#fff}@media(max-width: 575.98px){.table-responsive table th{padding:15px 20px}}.table-responsive table tbody>tr>td:first-child,.table-responsive table thead>tr>th:not(.table-header-divider):first-child{position:sticky;left:0;width:300px;max-width:min(30%,300px)}.table-responsive table tbody>tr>td:first-child>div,.table-responsive table thead>tr>th:not(.table-header-divider):first-child>div{width:300px;max-width:100%;white-space:normal;overflow:hidden;line-height:15px}.table-responsive table tbody>tr>td:first-child>div.is-clamped:after,.table-responsive table thead>tr>th:not(.table-header-divider):first-child>div.is-clamped:after{content:"...";position:absolute;bottom:0;right:0;background:#fff;padding-left:.5em;color:#000}.table-responsive table tbody>tr>td:first-child:after,.table-responsive table thead>tr>th:not(.table-header-divider):first-child:after{content:" ";display:flex;position:absolute;right:calc(var(--actionShadowWidthLeft)*-1);width:var(--actionShadowWidthLeft);top:0;bottom:0;transition:all .2s;box-shadow:inset calc(var(--actionShadowWidthLeft)*1) 0 calc(var(--actionShadowWidthLeft)*.5) calc(var(--actionShadowWidthLeft)*-1) #b3b3b3;pointer-events:none}.table-responsive table td{padding:18px 30px;font-size:16px;font-weight:400;line-height:15px;background-color:#fff}@media(max-width: 575.98px){.table-responsive table td{padding:15px 20px}}@media(min-width: 576px){.table-responsive table .col-action{width:0;position:sticky;right:0}.table-responsive table .col-action:before{content:" ";display:flex;position:absolute;left:calc(var(--actionShadowWidthRight)*-1);width:var(--actionShadowWidthRight);top:0;bottom:0;transition:all .2s;box-shadow:inset calc(var(--actionShadowWidthRight)*-1) 0 calc(var(--actionShadowWidthRight)*.5) calc(var(--actionShadowWidthRight)*-1) #b3b3b3;pointer-events:none}}.table-responsive table .col-action>div{position:relative;display:inline-flex;gap:15px}.table-responsive table .col-action .fa{color:var(--primaryColor)}.table-responsive table .col-action .fa:hover{color:var(--primaryColorDark)}.table-responsive table .col-action .btn:has(>.fa){padding:0;height:initial}.table-responsive table .col-action .dropdown-menu.show{border:0;box-shadow:0 4px 8px 0 rgba(0,0,0,.1490196078);max-width:300px;margin-top:8px !important;margin-right:-15px !important}.table-responsive table .col-action .dropdown-menu.show .dropdown-title{height:35px;display:flex;align-items:center;justify-content:center;background-color:var(--secondaryColor)}.table-responsive table .col-action .dropdown-menu.show>a{display:flex;justify-content:flex-start;align-items:center;background:#fff;gap:10px;align-self:stretch;text-decoration:none;font-size:14px;line-height:15px;padding:15px !important;text-wrap:nowrap;color:inherit}.table-responsive table .col-action .dropdown-menu.show>a>a:not(.btn-edit){padding:15px;width:100%}.table-responsive table .col-action .dropdown-menu.show>a:hover,.table-responsive table .col-action .dropdown-menu.show>a:focus{background:var(--secondaryColorDark)}.table-responsive table .col-action .dropdown-menu.show>.datagrid-delete .fa{color:#dc3545}.table-responsive table .col-action .dropdown-menu.show>.datagrid-delete:hover,.table-responsive table .col-action .dropdown-menu.show>.datagrid-delete:focus{background:rgb(248,214.6,217.8)}.table-responsive table .col-action .dropdown-menu.show>:not(:first-child).datagrid-delete{border-top:1px solid #000}.table-responsive table th.col-action:before{bottom:-6px}.table-responsive table tbody>tr:last-child>td{border-bottom:12px solid #fff}.table-responsive table thead>tr:first-child>th{padding-top:30px}.table-responsive table tr:has(.dropdown-menu.show){position:relative;z-index:99}.table-responsive table tr:hover td{background-color:hsl(0,0%,95%)}.table-responsive table .table-header-divider{height:1px;padding:0 30px}.table-responsive table .table-header-divider>div{background-color:hsl(0,0%,90%);height:1px}.icon-btn{color:var(--primaryColor)}.icon-btn:hover{color:var(--primaryColorDark)}form:has(>.table-responsive-wrapper){padding:0;display:flex;flex-direction:column;gap:20px}form:has(>.table-responsive-wrapper) [class^=grid-filters]:not(:has(input,select)){display:none}.col-pagination>div{display:flex;justify-content:center;gap:10px}.col-pagination>div .btn-group{gap:10px}.col-pagination>div .btn{border:1px solid #e7e6e9;border-radius:10px;border-top-right-radius:10px !important;border-bottom-right-radius:10px !important;border-top-left-radius:10px !important;border-bottom-left-radius:10px !important;width:35px;height:35px;display:flex;justify-content:center;align-items:center}.col-pagination>div .btn:hover{border-color:hsl(0,0%,90%)}.col-pagination>div .btn.btn-primary{border:none}.col-pagination>div .btn.btn-default{border:none;background-color:#f2f3f6 !important;align-items:center}.col-pagination>div .btn.btn-default:hover{background-color:rgba(0,0,0,0) !important;align-items:center}.col-pagination>div .btn.active{background-color:var(--secondaryColorDark) !important;border:1px solid var(--secondaryColorDarker)}.datagrid .main-search-filter{position:relative;display:flex;align-items:flex-end;justify-content:space-between;padding:.5rem 0 0 0}.datagrid .main-search-filter .form-group-filter{border:solid 1px var(--secondaryColorDarker);border-radius:20px;background-color:var(--secondaryColorDarker);width:300px;max-width:100%}.datagrid .main-search-filter .form-group-filter label{display:none}.datagrid .main-search-filter .search-icon{position:absolute;top:1.75rem;left:15px;pointer-events:none}.datagrid .main-search-filter [name="filter[search]"]{padding-left:40px}.datagrid .main-search-filter .btn{margin-left:5px}.datagrid .main-search-filter .collapse-filters:not(.collapsed) span.collapsed-text{display:none}.datagrid .main-search-filter .collapse-filters.collapsed span.not-collapsed-text{display:none}.datagrid .main-search-filter .grid-group-actions{display:flex}.datagrid .main-search-filter .grid-group-actions .btn-primary{color:var(--primaryColor);border:1px solid var(--primaryColor);background-color:rgba(0,0,0,0)}body{--inputBackground: var(--secondaryColor);--inputFocusBackground: var(--secondaryColorDark);--inputBorder: 0;--inputFocusBorder: 0}a{color:inherit}a:hover{color:var(--primaryColorDark)}.side-panel:not(.delay-animate){transition:all 260ms ease-in-out}:has(.side-panel .menu) #snippet--container{position:fixed;top:0;bottom:0;overflow:auto;margin-left:0;width:calc(100% - 70px);left:70px;padding:0px 25px 0 25px}@media(max-width: 575.98px){:has(.side-panel .menu) #snippet--container{padding:80px 15px 0 15px;bottom:65px}:has(.side-panel .menu):has(.sub-menu.opened) #snippet--container{bottom:108px}}@media(max-width: 575.98px){:has(.container-login) #snippet--container{--bs-gutter-x: 0 !important}.side-panel{display:none}#snippet--container{left:0 !important;width:100% !important}}.dashboard-card:has(.table-responsive){padding-bottom:0}.dashboard-card:has(.table-responsive) .table-responsive-wrapper{margin-left:-30px;margin-right:-30px}.dashboard-card:has(.table-responsive) .table-responsive{border:none;border-radius:0}.dashboard-card:has(.table-responsive) .table-responsive table th:not(.table-header-divider),.dashboard-card:has(.table-responsive) .table-responsive table td{padding:18px 30px}.header-title{padding:0;display:flex;flex-direction:column}.header-title .header-subtitle{font-size:18px;color:#8a8a8a;font-weight:normal}.form-label{font-size:18px;color:#333}input[type=file]{border:1px solid var(--secondaryColorDarker);border-radius:20px;padding:6px 15px 6px 12px;line-height:35px}input[type=color]{padding:0;border:1px solid var(--secondaryColorDarker);border-radius:20px;overflow:hidden;cursor:pointer}input[type=color]:focus{border-color:var(--secondaryColorDarker) !important}input[type=color]{-webkit-appearance:none}input[type=color]::-webkit-color-swatch-wrapper{padding:0}input[type=color]::-webkit-color-swatch{border:none}:not(.form-group-filter) .form-control{border:0;height:49px;border-radius:20px;padding:15px;font-size:16px;font-weight:400;line-height:18px}:not(.form-group-filter) .form-control:focus{box-shadow:none !important}:not(.form-group-filter) .form-control:disabled{background-color:#e7e6e9;cursor:not-allowed}.form-control:not(:disabled){background-color:var(--inputBackground);border:var(--inputBorder)}.form-control:focus{background-color:var(--inputFocusBackground) !important;border:var(--inputFocusBorder)}.form-check{padding-left:0;margin-top:0 !important;margin-bottom:0 !important}.form-check input{display:none}.form-check label{position:relative;display:flex;align-items:flex-start;gap:10px;cursor:pointer;user-select:none}.form-check label:before{display:block;content:" ";width:20px;height:20px;border:2px solid var(--secondaryColorDarker);border-radius:4px;transition:all .2s;min-width:20px;margin-top:2px}.form-check input:checked+label:before{background-color:var(--primaryColor);border:2px solid var(--primaryColor)}.form-check input:checked+label:after{left:0;position:absolute;content:"";font-family:"Font Awesome 6 Pro";font-weight:900;color:#fff;width:20px;height:20px;display:flex;align-items:center;justify-content:center;font-size:14px;margin-top:2px}.form-group-filter{display:flex}.form-group-filter:has(input[type=text]){position:relative}.form-group-filter:has(input[type=text])::before{content:"";font-family:"Font Awesome 6 Pro";position:absolute;bottom:12px;left:20px;pointer-events:none;z-index:9}.form-group-filter:has(input[type=text]) input[type=text]{padding-left:55px;border-radius:20px;border:none;max-width:100%;background-color:var(--secondaryColor)}.form-group-filter:has(input[type=text]) input[type=text]:focus{background-color:#fff !important}.form-group-filter:has(input[type=text]) input[type=text]:valid:not(:focus){background-color:var(--secondaryColorDark) !important}.vertical-divider{background-color:hsla(0,0%,100%,.3019607843);width:1px;height:45px}.dashboard-card{padding:30px;border:1px solid var(--secondaryColorDarker);border-radius:20px;display:flex;gap:25px;min-height:calc(100% - 1rem)}.dashboard-card [data-adt-components-panels-base-basechartpanel]{display:none}.dashboard-card .dashboard-card-header{display:flex;flex-direction:row;justify-content:space-between;align-items:center}.dashboard-card .icon{color:var(--primaryColor)}.dashboard-card .card-amount{font-size:max(min(10px + 2vw,40px),30px);font-weight:700;line-height:47px;display:flex;gap:32px}.dashboard-card .card-amount-diff{font-weight:400;color:#acacac;font-size:18px}.dashboard-card .card-text{font-size:16px;font-weight:400;line-height:19px}@media(max-width: 575.98px){.dashboard-card{padding:20px}.dashboard-card .table-responsive{margin-left:-20px !important;margin-right:-20px !important}}.dashboard-input-group{display:flex;align-items:flex-start}.dashboard-input-group input[type=text]{display:flex;padding:15px 25px;justify-content:center;align-items:center;border-bottom:0;border-radius:20px 0 0 20px;background:var(--secondaryColor)}.dashboard-input-group input[type=submit]{display:flex;padding:13px 30px 15px 25px;justify-content:center;align-items:center;color:#fff;border-radius:0 20px 20px 0;background:var(--primaryColor);font-size:16px;font-style:normal;font-weight:400;line-height:normal}.container-fluid,.container-sm,.container-md,.container-lg,.container-xl,.container-xxl{--bs-gutter-x: 4.5rem !important}.container-fluid>div>.panel.simple-table,.container-sm>div>.panel.simple-table,.container-md>div>.panel.simple-table,.container-lg>div>.panel.simple-table,.container-xl>div>.panel.simple-table,.container-xxl>div>.panel.simple-table{display:flex;margin:40px 0}.container-fluid>div>.header,.container-sm>div>.header,.container-md>div>.header,.container-lg>div>.header,.container-xl>div>.header,.container-xxl>div>.header{margin:20px 0}.container-fluid>div>.header:has(h1,.h1),.container-sm>div>.header:has(h1,.h1),.container-md>div>.header:has(h1,.h1),.container-lg>div>.header:has(h1,.h1),.container-xl>div>.header:has(h1,.h1),.container-xxl>div>.header:has(h1,.h1){display:flex;margin:20px 0 20px 0}.container-fluid>div>.header:has(h2,.h2),.container-sm>div>.header:has(h2,.h2),.container-md>div>.header:has(h2,.h2),.container-lg>div>.header:has(h2,.h2),.container-xl>div>.header:has(h2,.h2),.container-xxl>div>.header:has(h2,.h2){display:flex;margin:40px 0 20px 0}.container-fluid>div>.back-link,.container-sm>div>.back-link,.container-md>div>.back-link,.container-lg>div>.back-link,.container-xl>div>.back-link,.container-xxl>div>.back-link{display:flex;margin:20px 0}.container-fluid>div>.datagrid,.container-sm>div>.datagrid,.container-md>div>.datagrid,.container-lg>div>.datagrid,.container-xl>div>.datagrid,.container-xxl>div>.datagrid{display:flex;flex-direction:column;margin:20px 0}.container-fluid>div:has(.container-login),.container-sm>div:has(.container-login),.container-md>div:has(.container-login),.container-lg>div:has(.container-login),.container-xl>div:has(.container-login),.container-xxl>div:has(.container-login){--bs-gutter-x: 0 !important}.bottom-mobile-menu{position:fixed;bottom:0;left:0;right:0;height:65px;background-color:var(--secondaryColor);border-top:1px solid var(--secondaryColorDarker);z-index:10}.bottom-mobile-menu a{width:100%;height:100%;display:flex;align-items:center;flex-direction:column;justify-content:center;text-decoration:none}.bottom-mobile-menu a>i{font-size:24px;color:#333}.bottom-mobile-menu a>span{font-size:12px;font-weight:400;color:#333}.bottom-mobile-menu a.active>i,.bottom-mobile-menu a.active>span{color:var(--primaryColor)}.bottom-mobile-menu:has(.isOpened) a.isOpened>i,.bottom-mobile-menu:has(.isOpened) a.isOpened>span{color:var(--primaryColor) !important}.bottom-mobile-menu:has(.isOpened) a:not(.isOpened)>i,.bottom-mobile-menu:has(.isOpened) a:not(.isOpened)>span{color:#333 !important}.sub-menu{position:fixed;bottom:65px;left:0;right:0;height:45px;background-color:var(--secondaryColor);border-top:1px solid var(--secondaryColorDarker);z-index:9;transition:.2s all;display:flex;flex-direction:row;flex-wrap:nowrap;overflow-y:scroll}.sub-menu>a{display:flex;padding:0 20px;height:100%;align-items:center;text-decoration:none;gap:8px}.sub-menu>a>i{font-size:16px;color:#333}.sub-menu>a>span{font-size:12px;font-weight:400;color:#333;text-wrap:nowrap}.sub-menu>a.active>i,.sub-menu>a.active>span{color:var(--primaryColor)}.sub-menu:not(.opened){bottom:20px}.list-group-item ul{padding-left:0}.list-group-item ul li a{padding-left:2rem !important}.panel.simple-table{padding:35px;display:flex;flex-direction:column;justify-content:center;align-items:flex-start;gap:16px;border-radius:20px;border:1px solid #e7e6e9;background:#fff}@media(max-width: 575.98px){.panel.simple-table{padding:20px}}.panel.simple-table>.row{width:100%;font-size:16px;font-weight:400;line-height:normal}.panel.simple-table>.row>*:first-child{color:var(--primaryColor);font-weight:400}.btn-new:before{font-family:"Font Awesome 6 Pro";font-weight:900;content:"+";margin-right:10px}.back-link{width:auto;display:flex;align-items:center;font-size:16px;font-weight:400}.back-link:hover a{color:var(--primaryColor)}.back-link:before{font-family:"Font Awesome 6 Pro";font-weight:900;content:"";margin-right:10px;font-size:14px;color:#333}.btn-avatar{display:flex;width:45px;height:45px;margin:20px 12.5px;padding:0;justify-content:center;align-items:center;gap:10px;border-radius:100%;background:#fff;opacity:1}.btn-avatar:hover{opacity:.8}.btn-avatar i{color:rgb(var(--bs-dark-rgb))}.btn-avatar:hover,.btn-avatar.show,.btn-avatar:active{background-color:#fff !important}.btn-avatar:hover i,.btn-avatar.show i,.btn-avatar:active i{color:rgb(var(--bs-dark-rgb)) !important}.btn-avatar:has(>img){overflow:hidden}.btn-avatar:has(>img) i{display:none}.btn-avatar:has(>img) img{width:100%;height:100%;object-fit:contain}.bottom-mobile-menu .bottom-menu .user.dropdown .btn-avatar{margin:6px 0 1px 0}.bottom-mobile-menu .bottom-menu .user.dropdown ul{left:initial !important;bottom:10px !important;right:-10px !important}.order-simple-table{width:625px;max-width:100%;margin:40px 0}.order-simple-table .row>span:nth-child(1){width:220px}.order-simple-table .row>span:nth-child(2){width:calc(100% - 220px)}@media(max-width: 767.98px){.order-simple-table .row>span{width:100% !important}}.dropdown-menu{--bs-border-radius: 20px;--bs-dropdown-padding-y: 0;--bs-dropdown-spacer: 20px;overflow:hidden}.dropdown-menu .dropdown-item{padding:15px !important;cursor:pointer}@media(max-width: 575.98px){.dropdown-menu .dropdown-item{font-size:14px}}.dropdown-menu .dropdown-divider{display:none}.daterangepicker{border-radius:20px;overflow:hidden;box-shadow:0 4px 4px 0 rgba(0,0,0,.15);border:0;background-color:#fff;margin-top:10px;font-family:"Roboto"}.daterangepicker .drp-buttons .btn{margin-left:8px;font-weight:bold;padding:4px 14px;height:30px}.daterangepicker td.available:not(.off):hover{background-color:var(--secondaryColorDarker)}.daterangepicker td.in-range{background-color:var(--secondaryColorDark)}.daterangepicker td.in-range:hover{background-color:var(--secondaryColorDarker)}.daterangepicker td.off.in-range,.daterangepicker td.off.start-date,.daterangepicker td.off.end-date{background-color:var(--secondaryColor)}.daterangepicker td.off.in-range:hover,.daterangepicker td.off.start-date:hover,.daterangepicker td.off.end-date:hover{background-color:var(--secondaryColorDarker)}.daterangepicker .calendar-table{background-color:#fff;border:0}.daterangepicker:before,.daterangepicker:after{display:none}.daterangepicker .ranges{margin-top:0 !important}.daterangepicker .ranges li{padding:15px;font-size:14px}.daterangepicker .ranges li:hover{background-color:var(--secondaryColorDark)}.daterangepicker .ranges li.active{background-color:var(--secondaryColor);color:var(--primaryColor)}.daterangepicker .ranges li.active:hover{background-color:var(--secondaryColorDark)}.daterangepicker td.active{background-color:var(--primaryColor)}.daterangepicker td.active:hover{background-color:var(--primaryColor)}.chart-legend{display:flex;flex-direction:row;flex-wrap:wrap;justify-content:center;gap:8px;margin-top:20px}.chart-legend>.legend-item{text-wrap:nowrap;display:inline-flex;align-items:center;margin:0 5px;transition:all .1s;cursor:default;user-select:none}.chart-legend>.legend-item:before{content:" ";height:15px;width:15px;background-color:var(--legendItemColor);margin-right:8px;border-radius:5px}.chart-legend>.legend-item:hover{transform:scale(1.04)}.dashboardTopCardPanels .dashboard-card{border-color:var(--primaryColor)}label:has(input[name=dateRange]){position:relative}label:has(input[name=dateRange]) input{transition:all .15s !important;padding:15px 15px 15px 35px;text-align:center;background-color:var(--secondaryColorDarker)}label:has(input[name=dateRange]) input:focus{background-color:inherit}label:has(input[name=dateRange]) input:hover{background-color:#fff;cursor:pointer}label:has(input[name=dateRange])::before{position:absolute;top:12px;left:15px;display:block;content:"";font-family:"Font Awesome 6 Pro";font-size:15px;pointer-events:none;color:var(--primaryColor)}[data-adt-daterange].datepicker-open{background-color:var(--inputFocusBackground) !important;border:var(--inputFocusBorder)}.navbar-brand:hover{opacity:.8}body:not(:has(.navbar)) #snippet--container{padding-top:0 !important}@media(max-width: 575.98px){.sub-menu::-webkit-scrollbar-track{background-color:rgba(0,0,0,0)}.sub-menu::-webkit-scrollbar{height:0;width:0;background-color:rgba(0,0,0,0)}.sub-menu::-webkit-scrollbar-thumb{background-color:rgba(0,0,0,0)}}@media(min-width: 564px){.daterangepicker .ranges ul{width:auto !important}}.btn-icon{width:48px;height:48px;display:flex;align-items:center;justify-content:center;border:1px solid var(--secondaryColorDarker);border-radius:10px;background-color:var(--secondaryColor);font-size:18px !important}.btn-icon:not(.loading) .spinner-border{display:none}.btn-icon.loading:has(.spinner-border){padding:0;font-weight:normal;font-size:12px !important}.btn-icon.loading:has(.spinner-border)>i{display:none}:not(.btn-check)+.btn:active{--bs-btn-active-border-color: initial;--bs-btn-active-color: initial}.btn-dashboard-filter{padding-right:0 !important;padding-left:0 !important;background-color:#caece7}.btn-dashboard-filter .filter-name{margin-left:20px;margin-right:15px}.btn-dashboard-filter .icon{content:"";width:48px;height:48px;display:flex;font-family:"Font Awesome 6 Pro";align-items:center;justify-content:center;border-radius:20px;font-size:18px !important}.btn-dashboard-filter:has(.inactive) .icon{background-color:#82878d !important}.btn-dashboard-filter:not(.btn-dashboard-filter:has(.inactive)) .icon{background-color:#00b4a2 !important}.main-search-filter{margin-bottom:-5px}@media(max-width: 575.98px){.main-search-filter{flex-direction:column;gap:20px}.main-search-filter .form-group-filter{width:100% !important}}#iOsA2HS{z-index:9999;position:fixed;inset:0}#iOsA2HS .iOsA2HS_backdrop{position:absolute;inset:0;background-color:rgba(57,57,57,.5803921569)}#iOsA2HS .iOsA2HS_popup{border-radius:20px;z-index:9999;background:#f3f3f3;position:fixed;bottom:15px;left:15px;right:15px;text-align:left;color:#333;padding:15px;box-shadow:0 7px 14px 0px rgba(0,0,0,.7882352941)}#iOsA2HS .install-header{display:flex;flex-direction:row;align-items:center;gap:20px}#iOsA2HS .install-header>div:nth-child(1){width:50px;height:50px;display:flex;flex-direction:row;align-items:center;justify-content:center;background:#fff;box-shadow:0 1px 7px -2px rgba(0,0,0,0.7882352941);border-radius:12px}#iOsA2HS .install-header>div:nth-child(1) img{width:60%;height:60%;object-fit:contain}#iOsA2HS .install-header>div:nth-child(2){width:calc(100% - 50px)}#iOsA2HS li>i{background-color:#fff;border-radius:12px;color:#1e90ff;padding:8px;margin-left:5px}#iOsA2HS li>b{background-color:#fff;border-radius:12px;padding:8px 12px;margin-left:5px;font-weight:normal;font-size:90%;text-wrap:nowrap}#iOsA2HS li{margin-bottom:10px}label.required:after{content:"*";color:#ff4242;margin-left:5px}body:fullscreen #snippet--container{z-index:999;background-color:#fff;position:fixed !important;top:0 !important;width:calc(100% - 50px) !important;margin-left:0 !important;overflow:auto !important;padding:20px !important}body:fullscreen #snippet--container .header{display:none}body:fullscreen [data-open-fullscreen] .fa-expand{display:none}body:not(:fullscreen) [data-open-fullscreen] .fa-compress{display:none}body{overflow:hidden}iframe{z-index:99999;display:block;position:relative;inset:0;width:100%;height:100vh;opacity:0;pointer-events:none}.print-page{zoom:.55;width:390.6mm;margin:0;padding:0;-webkit-print-color-adjust:exact}.print-page #snippet--dashboardTopCardPanels>div{flex:0 0 auto !important;width:33.33333333% !important}.print-page canvas{max-height:310px}.print-page .col-md-8{width:66.66666667% !important}.print-page .col-md-4{width:33.33333333% !important}@page{size:A4;margin:0}.user-dropdown{box-shadow:0px 4px 4px 0px rgba(0,0,0,.15);left:70px !important;bottom:-50px !important;background-color:var(--ternaryColor);--bs-dropdown-link-color: white}.user-dropdown .logout-item{border-top:1px solid hsla(0,0%,100%,.3);box-shadow:0px 4px 4px 0px rgba(0,0,0,.25)}.user-dropdown .dropdown-item{text-decoration:none;color:var(--ternaryTextColor);background-color:hsla(0,0%,100%,.1019607843)}.user-dropdown .dropdown-item a{pointer-events:none;text-decoration:none;color:inherit}.user-dropdown .dropdown-item:active{background-color:var(--ternaryColor)}.user-dropdown .dropdown-item:hover{background-color:hsla(0,0%,100%,.2)}.user-dropdown .user-item-wrapper{--bs-dropdown-link-hover-bg: initial;--bs-dropdown-link-hover-color: white;cursor:default;border-bottom:1px solid hsla(0,0%,100%,.3);pointer-events:none;background-color:var(--ternaryColor)}.user-dropdown .user-item-wrapper .user-item{display:flex;gap:10px}.user-dropdown .user-item-wrapper .user-item>div:first-child{display:flex;justify-content:center;align-items:center;border-radius:100%;width:40px;height:40px;font-size:40px}.user-dropdown .user-item-wrapper .user-item>div:first-child:has(>img){overflow:hidden;background-color:#fff}.user-dropdown .user-item-wrapper .user-item>div:first-child:has(>img) i{display:none}.user-dropdown .user-item-wrapper .user-item>div:first-child:has(>img) img{width:40px;height:40px;object-fit:contain;border:2px solid #fff;border-radius:100%}.user-dropdown .user-item-wrapper .user-item>div:last-child{display:flex;flex-direction:column;justify-content:center;align-items:flex-start;gap:5px}.user-dropdown .user-item-wrapper .user-item>div:last-child>div:first-child{font-size:16px;font-weight:700;line-height:normal}.user-dropdown .user-item-wrapper .user-item>div:last-child>div:last-child{font-size:14px;font-weight:400;line-height:normal}.user-dropdown .dropdown-item:not(.user-item-wrapper):has(i.fa-solid){--bs-dropdown-link-hover-bg: rgba(255, 255, 255, 0.1)}.user-dropdown .dropdown-item:not(.user-item-wrapper):has(i.fa-solid)>div{display:flex;flex-direction:row;gap:10px;align-items:center;justify-content:flex-start}.user-dropdown .dropdown-item:not(.user-item-wrapper):has(i.fa-solid)>div>div:first-child{display:flex;flex-direction:row;align-items:center;justify-content:center;width:21px;font-size:18px}.user-dropdown .dropdown-item:not(.user-item-wrapper):has(i.fa-solid)>div>div:last-child{font-size:16px;font-weight:400;line-height:normal}.click-line-detail table tbody td:not(.col-action):not(:has(button,input,select)){cursor:pointer}.dropdown-filter{transition:background-color .25s;background-color:var(--inputBackground);border:var(--inputBorder)}.dropdown-filter:has(>a:hover>.dropdown-selected-name-wrapper){background-color:var(--inputFocusBackground)}.dropdown-filter a:not(:has(.dropdown-selected-name-wrapper))>span>i{background-color:var(--secondaryColor)}.dropdown-filter:not(.select) a:not(:has(.dropdown-selected-name-wrapper)):has(.fa-filter) i{border-top-right-radius:0;border-bottom-right-radius:0}.dropdown-filter:not(.select) a:not(:has(.dropdown-selected-name-wrapper)):has(.fa-filter):hover i{background-color:var(--inputFocusBackground)}.dropdown-filter>a.btn,.dropdown-filter button{--bs-border-width: 0;z-index:1;display:flex;height:48px;border-radius:20px;padding:0 !important;align-items:center;justify-content:center;border:0;background-color:rgba(0,0,0,0)}.dropdown-filter>a.btn:focus,.dropdown-filter>a.btn:active,.dropdown-filter button:focus,.dropdown-filter button:active{border-color:var(--secondaryColorDarker) !important}.dropdown-filter>a.btn a,.dropdown-filter button a{text-decoration:none}.dropdown-filter>a.btn a:hover,.dropdown-filter button a:hover{color:#333}.dropdown-filter>a.btn>span>i,.dropdown-filter button>span>i{display:flex;align-items:center;justify-content:center;width:48px;height:48px;border-radius:20px}.dropdown-filter>a.btn .dropdown-selected-name-wrapper,.dropdown-filter button .dropdown-selected-name-wrapper{display:flex;align-items:center;gap:15px;padding:0 10px 0 15px}.dropdown-filter>a.btn .dropdown-selected-name-wrapper i,.dropdown-filter button .dropdown-selected-name-wrapper i{color:var(--primaryColor);font-size:15px}.dropdown-filter>.disable-filter-button>i{margin-bottom:-1px;margin-top:-1px;height:50px !important;background-color:var(--secondaryColor)}.dropdown-filter button.dropdown-toggle{width:48px;background-color:var(--secondaryColor)}.dropdown-filter button.dropdown-toggle:hover{background-color:var(--inputFocusBackground)}.dropdown-filter.selected>a>span>i.fa-filter{display:none}.dropdown-filter.selected>a:not(.disable-filter-button)>i.fa-xmark{background-color:#e7e6e9;font-size:18px}.dropdown-filter:not(.selected)>a>i.fa-xmark{display:none}.dropdown-filter:not(.selected) a:has(.dropdown-selected-name-wrapper){display:none}.dropdown-filter:not(.selected) a.btn{border-radius:20px;border-right:solid 1px var(--secondaryColorDarker) !important}.dashboardFilterDateRangeForm,.primary-select,[data-adt-dashboard-filter]{--inputBackground: var(--secondaryColorDarker);--inputFocusBackground: white;--inputBorder: 1px solid var(--secondaryColorDarker);--inputFocusBorder: 1px solid var(--secondaryColorDarker)}@media(max-width: 575.98px){.header-actions:has(.dashboardFilterDateRangeForm):has([data-adt-dashboard-filter].selected){flex-direction:column-reverse;align-items:flex-end;flex-wrap:wrap;width:100%;justify-content:flex-end}.show-on-desktop{display:none}}@media(min-width: 576px){.show-on-mobile{display:none}}[data-adt-dashboard-filter] .selected a.disable-filter-button{top:0;right:0;text-decoration:none;color:inherit}[data-adt-dashboard-filter] .selected a.disable-filter-button i,[data-adt-dashboard-filter] .selected a.disable-filter-button a i{display:flex;align-items:center;justify-content:center;width:48px;height:48px;border-radius:20px 0 0 20px;background-color:var(--secondaryColor);font-size:18px;border:solid 1px var(--secondaryColorDarker)}[data-adt-dashboard-filter] .selected a.disable-filter-button i:hover,[data-adt-dashboard-filter] .selected a.disable-filter-button a i:hover{background-color:#fff;border-color:var(--secondaryColorDarker)}[data-adt-dashboard-filter]:not(.selected)>a.disable-filter-button{display:none}.was-validated .form-control:invalid,.form-control.is-invalid{background-color:rgba(255,66,66,.1215686275)}select.is-invalid+.select2 .select2-selection__rendered{border-color:var(--bs-form-invalid-border-color);padding-right:calc(1.5em + 1.2rem);background-image:url("data:image/svg+xml,%3csvg xmlns=%27http://www.w3.org/2000/svg%27 viewBox=%270 0 12 12%27 width=%2712%27 height=%2712%27 fill=%27none%27 stroke=%27%23dc3545%27%3e%3ccircle cx=%276%27 cy=%276%27 r=%274.5%27/%3e%3cpath stroke-linejoin=%27round%27 d=%27M5.8 3.6h.4L6 6.5z%27/%3e%3ccircle cx=%276%27 cy=%278.2%27 r=%27.6%27 fill=%27%23dc3545%27 stroke=%27none%27/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.975em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}select.is-invalid+.select2 .select2-selection{background-color:rgba(255,66,66,.1215686275) !important}select.is-invalid+.select2 .select2-selection--multiple .select2-selection__rendered{padding-right:calc(.9em + 1.2rem);background-position:right calc(.1em + .1875rem) center;background-size:calc(.65em + .375rem) calc(.75em + .375rem)}.datagrid-exports .btn{height:48px;width:48px;background-color:var(--secondaryColor);border:solid 1px var(--secondaryColorDarker);border-radius:20px;padding:0 !important;align-items:center;justify-content:center}.datagrid-exports .btn:hover{background-color:#fff;border:solid 1px var(--secondaryColorDarker)}[data-adt-replicator-item] .input-group input[name$="[value]"]{border-radius:20px 0 0 20px;border-right:solid 2px var(--secondaryColorDarker)}[data-adt-replicator-item] .input-group input[name$="[value]"]:focus,[data-adt-replicator-item] .input-group input[name$="[value]"]:active{border-right:solid 2px var(--secondaryColorDarker) !important}[data-adt-replicator-item] .input-group input[name$="[value2]"]{border-radius:0 20px 20px 0}[data-adt-replicator-item] [data-adt-replicator-remove]:hover .delete-text{color:#dc3545}[data-adt-replicator-item] [data-adt-replicator-remove]:hover i{color:#333}#canvas_cont #canvas{background-image:linear-gradient(to right, #E7E6E9 1px, transparent 1px),linear-gradient(to bottom, #E7E6E9 1px, transparent 1px);background-size:100px 100px;background-color:#fff;border:1px solid #e7e6e9;border-radius:10px}.draggable{cursor:move;transform:translate(0, 0)}.light-gray-bordered-box{border:1px solid #e7e6e9;border-radius:20px}.table-bottom-scroll{background-color:rgba(0,0,0,0);position:sticky;bottom:15px;margin:-30px 10px 30px;height:21px;overflow-x:auto;z-index:9}.table-bottom-scroll::-webkit-scrollbar{border-radius:20px;background:var(--secondaryColor);height:14px}.table-bottom-scroll::-webkit-scrollbar-thumb{border-radius:20px;background-color:var(--secondaryColorDarker);border:3px solid var(--secondaryColor);cursor:pointer}.table-bottom-scroll::-webkit-scrollbar-corner{background:rgba(0,0,0,0)}.select2-container{box-sizing:border-box;display:inline-block;margin:0;position:relative;vertical-align:middle}.select2-container .select2-selection--single{box-sizing:border-box;cursor:pointer;display:block;height:28px;user-select:none;-webkit-user-select:none}.select2-container .select2-selection--single .select2-selection__rendered{display:block;padding-left:8px;padding-right:20px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.select2-container .select2-selection--single .select2-selection__clear{position:relative}.select2-container[dir=rtl] .select2-selection--single .select2-selection__rendered{padding-right:8px;padding-left:20px}.select2-container .select2-selection--multiple{box-sizing:border-box;cursor:pointer;display:block;min-height:32px;user-select:none;-webkit-user-select:none}.select2-container .select2-selection--multiple .select2-selection__rendered{display:inline-block;overflow:hidden;padding-left:8px;text-overflow:ellipsis;white-space:nowrap}.select2-container .select2-search--inline{float:left}.select2-container .select2-search--inline .select2-search__field{box-sizing:border-box;border:none;font-size:100%;margin-top:5px;padding:0}.select2-container .select2-search--inline .select2-search__field::-webkit-search-cancel-button{-webkit-appearance:none}.select2-dropdown{background-color:white;border:1px solid #aaa;border-radius:4px;box-sizing:border-box;display:block;position:absolute;left:-100000px;width:100%;z-index:1051}.select2-results{display:block}.select2-results__options{list-style:none;margin:0;padding:0}.select2-results__option{padding:6px;user-select:none;-webkit-user-select:none}.select2-results__option[aria-selected]{cursor:pointer}.select2-container--open .select2-dropdown{left:0}.select2-container--open .select2-dropdown--above{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--open .select2-dropdown--below{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.select2-search--dropdown{display:block;padding:4px}.select2-search--dropdown .select2-search__field{padding:4px;width:100%;box-sizing:border-box}.select2-search--dropdown .select2-search__field::-webkit-search-cancel-button{-webkit-appearance:none}.select2-search--dropdown.select2-search--hide{display:none}.select2-close-mask{border:0;margin:0;padding:0;display:block;position:fixed;left:0;top:0;min-height:100%;min-width:100%;height:auto;width:auto;opacity:0;z-index:99;background-color:#fff;filter:alpha(opacity=0)}.select2-hidden-accessible{border:0 !important;clip:rect(0 0 0 0) !important;-webkit-clip-path:inset(50%) !important;clip-path:inset(50%) !important;height:1px !important;overflow:hidden !important;padding:0 !important;position:absolute !important;width:1px !important;white-space:nowrap !important}.select2-container--default .select2-selection--single{background-color:#fff;border:1px solid #aaa;border-radius:4px}.select2-container--default .select2-selection--single .select2-selection__rendered{color:#444;line-height:28px}.select2-container--default .select2-selection--single .select2-selection__clear{cursor:pointer;float:right;font-weight:bold}.select2-container--default .select2-selection--single .select2-selection__placeholder{color:#999}.select2-container--default .select2-selection--single .select2-selection__arrow{height:26px;position:absolute;top:1px;right:1px;width:20px}.select2-container--default .select2-selection--single .select2-selection__arrow b{border-color:#888 transparent transparent transparent;border-style:solid;border-width:5px 4px 0 4px;height:0;left:50%;margin-left:-4px;margin-top:-2px;position:absolute;top:50%;width:0}.select2-container--default[dir=rtl] .select2-selection--single .select2-selection__clear{float:left}.select2-container--default[dir=rtl] .select2-selection--single .select2-selection__arrow{left:1px;right:auto}.select2-container--default.select2-container--disabled .select2-selection--single{background-color:#eee;cursor:default}.select2-container--default.select2-container--disabled .select2-selection--single .select2-selection__clear{display:none}.select2-container--default.select2-container--open .select2-selection--single .select2-selection__arrow b{border-color:transparent transparent #888 transparent;border-width:0 4px 5px 4px}.select2-container--default .select2-selection--multiple{background-color:white;border:1px solid #aaa;border-radius:4px;cursor:text}.select2-container--default .select2-selection--multiple .select2-selection__rendered{box-sizing:border-box;list-style:none;margin:0;padding:0 5px;width:100%}.select2-container--default .select2-selection--multiple .select2-selection__rendered li{list-style:none}.select2-container--default .select2-selection--multiple .select2-selection__clear{cursor:pointer;float:right;font-weight:bold;margin-top:5px;margin-right:10px;padding:1px}.select2-container--default .select2-selection--multiple .select2-selection__choice{background-color:#e4e4e4;border:1px solid #aaa;border-radius:4px;cursor:default;float:left;margin-right:5px;margin-top:5px;padding:0 5px}.select2-container--default .select2-selection--multiple .select2-selection__choice__remove{color:#999;cursor:pointer;display:inline-block;font-weight:bold;margin-right:2px}.select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover{color:#333}.select2-container--default[dir=rtl] .select2-selection--multiple .select2-selection__choice,.select2-container--default[dir=rtl] .select2-selection--multiple .select2-search--inline{float:right}.select2-container--default[dir=rtl] .select2-selection--multiple .select2-selection__choice{margin-left:5px;margin-right:auto}.select2-container--default[dir=rtl] .select2-selection--multiple .select2-selection__choice__remove{margin-left:2px;margin-right:auto}.select2-container--default.select2-container--focus .select2-selection--multiple{border:solid black 1px;outline:0}.select2-container--default.select2-container--disabled .select2-selection--multiple{background-color:#eee;cursor:default}.select2-container--default.select2-container--disabled .select2-selection__choice__remove{display:none}.select2-container--default.select2-container--open.select2-container--above .select2-selection--single,.select2-container--default.select2-container--open.select2-container--above .select2-selection--multiple{border-top-left-radius:0;border-top-right-radius:0}.select2-container--default.select2-container--open.select2-container--below .select2-selection--single,.select2-container--default.select2-container--open.select2-container--below .select2-selection--multiple{border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--default .select2-search--dropdown .select2-search__field{border:1px solid #aaa}.select2-container--default .select2-search--inline .select2-search__field{background:transparent;border:none;outline:0;box-shadow:none;-webkit-appearance:textfield}.select2-container--default .select2-results>.select2-results__options{max-height:200px;overflow-y:auto}.select2-container--default .select2-results__option[role=group]{padding:0}.select2-container--default .select2-results__option[aria-disabled=true]{color:#999}.select2-container--default .select2-results__option[aria-selected=true]{background-color:#ddd}.select2-container--default .select2-results__option .select2-results__option{padding-left:1em}.select2-container--default .select2-results__option .select2-results__option .select2-results__group{padding-left:0}.select2-container--default .select2-results__option .select2-results__option .select2-results__option{margin-left:-1em;padding-left:2em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-2em;padding-left:3em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-3em;padding-left:4em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-4em;padding-left:5em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-5em;padding-left:6em}.select2-container--default .select2-results__option--highlighted[aria-selected]{background-color:#5897fb;color:white}.select2-container--default .select2-results__group{cursor:default;display:block;padding:6px}.select2-container--classic .select2-selection--single{background-color:#f7f7f7;border:1px solid #aaa;border-radius:4px;outline:0;background-image:-webkit-linear-gradient(top, white 50%, #eeeeee 100%);background-image:-o-linear-gradient(top, white 50%, #eeeeee 100%);background-image:linear-gradient(to bottom, white 50%, #eeeeee 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#FFFFFFFF", endColorstr="#FFEEEEEE", GradientType=0)}.select2-container--classic .select2-selection--single:focus{border:1px solid #5897fb}.select2-container--classic .select2-selection--single .select2-selection__rendered{color:#444;line-height:28px}.select2-container--classic .select2-selection--single .select2-selection__clear{cursor:pointer;float:right;font-weight:bold;margin-right:10px}.select2-container--classic .select2-selection--single .select2-selection__placeholder{color:#999}.select2-container--classic .select2-selection--single .select2-selection__arrow{background-color:#ddd;border:none;border-left:1px solid #aaa;border-top-right-radius:4px;border-bottom-right-radius:4px;height:26px;position:absolute;top:1px;right:1px;width:20px;background-image:-webkit-linear-gradient(top, #eeeeee 50%, #cccccc 100%);background-image:-o-linear-gradient(top, #eeeeee 50%, #cccccc 100%);background-image:linear-gradient(to bottom, #eeeeee 50%, #cccccc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#FFEEEEEE", endColorstr="#FFCCCCCC", GradientType=0)}.select2-container--classic .select2-selection--single .select2-selection__arrow b{border-color:#888 transparent transparent transparent;border-style:solid;border-width:5px 4px 0 4px;height:0;left:50%;margin-left:-4px;margin-top:-2px;position:absolute;top:50%;width:0}.select2-container--classic[dir=rtl] .select2-selection--single .select2-selection__clear{float:left}.select2-container--classic[dir=rtl] .select2-selection--single .select2-selection__arrow{border:none;border-right:1px solid #aaa;border-radius:0;border-top-left-radius:4px;border-bottom-left-radius:4px;left:1px;right:auto}.select2-container--classic.select2-container--open .select2-selection--single{border:1px solid #5897fb}.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow{background:transparent;border:none}.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow b{border-color:transparent transparent #888 transparent;border-width:0 4px 5px 4px}.select2-container--classic.select2-container--open.select2-container--above .select2-selection--single{border-top:none;border-top-left-radius:0;border-top-right-radius:0;background-image:-webkit-linear-gradient(top, white 0%, #eeeeee 50%);background-image:-o-linear-gradient(top, white 0%, #eeeeee 50%);background-image:linear-gradient(to bottom, white 0%, #eeeeee 50%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#FFFFFFFF", endColorstr="#FFEEEEEE", GradientType=0)}.select2-container--classic.select2-container--open.select2-container--below .select2-selection--single{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0;background-image:-webkit-linear-gradient(top, #eeeeee 50%, white 100%);background-image:-o-linear-gradient(top, #eeeeee 50%, white 100%);background-image:linear-gradient(to bottom, #eeeeee 50%, white 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#FFEEEEEE", endColorstr="#FFFFFFFF", GradientType=0)}.select2-container--classic .select2-selection--multiple{background-color:white;border:1px solid #aaa;border-radius:4px;cursor:text;outline:0}.select2-container--classic .select2-selection--multiple:focus{border:1px solid #5897fb}.select2-container--classic .select2-selection--multiple .select2-selection__rendered{list-style:none;margin:0;padding:0 5px}.select2-container--classic .select2-selection--multiple .select2-selection__clear{display:none}.select2-container--classic .select2-selection--multiple .select2-selection__choice{background-color:#e4e4e4;border:1px solid #aaa;border-radius:4px;cursor:default;float:left;margin-right:5px;margin-top:5px;padding:0 5px}.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove{color:#888;cursor:pointer;display:inline-block;font-weight:bold;margin-right:2px}.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove:hover{color:#555}.select2-container--classic[dir=rtl] .select2-selection--multiple .select2-selection__choice{float:right;margin-left:5px;margin-right:auto}.select2-container--classic[dir=rtl] .select2-selection--multiple .select2-selection__choice__remove{margin-left:2px;margin-right:auto}.select2-container--classic.select2-container--open .select2-selection--multiple{border:1px solid #5897fb}.select2-container--classic.select2-container--open.select2-container--above .select2-selection--multiple{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.select2-container--classic.select2-container--open.select2-container--below .select2-selection--multiple{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--classic .select2-search--dropdown .select2-search__field{border:1px solid #aaa;outline:0}.select2-container--classic .select2-search--inline .select2-search__field{outline:0;box-shadow:none}.select2-container--classic .select2-dropdown{background-color:white;border:1px solid transparent}.select2-container--classic .select2-dropdown--above{border-bottom:none}.select2-container--classic .select2-dropdown--below{border-top:none}.select2-container--classic .select2-results>.select2-results__options{max-height:200px;overflow-y:auto}.select2-container--classic .select2-results__option[role=group]{padding:0}.select2-container--classic .select2-results__option[aria-disabled=true]{color:grey}.select2-container--classic .select2-results__option--highlighted[aria-selected]{background-color:#3875d7;color:white}.select2-container--classic .select2-results__group{cursor:default;display:block;padding:6px}.select2-container--classic.select2-container--open .select2-dropdown{border-color:#5897fb}.structFilter{min-height:20px;padding:6px;display:flex;align-items:center;margin-bottom:10px;background-color:#fff;border-radius:4px;border:1px solid var(--secondaryColorDarker)}.structFilter .evo-searchFilters a{height:38px;display:inline-flex;align-items:center;color:#333;padding:0 8px}.structFilter .evo-searchFilters a>div{display:inline-flex;height:25px}.structFilter .evo-searchFilters a>div>span{background-color:#ececef;color:#737278;border-radius:2px;margin-right:1px;padding:0 6px;font-size:13px;display:inline-flex;align-items:center}.evo-bNew{display:inline-flex;height:38px;align-items:center;justify-content:center;padding:0 8px}.evo-bNew>i{margin-right:5px}.evo-bAdd{display:inline-flex;height:38px;align-items:center;justify-content:center;padding:0 8px}.evo-bDel{display:inline-flex;height:38px;align-items:center;justify-content:center;padding:0 8px}.evo-bSubmit{display:inline-flex;height:38px;align-items:center;justify-content:center;padding:0 8px}.evo-lBold{font-weight:bold}.evo-lLight{font-weight:normal}.evo-editFilter{display:inline-flex;align-items:center;height:38px}.evo-editFilter:after{clear:left}.evo-editFilter select{font-size:1.1em}.evo-editFilter input{font-size:1.1em}.evo-editFilter span#value{margin-right:5px}.evo-editFilter #value{display:flex;flex-direction:column}.evo-editFilter #value label{width:220px;margin-right:0;background-color:#fff;z-index:1;border-left:1px solid var(--secondaryColorDarker);border-right:1px solid var(--secondaryColorDarker)}.evo-editFilter #value label:last-child{border-bottom:1px solid var(--secondaryColorDarker)}.evo-editFilter #value input[type=radio]{margin-left:5px}.evo-editFilter input[type=number]#value{width:6em}.evo-editFilter input[type=time]#value{width:6em}.evo-editFilter input[type=time]#value2{width:6em}.evo-editFilter input.hasDatepicker{width:8em}.evo-editFilter>*{border:none}.evo-editFilter>input{padding:6px 12px;font-size:14px;line-height:1.42857143;color:#555;border-top:1px solid var(--secondaryColorDarker);border-bottom:1px solid var(--secondaryColorDarker);height:32px}.evo-editFilter>select{padding:0 9px;font-size:14px;color:#555;border-top:1px solid var(--secondaryColorDarker);border-bottom:1px solid var(--secondaryColorDarker);height:32px;background-color:#fff}.evo-editFilter>select:focus-visible{outline:none}.evo-editFilter>span{display:inline-flex;align-items:center;height:32px;background-color:#fff;border-top:1px solid var(--secondaryColorDarker);border-bottom:1px solid var(--secondaryColorDarker)}.evo-editFilter>span>label{margin-right:10px;white-space:nowrap}.evo-editFilter>span>label>input[type=checkbox]{margin:0 5px}.evo-editFilter>*:not([type=hidden]):last-child{border-right:1px solid var(--secondaryColorDarker);border-top-right-radius:4px;border-bottom-right-radius:4px}.evo-editFilter>input[id=delimiter]{width:80px;border-left:1px solid var(--secondaryColorDarker)}.evo-editFilter>*:first-child{border-left:1px solid var(--secondaryColorDarker);border-top-left-radius:4px;border-bottom-left-radius:4px}.evo-editFilter .as-Txt{display:inline-flex;align-items:center;border-top:1px solid var(--secondaryColorDarker);border-bottom:1px solid var(--secondaryColorDarker);height:32px;background-color:#fff} diff --git a/dist/admin/fonts/275dd55e10ba966bcb9b.ttf b/dist/admin/fonts/275dd55e10ba966bcb9b.ttf deleted file mode 100644 index 886134d..0000000 Binary files a/dist/admin/fonts/275dd55e10ba966bcb9b.ttf and /dev/null differ diff --git a/dist/admin/fonts/7c8d04cd831df3033c8a.ttf b/dist/admin/fonts/7c8d04cd831df3033c8a.ttf deleted file mode 100644 index ac0f908..0000000 Binary files a/dist/admin/fonts/7c8d04cd831df3033c8a.ttf and /dev/null differ diff --git a/dist/admin/fonts/9a42f2741ca78a25feaa.ttf b/dist/admin/fonts/9a42f2741ca78a25feaa.ttf deleted file mode 100644 index 7866278..0000000 Binary files a/dist/admin/fonts/9a42f2741ca78a25feaa.ttf and /dev/null differ diff --git a/dist/admin/fonts/9d7a6e03c6e3ed49c7ac.ttf b/dist/admin/fonts/9d7a6e03c6e3ed49c7ac.ttf deleted file mode 100644 index 9411bfb..0000000 Binary files a/dist/admin/fonts/9d7a6e03c6e3ed49c7ac.ttf and /dev/null differ diff --git a/dist/admin/fonts/9fb9e3d1e42a353d678c.woff2 b/dist/admin/fonts/9fb9e3d1e42a353d678c.woff2 deleted file mode 100644 index 9502c7c..0000000 Binary files a/dist/admin/fonts/9fb9e3d1e42a353d678c.woff2 and /dev/null differ diff --git a/dist/admin/fonts/b65ac3b8da9f6efd3346.ttf b/dist/admin/fonts/b65ac3b8da9f6efd3346.ttf deleted file mode 100644 index ba94f57..0000000 Binary files a/dist/admin/fonts/b65ac3b8da9f6efd3346.ttf and /dev/null differ diff --git a/dist/admin/fonts/cf56c1b149d0a5e8d7c6.ttf b/dist/admin/fonts/cf56c1b149d0a5e8d7c6.ttf deleted file mode 100644 index 0112e7d..0000000 Binary files a/dist/admin/fonts/cf56c1b149d0a5e8d7c6.ttf and /dev/null differ diff --git a/dist/admin/fonts/e6f4e254e8b705435dd6.woff2 b/dist/admin/fonts/e6f4e254e8b705435dd6.woff2 deleted file mode 100644 index 0c2ce0b..0000000 Binary files a/dist/admin/fonts/e6f4e254e8b705435dd6.woff2 and /dev/null differ diff --git a/dist/admin/fonts/fc2b5060f7accec5cf74.ttf b/dist/admin/fonts/fc2b5060f7accec5cf74.ttf deleted file mode 100644 index ddf4bfa..0000000 Binary files a/dist/admin/fonts/fc2b5060f7accec5cf74.ttf and /dev/null differ diff --git a/dist/admin/js/admin.js b/dist/admin/js/admin.js deleted file mode 100644 index 07ba658..0000000 --- a/dist/admin/js/admin.js +++ /dev/null @@ -1 +0,0 @@ -(()=>{var __webpack_modules__={976:(__unused_webpack_module,__unused_webpack_exports,__webpack_require__)=>{eval('/* provided dependency */ var jQuery = __webpack_require__(796);\n/**\n * menu-aim is a jQuery plugin for dropdown menus that can differentiate\n * between a user trying hover over a dropdown item vs trying to navigate into\n * a submenu\'s contents.\n *\n * menu-aim assumes that you have are using a menu with submenus that expand\n * to the menu\'s right. It will fire events when the user\'s mouse enters a new\n * dropdown item *and* when that item is being intentionally hovered over.\n *\n * __________________________\n * | Monkeys >| Gorilla |\n * | Gorillas >| Content |\n * | Chimps >| Here |\n * |___________|____________|\n *\n * In the above example, "Gorillas" is selected and its submenu content is\n * being shown on the right. Imagine that the user\'s cursor is hovering over\n * "Gorillas." When they move their mouse into the "Gorilla Content" area, they\n * may briefly hover over "Chimps." This shouldn\'t close the "Gorilla Content"\n * area.\n *\n * This problem is normally solved using timeouts and delays. menu-aim tries to\n * solve this by detecting the direction of the user\'s mouse movement. This can\n * make for quicker transitions when navigating up and down the menu. The\n * experience is hopefully similar to amazon.com/\'s "Shop by Department"\n * dropdown.\n *\n * Use like so:\n *\n * $("#menu").menuAim({\n * activate: $.noop, // fired on row activation\n * deactivate: $.noop // fired on row deactivation\n * });\n *\n * ...to receive events when a menu\'s row has been purposefully (de)activated.\n *\n * The following options can be passed to menuAim. All functions execute with\n * the relevant row\'s HTML element as the execution context (\'this\'):\n *\n * .menuAim({\n * // Function to call when a row is purposefully activated. Use this\n * // to show a submenu\'s content for the activated row.\n * activate: function() {},\n *\n * // Function to call when a row is deactivated.\n * deactivate: function() {},\n *\n * // Function to call when mouse enters a menu row. Entering a row\n * // does not mean the row has been activated, as the user may be\n * // mousing over to a submenu.\n * enter: function() {},\n *\n * // Function to call when mouse exits a menu row.\n * exit: function() {},\n *\n * // Selector for identifying which elements in the menu are rows\n * // that can trigger the above events. Defaults to "> li".\n * rowSelector: "> li",\n *\n * // You may have some menu rows that aren\'t submenus and therefore\n * // shouldn\'t ever need to "activate." If so, filter submenu rows w/\n * // this selector. Defaults to "*" (all elements).\n * submenuSelector: "*",\n *\n * // Direction the submenu opens relative to the main menu. Can be\n * // left, right, above, or below. Defaults to "right".\n * submenuDirection: "right"\n * });\n *\n * https://github.com/kamens/jQuery-menu-aim\n*/\n(function($) {\n\n $.fn.menuAim = function(opts) {\n // Initialize menu-aim for all elements in jQuery collection\n this.each(function() {\n init.call(this, opts);\n });\n\n return this;\n };\n\n function init(opts) {\n var $menu = $(this),\n activeRow = null,\n mouseLocs = [],\n lastDelayLoc = null,\n timeoutId = null,\n options = $.extend({\n rowSelector: "> li",\n submenuSelector: "*",\n submenuDirection: "right",\n tolerance: 75, // bigger = more forgivey when entering submenu\n enter: $.noop,\n exit: $.noop,\n activate: $.noop,\n deactivate: $.noop,\n exitMenu: $.noop\n }, opts);\n\n var MOUSE_LOCS_TRACKED = 3, // number of past mouse locations to track\n DELAY = 300; // ms delay when user appears to be entering submenu\n\n /**\n * Keep track of the last few locations of the mouse.\n */\n var mousemoveDocument = function(e) {\n mouseLocs.push({x: e.pageX, y: e.pageY});\n\n if (mouseLocs.length > MOUSE_LOCS_TRACKED) {\n mouseLocs.shift();\n }\n };\n\n /**\n * Cancel possible row activations when leaving the menu entirely\n */\n var mouseleaveMenu = function() {\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n\n // If exitMenu is supplied and returns true, deactivate the\n // currently active row on menu exit.\n if (options.exitMenu(this)) {\n if (activeRow) {\n options.deactivate(activeRow);\n }\n\n activeRow = null;\n }\n };\n\n /**\n * Trigger a possible row activation whenever entering a new row.\n */\n var mouseenterRow = function() {\n if (timeoutId) {\n // Cancel any previous activation delays\n clearTimeout(timeoutId);\n }\n\n options.enter(this);\n possiblyActivate(this);\n },\n mouseleaveRow = function() {\n options.exit(this);\n };\n\n /*\n * Immediately activate a row if the user clicks on it.\n */\n var clickRow = function() {\n activate(this);\n };\n\n /**\n * Activate a menu row.\n */\n var activate = function(row) {\n if (row == activeRow) {\n return;\n }\n\n if (activeRow) {\n options.deactivate(activeRow);\n }\n\n options.activate(row);\n activeRow = row;\n };\n\n /**\n * Possibly activate a menu row. If mouse movement indicates that we\n * shouldn\'t activate yet because user may be trying to enter\n * a submenu\'s content, then delay and check again later.\n */\n var possiblyActivate = function(row) {\n var delay = activationDelay();\n\n if (delay) {\n timeoutId = setTimeout(function() {\n possiblyActivate(row);\n }, delay);\n } else {\n activate(row);\n }\n };\n\n /**\n * Return the amount of time that should be used as a delay before the\n * currently hovered row is activated.\n *\n * Returns 0 if the activation should happen immediately. Otherwise,\n * returns the number of milliseconds that should be delayed before\n * checking again to see if the row should be activated.\n */\n var activationDelay = function() {\n if (!activeRow || !$(activeRow).is(options.submenuSelector)) {\n // If there is no other submenu row already active, then\n // go ahead and activate immediately.\n return 0;\n }\n\n var offset = $menu.offset(),\n upperLeft = {\n x: offset.left,\n y: offset.top - options.tolerance\n },\n upperRight = {\n x: offset.left + $menu.outerWidth(),\n y: upperLeft.y\n },\n lowerLeft = {\n x: offset.left,\n y: offset.top + $menu.outerHeight() + options.tolerance\n },\n lowerRight = {\n x: offset.left + $menu.outerWidth(),\n y: lowerLeft.y\n },\n loc = mouseLocs[mouseLocs.length - 1],\n prevLoc = mouseLocs[0];\n\n if (!loc) {\n return 0;\n }\n\n if (!prevLoc) {\n prevLoc = loc;\n }\n\n if (prevLoc.x < offset.left || prevLoc.x > lowerRight.x ||\n prevLoc.y < offset.top || prevLoc.y > lowerRight.y) {\n // If the previous mouse location was outside of the entire\n // menu\'s bounds, immediately activate.\n return 0;\n }\n\n if (lastDelayLoc &&\n loc.x == lastDelayLoc.x && loc.y == lastDelayLoc.y) {\n // If the mouse hasn\'t moved since the last time we checked\n // for activation status, immediately activate.\n return 0;\n }\n\n // Detect if the user is moving towards the currently activated\n // submenu.\n //\n // If the mouse is heading relatively clearly towards\n // the submenu\'s content, we should wait and give the user more\n // time before activating a new row. If the mouse is heading\n // elsewhere, we can immediately activate a new row.\n //\n // We detect this by calculating the slope formed between the\n // current mouse location and the upper/lower right points of\n // the menu. We do the same for the previous mouse location.\n // If the current mouse location\'s slopes are\n // increasing/decreasing appropriately compared to the\n // previous\'s, we know the user is moving toward the submenu.\n //\n // Note that since the y-axis increases as the cursor moves\n // down the screen, we are looking for the slope between the\n // cursor and the upper right corner to decrease over time, not\n // increase (somewhat counterintuitively).\n function slope(a, b) {\n return (b.y - a.y) / (b.x - a.x);\n };\n\n var decreasingCorner = upperRight,\n increasingCorner = lowerRight;\n\n // Our expectations for decreasing or increasing slope values\n // depends on which direction the submenu opens relative to the\n // main menu. By default, if the menu opens on the right, we\n // expect the slope between the cursor and the upper right\n // corner to decrease over time, as explained above. If the\n // submenu opens in a different direction, we change our slope\n // expectations.\n if (options.submenuDirection == "left") {\n decreasingCorner = lowerLeft;\n increasingCorner = upperLeft;\n } else if (options.submenuDirection == "below") {\n decreasingCorner = lowerRight;\n increasingCorner = lowerLeft;\n } else if (options.submenuDirection == "above") {\n decreasingCorner = upperLeft;\n increasingCorner = upperRight;\n }\n\n var decreasingSlope = slope(loc, decreasingCorner),\n increasingSlope = slope(loc, increasingCorner),\n prevDecreasingSlope = slope(prevLoc, decreasingCorner),\n prevIncreasingSlope = slope(prevLoc, increasingCorner);\n\n if (decreasingSlope < prevDecreasingSlope &&\n increasingSlope > prevIncreasingSlope) {\n // Mouse is moving from previous location towards the\n // currently activated submenu. Delay before activating a\n // new menu row, because user may be moving into submenu.\n lastDelayLoc = loc;\n return DELAY;\n }\n\n lastDelayLoc = null;\n return 0;\n };\n\n /**\n * Hook up initial menu events\n */\n $menu\n .mouseleave(mouseleaveMenu)\n .find(options.rowSelector)\n .mouseenter(mouseenterRow)\n .mouseleave(mouseleaveRow)\n .click(clickRow);\n\n $(document).mousemove(mousemoveDocument);\n\n };\n})(jQuery);\n\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiOTc2LmpzIiwibWFwcGluZ3MiOiI7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vLy4vbm9kZV9tb2R1bGVzL0ByZWdydS9qcXVlcnktbWVudS1haW0vanF1ZXJ5Lm1lbnUtYWltLmpzP2I0OGQiXSwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBtZW51LWFpbSBpcyBhIGpRdWVyeSBwbHVnaW4gZm9yIGRyb3Bkb3duIG1lbnVzIHRoYXQgY2FuIGRpZmZlcmVudGlhdGVcbiAqIGJldHdlZW4gYSB1c2VyIHRyeWluZyBob3ZlciBvdmVyIGEgZHJvcGRvd24gaXRlbSB2cyB0cnlpbmcgdG8gbmF2aWdhdGUgaW50b1xuICogYSBzdWJtZW51J3MgY29udGVudHMuXG4gKlxuICogbWVudS1haW0gYXNzdW1lcyB0aGF0IHlvdSBoYXZlIGFyZSB1c2luZyBhIG1lbnUgd2l0aCBzdWJtZW51cyB0aGF0IGV4cGFuZFxuICogdG8gdGhlIG1lbnUncyByaWdodC4gSXQgd2lsbCBmaXJlIGV2ZW50cyB3aGVuIHRoZSB1c2VyJ3MgbW91c2UgZW50ZXJzIGEgbmV3XG4gKiBkcm9wZG93biBpdGVtICphbmQqIHdoZW4gdGhhdCBpdGVtIGlzIGJlaW5nIGludGVudGlvbmFsbHkgaG92ZXJlZCBvdmVyLlxuICpcbiAqIF9fX19fX19fX19fX19fX19fX19fX19fX19fXG4gKiB8IE1vbmtleXMgID58ICAgR29yaWxsYSAgfFxuICogfCBHb3JpbGxhcyA+fCAgIENvbnRlbnQgIHxcbiAqIHwgQ2hpbXBzICAgPnwgICBIZXJlICAgICB8XG4gKiB8X19fX19fX19fX198X19fX19fX19fX19ffFxuICpcbiAqIEluIHRoZSBhYm92ZSBleGFtcGxlLCBcIkdvcmlsbGFzXCIgaXMgc2VsZWN0ZWQgYW5kIGl0cyBzdWJtZW51IGNvbnRlbnQgaXNcbiAqIGJlaW5nIHNob3duIG9uIHRoZSByaWdodC4gSW1hZ2luZSB0aGF0IHRoZSB1c2VyJ3MgY3Vyc29yIGlzIGhvdmVyaW5nIG92ZXJcbiAqIFwiR29yaWxsYXMuXCIgV2hlbiB0aGV5IG1vdmUgdGhlaXIgbW91c2UgaW50byB0aGUgXCJHb3JpbGxhIENvbnRlbnRcIiBhcmVhLCB0aGV5XG4gKiBtYXkgYnJpZWZseSBob3ZlciBvdmVyIFwiQ2hpbXBzLlwiIFRoaXMgc2hvdWxkbid0IGNsb3NlIHRoZSBcIkdvcmlsbGEgQ29udGVudFwiXG4gKiBhcmVhLlxuICpcbiAqIFRoaXMgcHJvYmxlbSBpcyBub3JtYWxseSBzb2x2ZWQgdXNpbmcgdGltZW91dHMgYW5kIGRlbGF5cy4gbWVudS1haW0gdHJpZXMgdG9cbiAqIHNvbHZlIHRoaXMgYnkgZGV0ZWN0aW5nIHRoZSBkaXJlY3Rpb24gb2YgdGhlIHVzZXIncyBtb3VzZSBtb3ZlbWVudC4gVGhpcyBjYW5cbiAqIG1ha2UgZm9yIHF1aWNrZXIgdHJhbnNpdGlvbnMgd2hlbiBuYXZpZ2F0aW5nIHVwIGFuZCBkb3duIHRoZSBtZW51LiBUaGVcbiAqIGV4cGVyaWVuY2UgaXMgaG9wZWZ1bGx5IHNpbWlsYXIgdG8gYW1hem9uLmNvbS8ncyBcIlNob3AgYnkgRGVwYXJ0bWVudFwiXG4gKiBkcm9wZG93bi5cbiAqXG4gKiBVc2UgbGlrZSBzbzpcbiAqXG4gKiAgICAgICQoXCIjbWVudVwiKS5tZW51QWltKHtcbiAqICAgICAgICAgIGFjdGl2YXRlOiAkLm5vb3AsICAvLyBmaXJlZCBvbiByb3cgYWN0aXZhdGlvblxuICogICAgICAgICAgZGVhY3RpdmF0ZTogJC5ub29wICAvLyBmaXJlZCBvbiByb3cgZGVhY3RpdmF0aW9uXG4gKiAgICAgIH0pO1xuICpcbiAqICAuLi50byByZWNlaXZlIGV2ZW50cyB3aGVuIGEgbWVudSdzIHJvdyBoYXMgYmVlbiBwdXJwb3NlZnVsbHkgKGRlKWFjdGl2YXRlZC5cbiAqXG4gKiBUaGUgZm9sbG93aW5nIG9wdGlvbnMgY2FuIGJlIHBhc3NlZCB0byBtZW51QWltLiBBbGwgZnVuY3Rpb25zIGV4ZWN1dGUgd2l0aFxuICogdGhlIHJlbGV2YW50IHJvdydzIEhUTUwgZWxlbWVudCBhcyB0aGUgZXhlY3V0aW9uIGNvbnRleHQgKCd0aGlzJyk6XG4gKlxuICogICAgICAubWVudUFpbSh7XG4gKiAgICAgICAgICAvLyBGdW5jdGlvbiB0byBjYWxsIHdoZW4gYSByb3cgaXMgcHVycG9zZWZ1bGx5IGFjdGl2YXRlZC4gVXNlIHRoaXNcbiAqICAgICAgICAgIC8vIHRvIHNob3cgYSBzdWJtZW51J3MgY29udGVudCBmb3IgdGhlIGFjdGl2YXRlZCByb3cuXG4gKiAgICAgICAgICBhY3RpdmF0ZTogZnVuY3Rpb24oKSB7fSxcbiAqXG4gKiAgICAgICAgICAvLyBGdW5jdGlvbiB0byBjYWxsIHdoZW4gYSByb3cgaXMgZGVhY3RpdmF0ZWQuXG4gKiAgICAgICAgICBkZWFjdGl2YXRlOiBmdW5jdGlvbigpIHt9LFxuICpcbiAqICAgICAgICAgIC8vIEZ1bmN0aW9uIHRvIGNhbGwgd2hlbiBtb3VzZSBlbnRlcnMgYSBtZW51IHJvdy4gRW50ZXJpbmcgYSByb3dcbiAqICAgICAgICAgIC8vIGRvZXMgbm90IG1lYW4gdGhlIHJvdyBoYXMgYmVlbiBhY3RpdmF0ZWQsIGFzIHRoZSB1c2VyIG1heSBiZVxuICogICAgICAgICAgLy8gbW91c2luZyBvdmVyIHRvIGEgc3VibWVudS5cbiAqICAgICAgICAgIGVudGVyOiBmdW5jdGlvbigpIHt9LFxuICpcbiAqICAgICAgICAgIC8vIEZ1bmN0aW9uIHRvIGNhbGwgd2hlbiBtb3VzZSBleGl0cyBhIG1lbnUgcm93LlxuICogICAgICAgICAgZXhpdDogZnVuY3Rpb24oKSB7fSxcbiAqXG4gKiAgICAgICAgICAvLyBTZWxlY3RvciBmb3IgaWRlbnRpZnlpbmcgd2hpY2ggZWxlbWVudHMgaW4gdGhlIG1lbnUgYXJlIHJvd3NcbiAqICAgICAgICAgIC8vIHRoYXQgY2FuIHRyaWdnZXIgdGhlIGFib3ZlIGV2ZW50cy4gRGVmYXVsdHMgdG8gXCI+IGxpXCIuXG4gKiAgICAgICAgICByb3dTZWxlY3RvcjogXCI+IGxpXCIsXG4gKlxuICogICAgICAgICAgLy8gWW91IG1heSBoYXZlIHNvbWUgbWVudSByb3dzIHRoYXQgYXJlbid0IHN1Ym1lbnVzIGFuZCB0aGVyZWZvcmVcbiAqICAgICAgICAgIC8vIHNob3VsZG4ndCBldmVyIG5lZWQgdG8gXCJhY3RpdmF0ZS5cIiBJZiBzbywgZmlsdGVyIHN1Ym1lbnUgcm93cyB3L1xuICogICAgICAgICAgLy8gdGhpcyBzZWxlY3Rvci4gRGVmYXVsdHMgdG8gXCIqXCIgKGFsbCBlbGVtZW50cykuXG4gKiAgICAgICAgICBzdWJtZW51U2VsZWN0b3I6IFwiKlwiLFxuICpcbiAqICAgICAgICAgIC8vIERpcmVjdGlvbiB0aGUgc3VibWVudSBvcGVucyByZWxhdGl2ZSB0byB0aGUgbWFpbiBtZW51LiBDYW4gYmVcbiAqICAgICAgICAgIC8vIGxlZnQsIHJpZ2h0LCBhYm92ZSwgb3IgYmVsb3cuIERlZmF1bHRzIHRvIFwicmlnaHRcIi5cbiAqICAgICAgICAgIHN1Ym1lbnVEaXJlY3Rpb246IFwicmlnaHRcIlxuICogICAgICB9KTtcbiAqXG4gKiBodHRwczovL2dpdGh1Yi5jb20va2FtZW5zL2pRdWVyeS1tZW51LWFpbVxuKi9cbihmdW5jdGlvbigkKSB7XG5cbiAgICAkLmZuLm1lbnVBaW0gPSBmdW5jdGlvbihvcHRzKSB7XG4gICAgICAgIC8vIEluaXRpYWxpemUgbWVudS1haW0gZm9yIGFsbCBlbGVtZW50cyBpbiBqUXVlcnkgY29sbGVjdGlvblxuICAgICAgICB0aGlzLmVhY2goZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICBpbml0LmNhbGwodGhpcywgb3B0cyk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH07XG5cbiAgICBmdW5jdGlvbiBpbml0KG9wdHMpIHtcbiAgICAgICAgdmFyICRtZW51ID0gJCh0aGlzKSxcbiAgICAgICAgICAgIGFjdGl2ZVJvdyA9IG51bGwsXG4gICAgICAgICAgICBtb3VzZUxvY3MgPSBbXSxcbiAgICAgICAgICAgIGxhc3REZWxheUxvYyA9IG51bGwsXG4gICAgICAgICAgICB0aW1lb3V0SWQgPSBudWxsLFxuICAgICAgICAgICAgb3B0aW9ucyA9ICQuZXh0ZW5kKHtcbiAgICAgICAgICAgICAgICByb3dTZWxlY3RvcjogXCI+IGxpXCIsXG4gICAgICAgICAgICAgICAgc3VibWVudVNlbGVjdG9yOiBcIipcIixcbiAgICAgICAgICAgICAgICBzdWJtZW51RGlyZWN0aW9uOiBcInJpZ2h0XCIsXG4gICAgICAgICAgICAgICAgdG9sZXJhbmNlOiA3NSwgIC8vIGJpZ2dlciA9IG1vcmUgZm9yZ2l2ZXkgd2hlbiBlbnRlcmluZyBzdWJtZW51XG4gICAgICAgICAgICAgICAgZW50ZXI6ICQubm9vcCxcbiAgICAgICAgICAgICAgICBleGl0OiAkLm5vb3AsXG4gICAgICAgICAgICAgICAgYWN0aXZhdGU6ICQubm9vcCxcbiAgICAgICAgICAgICAgICBkZWFjdGl2YXRlOiAkLm5vb3AsXG4gICAgICAgICAgICAgICAgZXhpdE1lbnU6ICQubm9vcFxuICAgICAgICAgICAgfSwgb3B0cyk7XG5cbiAgICAgICAgdmFyIE1PVVNFX0xPQ1NfVFJBQ0tFRCA9IDMsICAvLyBudW1iZXIgb2YgcGFzdCBtb3VzZSBsb2NhdGlvbnMgdG8gdHJhY2tcbiAgICAgICAgICAgIERFTEFZID0gMzAwOyAgLy8gbXMgZGVsYXkgd2hlbiB1c2VyIGFwcGVhcnMgdG8gYmUgZW50ZXJpbmcgc3VibWVudVxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBLZWVwIHRyYWNrIG9mIHRoZSBsYXN0IGZldyBsb2NhdGlvbnMgb2YgdGhlIG1vdXNlLlxuICAgICAgICAgKi9cbiAgICAgICAgdmFyIG1vdXNlbW92ZURvY3VtZW50ID0gZnVuY3Rpb24oZSkge1xuICAgICAgICAgICAgICAgIG1vdXNlTG9jcy5wdXNoKHt4OiBlLnBhZ2VYLCB5OiBlLnBhZ2VZfSk7XG5cbiAgICAgICAgICAgICAgICBpZiAobW91c2VMb2NzLmxlbmd0aCA+IE1PVVNFX0xPQ1NfVFJBQ0tFRCkge1xuICAgICAgICAgICAgICAgICAgICBtb3VzZUxvY3Muc2hpZnQoKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9O1xuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDYW5jZWwgcG9zc2libGUgcm93IGFjdGl2YXRpb25zIHdoZW4gbGVhdmluZyB0aGUgbWVudSBlbnRpcmVseVxuICAgICAgICAgKi9cbiAgICAgICAgdmFyIG1vdXNlbGVhdmVNZW51ID0gZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICAgICAgaWYgKHRpbWVvdXRJZCkge1xuICAgICAgICAgICAgICAgICAgICBjbGVhclRpbWVvdXQodGltZW91dElkKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAvLyBJZiBleGl0TWVudSBpcyBzdXBwbGllZCBhbmQgcmV0dXJucyB0cnVlLCBkZWFjdGl2YXRlIHRoZVxuICAgICAgICAgICAgICAgIC8vIGN1cnJlbnRseSBhY3RpdmUgcm93IG9uIG1lbnUgZXhpdC5cbiAgICAgICAgICAgICAgICBpZiAob3B0aW9ucy5leGl0TWVudSh0aGlzKSkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoYWN0aXZlUm93KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBvcHRpb25zLmRlYWN0aXZhdGUoYWN0aXZlUm93KTtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIGFjdGl2ZVJvdyA9IG51bGw7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfTtcblxuICAgICAgICAvKipcbiAgICAgICAgICogVHJpZ2dlciBhIHBvc3NpYmxlIHJvdyBhY3RpdmF0aW9uIHdoZW5ldmVyIGVudGVyaW5nIGEgbmV3IHJvdy5cbiAgICAgICAgICovXG4gICAgICAgIHZhciBtb3VzZWVudGVyUm93ID0gZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICAgICAgaWYgKHRpbWVvdXRJZCkge1xuICAgICAgICAgICAgICAgICAgICAvLyBDYW5jZWwgYW55IHByZXZpb3VzIGFjdGl2YXRpb24gZGVsYXlzXG4gICAgICAgICAgICAgICAgICAgIGNsZWFyVGltZW91dCh0aW1lb3V0SWQpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIG9wdGlvbnMuZW50ZXIodGhpcyk7XG4gICAgICAgICAgICAgICAgcG9zc2libHlBY3RpdmF0ZSh0aGlzKTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBtb3VzZWxlYXZlUm93ID0gZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICAgICAgb3B0aW9ucy5leGl0KHRoaXMpO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAvKlxuICAgICAgICAgKiBJbW1lZGlhdGVseSBhY3RpdmF0ZSBhIHJvdyBpZiB0aGUgdXNlciBjbGlja3Mgb24gaXQuXG4gICAgICAgICAqL1xuICAgICAgICB2YXIgY2xpY2tSb3cgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgICAgICBhY3RpdmF0ZSh0aGlzKTtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEFjdGl2YXRlIGEgbWVudSByb3cuXG4gICAgICAgICAqL1xuICAgICAgICB2YXIgYWN0aXZhdGUgPSBmdW5jdGlvbihyb3cpIHtcbiAgICAgICAgICAgICAgICBpZiAocm93ID09IGFjdGl2ZVJvdykge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWYgKGFjdGl2ZVJvdykge1xuICAgICAgICAgICAgICAgICAgICBvcHRpb25zLmRlYWN0aXZhdGUoYWN0aXZlUm93KTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBvcHRpb25zLmFjdGl2YXRlKHJvdyk7XG4gICAgICAgICAgICAgICAgYWN0aXZlUm93ID0gcm93O1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAvKipcbiAgICAgICAgICogUG9zc2libHkgYWN0aXZhdGUgYSBtZW51IHJvdy4gSWYgbW91c2UgbW92ZW1lbnQgaW5kaWNhdGVzIHRoYXQgd2VcbiAgICAgICAgICogc2hvdWxkbid0IGFjdGl2YXRlIHlldCBiZWNhdXNlIHVzZXIgbWF5IGJlIHRyeWluZyB0byBlbnRlclxuICAgICAgICAgKiBhIHN1Ym1lbnUncyBjb250ZW50LCB0aGVuIGRlbGF5IGFuZCBjaGVjayBhZ2FpbiBsYXRlci5cbiAgICAgICAgICovXG4gICAgICAgIHZhciBwb3NzaWJseUFjdGl2YXRlID0gZnVuY3Rpb24ocm93KSB7XG4gICAgICAgICAgICAgICAgdmFyIGRlbGF5ID0gYWN0aXZhdGlvbkRlbGF5KCk7XG5cbiAgICAgICAgICAgICAgICBpZiAoZGVsYXkpIHtcbiAgICAgICAgICAgICAgICAgICAgdGltZW91dElkID0gc2V0VGltZW91dChmdW5jdGlvbigpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHBvc3NpYmx5QWN0aXZhdGUocm93KTtcbiAgICAgICAgICAgICAgICAgICAgfSwgZGVsYXkpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGFjdGl2YXRlKHJvdyk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfTtcblxuICAgICAgICAvKipcbiAgICAgICAgICogUmV0dXJuIHRoZSBhbW91bnQgb2YgdGltZSB0aGF0IHNob3VsZCBiZSB1c2VkIGFzIGEgZGVsYXkgYmVmb3JlIHRoZVxuICAgICAgICAgKiBjdXJyZW50bHkgaG92ZXJlZCByb3cgaXMgYWN0aXZhdGVkLlxuICAgICAgICAgKlxuICAgICAgICAgKiBSZXR1cm5zIDAgaWYgdGhlIGFjdGl2YXRpb24gc2hvdWxkIGhhcHBlbiBpbW1lZGlhdGVseS4gT3RoZXJ3aXNlLFxuICAgICAgICAgKiByZXR1cm5zIHRoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIHRoYXQgc2hvdWxkIGJlIGRlbGF5ZWQgYmVmb3JlXG4gICAgICAgICAqIGNoZWNraW5nIGFnYWluIHRvIHNlZSBpZiB0aGUgcm93IHNob3VsZCBiZSBhY3RpdmF0ZWQuXG4gICAgICAgICAqL1xuICAgICAgICB2YXIgYWN0aXZhdGlvbkRlbGF5ID0gZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICAgICAgaWYgKCFhY3RpdmVSb3cgfHwgISQoYWN0aXZlUm93KS5pcyhvcHRpb25zLnN1Ym1lbnVTZWxlY3RvcikpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gSWYgdGhlcmUgaXMgbm8gb3RoZXIgc3VibWVudSByb3cgYWxyZWFkeSBhY3RpdmUsIHRoZW5cbiAgICAgICAgICAgICAgICAgICAgLy8gZ28gYWhlYWQgYW5kIGFjdGl2YXRlIGltbWVkaWF0ZWx5LlxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gMDtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICB2YXIgb2Zmc2V0ID0gJG1lbnUub2Zmc2V0KCksXG4gICAgICAgICAgICAgICAgICAgIHVwcGVyTGVmdCA9IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHg6IG9mZnNldC5sZWZ0LFxuICAgICAgICAgICAgICAgICAgICAgICAgeTogb2Zmc2V0LnRvcCAtIG9wdGlvbnMudG9sZXJhbmNlXG4gICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgIHVwcGVyUmlnaHQgPSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB4OiBvZmZzZXQubGVmdCArICRtZW51Lm91dGVyV2lkdGgoKSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHk6IHVwcGVyTGVmdC55XG4gICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgIGxvd2VyTGVmdCA9IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHg6IG9mZnNldC5sZWZ0LFxuICAgICAgICAgICAgICAgICAgICAgICAgeTogb2Zmc2V0LnRvcCArICRtZW51Lm91dGVySGVpZ2h0KCkgKyBvcHRpb25zLnRvbGVyYW5jZVxuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICBsb3dlclJpZ2h0ID0ge1xuICAgICAgICAgICAgICAgICAgICAgICAgeDogb2Zmc2V0LmxlZnQgKyAkbWVudS5vdXRlcldpZHRoKCksXG4gICAgICAgICAgICAgICAgICAgICAgICB5OiBsb3dlckxlZnQueVxuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICBsb2MgPSBtb3VzZUxvY3NbbW91c2VMb2NzLmxlbmd0aCAtIDFdLFxuICAgICAgICAgICAgICAgICAgICBwcmV2TG9jID0gbW91c2VMb2NzWzBdO1xuXG4gICAgICAgICAgICAgICAgaWYgKCFsb2MpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIDA7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWYgKCFwcmV2TG9jKSB7XG4gICAgICAgICAgICAgICAgICAgIHByZXZMb2MgPSBsb2M7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWYgKHByZXZMb2MueCA8IG9mZnNldC5sZWZ0IHx8IHByZXZMb2MueCA+IGxvd2VyUmlnaHQueCB8fFxuICAgICAgICAgICAgICAgICAgICBwcmV2TG9jLnkgPCBvZmZzZXQudG9wIHx8IHByZXZMb2MueSA+IGxvd2VyUmlnaHQueSkge1xuICAgICAgICAgICAgICAgICAgICAvLyBJZiB0aGUgcHJldmlvdXMgbW91c2UgbG9jYXRpb24gd2FzIG91dHNpZGUgb2YgdGhlIGVudGlyZVxuICAgICAgICAgICAgICAgICAgICAvLyBtZW51J3MgYm91bmRzLCBpbW1lZGlhdGVseSBhY3RpdmF0ZS5cbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIDA7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWYgKGxhc3REZWxheUxvYyAmJlxuICAgICAgICAgICAgICAgICAgICAgICAgbG9jLnggPT0gbGFzdERlbGF5TG9jLnggJiYgbG9jLnkgPT0gbGFzdERlbGF5TG9jLnkpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gSWYgdGhlIG1vdXNlIGhhc24ndCBtb3ZlZCBzaW5jZSB0aGUgbGFzdCB0aW1lIHdlIGNoZWNrZWRcbiAgICAgICAgICAgICAgICAgICAgLy8gZm9yIGFjdGl2YXRpb24gc3RhdHVzLCBpbW1lZGlhdGVseSBhY3RpdmF0ZS5cbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIDA7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgLy8gRGV0ZWN0IGlmIHRoZSB1c2VyIGlzIG1vdmluZyB0b3dhcmRzIHRoZSBjdXJyZW50bHkgYWN0aXZhdGVkXG4gICAgICAgICAgICAgICAgLy8gc3VibWVudS5cbiAgICAgICAgICAgICAgICAvL1xuICAgICAgICAgICAgICAgIC8vIElmIHRoZSBtb3VzZSBpcyBoZWFkaW5nIHJlbGF0aXZlbHkgY2xlYXJseSB0b3dhcmRzXG4gICAgICAgICAgICAgICAgLy8gdGhlIHN1Ym1lbnUncyBjb250ZW50LCB3ZSBzaG91bGQgd2FpdCBhbmQgZ2l2ZSB0aGUgdXNlciBtb3JlXG4gICAgICAgICAgICAgICAgLy8gdGltZSBiZWZvcmUgYWN0aXZhdGluZyBhIG5ldyByb3cuIElmIHRoZSBtb3VzZSBpcyBoZWFkaW5nXG4gICAgICAgICAgICAgICAgLy8gZWxzZXdoZXJlLCB3ZSBjYW4gaW1tZWRpYXRlbHkgYWN0aXZhdGUgYSBuZXcgcm93LlxuICAgICAgICAgICAgICAgIC8vXG4gICAgICAgICAgICAgICAgLy8gV2UgZGV0ZWN0IHRoaXMgYnkgY2FsY3VsYXRpbmcgdGhlIHNsb3BlIGZvcm1lZCBiZXR3ZWVuIHRoZVxuICAgICAgICAgICAgICAgIC8vIGN1cnJlbnQgbW91c2UgbG9jYXRpb24gYW5kIHRoZSB1cHBlci9sb3dlciByaWdodCBwb2ludHMgb2ZcbiAgICAgICAgICAgICAgICAvLyB0aGUgbWVudS4gV2UgZG8gdGhlIHNhbWUgZm9yIHRoZSBwcmV2aW91cyBtb3VzZSBsb2NhdGlvbi5cbiAgICAgICAgICAgICAgICAvLyBJZiB0aGUgY3VycmVudCBtb3VzZSBsb2NhdGlvbidzIHNsb3BlcyBhcmVcbiAgICAgICAgICAgICAgICAvLyBpbmNyZWFzaW5nL2RlY3JlYXNpbmcgYXBwcm9wcmlhdGVseSBjb21wYXJlZCB0byB0aGVcbiAgICAgICAgICAgICAgICAvLyBwcmV2aW91cydzLCB3ZSBrbm93IHRoZSB1c2VyIGlzIG1vdmluZyB0b3dhcmQgdGhlIHN1Ym1lbnUuXG4gICAgICAgICAgICAgICAgLy9cbiAgICAgICAgICAgICAgICAvLyBOb3RlIHRoYXQgc2luY2UgdGhlIHktYXhpcyBpbmNyZWFzZXMgYXMgdGhlIGN1cnNvciBtb3Zlc1xuICAgICAgICAgICAgICAgIC8vIGRvd24gdGhlIHNjcmVlbiwgd2UgYXJlIGxvb2tpbmcgZm9yIHRoZSBzbG9wZSBiZXR3ZWVuIHRoZVxuICAgICAgICAgICAgICAgIC8vIGN1cnNvciBhbmQgdGhlIHVwcGVyIHJpZ2h0IGNvcm5lciB0byBkZWNyZWFzZSBvdmVyIHRpbWUsIG5vdFxuICAgICAgICAgICAgICAgIC8vIGluY3JlYXNlIChzb21ld2hhdCBjb3VudGVyaW50dWl0aXZlbHkpLlxuICAgICAgICAgICAgICAgIGZ1bmN0aW9uIHNsb3BlKGEsIGIpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIChiLnkgLSBhLnkpIC8gKGIueCAtIGEueCk7XG4gICAgICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgICAgIHZhciBkZWNyZWFzaW5nQ29ybmVyID0gdXBwZXJSaWdodCxcbiAgICAgICAgICAgICAgICAgICAgaW5jcmVhc2luZ0Nvcm5lciA9IGxvd2VyUmlnaHQ7XG5cbiAgICAgICAgICAgICAgICAvLyBPdXIgZXhwZWN0YXRpb25zIGZvciBkZWNyZWFzaW5nIG9yIGluY3JlYXNpbmcgc2xvcGUgdmFsdWVzXG4gICAgICAgICAgICAgICAgLy8gZGVwZW5kcyBvbiB3aGljaCBkaXJlY3Rpb24gdGhlIHN1Ym1lbnUgb3BlbnMgcmVsYXRpdmUgdG8gdGhlXG4gICAgICAgICAgICAgICAgLy8gbWFpbiBtZW51LiBCeSBkZWZhdWx0LCBpZiB0aGUgbWVudSBvcGVucyBvbiB0aGUgcmlnaHQsIHdlXG4gICAgICAgICAgICAgICAgLy8gZXhwZWN0IHRoZSBzbG9wZSBiZXR3ZWVuIHRoZSBjdXJzb3IgYW5kIHRoZSB1cHBlciByaWdodFxuICAgICAgICAgICAgICAgIC8vIGNvcm5lciB0byBkZWNyZWFzZSBvdmVyIHRpbWUsIGFzIGV4cGxhaW5lZCBhYm92ZS4gSWYgdGhlXG4gICAgICAgICAgICAgICAgLy8gc3VibWVudSBvcGVucyBpbiBhIGRpZmZlcmVudCBkaXJlY3Rpb24sIHdlIGNoYW5nZSBvdXIgc2xvcGVcbiAgICAgICAgICAgICAgICAvLyBleHBlY3RhdGlvbnMuXG4gICAgICAgICAgICAgICAgaWYgKG9wdGlvbnMuc3VibWVudURpcmVjdGlvbiA9PSBcImxlZnRcIikge1xuICAgICAgICAgICAgICAgICAgICBkZWNyZWFzaW5nQ29ybmVyID0gbG93ZXJMZWZ0O1xuICAgICAgICAgICAgICAgICAgICBpbmNyZWFzaW5nQ29ybmVyID0gdXBwZXJMZWZ0O1xuICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAob3B0aW9ucy5zdWJtZW51RGlyZWN0aW9uID09IFwiYmVsb3dcIikge1xuICAgICAgICAgICAgICAgICAgICBkZWNyZWFzaW5nQ29ybmVyID0gbG93ZXJSaWdodDtcbiAgICAgICAgICAgICAgICAgICAgaW5jcmVhc2luZ0Nvcm5lciA9IGxvd2VyTGVmdDtcbiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKG9wdGlvbnMuc3VibWVudURpcmVjdGlvbiA9PSBcImFib3ZlXCIpIHtcbiAgICAgICAgICAgICAgICAgICAgZGVjcmVhc2luZ0Nvcm5lciA9IHVwcGVyTGVmdDtcbiAgICAgICAgICAgICAgICAgICAgaW5jcmVhc2luZ0Nvcm5lciA9IHVwcGVyUmlnaHQ7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgdmFyIGRlY3JlYXNpbmdTbG9wZSA9IHNsb3BlKGxvYywgZGVjcmVhc2luZ0Nvcm5lciksXG4gICAgICAgICAgICAgICAgICAgIGluY3JlYXNpbmdTbG9wZSA9IHNsb3BlKGxvYywgaW5jcmVhc2luZ0Nvcm5lciksXG4gICAgICAgICAgICAgICAgICAgIHByZXZEZWNyZWFzaW5nU2xvcGUgPSBzbG9wZShwcmV2TG9jLCBkZWNyZWFzaW5nQ29ybmVyKSxcbiAgICAgICAgICAgICAgICAgICAgcHJldkluY3JlYXNpbmdTbG9wZSA9IHNsb3BlKHByZXZMb2MsIGluY3JlYXNpbmdDb3JuZXIpO1xuXG4gICAgICAgICAgICAgICAgaWYgKGRlY3JlYXNpbmdTbG9wZSA8IHByZXZEZWNyZWFzaW5nU2xvcGUgJiZcbiAgICAgICAgICAgICAgICAgICAgICAgIGluY3JlYXNpbmdTbG9wZSA+IHByZXZJbmNyZWFzaW5nU2xvcGUpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gTW91c2UgaXMgbW92aW5nIGZyb20gcHJldmlvdXMgbG9jYXRpb24gdG93YXJkcyB0aGVcbiAgICAgICAgICAgICAgICAgICAgLy8gY3VycmVudGx5IGFjdGl2YXRlZCBzdWJtZW51LiBEZWxheSBiZWZvcmUgYWN0aXZhdGluZyBhXG4gICAgICAgICAgICAgICAgICAgIC8vIG5ldyBtZW51IHJvdywgYmVjYXVzZSB1c2VyIG1heSBiZSBtb3ZpbmcgaW50byBzdWJtZW51LlxuICAgICAgICAgICAgICAgICAgICBsYXN0RGVsYXlMb2MgPSBsb2M7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBERUxBWTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBsYXN0RGVsYXlMb2MgPSBudWxsO1xuICAgICAgICAgICAgICAgIHJldHVybiAwO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAvKipcbiAgICAgICAgICogSG9vayB1cCBpbml0aWFsIG1lbnUgZXZlbnRzXG4gICAgICAgICAqL1xuICAgICAgICAkbWVudVxuICAgICAgICAgICAgLm1vdXNlbGVhdmUobW91c2VsZWF2ZU1lbnUpXG4gICAgICAgICAgICAuZmluZChvcHRpb25zLnJvd1NlbGVjdG9yKVxuICAgICAgICAgICAgICAgIC5tb3VzZWVudGVyKG1vdXNlZW50ZXJSb3cpXG4gICAgICAgICAgICAgICAgLm1vdXNlbGVhdmUobW91c2VsZWF2ZVJvdylcbiAgICAgICAgICAgICAgICAuY2xpY2soY2xpY2tSb3cpO1xuXG4gICAgICAgICQoZG9jdW1lbnQpLm1vdXNlbW92ZShtb3VzZW1vdmVEb2N1bWVudCk7XG5cbiAgICB9O1xufSkoalF1ZXJ5KTtcblxuIl0sIm5hbWVzIjpbXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///976\n')},123:(__unused_webpack_module,__unused_webpack_exports,__webpack_require__)=>{eval("/* provided dependency */ var jQuery = __webpack_require__(796);\n(function(document, $, undefined) {\n\n/**\n * Provede daný callback na document a pak na každý snippet při nette ajaxu.\n * Depends on 'snippets' extension\n *\n * @param function($el) {} callback jemuž je jako první parametr předán document nebo snippet.\n */\n$.nette.ext('live', {\n}, {\n\tbefore: function (callback) {\n\t\tthis.ext('snippets').before($.proxy(function ($el) {\n\t\t\tcallback($el);\n\t\t}, this));\n\t\treturn this;\n\t},\n\tafter: function (callback) {\n\t\tthis.ext('snippets').after($.proxy(function ($el) {\n\t\t\tcallback($el);\n\t\t}, this));\n\t\tcallback($(document));\n\t\treturn this;\n\t},\n\tcomplete: function (callback) {\n\t\tthis.ext('snippets').complete($.proxy(function ($el) {\n\t\t\tcallback($el);\n\t\t}, this));\n\t\tcallback($(document));\n\t\treturn this;\n\t},\n});\n\n})(document, jQuery);\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMTIzLmpzIiwibWFwcGluZ3MiOiI7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vLi9ub2RlX21vZHVsZXMvYWR0LW5ldHRlLWFqYXgvZXh0ZW5zaW9ucy9saXZlLmpzP2EwMDciXSwic291cmNlc0NvbnRlbnQiOlsiKGZ1bmN0aW9uKGRvY3VtZW50LCAkLCB1bmRlZmluZWQpIHtcblxuLyoqXG4gKiBQcm92ZWRlIGRhbsO9IGNhbGxiYWNrIG5hIGRvY3VtZW50IGEgcGFrIG5hIGthxb5kw70gc25pcHBldCBwxZlpIG5ldHRlIGFqYXh1LlxuICogRGVwZW5kcyBvbiAnc25pcHBldHMnIGV4dGVuc2lvblxuICpcbiAqIEBwYXJhbSBmdW5jdGlvbigkZWwpIHt9IGNhbGxiYWNrIGplbXXFviBqZSBqYWtvIHBydm7DrSBwYXJhbWV0ciBwxZllZMOhbiBkb2N1bWVudCBuZWJvIHNuaXBwZXQuXG4gKi9cbiQubmV0dGUuZXh0KCdsaXZlJywge1xufSwge1xuXHRiZWZvcmU6IGZ1bmN0aW9uIChjYWxsYmFjaykge1xuXHRcdHRoaXMuZXh0KCdzbmlwcGV0cycpLmJlZm9yZSgkLnByb3h5KGZ1bmN0aW9uICgkZWwpIHtcblx0XHRcdGNhbGxiYWNrKCRlbCk7XG5cdFx0fSwgdGhpcykpO1xuXHRcdHJldHVybiB0aGlzO1xuXHR9LFxuXHRhZnRlcjogZnVuY3Rpb24gKGNhbGxiYWNrKSB7XG5cdFx0dGhpcy5leHQoJ3NuaXBwZXRzJykuYWZ0ZXIoJC5wcm94eShmdW5jdGlvbiAoJGVsKSB7XG5cdFx0XHRjYWxsYmFjaygkZWwpO1xuXHRcdH0sIHRoaXMpKTtcblx0XHRjYWxsYmFjaygkKGRvY3VtZW50KSk7XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH0sXG5cdGNvbXBsZXRlOiBmdW5jdGlvbiAoY2FsbGJhY2spIHtcblx0XHR0aGlzLmV4dCgnc25pcHBldHMnKS5jb21wbGV0ZSgkLnByb3h5KGZ1bmN0aW9uICgkZWwpIHtcblx0XHRcdGNhbGxiYWNrKCRlbCk7XG5cdFx0fSwgdGhpcykpO1xuXHRcdGNhbGxiYWNrKCQoZG9jdW1lbnQpKTtcblx0XHRyZXR1cm4gdGhpcztcblx0fSxcbn0pO1xuXG59KShkb2N1bWVudCwgalF1ZXJ5KTtcbiJdLCJuYW1lcyI6W10sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///123\n")},519:(__unused_webpack_module,__unused_webpack___webpack_exports__,__webpack_require__)=>{"use strict";eval("\n// NAMESPACE OBJECT: ./node_modules/@popperjs/core/lib/index.js\nvar lib_namespaceObject = {};\n__webpack_require__.r(lib_namespaceObject);\n__webpack_require__.d(lib_namespaceObject, {\n afterMain: () => (afterMain),\n afterRead: () => (afterRead),\n afterWrite: () => (afterWrite),\n applyStyles: () => (modifiers_applyStyles),\n arrow: () => (modifiers_arrow),\n auto: () => (enums_auto),\n basePlacements: () => (basePlacements),\n beforeMain: () => (beforeMain),\n beforeRead: () => (beforeRead),\n beforeWrite: () => (beforeWrite),\n bottom: () => (bottom),\n clippingParents: () => (clippingParents),\n computeStyles: () => (modifiers_computeStyles),\n createPopper: () => (popper_createPopper),\n createPopperBase: () => (createPopper),\n createPopperLite: () => (popper_lite_createPopper),\n detectOverflow: () => (detectOverflow),\n end: () => (end),\n eventListeners: () => (eventListeners),\n flip: () => (modifiers_flip),\n hide: () => (modifiers_hide),\n left: () => (left),\n main: () => (main),\n modifierPhases: () => (modifierPhases),\n offset: () => (modifiers_offset),\n placements: () => (enums_placements),\n popper: () => (popper),\n popperGenerator: () => (popperGenerator),\n popperOffsets: () => (modifiers_popperOffsets),\n preventOverflow: () => (modifiers_preventOverflow),\n read: () => (read),\n reference: () => (reference),\n right: () => (right),\n start: () => (start),\n top: () => (enums_top),\n variationPlacements: () => (variationPlacements),\n viewport: () => (viewport),\n write: () => (write)\n});\n\n// EXTERNAL MODULE: ./node_modules/jquery/dist/jquery-exposed.js\nvar jquery_exposed = __webpack_require__(796);\nvar jquery_exposed_default = /*#__PURE__*/__webpack_require__.n(jquery_exposed);\n// EXTERNAL MODULE: ./node_modules/jquery-ui-bundle/jquery-ui.js\nvar jquery_ui = __webpack_require__(668);\n// EXTERNAL MODULE: ./node_modules/@regru/jquery-menu-aim/jquery.menu-aim.js\nvar jquery_menu_aim = __webpack_require__(976);\n;// ./node_modules/@kurkle/color/dist/color.esm.js\n/*!\n * @kurkle/color v0.3.2\n * https://github.com/kurkle/color#readme\n * (c) 2023 Jukka Kurkela\n * Released under the MIT License\n */\nfunction round(v) {\n return v + 0.5 | 0;\n}\nconst lim = (v, l, h) => Math.max(Math.min(v, h), l);\nfunction p2b(v) {\n return lim(round(v * 2.55), 0, 255);\n}\nfunction b2p(v) {\n return lim(round(v / 2.55), 0, 100);\n}\nfunction n2b(v) {\n return lim(round(v * 255), 0, 255);\n}\nfunction b2n(v) {\n return lim(round(v / 2.55) / 100, 0, 1);\n}\nfunction n2p(v) {\n return lim(round(v * 100), 0, 100);\n}\n\nconst map$1 = {0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9, A: 10, B: 11, C: 12, D: 13, E: 14, F: 15, a: 10, b: 11, c: 12, d: 13, e: 14, f: 15};\nconst hex = [...'0123456789ABCDEF'];\nconst h1 = b => hex[b & 0xF];\nconst h2 = b => hex[(b & 0xF0) >> 4] + hex[b & 0xF];\nconst eq = b => ((b & 0xF0) >> 4) === (b & 0xF);\nconst isShort = v => eq(v.r) && eq(v.g) && eq(v.b) && eq(v.a);\nfunction hexParse(str) {\n var len = str.length;\n var ret;\n if (str[0] === '#') {\n if (len === 4 || len === 5) {\n ret = {\n r: 255 & map$1[str[1]] * 17,\n g: 255 & map$1[str[2]] * 17,\n b: 255 & map$1[str[3]] * 17,\n a: len === 5 ? map$1[str[4]] * 17 : 255\n };\n } else if (len === 7 || len === 9) {\n ret = {\n r: map$1[str[1]] << 4 | map$1[str[2]],\n g: map$1[str[3]] << 4 | map$1[str[4]],\n b: map$1[str[5]] << 4 | map$1[str[6]],\n a: len === 9 ? (map$1[str[7]] << 4 | map$1[str[8]]) : 255\n };\n }\n }\n return ret;\n}\nconst alpha = (a, f) => a < 255 ? f(a) : '';\nfunction hexString(v) {\n var f = isShort(v) ? h1 : h2;\n return v\n ? '#' + f(v.r) + f(v.g) + f(v.b) + alpha(v.a, f)\n : undefined;\n}\n\nconst HUE_RE = /^(hsla?|hwb|hsv)\\(\\s*([-+.e\\d]+)(?:deg)?[\\s,]+([-+.e\\d]+)%[\\s,]+([-+.e\\d]+)%(?:[\\s,]+([-+.e\\d]+)(%)?)?\\s*\\)$/;\nfunction hsl2rgbn(h, s, l) {\n const a = s * Math.min(l, 1 - l);\n const f = (n, k = (n + h / 30) % 12) => l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);\n return [f(0), f(8), f(4)];\n}\nfunction hsv2rgbn(h, s, v) {\n const f = (n, k = (n + h / 60) % 6) => v - v * s * Math.max(Math.min(k, 4 - k, 1), 0);\n return [f(5), f(3), f(1)];\n}\nfunction hwb2rgbn(h, w, b) {\n const rgb = hsl2rgbn(h, 1, 0.5);\n let i;\n if (w + b > 1) {\n i = 1 / (w + b);\n w *= i;\n b *= i;\n }\n for (i = 0; i < 3; i++) {\n rgb[i] *= 1 - w - b;\n rgb[i] += w;\n }\n return rgb;\n}\nfunction hueValue(r, g, b, d, max) {\n if (r === max) {\n return ((g - b) / d) + (g < b ? 6 : 0);\n }\n if (g === max) {\n return (b - r) / d + 2;\n }\n return (r - g) / d + 4;\n}\nfunction rgb2hsl(v) {\n const range = 255;\n const r = v.r / range;\n const g = v.g / range;\n const b = v.b / range;\n const max = Math.max(r, g, b);\n const min = Math.min(r, g, b);\n const l = (max + min) / 2;\n let h, s, d;\n if (max !== min) {\n d = max - min;\n s = l > 0.5 ? d / (2 - max - min) : d / (max + min);\n h = hueValue(r, g, b, d, max);\n h = h * 60 + 0.5;\n }\n return [h | 0, s || 0, l];\n}\nfunction calln(f, a, b, c) {\n return (\n Array.isArray(a)\n ? f(a[0], a[1], a[2])\n : f(a, b, c)\n ).map(n2b);\n}\nfunction hsl2rgb(h, s, l) {\n return calln(hsl2rgbn, h, s, l);\n}\nfunction hwb2rgb(h, w, b) {\n return calln(hwb2rgbn, h, w, b);\n}\nfunction hsv2rgb(h, s, v) {\n return calln(hsv2rgbn, h, s, v);\n}\nfunction hue(h) {\n return (h % 360 + 360) % 360;\n}\nfunction hueParse(str) {\n const m = HUE_RE.exec(str);\n let a = 255;\n let v;\n if (!m) {\n return;\n }\n if (m[5] !== v) {\n a = m[6] ? p2b(+m[5]) : n2b(+m[5]);\n }\n const h = hue(+m[2]);\n const p1 = +m[3] / 100;\n const p2 = +m[4] / 100;\n if (m[1] === 'hwb') {\n v = hwb2rgb(h, p1, p2);\n } else if (m[1] === 'hsv') {\n v = hsv2rgb(h, p1, p2);\n } else {\n v = hsl2rgb(h, p1, p2);\n }\n return {\n r: v[0],\n g: v[1],\n b: v[2],\n a: a\n };\n}\nfunction rotate(v, deg) {\n var h = rgb2hsl(v);\n h[0] = hue(h[0] + deg);\n h = hsl2rgb(h);\n v.r = h[0];\n v.g = h[1];\n v.b = h[2];\n}\nfunction hslString(v) {\n if (!v) {\n return;\n }\n const a = rgb2hsl(v);\n const h = a[0];\n const s = n2p(a[1]);\n const l = n2p(a[2]);\n return v.a < 255\n ? `hsla(${h}, ${s}%, ${l}%, ${b2n(v.a)})`\n : `hsl(${h}, ${s}%, ${l}%)`;\n}\n\nconst map = {\n x: 'dark',\n Z: 'light',\n Y: 're',\n X: 'blu',\n W: 'gr',\n V: 'medium',\n U: 'slate',\n A: 'ee',\n T: 'ol',\n S: 'or',\n B: 'ra',\n C: 'lateg',\n D: 'ights',\n R: 'in',\n Q: 'turquois',\n E: 'hi',\n P: 'ro',\n O: 'al',\n N: 'le',\n M: 'de',\n L: 'yello',\n F: 'en',\n K: 'ch',\n G: 'arks',\n H: 'ea',\n I: 'ightg',\n J: 'wh'\n};\nconst names$1 = {\n OiceXe: 'f0f8ff',\n antiquewEte: 'faebd7',\n aqua: 'ffff',\n aquamarRe: '7fffd4',\n azuY: 'f0ffff',\n beige: 'f5f5dc',\n bisque: 'ffe4c4',\n black: '0',\n blanKedOmond: 'ffebcd',\n Xe: 'ff',\n XeviTet: '8a2be2',\n bPwn: 'a52a2a',\n burlywood: 'deb887',\n caMtXe: '5f9ea0',\n KartYuse: '7fff00',\n KocTate: 'd2691e',\n cSO: 'ff7f50',\n cSnflowerXe: '6495ed',\n cSnsilk: 'fff8dc',\n crimson: 'dc143c',\n cyan: 'ffff',\n xXe: '8b',\n xcyan: '8b8b',\n xgTMnPd: 'b8860b',\n xWay: 'a9a9a9',\n xgYF: '6400',\n xgYy: 'a9a9a9',\n xkhaki: 'bdb76b',\n xmagFta: '8b008b',\n xTivegYF: '556b2f',\n xSange: 'ff8c00',\n xScEd: '9932cc',\n xYd: '8b0000',\n xsOmon: 'e9967a',\n xsHgYF: '8fbc8f',\n xUXe: '483d8b',\n xUWay: '2f4f4f',\n xUgYy: '2f4f4f',\n xQe: 'ced1',\n xviTet: '9400d3',\n dAppRk: 'ff1493',\n dApskyXe: 'bfff',\n dimWay: '696969',\n dimgYy: '696969',\n dodgerXe: '1e90ff',\n fiYbrick: 'b22222',\n flSOwEte: 'fffaf0',\n foYstWAn: '228b22',\n fuKsia: 'ff00ff',\n gaRsbSo: 'dcdcdc',\n ghostwEte: 'f8f8ff',\n gTd: 'ffd700',\n gTMnPd: 'daa520',\n Way: '808080',\n gYF: '8000',\n gYFLw: 'adff2f',\n gYy: '808080',\n honeyMw: 'f0fff0',\n hotpRk: 'ff69b4',\n RdianYd: 'cd5c5c',\n Rdigo: '4b0082',\n ivSy: 'fffff0',\n khaki: 'f0e68c',\n lavFMr: 'e6e6fa',\n lavFMrXsh: 'fff0f5',\n lawngYF: '7cfc00',\n NmoncEffon: 'fffacd',\n ZXe: 'add8e6',\n ZcSO: 'f08080',\n Zcyan: 'e0ffff',\n ZgTMnPdLw: 'fafad2',\n ZWay: 'd3d3d3',\n ZgYF: '90ee90',\n ZgYy: 'd3d3d3',\n ZpRk: 'ffb6c1',\n ZsOmon: 'ffa07a',\n ZsHgYF: '20b2aa',\n ZskyXe: '87cefa',\n ZUWay: '778899',\n ZUgYy: '778899',\n ZstAlXe: 'b0c4de',\n ZLw: 'ffffe0',\n lime: 'ff00',\n limegYF: '32cd32',\n lRF: 'faf0e6',\n magFta: 'ff00ff',\n maPon: '800000',\n VaquamarRe: '66cdaa',\n VXe: 'cd',\n VScEd: 'ba55d3',\n VpurpN: '9370db',\n VsHgYF: '3cb371',\n VUXe: '7b68ee',\n VsprRggYF: 'fa9a',\n VQe: '48d1cc',\n VviTetYd: 'c71585',\n midnightXe: '191970',\n mRtcYam: 'f5fffa',\n mistyPse: 'ffe4e1',\n moccasR: 'ffe4b5',\n navajowEte: 'ffdead',\n navy: '80',\n Tdlace: 'fdf5e6',\n Tive: '808000',\n TivedBb: '6b8e23',\n Sange: 'ffa500',\n SangeYd: 'ff4500',\n ScEd: 'da70d6',\n pOegTMnPd: 'eee8aa',\n pOegYF: '98fb98',\n pOeQe: 'afeeee',\n pOeviTetYd: 'db7093',\n papayawEp: 'ffefd5',\n pHKpuff: 'ffdab9',\n peru: 'cd853f',\n pRk: 'ffc0cb',\n plum: 'dda0dd',\n powMrXe: 'b0e0e6',\n purpN: '800080',\n YbeccapurpN: '663399',\n Yd: 'ff0000',\n Psybrown: 'bc8f8f',\n PyOXe: '4169e1',\n saddNbPwn: '8b4513',\n sOmon: 'fa8072',\n sandybPwn: 'f4a460',\n sHgYF: '2e8b57',\n sHshell: 'fff5ee',\n siFna: 'a0522d',\n silver: 'c0c0c0',\n skyXe: '87ceeb',\n UXe: '6a5acd',\n UWay: '708090',\n UgYy: '708090',\n snow: 'fffafa',\n sprRggYF: 'ff7f',\n stAlXe: '4682b4',\n tan: 'd2b48c',\n teO: '8080',\n tEstN: 'd8bfd8',\n tomato: 'ff6347',\n Qe: '40e0d0',\n viTet: 'ee82ee',\n JHt: 'f5deb3',\n wEte: 'ffffff',\n wEtesmoke: 'f5f5f5',\n Lw: 'ffff00',\n LwgYF: '9acd32'\n};\nfunction unpack() {\n const unpacked = {};\n const keys = Object.keys(names$1);\n const tkeys = Object.keys(map);\n let i, j, k, ok, nk;\n for (i = 0; i < keys.length; i++) {\n ok = nk = keys[i];\n for (j = 0; j < tkeys.length; j++) {\n k = tkeys[j];\n nk = nk.replace(k, map[k]);\n }\n k = parseInt(names$1[ok], 16);\n unpacked[nk] = [k >> 16 & 0xFF, k >> 8 & 0xFF, k & 0xFF];\n }\n return unpacked;\n}\n\nlet names;\nfunction nameParse(str) {\n if (!names) {\n names = unpack();\n names.transparent = [0, 0, 0, 0];\n }\n const a = names[str.toLowerCase()];\n return a && {\n r: a[0],\n g: a[1],\n b: a[2],\n a: a.length === 4 ? a[3] : 255\n };\n}\n\nconst RGB_RE = /^rgba?\\(\\s*([-+.\\d]+)(%)?[\\s,]+([-+.e\\d]+)(%)?[\\s,]+([-+.e\\d]+)(%)?(?:[\\s,/]+([-+.e\\d]+)(%)?)?\\s*\\)$/;\nfunction rgbParse(str) {\n const m = RGB_RE.exec(str);\n let a = 255;\n let r, g, b;\n if (!m) {\n return;\n }\n if (m[7] !== r) {\n const v = +m[7];\n a = m[8] ? p2b(v) : lim(v * 255, 0, 255);\n }\n r = +m[1];\n g = +m[3];\n b = +m[5];\n r = 255 & (m[2] ? p2b(r) : lim(r, 0, 255));\n g = 255 & (m[4] ? p2b(g) : lim(g, 0, 255));\n b = 255 & (m[6] ? p2b(b) : lim(b, 0, 255));\n return {\n r: r,\n g: g,\n b: b,\n a: a\n };\n}\nfunction rgbString(v) {\n return v && (\n v.a < 255\n ? `rgba(${v.r}, ${v.g}, ${v.b}, ${b2n(v.a)})`\n : `rgb(${v.r}, ${v.g}, ${v.b})`\n );\n}\n\nconst to = v => v <= 0.0031308 ? v * 12.92 : Math.pow(v, 1.0 / 2.4) * 1.055 - 0.055;\nconst from = v => v <= 0.04045 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);\nfunction interpolate(rgb1, rgb2, t) {\n const r = from(b2n(rgb1.r));\n const g = from(b2n(rgb1.g));\n const b = from(b2n(rgb1.b));\n return {\n r: n2b(to(r + t * (from(b2n(rgb2.r)) - r))),\n g: n2b(to(g + t * (from(b2n(rgb2.g)) - g))),\n b: n2b(to(b + t * (from(b2n(rgb2.b)) - b))),\n a: rgb1.a + t * (rgb2.a - rgb1.a)\n };\n}\n\nfunction modHSL(v, i, ratio) {\n if (v) {\n let tmp = rgb2hsl(v);\n tmp[i] = Math.max(0, Math.min(tmp[i] + tmp[i] * ratio, i === 0 ? 360 : 1));\n tmp = hsl2rgb(tmp);\n v.r = tmp[0];\n v.g = tmp[1];\n v.b = tmp[2];\n }\n}\nfunction clone(v, proto) {\n return v ? Object.assign(proto || {}, v) : v;\n}\nfunction fromObject(input) {\n var v = {r: 0, g: 0, b: 0, a: 255};\n if (Array.isArray(input)) {\n if (input.length >= 3) {\n v = {r: input[0], g: input[1], b: input[2], a: 255};\n if (input.length > 3) {\n v.a = n2b(input[3]);\n }\n }\n } else {\n v = clone(input, {r: 0, g: 0, b: 0, a: 1});\n v.a = n2b(v.a);\n }\n return v;\n}\nfunction functionParse(str) {\n if (str.charAt(0) === 'r') {\n return rgbParse(str);\n }\n return hueParse(str);\n}\nclass Color {\n constructor(input) {\n if (input instanceof Color) {\n return input;\n }\n const type = typeof input;\n let v;\n if (type === 'object') {\n v = fromObject(input);\n } else if (type === 'string') {\n v = hexParse(input) || nameParse(input) || functionParse(input);\n }\n this._rgb = v;\n this._valid = !!v;\n }\n get valid() {\n return this._valid;\n }\n get rgb() {\n var v = clone(this._rgb);\n if (v) {\n v.a = b2n(v.a);\n }\n return v;\n }\n set rgb(obj) {\n this._rgb = fromObject(obj);\n }\n rgbString() {\n return this._valid ? rgbString(this._rgb) : undefined;\n }\n hexString() {\n return this._valid ? hexString(this._rgb) : undefined;\n }\n hslString() {\n return this._valid ? hslString(this._rgb) : undefined;\n }\n mix(color, weight) {\n if (color) {\n const c1 = this.rgb;\n const c2 = color.rgb;\n let w2;\n const p = weight === w2 ? 0.5 : weight;\n const w = 2 * p - 1;\n const a = c1.a - c2.a;\n const w1 = ((w * a === -1 ? w : (w + a) / (1 + w * a)) + 1) / 2.0;\n w2 = 1 - w1;\n c1.r = 0xFF & w1 * c1.r + w2 * c2.r + 0.5;\n c1.g = 0xFF & w1 * c1.g + w2 * c2.g + 0.5;\n c1.b = 0xFF & w1 * c1.b + w2 * c2.b + 0.5;\n c1.a = p * c1.a + (1 - p) * c2.a;\n this.rgb = c1;\n }\n return this;\n }\n interpolate(color, t) {\n if (color) {\n this._rgb = interpolate(this._rgb, color._rgb, t);\n }\n return this;\n }\n clone() {\n return new Color(this.rgb);\n }\n alpha(a) {\n this._rgb.a = n2b(a);\n return this;\n }\n clearer(ratio) {\n const rgb = this._rgb;\n rgb.a *= 1 - ratio;\n return this;\n }\n greyscale() {\n const rgb = this._rgb;\n const val = round(rgb.r * 0.3 + rgb.g * 0.59 + rgb.b * 0.11);\n rgb.r = rgb.g = rgb.b = val;\n return this;\n }\n opaquer(ratio) {\n const rgb = this._rgb;\n rgb.a *= 1 + ratio;\n return this;\n }\n negate() {\n const v = this._rgb;\n v.r = 255 - v.r;\n v.g = 255 - v.g;\n v.b = 255 - v.b;\n return this;\n }\n lighten(ratio) {\n modHSL(this._rgb, 2, ratio);\n return this;\n }\n darken(ratio) {\n modHSL(this._rgb, 2, -ratio);\n return this;\n }\n saturate(ratio) {\n modHSL(this._rgb, 1, ratio);\n return this;\n }\n desaturate(ratio) {\n modHSL(this._rgb, 1, -ratio);\n return this;\n }\n rotate(deg) {\n rotate(this._rgb, deg);\n return this;\n }\n}\n\nfunction index_esm(input) {\n return new Color(input);\n}\n\n\n\n;// ./node_modules/chart.js/dist/chunks/helpers.segment.js\n/*!\n * Chart.js v4.4.4\n * https://www.chartjs.org\n * (c) 2024 Chart.js Contributors\n * Released under the MIT License\n */\n\n\n/**\n * @namespace Chart.helpers\n */ /**\n * An empty function that can be used, for example, for optional callback.\n */ function noop() {\n/* noop */ }\n/**\n * Returns a unique id, sequentially generated from a global variable.\n */ const uid = (()=>{\n let id = 0;\n return ()=>id++;\n})();\n/**\n * Returns true if `value` is neither null nor undefined, else returns false.\n * @param value - The value to test.\n * @since 2.7.0\n */ function isNullOrUndef(value) {\n return value === null || typeof value === 'undefined';\n}\n/**\n * Returns true if `value` is an array (including typed arrays), else returns false.\n * @param value - The value to test.\n * @function\n */ function isArray(value) {\n if (Array.isArray && Array.isArray(value)) {\n return true;\n }\n const type = Object.prototype.toString.call(value);\n if (type.slice(0, 7) === '[object' && type.slice(-6) === 'Array]') {\n return true;\n }\n return false;\n}\n/**\n * Returns true if `value` is an object (excluding null), else returns false.\n * @param value - The value to test.\n * @since 2.7.0\n */ function isObject(value) {\n return value !== null && Object.prototype.toString.call(value) === '[object Object]';\n}\n/**\n * Returns true if `value` is a finite number, else returns false\n * @param value - The value to test.\n */ function isNumberFinite(value) {\n return (typeof value === 'number' || value instanceof Number) && isFinite(+value);\n}\n/**\n * Returns `value` if finite, else returns `defaultValue`.\n * @param value - The value to return if defined.\n * @param defaultValue - The value to return if `value` is not finite.\n */ function finiteOrDefault(value, defaultValue) {\n return isNumberFinite(value) ? value : defaultValue;\n}\n/**\n * Returns `value` if defined, else returns `defaultValue`.\n * @param value - The value to return if defined.\n * @param defaultValue - The value to return if `value` is undefined.\n */ function valueOrDefault(value, defaultValue) {\n return typeof value === 'undefined' ? defaultValue : value;\n}\nconst toPercentage = (value, dimension)=>typeof value === 'string' && value.endsWith('%') ? parseFloat(value) / 100 : +value / dimension;\nconst toDimension = (value, dimension)=>typeof value === 'string' && value.endsWith('%') ? parseFloat(value) / 100 * dimension : +value;\n/**\n * Calls `fn` with the given `args` in the scope defined by `thisArg` and returns the\n * value returned by `fn`. If `fn` is not a function, this method returns undefined.\n * @param fn - The function to call.\n * @param args - The arguments with which `fn` should be called.\n * @param [thisArg] - The value of `this` provided for the call to `fn`.\n */ function callback(fn, args, thisArg) {\n if (fn && typeof fn.call === 'function') {\n return fn.apply(thisArg, args);\n }\n}\nfunction each(loopable, fn, thisArg, reverse) {\n let i, len, keys;\n if (isArray(loopable)) {\n len = loopable.length;\n if (reverse) {\n for(i = len - 1; i >= 0; i--){\n fn.call(thisArg, loopable[i], i);\n }\n } else {\n for(i = 0; i < len; i++){\n fn.call(thisArg, loopable[i], i);\n }\n }\n } else if (isObject(loopable)) {\n keys = Object.keys(loopable);\n len = keys.length;\n for(i = 0; i < len; i++){\n fn.call(thisArg, loopable[keys[i]], keys[i]);\n }\n }\n}\n/**\n * Returns true if the `a0` and `a1` arrays have the same content, else returns false.\n * @param a0 - The array to compare\n * @param a1 - The array to compare\n * @private\n */ function _elementsEqual(a0, a1) {\n let i, ilen, v0, v1;\n if (!a0 || !a1 || a0.length !== a1.length) {\n return false;\n }\n for(i = 0, ilen = a0.length; i < ilen; ++i){\n v0 = a0[i];\n v1 = a1[i];\n if (v0.datasetIndex !== v1.datasetIndex || v0.index !== v1.index) {\n return false;\n }\n }\n return true;\n}\n/**\n * Returns a deep copy of `source` without keeping references on objects and arrays.\n * @param source - The value to clone.\n */ function helpers_segment_clone(source) {\n if (isArray(source)) {\n return source.map(helpers_segment_clone);\n }\n if (isObject(source)) {\n const target = Object.create(null);\n const keys = Object.keys(source);\n const klen = keys.length;\n let k = 0;\n for(; k < klen; ++k){\n target[keys[k]] = helpers_segment_clone(source[keys[k]]);\n }\n return target;\n }\n return source;\n}\nfunction isValidKey(key) {\n return [\n '__proto__',\n 'prototype',\n 'constructor'\n ].indexOf(key) === -1;\n}\n/**\n * The default merger when Chart.helpers.merge is called without merger option.\n * Note(SB): also used by mergeConfig and mergeScaleConfig as fallback.\n * @private\n */ function _merger(key, target, source, options) {\n if (!isValidKey(key)) {\n return;\n }\n const tval = target[key];\n const sval = source[key];\n if (isObject(tval) && isObject(sval)) {\n // eslint-disable-next-line @typescript-eslint/no-use-before-define\n merge(tval, sval, options);\n } else {\n target[key] = helpers_segment_clone(sval);\n }\n}\nfunction merge(target, source, options) {\n const sources = isArray(source) ? source : [\n source\n ];\n const ilen = sources.length;\n if (!isObject(target)) {\n return target;\n }\n options = options || {};\n const merger = options.merger || _merger;\n let current;\n for(let i = 0; i < ilen; ++i){\n current = sources[i];\n if (!isObject(current)) {\n continue;\n }\n const keys = Object.keys(current);\n for(let k = 0, klen = keys.length; k < klen; ++k){\n merger(keys[k], target, current, options);\n }\n }\n return target;\n}\nfunction mergeIf(target, source) {\n // eslint-disable-next-line @typescript-eslint/no-use-before-define\n return merge(target, source, {\n merger: _mergerIf\n });\n}\n/**\n * Merges source[key] in target[key] only if target[key] is undefined.\n * @private\n */ function _mergerIf(key, target, source) {\n if (!isValidKey(key)) {\n return;\n }\n const tval = target[key];\n const sval = source[key];\n if (isObject(tval) && isObject(sval)) {\n mergeIf(tval, sval);\n } else if (!Object.prototype.hasOwnProperty.call(target, key)) {\n target[key] = helpers_segment_clone(sval);\n }\n}\n/**\n * @private\n */ function _deprecated(scope, value, previous, current) {\n if (value !== undefined) {\n console.warn(scope + ': \"' + previous + '\" is deprecated. Please use \"' + current + '\" instead');\n }\n}\n// resolveObjectKey resolver cache\nconst keyResolvers = {\n // Chart.helpers.core resolveObjectKey should resolve empty key to root object\n '': (v)=>v,\n // default resolvers\n x: (o)=>o.x,\n y: (o)=>o.y\n};\n/**\n * @private\n */ function _splitKey(key) {\n const parts = key.split('.');\n const keys = [];\n let tmp = '';\n for (const part of parts){\n tmp += part;\n if (tmp.endsWith('\\\\')) {\n tmp = tmp.slice(0, -1) + '.';\n } else {\n keys.push(tmp);\n tmp = '';\n }\n }\n return keys;\n}\nfunction _getKeyResolver(key) {\n const keys = _splitKey(key);\n return (obj)=>{\n for (const k of keys){\n if (k === '') {\n break;\n }\n obj = obj && obj[k];\n }\n return obj;\n };\n}\nfunction resolveObjectKey(obj, key) {\n const resolver = keyResolvers[key] || (keyResolvers[key] = _getKeyResolver(key));\n return resolver(obj);\n}\n/**\n * @private\n */ function _capitalize(str) {\n return str.charAt(0).toUpperCase() + str.slice(1);\n}\nconst defined = (value)=>typeof value !== 'undefined';\nconst isFunction = (value)=>typeof value === 'function';\n// Adapted from https://stackoverflow.com/questions/31128855/comparing-ecma6-sets-for-equality#31129384\nconst setsEqual = (a, b)=>{\n if (a.size !== b.size) {\n return false;\n }\n for (const item of a){\n if (!b.has(item)) {\n return false;\n }\n }\n return true;\n};\n/**\n * @param e - The event\n * @private\n */ function _isClickEvent(e) {\n return e.type === 'mouseup' || e.type === 'click' || e.type === 'contextmenu';\n}\n\n/**\n * @alias Chart.helpers.math\n * @namespace\n */ const PI = Math.PI;\nconst TAU = 2 * PI;\nconst PITAU = TAU + PI;\nconst INFINITY = Number.POSITIVE_INFINITY;\nconst RAD_PER_DEG = PI / 180;\nconst HALF_PI = PI / 2;\nconst QUARTER_PI = PI / 4;\nconst TWO_THIRDS_PI = PI * 2 / 3;\nconst log10 = Math.log10;\nconst sign = Math.sign;\nfunction almostEquals(x, y, epsilon) {\n return Math.abs(x - y) < epsilon;\n}\n/**\n * Implementation of the nice number algorithm used in determining where axis labels will go\n */ function niceNum(range) {\n const roundedRange = Math.round(range);\n range = almostEquals(range, roundedRange, range / 1000) ? roundedRange : range;\n const niceRange = Math.pow(10, Math.floor(log10(range)));\n const fraction = range / niceRange;\n const niceFraction = fraction <= 1 ? 1 : fraction <= 2 ? 2 : fraction <= 5 ? 5 : 10;\n return niceFraction * niceRange;\n}\n/**\n * Returns an array of factors sorted from 1 to sqrt(value)\n * @private\n */ function _factorize(value) {\n const result = [];\n const sqrt = Math.sqrt(value);\n let i;\n for(i = 1; i < sqrt; i++){\n if (value % i === 0) {\n result.push(i);\n result.push(value / i);\n }\n }\n if (sqrt === (sqrt | 0)) {\n result.push(sqrt);\n }\n result.sort((a, b)=>a - b).pop();\n return result;\n}\nfunction isNumber(n) {\n return !isNaN(parseFloat(n)) && isFinite(n);\n}\nfunction almostWhole(x, epsilon) {\n const rounded = Math.round(x);\n return rounded - epsilon <= x && rounded + epsilon >= x;\n}\n/**\n * @private\n */ function _setMinAndMaxByKey(array, target, property) {\n let i, ilen, value;\n for(i = 0, ilen = array.length; i < ilen; i++){\n value = array[i][property];\n if (!isNaN(value)) {\n target.min = Math.min(target.min, value);\n target.max = Math.max(target.max, value);\n }\n }\n}\nfunction toRadians(degrees) {\n return degrees * (PI / 180);\n}\nfunction toDegrees(radians) {\n return radians * (180 / PI);\n}\n/**\n * Returns the number of decimal places\n * i.e. the number of digits after the decimal point, of the value of this Number.\n * @param x - A number.\n * @returns The number of decimal places.\n * @private\n */ function _decimalPlaces(x) {\n if (!isNumberFinite(x)) {\n return;\n }\n let e = 1;\n let p = 0;\n while(Math.round(x * e) / e !== x){\n e *= 10;\n p++;\n }\n return p;\n}\n// Gets the angle from vertical upright to the point about a centre.\nfunction getAngleFromPoint(centrePoint, anglePoint) {\n const distanceFromXCenter = anglePoint.x - centrePoint.x;\n const distanceFromYCenter = anglePoint.y - centrePoint.y;\n const radialDistanceFromCenter = Math.sqrt(distanceFromXCenter * distanceFromXCenter + distanceFromYCenter * distanceFromYCenter);\n let angle = Math.atan2(distanceFromYCenter, distanceFromXCenter);\n if (angle < -0.5 * PI) {\n angle += TAU; // make sure the returned angle is in the range of (-PI/2, 3PI/2]\n }\n return {\n angle,\n distance: radialDistanceFromCenter\n };\n}\nfunction distanceBetweenPoints(pt1, pt2) {\n return Math.sqrt(Math.pow(pt2.x - pt1.x, 2) + Math.pow(pt2.y - pt1.y, 2));\n}\n/**\n * Shortest distance between angles, in either direction.\n * @private\n */ function _angleDiff(a, b) {\n return (a - b + PITAU) % TAU - PI;\n}\n/**\n * Normalize angle to be between 0 and 2*PI\n * @private\n */ function _normalizeAngle(a) {\n return (a % TAU + TAU) % TAU;\n}\n/**\n * @private\n */ function _angleBetween(angle, start, end, sameAngleIsFullCircle) {\n const a = _normalizeAngle(angle);\n const s = _normalizeAngle(start);\n const e = _normalizeAngle(end);\n const angleToStart = _normalizeAngle(s - a);\n const angleToEnd = _normalizeAngle(e - a);\n const startToAngle = _normalizeAngle(a - s);\n const endToAngle = _normalizeAngle(a - e);\n return a === s || a === e || sameAngleIsFullCircle && s === e || angleToStart > angleToEnd && startToAngle < endToAngle;\n}\n/**\n * Limit `value` between `min` and `max`\n * @param value\n * @param min\n * @param max\n * @private\n */ function _limitValue(value, min, max) {\n return Math.max(min, Math.min(max, value));\n}\n/**\n * @param {number} value\n * @private\n */ function _int16Range(value) {\n return _limitValue(value, -32768, 32767);\n}\n/**\n * @param value\n * @param start\n * @param end\n * @param [epsilon]\n * @private\n */ function _isBetween(value, start, end, epsilon = 1e-6) {\n return value >= Math.min(start, end) - epsilon && value <= Math.max(start, end) + epsilon;\n}\n\nfunction _lookup(table, value, cmp) {\n cmp = cmp || ((index)=>table[index] < value);\n let hi = table.length - 1;\n let lo = 0;\n let mid;\n while(hi - lo > 1){\n mid = lo + hi >> 1;\n if (cmp(mid)) {\n lo = mid;\n } else {\n hi = mid;\n }\n }\n return {\n lo,\n hi\n };\n}\n/**\n * Binary search\n * @param table - the table search. must be sorted!\n * @param key - property name for the value in each entry\n * @param value - value to find\n * @param last - lookup last index\n * @private\n */ const _lookupByKey = (table, key, value, last)=>_lookup(table, value, last ? (index)=>{\n const ti = table[index][key];\n return ti < value || ti === value && table[index + 1][key] === value;\n } : (index)=>table[index][key] < value);\n/**\n * Reverse binary search\n * @param table - the table search. must be sorted!\n * @param key - property name for the value in each entry\n * @param value - value to find\n * @private\n */ const _rlookupByKey = (table, key, value)=>_lookup(table, value, (index)=>table[index][key] >= value);\n/**\n * Return subset of `values` between `min` and `max` inclusive.\n * Values are assumed to be in sorted order.\n * @param values - sorted array of values\n * @param min - min value\n * @param max - max value\n */ function _filterBetween(values, min, max) {\n let start = 0;\n let end = values.length;\n while(start < end && values[start] < min){\n start++;\n }\n while(end > start && values[end - 1] > max){\n end--;\n }\n return start > 0 || end < values.length ? values.slice(start, end) : values;\n}\nconst arrayEvents = [\n 'push',\n 'pop',\n 'shift',\n 'splice',\n 'unshift'\n];\nfunction listenArrayEvents(array, listener) {\n if (array._chartjs) {\n array._chartjs.listeners.push(listener);\n return;\n }\n Object.defineProperty(array, '_chartjs', {\n configurable: true,\n enumerable: false,\n value: {\n listeners: [\n listener\n ]\n }\n });\n arrayEvents.forEach((key)=>{\n const method = '_onData' + _capitalize(key);\n const base = array[key];\n Object.defineProperty(array, key, {\n configurable: true,\n enumerable: false,\n value (...args) {\n const res = base.apply(this, args);\n array._chartjs.listeners.forEach((object)=>{\n if (typeof object[method] === 'function') {\n object[method](...args);\n }\n });\n return res;\n }\n });\n });\n}\nfunction unlistenArrayEvents(array, listener) {\n const stub = array._chartjs;\n if (!stub) {\n return;\n }\n const listeners = stub.listeners;\n const index = listeners.indexOf(listener);\n if (index !== -1) {\n listeners.splice(index, 1);\n }\n if (listeners.length > 0) {\n return;\n }\n arrayEvents.forEach((key)=>{\n delete array[key];\n });\n delete array._chartjs;\n}\n/**\n * @param items\n */ function _arrayUnique(items) {\n const set = new Set(items);\n if (set.size === items.length) {\n return items;\n }\n return Array.from(set);\n}\n\nfunction fontString(pixelSize, fontStyle, fontFamily) {\n return fontStyle + ' ' + pixelSize + 'px ' + fontFamily;\n}\n/**\n* Request animation polyfill\n*/ const requestAnimFrame = function() {\n if (typeof window === 'undefined') {\n return function(callback) {\n return callback();\n };\n }\n return window.requestAnimationFrame;\n}();\n/**\n * Throttles calling `fn` once per animation frame\n * Latest arguments are used on the actual call\n */ function throttled(fn, thisArg) {\n let argsToUse = [];\n let ticking = false;\n return function(...args) {\n // Save the args for use later\n argsToUse = args;\n if (!ticking) {\n ticking = true;\n requestAnimFrame.call(window, ()=>{\n ticking = false;\n fn.apply(thisArg, argsToUse);\n });\n }\n };\n}\n/**\n * Debounces calling `fn` for `delay` ms\n */ function debounce(fn, delay) {\n let timeout;\n return function(...args) {\n if (delay) {\n clearTimeout(timeout);\n timeout = setTimeout(fn, delay, args);\n } else {\n fn.apply(this, args);\n }\n return delay;\n };\n}\n/**\n * Converts 'start' to 'left', 'end' to 'right' and others to 'center'\n * @private\n */ const _toLeftRightCenter = (align)=>align === 'start' ? 'left' : align === 'end' ? 'right' : 'center';\n/**\n * Returns `start`, `end` or `(start + end) / 2` depending on `align`. Defaults to `center`\n * @private\n */ const _alignStartEnd = (align, start, end)=>align === 'start' ? start : align === 'end' ? end : (start + end) / 2;\n/**\n * Returns `left`, `right` or `(left + right) / 2` depending on `align`. Defaults to `left`\n * @private\n */ const _textX = (align, left, right, rtl)=>{\n const check = rtl ? 'left' : 'right';\n return align === check ? right : align === 'center' ? (left + right) / 2 : left;\n};\n/**\n * Return start and count of visible points.\n * @private\n */ function _getStartAndCountOfVisiblePoints(meta, points, animationsDisabled) {\n const pointCount = points.length;\n let start = 0;\n let count = pointCount;\n if (meta._sorted) {\n const { iScale , _parsed } = meta;\n const axis = iScale.axis;\n const { min , max , minDefined , maxDefined } = iScale.getUserBounds();\n if (minDefined) {\n start = _limitValue(Math.min(// @ts-expect-error Need to type _parsed\n _lookupByKey(_parsed, axis, min).lo, // @ts-expect-error Need to fix types on _lookupByKey\n animationsDisabled ? pointCount : _lookupByKey(points, axis, iScale.getPixelForValue(min)).lo), 0, pointCount - 1);\n }\n if (maxDefined) {\n count = _limitValue(Math.max(// @ts-expect-error Need to type _parsed\n _lookupByKey(_parsed, iScale.axis, max, true).hi + 1, // @ts-expect-error Need to fix types on _lookupByKey\n animationsDisabled ? 0 : _lookupByKey(points, axis, iScale.getPixelForValue(max), true).hi + 1), start, pointCount) - start;\n } else {\n count = pointCount - start;\n }\n }\n return {\n start,\n count\n };\n}\n/**\n * Checks if the scale ranges have changed.\n * @param {object} meta - dataset meta.\n * @returns {boolean}\n * @private\n */ function _scaleRangesChanged(meta) {\n const { xScale , yScale , _scaleRanges } = meta;\n const newRanges = {\n xmin: xScale.min,\n xmax: xScale.max,\n ymin: yScale.min,\n ymax: yScale.max\n };\n if (!_scaleRanges) {\n meta._scaleRanges = newRanges;\n return true;\n }\n const changed = _scaleRanges.xmin !== xScale.min || _scaleRanges.xmax !== xScale.max || _scaleRanges.ymin !== yScale.min || _scaleRanges.ymax !== yScale.max;\n Object.assign(_scaleRanges, newRanges);\n return changed;\n}\n\nconst atEdge = (t)=>t === 0 || t === 1;\nconst elasticIn = (t, s, p)=>-(Math.pow(2, 10 * (t -= 1)) * Math.sin((t - s) * TAU / p));\nconst elasticOut = (t, s, p)=>Math.pow(2, -10 * t) * Math.sin((t - s) * TAU / p) + 1;\n/**\n * Easing functions adapted from Robert Penner's easing equations.\n * @namespace Chart.helpers.easing.effects\n * @see http://www.robertpenner.com/easing/\n */ const effects = {\n linear: (t)=>t,\n easeInQuad: (t)=>t * t,\n easeOutQuad: (t)=>-t * (t - 2),\n easeInOutQuad: (t)=>(t /= 0.5) < 1 ? 0.5 * t * t : -0.5 * (--t * (t - 2) - 1),\n easeInCubic: (t)=>t * t * t,\n easeOutCubic: (t)=>(t -= 1) * t * t + 1,\n easeInOutCubic: (t)=>(t /= 0.5) < 1 ? 0.5 * t * t * t : 0.5 * ((t -= 2) * t * t + 2),\n easeInQuart: (t)=>t * t * t * t,\n easeOutQuart: (t)=>-((t -= 1) * t * t * t - 1),\n easeInOutQuart: (t)=>(t /= 0.5) < 1 ? 0.5 * t * t * t * t : -0.5 * ((t -= 2) * t * t * t - 2),\n easeInQuint: (t)=>t * t * t * t * t,\n easeOutQuint: (t)=>(t -= 1) * t * t * t * t + 1,\n easeInOutQuint: (t)=>(t /= 0.5) < 1 ? 0.5 * t * t * t * t * t : 0.5 * ((t -= 2) * t * t * t * t + 2),\n easeInSine: (t)=>-Math.cos(t * HALF_PI) + 1,\n easeOutSine: (t)=>Math.sin(t * HALF_PI),\n easeInOutSine: (t)=>-0.5 * (Math.cos(PI * t) - 1),\n easeInExpo: (t)=>t === 0 ? 0 : Math.pow(2, 10 * (t - 1)),\n easeOutExpo: (t)=>t === 1 ? 1 : -Math.pow(2, -10 * t) + 1,\n easeInOutExpo: (t)=>atEdge(t) ? t : t < 0.5 ? 0.5 * Math.pow(2, 10 * (t * 2 - 1)) : 0.5 * (-Math.pow(2, -10 * (t * 2 - 1)) + 2),\n easeInCirc: (t)=>t >= 1 ? t : -(Math.sqrt(1 - t * t) - 1),\n easeOutCirc: (t)=>Math.sqrt(1 - (t -= 1) * t),\n easeInOutCirc: (t)=>(t /= 0.5) < 1 ? -0.5 * (Math.sqrt(1 - t * t) - 1) : 0.5 * (Math.sqrt(1 - (t -= 2) * t) + 1),\n easeInElastic: (t)=>atEdge(t) ? t : elasticIn(t, 0.075, 0.3),\n easeOutElastic: (t)=>atEdge(t) ? t : elasticOut(t, 0.075, 0.3),\n easeInOutElastic (t) {\n const s = 0.1125;\n const p = 0.45;\n return atEdge(t) ? t : t < 0.5 ? 0.5 * elasticIn(t * 2, s, p) : 0.5 + 0.5 * elasticOut(t * 2 - 1, s, p);\n },\n easeInBack (t) {\n const s = 1.70158;\n return t * t * ((s + 1) * t - s);\n },\n easeOutBack (t) {\n const s = 1.70158;\n return (t -= 1) * t * ((s + 1) * t + s) + 1;\n },\n easeInOutBack (t) {\n let s = 1.70158;\n if ((t /= 0.5) < 1) {\n return 0.5 * (t * t * (((s *= 1.525) + 1) * t - s));\n }\n return 0.5 * ((t -= 2) * t * (((s *= 1.525) + 1) * t + s) + 2);\n },\n easeInBounce: (t)=>1 - effects.easeOutBounce(1 - t),\n easeOutBounce (t) {\n const m = 7.5625;\n const d = 2.75;\n if (t < 1 / d) {\n return m * t * t;\n }\n if (t < 2 / d) {\n return m * (t -= 1.5 / d) * t + 0.75;\n }\n if (t < 2.5 / d) {\n return m * (t -= 2.25 / d) * t + 0.9375;\n }\n return m * (t -= 2.625 / d) * t + 0.984375;\n },\n easeInOutBounce: (t)=>t < 0.5 ? effects.easeInBounce(t * 2) * 0.5 : effects.easeOutBounce(t * 2 - 1) * 0.5 + 0.5\n};\n\nfunction isPatternOrGradient(value) {\n if (value && typeof value === 'object') {\n const type = value.toString();\n return type === '[object CanvasPattern]' || type === '[object CanvasGradient]';\n }\n return false;\n}\nfunction color(value) {\n return isPatternOrGradient(value) ? value : new Color(value);\n}\nfunction getHoverColor(value) {\n return isPatternOrGradient(value) ? value : new Color(value).saturate(0.5).darken(0.1).hexString();\n}\n\nconst numbers = [\n 'x',\n 'y',\n 'borderWidth',\n 'radius',\n 'tension'\n];\nconst colors = [\n 'color',\n 'borderColor',\n 'backgroundColor'\n];\nfunction applyAnimationsDefaults(defaults) {\n defaults.set('animation', {\n delay: undefined,\n duration: 1000,\n easing: 'easeOutQuart',\n fn: undefined,\n from: undefined,\n loop: undefined,\n to: undefined,\n type: undefined\n });\n defaults.describe('animation', {\n _fallback: false,\n _indexable: false,\n _scriptable: (name)=>name !== 'onProgress' && name !== 'onComplete' && name !== 'fn'\n });\n defaults.set('animations', {\n colors: {\n type: 'color',\n properties: colors\n },\n numbers: {\n type: 'number',\n properties: numbers\n }\n });\n defaults.describe('animations', {\n _fallback: 'animation'\n });\n defaults.set('transitions', {\n active: {\n animation: {\n duration: 400\n }\n },\n resize: {\n animation: {\n duration: 0\n }\n },\n show: {\n animations: {\n colors: {\n from: 'transparent'\n },\n visible: {\n type: 'boolean',\n duration: 0\n }\n }\n },\n hide: {\n animations: {\n colors: {\n to: 'transparent'\n },\n visible: {\n type: 'boolean',\n easing: 'linear',\n fn: (v)=>v | 0\n }\n }\n }\n });\n}\n\nfunction applyLayoutsDefaults(defaults) {\n defaults.set('layout', {\n autoPadding: true,\n padding: {\n top: 0,\n right: 0,\n bottom: 0,\n left: 0\n }\n });\n}\n\nconst intlCache = new Map();\nfunction getNumberFormat(locale, options) {\n options = options || {};\n const cacheKey = locale + JSON.stringify(options);\n let formatter = intlCache.get(cacheKey);\n if (!formatter) {\n formatter = new Intl.NumberFormat(locale, options);\n intlCache.set(cacheKey, formatter);\n }\n return formatter;\n}\nfunction formatNumber(num, locale, options) {\n return getNumberFormat(locale, options).format(num);\n}\n\nconst formatters = {\n values (value) {\n return isArray(value) ? value : '' + value;\n },\n numeric (tickValue, index, ticks) {\n if (tickValue === 0) {\n return '0';\n }\n const locale = this.chart.options.locale;\n let notation;\n let delta = tickValue;\n if (ticks.length > 1) {\n const maxTick = Math.max(Math.abs(ticks[0].value), Math.abs(ticks[ticks.length - 1].value));\n if (maxTick < 1e-4 || maxTick > 1e+15) {\n notation = 'scientific';\n }\n delta = calculateDelta(tickValue, ticks);\n }\n const logDelta = log10(Math.abs(delta));\n const numDecimal = isNaN(logDelta) ? 1 : Math.max(Math.min(-1 * Math.floor(logDelta), 20), 0);\n const options = {\n notation,\n minimumFractionDigits: numDecimal,\n maximumFractionDigits: numDecimal\n };\n Object.assign(options, this.options.ticks.format);\n return formatNumber(tickValue, locale, options);\n },\n logarithmic (tickValue, index, ticks) {\n if (tickValue === 0) {\n return '0';\n }\n const remain = ticks[index].significand || tickValue / Math.pow(10, Math.floor(log10(tickValue)));\n if ([\n 1,\n 2,\n 3,\n 5,\n 10,\n 15\n ].includes(remain) || index > 0.8 * ticks.length) {\n return formatters.numeric.call(this, tickValue, index, ticks);\n }\n return '';\n }\n};\nfunction calculateDelta(tickValue, ticks) {\n let delta = ticks.length > 3 ? ticks[2].value - ticks[1].value : ticks[1].value - ticks[0].value;\n if (Math.abs(delta) >= 1 && tickValue !== Math.floor(tickValue)) {\n delta = tickValue - Math.floor(tickValue);\n }\n return delta;\n}\n var Ticks = {\n formatters\n};\n\nfunction applyScaleDefaults(defaults) {\n defaults.set('scale', {\n display: true,\n offset: false,\n reverse: false,\n beginAtZero: false,\n bounds: 'ticks',\n clip: true,\n grace: 0,\n grid: {\n display: true,\n lineWidth: 1,\n drawOnChartArea: true,\n drawTicks: true,\n tickLength: 8,\n tickWidth: (_ctx, options)=>options.lineWidth,\n tickColor: (_ctx, options)=>options.color,\n offset: false\n },\n border: {\n display: true,\n dash: [],\n dashOffset: 0.0,\n width: 1\n },\n title: {\n display: false,\n text: '',\n padding: {\n top: 4,\n bottom: 4\n }\n },\n ticks: {\n minRotation: 0,\n maxRotation: 50,\n mirror: false,\n textStrokeWidth: 0,\n textStrokeColor: '',\n padding: 3,\n display: true,\n autoSkip: true,\n autoSkipPadding: 3,\n labelOffset: 0,\n callback: Ticks.formatters.values,\n minor: {},\n major: {},\n align: 'center',\n crossAlign: 'near',\n showLabelBackdrop: false,\n backdropColor: 'rgba(255, 255, 255, 0.75)',\n backdropPadding: 2\n }\n });\n defaults.route('scale.ticks', 'color', '', 'color');\n defaults.route('scale.grid', 'color', '', 'borderColor');\n defaults.route('scale.border', 'color', '', 'borderColor');\n defaults.route('scale.title', 'color', '', 'color');\n defaults.describe('scale', {\n _fallback: false,\n _scriptable: (name)=>!name.startsWith('before') && !name.startsWith('after') && name !== 'callback' && name !== 'parser',\n _indexable: (name)=>name !== 'borderDash' && name !== 'tickBorderDash' && name !== 'dash'\n });\n defaults.describe('scales', {\n _fallback: 'scale'\n });\n defaults.describe('scale.ticks', {\n _scriptable: (name)=>name !== 'backdropPadding' && name !== 'callback',\n _indexable: (name)=>name !== 'backdropPadding'\n });\n}\n\nconst overrides = Object.create(null);\nconst descriptors = Object.create(null);\n function getScope$1(node, key) {\n if (!key) {\n return node;\n }\n const keys = key.split('.');\n for(let i = 0, n = keys.length; i < n; ++i){\n const k = keys[i];\n node = node[k] || (node[k] = Object.create(null));\n }\n return node;\n}\nfunction set(root, scope, values) {\n if (typeof scope === 'string') {\n return merge(getScope$1(root, scope), values);\n }\n return merge(getScope$1(root, ''), scope);\n}\n class Defaults {\n constructor(_descriptors, _appliers){\n this.animation = undefined;\n this.backgroundColor = 'rgba(0,0,0,0.1)';\n this.borderColor = 'rgba(0,0,0,0.1)';\n this.color = '#666';\n this.datasets = {};\n this.devicePixelRatio = (context)=>context.chart.platform.getDevicePixelRatio();\n this.elements = {};\n this.events = [\n 'mousemove',\n 'mouseout',\n 'click',\n 'touchstart',\n 'touchmove'\n ];\n this.font = {\n family: \"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif\",\n size: 12,\n style: 'normal',\n lineHeight: 1.2,\n weight: null\n };\n this.hover = {};\n this.hoverBackgroundColor = (ctx, options)=>getHoverColor(options.backgroundColor);\n this.hoverBorderColor = (ctx, options)=>getHoverColor(options.borderColor);\n this.hoverColor = (ctx, options)=>getHoverColor(options.color);\n this.indexAxis = 'x';\n this.interaction = {\n mode: 'nearest',\n intersect: true,\n includeInvisible: false\n };\n this.maintainAspectRatio = true;\n this.onHover = null;\n this.onClick = null;\n this.parsing = true;\n this.plugins = {};\n this.responsive = true;\n this.scale = undefined;\n this.scales = {};\n this.showLine = true;\n this.drawActiveElementsOnTop = true;\n this.describe(_descriptors);\n this.apply(_appliers);\n }\n set(scope, values) {\n return set(this, scope, values);\n }\n get(scope) {\n return getScope$1(this, scope);\n }\n describe(scope, values) {\n return set(descriptors, scope, values);\n }\n override(scope, values) {\n return set(overrides, scope, values);\n }\n route(scope, name, targetScope, targetName) {\n const scopeObject = getScope$1(this, scope);\n const targetScopeObject = getScope$1(this, targetScope);\n const privateName = '_' + name;\n Object.defineProperties(scopeObject, {\n [privateName]: {\n value: scopeObject[name],\n writable: true\n },\n [name]: {\n enumerable: true,\n get () {\n const local = this[privateName];\n const target = targetScopeObject[targetName];\n if (isObject(local)) {\n return Object.assign({}, target, local);\n }\n return valueOrDefault(local, target);\n },\n set (value) {\n this[privateName] = value;\n }\n }\n });\n }\n apply(appliers) {\n appliers.forEach((apply)=>apply(this));\n }\n}\nvar defaults = /* #__PURE__ */ new Defaults({\n _scriptable: (name)=>!name.startsWith('on'),\n _indexable: (name)=>name !== 'events',\n hover: {\n _fallback: 'interaction'\n },\n interaction: {\n _scriptable: false,\n _indexable: false\n }\n}, [\n applyAnimationsDefaults,\n applyLayoutsDefaults,\n applyScaleDefaults\n]);\n\n/**\n * Converts the given font object into a CSS font string.\n * @param font - A font object.\n * @return The CSS font string. See https://developer.mozilla.org/en-US/docs/Web/CSS/font\n * @private\n */ function toFontString(font) {\n if (!font || isNullOrUndef(font.size) || isNullOrUndef(font.family)) {\n return null;\n }\n return (font.style ? font.style + ' ' : '') + (font.weight ? font.weight + ' ' : '') + font.size + 'px ' + font.family;\n}\n/**\n * @private\n */ function _measureText(ctx, data, gc, longest, string) {\n let textWidth = data[string];\n if (!textWidth) {\n textWidth = data[string] = ctx.measureText(string).width;\n gc.push(string);\n }\n if (textWidth > longest) {\n longest = textWidth;\n }\n return longest;\n}\n/**\n * @private\n */ // eslint-disable-next-line complexity\nfunction _longestText(ctx, font, arrayOfThings, cache) {\n cache = cache || {};\n let data = cache.data = cache.data || {};\n let gc = cache.garbageCollect = cache.garbageCollect || [];\n if (cache.font !== font) {\n data = cache.data = {};\n gc = cache.garbageCollect = [];\n cache.font = font;\n }\n ctx.save();\n ctx.font = font;\n let longest = 0;\n const ilen = arrayOfThings.length;\n let i, j, jlen, thing, nestedThing;\n for(i = 0; i < ilen; i++){\n thing = arrayOfThings[i];\n // Undefined strings and arrays should not be measured\n if (thing !== undefined && thing !== null && !isArray(thing)) {\n longest = _measureText(ctx, data, gc, longest, thing);\n } else if (isArray(thing)) {\n // if it is an array lets measure each element\n // to do maybe simplify this function a bit so we can do this more recursively?\n for(j = 0, jlen = thing.length; j < jlen; j++){\n nestedThing = thing[j];\n // Undefined strings and arrays should not be measured\n if (nestedThing !== undefined && nestedThing !== null && !isArray(nestedThing)) {\n longest = _measureText(ctx, data, gc, longest, nestedThing);\n }\n }\n }\n }\n ctx.restore();\n const gcLen = gc.length / 2;\n if (gcLen > arrayOfThings.length) {\n for(i = 0; i < gcLen; i++){\n delete data[gc[i]];\n }\n gc.splice(0, gcLen);\n }\n return longest;\n}\n/**\n * Returns the aligned pixel value to avoid anti-aliasing blur\n * @param chart - The chart instance.\n * @param pixel - A pixel value.\n * @param width - The width of the element.\n * @returns The aligned pixel value.\n * @private\n */ function _alignPixel(chart, pixel, width) {\n const devicePixelRatio = chart.currentDevicePixelRatio;\n const halfWidth = width !== 0 ? Math.max(width / 2, 0.5) : 0;\n return Math.round((pixel - halfWidth) * devicePixelRatio) / devicePixelRatio + halfWidth;\n}\n/**\n * Clears the entire canvas.\n */ function clearCanvas(canvas, ctx) {\n if (!ctx && !canvas) {\n return;\n }\n ctx = ctx || canvas.getContext('2d');\n ctx.save();\n // canvas.width and canvas.height do not consider the canvas transform,\n // while clearRect does\n ctx.resetTransform();\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n ctx.restore();\n}\nfunction drawPoint(ctx, options, x, y) {\n // eslint-disable-next-line @typescript-eslint/no-use-before-define\n drawPointLegend(ctx, options, x, y, null);\n}\n// eslint-disable-next-line complexity\nfunction drawPointLegend(ctx, options, x, y, w) {\n let type, xOffset, yOffset, size, cornerRadius, width, xOffsetW, yOffsetW;\n const style = options.pointStyle;\n const rotation = options.rotation;\n const radius = options.radius;\n let rad = (rotation || 0) * RAD_PER_DEG;\n if (style && typeof style === 'object') {\n type = style.toString();\n if (type === '[object HTMLImageElement]' || type === '[object HTMLCanvasElement]') {\n ctx.save();\n ctx.translate(x, y);\n ctx.rotate(rad);\n ctx.drawImage(style, -style.width / 2, -style.height / 2, style.width, style.height);\n ctx.restore();\n return;\n }\n }\n if (isNaN(radius) || radius <= 0) {\n return;\n }\n ctx.beginPath();\n switch(style){\n // Default includes circle\n default:\n if (w) {\n ctx.ellipse(x, y, w / 2, radius, 0, 0, TAU);\n } else {\n ctx.arc(x, y, radius, 0, TAU);\n }\n ctx.closePath();\n break;\n case 'triangle':\n width = w ? w / 2 : radius;\n ctx.moveTo(x + Math.sin(rad) * width, y - Math.cos(rad) * radius);\n rad += TWO_THIRDS_PI;\n ctx.lineTo(x + Math.sin(rad) * width, y - Math.cos(rad) * radius);\n rad += TWO_THIRDS_PI;\n ctx.lineTo(x + Math.sin(rad) * width, y - Math.cos(rad) * radius);\n ctx.closePath();\n break;\n case 'rectRounded':\n // NOTE: the rounded rect implementation changed to use `arc` instead of\n // `quadraticCurveTo` since it generates better results when rect is\n // almost a circle. 0.516 (instead of 0.5) produces results with visually\n // closer proportion to the previous impl and it is inscribed in the\n // circle with `radius`. For more details, see the following PRs:\n // https://github.com/chartjs/Chart.js/issues/5597\n // https://github.com/chartjs/Chart.js/issues/5858\n cornerRadius = radius * 0.516;\n size = radius - cornerRadius;\n xOffset = Math.cos(rad + QUARTER_PI) * size;\n xOffsetW = Math.cos(rad + QUARTER_PI) * (w ? w / 2 - cornerRadius : size);\n yOffset = Math.sin(rad + QUARTER_PI) * size;\n yOffsetW = Math.sin(rad + QUARTER_PI) * (w ? w / 2 - cornerRadius : size);\n ctx.arc(x - xOffsetW, y - yOffset, cornerRadius, rad - PI, rad - HALF_PI);\n ctx.arc(x + yOffsetW, y - xOffset, cornerRadius, rad - HALF_PI, rad);\n ctx.arc(x + xOffsetW, y + yOffset, cornerRadius, rad, rad + HALF_PI);\n ctx.arc(x - yOffsetW, y + xOffset, cornerRadius, rad + HALF_PI, rad + PI);\n ctx.closePath();\n break;\n case 'rect':\n if (!rotation) {\n size = Math.SQRT1_2 * radius;\n width = w ? w / 2 : size;\n ctx.rect(x - width, y - size, 2 * width, 2 * size);\n break;\n }\n rad += QUARTER_PI;\n /* falls through */ case 'rectRot':\n xOffsetW = Math.cos(rad) * (w ? w / 2 : radius);\n xOffset = Math.cos(rad) * radius;\n yOffset = Math.sin(rad) * radius;\n yOffsetW = Math.sin(rad) * (w ? w / 2 : radius);\n ctx.moveTo(x - xOffsetW, y - yOffset);\n ctx.lineTo(x + yOffsetW, y - xOffset);\n ctx.lineTo(x + xOffsetW, y + yOffset);\n ctx.lineTo(x - yOffsetW, y + xOffset);\n ctx.closePath();\n break;\n case 'crossRot':\n rad += QUARTER_PI;\n /* falls through */ case 'cross':\n xOffsetW = Math.cos(rad) * (w ? w / 2 : radius);\n xOffset = Math.cos(rad) * radius;\n yOffset = Math.sin(rad) * radius;\n yOffsetW = Math.sin(rad) * (w ? w / 2 : radius);\n ctx.moveTo(x - xOffsetW, y - yOffset);\n ctx.lineTo(x + xOffsetW, y + yOffset);\n ctx.moveTo(x + yOffsetW, y - xOffset);\n ctx.lineTo(x - yOffsetW, y + xOffset);\n break;\n case 'star':\n xOffsetW = Math.cos(rad) * (w ? w / 2 : radius);\n xOffset = Math.cos(rad) * radius;\n yOffset = Math.sin(rad) * radius;\n yOffsetW = Math.sin(rad) * (w ? w / 2 : radius);\n ctx.moveTo(x - xOffsetW, y - yOffset);\n ctx.lineTo(x + xOffsetW, y + yOffset);\n ctx.moveTo(x + yOffsetW, y - xOffset);\n ctx.lineTo(x - yOffsetW, y + xOffset);\n rad += QUARTER_PI;\n xOffsetW = Math.cos(rad) * (w ? w / 2 : radius);\n xOffset = Math.cos(rad) * radius;\n yOffset = Math.sin(rad) * radius;\n yOffsetW = Math.sin(rad) * (w ? w / 2 : radius);\n ctx.moveTo(x - xOffsetW, y - yOffset);\n ctx.lineTo(x + xOffsetW, y + yOffset);\n ctx.moveTo(x + yOffsetW, y - xOffset);\n ctx.lineTo(x - yOffsetW, y + xOffset);\n break;\n case 'line':\n xOffset = w ? w / 2 : Math.cos(rad) * radius;\n yOffset = Math.sin(rad) * radius;\n ctx.moveTo(x - xOffset, y - yOffset);\n ctx.lineTo(x + xOffset, y + yOffset);\n break;\n case 'dash':\n ctx.moveTo(x, y);\n ctx.lineTo(x + Math.cos(rad) * (w ? w / 2 : radius), y + Math.sin(rad) * radius);\n break;\n case false:\n ctx.closePath();\n break;\n }\n ctx.fill();\n if (options.borderWidth > 0) {\n ctx.stroke();\n }\n}\n/**\n * Returns true if the point is inside the rectangle\n * @param point - The point to test\n * @param area - The rectangle\n * @param margin - allowed margin\n * @private\n */ function _isPointInArea(point, area, margin) {\n margin = margin || 0.5; // margin - default is to match rounded decimals\n return !area || point && point.x > area.left - margin && point.x < area.right + margin && point.y > area.top - margin && point.y < area.bottom + margin;\n}\nfunction clipArea(ctx, area) {\n ctx.save();\n ctx.beginPath();\n ctx.rect(area.left, area.top, area.right - area.left, area.bottom - area.top);\n ctx.clip();\n}\nfunction unclipArea(ctx) {\n ctx.restore();\n}\n/**\n * @private\n */ function _steppedLineTo(ctx, previous, target, flip, mode) {\n if (!previous) {\n return ctx.lineTo(target.x, target.y);\n }\n if (mode === 'middle') {\n const midpoint = (previous.x + target.x) / 2.0;\n ctx.lineTo(midpoint, previous.y);\n ctx.lineTo(midpoint, target.y);\n } else if (mode === 'after' !== !!flip) {\n ctx.lineTo(previous.x, target.y);\n } else {\n ctx.lineTo(target.x, previous.y);\n }\n ctx.lineTo(target.x, target.y);\n}\n/**\n * @private\n */ function _bezierCurveTo(ctx, previous, target, flip) {\n if (!previous) {\n return ctx.lineTo(target.x, target.y);\n }\n ctx.bezierCurveTo(flip ? previous.cp1x : previous.cp2x, flip ? previous.cp1y : previous.cp2y, flip ? target.cp2x : target.cp1x, flip ? target.cp2y : target.cp1y, target.x, target.y);\n}\nfunction setRenderOpts(ctx, opts) {\n if (opts.translation) {\n ctx.translate(opts.translation[0], opts.translation[1]);\n }\n if (!isNullOrUndef(opts.rotation)) {\n ctx.rotate(opts.rotation);\n }\n if (opts.color) {\n ctx.fillStyle = opts.color;\n }\n if (opts.textAlign) {\n ctx.textAlign = opts.textAlign;\n }\n if (opts.textBaseline) {\n ctx.textBaseline = opts.textBaseline;\n }\n}\nfunction decorateText(ctx, x, y, line, opts) {\n if (opts.strikethrough || opts.underline) {\n /**\n * Now that IE11 support has been dropped, we can use more\n * of the TextMetrics object. The actual bounding boxes\n * are unflagged in Chrome, Firefox, Edge, and Safari so they\n * can be safely used.\n * See https://developer.mozilla.org/en-US/docs/Web/API/TextMetrics#Browser_compatibility\n */ const metrics = ctx.measureText(line);\n const left = x - metrics.actualBoundingBoxLeft;\n const right = x + metrics.actualBoundingBoxRight;\n const top = y - metrics.actualBoundingBoxAscent;\n const bottom = y + metrics.actualBoundingBoxDescent;\n const yDecoration = opts.strikethrough ? (top + bottom) / 2 : bottom;\n ctx.strokeStyle = ctx.fillStyle;\n ctx.beginPath();\n ctx.lineWidth = opts.decorationWidth || 2;\n ctx.moveTo(left, yDecoration);\n ctx.lineTo(right, yDecoration);\n ctx.stroke();\n }\n}\nfunction drawBackdrop(ctx, opts) {\n const oldColor = ctx.fillStyle;\n ctx.fillStyle = opts.color;\n ctx.fillRect(opts.left, opts.top, opts.width, opts.height);\n ctx.fillStyle = oldColor;\n}\n/**\n * Render text onto the canvas\n */ function renderText(ctx, text, x, y, font, opts = {}) {\n const lines = isArray(text) ? text : [\n text\n ];\n const stroke = opts.strokeWidth > 0 && opts.strokeColor !== '';\n let i, line;\n ctx.save();\n ctx.font = font.string;\n setRenderOpts(ctx, opts);\n for(i = 0; i < lines.length; ++i){\n line = lines[i];\n if (opts.backdrop) {\n drawBackdrop(ctx, opts.backdrop);\n }\n if (stroke) {\n if (opts.strokeColor) {\n ctx.strokeStyle = opts.strokeColor;\n }\n if (!isNullOrUndef(opts.strokeWidth)) {\n ctx.lineWidth = opts.strokeWidth;\n }\n ctx.strokeText(line, x, y, opts.maxWidth);\n }\n ctx.fillText(line, x, y, opts.maxWidth);\n decorateText(ctx, x, y, line, opts);\n y += Number(font.lineHeight);\n }\n ctx.restore();\n}\n/**\n * Add a path of a rectangle with rounded corners to the current sub-path\n * @param ctx - Context\n * @param rect - Bounding rect\n */ function addRoundedRectPath(ctx, rect) {\n const { x , y , w , h , radius } = rect;\n // top left arc\n ctx.arc(x + radius.topLeft, y + radius.topLeft, radius.topLeft, 1.5 * PI, PI, true);\n // line from top left to bottom left\n ctx.lineTo(x, y + h - radius.bottomLeft);\n // bottom left arc\n ctx.arc(x + radius.bottomLeft, y + h - radius.bottomLeft, radius.bottomLeft, PI, HALF_PI, true);\n // line from bottom left to bottom right\n ctx.lineTo(x + w - radius.bottomRight, y + h);\n // bottom right arc\n ctx.arc(x + w - radius.bottomRight, y + h - radius.bottomRight, radius.bottomRight, HALF_PI, 0, true);\n // line from bottom right to top right\n ctx.lineTo(x + w, y + radius.topRight);\n // top right arc\n ctx.arc(x + w - radius.topRight, y + radius.topRight, radius.topRight, 0, -HALF_PI, true);\n // line from top right to top left\n ctx.lineTo(x + radius.topLeft, y);\n}\n\nconst LINE_HEIGHT = /^(normal|(\\d+(?:\\.\\d+)?)(px|em|%)?)$/;\nconst FONT_STYLE = /^(normal|italic|initial|inherit|unset|(oblique( -?[0-9]?[0-9]deg)?))$/;\n/**\n * @alias Chart.helpers.options\n * @namespace\n */ /**\n * Converts the given line height `value` in pixels for a specific font `size`.\n * @param value - The lineHeight to parse (eg. 1.6, '14px', '75%', '1.6em').\n * @param size - The font size (in pixels) used to resolve relative `value`.\n * @returns The effective line height in pixels (size * 1.2 if value is invalid).\n * @see https://developer.mozilla.org/en-US/docs/Web/CSS/line-height\n * @since 2.7.0\n */ function toLineHeight(value, size) {\n const matches = ('' + value).match(LINE_HEIGHT);\n if (!matches || matches[1] === 'normal') {\n return size * 1.2;\n }\n value = +matches[2];\n switch(matches[3]){\n case 'px':\n return value;\n case '%':\n value /= 100;\n break;\n }\n return size * value;\n}\nconst numberOrZero = (v)=>+v || 0;\nfunction _readValueToProps(value, props) {\n const ret = {};\n const objProps = isObject(props);\n const keys = objProps ? Object.keys(props) : props;\n const read = isObject(value) ? objProps ? (prop)=>valueOrDefault(value[prop], value[props[prop]]) : (prop)=>value[prop] : ()=>value;\n for (const prop of keys){\n ret[prop] = numberOrZero(read(prop));\n }\n return ret;\n}\n/**\n * Converts the given value into a TRBL object.\n * @param value - If a number, set the value to all TRBL component,\n * else, if an object, use defined properties and sets undefined ones to 0.\n * x / y are shorthands for same value for left/right and top/bottom.\n * @returns The padding values (top, right, bottom, left)\n * @since 3.0.0\n */ function toTRBL(value) {\n return _readValueToProps(value, {\n top: 'y',\n right: 'x',\n bottom: 'y',\n left: 'x'\n });\n}\n/**\n * Converts the given value into a TRBL corners object (similar with css border-radius).\n * @param value - If a number, set the value to all TRBL corner components,\n * else, if an object, use defined properties and sets undefined ones to 0.\n * @returns The TRBL corner values (topLeft, topRight, bottomLeft, bottomRight)\n * @since 3.0.0\n */ function toTRBLCorners(value) {\n return _readValueToProps(value, [\n 'topLeft',\n 'topRight',\n 'bottomLeft',\n 'bottomRight'\n ]);\n}\n/**\n * Converts the given value into a padding object with pre-computed width/height.\n * @param value - If a number, set the value to all TRBL component,\n * else, if an object, use defined properties and sets undefined ones to 0.\n * x / y are shorthands for same value for left/right and top/bottom.\n * @returns The padding values (top, right, bottom, left, width, height)\n * @since 2.7.0\n */ function toPadding(value) {\n const obj = toTRBL(value);\n obj.width = obj.left + obj.right;\n obj.height = obj.top + obj.bottom;\n return obj;\n}\n/**\n * Parses font options and returns the font object.\n * @param options - A object that contains font options to be parsed.\n * @param fallback - A object that contains fallback font options.\n * @return The font object.\n * @private\n */ function toFont(options, fallback) {\n options = options || {};\n fallback = fallback || defaults.font;\n let size = valueOrDefault(options.size, fallback.size);\n if (typeof size === 'string') {\n size = parseInt(size, 10);\n }\n let style = valueOrDefault(options.style, fallback.style);\n if (style && !('' + style).match(FONT_STYLE)) {\n console.warn('Invalid font style specified: \"' + style + '\"');\n style = undefined;\n }\n const font = {\n family: valueOrDefault(options.family, fallback.family),\n lineHeight: toLineHeight(valueOrDefault(options.lineHeight, fallback.lineHeight), size),\n size,\n style,\n weight: valueOrDefault(options.weight, fallback.weight),\n string: ''\n };\n font.string = toFontString(font);\n return font;\n}\n/**\n * Evaluates the given `inputs` sequentially and returns the first defined value.\n * @param inputs - An array of values, falling back to the last value.\n * @param context - If defined and the current value is a function, the value\n * is called with `context` as first argument and the result becomes the new input.\n * @param index - If defined and the current value is an array, the value\n * at `index` become the new input.\n * @param info - object to return information about resolution in\n * @param info.cacheable - Will be set to `false` if option is not cacheable.\n * @since 2.7.0\n */ function resolve(inputs, context, index, info) {\n let cacheable = true;\n let i, ilen, value;\n for(i = 0, ilen = inputs.length; i < ilen; ++i){\n value = inputs[i];\n if (value === undefined) {\n continue;\n }\n if (context !== undefined && typeof value === 'function') {\n value = value(context);\n cacheable = false;\n }\n if (index !== undefined && isArray(value)) {\n value = value[index % value.length];\n cacheable = false;\n }\n if (value !== undefined) {\n if (info && !cacheable) {\n info.cacheable = false;\n }\n return value;\n }\n }\n}\n/**\n * @param minmax\n * @param grace\n * @param beginAtZero\n * @private\n */ function _addGrace(minmax, grace, beginAtZero) {\n const { min , max } = minmax;\n const change = toDimension(grace, (max - min) / 2);\n const keepZero = (value, add)=>beginAtZero && value === 0 ? 0 : value + add;\n return {\n min: keepZero(min, -Math.abs(change)),\n max: keepZero(max, change)\n };\n}\nfunction createContext(parentContext, context) {\n return Object.assign(Object.create(parentContext), context);\n}\n\n/**\n * Creates a Proxy for resolving raw values for options.\n * @param scopes - The option scopes to look for values, in resolution order\n * @param prefixes - The prefixes for values, in resolution order.\n * @param rootScopes - The root option scopes\n * @param fallback - Parent scopes fallback\n * @param getTarget - callback for getting the target for changed values\n * @returns Proxy\n * @private\n */ function _createResolver(scopes, prefixes = [\n ''\n], rootScopes, fallback, getTarget = ()=>scopes[0]) {\n const finalRootScopes = rootScopes || scopes;\n if (typeof fallback === 'undefined') {\n fallback = _resolve('_fallback', scopes);\n }\n const cache = {\n [Symbol.toStringTag]: 'Object',\n _cacheable: true,\n _scopes: scopes,\n _rootScopes: finalRootScopes,\n _fallback: fallback,\n _getTarget: getTarget,\n override: (scope)=>_createResolver([\n scope,\n ...scopes\n ], prefixes, finalRootScopes, fallback)\n };\n return new Proxy(cache, {\n /**\n * A trap for the delete operator.\n */ deleteProperty (target, prop) {\n delete target[prop]; // remove from cache\n delete target._keys; // remove cached keys\n delete scopes[0][prop]; // remove from top level scope\n return true;\n },\n /**\n * A trap for getting property values.\n */ get (target, prop) {\n return _cached(target, prop, ()=>_resolveWithPrefixes(prop, prefixes, scopes, target));\n },\n /**\n * A trap for Object.getOwnPropertyDescriptor.\n * Also used by Object.hasOwnProperty.\n */ getOwnPropertyDescriptor (target, prop) {\n return Reflect.getOwnPropertyDescriptor(target._scopes[0], prop);\n },\n /**\n * A trap for Object.getPrototypeOf.\n */ getPrototypeOf () {\n return Reflect.getPrototypeOf(scopes[0]);\n },\n /**\n * A trap for the in operator.\n */ has (target, prop) {\n return getKeysFromAllScopes(target).includes(prop);\n },\n /**\n * A trap for Object.getOwnPropertyNames and Object.getOwnPropertySymbols.\n */ ownKeys (target) {\n return getKeysFromAllScopes(target);\n },\n /**\n * A trap for setting property values.\n */ set (target, prop, value) {\n const storage = target._storage || (target._storage = getTarget());\n target[prop] = storage[prop] = value; // set to top level scope + cache\n delete target._keys; // remove cached keys\n return true;\n }\n });\n}\n/**\n * Returns an Proxy for resolving option values with context.\n * @param proxy - The Proxy returned by `_createResolver`\n * @param context - Context object for scriptable/indexable options\n * @param subProxy - The proxy provided for scriptable options\n * @param descriptorDefaults - Defaults for descriptors\n * @private\n */ function _attachContext(proxy, context, subProxy, descriptorDefaults) {\n const cache = {\n _cacheable: false,\n _proxy: proxy,\n _context: context,\n _subProxy: subProxy,\n _stack: new Set(),\n _descriptors: _descriptors(proxy, descriptorDefaults),\n setContext: (ctx)=>_attachContext(proxy, ctx, subProxy, descriptorDefaults),\n override: (scope)=>_attachContext(proxy.override(scope), context, subProxy, descriptorDefaults)\n };\n return new Proxy(cache, {\n /**\n * A trap for the delete operator.\n */ deleteProperty (target, prop) {\n delete target[prop]; // remove from cache\n delete proxy[prop]; // remove from proxy\n return true;\n },\n /**\n * A trap for getting property values.\n */ get (target, prop, receiver) {\n return _cached(target, prop, ()=>_resolveWithContext(target, prop, receiver));\n },\n /**\n * A trap for Object.getOwnPropertyDescriptor.\n * Also used by Object.hasOwnProperty.\n */ getOwnPropertyDescriptor (target, prop) {\n return target._descriptors.allKeys ? Reflect.has(proxy, prop) ? {\n enumerable: true,\n configurable: true\n } : undefined : Reflect.getOwnPropertyDescriptor(proxy, prop);\n },\n /**\n * A trap for Object.getPrototypeOf.\n */ getPrototypeOf () {\n return Reflect.getPrototypeOf(proxy);\n },\n /**\n * A trap for the in operator.\n */ has (target, prop) {\n return Reflect.has(proxy, prop);\n },\n /**\n * A trap for Object.getOwnPropertyNames and Object.getOwnPropertySymbols.\n */ ownKeys () {\n return Reflect.ownKeys(proxy);\n },\n /**\n * A trap for setting property values.\n */ set (target, prop, value) {\n proxy[prop] = value; // set to proxy\n delete target[prop]; // remove from cache\n return true;\n }\n });\n}\n/**\n * @private\n */ function _descriptors(proxy, defaults = {\n scriptable: true,\n indexable: true\n}) {\n const { _scriptable =defaults.scriptable , _indexable =defaults.indexable , _allKeys =defaults.allKeys } = proxy;\n return {\n allKeys: _allKeys,\n scriptable: _scriptable,\n indexable: _indexable,\n isScriptable: isFunction(_scriptable) ? _scriptable : ()=>_scriptable,\n isIndexable: isFunction(_indexable) ? _indexable : ()=>_indexable\n };\n}\nconst readKey = (prefix, name)=>prefix ? prefix + _capitalize(name) : name;\nconst needsSubResolver = (prop, value)=>isObject(value) && prop !== 'adapters' && (Object.getPrototypeOf(value) === null || value.constructor === Object);\nfunction _cached(target, prop, resolve) {\n if (Object.prototype.hasOwnProperty.call(target, prop) || prop === 'constructor') {\n return target[prop];\n }\n const value = resolve();\n // cache the resolved value\n target[prop] = value;\n return value;\n}\nfunction _resolveWithContext(target, prop, receiver) {\n const { _proxy , _context , _subProxy , _descriptors: descriptors } = target;\n let value = _proxy[prop]; // resolve from proxy\n // resolve with context\n if (isFunction(value) && descriptors.isScriptable(prop)) {\n value = _resolveScriptable(prop, value, target, receiver);\n }\n if (isArray(value) && value.length) {\n value = _resolveArray(prop, value, target, descriptors.isIndexable);\n }\n if (needsSubResolver(prop, value)) {\n // if the resolved value is an object, create a sub resolver for it\n value = _attachContext(value, _context, _subProxy && _subProxy[prop], descriptors);\n }\n return value;\n}\nfunction _resolveScriptable(prop, getValue, target, receiver) {\n const { _proxy , _context , _subProxy , _stack } = target;\n if (_stack.has(prop)) {\n throw new Error('Recursion detected: ' + Array.from(_stack).join('->') + '->' + prop);\n }\n _stack.add(prop);\n let value = getValue(_context, _subProxy || receiver);\n _stack.delete(prop);\n if (needsSubResolver(prop, value)) {\n // When scriptable option returns an object, create a resolver on that.\n value = createSubResolver(_proxy._scopes, _proxy, prop, value);\n }\n return value;\n}\nfunction _resolveArray(prop, value, target, isIndexable) {\n const { _proxy , _context , _subProxy , _descriptors: descriptors } = target;\n if (typeof _context.index !== 'undefined' && isIndexable(prop)) {\n return value[_context.index % value.length];\n } else if (isObject(value[0])) {\n // Array of objects, return array or resolvers\n const arr = value;\n const scopes = _proxy._scopes.filter((s)=>s !== arr);\n value = [];\n for (const item of arr){\n const resolver = createSubResolver(scopes, _proxy, prop, item);\n value.push(_attachContext(resolver, _context, _subProxy && _subProxy[prop], descriptors));\n }\n }\n return value;\n}\nfunction resolveFallback(fallback, prop, value) {\n return isFunction(fallback) ? fallback(prop, value) : fallback;\n}\nconst getScope = (key, parent)=>key === true ? parent : typeof key === 'string' ? resolveObjectKey(parent, key) : undefined;\nfunction addScopes(set, parentScopes, key, parentFallback, value) {\n for (const parent of parentScopes){\n const scope = getScope(key, parent);\n if (scope) {\n set.add(scope);\n const fallback = resolveFallback(scope._fallback, key, value);\n if (typeof fallback !== 'undefined' && fallback !== key && fallback !== parentFallback) {\n // When we reach the descriptor that defines a new _fallback, return that.\n // The fallback will resume to that new scope.\n return fallback;\n }\n } else if (scope === false && typeof parentFallback !== 'undefined' && key !== parentFallback) {\n // Fallback to `false` results to `false`, when falling back to different key.\n // For example `interaction` from `hover` or `plugins.tooltip` and `animation` from `animations`\n return null;\n }\n }\n return false;\n}\nfunction createSubResolver(parentScopes, resolver, prop, value) {\n const rootScopes = resolver._rootScopes;\n const fallback = resolveFallback(resolver._fallback, prop, value);\n const allScopes = [\n ...parentScopes,\n ...rootScopes\n ];\n const set = new Set();\n set.add(value);\n let key = addScopesFromKey(set, allScopes, prop, fallback || prop, value);\n if (key === null) {\n return false;\n }\n if (typeof fallback !== 'undefined' && fallback !== prop) {\n key = addScopesFromKey(set, allScopes, fallback, key, value);\n if (key === null) {\n return false;\n }\n }\n return _createResolver(Array.from(set), [\n ''\n ], rootScopes, fallback, ()=>subGetTarget(resolver, prop, value));\n}\nfunction addScopesFromKey(set, allScopes, key, fallback, item) {\n while(key){\n key = addScopes(set, allScopes, key, fallback, item);\n }\n return key;\n}\nfunction subGetTarget(resolver, prop, value) {\n const parent = resolver._getTarget();\n if (!(prop in parent)) {\n parent[prop] = {};\n }\n const target = parent[prop];\n if (isArray(target) && isObject(value)) {\n // For array of objects, the object is used to store updated values\n return value;\n }\n return target || {};\n}\nfunction _resolveWithPrefixes(prop, prefixes, scopes, proxy) {\n let value;\n for (const prefix of prefixes){\n value = _resolve(readKey(prefix, prop), scopes);\n if (typeof value !== 'undefined') {\n return needsSubResolver(prop, value) ? createSubResolver(scopes, proxy, prop, value) : value;\n }\n }\n}\nfunction _resolve(key, scopes) {\n for (const scope of scopes){\n if (!scope) {\n continue;\n }\n const value = scope[key];\n if (typeof value !== 'undefined') {\n return value;\n }\n }\n}\nfunction getKeysFromAllScopes(target) {\n let keys = target._keys;\n if (!keys) {\n keys = target._keys = resolveKeysFromAllScopes(target._scopes);\n }\n return keys;\n}\nfunction resolveKeysFromAllScopes(scopes) {\n const set = new Set();\n for (const scope of scopes){\n for (const key of Object.keys(scope).filter((k)=>!k.startsWith('_'))){\n set.add(key);\n }\n }\n return Array.from(set);\n}\nfunction _parseObjectDataRadialScale(meta, data, start, count) {\n const { iScale } = meta;\n const { key ='r' } = this._parsing;\n const parsed = new Array(count);\n let i, ilen, index, item;\n for(i = 0, ilen = count; i < ilen; ++i){\n index = i + start;\n item = data[index];\n parsed[i] = {\n r: iScale.parse(resolveObjectKey(item, key), index)\n };\n }\n return parsed;\n}\n\nconst EPSILON = Number.EPSILON || 1e-14;\nconst getPoint = (points, i)=>i < points.length && !points[i].skip && points[i];\nconst getValueAxis = (indexAxis)=>indexAxis === 'x' ? 'y' : 'x';\nfunction splineCurve(firstPoint, middlePoint, afterPoint, t) {\n // Props to Rob Spencer at scaled innovation for his post on splining between points\n // http://scaledinnovation.com/analytics/splines/aboutSplines.html\n // This function must also respect \"skipped\" points\n const previous = firstPoint.skip ? middlePoint : firstPoint;\n const current = middlePoint;\n const next = afterPoint.skip ? middlePoint : afterPoint;\n const d01 = distanceBetweenPoints(current, previous);\n const d12 = distanceBetweenPoints(next, current);\n let s01 = d01 / (d01 + d12);\n let s12 = d12 / (d01 + d12);\n // If all points are the same, s01 & s02 will be inf\n s01 = isNaN(s01) ? 0 : s01;\n s12 = isNaN(s12) ? 0 : s12;\n const fa = t * s01; // scaling factor for triangle Ta\n const fb = t * s12;\n return {\n previous: {\n x: current.x - fa * (next.x - previous.x),\n y: current.y - fa * (next.y - previous.y)\n },\n next: {\n x: current.x + fb * (next.x - previous.x),\n y: current.y + fb * (next.y - previous.y)\n }\n };\n}\n/**\n * Adjust tangents to ensure monotonic properties\n */ function monotoneAdjust(points, deltaK, mK) {\n const pointsLen = points.length;\n let alphaK, betaK, tauK, squaredMagnitude, pointCurrent;\n let pointAfter = getPoint(points, 0);\n for(let i = 0; i < pointsLen - 1; ++i){\n pointCurrent = pointAfter;\n pointAfter = getPoint(points, i + 1);\n if (!pointCurrent || !pointAfter) {\n continue;\n }\n if (almostEquals(deltaK[i], 0, EPSILON)) {\n mK[i] = mK[i + 1] = 0;\n continue;\n }\n alphaK = mK[i] / deltaK[i];\n betaK = mK[i + 1] / deltaK[i];\n squaredMagnitude = Math.pow(alphaK, 2) + Math.pow(betaK, 2);\n if (squaredMagnitude <= 9) {\n continue;\n }\n tauK = 3 / Math.sqrt(squaredMagnitude);\n mK[i] = alphaK * tauK * deltaK[i];\n mK[i + 1] = betaK * tauK * deltaK[i];\n }\n}\nfunction monotoneCompute(points, mK, indexAxis = 'x') {\n const valueAxis = getValueAxis(indexAxis);\n const pointsLen = points.length;\n let delta, pointBefore, pointCurrent;\n let pointAfter = getPoint(points, 0);\n for(let i = 0; i < pointsLen; ++i){\n pointBefore = pointCurrent;\n pointCurrent = pointAfter;\n pointAfter = getPoint(points, i + 1);\n if (!pointCurrent) {\n continue;\n }\n const iPixel = pointCurrent[indexAxis];\n const vPixel = pointCurrent[valueAxis];\n if (pointBefore) {\n delta = (iPixel - pointBefore[indexAxis]) / 3;\n pointCurrent[`cp1${indexAxis}`] = iPixel - delta;\n pointCurrent[`cp1${valueAxis}`] = vPixel - delta * mK[i];\n }\n if (pointAfter) {\n delta = (pointAfter[indexAxis] - iPixel) / 3;\n pointCurrent[`cp2${indexAxis}`] = iPixel + delta;\n pointCurrent[`cp2${valueAxis}`] = vPixel + delta * mK[i];\n }\n }\n}\n/**\n * This function calculates Bézier control points in a similar way than |splineCurve|,\n * but preserves monotonicity of the provided data and ensures no local extremums are added\n * between the dataset discrete points due to the interpolation.\n * See : https://en.wikipedia.org/wiki/Monotone_cubic_interpolation\n */ function splineCurveMonotone(points, indexAxis = 'x') {\n const valueAxis = getValueAxis(indexAxis);\n const pointsLen = points.length;\n const deltaK = Array(pointsLen).fill(0);\n const mK = Array(pointsLen);\n // Calculate slopes (deltaK) and initialize tangents (mK)\n let i, pointBefore, pointCurrent;\n let pointAfter = getPoint(points, 0);\n for(i = 0; i < pointsLen; ++i){\n pointBefore = pointCurrent;\n pointCurrent = pointAfter;\n pointAfter = getPoint(points, i + 1);\n if (!pointCurrent) {\n continue;\n }\n if (pointAfter) {\n const slopeDelta = pointAfter[indexAxis] - pointCurrent[indexAxis];\n // In the case of two points that appear at the same x pixel, slopeDeltaX is 0\n deltaK[i] = slopeDelta !== 0 ? (pointAfter[valueAxis] - pointCurrent[valueAxis]) / slopeDelta : 0;\n }\n mK[i] = !pointBefore ? deltaK[i] : !pointAfter ? deltaK[i - 1] : sign(deltaK[i - 1]) !== sign(deltaK[i]) ? 0 : (deltaK[i - 1] + deltaK[i]) / 2;\n }\n monotoneAdjust(points, deltaK, mK);\n monotoneCompute(points, mK, indexAxis);\n}\nfunction capControlPoint(pt, min, max) {\n return Math.max(Math.min(pt, max), min);\n}\nfunction capBezierPoints(points, area) {\n let i, ilen, point, inArea, inAreaPrev;\n let inAreaNext = _isPointInArea(points[0], area);\n for(i = 0, ilen = points.length; i < ilen; ++i){\n inAreaPrev = inArea;\n inArea = inAreaNext;\n inAreaNext = i < ilen - 1 && _isPointInArea(points[i + 1], area);\n if (!inArea) {\n continue;\n }\n point = points[i];\n if (inAreaPrev) {\n point.cp1x = capControlPoint(point.cp1x, area.left, area.right);\n point.cp1y = capControlPoint(point.cp1y, area.top, area.bottom);\n }\n if (inAreaNext) {\n point.cp2x = capControlPoint(point.cp2x, area.left, area.right);\n point.cp2y = capControlPoint(point.cp2y, area.top, area.bottom);\n }\n }\n}\n/**\n * @private\n */ function _updateBezierControlPoints(points, options, area, loop, indexAxis) {\n let i, ilen, point, controlPoints;\n // Only consider points that are drawn in case the spanGaps option is used\n if (options.spanGaps) {\n points = points.filter((pt)=>!pt.skip);\n }\n if (options.cubicInterpolationMode === 'monotone') {\n splineCurveMonotone(points, indexAxis);\n } else {\n let prev = loop ? points[points.length - 1] : points[0];\n for(i = 0, ilen = points.length; i < ilen; ++i){\n point = points[i];\n controlPoints = splineCurve(prev, point, points[Math.min(i + 1, ilen - (loop ? 0 : 1)) % ilen], options.tension);\n point.cp1x = controlPoints.previous.x;\n point.cp1y = controlPoints.previous.y;\n point.cp2x = controlPoints.next.x;\n point.cp2y = controlPoints.next.y;\n prev = point;\n }\n }\n if (options.capBezierPoints) {\n capBezierPoints(points, area);\n }\n}\n\n/**\n * Note: typedefs are auto-exported, so use a made-up `dom` namespace where\n * necessary to avoid duplicates with `export * from './helpers`; see\n * https://github.com/microsoft/TypeScript/issues/46011\n * @typedef { import('../core/core.controller.js').default } dom.Chart\n * @typedef { import('../../types').ChartEvent } ChartEvent\n */ /**\n * @private\n */ function _isDomSupported() {\n return typeof window !== 'undefined' && typeof document !== 'undefined';\n}\n/**\n * @private\n */ function _getParentNode(domNode) {\n let parent = domNode.parentNode;\n if (parent && parent.toString() === '[object ShadowRoot]') {\n parent = parent.host;\n }\n return parent;\n}\n/**\n * convert max-width/max-height values that may be percentages into a number\n * @private\n */ function parseMaxStyle(styleValue, node, parentProperty) {\n let valueInPixels;\n if (typeof styleValue === 'string') {\n valueInPixels = parseInt(styleValue, 10);\n if (styleValue.indexOf('%') !== -1) {\n // percentage * size in dimension\n valueInPixels = valueInPixels / 100 * node.parentNode[parentProperty];\n }\n } else {\n valueInPixels = styleValue;\n }\n return valueInPixels;\n}\nconst helpers_segment_getComputedStyle = (element)=>element.ownerDocument.defaultView.getComputedStyle(element, null);\nfunction getStyle(el, property) {\n return helpers_segment_getComputedStyle(el).getPropertyValue(property);\n}\nconst positions = [\n 'top',\n 'right',\n 'bottom',\n 'left'\n];\nfunction getPositionedStyle(styles, style, suffix) {\n const result = {};\n suffix = suffix ? '-' + suffix : '';\n for(let i = 0; i < 4; i++){\n const pos = positions[i];\n result[pos] = parseFloat(styles[style + '-' + pos + suffix]) || 0;\n }\n result.width = result.left + result.right;\n result.height = result.top + result.bottom;\n return result;\n}\nconst useOffsetPos = (x, y, target)=>(x > 0 || y > 0) && (!target || !target.shadowRoot);\n/**\n * @param e\n * @param canvas\n * @returns Canvas position\n */ function getCanvasPosition(e, canvas) {\n const touches = e.touches;\n const source = touches && touches.length ? touches[0] : e;\n const { offsetX , offsetY } = source;\n let box = false;\n let x, y;\n if (useOffsetPos(offsetX, offsetY, e.target)) {\n x = offsetX;\n y = offsetY;\n } else {\n const rect = canvas.getBoundingClientRect();\n x = source.clientX - rect.left;\n y = source.clientY - rect.top;\n box = true;\n }\n return {\n x,\n y,\n box\n };\n}\n/**\n * Gets an event's x, y coordinates, relative to the chart area\n * @param event\n * @param chart\n * @returns x and y coordinates of the event\n */ function getRelativePosition(event, chart) {\n if ('native' in event) {\n return event;\n }\n const { canvas , currentDevicePixelRatio } = chart;\n const style = helpers_segment_getComputedStyle(canvas);\n const borderBox = style.boxSizing === 'border-box';\n const paddings = getPositionedStyle(style, 'padding');\n const borders = getPositionedStyle(style, 'border', 'width');\n const { x , y , box } = getCanvasPosition(event, canvas);\n const xOffset = paddings.left + (box && borders.left);\n const yOffset = paddings.top + (box && borders.top);\n let { width , height } = chart;\n if (borderBox) {\n width -= paddings.width + borders.width;\n height -= paddings.height + borders.height;\n }\n return {\n x: Math.round((x - xOffset) / width * canvas.width / currentDevicePixelRatio),\n y: Math.round((y - yOffset) / height * canvas.height / currentDevicePixelRatio)\n };\n}\nfunction getContainerSize(canvas, width, height) {\n let maxWidth, maxHeight;\n if (width === undefined || height === undefined) {\n const container = canvas && _getParentNode(canvas);\n if (!container) {\n width = canvas.clientWidth;\n height = canvas.clientHeight;\n } else {\n const rect = container.getBoundingClientRect(); // this is the border box of the container\n const containerStyle = helpers_segment_getComputedStyle(container);\n const containerBorder = getPositionedStyle(containerStyle, 'border', 'width');\n const containerPadding = getPositionedStyle(containerStyle, 'padding');\n width = rect.width - containerPadding.width - containerBorder.width;\n height = rect.height - containerPadding.height - containerBorder.height;\n maxWidth = parseMaxStyle(containerStyle.maxWidth, container, 'clientWidth');\n maxHeight = parseMaxStyle(containerStyle.maxHeight, container, 'clientHeight');\n }\n }\n return {\n width,\n height,\n maxWidth: maxWidth || INFINITY,\n maxHeight: maxHeight || INFINITY\n };\n}\nconst round1 = (v)=>Math.round(v * 10) / 10;\n// eslint-disable-next-line complexity\nfunction getMaximumSize(canvas, bbWidth, bbHeight, aspectRatio) {\n const style = helpers_segment_getComputedStyle(canvas);\n const margins = getPositionedStyle(style, 'margin');\n const maxWidth = parseMaxStyle(style.maxWidth, canvas, 'clientWidth') || INFINITY;\n const maxHeight = parseMaxStyle(style.maxHeight, canvas, 'clientHeight') || INFINITY;\n const containerSize = getContainerSize(canvas, bbWidth, bbHeight);\n let { width , height } = containerSize;\n if (style.boxSizing === 'content-box') {\n const borders = getPositionedStyle(style, 'border', 'width');\n const paddings = getPositionedStyle(style, 'padding');\n width -= paddings.width + borders.width;\n height -= paddings.height + borders.height;\n }\n width = Math.max(0, width - margins.width);\n height = Math.max(0, aspectRatio ? width / aspectRatio : height - margins.height);\n width = round1(Math.min(width, maxWidth, containerSize.maxWidth));\n height = round1(Math.min(height, maxHeight, containerSize.maxHeight));\n if (width && !height) {\n // https://github.com/chartjs/Chart.js/issues/4659\n // If the canvas has width, but no height, default to aspectRatio of 2 (canvas default)\n height = round1(width / 2);\n }\n const maintainHeight = bbWidth !== undefined || bbHeight !== undefined;\n if (maintainHeight && aspectRatio && containerSize.height && height > containerSize.height) {\n height = containerSize.height;\n width = round1(Math.floor(height * aspectRatio));\n }\n return {\n width,\n height\n };\n}\n/**\n * @param chart\n * @param forceRatio\n * @param forceStyle\n * @returns True if the canvas context size or transformation has changed.\n */ function retinaScale(chart, forceRatio, forceStyle) {\n const pixelRatio = forceRatio || 1;\n const deviceHeight = Math.floor(chart.height * pixelRatio);\n const deviceWidth = Math.floor(chart.width * pixelRatio);\n chart.height = Math.floor(chart.height);\n chart.width = Math.floor(chart.width);\n const canvas = chart.canvas;\n // If no style has been set on the canvas, the render size is used as display size,\n // making the chart visually bigger, so let's enforce it to the \"correct\" values.\n // See https://github.com/chartjs/Chart.js/issues/3575\n if (canvas.style && (forceStyle || !canvas.style.height && !canvas.style.width)) {\n canvas.style.height = `${chart.height}px`;\n canvas.style.width = `${chart.width}px`;\n }\n if (chart.currentDevicePixelRatio !== pixelRatio || canvas.height !== deviceHeight || canvas.width !== deviceWidth) {\n chart.currentDevicePixelRatio = pixelRatio;\n canvas.height = deviceHeight;\n canvas.width = deviceWidth;\n chart.ctx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);\n return true;\n }\n return false;\n}\n/**\n * Detects support for options object argument in addEventListener.\n * https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#Safely_detecting_option_support\n * @private\n */ const supportsEventListenerOptions = function() {\n let passiveSupported = false;\n try {\n const options = {\n get passive () {\n passiveSupported = true;\n return false;\n }\n };\n if (_isDomSupported()) {\n window.addEventListener('test', null, options);\n window.removeEventListener('test', null, options);\n }\n } catch (e) {\n // continue regardless of error\n }\n return passiveSupported;\n}();\n/**\n * The \"used\" size is the final value of a dimension property after all calculations have\n * been performed. This method uses the computed style of `element` but returns undefined\n * if the computed style is not expressed in pixels. That can happen in some cases where\n * `element` has a size relative to its parent and this last one is not yet displayed,\n * for example because of `display: none` on a parent node.\n * @see https://developer.mozilla.org/en-US/docs/Web/CSS/used_value\n * @returns Size in pixels or undefined if unknown.\n */ function readUsedSize(element, property) {\n const value = getStyle(element, property);\n const matches = value && value.match(/^(\\d+)(\\.\\d+)?px$/);\n return matches ? +matches[1] : undefined;\n}\n\n/**\n * @private\n */ function _pointInLine(p1, p2, t, mode) {\n return {\n x: p1.x + t * (p2.x - p1.x),\n y: p1.y + t * (p2.y - p1.y)\n };\n}\n/**\n * @private\n */ function _steppedInterpolation(p1, p2, t, mode) {\n return {\n x: p1.x + t * (p2.x - p1.x),\n y: mode === 'middle' ? t < 0.5 ? p1.y : p2.y : mode === 'after' ? t < 1 ? p1.y : p2.y : t > 0 ? p2.y : p1.y\n };\n}\n/**\n * @private\n */ function _bezierInterpolation(p1, p2, t, mode) {\n const cp1 = {\n x: p1.cp2x,\n y: p1.cp2y\n };\n const cp2 = {\n x: p2.cp1x,\n y: p2.cp1y\n };\n const a = _pointInLine(p1, cp1, t);\n const b = _pointInLine(cp1, cp2, t);\n const c = _pointInLine(cp2, p2, t);\n const d = _pointInLine(a, b, t);\n const e = _pointInLine(b, c, t);\n return _pointInLine(d, e, t);\n}\n\nconst getRightToLeftAdapter = function(rectX, width) {\n return {\n x (x) {\n return rectX + rectX + width - x;\n },\n setWidth (w) {\n width = w;\n },\n textAlign (align) {\n if (align === 'center') {\n return align;\n }\n return align === 'right' ? 'left' : 'right';\n },\n xPlus (x, value) {\n return x - value;\n },\n leftForLtr (x, itemWidth) {\n return x - itemWidth;\n }\n };\n};\nconst getLeftToRightAdapter = function() {\n return {\n x (x) {\n return x;\n },\n setWidth (w) {},\n textAlign (align) {\n return align;\n },\n xPlus (x, value) {\n return x + value;\n },\n leftForLtr (x, _itemWidth) {\n return x;\n }\n };\n};\nfunction getRtlAdapter(rtl, rectX, width) {\n return rtl ? getRightToLeftAdapter(rectX, width) : getLeftToRightAdapter();\n}\nfunction overrideTextDirection(ctx, direction) {\n let style, original;\n if (direction === 'ltr' || direction === 'rtl') {\n style = ctx.canvas.style;\n original = [\n style.getPropertyValue('direction'),\n style.getPropertyPriority('direction')\n ];\n style.setProperty('direction', direction, 'important');\n ctx.prevTextDirection = original;\n }\n}\nfunction restoreTextDirection(ctx, original) {\n if (original !== undefined) {\n delete ctx.prevTextDirection;\n ctx.canvas.style.setProperty('direction', original[0], original[1]);\n }\n}\n\nfunction propertyFn(property) {\n if (property === 'angle') {\n return {\n between: _angleBetween,\n compare: _angleDiff,\n normalize: _normalizeAngle\n };\n }\n return {\n between: _isBetween,\n compare: (a, b)=>a - b,\n normalize: (x)=>x\n };\n}\nfunction normalizeSegment({ start , end , count , loop , style }) {\n return {\n start: start % count,\n end: end % count,\n loop: loop && (end - start + 1) % count === 0,\n style\n };\n}\nfunction getSegment(segment, points, bounds) {\n const { property , start: startBound , end: endBound } = bounds;\n const { between , normalize } = propertyFn(property);\n const count = points.length;\n let { start , end , loop } = segment;\n let i, ilen;\n if (loop) {\n start += count;\n end += count;\n for(i = 0, ilen = count; i < ilen; ++i){\n if (!between(normalize(points[start % count][property]), startBound, endBound)) {\n break;\n }\n start--;\n end--;\n }\n start %= count;\n end %= count;\n }\n if (end < start) {\n end += count;\n }\n return {\n start,\n end,\n loop,\n style: segment.style\n };\n}\n function _boundSegment(segment, points, bounds) {\n if (!bounds) {\n return [\n segment\n ];\n }\n const { property , start: startBound , end: endBound } = bounds;\n const count = points.length;\n const { compare , between , normalize } = propertyFn(property);\n const { start , end , loop , style } = getSegment(segment, points, bounds);\n const result = [];\n let inside = false;\n let subStart = null;\n let value, point, prevValue;\n const startIsBefore = ()=>between(startBound, prevValue, value) && compare(startBound, prevValue) !== 0;\n const endIsBefore = ()=>compare(endBound, value) === 0 || between(endBound, prevValue, value);\n const shouldStart = ()=>inside || startIsBefore();\n const shouldStop = ()=>!inside || endIsBefore();\n for(let i = start, prev = start; i <= end; ++i){\n point = points[i % count];\n if (point.skip) {\n continue;\n }\n value = normalize(point[property]);\n if (value === prevValue) {\n continue;\n }\n inside = between(value, startBound, endBound);\n if (subStart === null && shouldStart()) {\n subStart = compare(value, startBound) === 0 ? i : prev;\n }\n if (subStart !== null && shouldStop()) {\n result.push(normalizeSegment({\n start: subStart,\n end: i,\n loop,\n count,\n style\n }));\n subStart = null;\n }\n prev = i;\n prevValue = value;\n }\n if (subStart !== null) {\n result.push(normalizeSegment({\n start: subStart,\n end,\n loop,\n count,\n style\n }));\n }\n return result;\n}\n function _boundSegments(line, bounds) {\n const result = [];\n const segments = line.segments;\n for(let i = 0; i < segments.length; i++){\n const sub = _boundSegment(segments[i], line.points, bounds);\n if (sub.length) {\n result.push(...sub);\n }\n }\n return result;\n}\n function findStartAndEnd(points, count, loop, spanGaps) {\n let start = 0;\n let end = count - 1;\n if (loop && !spanGaps) {\n while(start < count && !points[start].skip){\n start++;\n }\n }\n while(start < count && points[start].skip){\n start++;\n }\n start %= count;\n if (loop) {\n end += start;\n }\n while(end > start && points[end % count].skip){\n end--;\n }\n end %= count;\n return {\n start,\n end\n };\n}\n function solidSegments(points, start, max, loop) {\n const count = points.length;\n const result = [];\n let last = start;\n let prev = points[start];\n let end;\n for(end = start + 1; end <= max; ++end){\n const cur = points[end % count];\n if (cur.skip || cur.stop) {\n if (!prev.skip) {\n loop = false;\n result.push({\n start: start % count,\n end: (end - 1) % count,\n loop\n });\n start = last = cur.stop ? end : null;\n }\n } else {\n last = end;\n if (prev.skip) {\n start = end;\n }\n }\n prev = cur;\n }\n if (last !== null) {\n result.push({\n start: start % count,\n end: last % count,\n loop\n });\n }\n return result;\n}\n function _computeSegments(line, segmentOptions) {\n const points = line.points;\n const spanGaps = line.options.spanGaps;\n const count = points.length;\n if (!count) {\n return [];\n }\n const loop = !!line._loop;\n const { start , end } = findStartAndEnd(points, count, loop, spanGaps);\n if (spanGaps === true) {\n return splitByStyles(line, [\n {\n start,\n end,\n loop\n }\n ], points, segmentOptions);\n }\n const max = end < start ? end + count : end;\n const completeLoop = !!line._fullLoop && start === 0 && end === count - 1;\n return splitByStyles(line, solidSegments(points, start, max, completeLoop), points, segmentOptions);\n}\n function splitByStyles(line, segments, points, segmentOptions) {\n if (!segmentOptions || !segmentOptions.setContext || !points) {\n return segments;\n }\n return doSplitByStyles(line, segments, points, segmentOptions);\n}\n function doSplitByStyles(line, segments, points, segmentOptions) {\n const chartContext = line._chart.getContext();\n const baseStyle = readStyle(line.options);\n const { _datasetIndex: datasetIndex , options: { spanGaps } } = line;\n const count = points.length;\n const result = [];\n let prevStyle = baseStyle;\n let start = segments[0].start;\n let i = start;\n function addStyle(s, e, l, st) {\n const dir = spanGaps ? -1 : 1;\n if (s === e) {\n return;\n }\n s += count;\n while(points[s % count].skip){\n s -= dir;\n }\n while(points[e % count].skip){\n e += dir;\n }\n if (s % count !== e % count) {\n result.push({\n start: s % count,\n end: e % count,\n loop: l,\n style: st\n });\n prevStyle = st;\n start = e % count;\n }\n }\n for (const segment of segments){\n start = spanGaps ? start : segment.start;\n let prev = points[start % count];\n let style;\n for(i = start + 1; i <= segment.end; i++){\n const pt = points[i % count];\n style = readStyle(segmentOptions.setContext(createContext(chartContext, {\n type: 'segment',\n p0: prev,\n p1: pt,\n p0DataIndex: (i - 1) % count,\n p1DataIndex: i % count,\n datasetIndex\n })));\n if (styleChanged(style, prevStyle)) {\n addStyle(start, i - 1, segment.loop, prevStyle);\n }\n prev = pt;\n prevStyle = style;\n }\n if (start < i - 1) {\n addStyle(start, i - 1, segment.loop, prevStyle);\n }\n }\n return result;\n}\nfunction readStyle(options) {\n return {\n backgroundColor: options.backgroundColor,\n borderCapStyle: options.borderCapStyle,\n borderDash: options.borderDash,\n borderDashOffset: options.borderDashOffset,\n borderJoinStyle: options.borderJoinStyle,\n borderWidth: options.borderWidth,\n borderColor: options.borderColor\n };\n}\nfunction styleChanged(style, prevStyle) {\n if (!prevStyle) {\n return false;\n }\n const cache = [];\n const replacer = function(key, value) {\n if (!isPatternOrGradient(value)) {\n return value;\n }\n if (!cache.includes(value)) {\n cache.push(value);\n }\n return cache.indexOf(value);\n };\n return JSON.stringify(style, replacer) !== JSON.stringify(prevStyle, replacer);\n}\n\n\n//# sourceMappingURL=helpers.segment.js.map\n\n;// ./node_modules/chart.js/dist/chart.js\n/*!\n * Chart.js v4.4.4\n * https://www.chartjs.org\n * (c) 2024 Chart.js Contributors\n * Released under the MIT License\n */\n\n\n\nclass Animator {\n constructor(){\n this._request = null;\n this._charts = new Map();\n this._running = false;\n this._lastDate = undefined;\n }\n _notify(chart, anims, date, type) {\n const callbacks = anims.listeners[type];\n const numSteps = anims.duration;\n callbacks.forEach((fn)=>fn({\n chart,\n initial: anims.initial,\n numSteps,\n currentStep: Math.min(date - anims.start, numSteps)\n }));\n }\n _refresh() {\n if (this._request) {\n return;\n }\n this._running = true;\n this._request = requestAnimFrame.call(window, ()=>{\n this._update();\n this._request = null;\n if (this._running) {\n this._refresh();\n }\n });\n }\n _update(date = Date.now()) {\n let remaining = 0;\n this._charts.forEach((anims, chart)=>{\n if (!anims.running || !anims.items.length) {\n return;\n }\n const items = anims.items;\n let i = items.length - 1;\n let draw = false;\n let item;\n for(; i >= 0; --i){\n item = items[i];\n if (item._active) {\n if (item._total > anims.duration) {\n anims.duration = item._total;\n }\n item.tick(date);\n draw = true;\n } else {\n items[i] = items[items.length - 1];\n items.pop();\n }\n }\n if (draw) {\n chart.draw();\n this._notify(chart, anims, date, 'progress');\n }\n if (!items.length) {\n anims.running = false;\n this._notify(chart, anims, date, 'complete');\n anims.initial = false;\n }\n remaining += items.length;\n });\n this._lastDate = date;\n if (remaining === 0) {\n this._running = false;\n }\n }\n _getAnims(chart) {\n const charts = this._charts;\n let anims = charts.get(chart);\n if (!anims) {\n anims = {\n running: false,\n initial: true,\n items: [],\n listeners: {\n complete: [],\n progress: []\n }\n };\n charts.set(chart, anims);\n }\n return anims;\n }\n listen(chart, event, cb) {\n this._getAnims(chart).listeners[event].push(cb);\n }\n add(chart, items) {\n if (!items || !items.length) {\n return;\n }\n this._getAnims(chart).items.push(...items);\n }\n has(chart) {\n return this._getAnims(chart).items.length > 0;\n }\n start(chart) {\n const anims = this._charts.get(chart);\n if (!anims) {\n return;\n }\n anims.running = true;\n anims.start = Date.now();\n anims.duration = anims.items.reduce((acc, cur)=>Math.max(acc, cur._duration), 0);\n this._refresh();\n }\n running(chart) {\n if (!this._running) {\n return false;\n }\n const anims = this._charts.get(chart);\n if (!anims || !anims.running || !anims.items.length) {\n return false;\n }\n return true;\n }\n stop(chart) {\n const anims = this._charts.get(chart);\n if (!anims || !anims.items.length) {\n return;\n }\n const items = anims.items;\n let i = items.length - 1;\n for(; i >= 0; --i){\n items[i].cancel();\n }\n anims.items = [];\n this._notify(chart, anims, Date.now(), 'complete');\n }\n remove(chart) {\n return this._charts.delete(chart);\n }\n}\nvar animator = /* #__PURE__ */ new Animator();\n\nconst transparent = 'transparent';\nconst interpolators = {\n boolean (from, to, factor) {\n return factor > 0.5 ? to : from;\n },\n color (from, to, factor) {\n const c0 = color(from || transparent);\n const c1 = c0.valid && color(to || transparent);\n return c1 && c1.valid ? c1.mix(c0, factor).hexString() : to;\n },\n number (from, to, factor) {\n return from + (to - from) * factor;\n }\n};\nclass Animation {\n constructor(cfg, target, prop, to){\n const currentValue = target[prop];\n to = resolve([\n cfg.to,\n to,\n currentValue,\n cfg.from\n ]);\n const from = resolve([\n cfg.from,\n currentValue,\n to\n ]);\n this._active = true;\n this._fn = cfg.fn || interpolators[cfg.type || typeof from];\n this._easing = effects[cfg.easing] || effects.linear;\n this._start = Math.floor(Date.now() + (cfg.delay || 0));\n this._duration = this._total = Math.floor(cfg.duration);\n this._loop = !!cfg.loop;\n this._target = target;\n this._prop = prop;\n this._from = from;\n this._to = to;\n this._promises = undefined;\n }\n active() {\n return this._active;\n }\n update(cfg, to, date) {\n if (this._active) {\n this._notify(false);\n const currentValue = this._target[this._prop];\n const elapsed = date - this._start;\n const remain = this._duration - elapsed;\n this._start = date;\n this._duration = Math.floor(Math.max(remain, cfg.duration));\n this._total += elapsed;\n this._loop = !!cfg.loop;\n this._to = resolve([\n cfg.to,\n to,\n currentValue,\n cfg.from\n ]);\n this._from = resolve([\n cfg.from,\n currentValue,\n to\n ]);\n }\n }\n cancel() {\n if (this._active) {\n this.tick(Date.now());\n this._active = false;\n this._notify(false);\n }\n }\n tick(date) {\n const elapsed = date - this._start;\n const duration = this._duration;\n const prop = this._prop;\n const from = this._from;\n const loop = this._loop;\n const to = this._to;\n let factor;\n this._active = from !== to && (loop || elapsed < duration);\n if (!this._active) {\n this._target[prop] = to;\n this._notify(true);\n return;\n }\n if (elapsed < 0) {\n this._target[prop] = from;\n return;\n }\n factor = elapsed / duration % 2;\n factor = loop && factor > 1 ? 2 - factor : factor;\n factor = this._easing(Math.min(1, Math.max(0, factor)));\n this._target[prop] = this._fn(from, to, factor);\n }\n wait() {\n const promises = this._promises || (this._promises = []);\n return new Promise((res, rej)=>{\n promises.push({\n res,\n rej\n });\n });\n }\n _notify(resolved) {\n const method = resolved ? 'res' : 'rej';\n const promises = this._promises || [];\n for(let i = 0; i < promises.length; i++){\n promises[i][method]();\n }\n }\n}\n\nclass Animations {\n constructor(chart, config){\n this._chart = chart;\n this._properties = new Map();\n this.configure(config);\n }\n configure(config) {\n if (!isObject(config)) {\n return;\n }\n const animationOptions = Object.keys(defaults.animation);\n const animatedProps = this._properties;\n Object.getOwnPropertyNames(config).forEach((key)=>{\n const cfg = config[key];\n if (!isObject(cfg)) {\n return;\n }\n const resolved = {};\n for (const option of animationOptions){\n resolved[option] = cfg[option];\n }\n (isArray(cfg.properties) && cfg.properties || [\n key\n ]).forEach((prop)=>{\n if (prop === key || !animatedProps.has(prop)) {\n animatedProps.set(prop, resolved);\n }\n });\n });\n }\n _animateOptions(target, values) {\n const newOptions = values.options;\n const options = resolveTargetOptions(target, newOptions);\n if (!options) {\n return [];\n }\n const animations = this._createAnimations(options, newOptions);\n if (newOptions.$shared) {\n awaitAll(target.options.$animations, newOptions).then(()=>{\n target.options = newOptions;\n }, ()=>{\n });\n }\n return animations;\n }\n _createAnimations(target, values) {\n const animatedProps = this._properties;\n const animations = [];\n const running = target.$animations || (target.$animations = {});\n const props = Object.keys(values);\n const date = Date.now();\n let i;\n for(i = props.length - 1; i >= 0; --i){\n const prop = props[i];\n if (prop.charAt(0) === '$') {\n continue;\n }\n if (prop === 'options') {\n animations.push(...this._animateOptions(target, values));\n continue;\n }\n const value = values[prop];\n let animation = running[prop];\n const cfg = animatedProps.get(prop);\n if (animation) {\n if (cfg && animation.active()) {\n animation.update(cfg, value, date);\n continue;\n } else {\n animation.cancel();\n }\n }\n if (!cfg || !cfg.duration) {\n target[prop] = value;\n continue;\n }\n running[prop] = animation = new Animation(cfg, target, prop, value);\n animations.push(animation);\n }\n return animations;\n }\n update(target, values) {\n if (this._properties.size === 0) {\n Object.assign(target, values);\n return;\n }\n const animations = this._createAnimations(target, values);\n if (animations.length) {\n animator.add(this._chart, animations);\n return true;\n }\n }\n}\nfunction awaitAll(animations, properties) {\n const running = [];\n const keys = Object.keys(properties);\n for(let i = 0; i < keys.length; i++){\n const anim = animations[keys[i]];\n if (anim && anim.active()) {\n running.push(anim.wait());\n }\n }\n return Promise.all(running);\n}\nfunction resolveTargetOptions(target, newOptions) {\n if (!newOptions) {\n return;\n }\n let options = target.options;\n if (!options) {\n target.options = newOptions;\n return;\n }\n if (options.$shared) {\n target.options = options = Object.assign({}, options, {\n $shared: false,\n $animations: {}\n });\n }\n return options;\n}\n\nfunction scaleClip(scale, allowedOverflow) {\n const opts = scale && scale.options || {};\n const reverse = opts.reverse;\n const min = opts.min === undefined ? allowedOverflow : 0;\n const max = opts.max === undefined ? allowedOverflow : 0;\n return {\n start: reverse ? max : min,\n end: reverse ? min : max\n };\n}\nfunction defaultClip(xScale, yScale, allowedOverflow) {\n if (allowedOverflow === false) {\n return false;\n }\n const x = scaleClip(xScale, allowedOverflow);\n const y = scaleClip(yScale, allowedOverflow);\n return {\n top: y.end,\n right: x.end,\n bottom: y.start,\n left: x.start\n };\n}\nfunction toClip(value) {\n let t, r, b, l;\n if (isObject(value)) {\n t = value.top;\n r = value.right;\n b = value.bottom;\n l = value.left;\n } else {\n t = r = b = l = value;\n }\n return {\n top: t,\n right: r,\n bottom: b,\n left: l,\n disabled: value === false\n };\n}\nfunction getSortedDatasetIndices(chart, filterVisible) {\n const keys = [];\n const metasets = chart._getSortedDatasetMetas(filterVisible);\n let i, ilen;\n for(i = 0, ilen = metasets.length; i < ilen; ++i){\n keys.push(metasets[i].index);\n }\n return keys;\n}\nfunction applyStack(stack, value, dsIndex, options = {}) {\n const keys = stack.keys;\n const singleMode = options.mode === 'single';\n let i, ilen, datasetIndex, otherValue;\n if (value === null) {\n return;\n }\n for(i = 0, ilen = keys.length; i < ilen; ++i){\n datasetIndex = +keys[i];\n if (datasetIndex === dsIndex) {\n if (options.all) {\n continue;\n }\n break;\n }\n otherValue = stack.values[datasetIndex];\n if (isNumberFinite(otherValue) && (singleMode || value === 0 || sign(value) === sign(otherValue))) {\n value += otherValue;\n }\n }\n return value;\n}\nfunction convertObjectDataToArray(data, meta) {\n const { iScale , vScale } = meta;\n const iAxisKey = iScale.axis === 'x' ? 'x' : 'y';\n const vAxisKey = vScale.axis === 'x' ? 'x' : 'y';\n const keys = Object.keys(data);\n const adata = new Array(keys.length);\n let i, ilen, key;\n for(i = 0, ilen = keys.length; i < ilen; ++i){\n key = keys[i];\n adata[i] = {\n [iAxisKey]: key,\n [vAxisKey]: data[key]\n };\n }\n return adata;\n}\nfunction isStacked(scale, meta) {\n const stacked = scale && scale.options.stacked;\n return stacked || stacked === undefined && meta.stack !== undefined;\n}\nfunction getStackKey(indexScale, valueScale, meta) {\n return `${indexScale.id}.${valueScale.id}.${meta.stack || meta.type}`;\n}\nfunction getUserBounds(scale) {\n const { min , max , minDefined , maxDefined } = scale.getUserBounds();\n return {\n min: minDefined ? min : Number.NEGATIVE_INFINITY,\n max: maxDefined ? max : Number.POSITIVE_INFINITY\n };\n}\nfunction getOrCreateStack(stacks, stackKey, indexValue) {\n const subStack = stacks[stackKey] || (stacks[stackKey] = {});\n return subStack[indexValue] || (subStack[indexValue] = {});\n}\nfunction getLastIndexInStack(stack, vScale, positive, type) {\n for (const meta of vScale.getMatchingVisibleMetas(type).reverse()){\n const value = stack[meta.index];\n if (positive && value > 0 || !positive && value < 0) {\n return meta.index;\n }\n }\n return null;\n}\nfunction updateStacks(controller, parsed) {\n const { chart , _cachedMeta: meta } = controller;\n const stacks = chart._stacks || (chart._stacks = {});\n const { iScale , vScale , index: datasetIndex } = meta;\n const iAxis = iScale.axis;\n const vAxis = vScale.axis;\n const key = getStackKey(iScale, vScale, meta);\n const ilen = parsed.length;\n let stack;\n for(let i = 0; i < ilen; ++i){\n const item = parsed[i];\n const { [iAxis]: index , [vAxis]: value } = item;\n const itemStacks = item._stacks || (item._stacks = {});\n stack = itemStacks[vAxis] = getOrCreateStack(stacks, key, index);\n stack[datasetIndex] = value;\n stack._top = getLastIndexInStack(stack, vScale, true, meta.type);\n stack._bottom = getLastIndexInStack(stack, vScale, false, meta.type);\n const visualValues = stack._visualValues || (stack._visualValues = {});\n visualValues[datasetIndex] = value;\n }\n}\nfunction getFirstScaleId(chart, axis) {\n const scales = chart.scales;\n return Object.keys(scales).filter((key)=>scales[key].axis === axis).shift();\n}\nfunction createDatasetContext(parent, index) {\n return createContext(parent, {\n active: false,\n dataset: undefined,\n datasetIndex: index,\n index,\n mode: 'default',\n type: 'dataset'\n });\n}\nfunction createDataContext(parent, index, element) {\n return createContext(parent, {\n active: false,\n dataIndex: index,\n parsed: undefined,\n raw: undefined,\n element,\n index,\n mode: 'default',\n type: 'data'\n });\n}\nfunction clearStacks(meta, items) {\n const datasetIndex = meta.controller.index;\n const axis = meta.vScale && meta.vScale.axis;\n if (!axis) {\n return;\n }\n items = items || meta._parsed;\n for (const parsed of items){\n const stacks = parsed._stacks;\n if (!stacks || stacks[axis] === undefined || stacks[axis][datasetIndex] === undefined) {\n return;\n }\n delete stacks[axis][datasetIndex];\n if (stacks[axis]._visualValues !== undefined && stacks[axis]._visualValues[datasetIndex] !== undefined) {\n delete stacks[axis]._visualValues[datasetIndex];\n }\n }\n}\nconst isDirectUpdateMode = (mode)=>mode === 'reset' || mode === 'none';\nconst cloneIfNotShared = (cached, shared)=>shared ? cached : Object.assign({}, cached);\nconst createStack = (canStack, meta, chart)=>canStack && !meta.hidden && meta._stacked && {\n keys: getSortedDatasetIndices(chart, true),\n values: null\n };\nclass DatasetController {\n static defaults = {};\n static datasetElementType = null;\n static dataElementType = null;\n constructor(chart, datasetIndex){\n this.chart = chart;\n this._ctx = chart.ctx;\n this.index = datasetIndex;\n this._cachedDataOpts = {};\n this._cachedMeta = this.getMeta();\n this._type = this._cachedMeta.type;\n this.options = undefined;\n this._parsing = false;\n this._data = undefined;\n this._objectData = undefined;\n this._sharedOptions = undefined;\n this._drawStart = undefined;\n this._drawCount = undefined;\n this.enableOptionSharing = false;\n this.supportsDecimation = false;\n this.$context = undefined;\n this._syncList = [];\n this.datasetElementType = new.target.datasetElementType;\n this.dataElementType = new.target.dataElementType;\n this.initialize();\n }\n initialize() {\n const meta = this._cachedMeta;\n this.configure();\n this.linkScales();\n meta._stacked = isStacked(meta.vScale, meta);\n this.addElements();\n if (this.options.fill && !this.chart.isPluginEnabled('filler')) {\n console.warn(\"Tried to use the 'fill' option without the 'Filler' plugin enabled. Please import and register the 'Filler' plugin and make sure it is not disabled in the options\");\n }\n }\n updateIndex(datasetIndex) {\n if (this.index !== datasetIndex) {\n clearStacks(this._cachedMeta);\n }\n this.index = datasetIndex;\n }\n linkScales() {\n const chart = this.chart;\n const meta = this._cachedMeta;\n const dataset = this.getDataset();\n const chooseId = (axis, x, y, r)=>axis === 'x' ? x : axis === 'r' ? r : y;\n const xid = meta.xAxisID = valueOrDefault(dataset.xAxisID, getFirstScaleId(chart, 'x'));\n const yid = meta.yAxisID = valueOrDefault(dataset.yAxisID, getFirstScaleId(chart, 'y'));\n const rid = meta.rAxisID = valueOrDefault(dataset.rAxisID, getFirstScaleId(chart, 'r'));\n const indexAxis = meta.indexAxis;\n const iid = meta.iAxisID = chooseId(indexAxis, xid, yid, rid);\n const vid = meta.vAxisID = chooseId(indexAxis, yid, xid, rid);\n meta.xScale = this.getScaleForId(xid);\n meta.yScale = this.getScaleForId(yid);\n meta.rScale = this.getScaleForId(rid);\n meta.iScale = this.getScaleForId(iid);\n meta.vScale = this.getScaleForId(vid);\n }\n getDataset() {\n return this.chart.data.datasets[this.index];\n }\n getMeta() {\n return this.chart.getDatasetMeta(this.index);\n }\n getScaleForId(scaleID) {\n return this.chart.scales[scaleID];\n }\n _getOtherScale(scale) {\n const meta = this._cachedMeta;\n return scale === meta.iScale ? meta.vScale : meta.iScale;\n }\n reset() {\n this._update('reset');\n }\n _destroy() {\n const meta = this._cachedMeta;\n if (this._data) {\n unlistenArrayEvents(this._data, this);\n }\n if (meta._stacked) {\n clearStacks(meta);\n }\n }\n _dataCheck() {\n const dataset = this.getDataset();\n const data = dataset.data || (dataset.data = []);\n const _data = this._data;\n if (isObject(data)) {\n const meta = this._cachedMeta;\n this._data = convertObjectDataToArray(data, meta);\n } else if (_data !== data) {\n if (_data) {\n unlistenArrayEvents(_data, this);\n const meta = this._cachedMeta;\n clearStacks(meta);\n meta._parsed = [];\n }\n if (data && Object.isExtensible(data)) {\n listenArrayEvents(data, this);\n }\n this._syncList = [];\n this._data = data;\n }\n }\n addElements() {\n const meta = this._cachedMeta;\n this._dataCheck();\n if (this.datasetElementType) {\n meta.dataset = new this.datasetElementType();\n }\n }\n buildOrUpdateElements(resetNewElements) {\n const meta = this._cachedMeta;\n const dataset = this.getDataset();\n let stackChanged = false;\n this._dataCheck();\n const oldStacked = meta._stacked;\n meta._stacked = isStacked(meta.vScale, meta);\n if (meta.stack !== dataset.stack) {\n stackChanged = true;\n clearStacks(meta);\n meta.stack = dataset.stack;\n }\n this._resyncElements(resetNewElements);\n if (stackChanged || oldStacked !== meta._stacked) {\n updateStacks(this, meta._parsed);\n }\n }\n configure() {\n const config = this.chart.config;\n const scopeKeys = config.datasetScopeKeys(this._type);\n const scopes = config.getOptionScopes(this.getDataset(), scopeKeys, true);\n this.options = config.createResolver(scopes, this.getContext());\n this._parsing = this.options.parsing;\n this._cachedDataOpts = {};\n }\n parse(start, count) {\n const { _cachedMeta: meta , _data: data } = this;\n const { iScale , _stacked } = meta;\n const iAxis = iScale.axis;\n let sorted = start === 0 && count === data.length ? true : meta._sorted;\n let prev = start > 0 && meta._parsed[start - 1];\n let i, cur, parsed;\n if (this._parsing === false) {\n meta._parsed = data;\n meta._sorted = true;\n parsed = data;\n } else {\n if (isArray(data[start])) {\n parsed = this.parseArrayData(meta, data, start, count);\n } else if (isObject(data[start])) {\n parsed = this.parseObjectData(meta, data, start, count);\n } else {\n parsed = this.parsePrimitiveData(meta, data, start, count);\n }\n const isNotInOrderComparedToPrev = ()=>cur[iAxis] === null || prev && cur[iAxis] < prev[iAxis];\n for(i = 0; i < count; ++i){\n meta._parsed[i + start] = cur = parsed[i];\n if (sorted) {\n if (isNotInOrderComparedToPrev()) {\n sorted = false;\n }\n prev = cur;\n }\n }\n meta._sorted = sorted;\n }\n if (_stacked) {\n updateStacks(this, parsed);\n }\n }\n parsePrimitiveData(meta, data, start, count) {\n const { iScale , vScale } = meta;\n const iAxis = iScale.axis;\n const vAxis = vScale.axis;\n const labels = iScale.getLabels();\n const singleScale = iScale === vScale;\n const parsed = new Array(count);\n let i, ilen, index;\n for(i = 0, ilen = count; i < ilen; ++i){\n index = i + start;\n parsed[i] = {\n [iAxis]: singleScale || iScale.parse(labels[index], index),\n [vAxis]: vScale.parse(data[index], index)\n };\n }\n return parsed;\n }\n parseArrayData(meta, data, start, count) {\n const { xScale , yScale } = meta;\n const parsed = new Array(count);\n let i, ilen, index, item;\n for(i = 0, ilen = count; i < ilen; ++i){\n index = i + start;\n item = data[index];\n parsed[i] = {\n x: xScale.parse(item[0], index),\n y: yScale.parse(item[1], index)\n };\n }\n return parsed;\n }\n parseObjectData(meta, data, start, count) {\n const { xScale , yScale } = meta;\n const { xAxisKey ='x' , yAxisKey ='y' } = this._parsing;\n const parsed = new Array(count);\n let i, ilen, index, item;\n for(i = 0, ilen = count; i < ilen; ++i){\n index = i + start;\n item = data[index];\n parsed[i] = {\n x: xScale.parse(resolveObjectKey(item, xAxisKey), index),\n y: yScale.parse(resolveObjectKey(item, yAxisKey), index)\n };\n }\n return parsed;\n }\n getParsed(index) {\n return this._cachedMeta._parsed[index];\n }\n getDataElement(index) {\n return this._cachedMeta.data[index];\n }\n applyStack(scale, parsed, mode) {\n const chart = this.chart;\n const meta = this._cachedMeta;\n const value = parsed[scale.axis];\n const stack = {\n keys: getSortedDatasetIndices(chart, true),\n values: parsed._stacks[scale.axis]._visualValues\n };\n return applyStack(stack, value, meta.index, {\n mode\n });\n }\n updateRangeFromParsed(range, scale, parsed, stack) {\n const parsedValue = parsed[scale.axis];\n let value = parsedValue === null ? NaN : parsedValue;\n const values = stack && parsed._stacks[scale.axis];\n if (stack && values) {\n stack.values = values;\n value = applyStack(stack, parsedValue, this._cachedMeta.index);\n }\n range.min = Math.min(range.min, value);\n range.max = Math.max(range.max, value);\n }\n getMinMax(scale, canStack) {\n const meta = this._cachedMeta;\n const _parsed = meta._parsed;\n const sorted = meta._sorted && scale === meta.iScale;\n const ilen = _parsed.length;\n const otherScale = this._getOtherScale(scale);\n const stack = createStack(canStack, meta, this.chart);\n const range = {\n min: Number.POSITIVE_INFINITY,\n max: Number.NEGATIVE_INFINITY\n };\n const { min: otherMin , max: otherMax } = getUserBounds(otherScale);\n let i, parsed;\n function _skip() {\n parsed = _parsed[i];\n const otherValue = parsed[otherScale.axis];\n return !isNumberFinite(parsed[scale.axis]) || otherMin > otherValue || otherMax < otherValue;\n }\n for(i = 0; i < ilen; ++i){\n if (_skip()) {\n continue;\n }\n this.updateRangeFromParsed(range, scale, parsed, stack);\n if (sorted) {\n break;\n }\n }\n if (sorted) {\n for(i = ilen - 1; i >= 0; --i){\n if (_skip()) {\n continue;\n }\n this.updateRangeFromParsed(range, scale, parsed, stack);\n break;\n }\n }\n return range;\n }\n getAllParsedValues(scale) {\n const parsed = this._cachedMeta._parsed;\n const values = [];\n let i, ilen, value;\n for(i = 0, ilen = parsed.length; i < ilen; ++i){\n value = parsed[i][scale.axis];\n if (isNumberFinite(value)) {\n values.push(value);\n }\n }\n return values;\n }\n getMaxOverflow() {\n return false;\n }\n getLabelAndValue(index) {\n const meta = this._cachedMeta;\n const iScale = meta.iScale;\n const vScale = meta.vScale;\n const parsed = this.getParsed(index);\n return {\n label: iScale ? '' + iScale.getLabelForValue(parsed[iScale.axis]) : '',\n value: vScale ? '' + vScale.getLabelForValue(parsed[vScale.axis]) : ''\n };\n }\n _update(mode) {\n const meta = this._cachedMeta;\n this.update(mode || 'default');\n meta._clip = toClip(valueOrDefault(this.options.clip, defaultClip(meta.xScale, meta.yScale, this.getMaxOverflow())));\n }\n update(mode) {}\n draw() {\n const ctx = this._ctx;\n const chart = this.chart;\n const meta = this._cachedMeta;\n const elements = meta.data || [];\n const area = chart.chartArea;\n const active = [];\n const start = this._drawStart || 0;\n const count = this._drawCount || elements.length - start;\n const drawActiveElementsOnTop = this.options.drawActiveElementsOnTop;\n let i;\n if (meta.dataset) {\n meta.dataset.draw(ctx, area, start, count);\n }\n for(i = start; i < start + count; ++i){\n const element = elements[i];\n if (element.hidden) {\n continue;\n }\n if (element.active && drawActiveElementsOnTop) {\n active.push(element);\n } else {\n element.draw(ctx, area);\n }\n }\n for(i = 0; i < active.length; ++i){\n active[i].draw(ctx, area);\n }\n }\n getStyle(index, active) {\n const mode = active ? 'active' : 'default';\n return index === undefined && this._cachedMeta.dataset ? this.resolveDatasetElementOptions(mode) : this.resolveDataElementOptions(index || 0, mode);\n }\n getContext(index, active, mode) {\n const dataset = this.getDataset();\n let context;\n if (index >= 0 && index < this._cachedMeta.data.length) {\n const element = this._cachedMeta.data[index];\n context = element.$context || (element.$context = createDataContext(this.getContext(), index, element));\n context.parsed = this.getParsed(index);\n context.raw = dataset.data[index];\n context.index = context.dataIndex = index;\n } else {\n context = this.$context || (this.$context = createDatasetContext(this.chart.getContext(), this.index));\n context.dataset = dataset;\n context.index = context.datasetIndex = this.index;\n }\n context.active = !!active;\n context.mode = mode;\n return context;\n }\n resolveDatasetElementOptions(mode) {\n return this._resolveElementOptions(this.datasetElementType.id, mode);\n }\n resolveDataElementOptions(index, mode) {\n return this._resolveElementOptions(this.dataElementType.id, mode, index);\n }\n _resolveElementOptions(elementType, mode = 'default', index) {\n const active = mode === 'active';\n const cache = this._cachedDataOpts;\n const cacheKey = elementType + '-' + mode;\n const cached = cache[cacheKey];\n const sharing = this.enableOptionSharing && defined(index);\n if (cached) {\n return cloneIfNotShared(cached, sharing);\n }\n const config = this.chart.config;\n const scopeKeys = config.datasetElementScopeKeys(this._type, elementType);\n const prefixes = active ? [\n `${elementType}Hover`,\n 'hover',\n elementType,\n ''\n ] : [\n elementType,\n ''\n ];\n const scopes = config.getOptionScopes(this.getDataset(), scopeKeys);\n const names = Object.keys(defaults.elements[elementType]);\n const context = ()=>this.getContext(index, active, mode);\n const values = config.resolveNamedOptions(scopes, names, context, prefixes);\n if (values.$shared) {\n values.$shared = sharing;\n cache[cacheKey] = Object.freeze(cloneIfNotShared(values, sharing));\n }\n return values;\n }\n _resolveAnimations(index, transition, active) {\n const chart = this.chart;\n const cache = this._cachedDataOpts;\n const cacheKey = `animation-${transition}`;\n const cached = cache[cacheKey];\n if (cached) {\n return cached;\n }\n let options;\n if (chart.options.animation !== false) {\n const config = this.chart.config;\n const scopeKeys = config.datasetAnimationScopeKeys(this._type, transition);\n const scopes = config.getOptionScopes(this.getDataset(), scopeKeys);\n options = config.createResolver(scopes, this.getContext(index, active, transition));\n }\n const animations = new Animations(chart, options && options.animations);\n if (options && options._cacheable) {\n cache[cacheKey] = Object.freeze(animations);\n }\n return animations;\n }\n getSharedOptions(options) {\n if (!options.$shared) {\n return;\n }\n return this._sharedOptions || (this._sharedOptions = Object.assign({}, options));\n }\n includeOptions(mode, sharedOptions) {\n return !sharedOptions || isDirectUpdateMode(mode) || this.chart._animationsDisabled;\n }\n _getSharedOptions(start, mode) {\n const firstOpts = this.resolveDataElementOptions(start, mode);\n const previouslySharedOptions = this._sharedOptions;\n const sharedOptions = this.getSharedOptions(firstOpts);\n const includeOptions = this.includeOptions(mode, sharedOptions) || sharedOptions !== previouslySharedOptions;\n this.updateSharedOptions(sharedOptions, mode, firstOpts);\n return {\n sharedOptions,\n includeOptions\n };\n }\n updateElement(element, index, properties, mode) {\n if (isDirectUpdateMode(mode)) {\n Object.assign(element, properties);\n } else {\n this._resolveAnimations(index, mode).update(element, properties);\n }\n }\n updateSharedOptions(sharedOptions, mode, newOptions) {\n if (sharedOptions && !isDirectUpdateMode(mode)) {\n this._resolveAnimations(undefined, mode).update(sharedOptions, newOptions);\n }\n }\n _setStyle(element, index, mode, active) {\n element.active = active;\n const options = this.getStyle(index, active);\n this._resolveAnimations(index, mode, active).update(element, {\n options: !active && this.getSharedOptions(options) || options\n });\n }\n removeHoverStyle(element, datasetIndex, index) {\n this._setStyle(element, index, 'active', false);\n }\n setHoverStyle(element, datasetIndex, index) {\n this._setStyle(element, index, 'active', true);\n }\n _removeDatasetHoverStyle() {\n const element = this._cachedMeta.dataset;\n if (element) {\n this._setStyle(element, undefined, 'active', false);\n }\n }\n _setDatasetHoverStyle() {\n const element = this._cachedMeta.dataset;\n if (element) {\n this._setStyle(element, undefined, 'active', true);\n }\n }\n _resyncElements(resetNewElements) {\n const data = this._data;\n const elements = this._cachedMeta.data;\n for (const [method, arg1, arg2] of this._syncList){\n this[method](arg1, arg2);\n }\n this._syncList = [];\n const numMeta = elements.length;\n const numData = data.length;\n const count = Math.min(numData, numMeta);\n if (count) {\n this.parse(0, count);\n }\n if (numData > numMeta) {\n this._insertElements(numMeta, numData - numMeta, resetNewElements);\n } else if (numData < numMeta) {\n this._removeElements(numData, numMeta - numData);\n }\n }\n _insertElements(start, count, resetNewElements = true) {\n const meta = this._cachedMeta;\n const data = meta.data;\n const end = start + count;\n let i;\n const move = (arr)=>{\n arr.length += count;\n for(i = arr.length - 1; i >= end; i--){\n arr[i] = arr[i - count];\n }\n };\n move(data);\n for(i = start; i < end; ++i){\n data[i] = new this.dataElementType();\n }\n if (this._parsing) {\n move(meta._parsed);\n }\n this.parse(start, count);\n if (resetNewElements) {\n this.updateElements(data, start, count, 'reset');\n }\n }\n updateElements(element, start, count, mode) {}\n _removeElements(start, count) {\n const meta = this._cachedMeta;\n if (this._parsing) {\n const removed = meta._parsed.splice(start, count);\n if (meta._stacked) {\n clearStacks(meta, removed);\n }\n }\n meta.data.splice(start, count);\n }\n _sync(args) {\n if (this._parsing) {\n this._syncList.push(args);\n } else {\n const [method, arg1, arg2] = args;\n this[method](arg1, arg2);\n }\n this.chart._dataChanges.push([\n this.index,\n ...args\n ]);\n }\n _onDataPush() {\n const count = arguments.length;\n this._sync([\n '_insertElements',\n this.getDataset().data.length - count,\n count\n ]);\n }\n _onDataPop() {\n this._sync([\n '_removeElements',\n this._cachedMeta.data.length - 1,\n 1\n ]);\n }\n _onDataShift() {\n this._sync([\n '_removeElements',\n 0,\n 1\n ]);\n }\n _onDataSplice(start, count) {\n if (count) {\n this._sync([\n '_removeElements',\n start,\n count\n ]);\n }\n const newCount = arguments.length - 2;\n if (newCount) {\n this._sync([\n '_insertElements',\n start,\n newCount\n ]);\n }\n }\n _onDataUnshift() {\n this._sync([\n '_insertElements',\n 0,\n arguments.length\n ]);\n }\n}\n\nfunction getAllScaleValues(scale, type) {\n if (!scale._cache.$bar) {\n const visibleMetas = scale.getMatchingVisibleMetas(type);\n let values = [];\n for(let i = 0, ilen = visibleMetas.length; i < ilen; i++){\n values = values.concat(visibleMetas[i].controller.getAllParsedValues(scale));\n }\n scale._cache.$bar = _arrayUnique(values.sort((a, b)=>a - b));\n }\n return scale._cache.$bar;\n}\n function computeMinSampleSize(meta) {\n const scale = meta.iScale;\n const values = getAllScaleValues(scale, meta.type);\n let min = scale._length;\n let i, ilen, curr, prev;\n const updateMinAndPrev = ()=>{\n if (curr === 32767 || curr === -32768) {\n return;\n }\n if (defined(prev)) {\n min = Math.min(min, Math.abs(curr - prev) || min);\n }\n prev = curr;\n };\n for(i = 0, ilen = values.length; i < ilen; ++i){\n curr = scale.getPixelForValue(values[i]);\n updateMinAndPrev();\n }\n prev = undefined;\n for(i = 0, ilen = scale.ticks.length; i < ilen; ++i){\n curr = scale.getPixelForTick(i);\n updateMinAndPrev();\n }\n return min;\n}\n function computeFitCategoryTraits(index, ruler, options, stackCount) {\n const thickness = options.barThickness;\n let size, ratio;\n if (isNullOrUndef(thickness)) {\n size = ruler.min * options.categoryPercentage;\n ratio = options.barPercentage;\n } else {\n size = thickness * stackCount;\n ratio = 1;\n }\n return {\n chunk: size / stackCount,\n ratio,\n start: ruler.pixels[index] - size / 2\n };\n}\n function computeFlexCategoryTraits(index, ruler, options, stackCount) {\n const pixels = ruler.pixels;\n const curr = pixels[index];\n let prev = index > 0 ? pixels[index - 1] : null;\n let next = index < pixels.length - 1 ? pixels[index + 1] : null;\n const percent = options.categoryPercentage;\n if (prev === null) {\n prev = curr - (next === null ? ruler.end - ruler.start : next - curr);\n }\n if (next === null) {\n next = curr + curr - prev;\n }\n const start = curr - (curr - Math.min(prev, next)) / 2 * percent;\n const size = Math.abs(next - prev) / 2 * percent;\n return {\n chunk: size / stackCount,\n ratio: options.barPercentage,\n start\n };\n}\nfunction parseFloatBar(entry, item, vScale, i) {\n const startValue = vScale.parse(entry[0], i);\n const endValue = vScale.parse(entry[1], i);\n const min = Math.min(startValue, endValue);\n const max = Math.max(startValue, endValue);\n let barStart = min;\n let barEnd = max;\n if (Math.abs(min) > Math.abs(max)) {\n barStart = max;\n barEnd = min;\n }\n item[vScale.axis] = barEnd;\n item._custom = {\n barStart,\n barEnd,\n start: startValue,\n end: endValue,\n min,\n max\n };\n}\nfunction parseValue(entry, item, vScale, i) {\n if (isArray(entry)) {\n parseFloatBar(entry, item, vScale, i);\n } else {\n item[vScale.axis] = vScale.parse(entry, i);\n }\n return item;\n}\nfunction parseArrayOrPrimitive(meta, data, start, count) {\n const iScale = meta.iScale;\n const vScale = meta.vScale;\n const labels = iScale.getLabels();\n const singleScale = iScale === vScale;\n const parsed = [];\n let i, ilen, item, entry;\n for(i = start, ilen = start + count; i < ilen; ++i){\n entry = data[i];\n item = {};\n item[iScale.axis] = singleScale || iScale.parse(labels[i], i);\n parsed.push(parseValue(entry, item, vScale, i));\n }\n return parsed;\n}\nfunction isFloatBar(custom) {\n return custom && custom.barStart !== undefined && custom.barEnd !== undefined;\n}\nfunction barSign(size, vScale, actualBase) {\n if (size !== 0) {\n return sign(size);\n }\n return (vScale.isHorizontal() ? 1 : -1) * (vScale.min >= actualBase ? 1 : -1);\n}\nfunction borderProps(properties) {\n let reverse, start, end, top, bottom;\n if (properties.horizontal) {\n reverse = properties.base > properties.x;\n start = 'left';\n end = 'right';\n } else {\n reverse = properties.base < properties.y;\n start = 'bottom';\n end = 'top';\n }\n if (reverse) {\n top = 'end';\n bottom = 'start';\n } else {\n top = 'start';\n bottom = 'end';\n }\n return {\n start,\n end,\n reverse,\n top,\n bottom\n };\n}\nfunction setBorderSkipped(properties, options, stack, index) {\n let edge = options.borderSkipped;\n const res = {};\n if (!edge) {\n properties.borderSkipped = res;\n return;\n }\n if (edge === true) {\n properties.borderSkipped = {\n top: true,\n right: true,\n bottom: true,\n left: true\n };\n return;\n }\n const { start , end , reverse , top , bottom } = borderProps(properties);\n if (edge === 'middle' && stack) {\n properties.enableBorderRadius = true;\n if ((stack._top || 0) === index) {\n edge = top;\n } else if ((stack._bottom || 0) === index) {\n edge = bottom;\n } else {\n res[parseEdge(bottom, start, end, reverse)] = true;\n edge = top;\n }\n }\n res[parseEdge(edge, start, end, reverse)] = true;\n properties.borderSkipped = res;\n}\nfunction parseEdge(edge, a, b, reverse) {\n if (reverse) {\n edge = swap(edge, a, b);\n edge = startEnd(edge, b, a);\n } else {\n edge = startEnd(edge, a, b);\n }\n return edge;\n}\nfunction swap(orig, v1, v2) {\n return orig === v1 ? v2 : orig === v2 ? v1 : orig;\n}\nfunction startEnd(v, start, end) {\n return v === 'start' ? start : v === 'end' ? end : v;\n}\nfunction setInflateAmount(properties, { inflateAmount }, ratio) {\n properties.inflateAmount = inflateAmount === 'auto' ? ratio === 1 ? 0.33 : 0 : inflateAmount;\n}\nclass BarController extends DatasetController {\n static id = 'bar';\n static defaults = {\n datasetElementType: false,\n dataElementType: 'bar',\n categoryPercentage: 0.8,\n barPercentage: 0.9,\n grouped: true,\n animations: {\n numbers: {\n type: 'number',\n properties: [\n 'x',\n 'y',\n 'base',\n 'width',\n 'height'\n ]\n }\n }\n };\n static overrides = {\n scales: {\n _index_: {\n type: 'category',\n offset: true,\n grid: {\n offset: true\n }\n },\n _value_: {\n type: 'linear',\n beginAtZero: true\n }\n }\n };\n parsePrimitiveData(meta, data, start, count) {\n return parseArrayOrPrimitive(meta, data, start, count);\n }\n parseArrayData(meta, data, start, count) {\n return parseArrayOrPrimitive(meta, data, start, count);\n }\n parseObjectData(meta, data, start, count) {\n const { iScale , vScale } = meta;\n const { xAxisKey ='x' , yAxisKey ='y' } = this._parsing;\n const iAxisKey = iScale.axis === 'x' ? xAxisKey : yAxisKey;\n const vAxisKey = vScale.axis === 'x' ? xAxisKey : yAxisKey;\n const parsed = [];\n let i, ilen, item, obj;\n for(i = start, ilen = start + count; i < ilen; ++i){\n obj = data[i];\n item = {};\n item[iScale.axis] = iScale.parse(resolveObjectKey(obj, iAxisKey), i);\n parsed.push(parseValue(resolveObjectKey(obj, vAxisKey), item, vScale, i));\n }\n return parsed;\n }\n updateRangeFromParsed(range, scale, parsed, stack) {\n super.updateRangeFromParsed(range, scale, parsed, stack);\n const custom = parsed._custom;\n if (custom && scale === this._cachedMeta.vScale) {\n range.min = Math.min(range.min, custom.min);\n range.max = Math.max(range.max, custom.max);\n }\n }\n getMaxOverflow() {\n return 0;\n }\n getLabelAndValue(index) {\n const meta = this._cachedMeta;\n const { iScale , vScale } = meta;\n const parsed = this.getParsed(index);\n const custom = parsed._custom;\n const value = isFloatBar(custom) ? '[' + custom.start + ', ' + custom.end + ']' : '' + vScale.getLabelForValue(parsed[vScale.axis]);\n return {\n label: '' + iScale.getLabelForValue(parsed[iScale.axis]),\n value\n };\n }\n initialize() {\n this.enableOptionSharing = true;\n super.initialize();\n const meta = this._cachedMeta;\n meta.stack = this.getDataset().stack;\n }\n update(mode) {\n const meta = this._cachedMeta;\n this.updateElements(meta.data, 0, meta.data.length, mode);\n }\n updateElements(bars, start, count, mode) {\n const reset = mode === 'reset';\n const { index , _cachedMeta: { vScale } } = this;\n const base = vScale.getBasePixel();\n const horizontal = vScale.isHorizontal();\n const ruler = this._getRuler();\n const { sharedOptions , includeOptions } = this._getSharedOptions(start, mode);\n for(let i = start; i < start + count; i++){\n const parsed = this.getParsed(i);\n const vpixels = reset || isNullOrUndef(parsed[vScale.axis]) ? {\n base,\n head: base\n } : this._calculateBarValuePixels(i);\n const ipixels = this._calculateBarIndexPixels(i, ruler);\n const stack = (parsed._stacks || {})[vScale.axis];\n const properties = {\n horizontal,\n base: vpixels.base,\n enableBorderRadius: !stack || isFloatBar(parsed._custom) || index === stack._top || index === stack._bottom,\n x: horizontal ? vpixels.head : ipixels.center,\n y: horizontal ? ipixels.center : vpixels.head,\n height: horizontal ? ipixels.size : Math.abs(vpixels.size),\n width: horizontal ? Math.abs(vpixels.size) : ipixels.size\n };\n if (includeOptions) {\n properties.options = sharedOptions || this.resolveDataElementOptions(i, bars[i].active ? 'active' : mode);\n }\n const options = properties.options || bars[i].options;\n setBorderSkipped(properties, options, stack, index);\n setInflateAmount(properties, options, ruler.ratio);\n this.updateElement(bars[i], i, properties, mode);\n }\n }\n _getStacks(last, dataIndex) {\n const { iScale } = this._cachedMeta;\n const metasets = iScale.getMatchingVisibleMetas(this._type).filter((meta)=>meta.controller.options.grouped);\n const stacked = iScale.options.stacked;\n const stacks = [];\n const currentParsed = this._cachedMeta.controller.getParsed(dataIndex);\n const iScaleValue = currentParsed && currentParsed[iScale.axis];\n const skipNull = (meta)=>{\n const parsed = meta._parsed.find((item)=>item[iScale.axis] === iScaleValue);\n const val = parsed && parsed[meta.vScale.axis];\n if (isNullOrUndef(val) || isNaN(val)) {\n return true;\n }\n };\n for (const meta of metasets){\n if (dataIndex !== undefined && skipNull(meta)) {\n continue;\n }\n if (stacked === false || stacks.indexOf(meta.stack) === -1 || stacked === undefined && meta.stack === undefined) {\n stacks.push(meta.stack);\n }\n if (meta.index === last) {\n break;\n }\n }\n if (!stacks.length) {\n stacks.push(undefined);\n }\n return stacks;\n }\n _getStackCount(index) {\n return this._getStacks(undefined, index).length;\n }\n _getStackIndex(datasetIndex, name, dataIndex) {\n const stacks = this._getStacks(datasetIndex, dataIndex);\n const index = name !== undefined ? stacks.indexOf(name) : -1;\n return index === -1 ? stacks.length - 1 : index;\n }\n _getRuler() {\n const opts = this.options;\n const meta = this._cachedMeta;\n const iScale = meta.iScale;\n const pixels = [];\n let i, ilen;\n for(i = 0, ilen = meta.data.length; i < ilen; ++i){\n pixels.push(iScale.getPixelForValue(this.getParsed(i)[iScale.axis], i));\n }\n const barThickness = opts.barThickness;\n const min = barThickness || computeMinSampleSize(meta);\n return {\n min,\n pixels,\n start: iScale._startPixel,\n end: iScale._endPixel,\n stackCount: this._getStackCount(),\n scale: iScale,\n grouped: opts.grouped,\n ratio: barThickness ? 1 : opts.categoryPercentage * opts.barPercentage\n };\n }\n _calculateBarValuePixels(index) {\n const { _cachedMeta: { vScale , _stacked , index: datasetIndex } , options: { base: baseValue , minBarLength } } = this;\n const actualBase = baseValue || 0;\n const parsed = this.getParsed(index);\n const custom = parsed._custom;\n const floating = isFloatBar(custom);\n let value = parsed[vScale.axis];\n let start = 0;\n let length = _stacked ? this.applyStack(vScale, parsed, _stacked) : value;\n let head, size;\n if (length !== value) {\n start = length - value;\n length = value;\n }\n if (floating) {\n value = custom.barStart;\n length = custom.barEnd - custom.barStart;\n if (value !== 0 && sign(value) !== sign(custom.barEnd)) {\n start = 0;\n }\n start += value;\n }\n const startValue = !isNullOrUndef(baseValue) && !floating ? baseValue : start;\n let base = vScale.getPixelForValue(startValue);\n if (this.chart.getDataVisibility(index)) {\n head = vScale.getPixelForValue(start + length);\n } else {\n head = base;\n }\n size = head - base;\n if (Math.abs(size) < minBarLength) {\n size = barSign(size, vScale, actualBase) * minBarLength;\n if (value === actualBase) {\n base -= size / 2;\n }\n const startPixel = vScale.getPixelForDecimal(0);\n const endPixel = vScale.getPixelForDecimal(1);\n const min = Math.min(startPixel, endPixel);\n const max = Math.max(startPixel, endPixel);\n base = Math.max(Math.min(base, max), min);\n head = base + size;\n if (_stacked && !floating) {\n parsed._stacks[vScale.axis]._visualValues[datasetIndex] = vScale.getValueForPixel(head) - vScale.getValueForPixel(base);\n }\n }\n if (base === vScale.getPixelForValue(actualBase)) {\n const halfGrid = sign(size) * vScale.getLineWidthForValue(actualBase) / 2;\n base += halfGrid;\n size -= halfGrid;\n }\n return {\n size,\n base,\n head,\n center: head + size / 2\n };\n }\n _calculateBarIndexPixels(index, ruler) {\n const scale = ruler.scale;\n const options = this.options;\n const skipNull = options.skipNull;\n const maxBarThickness = valueOrDefault(options.maxBarThickness, Infinity);\n let center, size;\n if (ruler.grouped) {\n const stackCount = skipNull ? this._getStackCount(index) : ruler.stackCount;\n const range = options.barThickness === 'flex' ? computeFlexCategoryTraits(index, ruler, options, stackCount) : computeFitCategoryTraits(index, ruler, options, stackCount);\n const stackIndex = this._getStackIndex(this.index, this._cachedMeta.stack, skipNull ? index : undefined);\n center = range.start + range.chunk * stackIndex + range.chunk / 2;\n size = Math.min(maxBarThickness, range.chunk * range.ratio);\n } else {\n center = scale.getPixelForValue(this.getParsed(index)[scale.axis], index);\n size = Math.min(maxBarThickness, ruler.min * ruler.ratio);\n }\n return {\n base: center - size / 2,\n head: center + size / 2,\n center,\n size\n };\n }\n draw() {\n const meta = this._cachedMeta;\n const vScale = meta.vScale;\n const rects = meta.data;\n const ilen = rects.length;\n let i = 0;\n for(; i < ilen; ++i){\n if (this.getParsed(i)[vScale.axis] !== null && !rects[i].hidden) {\n rects[i].draw(this._ctx);\n }\n }\n }\n}\n\nclass BubbleController extends DatasetController {\n static id = 'bubble';\n static defaults = {\n datasetElementType: false,\n dataElementType: 'point',\n animations: {\n numbers: {\n type: 'number',\n properties: [\n 'x',\n 'y',\n 'borderWidth',\n 'radius'\n ]\n }\n }\n };\n static overrides = {\n scales: {\n x: {\n type: 'linear'\n },\n y: {\n type: 'linear'\n }\n }\n };\n initialize() {\n this.enableOptionSharing = true;\n super.initialize();\n }\n parsePrimitiveData(meta, data, start, count) {\n const parsed = super.parsePrimitiveData(meta, data, start, count);\n for(let i = 0; i < parsed.length; i++){\n parsed[i]._custom = this.resolveDataElementOptions(i + start).radius;\n }\n return parsed;\n }\n parseArrayData(meta, data, start, count) {\n const parsed = super.parseArrayData(meta, data, start, count);\n for(let i = 0; i < parsed.length; i++){\n const item = data[start + i];\n parsed[i]._custom = valueOrDefault(item[2], this.resolveDataElementOptions(i + start).radius);\n }\n return parsed;\n }\n parseObjectData(meta, data, start, count) {\n const parsed = super.parseObjectData(meta, data, start, count);\n for(let i = 0; i < parsed.length; i++){\n const item = data[start + i];\n parsed[i]._custom = valueOrDefault(item && item.r && +item.r, this.resolveDataElementOptions(i + start).radius);\n }\n return parsed;\n }\n getMaxOverflow() {\n const data = this._cachedMeta.data;\n let max = 0;\n for(let i = data.length - 1; i >= 0; --i){\n max = Math.max(max, data[i].size(this.resolveDataElementOptions(i)) / 2);\n }\n return max > 0 && max;\n }\n getLabelAndValue(index) {\n const meta = this._cachedMeta;\n const labels = this.chart.data.labels || [];\n const { xScale , yScale } = meta;\n const parsed = this.getParsed(index);\n const x = xScale.getLabelForValue(parsed.x);\n const y = yScale.getLabelForValue(parsed.y);\n const r = parsed._custom;\n return {\n label: labels[index] || '',\n value: '(' + x + ', ' + y + (r ? ', ' + r : '') + ')'\n };\n }\n update(mode) {\n const points = this._cachedMeta.data;\n this.updateElements(points, 0, points.length, mode);\n }\n updateElements(points, start, count, mode) {\n const reset = mode === 'reset';\n const { iScale , vScale } = this._cachedMeta;\n const { sharedOptions , includeOptions } = this._getSharedOptions(start, mode);\n const iAxis = iScale.axis;\n const vAxis = vScale.axis;\n for(let i = start; i < start + count; i++){\n const point = points[i];\n const parsed = !reset && this.getParsed(i);\n const properties = {};\n const iPixel = properties[iAxis] = reset ? iScale.getPixelForDecimal(0.5) : iScale.getPixelForValue(parsed[iAxis]);\n const vPixel = properties[vAxis] = reset ? vScale.getBasePixel() : vScale.getPixelForValue(parsed[vAxis]);\n properties.skip = isNaN(iPixel) || isNaN(vPixel);\n if (includeOptions) {\n properties.options = sharedOptions || this.resolveDataElementOptions(i, point.active ? 'active' : mode);\n if (reset) {\n properties.options.radius = 0;\n }\n }\n this.updateElement(point, i, properties, mode);\n }\n }\n resolveDataElementOptions(index, mode) {\n const parsed = this.getParsed(index);\n let values = super.resolveDataElementOptions(index, mode);\n if (values.$shared) {\n values = Object.assign({}, values, {\n $shared: false\n });\n }\n const radius = values.radius;\n if (mode !== 'active') {\n values.radius = 0;\n }\n values.radius += valueOrDefault(parsed && parsed._custom, radius);\n return values;\n }\n}\n\nfunction getRatioAndOffset(rotation, circumference, cutout) {\n let ratioX = 1;\n let ratioY = 1;\n let offsetX = 0;\n let offsetY = 0;\n if (circumference < TAU) {\n const startAngle = rotation;\n const endAngle = startAngle + circumference;\n const startX = Math.cos(startAngle);\n const startY = Math.sin(startAngle);\n const endX = Math.cos(endAngle);\n const endY = Math.sin(endAngle);\n const calcMax = (angle, a, b)=>_angleBetween(angle, startAngle, endAngle, true) ? 1 : Math.max(a, a * cutout, b, b * cutout);\n const calcMin = (angle, a, b)=>_angleBetween(angle, startAngle, endAngle, true) ? -1 : Math.min(a, a * cutout, b, b * cutout);\n const maxX = calcMax(0, startX, endX);\n const maxY = calcMax(HALF_PI, startY, endY);\n const minX = calcMin(PI, startX, endX);\n const minY = calcMin(PI + HALF_PI, startY, endY);\n ratioX = (maxX - minX) / 2;\n ratioY = (maxY - minY) / 2;\n offsetX = -(maxX + minX) / 2;\n offsetY = -(maxY + minY) / 2;\n }\n return {\n ratioX,\n ratioY,\n offsetX,\n offsetY\n };\n}\nclass DoughnutController extends DatasetController {\n static id = 'doughnut';\n static defaults = {\n datasetElementType: false,\n dataElementType: 'arc',\n animation: {\n animateRotate: true,\n animateScale: false\n },\n animations: {\n numbers: {\n type: 'number',\n properties: [\n 'circumference',\n 'endAngle',\n 'innerRadius',\n 'outerRadius',\n 'startAngle',\n 'x',\n 'y',\n 'offset',\n 'borderWidth',\n 'spacing'\n ]\n }\n },\n cutout: '50%',\n rotation: 0,\n circumference: 360,\n radius: '100%',\n spacing: 0,\n indexAxis: 'r'\n };\n static descriptors = {\n _scriptable: (name)=>name !== 'spacing',\n _indexable: (name)=>name !== 'spacing' && !name.startsWith('borderDash') && !name.startsWith('hoverBorderDash')\n };\n static overrides = {\n aspectRatio: 1,\n plugins: {\n legend: {\n labels: {\n generateLabels (chart) {\n const data = chart.data;\n if (data.labels.length && data.datasets.length) {\n const { labels: { pointStyle , color } } = chart.legend.options;\n return data.labels.map((label, i)=>{\n const meta = chart.getDatasetMeta(0);\n const style = meta.controller.getStyle(i);\n return {\n text: label,\n fillStyle: style.backgroundColor,\n strokeStyle: style.borderColor,\n fontColor: color,\n lineWidth: style.borderWidth,\n pointStyle: pointStyle,\n hidden: !chart.getDataVisibility(i),\n index: i\n };\n });\n }\n return [];\n }\n },\n onClick (e, legendItem, legend) {\n legend.chart.toggleDataVisibility(legendItem.index);\n legend.chart.update();\n }\n }\n }\n };\n constructor(chart, datasetIndex){\n super(chart, datasetIndex);\n this.enableOptionSharing = true;\n this.innerRadius = undefined;\n this.outerRadius = undefined;\n this.offsetX = undefined;\n this.offsetY = undefined;\n }\n linkScales() {}\n parse(start, count) {\n const data = this.getDataset().data;\n const meta = this._cachedMeta;\n if (this._parsing === false) {\n meta._parsed = data;\n } else {\n let getter = (i)=>+data[i];\n if (isObject(data[start])) {\n const { key ='value' } = this._parsing;\n getter = (i)=>+resolveObjectKey(data[i], key);\n }\n let i, ilen;\n for(i = start, ilen = start + count; i < ilen; ++i){\n meta._parsed[i] = getter(i);\n }\n }\n }\n _getRotation() {\n return toRadians(this.options.rotation - 90);\n }\n _getCircumference() {\n return toRadians(this.options.circumference);\n }\n _getRotationExtents() {\n let min = TAU;\n let max = -TAU;\n for(let i = 0; i < this.chart.data.datasets.length; ++i){\n if (this.chart.isDatasetVisible(i) && this.chart.getDatasetMeta(i).type === this._type) {\n const controller = this.chart.getDatasetMeta(i).controller;\n const rotation = controller._getRotation();\n const circumference = controller._getCircumference();\n min = Math.min(min, rotation);\n max = Math.max(max, rotation + circumference);\n }\n }\n return {\n rotation: min,\n circumference: max - min\n };\n }\n update(mode) {\n const chart = this.chart;\n const { chartArea } = chart;\n const meta = this._cachedMeta;\n const arcs = meta.data;\n const spacing = this.getMaxBorderWidth() + this.getMaxOffset(arcs) + this.options.spacing;\n const maxSize = Math.max((Math.min(chartArea.width, chartArea.height) - spacing) / 2, 0);\n const cutout = Math.min(toPercentage(this.options.cutout, maxSize), 1);\n const chartWeight = this._getRingWeight(this.index);\n const { circumference , rotation } = this._getRotationExtents();\n const { ratioX , ratioY , offsetX , offsetY } = getRatioAndOffset(rotation, circumference, cutout);\n const maxWidth = (chartArea.width - spacing) / ratioX;\n const maxHeight = (chartArea.height - spacing) / ratioY;\n const maxRadius = Math.max(Math.min(maxWidth, maxHeight) / 2, 0);\n const outerRadius = toDimension(this.options.radius, maxRadius);\n const innerRadius = Math.max(outerRadius * cutout, 0);\n const radiusLength = (outerRadius - innerRadius) / this._getVisibleDatasetWeightTotal();\n this.offsetX = offsetX * outerRadius;\n this.offsetY = offsetY * outerRadius;\n meta.total = this.calculateTotal();\n this.outerRadius = outerRadius - radiusLength * this._getRingWeightOffset(this.index);\n this.innerRadius = Math.max(this.outerRadius - radiusLength * chartWeight, 0);\n this.updateElements(arcs, 0, arcs.length, mode);\n }\n _circumference(i, reset) {\n const opts = this.options;\n const meta = this._cachedMeta;\n const circumference = this._getCircumference();\n if (reset && opts.animation.animateRotate || !this.chart.getDataVisibility(i) || meta._parsed[i] === null || meta.data[i].hidden) {\n return 0;\n }\n return this.calculateCircumference(meta._parsed[i] * circumference / TAU);\n }\n updateElements(arcs, start, count, mode) {\n const reset = mode === 'reset';\n const chart = this.chart;\n const chartArea = chart.chartArea;\n const opts = chart.options;\n const animationOpts = opts.animation;\n const centerX = (chartArea.left + chartArea.right) / 2;\n const centerY = (chartArea.top + chartArea.bottom) / 2;\n const animateScale = reset && animationOpts.animateScale;\n const innerRadius = animateScale ? 0 : this.innerRadius;\n const outerRadius = animateScale ? 0 : this.outerRadius;\n const { sharedOptions , includeOptions } = this._getSharedOptions(start, mode);\n let startAngle = this._getRotation();\n let i;\n for(i = 0; i < start; ++i){\n startAngle += this._circumference(i, reset);\n }\n for(i = start; i < start + count; ++i){\n const circumference = this._circumference(i, reset);\n const arc = arcs[i];\n const properties = {\n x: centerX + this.offsetX,\n y: centerY + this.offsetY,\n startAngle,\n endAngle: startAngle + circumference,\n circumference,\n outerRadius,\n innerRadius\n };\n if (includeOptions) {\n properties.options = sharedOptions || this.resolveDataElementOptions(i, arc.active ? 'active' : mode);\n }\n startAngle += circumference;\n this.updateElement(arc, i, properties, mode);\n }\n }\n calculateTotal() {\n const meta = this._cachedMeta;\n const metaData = meta.data;\n let total = 0;\n let i;\n for(i = 0; i < metaData.length; i++){\n const value = meta._parsed[i];\n if (value !== null && !isNaN(value) && this.chart.getDataVisibility(i) && !metaData[i].hidden) {\n total += Math.abs(value);\n }\n }\n return total;\n }\n calculateCircumference(value) {\n const total = this._cachedMeta.total;\n if (total > 0 && !isNaN(value)) {\n return TAU * (Math.abs(value) / total);\n }\n return 0;\n }\n getLabelAndValue(index) {\n const meta = this._cachedMeta;\n const chart = this.chart;\n const labels = chart.data.labels || [];\n const value = formatNumber(meta._parsed[index], chart.options.locale);\n return {\n label: labels[index] || '',\n value\n };\n }\n getMaxBorderWidth(arcs) {\n let max = 0;\n const chart = this.chart;\n let i, ilen, meta, controller, options;\n if (!arcs) {\n for(i = 0, ilen = chart.data.datasets.length; i < ilen; ++i){\n if (chart.isDatasetVisible(i)) {\n meta = chart.getDatasetMeta(i);\n arcs = meta.data;\n controller = meta.controller;\n break;\n }\n }\n }\n if (!arcs) {\n return 0;\n }\n for(i = 0, ilen = arcs.length; i < ilen; ++i){\n options = controller.resolveDataElementOptions(i);\n if (options.borderAlign !== 'inner') {\n max = Math.max(max, options.borderWidth || 0, options.hoverBorderWidth || 0);\n }\n }\n return max;\n }\n getMaxOffset(arcs) {\n let max = 0;\n for(let i = 0, ilen = arcs.length; i < ilen; ++i){\n const options = this.resolveDataElementOptions(i);\n max = Math.max(max, options.offset || 0, options.hoverOffset || 0);\n }\n return max;\n }\n _getRingWeightOffset(datasetIndex) {\n let ringWeightOffset = 0;\n for(let i = 0; i < datasetIndex; ++i){\n if (this.chart.isDatasetVisible(i)) {\n ringWeightOffset += this._getRingWeight(i);\n }\n }\n return ringWeightOffset;\n }\n _getRingWeight(datasetIndex) {\n return Math.max(valueOrDefault(this.chart.data.datasets[datasetIndex].weight, 1), 0);\n }\n _getVisibleDatasetWeightTotal() {\n return this._getRingWeightOffset(this.chart.data.datasets.length) || 1;\n }\n}\n\nclass LineController extends DatasetController {\n static id = 'line';\n static defaults = {\n datasetElementType: 'line',\n dataElementType: 'point',\n showLine: true,\n spanGaps: false\n };\n static overrides = {\n scales: {\n _index_: {\n type: 'category'\n },\n _value_: {\n type: 'linear'\n }\n }\n };\n initialize() {\n this.enableOptionSharing = true;\n this.supportsDecimation = true;\n super.initialize();\n }\n update(mode) {\n const meta = this._cachedMeta;\n const { dataset: line , data: points = [] , _dataset } = meta;\n const animationsDisabled = this.chart._animationsDisabled;\n let { start , count } = _getStartAndCountOfVisiblePoints(meta, points, animationsDisabled);\n this._drawStart = start;\n this._drawCount = count;\n if (_scaleRangesChanged(meta)) {\n start = 0;\n count = points.length;\n }\n line._chart = this.chart;\n line._datasetIndex = this.index;\n line._decimated = !!_dataset._decimated;\n line.points = points;\n const options = this.resolveDatasetElementOptions(mode);\n if (!this.options.showLine) {\n options.borderWidth = 0;\n }\n options.segment = this.options.segment;\n this.updateElement(line, undefined, {\n animated: !animationsDisabled,\n options\n }, mode);\n this.updateElements(points, start, count, mode);\n }\n updateElements(points, start, count, mode) {\n const reset = mode === 'reset';\n const { iScale , vScale , _stacked , _dataset } = this._cachedMeta;\n const { sharedOptions , includeOptions } = this._getSharedOptions(start, mode);\n const iAxis = iScale.axis;\n const vAxis = vScale.axis;\n const { spanGaps , segment } = this.options;\n const maxGapLength = isNumber(spanGaps) ? spanGaps : Number.POSITIVE_INFINITY;\n const directUpdate = this.chart._animationsDisabled || reset || mode === 'none';\n const end = start + count;\n const pointsCount = points.length;\n let prevParsed = start > 0 && this.getParsed(start - 1);\n for(let i = 0; i < pointsCount; ++i){\n const point = points[i];\n const properties = directUpdate ? point : {};\n if (i < start || i >= end) {\n properties.skip = true;\n continue;\n }\n const parsed = this.getParsed(i);\n const nullData = isNullOrUndef(parsed[vAxis]);\n const iPixel = properties[iAxis] = iScale.getPixelForValue(parsed[iAxis], i);\n const vPixel = properties[vAxis] = reset || nullData ? vScale.getBasePixel() : vScale.getPixelForValue(_stacked ? this.applyStack(vScale, parsed, _stacked) : parsed[vAxis], i);\n properties.skip = isNaN(iPixel) || isNaN(vPixel) || nullData;\n properties.stop = i > 0 && Math.abs(parsed[iAxis] - prevParsed[iAxis]) > maxGapLength;\n if (segment) {\n properties.parsed = parsed;\n properties.raw = _dataset.data[i];\n }\n if (includeOptions) {\n properties.options = sharedOptions || this.resolveDataElementOptions(i, point.active ? 'active' : mode);\n }\n if (!directUpdate) {\n this.updateElement(point, i, properties, mode);\n }\n prevParsed = parsed;\n }\n }\n getMaxOverflow() {\n const meta = this._cachedMeta;\n const dataset = meta.dataset;\n const border = dataset.options && dataset.options.borderWidth || 0;\n const data = meta.data || [];\n if (!data.length) {\n return border;\n }\n const firstPoint = data[0].size(this.resolveDataElementOptions(0));\n const lastPoint = data[data.length - 1].size(this.resolveDataElementOptions(data.length - 1));\n return Math.max(border, firstPoint, lastPoint) / 2;\n }\n draw() {\n const meta = this._cachedMeta;\n meta.dataset.updateControlPoints(this.chart.chartArea, meta.iScale.axis);\n super.draw();\n }\n}\n\nclass PolarAreaController extends DatasetController {\n static id = 'polarArea';\n static defaults = {\n dataElementType: 'arc',\n animation: {\n animateRotate: true,\n animateScale: true\n },\n animations: {\n numbers: {\n type: 'number',\n properties: [\n 'x',\n 'y',\n 'startAngle',\n 'endAngle',\n 'innerRadius',\n 'outerRadius'\n ]\n }\n },\n indexAxis: 'r',\n startAngle: 0\n };\n static overrides = {\n aspectRatio: 1,\n plugins: {\n legend: {\n labels: {\n generateLabels (chart) {\n const data = chart.data;\n if (data.labels.length && data.datasets.length) {\n const { labels: { pointStyle , color } } = chart.legend.options;\n return data.labels.map((label, i)=>{\n const meta = chart.getDatasetMeta(0);\n const style = meta.controller.getStyle(i);\n return {\n text: label,\n fillStyle: style.backgroundColor,\n strokeStyle: style.borderColor,\n fontColor: color,\n lineWidth: style.borderWidth,\n pointStyle: pointStyle,\n hidden: !chart.getDataVisibility(i),\n index: i\n };\n });\n }\n return [];\n }\n },\n onClick (e, legendItem, legend) {\n legend.chart.toggleDataVisibility(legendItem.index);\n legend.chart.update();\n }\n }\n },\n scales: {\n r: {\n type: 'radialLinear',\n angleLines: {\n display: false\n },\n beginAtZero: true,\n grid: {\n circular: true\n },\n pointLabels: {\n display: false\n },\n startAngle: 0\n }\n }\n };\n constructor(chart, datasetIndex){\n super(chart, datasetIndex);\n this.innerRadius = undefined;\n this.outerRadius = undefined;\n }\n getLabelAndValue(index) {\n const meta = this._cachedMeta;\n const chart = this.chart;\n const labels = chart.data.labels || [];\n const value = formatNumber(meta._parsed[index].r, chart.options.locale);\n return {\n label: labels[index] || '',\n value\n };\n }\n parseObjectData(meta, data, start, count) {\n return _parseObjectDataRadialScale.bind(this)(meta, data, start, count);\n }\n update(mode) {\n const arcs = this._cachedMeta.data;\n this._updateRadius();\n this.updateElements(arcs, 0, arcs.length, mode);\n }\n getMinMax() {\n const meta = this._cachedMeta;\n const range = {\n min: Number.POSITIVE_INFINITY,\n max: Number.NEGATIVE_INFINITY\n };\n meta.data.forEach((element, index)=>{\n const parsed = this.getParsed(index).r;\n if (!isNaN(parsed) && this.chart.getDataVisibility(index)) {\n if (parsed < range.min) {\n range.min = parsed;\n }\n if (parsed > range.max) {\n range.max = parsed;\n }\n }\n });\n return range;\n }\n _updateRadius() {\n const chart = this.chart;\n const chartArea = chart.chartArea;\n const opts = chart.options;\n const minSize = Math.min(chartArea.right - chartArea.left, chartArea.bottom - chartArea.top);\n const outerRadius = Math.max(minSize / 2, 0);\n const innerRadius = Math.max(opts.cutoutPercentage ? outerRadius / 100 * opts.cutoutPercentage : 1, 0);\n const radiusLength = (outerRadius - innerRadius) / chart.getVisibleDatasetCount();\n this.outerRadius = outerRadius - radiusLength * this.index;\n this.innerRadius = this.outerRadius - radiusLength;\n }\n updateElements(arcs, start, count, mode) {\n const reset = mode === 'reset';\n const chart = this.chart;\n const opts = chart.options;\n const animationOpts = opts.animation;\n const scale = this._cachedMeta.rScale;\n const centerX = scale.xCenter;\n const centerY = scale.yCenter;\n const datasetStartAngle = scale.getIndexAngle(0) - 0.5 * PI;\n let angle = datasetStartAngle;\n let i;\n const defaultAngle = 360 / this.countVisibleElements();\n for(i = 0; i < start; ++i){\n angle += this._computeAngle(i, mode, defaultAngle);\n }\n for(i = start; i < start + count; i++){\n const arc = arcs[i];\n let startAngle = angle;\n let endAngle = angle + this._computeAngle(i, mode, defaultAngle);\n let outerRadius = chart.getDataVisibility(i) ? scale.getDistanceFromCenterForValue(this.getParsed(i).r) : 0;\n angle = endAngle;\n if (reset) {\n if (animationOpts.animateScale) {\n outerRadius = 0;\n }\n if (animationOpts.animateRotate) {\n startAngle = endAngle = datasetStartAngle;\n }\n }\n const properties = {\n x: centerX,\n y: centerY,\n innerRadius: 0,\n outerRadius,\n startAngle,\n endAngle,\n options: this.resolveDataElementOptions(i, arc.active ? 'active' : mode)\n };\n this.updateElement(arc, i, properties, mode);\n }\n }\n countVisibleElements() {\n const meta = this._cachedMeta;\n let count = 0;\n meta.data.forEach((element, index)=>{\n if (!isNaN(this.getParsed(index).r) && this.chart.getDataVisibility(index)) {\n count++;\n }\n });\n return count;\n }\n _computeAngle(index, mode, defaultAngle) {\n return this.chart.getDataVisibility(index) ? toRadians(this.resolveDataElementOptions(index, mode).angle || defaultAngle) : 0;\n }\n}\n\nclass PieController extends DoughnutController {\n static id = 'pie';\n static defaults = {\n cutout: 0,\n rotation: 0,\n circumference: 360,\n radius: '100%'\n };\n}\n\nclass RadarController extends DatasetController {\n static id = 'radar';\n static defaults = {\n datasetElementType: 'line',\n dataElementType: 'point',\n indexAxis: 'r',\n showLine: true,\n elements: {\n line: {\n fill: 'start'\n }\n }\n };\n static overrides = {\n aspectRatio: 1,\n scales: {\n r: {\n type: 'radialLinear'\n }\n }\n };\n getLabelAndValue(index) {\n const vScale = this._cachedMeta.vScale;\n const parsed = this.getParsed(index);\n return {\n label: vScale.getLabels()[index],\n value: '' + vScale.getLabelForValue(parsed[vScale.axis])\n };\n }\n parseObjectData(meta, data, start, count) {\n return _parseObjectDataRadialScale.bind(this)(meta, data, start, count);\n }\n update(mode) {\n const meta = this._cachedMeta;\n const line = meta.dataset;\n const points = meta.data || [];\n const labels = meta.iScale.getLabels();\n line.points = points;\n if (mode !== 'resize') {\n const options = this.resolveDatasetElementOptions(mode);\n if (!this.options.showLine) {\n options.borderWidth = 0;\n }\n const properties = {\n _loop: true,\n _fullLoop: labels.length === points.length,\n options\n };\n this.updateElement(line, undefined, properties, mode);\n }\n this.updateElements(points, 0, points.length, mode);\n }\n updateElements(points, start, count, mode) {\n const scale = this._cachedMeta.rScale;\n const reset = mode === 'reset';\n for(let i = start; i < start + count; i++){\n const point = points[i];\n const options = this.resolveDataElementOptions(i, point.active ? 'active' : mode);\n const pointPosition = scale.getPointPositionForValue(i, this.getParsed(i).r);\n const x = reset ? scale.xCenter : pointPosition.x;\n const y = reset ? scale.yCenter : pointPosition.y;\n const properties = {\n x,\n y,\n angle: pointPosition.angle,\n skip: isNaN(x) || isNaN(y),\n options\n };\n this.updateElement(point, i, properties, mode);\n }\n }\n}\n\nclass ScatterController extends DatasetController {\n static id = 'scatter';\n static defaults = {\n datasetElementType: false,\n dataElementType: 'point',\n showLine: false,\n fill: false\n };\n static overrides = {\n interaction: {\n mode: 'point'\n },\n scales: {\n x: {\n type: 'linear'\n },\n y: {\n type: 'linear'\n }\n }\n };\n getLabelAndValue(index) {\n const meta = this._cachedMeta;\n const labels = this.chart.data.labels || [];\n const { xScale , yScale } = meta;\n const parsed = this.getParsed(index);\n const x = xScale.getLabelForValue(parsed.x);\n const y = yScale.getLabelForValue(parsed.y);\n return {\n label: labels[index] || '',\n value: '(' + x + ', ' + y + ')'\n };\n }\n update(mode) {\n const meta = this._cachedMeta;\n const { data: points = [] } = meta;\n const animationsDisabled = this.chart._animationsDisabled;\n let { start , count } = _getStartAndCountOfVisiblePoints(meta, points, animationsDisabled);\n this._drawStart = start;\n this._drawCount = count;\n if (_scaleRangesChanged(meta)) {\n start = 0;\n count = points.length;\n }\n if (this.options.showLine) {\n if (!this.datasetElementType) {\n this.addElements();\n }\n const { dataset: line , _dataset } = meta;\n line._chart = this.chart;\n line._datasetIndex = this.index;\n line._decimated = !!_dataset._decimated;\n line.points = points;\n const options = this.resolveDatasetElementOptions(mode);\n options.segment = this.options.segment;\n this.updateElement(line, undefined, {\n animated: !animationsDisabled,\n options\n }, mode);\n } else if (this.datasetElementType) {\n delete meta.dataset;\n this.datasetElementType = false;\n }\n this.updateElements(points, start, count, mode);\n }\n addElements() {\n const { showLine } = this.options;\n if (!this.datasetElementType && showLine) {\n this.datasetElementType = this.chart.registry.getElement('line');\n }\n super.addElements();\n }\n updateElements(points, start, count, mode) {\n const reset = mode === 'reset';\n const { iScale , vScale , _stacked , _dataset } = this._cachedMeta;\n const firstOpts = this.resolveDataElementOptions(start, mode);\n const sharedOptions = this.getSharedOptions(firstOpts);\n const includeOptions = this.includeOptions(mode, sharedOptions);\n const iAxis = iScale.axis;\n const vAxis = vScale.axis;\n const { spanGaps , segment } = this.options;\n const maxGapLength = isNumber(spanGaps) ? spanGaps : Number.POSITIVE_INFINITY;\n const directUpdate = this.chart._animationsDisabled || reset || mode === 'none';\n let prevParsed = start > 0 && this.getParsed(start - 1);\n for(let i = start; i < start + count; ++i){\n const point = points[i];\n const parsed = this.getParsed(i);\n const properties = directUpdate ? point : {};\n const nullData = isNullOrUndef(parsed[vAxis]);\n const iPixel = properties[iAxis] = iScale.getPixelForValue(parsed[iAxis], i);\n const vPixel = properties[vAxis] = reset || nullData ? vScale.getBasePixel() : vScale.getPixelForValue(_stacked ? this.applyStack(vScale, parsed, _stacked) : parsed[vAxis], i);\n properties.skip = isNaN(iPixel) || isNaN(vPixel) || nullData;\n properties.stop = i > 0 && Math.abs(parsed[iAxis] - prevParsed[iAxis]) > maxGapLength;\n if (segment) {\n properties.parsed = parsed;\n properties.raw = _dataset.data[i];\n }\n if (includeOptions) {\n properties.options = sharedOptions || this.resolveDataElementOptions(i, point.active ? 'active' : mode);\n }\n if (!directUpdate) {\n this.updateElement(point, i, properties, mode);\n }\n prevParsed = parsed;\n }\n this.updateSharedOptions(sharedOptions, mode, firstOpts);\n }\n getMaxOverflow() {\n const meta = this._cachedMeta;\n const data = meta.data || [];\n if (!this.options.showLine) {\n let max = 0;\n for(let i = data.length - 1; i >= 0; --i){\n max = Math.max(max, data[i].size(this.resolveDataElementOptions(i)) / 2);\n }\n return max > 0 && max;\n }\n const dataset = meta.dataset;\n const border = dataset.options && dataset.options.borderWidth || 0;\n if (!data.length) {\n return border;\n }\n const firstPoint = data[0].size(this.resolveDataElementOptions(0));\n const lastPoint = data[data.length - 1].size(this.resolveDataElementOptions(data.length - 1));\n return Math.max(border, firstPoint, lastPoint) / 2;\n }\n}\n\nvar controllers = /*#__PURE__*/Object.freeze({\n__proto__: null,\nBarController: BarController,\nBubbleController: BubbleController,\nDoughnutController: DoughnutController,\nLineController: LineController,\nPieController: PieController,\nPolarAreaController: PolarAreaController,\nRadarController: RadarController,\nScatterController: ScatterController\n});\n\n/**\n * @namespace Chart._adapters\n * @since 2.8.0\n * @private\n */ function chart_abstract() {\n throw new Error('This method is not implemented: Check that a complete date adapter is provided.');\n}\n/**\n * Date adapter (current used by the time scale)\n * @namespace Chart._adapters._date\n * @memberof Chart._adapters\n * @private\n */ class DateAdapterBase {\n /**\n * Override default date adapter methods.\n * Accepts type parameter to define options type.\n * @example\n * Chart._adapters._date.override<{myAdapterOption: string}>({\n * init() {\n * console.log(this.options.myAdapterOption);\n * }\n * })\n */ static override(members) {\n Object.assign(DateAdapterBase.prototype, members);\n }\n options;\n constructor(options){\n this.options = options || {};\n }\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n init() {}\n formats() {\n return chart_abstract();\n }\n parse() {\n return chart_abstract();\n }\n format() {\n return chart_abstract();\n }\n add() {\n return chart_abstract();\n }\n diff() {\n return chart_abstract();\n }\n startOf() {\n return chart_abstract();\n }\n endOf() {\n return chart_abstract();\n }\n}\nvar adapters = {\n _date: DateAdapterBase\n};\n\nfunction binarySearch(metaset, axis, value, intersect) {\n const { controller , data , _sorted } = metaset;\n const iScale = controller._cachedMeta.iScale;\n if (iScale && axis === iScale.axis && axis !== 'r' && _sorted && data.length) {\n const lookupMethod = iScale._reversePixels ? _rlookupByKey : _lookupByKey;\n if (!intersect) {\n return lookupMethod(data, axis, value);\n } else if (controller._sharedOptions) {\n const el = data[0];\n const range = typeof el.getRange === 'function' && el.getRange(axis);\n if (range) {\n const start = lookupMethod(data, axis, value - range);\n const end = lookupMethod(data, axis, value + range);\n return {\n lo: start.lo,\n hi: end.hi\n };\n }\n }\n }\n return {\n lo: 0,\n hi: data.length - 1\n };\n}\n function evaluateInteractionItems(chart, axis, position, handler, intersect) {\n const metasets = chart.getSortedVisibleDatasetMetas();\n const value = position[axis];\n for(let i = 0, ilen = metasets.length; i < ilen; ++i){\n const { index , data } = metasets[i];\n const { lo , hi } = binarySearch(metasets[i], axis, value, intersect);\n for(let j = lo; j <= hi; ++j){\n const element = data[j];\n if (!element.skip) {\n handler(element, index, j);\n }\n }\n }\n}\n function getDistanceMetricForAxis(axis) {\n const useX = axis.indexOf('x') !== -1;\n const useY = axis.indexOf('y') !== -1;\n return function(pt1, pt2) {\n const deltaX = useX ? Math.abs(pt1.x - pt2.x) : 0;\n const deltaY = useY ? Math.abs(pt1.y - pt2.y) : 0;\n return Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2));\n };\n}\n function getIntersectItems(chart, position, axis, useFinalPosition, includeInvisible) {\n const items = [];\n if (!includeInvisible && !chart.isPointInArea(position)) {\n return items;\n }\n const evaluationFunc = function(element, datasetIndex, index) {\n if (!includeInvisible && !_isPointInArea(element, chart.chartArea, 0)) {\n return;\n }\n if (element.inRange(position.x, position.y, useFinalPosition)) {\n items.push({\n element,\n datasetIndex,\n index\n });\n }\n };\n evaluateInteractionItems(chart, axis, position, evaluationFunc, true);\n return items;\n}\n function getNearestRadialItems(chart, position, axis, useFinalPosition) {\n let items = [];\n function evaluationFunc(element, datasetIndex, index) {\n const { startAngle , endAngle } = element.getProps([\n 'startAngle',\n 'endAngle'\n ], useFinalPosition);\n const { angle } = getAngleFromPoint(element, {\n x: position.x,\n y: position.y\n });\n if (_angleBetween(angle, startAngle, endAngle)) {\n items.push({\n element,\n datasetIndex,\n index\n });\n }\n }\n evaluateInteractionItems(chart, axis, position, evaluationFunc);\n return items;\n}\n function getNearestCartesianItems(chart, position, axis, intersect, useFinalPosition, includeInvisible) {\n let items = [];\n const distanceMetric = getDistanceMetricForAxis(axis);\n let minDistance = Number.POSITIVE_INFINITY;\n function evaluationFunc(element, datasetIndex, index) {\n const inRange = element.inRange(position.x, position.y, useFinalPosition);\n if (intersect && !inRange) {\n return;\n }\n const center = element.getCenterPoint(useFinalPosition);\n const pointInArea = !!includeInvisible || chart.isPointInArea(center);\n if (!pointInArea && !inRange) {\n return;\n }\n const distance = distanceMetric(position, center);\n if (distance < minDistance) {\n items = [\n {\n element,\n datasetIndex,\n index\n }\n ];\n minDistance = distance;\n } else if (distance === minDistance) {\n items.push({\n element,\n datasetIndex,\n index\n });\n }\n }\n evaluateInteractionItems(chart, axis, position, evaluationFunc);\n return items;\n}\n function getNearestItems(chart, position, axis, intersect, useFinalPosition, includeInvisible) {\n if (!includeInvisible && !chart.isPointInArea(position)) {\n return [];\n }\n return axis === 'r' && !intersect ? getNearestRadialItems(chart, position, axis, useFinalPosition) : getNearestCartesianItems(chart, position, axis, intersect, useFinalPosition, includeInvisible);\n}\n function getAxisItems(chart, position, axis, intersect, useFinalPosition) {\n const items = [];\n const rangeMethod = axis === 'x' ? 'inXRange' : 'inYRange';\n let intersectsItem = false;\n evaluateInteractionItems(chart, axis, position, (element, datasetIndex, index)=>{\n if (element[rangeMethod] && element[rangeMethod](position[axis], useFinalPosition)) {\n items.push({\n element,\n datasetIndex,\n index\n });\n intersectsItem = intersectsItem || element.inRange(position.x, position.y, useFinalPosition);\n }\n });\n if (intersect && !intersectsItem) {\n return [];\n }\n return items;\n}\n var Interaction = {\n evaluateInteractionItems,\n modes: {\n index (chart, e, options, useFinalPosition) {\n const position = getRelativePosition(e, chart);\n const axis = options.axis || 'x';\n const includeInvisible = options.includeInvisible || false;\n const items = options.intersect ? getIntersectItems(chart, position, axis, useFinalPosition, includeInvisible) : getNearestItems(chart, position, axis, false, useFinalPosition, includeInvisible);\n const elements = [];\n if (!items.length) {\n return [];\n }\n chart.getSortedVisibleDatasetMetas().forEach((meta)=>{\n const index = items[0].index;\n const element = meta.data[index];\n if (element && !element.skip) {\n elements.push({\n element,\n datasetIndex: meta.index,\n index\n });\n }\n });\n return elements;\n },\n dataset (chart, e, options, useFinalPosition) {\n const position = getRelativePosition(e, chart);\n const axis = options.axis || 'xy';\n const includeInvisible = options.includeInvisible || false;\n let items = options.intersect ? getIntersectItems(chart, position, axis, useFinalPosition, includeInvisible) : getNearestItems(chart, position, axis, false, useFinalPosition, includeInvisible);\n if (items.length > 0) {\n const datasetIndex = items[0].datasetIndex;\n const data = chart.getDatasetMeta(datasetIndex).data;\n items = [];\n for(let i = 0; i < data.length; ++i){\n items.push({\n element: data[i],\n datasetIndex,\n index: i\n });\n }\n }\n return items;\n },\n point (chart, e, options, useFinalPosition) {\n const position = getRelativePosition(e, chart);\n const axis = options.axis || 'xy';\n const includeInvisible = options.includeInvisible || false;\n return getIntersectItems(chart, position, axis, useFinalPosition, includeInvisible);\n },\n nearest (chart, e, options, useFinalPosition) {\n const position = getRelativePosition(e, chart);\n const axis = options.axis || 'xy';\n const includeInvisible = options.includeInvisible || false;\n return getNearestItems(chart, position, axis, options.intersect, useFinalPosition, includeInvisible);\n },\n x (chart, e, options, useFinalPosition) {\n const position = getRelativePosition(e, chart);\n return getAxisItems(chart, position, 'x', options.intersect, useFinalPosition);\n },\n y (chart, e, options, useFinalPosition) {\n const position = getRelativePosition(e, chart);\n return getAxisItems(chart, position, 'y', options.intersect, useFinalPosition);\n }\n }\n};\n\nconst STATIC_POSITIONS = [\n 'left',\n 'top',\n 'right',\n 'bottom'\n];\nfunction filterByPosition(array, position) {\n return array.filter((v)=>v.pos === position);\n}\nfunction filterDynamicPositionByAxis(array, axis) {\n return array.filter((v)=>STATIC_POSITIONS.indexOf(v.pos) === -1 && v.box.axis === axis);\n}\nfunction sortByWeight(array, reverse) {\n return array.sort((a, b)=>{\n const v0 = reverse ? b : a;\n const v1 = reverse ? a : b;\n return v0.weight === v1.weight ? v0.index - v1.index : v0.weight - v1.weight;\n });\n}\nfunction wrapBoxes(boxes) {\n const layoutBoxes = [];\n let i, ilen, box, pos, stack, stackWeight;\n for(i = 0, ilen = (boxes || []).length; i < ilen; ++i){\n box = boxes[i];\n ({ position: pos , options: { stack , stackWeight =1 } } = box);\n layoutBoxes.push({\n index: i,\n box,\n pos,\n horizontal: box.isHorizontal(),\n weight: box.weight,\n stack: stack && pos + stack,\n stackWeight\n });\n }\n return layoutBoxes;\n}\nfunction buildStacks(layouts) {\n const stacks = {};\n for (const wrap of layouts){\n const { stack , pos , stackWeight } = wrap;\n if (!stack || !STATIC_POSITIONS.includes(pos)) {\n continue;\n }\n const _stack = stacks[stack] || (stacks[stack] = {\n count: 0,\n placed: 0,\n weight: 0,\n size: 0\n });\n _stack.count++;\n _stack.weight += stackWeight;\n }\n return stacks;\n}\n function setLayoutDims(layouts, params) {\n const stacks = buildStacks(layouts);\n const { vBoxMaxWidth , hBoxMaxHeight } = params;\n let i, ilen, layout;\n for(i = 0, ilen = layouts.length; i < ilen; ++i){\n layout = layouts[i];\n const { fullSize } = layout.box;\n const stack = stacks[layout.stack];\n const factor = stack && layout.stackWeight / stack.weight;\n if (layout.horizontal) {\n layout.width = factor ? factor * vBoxMaxWidth : fullSize && params.availableWidth;\n layout.height = hBoxMaxHeight;\n } else {\n layout.width = vBoxMaxWidth;\n layout.height = factor ? factor * hBoxMaxHeight : fullSize && params.availableHeight;\n }\n }\n return stacks;\n}\nfunction buildLayoutBoxes(boxes) {\n const layoutBoxes = wrapBoxes(boxes);\n const fullSize = sortByWeight(layoutBoxes.filter((wrap)=>wrap.box.fullSize), true);\n const left = sortByWeight(filterByPosition(layoutBoxes, 'left'), true);\n const right = sortByWeight(filterByPosition(layoutBoxes, 'right'));\n const top = sortByWeight(filterByPosition(layoutBoxes, 'top'), true);\n const bottom = sortByWeight(filterByPosition(layoutBoxes, 'bottom'));\n const centerHorizontal = filterDynamicPositionByAxis(layoutBoxes, 'x');\n const centerVertical = filterDynamicPositionByAxis(layoutBoxes, 'y');\n return {\n fullSize,\n leftAndTop: left.concat(top),\n rightAndBottom: right.concat(centerVertical).concat(bottom).concat(centerHorizontal),\n chartArea: filterByPosition(layoutBoxes, 'chartArea'),\n vertical: left.concat(right).concat(centerVertical),\n horizontal: top.concat(bottom).concat(centerHorizontal)\n };\n}\nfunction getCombinedMax(maxPadding, chartArea, a, b) {\n return Math.max(maxPadding[a], chartArea[a]) + Math.max(maxPadding[b], chartArea[b]);\n}\nfunction updateMaxPadding(maxPadding, boxPadding) {\n maxPadding.top = Math.max(maxPadding.top, boxPadding.top);\n maxPadding.left = Math.max(maxPadding.left, boxPadding.left);\n maxPadding.bottom = Math.max(maxPadding.bottom, boxPadding.bottom);\n maxPadding.right = Math.max(maxPadding.right, boxPadding.right);\n}\nfunction updateDims(chartArea, params, layout, stacks) {\n const { pos , box } = layout;\n const maxPadding = chartArea.maxPadding;\n if (!isObject(pos)) {\n if (layout.size) {\n chartArea[pos] -= layout.size;\n }\n const stack = stacks[layout.stack] || {\n size: 0,\n count: 1\n };\n stack.size = Math.max(stack.size, layout.horizontal ? box.height : box.width);\n layout.size = stack.size / stack.count;\n chartArea[pos] += layout.size;\n }\n if (box.getPadding) {\n updateMaxPadding(maxPadding, box.getPadding());\n }\n const newWidth = Math.max(0, params.outerWidth - getCombinedMax(maxPadding, chartArea, 'left', 'right'));\n const newHeight = Math.max(0, params.outerHeight - getCombinedMax(maxPadding, chartArea, 'top', 'bottom'));\n const widthChanged = newWidth !== chartArea.w;\n const heightChanged = newHeight !== chartArea.h;\n chartArea.w = newWidth;\n chartArea.h = newHeight;\n return layout.horizontal ? {\n same: widthChanged,\n other: heightChanged\n } : {\n same: heightChanged,\n other: widthChanged\n };\n}\nfunction handleMaxPadding(chartArea) {\n const maxPadding = chartArea.maxPadding;\n function updatePos(pos) {\n const change = Math.max(maxPadding[pos] - chartArea[pos], 0);\n chartArea[pos] += change;\n return change;\n }\n chartArea.y += updatePos('top');\n chartArea.x += updatePos('left');\n updatePos('right');\n updatePos('bottom');\n}\nfunction getMargins(horizontal, chartArea) {\n const maxPadding = chartArea.maxPadding;\n function marginForPositions(positions) {\n const margin = {\n left: 0,\n top: 0,\n right: 0,\n bottom: 0\n };\n positions.forEach((pos)=>{\n margin[pos] = Math.max(chartArea[pos], maxPadding[pos]);\n });\n return margin;\n }\n return horizontal ? marginForPositions([\n 'left',\n 'right'\n ]) : marginForPositions([\n 'top',\n 'bottom'\n ]);\n}\nfunction fitBoxes(boxes, chartArea, params, stacks) {\n const refitBoxes = [];\n let i, ilen, layout, box, refit, changed;\n for(i = 0, ilen = boxes.length, refit = 0; i < ilen; ++i){\n layout = boxes[i];\n box = layout.box;\n box.update(layout.width || chartArea.w, layout.height || chartArea.h, getMargins(layout.horizontal, chartArea));\n const { same , other } = updateDims(chartArea, params, layout, stacks);\n refit |= same && refitBoxes.length;\n changed = changed || other;\n if (!box.fullSize) {\n refitBoxes.push(layout);\n }\n }\n return refit && fitBoxes(refitBoxes, chartArea, params, stacks) || changed;\n}\nfunction setBoxDims(box, left, top, width, height) {\n box.top = top;\n box.left = left;\n box.right = left + width;\n box.bottom = top + height;\n box.width = width;\n box.height = height;\n}\nfunction placeBoxes(boxes, chartArea, params, stacks) {\n const userPadding = params.padding;\n let { x , y } = chartArea;\n for (const layout of boxes){\n const box = layout.box;\n const stack = stacks[layout.stack] || {\n count: 1,\n placed: 0,\n weight: 1\n };\n const weight = layout.stackWeight / stack.weight || 1;\n if (layout.horizontal) {\n const width = chartArea.w * weight;\n const height = stack.size || box.height;\n if (defined(stack.start)) {\n y = stack.start;\n }\n if (box.fullSize) {\n setBoxDims(box, userPadding.left, y, params.outerWidth - userPadding.right - userPadding.left, height);\n } else {\n setBoxDims(box, chartArea.left + stack.placed, y, width, height);\n }\n stack.start = y;\n stack.placed += width;\n y = box.bottom;\n } else {\n const height = chartArea.h * weight;\n const width = stack.size || box.width;\n if (defined(stack.start)) {\n x = stack.start;\n }\n if (box.fullSize) {\n setBoxDims(box, x, userPadding.top, width, params.outerHeight - userPadding.bottom - userPadding.top);\n } else {\n setBoxDims(box, x, chartArea.top + stack.placed, width, height);\n }\n stack.start = x;\n stack.placed += height;\n x = box.right;\n }\n }\n chartArea.x = x;\n chartArea.y = y;\n}\nvar layouts = {\n addBox (chart, item) {\n if (!chart.boxes) {\n chart.boxes = [];\n }\n item.fullSize = item.fullSize || false;\n item.position = item.position || 'top';\n item.weight = item.weight || 0;\n item._layers = item._layers || function() {\n return [\n {\n z: 0,\n draw (chartArea) {\n item.draw(chartArea);\n }\n }\n ];\n };\n chart.boxes.push(item);\n },\n removeBox (chart, layoutItem) {\n const index = chart.boxes ? chart.boxes.indexOf(layoutItem) : -1;\n if (index !== -1) {\n chart.boxes.splice(index, 1);\n }\n },\n configure (chart, item, options) {\n item.fullSize = options.fullSize;\n item.position = options.position;\n item.weight = options.weight;\n },\n update (chart, width, height, minPadding) {\n if (!chart) {\n return;\n }\n const padding = toPadding(chart.options.layout.padding);\n const availableWidth = Math.max(width - padding.width, 0);\n const availableHeight = Math.max(height - padding.height, 0);\n const boxes = buildLayoutBoxes(chart.boxes);\n const verticalBoxes = boxes.vertical;\n const horizontalBoxes = boxes.horizontal;\n each(chart.boxes, (box)=>{\n if (typeof box.beforeLayout === 'function') {\n box.beforeLayout();\n }\n });\n const visibleVerticalBoxCount = verticalBoxes.reduce((total, wrap)=>wrap.box.options && wrap.box.options.display === false ? total : total + 1, 0) || 1;\n const params = Object.freeze({\n outerWidth: width,\n outerHeight: height,\n padding,\n availableWidth,\n availableHeight,\n vBoxMaxWidth: availableWidth / 2 / visibleVerticalBoxCount,\n hBoxMaxHeight: availableHeight / 2\n });\n const maxPadding = Object.assign({}, padding);\n updateMaxPadding(maxPadding, toPadding(minPadding));\n const chartArea = Object.assign({\n maxPadding,\n w: availableWidth,\n h: availableHeight,\n x: padding.left,\n y: padding.top\n }, padding);\n const stacks = setLayoutDims(verticalBoxes.concat(horizontalBoxes), params);\n fitBoxes(boxes.fullSize, chartArea, params, stacks);\n fitBoxes(verticalBoxes, chartArea, params, stacks);\n if (fitBoxes(horizontalBoxes, chartArea, params, stacks)) {\n fitBoxes(verticalBoxes, chartArea, params, stacks);\n }\n handleMaxPadding(chartArea);\n placeBoxes(boxes.leftAndTop, chartArea, params, stacks);\n chartArea.x += chartArea.w;\n chartArea.y += chartArea.h;\n placeBoxes(boxes.rightAndBottom, chartArea, params, stacks);\n chart.chartArea = {\n left: chartArea.left,\n top: chartArea.top,\n right: chartArea.left + chartArea.w,\n bottom: chartArea.top + chartArea.h,\n height: chartArea.h,\n width: chartArea.w\n };\n each(boxes.chartArea, (layout)=>{\n const box = layout.box;\n Object.assign(box, chart.chartArea);\n box.update(chartArea.w, chartArea.h, {\n left: 0,\n top: 0,\n right: 0,\n bottom: 0\n });\n });\n }\n};\n\nclass BasePlatform {\n acquireContext(canvas, aspectRatio) {}\n releaseContext(context) {\n return false;\n }\n addEventListener(chart, type, listener) {}\n removeEventListener(chart, type, listener) {}\n getDevicePixelRatio() {\n return 1;\n }\n getMaximumSize(element, width, height, aspectRatio) {\n width = Math.max(0, width || element.width);\n height = height || element.height;\n return {\n width,\n height: Math.max(0, aspectRatio ? Math.floor(width / aspectRatio) : height)\n };\n }\n isAttached(canvas) {\n return true;\n }\n updateConfig(config) {\n }\n}\n\nclass BasicPlatform extends BasePlatform {\n acquireContext(item) {\n return item && item.getContext && item.getContext('2d') || null;\n }\n updateConfig(config) {\n config.options.animation = false;\n }\n}\n\nconst EXPANDO_KEY = '$chartjs';\n const EVENT_TYPES = {\n touchstart: 'mousedown',\n touchmove: 'mousemove',\n touchend: 'mouseup',\n pointerenter: 'mouseenter',\n pointerdown: 'mousedown',\n pointermove: 'mousemove',\n pointerup: 'mouseup',\n pointerleave: 'mouseout',\n pointerout: 'mouseout'\n};\nconst isNullOrEmpty = (value)=>value === null || value === '';\n function initCanvas(canvas, aspectRatio) {\n const style = canvas.style;\n const renderHeight = canvas.getAttribute('height');\n const renderWidth = canvas.getAttribute('width');\n canvas[EXPANDO_KEY] = {\n initial: {\n height: renderHeight,\n width: renderWidth,\n style: {\n display: style.display,\n height: style.height,\n width: style.width\n }\n }\n };\n style.display = style.display || 'block';\n style.boxSizing = style.boxSizing || 'border-box';\n if (isNullOrEmpty(renderWidth)) {\n const displayWidth = readUsedSize(canvas, 'width');\n if (displayWidth !== undefined) {\n canvas.width = displayWidth;\n }\n }\n if (isNullOrEmpty(renderHeight)) {\n if (canvas.style.height === '') {\n canvas.height = canvas.width / (aspectRatio || 2);\n } else {\n const displayHeight = readUsedSize(canvas, 'height');\n if (displayHeight !== undefined) {\n canvas.height = displayHeight;\n }\n }\n }\n return canvas;\n}\nconst eventListenerOptions = supportsEventListenerOptions ? {\n passive: true\n} : false;\nfunction addListener(node, type, listener) {\n if (node) {\n node.addEventListener(type, listener, eventListenerOptions);\n }\n}\nfunction removeListener(chart, type, listener) {\n if (chart && chart.canvas) {\n chart.canvas.removeEventListener(type, listener, eventListenerOptions);\n }\n}\nfunction fromNativeEvent(event, chart) {\n const type = EVENT_TYPES[event.type] || event.type;\n const { x , y } = getRelativePosition(event, chart);\n return {\n type,\n chart,\n native: event,\n x: x !== undefined ? x : null,\n y: y !== undefined ? y : null\n };\n}\nfunction nodeListContains(nodeList, canvas) {\n for (const node of nodeList){\n if (node === canvas || node.contains(canvas)) {\n return true;\n }\n }\n}\nfunction createAttachObserver(chart, type, listener) {\n const canvas = chart.canvas;\n const observer = new MutationObserver((entries)=>{\n let trigger = false;\n for (const entry of entries){\n trigger = trigger || nodeListContains(entry.addedNodes, canvas);\n trigger = trigger && !nodeListContains(entry.removedNodes, canvas);\n }\n if (trigger) {\n listener();\n }\n });\n observer.observe(document, {\n childList: true,\n subtree: true\n });\n return observer;\n}\nfunction createDetachObserver(chart, type, listener) {\n const canvas = chart.canvas;\n const observer = new MutationObserver((entries)=>{\n let trigger = false;\n for (const entry of entries){\n trigger = trigger || nodeListContains(entry.removedNodes, canvas);\n trigger = trigger && !nodeListContains(entry.addedNodes, canvas);\n }\n if (trigger) {\n listener();\n }\n });\n observer.observe(document, {\n childList: true,\n subtree: true\n });\n return observer;\n}\nconst drpListeningCharts = new Map();\nlet oldDevicePixelRatio = 0;\nfunction onWindowResize() {\n const dpr = window.devicePixelRatio;\n if (dpr === oldDevicePixelRatio) {\n return;\n }\n oldDevicePixelRatio = dpr;\n drpListeningCharts.forEach((resize, chart)=>{\n if (chart.currentDevicePixelRatio !== dpr) {\n resize();\n }\n });\n}\nfunction listenDevicePixelRatioChanges(chart, resize) {\n if (!drpListeningCharts.size) {\n window.addEventListener('resize', onWindowResize);\n }\n drpListeningCharts.set(chart, resize);\n}\nfunction unlistenDevicePixelRatioChanges(chart) {\n drpListeningCharts.delete(chart);\n if (!drpListeningCharts.size) {\n window.removeEventListener('resize', onWindowResize);\n }\n}\nfunction createResizeObserver(chart, type, listener) {\n const canvas = chart.canvas;\n const container = canvas && _getParentNode(canvas);\n if (!container) {\n return;\n }\n const resize = throttled((width, height)=>{\n const w = container.clientWidth;\n listener(width, height);\n if (w < container.clientWidth) {\n listener();\n }\n }, window);\n const observer = new ResizeObserver((entries)=>{\n const entry = entries[0];\n const width = entry.contentRect.width;\n const height = entry.contentRect.height;\n if (width === 0 && height === 0) {\n return;\n }\n resize(width, height);\n });\n observer.observe(container);\n listenDevicePixelRatioChanges(chart, resize);\n return observer;\n}\nfunction releaseObserver(chart, type, observer) {\n if (observer) {\n observer.disconnect();\n }\n if (type === 'resize') {\n unlistenDevicePixelRatioChanges(chart);\n }\n}\nfunction createProxyAndListen(chart, type, listener) {\n const canvas = chart.canvas;\n const proxy = throttled((event)=>{\n if (chart.ctx !== null) {\n listener(fromNativeEvent(event, chart));\n }\n }, chart);\n addListener(canvas, type, proxy);\n return proxy;\n}\n class DomPlatform extends BasePlatform {\n acquireContext(canvas, aspectRatio) {\n const context = canvas && canvas.getContext && canvas.getContext('2d');\n if (context && context.canvas === canvas) {\n initCanvas(canvas, aspectRatio);\n return context;\n }\n return null;\n }\n releaseContext(context) {\n const canvas = context.canvas;\n if (!canvas[EXPANDO_KEY]) {\n return false;\n }\n const initial = canvas[EXPANDO_KEY].initial;\n [\n 'height',\n 'width'\n ].forEach((prop)=>{\n const value = initial[prop];\n if (isNullOrUndef(value)) {\n canvas.removeAttribute(prop);\n } else {\n canvas.setAttribute(prop, value);\n }\n });\n const style = initial.style || {};\n Object.keys(style).forEach((key)=>{\n canvas.style[key] = style[key];\n });\n canvas.width = canvas.width;\n delete canvas[EXPANDO_KEY];\n return true;\n }\n addEventListener(chart, type, listener) {\n this.removeEventListener(chart, type);\n const proxies = chart.$proxies || (chart.$proxies = {});\n const handlers = {\n attach: createAttachObserver,\n detach: createDetachObserver,\n resize: createResizeObserver\n };\n const handler = handlers[type] || createProxyAndListen;\n proxies[type] = handler(chart, type, listener);\n }\n removeEventListener(chart, type) {\n const proxies = chart.$proxies || (chart.$proxies = {});\n const proxy = proxies[type];\n if (!proxy) {\n return;\n }\n const handlers = {\n attach: releaseObserver,\n detach: releaseObserver,\n resize: releaseObserver\n };\n const handler = handlers[type] || removeListener;\n handler(chart, type, proxy);\n proxies[type] = undefined;\n }\n getDevicePixelRatio() {\n return window.devicePixelRatio;\n }\n getMaximumSize(canvas, width, height, aspectRatio) {\n return getMaximumSize(canvas, width, height, aspectRatio);\n }\n isAttached(canvas) {\n const container = canvas && _getParentNode(canvas);\n return !!(container && container.isConnected);\n }\n}\n\nfunction _detectPlatform(canvas) {\n if (!_isDomSupported() || typeof OffscreenCanvas !== 'undefined' && canvas instanceof OffscreenCanvas) {\n return BasicPlatform;\n }\n return DomPlatform;\n}\n\nclass chart_Element {\n static defaults = {};\n static defaultRoutes = undefined;\n x;\n y;\n active = false;\n options;\n $animations;\n tooltipPosition(useFinalPosition) {\n const { x , y } = this.getProps([\n 'x',\n 'y'\n ], useFinalPosition);\n return {\n x,\n y\n };\n }\n hasValue() {\n return isNumber(this.x) && isNumber(this.y);\n }\n getProps(props, final) {\n const anims = this.$animations;\n if (!final || !anims) {\n // let's not create an object, if not needed\n return this;\n }\n const ret = {};\n props.forEach((prop)=>{\n ret[prop] = anims[prop] && anims[prop].active() ? anims[prop]._to : this[prop];\n });\n return ret;\n }\n}\n\nfunction autoSkip(scale, ticks) {\n const tickOpts = scale.options.ticks;\n const determinedMaxTicks = determineMaxTicks(scale);\n const ticksLimit = Math.min(tickOpts.maxTicksLimit || determinedMaxTicks, determinedMaxTicks);\n const majorIndices = tickOpts.major.enabled ? getMajorIndices(ticks) : [];\n const numMajorIndices = majorIndices.length;\n const first = majorIndices[0];\n const last = majorIndices[numMajorIndices - 1];\n const newTicks = [];\n if (numMajorIndices > ticksLimit) {\n skipMajors(ticks, newTicks, majorIndices, numMajorIndices / ticksLimit);\n return newTicks;\n }\n const spacing = calculateSpacing(majorIndices, ticks, ticksLimit);\n if (numMajorIndices > 0) {\n let i, ilen;\n const avgMajorSpacing = numMajorIndices > 1 ? Math.round((last - first) / (numMajorIndices - 1)) : null;\n skip(ticks, newTicks, spacing, isNullOrUndef(avgMajorSpacing) ? 0 : first - avgMajorSpacing, first);\n for(i = 0, ilen = numMajorIndices - 1; i < ilen; i++){\n skip(ticks, newTicks, spacing, majorIndices[i], majorIndices[i + 1]);\n }\n skip(ticks, newTicks, spacing, last, isNullOrUndef(avgMajorSpacing) ? ticks.length : last + avgMajorSpacing);\n return newTicks;\n }\n skip(ticks, newTicks, spacing);\n return newTicks;\n}\nfunction determineMaxTicks(scale) {\n const offset = scale.options.offset;\n const tickLength = scale._tickSize();\n const maxScale = scale._length / tickLength + (offset ? 0 : 1);\n const maxChart = scale._maxLength / tickLength;\n return Math.floor(Math.min(maxScale, maxChart));\n}\n function calculateSpacing(majorIndices, ticks, ticksLimit) {\n const evenMajorSpacing = getEvenSpacing(majorIndices);\n const spacing = ticks.length / ticksLimit;\n if (!evenMajorSpacing) {\n return Math.max(spacing, 1);\n }\n const factors = _factorize(evenMajorSpacing);\n for(let i = 0, ilen = factors.length - 1; i < ilen; i++){\n const factor = factors[i];\n if (factor > spacing) {\n return factor;\n }\n }\n return Math.max(spacing, 1);\n}\n function getMajorIndices(ticks) {\n const result = [];\n let i, ilen;\n for(i = 0, ilen = ticks.length; i < ilen; i++){\n if (ticks[i].major) {\n result.push(i);\n }\n }\n return result;\n}\n function skipMajors(ticks, newTicks, majorIndices, spacing) {\n let count = 0;\n let next = majorIndices[0];\n let i;\n spacing = Math.ceil(spacing);\n for(i = 0; i < ticks.length; i++){\n if (i === next) {\n newTicks.push(ticks[i]);\n count++;\n next = majorIndices[count * spacing];\n }\n }\n}\n function skip(ticks, newTicks, spacing, majorStart, majorEnd) {\n const start = valueOrDefault(majorStart, 0);\n const end = Math.min(valueOrDefault(majorEnd, ticks.length), ticks.length);\n let count = 0;\n let length, i, next;\n spacing = Math.ceil(spacing);\n if (majorEnd) {\n length = majorEnd - majorStart;\n spacing = length / Math.floor(length / spacing);\n }\n next = start;\n while(next < 0){\n count++;\n next = Math.round(start + count * spacing);\n }\n for(i = Math.max(start, 0); i < end; i++){\n if (i === next) {\n newTicks.push(ticks[i]);\n count++;\n next = Math.round(start + count * spacing);\n }\n }\n}\n function getEvenSpacing(arr) {\n const len = arr.length;\n let i, diff;\n if (len < 2) {\n return false;\n }\n for(diff = arr[0], i = 1; i < len; ++i){\n if (arr[i] - arr[i - 1] !== diff) {\n return false;\n }\n }\n return diff;\n}\n\nconst reverseAlign = (align)=>align === 'left' ? 'right' : align === 'right' ? 'left' : align;\nconst offsetFromEdge = (scale, edge, offset)=>edge === 'top' || edge === 'left' ? scale[edge] + offset : scale[edge] - offset;\nconst getTicksLimit = (ticksLength, maxTicksLimit)=>Math.min(maxTicksLimit || ticksLength, ticksLength);\n function sample(arr, numItems) {\n const result = [];\n const increment = arr.length / numItems;\n const len = arr.length;\n let i = 0;\n for(; i < len; i += increment){\n result.push(arr[Math.floor(i)]);\n }\n return result;\n}\n function getPixelForGridLine(scale, index, offsetGridLines) {\n const length = scale.ticks.length;\n const validIndex = Math.min(index, length - 1);\n const start = scale._startPixel;\n const end = scale._endPixel;\n const epsilon = 1e-6;\n let lineValue = scale.getPixelForTick(validIndex);\n let offset;\n if (offsetGridLines) {\n if (length === 1) {\n offset = Math.max(lineValue - start, end - lineValue);\n } else if (index === 0) {\n offset = (scale.getPixelForTick(1) - lineValue) / 2;\n } else {\n offset = (lineValue - scale.getPixelForTick(validIndex - 1)) / 2;\n }\n lineValue += validIndex < index ? offset : -offset;\n if (lineValue < start - epsilon || lineValue > end + epsilon) {\n return;\n }\n }\n return lineValue;\n}\n function garbageCollect(caches, length) {\n each(caches, (cache)=>{\n const gc = cache.gc;\n const gcLen = gc.length / 2;\n let i;\n if (gcLen > length) {\n for(i = 0; i < gcLen; ++i){\n delete cache.data[gc[i]];\n }\n gc.splice(0, gcLen);\n }\n });\n}\n function getTickMarkLength(options) {\n return options.drawTicks ? options.tickLength : 0;\n}\n function getTitleHeight(options, fallback) {\n if (!options.display) {\n return 0;\n }\n const font = toFont(options.font, fallback);\n const padding = toPadding(options.padding);\n const lines = isArray(options.text) ? options.text.length : 1;\n return lines * font.lineHeight + padding.height;\n}\nfunction createScaleContext(parent, scale) {\n return createContext(parent, {\n scale,\n type: 'scale'\n });\n}\nfunction createTickContext(parent, index, tick) {\n return createContext(parent, {\n tick,\n index,\n type: 'tick'\n });\n}\nfunction titleAlign(align, position, reverse) {\n let ret = _toLeftRightCenter(align);\n if (reverse && position !== 'right' || !reverse && position === 'right') {\n ret = reverseAlign(ret);\n }\n return ret;\n}\nfunction titleArgs(scale, offset, position, align) {\n const { top , left , bottom , right , chart } = scale;\n const { chartArea , scales } = chart;\n let rotation = 0;\n let maxWidth, titleX, titleY;\n const height = bottom - top;\n const width = right - left;\n if (scale.isHorizontal()) {\n titleX = _alignStartEnd(align, left, right);\n if (isObject(position)) {\n const positionAxisID = Object.keys(position)[0];\n const value = position[positionAxisID];\n titleY = scales[positionAxisID].getPixelForValue(value) + height - offset;\n } else if (position === 'center') {\n titleY = (chartArea.bottom + chartArea.top) / 2 + height - offset;\n } else {\n titleY = offsetFromEdge(scale, position, offset);\n }\n maxWidth = right - left;\n } else {\n if (isObject(position)) {\n const positionAxisID = Object.keys(position)[0];\n const value = position[positionAxisID];\n titleX = scales[positionAxisID].getPixelForValue(value) - width + offset;\n } else if (position === 'center') {\n titleX = (chartArea.left + chartArea.right) / 2 - width + offset;\n } else {\n titleX = offsetFromEdge(scale, position, offset);\n }\n titleY = _alignStartEnd(align, bottom, top);\n rotation = position === 'left' ? -HALF_PI : HALF_PI;\n }\n return {\n titleX,\n titleY,\n maxWidth,\n rotation\n };\n}\nclass Scale extends chart_Element {\n constructor(cfg){\n super();\n this.id = cfg.id;\n this.type = cfg.type;\n this.options = undefined;\n this.ctx = cfg.ctx;\n this.chart = cfg.chart;\n this.top = undefined;\n this.bottom = undefined;\n this.left = undefined;\n this.right = undefined;\n this.width = undefined;\n this.height = undefined;\n this._margins = {\n left: 0,\n right: 0,\n top: 0,\n bottom: 0\n };\n this.maxWidth = undefined;\n this.maxHeight = undefined;\n this.paddingTop = undefined;\n this.paddingBottom = undefined;\n this.paddingLeft = undefined;\n this.paddingRight = undefined;\n this.axis = undefined;\n this.labelRotation = undefined;\n this.min = undefined;\n this.max = undefined;\n this._range = undefined;\n this.ticks = [];\n this._gridLineItems = null;\n this._labelItems = null;\n this._labelSizes = null;\n this._length = 0;\n this._maxLength = 0;\n this._longestTextCache = {};\n this._startPixel = undefined;\n this._endPixel = undefined;\n this._reversePixels = false;\n this._userMax = undefined;\n this._userMin = undefined;\n this._suggestedMax = undefined;\n this._suggestedMin = undefined;\n this._ticksLength = 0;\n this._borderValue = 0;\n this._cache = {};\n this._dataLimitsCached = false;\n this.$context = undefined;\n }\n init(options) {\n this.options = options.setContext(this.getContext());\n this.axis = options.axis;\n this._userMin = this.parse(options.min);\n this._userMax = this.parse(options.max);\n this._suggestedMin = this.parse(options.suggestedMin);\n this._suggestedMax = this.parse(options.suggestedMax);\n }\n parse(raw, index) {\n return raw;\n }\n getUserBounds() {\n let { _userMin , _userMax , _suggestedMin , _suggestedMax } = this;\n _userMin = finiteOrDefault(_userMin, Number.POSITIVE_INFINITY);\n _userMax = finiteOrDefault(_userMax, Number.NEGATIVE_INFINITY);\n _suggestedMin = finiteOrDefault(_suggestedMin, Number.POSITIVE_INFINITY);\n _suggestedMax = finiteOrDefault(_suggestedMax, Number.NEGATIVE_INFINITY);\n return {\n min: finiteOrDefault(_userMin, _suggestedMin),\n max: finiteOrDefault(_userMax, _suggestedMax),\n minDefined: isNumberFinite(_userMin),\n maxDefined: isNumberFinite(_userMax)\n };\n }\n getMinMax(canStack) {\n let { min , max , minDefined , maxDefined } = this.getUserBounds();\n let range;\n if (minDefined && maxDefined) {\n return {\n min,\n max\n };\n }\n const metas = this.getMatchingVisibleMetas();\n for(let i = 0, ilen = metas.length; i < ilen; ++i){\n range = metas[i].controller.getMinMax(this, canStack);\n if (!minDefined) {\n min = Math.min(min, range.min);\n }\n if (!maxDefined) {\n max = Math.max(max, range.max);\n }\n }\n min = maxDefined && min > max ? max : min;\n max = minDefined && min > max ? min : max;\n return {\n min: finiteOrDefault(min, finiteOrDefault(max, min)),\n max: finiteOrDefault(max, finiteOrDefault(min, max))\n };\n }\n getPadding() {\n return {\n left: this.paddingLeft || 0,\n top: this.paddingTop || 0,\n right: this.paddingRight || 0,\n bottom: this.paddingBottom || 0\n };\n }\n getTicks() {\n return this.ticks;\n }\n getLabels() {\n const data = this.chart.data;\n return this.options.labels || (this.isHorizontal() ? data.xLabels : data.yLabels) || data.labels || [];\n }\n getLabelItems(chartArea = this.chart.chartArea) {\n const items = this._labelItems || (this._labelItems = this._computeLabelItems(chartArea));\n return items;\n }\n beforeLayout() {\n this._cache = {};\n this._dataLimitsCached = false;\n }\n beforeUpdate() {\n callback(this.options.beforeUpdate, [\n this\n ]);\n }\n update(maxWidth, maxHeight, margins) {\n const { beginAtZero , grace , ticks: tickOpts } = this.options;\n const sampleSize = tickOpts.sampleSize;\n this.beforeUpdate();\n this.maxWidth = maxWidth;\n this.maxHeight = maxHeight;\n this._margins = margins = Object.assign({\n left: 0,\n right: 0,\n top: 0,\n bottom: 0\n }, margins);\n this.ticks = null;\n this._labelSizes = null;\n this._gridLineItems = null;\n this._labelItems = null;\n this.beforeSetDimensions();\n this.setDimensions();\n this.afterSetDimensions();\n this._maxLength = this.isHorizontal() ? this.width + margins.left + margins.right : this.height + margins.top + margins.bottom;\n if (!this._dataLimitsCached) {\n this.beforeDataLimits();\n this.determineDataLimits();\n this.afterDataLimits();\n this._range = _addGrace(this, grace, beginAtZero);\n this._dataLimitsCached = true;\n }\n this.beforeBuildTicks();\n this.ticks = this.buildTicks() || [];\n this.afterBuildTicks();\n const samplingEnabled = sampleSize < this.ticks.length;\n this._convertTicksToLabels(samplingEnabled ? sample(this.ticks, sampleSize) : this.ticks);\n this.configure();\n this.beforeCalculateLabelRotation();\n this.calculateLabelRotation();\n this.afterCalculateLabelRotation();\n if (tickOpts.display && (tickOpts.autoSkip || tickOpts.source === 'auto')) {\n this.ticks = autoSkip(this, this.ticks);\n this._labelSizes = null;\n this.afterAutoSkip();\n }\n if (samplingEnabled) {\n this._convertTicksToLabels(this.ticks);\n }\n this.beforeFit();\n this.fit();\n this.afterFit();\n this.afterUpdate();\n }\n configure() {\n let reversePixels = this.options.reverse;\n let startPixel, endPixel;\n if (this.isHorizontal()) {\n startPixel = this.left;\n endPixel = this.right;\n } else {\n startPixel = this.top;\n endPixel = this.bottom;\n reversePixels = !reversePixels;\n }\n this._startPixel = startPixel;\n this._endPixel = endPixel;\n this._reversePixels = reversePixels;\n this._length = endPixel - startPixel;\n this._alignToPixels = this.options.alignToPixels;\n }\n afterUpdate() {\n callback(this.options.afterUpdate, [\n this\n ]);\n }\n beforeSetDimensions() {\n callback(this.options.beforeSetDimensions, [\n this\n ]);\n }\n setDimensions() {\n if (this.isHorizontal()) {\n this.width = this.maxWidth;\n this.left = 0;\n this.right = this.width;\n } else {\n this.height = this.maxHeight;\n this.top = 0;\n this.bottom = this.height;\n }\n this.paddingLeft = 0;\n this.paddingTop = 0;\n this.paddingRight = 0;\n this.paddingBottom = 0;\n }\n afterSetDimensions() {\n callback(this.options.afterSetDimensions, [\n this\n ]);\n }\n _callHooks(name) {\n this.chart.notifyPlugins(name, this.getContext());\n callback(this.options[name], [\n this\n ]);\n }\n beforeDataLimits() {\n this._callHooks('beforeDataLimits');\n }\n determineDataLimits() {}\n afterDataLimits() {\n this._callHooks('afterDataLimits');\n }\n beforeBuildTicks() {\n this._callHooks('beforeBuildTicks');\n }\n buildTicks() {\n return [];\n }\n afterBuildTicks() {\n this._callHooks('afterBuildTicks');\n }\n beforeTickToLabelConversion() {\n callback(this.options.beforeTickToLabelConversion, [\n this\n ]);\n }\n generateTickLabels(ticks) {\n const tickOpts = this.options.ticks;\n let i, ilen, tick;\n for(i = 0, ilen = ticks.length; i < ilen; i++){\n tick = ticks[i];\n tick.label = callback(tickOpts.callback, [\n tick.value,\n i,\n ticks\n ], this);\n }\n }\n afterTickToLabelConversion() {\n callback(this.options.afterTickToLabelConversion, [\n this\n ]);\n }\n beforeCalculateLabelRotation() {\n callback(this.options.beforeCalculateLabelRotation, [\n this\n ]);\n }\n calculateLabelRotation() {\n const options = this.options;\n const tickOpts = options.ticks;\n const numTicks = getTicksLimit(this.ticks.length, options.ticks.maxTicksLimit);\n const minRotation = tickOpts.minRotation || 0;\n const maxRotation = tickOpts.maxRotation;\n let labelRotation = minRotation;\n let tickWidth, maxHeight, maxLabelDiagonal;\n if (!this._isVisible() || !tickOpts.display || minRotation >= maxRotation || numTicks <= 1 || !this.isHorizontal()) {\n this.labelRotation = minRotation;\n return;\n }\n const labelSizes = this._getLabelSizes();\n const maxLabelWidth = labelSizes.widest.width;\n const maxLabelHeight = labelSizes.highest.height;\n const maxWidth = _limitValue(this.chart.width - maxLabelWidth, 0, this.maxWidth);\n tickWidth = options.offset ? this.maxWidth / numTicks : maxWidth / (numTicks - 1);\n if (maxLabelWidth + 6 > tickWidth) {\n tickWidth = maxWidth / (numTicks - (options.offset ? 0.5 : 1));\n maxHeight = this.maxHeight - getTickMarkLength(options.grid) - tickOpts.padding - getTitleHeight(options.title, this.chart.options.font);\n maxLabelDiagonal = Math.sqrt(maxLabelWidth * maxLabelWidth + maxLabelHeight * maxLabelHeight);\n labelRotation = toDegrees(Math.min(Math.asin(_limitValue((labelSizes.highest.height + 6) / tickWidth, -1, 1)), Math.asin(_limitValue(maxHeight / maxLabelDiagonal, -1, 1)) - Math.asin(_limitValue(maxLabelHeight / maxLabelDiagonal, -1, 1))));\n labelRotation = Math.max(minRotation, Math.min(maxRotation, labelRotation));\n }\n this.labelRotation = labelRotation;\n }\n afterCalculateLabelRotation() {\n callback(this.options.afterCalculateLabelRotation, [\n this\n ]);\n }\n afterAutoSkip() {}\n beforeFit() {\n callback(this.options.beforeFit, [\n this\n ]);\n }\n fit() {\n const minSize = {\n width: 0,\n height: 0\n };\n const { chart , options: { ticks: tickOpts , title: titleOpts , grid: gridOpts } } = this;\n const display = this._isVisible();\n const isHorizontal = this.isHorizontal();\n if (display) {\n const titleHeight = getTitleHeight(titleOpts, chart.options.font);\n if (isHorizontal) {\n minSize.width = this.maxWidth;\n minSize.height = getTickMarkLength(gridOpts) + titleHeight;\n } else {\n minSize.height = this.maxHeight;\n minSize.width = getTickMarkLength(gridOpts) + titleHeight;\n }\n if (tickOpts.display && this.ticks.length) {\n const { first , last , widest , highest } = this._getLabelSizes();\n const tickPadding = tickOpts.padding * 2;\n const angleRadians = toRadians(this.labelRotation);\n const cos = Math.cos(angleRadians);\n const sin = Math.sin(angleRadians);\n if (isHorizontal) {\n const labelHeight = tickOpts.mirror ? 0 : sin * widest.width + cos * highest.height;\n minSize.height = Math.min(this.maxHeight, minSize.height + labelHeight + tickPadding);\n } else {\n const labelWidth = tickOpts.mirror ? 0 : cos * widest.width + sin * highest.height;\n minSize.width = Math.min(this.maxWidth, minSize.width + labelWidth + tickPadding);\n }\n this._calculatePadding(first, last, sin, cos);\n }\n }\n this._handleMargins();\n if (isHorizontal) {\n this.width = this._length = chart.width - this._margins.left - this._margins.right;\n this.height = minSize.height;\n } else {\n this.width = minSize.width;\n this.height = this._length = chart.height - this._margins.top - this._margins.bottom;\n }\n }\n _calculatePadding(first, last, sin, cos) {\n const { ticks: { align , padding } , position } = this.options;\n const isRotated = this.labelRotation !== 0;\n const labelsBelowTicks = position !== 'top' && this.axis === 'x';\n if (this.isHorizontal()) {\n const offsetLeft = this.getPixelForTick(0) - this.left;\n const offsetRight = this.right - this.getPixelForTick(this.ticks.length - 1);\n let paddingLeft = 0;\n let paddingRight = 0;\n if (isRotated) {\n if (labelsBelowTicks) {\n paddingLeft = cos * first.width;\n paddingRight = sin * last.height;\n } else {\n paddingLeft = sin * first.height;\n paddingRight = cos * last.width;\n }\n } else if (align === 'start') {\n paddingRight = last.width;\n } else if (align === 'end') {\n paddingLeft = first.width;\n } else if (align !== 'inner') {\n paddingLeft = first.width / 2;\n paddingRight = last.width / 2;\n }\n this.paddingLeft = Math.max((paddingLeft - offsetLeft + padding) * this.width / (this.width - offsetLeft), 0);\n this.paddingRight = Math.max((paddingRight - offsetRight + padding) * this.width / (this.width - offsetRight), 0);\n } else {\n let paddingTop = last.height / 2;\n let paddingBottom = first.height / 2;\n if (align === 'start') {\n paddingTop = 0;\n paddingBottom = first.height;\n } else if (align === 'end') {\n paddingTop = last.height;\n paddingBottom = 0;\n }\n this.paddingTop = paddingTop + padding;\n this.paddingBottom = paddingBottom + padding;\n }\n }\n _handleMargins() {\n if (this._margins) {\n this._margins.left = Math.max(this.paddingLeft, this._margins.left);\n this._margins.top = Math.max(this.paddingTop, this._margins.top);\n this._margins.right = Math.max(this.paddingRight, this._margins.right);\n this._margins.bottom = Math.max(this.paddingBottom, this._margins.bottom);\n }\n }\n afterFit() {\n callback(this.options.afterFit, [\n this\n ]);\n }\n isHorizontal() {\n const { axis , position } = this.options;\n return position === 'top' || position === 'bottom' || axis === 'x';\n }\n isFullSize() {\n return this.options.fullSize;\n }\n _convertTicksToLabels(ticks) {\n this.beforeTickToLabelConversion();\n this.generateTickLabels(ticks);\n let i, ilen;\n for(i = 0, ilen = ticks.length; i < ilen; i++){\n if (isNullOrUndef(ticks[i].label)) {\n ticks.splice(i, 1);\n ilen--;\n i--;\n }\n }\n this.afterTickToLabelConversion();\n }\n _getLabelSizes() {\n let labelSizes = this._labelSizes;\n if (!labelSizes) {\n const sampleSize = this.options.ticks.sampleSize;\n let ticks = this.ticks;\n if (sampleSize < ticks.length) {\n ticks = sample(ticks, sampleSize);\n }\n this._labelSizes = labelSizes = this._computeLabelSizes(ticks, ticks.length, this.options.ticks.maxTicksLimit);\n }\n return labelSizes;\n }\n _computeLabelSizes(ticks, length, maxTicksLimit) {\n const { ctx , _longestTextCache: caches } = this;\n const widths = [];\n const heights = [];\n const increment = Math.floor(length / getTicksLimit(length, maxTicksLimit));\n let widestLabelSize = 0;\n let highestLabelSize = 0;\n let i, j, jlen, label, tickFont, fontString, cache, lineHeight, width, height, nestedLabel;\n for(i = 0; i < length; i += increment){\n label = ticks[i].label;\n tickFont = this._resolveTickFontOptions(i);\n ctx.font = fontString = tickFont.string;\n cache = caches[fontString] = caches[fontString] || {\n data: {},\n gc: []\n };\n lineHeight = tickFont.lineHeight;\n width = height = 0;\n if (!isNullOrUndef(label) && !isArray(label)) {\n width = _measureText(ctx, cache.data, cache.gc, width, label);\n height = lineHeight;\n } else if (isArray(label)) {\n for(j = 0, jlen = label.length; j < jlen; ++j){\n nestedLabel = label[j];\n if (!isNullOrUndef(nestedLabel) && !isArray(nestedLabel)) {\n width = _measureText(ctx, cache.data, cache.gc, width, nestedLabel);\n height += lineHeight;\n }\n }\n }\n widths.push(width);\n heights.push(height);\n widestLabelSize = Math.max(width, widestLabelSize);\n highestLabelSize = Math.max(height, highestLabelSize);\n }\n garbageCollect(caches, length);\n const widest = widths.indexOf(widestLabelSize);\n const highest = heights.indexOf(highestLabelSize);\n const valueAt = (idx)=>({\n width: widths[idx] || 0,\n height: heights[idx] || 0\n });\n return {\n first: valueAt(0),\n last: valueAt(length - 1),\n widest: valueAt(widest),\n highest: valueAt(highest),\n widths,\n heights\n };\n }\n getLabelForValue(value) {\n return value;\n }\n getPixelForValue(value, index) {\n return NaN;\n }\n getValueForPixel(pixel) {}\n getPixelForTick(index) {\n const ticks = this.ticks;\n if (index < 0 || index > ticks.length - 1) {\n return null;\n }\n return this.getPixelForValue(ticks[index].value);\n }\n getPixelForDecimal(decimal) {\n if (this._reversePixels) {\n decimal = 1 - decimal;\n }\n const pixel = this._startPixel + decimal * this._length;\n return _int16Range(this._alignToPixels ? _alignPixel(this.chart, pixel, 0) : pixel);\n }\n getDecimalForPixel(pixel) {\n const decimal = (pixel - this._startPixel) / this._length;\n return this._reversePixels ? 1 - decimal : decimal;\n }\n getBasePixel() {\n return this.getPixelForValue(this.getBaseValue());\n }\n getBaseValue() {\n const { min , max } = this;\n return min < 0 && max < 0 ? max : min > 0 && max > 0 ? min : 0;\n }\n getContext(index) {\n const ticks = this.ticks || [];\n if (index >= 0 && index < ticks.length) {\n const tick = ticks[index];\n return tick.$context || (tick.$context = createTickContext(this.getContext(), index, tick));\n }\n return this.$context || (this.$context = createScaleContext(this.chart.getContext(), this));\n }\n _tickSize() {\n const optionTicks = this.options.ticks;\n const rot = toRadians(this.labelRotation);\n const cos = Math.abs(Math.cos(rot));\n const sin = Math.abs(Math.sin(rot));\n const labelSizes = this._getLabelSizes();\n const padding = optionTicks.autoSkipPadding || 0;\n const w = labelSizes ? labelSizes.widest.width + padding : 0;\n const h = labelSizes ? labelSizes.highest.height + padding : 0;\n return this.isHorizontal() ? h * cos > w * sin ? w / cos : h / sin : h * sin < w * cos ? h / cos : w / sin;\n }\n _isVisible() {\n const display = this.options.display;\n if (display !== 'auto') {\n return !!display;\n }\n return this.getMatchingVisibleMetas().length > 0;\n }\n _computeGridLineItems(chartArea) {\n const axis = this.axis;\n const chart = this.chart;\n const options = this.options;\n const { grid , position , border } = options;\n const offset = grid.offset;\n const isHorizontal = this.isHorizontal();\n const ticks = this.ticks;\n const ticksLength = ticks.length + (offset ? 1 : 0);\n const tl = getTickMarkLength(grid);\n const items = [];\n const borderOpts = border.setContext(this.getContext());\n const axisWidth = borderOpts.display ? borderOpts.width : 0;\n const axisHalfWidth = axisWidth / 2;\n const alignBorderValue = function(pixel) {\n return _alignPixel(chart, pixel, axisWidth);\n };\n let borderValue, i, lineValue, alignedLineValue;\n let tx1, ty1, tx2, ty2, x1, y1, x2, y2;\n if (position === 'top') {\n borderValue = alignBorderValue(this.bottom);\n ty1 = this.bottom - tl;\n ty2 = borderValue - axisHalfWidth;\n y1 = alignBorderValue(chartArea.top) + axisHalfWidth;\n y2 = chartArea.bottom;\n } else if (position === 'bottom') {\n borderValue = alignBorderValue(this.top);\n y1 = chartArea.top;\n y2 = alignBorderValue(chartArea.bottom) - axisHalfWidth;\n ty1 = borderValue + axisHalfWidth;\n ty2 = this.top + tl;\n } else if (position === 'left') {\n borderValue = alignBorderValue(this.right);\n tx1 = this.right - tl;\n tx2 = borderValue - axisHalfWidth;\n x1 = alignBorderValue(chartArea.left) + axisHalfWidth;\n x2 = chartArea.right;\n } else if (position === 'right') {\n borderValue = alignBorderValue(this.left);\n x1 = chartArea.left;\n x2 = alignBorderValue(chartArea.right) - axisHalfWidth;\n tx1 = borderValue + axisHalfWidth;\n tx2 = this.left + tl;\n } else if (axis === 'x') {\n if (position === 'center') {\n borderValue = alignBorderValue((chartArea.top + chartArea.bottom) / 2 + 0.5);\n } else if (isObject(position)) {\n const positionAxisID = Object.keys(position)[0];\n const value = position[positionAxisID];\n borderValue = alignBorderValue(this.chart.scales[positionAxisID].getPixelForValue(value));\n }\n y1 = chartArea.top;\n y2 = chartArea.bottom;\n ty1 = borderValue + axisHalfWidth;\n ty2 = ty1 + tl;\n } else if (axis === 'y') {\n if (position === 'center') {\n borderValue = alignBorderValue((chartArea.left + chartArea.right) / 2);\n } else if (isObject(position)) {\n const positionAxisID = Object.keys(position)[0];\n const value = position[positionAxisID];\n borderValue = alignBorderValue(this.chart.scales[positionAxisID].getPixelForValue(value));\n }\n tx1 = borderValue - axisHalfWidth;\n tx2 = tx1 - tl;\n x1 = chartArea.left;\n x2 = chartArea.right;\n }\n const limit = valueOrDefault(options.ticks.maxTicksLimit, ticksLength);\n const step = Math.max(1, Math.ceil(ticksLength / limit));\n for(i = 0; i < ticksLength; i += step){\n const context = this.getContext(i);\n const optsAtIndex = grid.setContext(context);\n const optsAtIndexBorder = border.setContext(context);\n const lineWidth = optsAtIndex.lineWidth;\n const lineColor = optsAtIndex.color;\n const borderDash = optsAtIndexBorder.dash || [];\n const borderDashOffset = optsAtIndexBorder.dashOffset;\n const tickWidth = optsAtIndex.tickWidth;\n const tickColor = optsAtIndex.tickColor;\n const tickBorderDash = optsAtIndex.tickBorderDash || [];\n const tickBorderDashOffset = optsAtIndex.tickBorderDashOffset;\n lineValue = getPixelForGridLine(this, i, offset);\n if (lineValue === undefined) {\n continue;\n }\n alignedLineValue = _alignPixel(chart, lineValue, lineWidth);\n if (isHorizontal) {\n tx1 = tx2 = x1 = x2 = alignedLineValue;\n } else {\n ty1 = ty2 = y1 = y2 = alignedLineValue;\n }\n items.push({\n tx1,\n ty1,\n tx2,\n ty2,\n x1,\n y1,\n x2,\n y2,\n width: lineWidth,\n color: lineColor,\n borderDash,\n borderDashOffset,\n tickWidth,\n tickColor,\n tickBorderDash,\n tickBorderDashOffset\n });\n }\n this._ticksLength = ticksLength;\n this._borderValue = borderValue;\n return items;\n }\n _computeLabelItems(chartArea) {\n const axis = this.axis;\n const options = this.options;\n const { position , ticks: optionTicks } = options;\n const isHorizontal = this.isHorizontal();\n const ticks = this.ticks;\n const { align , crossAlign , padding , mirror } = optionTicks;\n const tl = getTickMarkLength(options.grid);\n const tickAndPadding = tl + padding;\n const hTickAndPadding = mirror ? -padding : tickAndPadding;\n const rotation = -toRadians(this.labelRotation);\n const items = [];\n let i, ilen, tick, label, x, y, textAlign, pixel, font, lineHeight, lineCount, textOffset;\n let textBaseline = 'middle';\n if (position === 'top') {\n y = this.bottom - hTickAndPadding;\n textAlign = this._getXAxisLabelAlignment();\n } else if (position === 'bottom') {\n y = this.top + hTickAndPadding;\n textAlign = this._getXAxisLabelAlignment();\n } else if (position === 'left') {\n const ret = this._getYAxisLabelAlignment(tl);\n textAlign = ret.textAlign;\n x = ret.x;\n } else if (position === 'right') {\n const ret = this._getYAxisLabelAlignment(tl);\n textAlign = ret.textAlign;\n x = ret.x;\n } else if (axis === 'x') {\n if (position === 'center') {\n y = (chartArea.top + chartArea.bottom) / 2 + tickAndPadding;\n } else if (isObject(position)) {\n const positionAxisID = Object.keys(position)[0];\n const value = position[positionAxisID];\n y = this.chart.scales[positionAxisID].getPixelForValue(value) + tickAndPadding;\n }\n textAlign = this._getXAxisLabelAlignment();\n } else if (axis === 'y') {\n if (position === 'center') {\n x = (chartArea.left + chartArea.right) / 2 - tickAndPadding;\n } else if (isObject(position)) {\n const positionAxisID = Object.keys(position)[0];\n const value = position[positionAxisID];\n x = this.chart.scales[positionAxisID].getPixelForValue(value);\n }\n textAlign = this._getYAxisLabelAlignment(tl).textAlign;\n }\n if (axis === 'y') {\n if (align === 'start') {\n textBaseline = 'top';\n } else if (align === 'end') {\n textBaseline = 'bottom';\n }\n }\n const labelSizes = this._getLabelSizes();\n for(i = 0, ilen = ticks.length; i < ilen; ++i){\n tick = ticks[i];\n label = tick.label;\n const optsAtIndex = optionTicks.setContext(this.getContext(i));\n pixel = this.getPixelForTick(i) + optionTicks.labelOffset;\n font = this._resolveTickFontOptions(i);\n lineHeight = font.lineHeight;\n lineCount = isArray(label) ? label.length : 1;\n const halfCount = lineCount / 2;\n const color = optsAtIndex.color;\n const strokeColor = optsAtIndex.textStrokeColor;\n const strokeWidth = optsAtIndex.textStrokeWidth;\n let tickTextAlign = textAlign;\n if (isHorizontal) {\n x = pixel;\n if (textAlign === 'inner') {\n if (i === ilen - 1) {\n tickTextAlign = !this.options.reverse ? 'right' : 'left';\n } else if (i === 0) {\n tickTextAlign = !this.options.reverse ? 'left' : 'right';\n } else {\n tickTextAlign = 'center';\n }\n }\n if (position === 'top') {\n if (crossAlign === 'near' || rotation !== 0) {\n textOffset = -lineCount * lineHeight + lineHeight / 2;\n } else if (crossAlign === 'center') {\n textOffset = -labelSizes.highest.height / 2 - halfCount * lineHeight + lineHeight;\n } else {\n textOffset = -labelSizes.highest.height + lineHeight / 2;\n }\n } else {\n if (crossAlign === 'near' || rotation !== 0) {\n textOffset = lineHeight / 2;\n } else if (crossAlign === 'center') {\n textOffset = labelSizes.highest.height / 2 - halfCount * lineHeight;\n } else {\n textOffset = labelSizes.highest.height - lineCount * lineHeight;\n }\n }\n if (mirror) {\n textOffset *= -1;\n }\n if (rotation !== 0 && !optsAtIndex.showLabelBackdrop) {\n x += lineHeight / 2 * Math.sin(rotation);\n }\n } else {\n y = pixel;\n textOffset = (1 - lineCount) * lineHeight / 2;\n }\n let backdrop;\n if (optsAtIndex.showLabelBackdrop) {\n const labelPadding = toPadding(optsAtIndex.backdropPadding);\n const height = labelSizes.heights[i];\n const width = labelSizes.widths[i];\n let top = textOffset - labelPadding.top;\n let left = 0 - labelPadding.left;\n switch(textBaseline){\n case 'middle':\n top -= height / 2;\n break;\n case 'bottom':\n top -= height;\n break;\n }\n switch(textAlign){\n case 'center':\n left -= width / 2;\n break;\n case 'right':\n left -= width;\n break;\n case 'inner':\n if (i === ilen - 1) {\n left -= width;\n } else if (i > 0) {\n left -= width / 2;\n }\n break;\n }\n backdrop = {\n left,\n top,\n width: width + labelPadding.width,\n height: height + labelPadding.height,\n color: optsAtIndex.backdropColor\n };\n }\n items.push({\n label,\n font,\n textOffset,\n options: {\n rotation,\n color,\n strokeColor,\n strokeWidth,\n textAlign: tickTextAlign,\n textBaseline,\n translation: [\n x,\n y\n ],\n backdrop\n }\n });\n }\n return items;\n }\n _getXAxisLabelAlignment() {\n const { position , ticks } = this.options;\n const rotation = -toRadians(this.labelRotation);\n if (rotation) {\n return position === 'top' ? 'left' : 'right';\n }\n let align = 'center';\n if (ticks.align === 'start') {\n align = 'left';\n } else if (ticks.align === 'end') {\n align = 'right';\n } else if (ticks.align === 'inner') {\n align = 'inner';\n }\n return align;\n }\n _getYAxisLabelAlignment(tl) {\n const { position , ticks: { crossAlign , mirror , padding } } = this.options;\n const labelSizes = this._getLabelSizes();\n const tickAndPadding = tl + padding;\n const widest = labelSizes.widest.width;\n let textAlign;\n let x;\n if (position === 'left') {\n if (mirror) {\n x = this.right + padding;\n if (crossAlign === 'near') {\n textAlign = 'left';\n } else if (crossAlign === 'center') {\n textAlign = 'center';\n x += widest / 2;\n } else {\n textAlign = 'right';\n x += widest;\n }\n } else {\n x = this.right - tickAndPadding;\n if (crossAlign === 'near') {\n textAlign = 'right';\n } else if (crossAlign === 'center') {\n textAlign = 'center';\n x -= widest / 2;\n } else {\n textAlign = 'left';\n x = this.left;\n }\n }\n } else if (position === 'right') {\n if (mirror) {\n x = this.left + padding;\n if (crossAlign === 'near') {\n textAlign = 'right';\n } else if (crossAlign === 'center') {\n textAlign = 'center';\n x -= widest / 2;\n } else {\n textAlign = 'left';\n x -= widest;\n }\n } else {\n x = this.left + tickAndPadding;\n if (crossAlign === 'near') {\n textAlign = 'left';\n } else if (crossAlign === 'center') {\n textAlign = 'center';\n x += widest / 2;\n } else {\n textAlign = 'right';\n x = this.right;\n }\n }\n } else {\n textAlign = 'right';\n }\n return {\n textAlign,\n x\n };\n }\n _computeLabelArea() {\n if (this.options.ticks.mirror) {\n return;\n }\n const chart = this.chart;\n const position = this.options.position;\n if (position === 'left' || position === 'right') {\n return {\n top: 0,\n left: this.left,\n bottom: chart.height,\n right: this.right\n };\n }\n if (position === 'top' || position === 'bottom') {\n return {\n top: this.top,\n left: 0,\n bottom: this.bottom,\n right: chart.width\n };\n }\n }\n drawBackground() {\n const { ctx , options: { backgroundColor } , left , top , width , height } = this;\n if (backgroundColor) {\n ctx.save();\n ctx.fillStyle = backgroundColor;\n ctx.fillRect(left, top, width, height);\n ctx.restore();\n }\n }\n getLineWidthForValue(value) {\n const grid = this.options.grid;\n if (!this._isVisible() || !grid.display) {\n return 0;\n }\n const ticks = this.ticks;\n const index = ticks.findIndex((t)=>t.value === value);\n if (index >= 0) {\n const opts = grid.setContext(this.getContext(index));\n return opts.lineWidth;\n }\n return 0;\n }\n drawGrid(chartArea) {\n const grid = this.options.grid;\n const ctx = this.ctx;\n const items = this._gridLineItems || (this._gridLineItems = this._computeGridLineItems(chartArea));\n let i, ilen;\n const drawLine = (p1, p2, style)=>{\n if (!style.width || !style.color) {\n return;\n }\n ctx.save();\n ctx.lineWidth = style.width;\n ctx.strokeStyle = style.color;\n ctx.setLineDash(style.borderDash || []);\n ctx.lineDashOffset = style.borderDashOffset;\n ctx.beginPath();\n ctx.moveTo(p1.x, p1.y);\n ctx.lineTo(p2.x, p2.y);\n ctx.stroke();\n ctx.restore();\n };\n if (grid.display) {\n for(i = 0, ilen = items.length; i < ilen; ++i){\n const item = items[i];\n if (grid.drawOnChartArea) {\n drawLine({\n x: item.x1,\n y: item.y1\n }, {\n x: item.x2,\n y: item.y2\n }, item);\n }\n if (grid.drawTicks) {\n drawLine({\n x: item.tx1,\n y: item.ty1\n }, {\n x: item.tx2,\n y: item.ty2\n }, {\n color: item.tickColor,\n width: item.tickWidth,\n borderDash: item.tickBorderDash,\n borderDashOffset: item.tickBorderDashOffset\n });\n }\n }\n }\n }\n drawBorder() {\n const { chart , ctx , options: { border , grid } } = this;\n const borderOpts = border.setContext(this.getContext());\n const axisWidth = border.display ? borderOpts.width : 0;\n if (!axisWidth) {\n return;\n }\n const lastLineWidth = grid.setContext(this.getContext(0)).lineWidth;\n const borderValue = this._borderValue;\n let x1, x2, y1, y2;\n if (this.isHorizontal()) {\n x1 = _alignPixel(chart, this.left, axisWidth) - axisWidth / 2;\n x2 = _alignPixel(chart, this.right, lastLineWidth) + lastLineWidth / 2;\n y1 = y2 = borderValue;\n } else {\n y1 = _alignPixel(chart, this.top, axisWidth) - axisWidth / 2;\n y2 = _alignPixel(chart, this.bottom, lastLineWidth) + lastLineWidth / 2;\n x1 = x2 = borderValue;\n }\n ctx.save();\n ctx.lineWidth = borderOpts.width;\n ctx.strokeStyle = borderOpts.color;\n ctx.beginPath();\n ctx.moveTo(x1, y1);\n ctx.lineTo(x2, y2);\n ctx.stroke();\n ctx.restore();\n }\n drawLabels(chartArea) {\n const optionTicks = this.options.ticks;\n if (!optionTicks.display) {\n return;\n }\n const ctx = this.ctx;\n const area = this._computeLabelArea();\n if (area) {\n clipArea(ctx, area);\n }\n const items = this.getLabelItems(chartArea);\n for (const item of items){\n const renderTextOptions = item.options;\n const tickFont = item.font;\n const label = item.label;\n const y = item.textOffset;\n renderText(ctx, label, 0, y, tickFont, renderTextOptions);\n }\n if (area) {\n unclipArea(ctx);\n }\n }\n drawTitle() {\n const { ctx , options: { position , title , reverse } } = this;\n if (!title.display) {\n return;\n }\n const font = toFont(title.font);\n const padding = toPadding(title.padding);\n const align = title.align;\n let offset = font.lineHeight / 2;\n if (position === 'bottom' || position === 'center' || isObject(position)) {\n offset += padding.bottom;\n if (isArray(title.text)) {\n offset += font.lineHeight * (title.text.length - 1);\n }\n } else {\n offset += padding.top;\n }\n const { titleX , titleY , maxWidth , rotation } = titleArgs(this, offset, position, align);\n renderText(ctx, title.text, 0, 0, font, {\n color: title.color,\n maxWidth,\n rotation,\n textAlign: titleAlign(align, position, reverse),\n textBaseline: 'middle',\n translation: [\n titleX,\n titleY\n ]\n });\n }\n draw(chartArea) {\n if (!this._isVisible()) {\n return;\n }\n this.drawBackground();\n this.drawGrid(chartArea);\n this.drawBorder();\n this.drawTitle();\n this.drawLabels(chartArea);\n }\n _layers() {\n const opts = this.options;\n const tz = opts.ticks && opts.ticks.z || 0;\n const gz = valueOrDefault(opts.grid && opts.grid.z, -1);\n const bz = valueOrDefault(opts.border && opts.border.z, 0);\n if (!this._isVisible() || this.draw !== Scale.prototype.draw) {\n return [\n {\n z: tz,\n draw: (chartArea)=>{\n this.draw(chartArea);\n }\n }\n ];\n }\n return [\n {\n z: gz,\n draw: (chartArea)=>{\n this.drawBackground();\n this.drawGrid(chartArea);\n this.drawTitle();\n }\n },\n {\n z: bz,\n draw: ()=>{\n this.drawBorder();\n }\n },\n {\n z: tz,\n draw: (chartArea)=>{\n this.drawLabels(chartArea);\n }\n }\n ];\n }\n getMatchingVisibleMetas(type) {\n const metas = this.chart.getSortedVisibleDatasetMetas();\n const axisID = this.axis + 'AxisID';\n const result = [];\n let i, ilen;\n for(i = 0, ilen = metas.length; i < ilen; ++i){\n const meta = metas[i];\n if (meta[axisID] === this.id && (!type || meta.type === type)) {\n result.push(meta);\n }\n }\n return result;\n }\n _resolveTickFontOptions(index) {\n const opts = this.options.ticks.setContext(this.getContext(index));\n return toFont(opts.font);\n }\n _maxDigits() {\n const fontSize = this._resolveTickFontOptions(0).lineHeight;\n return (this.isHorizontal() ? this.width : this.height) / fontSize;\n }\n}\n\nclass TypedRegistry {\n constructor(type, scope, override){\n this.type = type;\n this.scope = scope;\n this.override = override;\n this.items = Object.create(null);\n }\n isForType(type) {\n return Object.prototype.isPrototypeOf.call(this.type.prototype, type.prototype);\n }\n register(item) {\n const proto = Object.getPrototypeOf(item);\n let parentScope;\n if (isIChartComponent(proto)) {\n parentScope = this.register(proto);\n }\n const items = this.items;\n const id = item.id;\n const scope = this.scope + '.' + id;\n if (!id) {\n throw new Error('class does not have id: ' + item);\n }\n if (id in items) {\n return scope;\n }\n items[id] = item;\n registerDefaults(item, scope, parentScope);\n if (this.override) {\n defaults.override(item.id, item.overrides);\n }\n return scope;\n }\n get(id) {\n return this.items[id];\n }\n unregister(item) {\n const items = this.items;\n const id = item.id;\n const scope = this.scope;\n if (id in items) {\n delete items[id];\n }\n if (scope && id in defaults[scope]) {\n delete defaults[scope][id];\n if (this.override) {\n delete overrides[id];\n }\n }\n }\n}\nfunction registerDefaults(item, scope, parentScope) {\n const itemDefaults = merge(Object.create(null), [\n parentScope ? defaults.get(parentScope) : {},\n defaults.get(scope),\n item.defaults\n ]);\n defaults.set(scope, itemDefaults);\n if (item.defaultRoutes) {\n routeDefaults(scope, item.defaultRoutes);\n }\n if (item.descriptors) {\n defaults.describe(scope, item.descriptors);\n }\n}\nfunction routeDefaults(scope, routes) {\n Object.keys(routes).forEach((property)=>{\n const propertyParts = property.split('.');\n const sourceName = propertyParts.pop();\n const sourceScope = [\n scope\n ].concat(propertyParts).join('.');\n const parts = routes[property].split('.');\n const targetName = parts.pop();\n const targetScope = parts.join('.');\n defaults.route(sourceScope, sourceName, targetScope, targetName);\n });\n}\nfunction isIChartComponent(proto) {\n return 'id' in proto && 'defaults' in proto;\n}\n\nclass Registry {\n constructor(){\n this.controllers = new TypedRegistry(DatasetController, 'datasets', true);\n this.elements = new TypedRegistry(chart_Element, 'elements');\n this.plugins = new TypedRegistry(Object, 'plugins');\n this.scales = new TypedRegistry(Scale, 'scales');\n this._typedRegistries = [\n this.controllers,\n this.scales,\n this.elements\n ];\n }\n add(...args) {\n this._each('register', args);\n }\n remove(...args) {\n this._each('unregister', args);\n }\n addControllers(...args) {\n this._each('register', args, this.controllers);\n }\n addElements(...args) {\n this._each('register', args, this.elements);\n }\n addPlugins(...args) {\n this._each('register', args, this.plugins);\n }\n addScales(...args) {\n this._each('register', args, this.scales);\n }\n getController(id) {\n return this._get(id, this.controllers, 'controller');\n }\n getElement(id) {\n return this._get(id, this.elements, 'element');\n }\n getPlugin(id) {\n return this._get(id, this.plugins, 'plugin');\n }\n getScale(id) {\n return this._get(id, this.scales, 'scale');\n }\n removeControllers(...args) {\n this._each('unregister', args, this.controllers);\n }\n removeElements(...args) {\n this._each('unregister', args, this.elements);\n }\n removePlugins(...args) {\n this._each('unregister', args, this.plugins);\n }\n removeScales(...args) {\n this._each('unregister', args, this.scales);\n }\n _each(method, args, typedRegistry) {\n [\n ...args\n ].forEach((arg)=>{\n const reg = typedRegistry || this._getRegistryForType(arg);\n if (typedRegistry || reg.isForType(arg) || reg === this.plugins && arg.id) {\n this._exec(method, reg, arg);\n } else {\n each(arg, (item)=>{\n const itemReg = typedRegistry || this._getRegistryForType(item);\n this._exec(method, itemReg, item);\n });\n }\n });\n }\n _exec(method, registry, component) {\n const camelMethod = _capitalize(method);\n callback(component['before' + camelMethod], [], component);\n registry[method](component);\n callback(component['after' + camelMethod], [], component);\n }\n _getRegistryForType(type) {\n for(let i = 0; i < this._typedRegistries.length; i++){\n const reg = this._typedRegistries[i];\n if (reg.isForType(type)) {\n return reg;\n }\n }\n return this.plugins;\n }\n _get(id, typedRegistry, type) {\n const item = typedRegistry.get(id);\n if (item === undefined) {\n throw new Error('\"' + id + '\" is not a registered ' + type + '.');\n }\n return item;\n }\n}\nvar registry = /* #__PURE__ */ new Registry();\n\nclass PluginService {\n constructor(){\n this._init = [];\n }\n notify(chart, hook, args, filter) {\n if (hook === 'beforeInit') {\n this._init = this._createDescriptors(chart, true);\n this._notify(this._init, chart, 'install');\n }\n const descriptors = filter ? this._descriptors(chart).filter(filter) : this._descriptors(chart);\n const result = this._notify(descriptors, chart, hook, args);\n if (hook === 'afterDestroy') {\n this._notify(descriptors, chart, 'stop');\n this._notify(this._init, chart, 'uninstall');\n }\n return result;\n }\n _notify(descriptors, chart, hook, args) {\n args = args || {};\n for (const descriptor of descriptors){\n const plugin = descriptor.plugin;\n const method = plugin[hook];\n const params = [\n chart,\n args,\n descriptor.options\n ];\n if (callback(method, params, plugin) === false && args.cancelable) {\n return false;\n }\n }\n return true;\n }\n invalidate() {\n if (!isNullOrUndef(this._cache)) {\n this._oldCache = this._cache;\n this._cache = undefined;\n }\n }\n _descriptors(chart) {\n if (this._cache) {\n return this._cache;\n }\n const descriptors = this._cache = this._createDescriptors(chart);\n this._notifyStateChanges(chart);\n return descriptors;\n }\n _createDescriptors(chart, all) {\n const config = chart && chart.config;\n const options = valueOrDefault(config.options && config.options.plugins, {});\n const plugins = allPlugins(config);\n return options === false && !all ? [] : createDescriptors(chart, plugins, options, all);\n }\n _notifyStateChanges(chart) {\n const previousDescriptors = this._oldCache || [];\n const descriptors = this._cache;\n const diff = (a, b)=>a.filter((x)=>!b.some((y)=>x.plugin.id === y.plugin.id));\n this._notify(diff(previousDescriptors, descriptors), chart, 'stop');\n this._notify(diff(descriptors, previousDescriptors), chart, 'start');\n }\n}\n function allPlugins(config) {\n const localIds = {};\n const plugins = [];\n const keys = Object.keys(registry.plugins.items);\n for(let i = 0; i < keys.length; i++){\n plugins.push(registry.getPlugin(keys[i]));\n }\n const local = config.plugins || [];\n for(let i = 0; i < local.length; i++){\n const plugin = local[i];\n if (plugins.indexOf(plugin) === -1) {\n plugins.push(plugin);\n localIds[plugin.id] = true;\n }\n }\n return {\n plugins,\n localIds\n };\n}\nfunction getOpts(options, all) {\n if (!all && options === false) {\n return null;\n }\n if (options === true) {\n return {};\n }\n return options;\n}\nfunction createDescriptors(chart, { plugins , localIds }, options, all) {\n const result = [];\n const context = chart.getContext();\n for (const plugin of plugins){\n const id = plugin.id;\n const opts = getOpts(options[id], all);\n if (opts === null) {\n continue;\n }\n result.push({\n plugin,\n options: pluginOpts(chart.config, {\n plugin,\n local: localIds[id]\n }, opts, context)\n });\n }\n return result;\n}\nfunction pluginOpts(config, { plugin , local }, opts, context) {\n const keys = config.pluginScopeKeys(plugin);\n const scopes = config.getOptionScopes(opts, keys);\n if (local && plugin.defaults) {\n scopes.push(plugin.defaults);\n }\n return config.createResolver(scopes, context, [\n ''\n ], {\n scriptable: false,\n indexable: false,\n allKeys: true\n });\n}\n\nfunction getIndexAxis(type, options) {\n const datasetDefaults = defaults.datasets[type] || {};\n const datasetOptions = (options.datasets || {})[type] || {};\n return datasetOptions.indexAxis || options.indexAxis || datasetDefaults.indexAxis || 'x';\n}\nfunction getAxisFromDefaultScaleID(id, indexAxis) {\n let axis = id;\n if (id === '_index_') {\n axis = indexAxis;\n } else if (id === '_value_') {\n axis = indexAxis === 'x' ? 'y' : 'x';\n }\n return axis;\n}\nfunction getDefaultScaleIDFromAxis(axis, indexAxis) {\n return axis === indexAxis ? '_index_' : '_value_';\n}\nfunction idMatchesAxis(id) {\n if (id === 'x' || id === 'y' || id === 'r') {\n return id;\n }\n}\nfunction axisFromPosition(position) {\n if (position === 'top' || position === 'bottom') {\n return 'x';\n }\n if (position === 'left' || position === 'right') {\n return 'y';\n }\n}\nfunction determineAxis(id, ...scaleOptions) {\n if (idMatchesAxis(id)) {\n return id;\n }\n for (const opts of scaleOptions){\n const axis = opts.axis || axisFromPosition(opts.position) || id.length > 1 && idMatchesAxis(id[0].toLowerCase());\n if (axis) {\n return axis;\n }\n }\n throw new Error(`Cannot determine type of '${id}' axis. Please provide 'axis' or 'position' option.`);\n}\nfunction getAxisFromDataset(id, axis, dataset) {\n if (dataset[axis + 'AxisID'] === id) {\n return {\n axis\n };\n }\n}\nfunction retrieveAxisFromDatasets(id, config) {\n if (config.data && config.data.datasets) {\n const boundDs = config.data.datasets.filter((d)=>d.xAxisID === id || d.yAxisID === id);\n if (boundDs.length) {\n return getAxisFromDataset(id, 'x', boundDs[0]) || getAxisFromDataset(id, 'y', boundDs[0]);\n }\n }\n return {};\n}\nfunction mergeScaleConfig(config, options) {\n const chartDefaults = overrides[config.type] || {\n scales: {}\n };\n const configScales = options.scales || {};\n const chartIndexAxis = getIndexAxis(config.type, options);\n const scales = Object.create(null);\n Object.keys(configScales).forEach((id)=>{\n const scaleConf = configScales[id];\n if (!isObject(scaleConf)) {\n return console.error(`Invalid scale configuration for scale: ${id}`);\n }\n if (scaleConf._proxy) {\n return console.warn(`Ignoring resolver passed as options for scale: ${id}`);\n }\n const axis = determineAxis(id, scaleConf, retrieveAxisFromDatasets(id, config), defaults.scales[scaleConf.type]);\n const defaultId = getDefaultScaleIDFromAxis(axis, chartIndexAxis);\n const defaultScaleOptions = chartDefaults.scales || {};\n scales[id] = mergeIf(Object.create(null), [\n {\n axis\n },\n scaleConf,\n defaultScaleOptions[axis],\n defaultScaleOptions[defaultId]\n ]);\n });\n config.data.datasets.forEach((dataset)=>{\n const type = dataset.type || config.type;\n const indexAxis = dataset.indexAxis || getIndexAxis(type, options);\n const datasetDefaults = overrides[type] || {};\n const defaultScaleOptions = datasetDefaults.scales || {};\n Object.keys(defaultScaleOptions).forEach((defaultID)=>{\n const axis = getAxisFromDefaultScaleID(defaultID, indexAxis);\n const id = dataset[axis + 'AxisID'] || axis;\n scales[id] = scales[id] || Object.create(null);\n mergeIf(scales[id], [\n {\n axis\n },\n configScales[id],\n defaultScaleOptions[defaultID]\n ]);\n });\n });\n Object.keys(scales).forEach((key)=>{\n const scale = scales[key];\n mergeIf(scale, [\n defaults.scales[scale.type],\n defaults.scale\n ]);\n });\n return scales;\n}\nfunction initOptions(config) {\n const options = config.options || (config.options = {});\n options.plugins = valueOrDefault(options.plugins, {});\n options.scales = mergeScaleConfig(config, options);\n}\nfunction initData(data) {\n data = data || {};\n data.datasets = data.datasets || [];\n data.labels = data.labels || [];\n return data;\n}\nfunction initConfig(config) {\n config = config || {};\n config.data = initData(config.data);\n initOptions(config);\n return config;\n}\nconst keyCache = new Map();\nconst keysCached = new Set();\nfunction cachedKeys(cacheKey, generate) {\n let keys = keyCache.get(cacheKey);\n if (!keys) {\n keys = generate();\n keyCache.set(cacheKey, keys);\n keysCached.add(keys);\n }\n return keys;\n}\nconst addIfFound = (set, obj, key)=>{\n const opts = resolveObjectKey(obj, key);\n if (opts !== undefined) {\n set.add(opts);\n }\n};\nclass Config {\n constructor(config){\n this._config = initConfig(config);\n this._scopeCache = new Map();\n this._resolverCache = new Map();\n }\n get platform() {\n return this._config.platform;\n }\n get type() {\n return this._config.type;\n }\n set type(type) {\n this._config.type = type;\n }\n get data() {\n return this._config.data;\n }\n set data(data) {\n this._config.data = initData(data);\n }\n get options() {\n return this._config.options;\n }\n set options(options) {\n this._config.options = options;\n }\n get plugins() {\n return this._config.plugins;\n }\n update() {\n const config = this._config;\n this.clearCache();\n initOptions(config);\n }\n clearCache() {\n this._scopeCache.clear();\n this._resolverCache.clear();\n }\n datasetScopeKeys(datasetType) {\n return cachedKeys(datasetType, ()=>[\n [\n `datasets.${datasetType}`,\n ''\n ]\n ]);\n }\n datasetAnimationScopeKeys(datasetType, transition) {\n return cachedKeys(`${datasetType}.transition.${transition}`, ()=>[\n [\n `datasets.${datasetType}.transitions.${transition}`,\n `transitions.${transition}`\n ],\n [\n `datasets.${datasetType}`,\n ''\n ]\n ]);\n }\n datasetElementScopeKeys(datasetType, elementType) {\n return cachedKeys(`${datasetType}-${elementType}`, ()=>[\n [\n `datasets.${datasetType}.elements.${elementType}`,\n `datasets.${datasetType}`,\n `elements.${elementType}`,\n ''\n ]\n ]);\n }\n pluginScopeKeys(plugin) {\n const id = plugin.id;\n const type = this.type;\n return cachedKeys(`${type}-plugin-${id}`, ()=>[\n [\n `plugins.${id}`,\n ...plugin.additionalOptionScopes || []\n ]\n ]);\n }\n _cachedScopes(mainScope, resetCache) {\n const _scopeCache = this._scopeCache;\n let cache = _scopeCache.get(mainScope);\n if (!cache || resetCache) {\n cache = new Map();\n _scopeCache.set(mainScope, cache);\n }\n return cache;\n }\n getOptionScopes(mainScope, keyLists, resetCache) {\n const { options , type } = this;\n const cache = this._cachedScopes(mainScope, resetCache);\n const cached = cache.get(keyLists);\n if (cached) {\n return cached;\n }\n const scopes = new Set();\n keyLists.forEach((keys)=>{\n if (mainScope) {\n scopes.add(mainScope);\n keys.forEach((key)=>addIfFound(scopes, mainScope, key));\n }\n keys.forEach((key)=>addIfFound(scopes, options, key));\n keys.forEach((key)=>addIfFound(scopes, overrides[type] || {}, key));\n keys.forEach((key)=>addIfFound(scopes, defaults, key));\n keys.forEach((key)=>addIfFound(scopes, descriptors, key));\n });\n const array = Array.from(scopes);\n if (array.length === 0) {\n array.push(Object.create(null));\n }\n if (keysCached.has(keyLists)) {\n cache.set(keyLists, array);\n }\n return array;\n }\n chartOptionScopes() {\n const { options , type } = this;\n return [\n options,\n overrides[type] || {},\n defaults.datasets[type] || {},\n {\n type\n },\n defaults,\n descriptors\n ];\n }\n resolveNamedOptions(scopes, names, context, prefixes = [\n ''\n ]) {\n const result = {\n $shared: true\n };\n const { resolver , subPrefixes } = getResolver(this._resolverCache, scopes, prefixes);\n let options = resolver;\n if (needContext(resolver, names)) {\n result.$shared = false;\n context = isFunction(context) ? context() : context;\n const subResolver = this.createResolver(scopes, context, subPrefixes);\n options = _attachContext(resolver, context, subResolver);\n }\n for (const prop of names){\n result[prop] = options[prop];\n }\n return result;\n }\n createResolver(scopes, context, prefixes = [\n ''\n ], descriptorDefaults) {\n const { resolver } = getResolver(this._resolverCache, scopes, prefixes);\n return isObject(context) ? _attachContext(resolver, context, undefined, descriptorDefaults) : resolver;\n }\n}\nfunction getResolver(resolverCache, scopes, prefixes) {\n let cache = resolverCache.get(scopes);\n if (!cache) {\n cache = new Map();\n resolverCache.set(scopes, cache);\n }\n const cacheKey = prefixes.join();\n let cached = cache.get(cacheKey);\n if (!cached) {\n const resolver = _createResolver(scopes, prefixes);\n cached = {\n resolver,\n subPrefixes: prefixes.filter((p)=>!p.toLowerCase().includes('hover'))\n };\n cache.set(cacheKey, cached);\n }\n return cached;\n}\nconst hasFunction = (value)=>isObject(value) && Object.getOwnPropertyNames(value).some((key)=>isFunction(value[key]));\nfunction needContext(proxy, names) {\n const { isScriptable , isIndexable } = _descriptors(proxy);\n for (const prop of names){\n const scriptable = isScriptable(prop);\n const indexable = isIndexable(prop);\n const value = (indexable || scriptable) && proxy[prop];\n if (scriptable && (isFunction(value) || hasFunction(value)) || indexable && isArray(value)) {\n return true;\n }\n }\n return false;\n}\n\nvar version = \"4.4.4\";\n\nconst KNOWN_POSITIONS = [\n 'top',\n 'bottom',\n 'left',\n 'right',\n 'chartArea'\n];\nfunction positionIsHorizontal(position, axis) {\n return position === 'top' || position === 'bottom' || KNOWN_POSITIONS.indexOf(position) === -1 && axis === 'x';\n}\nfunction compare2Level(l1, l2) {\n return function(a, b) {\n return a[l1] === b[l1] ? a[l2] - b[l2] : a[l1] - b[l1];\n };\n}\nfunction onAnimationsComplete(context) {\n const chart = context.chart;\n const animationOptions = chart.options.animation;\n chart.notifyPlugins('afterRender');\n callback(animationOptions && animationOptions.onComplete, [\n context\n ], chart);\n}\nfunction onAnimationProgress(context) {\n const chart = context.chart;\n const animationOptions = chart.options.animation;\n callback(animationOptions && animationOptions.onProgress, [\n context\n ], chart);\n}\n function getCanvas(item) {\n if (_isDomSupported() && typeof item === 'string') {\n item = document.getElementById(item);\n } else if (item && item.length) {\n item = item[0];\n }\n if (item && item.canvas) {\n item = item.canvas;\n }\n return item;\n}\nconst instances = {};\nconst getChart = (key)=>{\n const canvas = getCanvas(key);\n return Object.values(instances).filter((c)=>c.canvas === canvas).pop();\n};\nfunction moveNumericKeys(obj, start, move) {\n const keys = Object.keys(obj);\n for (const key of keys){\n const intKey = +key;\n if (intKey >= start) {\n const value = obj[key];\n delete obj[key];\n if (move > 0 || intKey > start) {\n obj[intKey + move] = value;\n }\n }\n }\n}\n function determineLastEvent(e, lastEvent, inChartArea, isClick) {\n if (!inChartArea || e.type === 'mouseout') {\n return null;\n }\n if (isClick) {\n return lastEvent;\n }\n return e;\n}\nfunction getSizeForArea(scale, chartArea, field) {\n return scale.options.clip ? scale[field] : chartArea[field];\n}\nfunction getDatasetArea(meta, chartArea) {\n const { xScale , yScale } = meta;\n if (xScale && yScale) {\n return {\n left: getSizeForArea(xScale, chartArea, 'left'),\n right: getSizeForArea(xScale, chartArea, 'right'),\n top: getSizeForArea(yScale, chartArea, 'top'),\n bottom: getSizeForArea(yScale, chartArea, 'bottom')\n };\n }\n return chartArea;\n}\nclass chart_Chart {\n static defaults = defaults;\n static instances = instances;\n static overrides = overrides;\n static registry = registry;\n static version = version;\n static getChart = getChart;\n static register(...items) {\n registry.add(...items);\n invalidatePlugins();\n }\n static unregister(...items) {\n registry.remove(...items);\n invalidatePlugins();\n }\n constructor(item, userConfig){\n const config = this.config = new Config(userConfig);\n const initialCanvas = getCanvas(item);\n const existingChart = getChart(initialCanvas);\n if (existingChart) {\n throw new Error('Canvas is already in use. Chart with ID \\'' + existingChart.id + '\\'' + ' must be destroyed before the canvas with ID \\'' + existingChart.canvas.id + '\\' can be reused.');\n }\n const options = config.createResolver(config.chartOptionScopes(), this.getContext());\n this.platform = new (config.platform || _detectPlatform(initialCanvas))();\n this.platform.updateConfig(config);\n const context = this.platform.acquireContext(initialCanvas, options.aspectRatio);\n const canvas = context && context.canvas;\n const height = canvas && canvas.height;\n const width = canvas && canvas.width;\n this.id = uid();\n this.ctx = context;\n this.canvas = canvas;\n this.width = width;\n this.height = height;\n this._options = options;\n this._aspectRatio = this.aspectRatio;\n this._layers = [];\n this._metasets = [];\n this._stacks = undefined;\n this.boxes = [];\n this.currentDevicePixelRatio = undefined;\n this.chartArea = undefined;\n this._active = [];\n this._lastEvent = undefined;\n this._listeners = {};\n this._responsiveListeners = undefined;\n this._sortedMetasets = [];\n this.scales = {};\n this._plugins = new PluginService();\n this.$proxies = {};\n this._hiddenIndices = {};\n this.attached = false;\n this._animationsDisabled = undefined;\n this.$context = undefined;\n this._doResize = debounce((mode)=>this.update(mode), options.resizeDelay || 0);\n this._dataChanges = [];\n instances[this.id] = this;\n if (!context || !canvas) {\n console.error(\"Failed to create chart: can't acquire context from the given item\");\n return;\n }\n animator.listen(this, 'complete', onAnimationsComplete);\n animator.listen(this, 'progress', onAnimationProgress);\n this._initialize();\n if (this.attached) {\n this.update();\n }\n }\n get aspectRatio() {\n const { options: { aspectRatio , maintainAspectRatio } , width , height , _aspectRatio } = this;\n if (!isNullOrUndef(aspectRatio)) {\n return aspectRatio;\n }\n if (maintainAspectRatio && _aspectRatio) {\n return _aspectRatio;\n }\n return height ? width / height : null;\n }\n get data() {\n return this.config.data;\n }\n set data(data) {\n this.config.data = data;\n }\n get options() {\n return this._options;\n }\n set options(options) {\n this.config.options = options;\n }\n get registry() {\n return registry;\n }\n _initialize() {\n this.notifyPlugins('beforeInit');\n if (this.options.responsive) {\n this.resize();\n } else {\n retinaScale(this, this.options.devicePixelRatio);\n }\n this.bindEvents();\n this.notifyPlugins('afterInit');\n return this;\n }\n clear() {\n clearCanvas(this.canvas, this.ctx);\n return this;\n }\n stop() {\n animator.stop(this);\n return this;\n }\n resize(width, height) {\n if (!animator.running(this)) {\n this._resize(width, height);\n } else {\n this._resizeBeforeDraw = {\n width,\n height\n };\n }\n }\n _resize(width, height) {\n const options = this.options;\n const canvas = this.canvas;\n const aspectRatio = options.maintainAspectRatio && this.aspectRatio;\n const newSize = this.platform.getMaximumSize(canvas, width, height, aspectRatio);\n const newRatio = options.devicePixelRatio || this.platform.getDevicePixelRatio();\n const mode = this.width ? 'resize' : 'attach';\n this.width = newSize.width;\n this.height = newSize.height;\n this._aspectRatio = this.aspectRatio;\n if (!retinaScale(this, newRatio, true)) {\n return;\n }\n this.notifyPlugins('resize', {\n size: newSize\n });\n callback(options.onResize, [\n this,\n newSize\n ], this);\n if (this.attached) {\n if (this._doResize(mode)) {\n this.render();\n }\n }\n }\n ensureScalesHaveIDs() {\n const options = this.options;\n const scalesOptions = options.scales || {};\n each(scalesOptions, (axisOptions, axisID)=>{\n axisOptions.id = axisID;\n });\n }\n buildOrUpdateScales() {\n const options = this.options;\n const scaleOpts = options.scales;\n const scales = this.scales;\n const updated = Object.keys(scales).reduce((obj, id)=>{\n obj[id] = false;\n return obj;\n }, {});\n let items = [];\n if (scaleOpts) {\n items = items.concat(Object.keys(scaleOpts).map((id)=>{\n const scaleOptions = scaleOpts[id];\n const axis = determineAxis(id, scaleOptions);\n const isRadial = axis === 'r';\n const isHorizontal = axis === 'x';\n return {\n options: scaleOptions,\n dposition: isRadial ? 'chartArea' : isHorizontal ? 'bottom' : 'left',\n dtype: isRadial ? 'radialLinear' : isHorizontal ? 'category' : 'linear'\n };\n }));\n }\n each(items, (item)=>{\n const scaleOptions = item.options;\n const id = scaleOptions.id;\n const axis = determineAxis(id, scaleOptions);\n const scaleType = valueOrDefault(scaleOptions.type, item.dtype);\n if (scaleOptions.position === undefined || positionIsHorizontal(scaleOptions.position, axis) !== positionIsHorizontal(item.dposition)) {\n scaleOptions.position = item.dposition;\n }\n updated[id] = true;\n let scale = null;\n if (id in scales && scales[id].type === scaleType) {\n scale = scales[id];\n } else {\n const scaleClass = registry.getScale(scaleType);\n scale = new scaleClass({\n id,\n type: scaleType,\n ctx: this.ctx,\n chart: this\n });\n scales[scale.id] = scale;\n }\n scale.init(scaleOptions, options);\n });\n each(updated, (hasUpdated, id)=>{\n if (!hasUpdated) {\n delete scales[id];\n }\n });\n each(scales, (scale)=>{\n layouts.configure(this, scale, scale.options);\n layouts.addBox(this, scale);\n });\n }\n _updateMetasets() {\n const metasets = this._metasets;\n const numData = this.data.datasets.length;\n const numMeta = metasets.length;\n metasets.sort((a, b)=>a.index - b.index);\n if (numMeta > numData) {\n for(let i = numData; i < numMeta; ++i){\n this._destroyDatasetMeta(i);\n }\n metasets.splice(numData, numMeta - numData);\n }\n this._sortedMetasets = metasets.slice(0).sort(compare2Level('order', 'index'));\n }\n _removeUnreferencedMetasets() {\n const { _metasets: metasets , data: { datasets } } = this;\n if (metasets.length > datasets.length) {\n delete this._stacks;\n }\n metasets.forEach((meta, index)=>{\n if (datasets.filter((x)=>x === meta._dataset).length === 0) {\n this._destroyDatasetMeta(index);\n }\n });\n }\n buildOrUpdateControllers() {\n const newControllers = [];\n const datasets = this.data.datasets;\n let i, ilen;\n this._removeUnreferencedMetasets();\n for(i = 0, ilen = datasets.length; i < ilen; i++){\n const dataset = datasets[i];\n let meta = this.getDatasetMeta(i);\n const type = dataset.type || this.config.type;\n if (meta.type && meta.type !== type) {\n this._destroyDatasetMeta(i);\n meta = this.getDatasetMeta(i);\n }\n meta.type = type;\n meta.indexAxis = dataset.indexAxis || getIndexAxis(type, this.options);\n meta.order = dataset.order || 0;\n meta.index = i;\n meta.label = '' + dataset.label;\n meta.visible = this.isDatasetVisible(i);\n if (meta.controller) {\n meta.controller.updateIndex(i);\n meta.controller.linkScales();\n } else {\n const ControllerClass = registry.getController(type);\n const { datasetElementType , dataElementType } = defaults.datasets[type];\n Object.assign(ControllerClass, {\n dataElementType: registry.getElement(dataElementType),\n datasetElementType: datasetElementType && registry.getElement(datasetElementType)\n });\n meta.controller = new ControllerClass(this, i);\n newControllers.push(meta.controller);\n }\n }\n this._updateMetasets();\n return newControllers;\n }\n _resetElements() {\n each(this.data.datasets, (dataset, datasetIndex)=>{\n this.getDatasetMeta(datasetIndex).controller.reset();\n }, this);\n }\n reset() {\n this._resetElements();\n this.notifyPlugins('reset');\n }\n update(mode) {\n const config = this.config;\n config.update();\n const options = this._options = config.createResolver(config.chartOptionScopes(), this.getContext());\n const animsDisabled = this._animationsDisabled = !options.animation;\n this._updateScales();\n this._checkEventBindings();\n this._updateHiddenIndices();\n this._plugins.invalidate();\n if (this.notifyPlugins('beforeUpdate', {\n mode,\n cancelable: true\n }) === false) {\n return;\n }\n const newControllers = this.buildOrUpdateControllers();\n this.notifyPlugins('beforeElementsUpdate');\n let minPadding = 0;\n for(let i = 0, ilen = this.data.datasets.length; i < ilen; i++){\n const { controller } = this.getDatasetMeta(i);\n const reset = !animsDisabled && newControllers.indexOf(controller) === -1;\n controller.buildOrUpdateElements(reset);\n minPadding = Math.max(+controller.getMaxOverflow(), minPadding);\n }\n minPadding = this._minPadding = options.layout.autoPadding ? minPadding : 0;\n this._updateLayout(minPadding);\n if (!animsDisabled) {\n each(newControllers, (controller)=>{\n controller.reset();\n });\n }\n this._updateDatasets(mode);\n this.notifyPlugins('afterUpdate', {\n mode\n });\n this._layers.sort(compare2Level('z', '_idx'));\n const { _active , _lastEvent } = this;\n if (_lastEvent) {\n this._eventHandler(_lastEvent, true);\n } else if (_active.length) {\n this._updateHoverStyles(_active, _active, true);\n }\n this.render();\n }\n _updateScales() {\n each(this.scales, (scale)=>{\n layouts.removeBox(this, scale);\n });\n this.ensureScalesHaveIDs();\n this.buildOrUpdateScales();\n }\n _checkEventBindings() {\n const options = this.options;\n const existingEvents = new Set(Object.keys(this._listeners));\n const newEvents = new Set(options.events);\n if (!setsEqual(existingEvents, newEvents) || !!this._responsiveListeners !== options.responsive) {\n this.unbindEvents();\n this.bindEvents();\n }\n }\n _updateHiddenIndices() {\n const { _hiddenIndices } = this;\n const changes = this._getUniformDataChanges() || [];\n for (const { method , start , count } of changes){\n const move = method === '_removeElements' ? -count : count;\n moveNumericKeys(_hiddenIndices, start, move);\n }\n }\n _getUniformDataChanges() {\n const _dataChanges = this._dataChanges;\n if (!_dataChanges || !_dataChanges.length) {\n return;\n }\n this._dataChanges = [];\n const datasetCount = this.data.datasets.length;\n const makeSet = (idx)=>new Set(_dataChanges.filter((c)=>c[0] === idx).map((c, i)=>i + ',' + c.splice(1).join(',')));\n const changeSet = makeSet(0);\n for(let i = 1; i < datasetCount; i++){\n if (!setsEqual(changeSet, makeSet(i))) {\n return;\n }\n }\n return Array.from(changeSet).map((c)=>c.split(',')).map((a)=>({\n method: a[1],\n start: +a[2],\n count: +a[3]\n }));\n }\n _updateLayout(minPadding) {\n if (this.notifyPlugins('beforeLayout', {\n cancelable: true\n }) === false) {\n return;\n }\n layouts.update(this, this.width, this.height, minPadding);\n const area = this.chartArea;\n const noArea = area.width <= 0 || area.height <= 0;\n this._layers = [];\n each(this.boxes, (box)=>{\n if (noArea && box.position === 'chartArea') {\n return;\n }\n if (box.configure) {\n box.configure();\n }\n this._layers.push(...box._layers());\n }, this);\n this._layers.forEach((item, index)=>{\n item._idx = index;\n });\n this.notifyPlugins('afterLayout');\n }\n _updateDatasets(mode) {\n if (this.notifyPlugins('beforeDatasetsUpdate', {\n mode,\n cancelable: true\n }) === false) {\n return;\n }\n for(let i = 0, ilen = this.data.datasets.length; i < ilen; ++i){\n this.getDatasetMeta(i).controller.configure();\n }\n for(let i = 0, ilen = this.data.datasets.length; i < ilen; ++i){\n this._updateDataset(i, isFunction(mode) ? mode({\n datasetIndex: i\n }) : mode);\n }\n this.notifyPlugins('afterDatasetsUpdate', {\n mode\n });\n }\n _updateDataset(index, mode) {\n const meta = this.getDatasetMeta(index);\n const args = {\n meta,\n index,\n mode,\n cancelable: true\n };\n if (this.notifyPlugins('beforeDatasetUpdate', args) === false) {\n return;\n }\n meta.controller._update(mode);\n args.cancelable = false;\n this.notifyPlugins('afterDatasetUpdate', args);\n }\n render() {\n if (this.notifyPlugins('beforeRender', {\n cancelable: true\n }) === false) {\n return;\n }\n if (animator.has(this)) {\n if (this.attached && !animator.running(this)) {\n animator.start(this);\n }\n } else {\n this.draw();\n onAnimationsComplete({\n chart: this\n });\n }\n }\n draw() {\n let i;\n if (this._resizeBeforeDraw) {\n const { width , height } = this._resizeBeforeDraw;\n this._resizeBeforeDraw = null;\n this._resize(width, height);\n }\n this.clear();\n if (this.width <= 0 || this.height <= 0) {\n return;\n }\n if (this.notifyPlugins('beforeDraw', {\n cancelable: true\n }) === false) {\n return;\n }\n const layers = this._layers;\n for(i = 0; i < layers.length && layers[i].z <= 0; ++i){\n layers[i].draw(this.chartArea);\n }\n this._drawDatasets();\n for(; i < layers.length; ++i){\n layers[i].draw(this.chartArea);\n }\n this.notifyPlugins('afterDraw');\n }\n _getSortedDatasetMetas(filterVisible) {\n const metasets = this._sortedMetasets;\n const result = [];\n let i, ilen;\n for(i = 0, ilen = metasets.length; i < ilen; ++i){\n const meta = metasets[i];\n if (!filterVisible || meta.visible) {\n result.push(meta);\n }\n }\n return result;\n }\n getSortedVisibleDatasetMetas() {\n return this._getSortedDatasetMetas(true);\n }\n _drawDatasets() {\n if (this.notifyPlugins('beforeDatasetsDraw', {\n cancelable: true\n }) === false) {\n return;\n }\n const metasets = this.getSortedVisibleDatasetMetas();\n for(let i = metasets.length - 1; i >= 0; --i){\n this._drawDataset(metasets[i]);\n }\n this.notifyPlugins('afterDatasetsDraw');\n }\n _drawDataset(meta) {\n const ctx = this.ctx;\n const clip = meta._clip;\n const useClip = !clip.disabled;\n const area = getDatasetArea(meta, this.chartArea);\n const args = {\n meta,\n index: meta.index,\n cancelable: true\n };\n if (this.notifyPlugins('beforeDatasetDraw', args) === false) {\n return;\n }\n if (useClip) {\n clipArea(ctx, {\n left: clip.left === false ? 0 : area.left - clip.left,\n right: clip.right === false ? this.width : area.right + clip.right,\n top: clip.top === false ? 0 : area.top - clip.top,\n bottom: clip.bottom === false ? this.height : area.bottom + clip.bottom\n });\n }\n meta.controller.draw();\n if (useClip) {\n unclipArea(ctx);\n }\n args.cancelable = false;\n this.notifyPlugins('afterDatasetDraw', args);\n }\n isPointInArea(point) {\n return _isPointInArea(point, this.chartArea, this._minPadding);\n }\n getElementsAtEventForMode(e, mode, options, useFinalPosition) {\n const method = Interaction.modes[mode];\n if (typeof method === 'function') {\n return method(this, e, options, useFinalPosition);\n }\n return [];\n }\n getDatasetMeta(datasetIndex) {\n const dataset = this.data.datasets[datasetIndex];\n const metasets = this._metasets;\n let meta = metasets.filter((x)=>x && x._dataset === dataset).pop();\n if (!meta) {\n meta = {\n type: null,\n data: [],\n dataset: null,\n controller: null,\n hidden: null,\n xAxisID: null,\n yAxisID: null,\n order: dataset && dataset.order || 0,\n index: datasetIndex,\n _dataset: dataset,\n _parsed: [],\n _sorted: false\n };\n metasets.push(meta);\n }\n return meta;\n }\n getContext() {\n return this.$context || (this.$context = createContext(null, {\n chart: this,\n type: 'chart'\n }));\n }\n getVisibleDatasetCount() {\n return this.getSortedVisibleDatasetMetas().length;\n }\n isDatasetVisible(datasetIndex) {\n const dataset = this.data.datasets[datasetIndex];\n if (!dataset) {\n return false;\n }\n const meta = this.getDatasetMeta(datasetIndex);\n return typeof meta.hidden === 'boolean' ? !meta.hidden : !dataset.hidden;\n }\n setDatasetVisibility(datasetIndex, visible) {\n const meta = this.getDatasetMeta(datasetIndex);\n meta.hidden = !visible;\n }\n toggleDataVisibility(index) {\n this._hiddenIndices[index] = !this._hiddenIndices[index];\n }\n getDataVisibility(index) {\n return !this._hiddenIndices[index];\n }\n _updateVisibility(datasetIndex, dataIndex, visible) {\n const mode = visible ? 'show' : 'hide';\n const meta = this.getDatasetMeta(datasetIndex);\n const anims = meta.controller._resolveAnimations(undefined, mode);\n if (defined(dataIndex)) {\n meta.data[dataIndex].hidden = !visible;\n this.update();\n } else {\n this.setDatasetVisibility(datasetIndex, visible);\n anims.update(meta, {\n visible\n });\n this.update((ctx)=>ctx.datasetIndex === datasetIndex ? mode : undefined);\n }\n }\n hide(datasetIndex, dataIndex) {\n this._updateVisibility(datasetIndex, dataIndex, false);\n }\n show(datasetIndex, dataIndex) {\n this._updateVisibility(datasetIndex, dataIndex, true);\n }\n _destroyDatasetMeta(datasetIndex) {\n const meta = this._metasets[datasetIndex];\n if (meta && meta.controller) {\n meta.controller._destroy();\n }\n delete this._metasets[datasetIndex];\n }\n _stop() {\n let i, ilen;\n this.stop();\n animator.remove(this);\n for(i = 0, ilen = this.data.datasets.length; i < ilen; ++i){\n this._destroyDatasetMeta(i);\n }\n }\n destroy() {\n this.notifyPlugins('beforeDestroy');\n const { canvas , ctx } = this;\n this._stop();\n this.config.clearCache();\n if (canvas) {\n this.unbindEvents();\n clearCanvas(canvas, ctx);\n this.platform.releaseContext(ctx);\n this.canvas = null;\n this.ctx = null;\n }\n delete instances[this.id];\n this.notifyPlugins('afterDestroy');\n }\n toBase64Image(...args) {\n return this.canvas.toDataURL(...args);\n }\n bindEvents() {\n this.bindUserEvents();\n if (this.options.responsive) {\n this.bindResponsiveEvents();\n } else {\n this.attached = true;\n }\n }\n bindUserEvents() {\n const listeners = this._listeners;\n const platform = this.platform;\n const _add = (type, listener)=>{\n platform.addEventListener(this, type, listener);\n listeners[type] = listener;\n };\n const listener = (e, x, y)=>{\n e.offsetX = x;\n e.offsetY = y;\n this._eventHandler(e);\n };\n each(this.options.events, (type)=>_add(type, listener));\n }\n bindResponsiveEvents() {\n if (!this._responsiveListeners) {\n this._responsiveListeners = {};\n }\n const listeners = this._responsiveListeners;\n const platform = this.platform;\n const _add = (type, listener)=>{\n platform.addEventListener(this, type, listener);\n listeners[type] = listener;\n };\n const _remove = (type, listener)=>{\n if (listeners[type]) {\n platform.removeEventListener(this, type, listener);\n delete listeners[type];\n }\n };\n const listener = (width, height)=>{\n if (this.canvas) {\n this.resize(width, height);\n }\n };\n let detached;\n const attached = ()=>{\n _remove('attach', attached);\n this.attached = true;\n this.resize();\n _add('resize', listener);\n _add('detach', detached);\n };\n detached = ()=>{\n this.attached = false;\n _remove('resize', listener);\n this._stop();\n this._resize(0, 0);\n _add('attach', attached);\n };\n if (platform.isAttached(this.canvas)) {\n attached();\n } else {\n detached();\n }\n }\n unbindEvents() {\n each(this._listeners, (listener, type)=>{\n this.platform.removeEventListener(this, type, listener);\n });\n this._listeners = {};\n each(this._responsiveListeners, (listener, type)=>{\n this.platform.removeEventListener(this, type, listener);\n });\n this._responsiveListeners = undefined;\n }\n updateHoverStyle(items, mode, enabled) {\n const prefix = enabled ? 'set' : 'remove';\n let meta, item, i, ilen;\n if (mode === 'dataset') {\n meta = this.getDatasetMeta(items[0].datasetIndex);\n meta.controller['_' + prefix + 'DatasetHoverStyle']();\n }\n for(i = 0, ilen = items.length; i < ilen; ++i){\n item = items[i];\n const controller = item && this.getDatasetMeta(item.datasetIndex).controller;\n if (controller) {\n controller[prefix + 'HoverStyle'](item.element, item.datasetIndex, item.index);\n }\n }\n }\n getActiveElements() {\n return this._active || [];\n }\n setActiveElements(activeElements) {\n const lastActive = this._active || [];\n const active = activeElements.map(({ datasetIndex , index })=>{\n const meta = this.getDatasetMeta(datasetIndex);\n if (!meta) {\n throw new Error('No dataset found at index ' + datasetIndex);\n }\n return {\n datasetIndex,\n element: meta.data[index],\n index\n };\n });\n const changed = !_elementsEqual(active, lastActive);\n if (changed) {\n this._active = active;\n this._lastEvent = null;\n this._updateHoverStyles(active, lastActive);\n }\n }\n notifyPlugins(hook, args, filter) {\n return this._plugins.notify(this, hook, args, filter);\n }\n isPluginEnabled(pluginId) {\n return this._plugins._cache.filter((p)=>p.plugin.id === pluginId).length === 1;\n }\n _updateHoverStyles(active, lastActive, replay) {\n const hoverOptions = this.options.hover;\n const diff = (a, b)=>a.filter((x)=>!b.some((y)=>x.datasetIndex === y.datasetIndex && x.index === y.index));\n const deactivated = diff(lastActive, active);\n const activated = replay ? active : diff(active, lastActive);\n if (deactivated.length) {\n this.updateHoverStyle(deactivated, hoverOptions.mode, false);\n }\n if (activated.length && hoverOptions.mode) {\n this.updateHoverStyle(activated, hoverOptions.mode, true);\n }\n }\n _eventHandler(e, replay) {\n const args = {\n event: e,\n replay,\n cancelable: true,\n inChartArea: this.isPointInArea(e)\n };\n const eventFilter = (plugin)=>(plugin.options.events || this.options.events).includes(e.native.type);\n if (this.notifyPlugins('beforeEvent', args, eventFilter) === false) {\n return;\n }\n const changed = this._handleEvent(e, replay, args.inChartArea);\n args.cancelable = false;\n this.notifyPlugins('afterEvent', args, eventFilter);\n if (changed || args.changed) {\n this.render();\n }\n return this;\n }\n _handleEvent(e, replay, inChartArea) {\n const { _active: lastActive = [] , options } = this;\n const useFinalPosition = replay;\n const active = this._getActiveElements(e, lastActive, inChartArea, useFinalPosition);\n const isClick = _isClickEvent(e);\n const lastEvent = determineLastEvent(e, this._lastEvent, inChartArea, isClick);\n if (inChartArea) {\n this._lastEvent = null;\n callback(options.onHover, [\n e,\n active,\n this\n ], this);\n if (isClick) {\n callback(options.onClick, [\n e,\n active,\n this\n ], this);\n }\n }\n const changed = !_elementsEqual(active, lastActive);\n if (changed || replay) {\n this._active = active;\n this._updateHoverStyles(active, lastActive, replay);\n }\n this._lastEvent = lastEvent;\n return changed;\n }\n _getActiveElements(e, lastActive, inChartArea, useFinalPosition) {\n if (e.type === 'mouseout') {\n return [];\n }\n if (!inChartArea) {\n return lastActive;\n }\n const hoverOptions = this.options.hover;\n return this.getElementsAtEventForMode(e, hoverOptions.mode, hoverOptions, useFinalPosition);\n }\n}\nfunction invalidatePlugins() {\n return each(chart_Chart.instances, (chart)=>chart._plugins.invalidate());\n}\n\nfunction clipArc(ctx, element, endAngle) {\n const { startAngle , pixelMargin , x , y , outerRadius , innerRadius } = element;\n let angleMargin = pixelMargin / outerRadius;\n // Draw an inner border by clipping the arc and drawing a double-width border\n // Enlarge the clipping arc by 0.33 pixels to eliminate glitches between borders\n ctx.beginPath();\n ctx.arc(x, y, outerRadius, startAngle - angleMargin, endAngle + angleMargin);\n if (innerRadius > pixelMargin) {\n angleMargin = pixelMargin / innerRadius;\n ctx.arc(x, y, innerRadius, endAngle + angleMargin, startAngle - angleMargin, true);\n } else {\n ctx.arc(x, y, pixelMargin, endAngle + HALF_PI, startAngle - HALF_PI);\n }\n ctx.closePath();\n ctx.clip();\n}\nfunction toRadiusCorners(value) {\n return _readValueToProps(value, [\n 'outerStart',\n 'outerEnd',\n 'innerStart',\n 'innerEnd'\n ]);\n}\n/**\n * Parse border radius from the provided options\n */ function parseBorderRadius$1(arc, innerRadius, outerRadius, angleDelta) {\n const o = toRadiusCorners(arc.options.borderRadius);\n const halfThickness = (outerRadius - innerRadius) / 2;\n const innerLimit = Math.min(halfThickness, angleDelta * innerRadius / 2);\n // Outer limits are complicated. We want to compute the available angular distance at\n // a radius of outerRadius - borderRadius because for small angular distances, this term limits.\n // We compute at r = outerRadius - borderRadius because this circle defines the center of the border corners.\n //\n // If the borderRadius is large, that value can become negative.\n // This causes the outer borders to lose their radius entirely, which is rather unexpected. To solve that, if borderRadius > outerRadius\n // we know that the thickness term will dominate and compute the limits at that point\n const computeOuterLimit = (val)=>{\n const outerArcLimit = (outerRadius - Math.min(halfThickness, val)) * angleDelta / 2;\n return _limitValue(val, 0, Math.min(halfThickness, outerArcLimit));\n };\n return {\n outerStart: computeOuterLimit(o.outerStart),\n outerEnd: computeOuterLimit(o.outerEnd),\n innerStart: _limitValue(o.innerStart, 0, innerLimit),\n innerEnd: _limitValue(o.innerEnd, 0, innerLimit)\n };\n}\n/**\n * Convert (r, 𝜃) to (x, y)\n */ function rThetaToXY(r, theta, x, y) {\n return {\n x: x + r * Math.cos(theta),\n y: y + r * Math.sin(theta)\n };\n}\n/**\n * Path the arc, respecting border radius by separating into left and right halves.\n *\n * Start End\n *\n * 1---\x3ea---\x3e2 Outer\n * / \\\n * 8 3\n * | |\n * | |\n * 7 4\n * \\ /\n * 6<---b<---5 Inner\n */ function pathArc(ctx, element, offset, spacing, end, circular) {\n const { x , y , startAngle: start , pixelMargin , innerRadius: innerR } = element;\n const outerRadius = Math.max(element.outerRadius + spacing + offset - pixelMargin, 0);\n const innerRadius = innerR > 0 ? innerR + spacing + offset + pixelMargin : 0;\n let spacingOffset = 0;\n const alpha = end - start;\n if (spacing) {\n // When spacing is present, it is the same for all items\n // So we adjust the start and end angle of the arc such that\n // the distance is the same as it would be without the spacing\n const noSpacingInnerRadius = innerR > 0 ? innerR - spacing : 0;\n const noSpacingOuterRadius = outerRadius > 0 ? outerRadius - spacing : 0;\n const avNogSpacingRadius = (noSpacingInnerRadius + noSpacingOuterRadius) / 2;\n const adjustedAngle = avNogSpacingRadius !== 0 ? alpha * avNogSpacingRadius / (avNogSpacingRadius + spacing) : alpha;\n spacingOffset = (alpha - adjustedAngle) / 2;\n }\n const beta = Math.max(0.001, alpha * outerRadius - offset / PI) / outerRadius;\n const angleOffset = (alpha - beta) / 2;\n const startAngle = start + angleOffset + spacingOffset;\n const endAngle = end - angleOffset - spacingOffset;\n const { outerStart , outerEnd , innerStart , innerEnd } = parseBorderRadius$1(element, innerRadius, outerRadius, endAngle - startAngle);\n const outerStartAdjustedRadius = outerRadius - outerStart;\n const outerEndAdjustedRadius = outerRadius - outerEnd;\n const outerStartAdjustedAngle = startAngle + outerStart / outerStartAdjustedRadius;\n const outerEndAdjustedAngle = endAngle - outerEnd / outerEndAdjustedRadius;\n const innerStartAdjustedRadius = innerRadius + innerStart;\n const innerEndAdjustedRadius = innerRadius + innerEnd;\n const innerStartAdjustedAngle = startAngle + innerStart / innerStartAdjustedRadius;\n const innerEndAdjustedAngle = endAngle - innerEnd / innerEndAdjustedRadius;\n ctx.beginPath();\n if (circular) {\n // The first arc segments from point 1 to point a to point 2\n const outerMidAdjustedAngle = (outerStartAdjustedAngle + outerEndAdjustedAngle) / 2;\n ctx.arc(x, y, outerRadius, outerStartAdjustedAngle, outerMidAdjustedAngle);\n ctx.arc(x, y, outerRadius, outerMidAdjustedAngle, outerEndAdjustedAngle);\n // The corner segment from point 2 to point 3\n if (outerEnd > 0) {\n const pCenter = rThetaToXY(outerEndAdjustedRadius, outerEndAdjustedAngle, x, y);\n ctx.arc(pCenter.x, pCenter.y, outerEnd, outerEndAdjustedAngle, endAngle + HALF_PI);\n }\n // The line from point 3 to point 4\n const p4 = rThetaToXY(innerEndAdjustedRadius, endAngle, x, y);\n ctx.lineTo(p4.x, p4.y);\n // The corner segment from point 4 to point 5\n if (innerEnd > 0) {\n const pCenter = rThetaToXY(innerEndAdjustedRadius, innerEndAdjustedAngle, x, y);\n ctx.arc(pCenter.x, pCenter.y, innerEnd, endAngle + HALF_PI, innerEndAdjustedAngle + Math.PI);\n }\n // The inner arc from point 5 to point b to point 6\n const innerMidAdjustedAngle = (endAngle - innerEnd / innerRadius + (startAngle + innerStart / innerRadius)) / 2;\n ctx.arc(x, y, innerRadius, endAngle - innerEnd / innerRadius, innerMidAdjustedAngle, true);\n ctx.arc(x, y, innerRadius, innerMidAdjustedAngle, startAngle + innerStart / innerRadius, true);\n // The corner segment from point 6 to point 7\n if (innerStart > 0) {\n const pCenter = rThetaToXY(innerStartAdjustedRadius, innerStartAdjustedAngle, x, y);\n ctx.arc(pCenter.x, pCenter.y, innerStart, innerStartAdjustedAngle + Math.PI, startAngle - HALF_PI);\n }\n // The line from point 7 to point 8\n const p8 = rThetaToXY(outerStartAdjustedRadius, startAngle, x, y);\n ctx.lineTo(p8.x, p8.y);\n // The corner segment from point 8 to point 1\n if (outerStart > 0) {\n const pCenter = rThetaToXY(outerStartAdjustedRadius, outerStartAdjustedAngle, x, y);\n ctx.arc(pCenter.x, pCenter.y, outerStart, startAngle - HALF_PI, outerStartAdjustedAngle);\n }\n } else {\n ctx.moveTo(x, y);\n const outerStartX = Math.cos(outerStartAdjustedAngle) * outerRadius + x;\n const outerStartY = Math.sin(outerStartAdjustedAngle) * outerRadius + y;\n ctx.lineTo(outerStartX, outerStartY);\n const outerEndX = Math.cos(outerEndAdjustedAngle) * outerRadius + x;\n const outerEndY = Math.sin(outerEndAdjustedAngle) * outerRadius + y;\n ctx.lineTo(outerEndX, outerEndY);\n }\n ctx.closePath();\n}\nfunction drawArc(ctx, element, offset, spacing, circular) {\n const { fullCircles , startAngle , circumference } = element;\n let endAngle = element.endAngle;\n if (fullCircles) {\n pathArc(ctx, element, offset, spacing, endAngle, circular);\n for(let i = 0; i < fullCircles; ++i){\n ctx.fill();\n }\n if (!isNaN(circumference)) {\n endAngle = startAngle + (circumference % TAU || TAU);\n }\n }\n pathArc(ctx, element, offset, spacing, endAngle, circular);\n ctx.fill();\n return endAngle;\n}\nfunction drawBorder(ctx, element, offset, spacing, circular) {\n const { fullCircles , startAngle , circumference , options } = element;\n const { borderWidth , borderJoinStyle , borderDash , borderDashOffset } = options;\n const inner = options.borderAlign === 'inner';\n if (!borderWidth) {\n return;\n }\n ctx.setLineDash(borderDash || []);\n ctx.lineDashOffset = borderDashOffset;\n if (inner) {\n ctx.lineWidth = borderWidth * 2;\n ctx.lineJoin = borderJoinStyle || 'round';\n } else {\n ctx.lineWidth = borderWidth;\n ctx.lineJoin = borderJoinStyle || 'bevel';\n }\n let endAngle = element.endAngle;\n if (fullCircles) {\n pathArc(ctx, element, offset, spacing, endAngle, circular);\n for(let i = 0; i < fullCircles; ++i){\n ctx.stroke();\n }\n if (!isNaN(circumference)) {\n endAngle = startAngle + (circumference % TAU || TAU);\n }\n }\n if (inner) {\n clipArc(ctx, element, endAngle);\n }\n if (!fullCircles) {\n pathArc(ctx, element, offset, spacing, endAngle, circular);\n ctx.stroke();\n }\n}\nclass ArcElement extends chart_Element {\n static id = 'arc';\n static defaults = {\n borderAlign: 'center',\n borderColor: '#fff',\n borderDash: [],\n borderDashOffset: 0,\n borderJoinStyle: undefined,\n borderRadius: 0,\n borderWidth: 2,\n offset: 0,\n spacing: 0,\n angle: undefined,\n circular: true\n };\n static defaultRoutes = {\n backgroundColor: 'backgroundColor'\n };\n static descriptors = {\n _scriptable: true,\n _indexable: (name)=>name !== 'borderDash'\n };\n circumference;\n endAngle;\n fullCircles;\n innerRadius;\n outerRadius;\n pixelMargin;\n startAngle;\n constructor(cfg){\n super();\n this.options = undefined;\n this.circumference = undefined;\n this.startAngle = undefined;\n this.endAngle = undefined;\n this.innerRadius = undefined;\n this.outerRadius = undefined;\n this.pixelMargin = 0;\n this.fullCircles = 0;\n if (cfg) {\n Object.assign(this, cfg);\n }\n }\n inRange(chartX, chartY, useFinalPosition) {\n const point = this.getProps([\n 'x',\n 'y'\n ], useFinalPosition);\n const { angle , distance } = getAngleFromPoint(point, {\n x: chartX,\n y: chartY\n });\n const { startAngle , endAngle , innerRadius , outerRadius , circumference } = this.getProps([\n 'startAngle',\n 'endAngle',\n 'innerRadius',\n 'outerRadius',\n 'circumference'\n ], useFinalPosition);\n const rAdjust = (this.options.spacing + this.options.borderWidth) / 2;\n const _circumference = valueOrDefault(circumference, endAngle - startAngle);\n const nonZeroBetween = _angleBetween(angle, startAngle, endAngle) && startAngle !== endAngle;\n const betweenAngles = _circumference >= TAU || nonZeroBetween;\n const withinRadius = _isBetween(distance, innerRadius + rAdjust, outerRadius + rAdjust);\n return betweenAngles && withinRadius;\n }\n getCenterPoint(useFinalPosition) {\n const { x , y , startAngle , endAngle , innerRadius , outerRadius } = this.getProps([\n 'x',\n 'y',\n 'startAngle',\n 'endAngle',\n 'innerRadius',\n 'outerRadius'\n ], useFinalPosition);\n const { offset , spacing } = this.options;\n const halfAngle = (startAngle + endAngle) / 2;\n const halfRadius = (innerRadius + outerRadius + spacing + offset) / 2;\n return {\n x: x + Math.cos(halfAngle) * halfRadius,\n y: y + Math.sin(halfAngle) * halfRadius\n };\n }\n tooltipPosition(useFinalPosition) {\n return this.getCenterPoint(useFinalPosition);\n }\n draw(ctx) {\n const { options , circumference } = this;\n const offset = (options.offset || 0) / 4;\n const spacing = (options.spacing || 0) / 2;\n const circular = options.circular;\n this.pixelMargin = options.borderAlign === 'inner' ? 0.33 : 0;\n this.fullCircles = circumference > TAU ? Math.floor(circumference / TAU) : 0;\n if (circumference === 0 || this.innerRadius < 0 || this.outerRadius < 0) {\n return;\n }\n ctx.save();\n const halfAngle = (this.startAngle + this.endAngle) / 2;\n ctx.translate(Math.cos(halfAngle) * offset, Math.sin(halfAngle) * offset);\n const fix = 1 - Math.sin(Math.min(PI, circumference || 0));\n const radiusOffset = offset * fix;\n ctx.fillStyle = options.backgroundColor;\n ctx.strokeStyle = options.borderColor;\n drawArc(ctx, this, radiusOffset, spacing, circular);\n drawBorder(ctx, this, radiusOffset, spacing, circular);\n ctx.restore();\n }\n}\n\nfunction setStyle(ctx, options, style = options) {\n ctx.lineCap = valueOrDefault(style.borderCapStyle, options.borderCapStyle);\n ctx.setLineDash(valueOrDefault(style.borderDash, options.borderDash));\n ctx.lineDashOffset = valueOrDefault(style.borderDashOffset, options.borderDashOffset);\n ctx.lineJoin = valueOrDefault(style.borderJoinStyle, options.borderJoinStyle);\n ctx.lineWidth = valueOrDefault(style.borderWidth, options.borderWidth);\n ctx.strokeStyle = valueOrDefault(style.borderColor, options.borderColor);\n}\nfunction lineTo(ctx, previous, target) {\n ctx.lineTo(target.x, target.y);\n}\n function getLineMethod(options) {\n if (options.stepped) {\n return _steppedLineTo;\n }\n if (options.tension || options.cubicInterpolationMode === 'monotone') {\n return _bezierCurveTo;\n }\n return lineTo;\n}\nfunction pathVars(points, segment, params = {}) {\n const count = points.length;\n const { start: paramsStart = 0 , end: paramsEnd = count - 1 } = params;\n const { start: segmentStart , end: segmentEnd } = segment;\n const start = Math.max(paramsStart, segmentStart);\n const end = Math.min(paramsEnd, segmentEnd);\n const outside = paramsStart < segmentStart && paramsEnd < segmentStart || paramsStart > segmentEnd && paramsEnd > segmentEnd;\n return {\n count,\n start,\n loop: segment.loop,\n ilen: end < start && !outside ? count + end - start : end - start\n };\n}\n function pathSegment(ctx, line, segment, params) {\n const { points , options } = line;\n const { count , start , loop , ilen } = pathVars(points, segment, params);\n const lineMethod = getLineMethod(options);\n let { move =true , reverse } = params || {};\n let i, point, prev;\n for(i = 0; i <= ilen; ++i){\n point = points[(start + (reverse ? ilen - i : i)) % count];\n if (point.skip) {\n continue;\n } else if (move) {\n ctx.moveTo(point.x, point.y);\n move = false;\n } else {\n lineMethod(ctx, prev, point, reverse, options.stepped);\n }\n prev = point;\n }\n if (loop) {\n point = points[(start + (reverse ? ilen : 0)) % count];\n lineMethod(ctx, prev, point, reverse, options.stepped);\n }\n return !!loop;\n}\n function fastPathSegment(ctx, line, segment, params) {\n const points = line.points;\n const { count , start , ilen } = pathVars(points, segment, params);\n const { move =true , reverse } = params || {};\n let avgX = 0;\n let countX = 0;\n let i, point, prevX, minY, maxY, lastY;\n const pointIndex = (index)=>(start + (reverse ? ilen - index : index)) % count;\n const drawX = ()=>{\n if (minY !== maxY) {\n ctx.lineTo(avgX, maxY);\n ctx.lineTo(avgX, minY);\n ctx.lineTo(avgX, lastY);\n }\n };\n if (move) {\n point = points[pointIndex(0)];\n ctx.moveTo(point.x, point.y);\n }\n for(i = 0; i <= ilen; ++i){\n point = points[pointIndex(i)];\n if (point.skip) {\n continue;\n }\n const x = point.x;\n const y = point.y;\n const truncX = x | 0;\n if (truncX === prevX) {\n if (y < minY) {\n minY = y;\n } else if (y > maxY) {\n maxY = y;\n }\n avgX = (countX * avgX + x) / ++countX;\n } else {\n drawX();\n ctx.lineTo(x, y);\n prevX = truncX;\n countX = 0;\n minY = maxY = y;\n }\n lastY = y;\n }\n drawX();\n}\n function _getSegmentMethod(line) {\n const opts = line.options;\n const borderDash = opts.borderDash && opts.borderDash.length;\n const useFastPath = !line._decimated && !line._loop && !opts.tension && opts.cubicInterpolationMode !== 'monotone' && !opts.stepped && !borderDash;\n return useFastPath ? fastPathSegment : pathSegment;\n}\n function _getInterpolationMethod(options) {\n if (options.stepped) {\n return _steppedInterpolation;\n }\n if (options.tension || options.cubicInterpolationMode === 'monotone') {\n return _bezierInterpolation;\n }\n return _pointInLine;\n}\nfunction strokePathWithCache(ctx, line, start, count) {\n let path = line._path;\n if (!path) {\n path = line._path = new Path2D();\n if (line.path(path, start, count)) {\n path.closePath();\n }\n }\n setStyle(ctx, line.options);\n ctx.stroke(path);\n}\nfunction strokePathDirect(ctx, line, start, count) {\n const { segments , options } = line;\n const segmentMethod = _getSegmentMethod(line);\n for (const segment of segments){\n setStyle(ctx, options, segment.style);\n ctx.beginPath();\n if (segmentMethod(ctx, line, segment, {\n start,\n end: start + count - 1\n })) {\n ctx.closePath();\n }\n ctx.stroke();\n }\n}\nconst usePath2D = typeof Path2D === 'function';\nfunction draw(ctx, line, start, count) {\n if (usePath2D && !line.options.segment) {\n strokePathWithCache(ctx, line, start, count);\n } else {\n strokePathDirect(ctx, line, start, count);\n }\n}\nclass LineElement extends chart_Element {\n static id = 'line';\n static defaults = {\n borderCapStyle: 'butt',\n borderDash: [],\n borderDashOffset: 0,\n borderJoinStyle: 'miter',\n borderWidth: 3,\n capBezierPoints: true,\n cubicInterpolationMode: 'default',\n fill: false,\n spanGaps: false,\n stepped: false,\n tension: 0\n };\n static defaultRoutes = {\n backgroundColor: 'backgroundColor',\n borderColor: 'borderColor'\n };\n static descriptors = {\n _scriptable: true,\n _indexable: (name)=>name !== 'borderDash' && name !== 'fill'\n };\n constructor(cfg){\n super();\n this.animated = true;\n this.options = undefined;\n this._chart = undefined;\n this._loop = undefined;\n this._fullLoop = undefined;\n this._path = undefined;\n this._points = undefined;\n this._segments = undefined;\n this._decimated = false;\n this._pointsUpdated = false;\n this._datasetIndex = undefined;\n if (cfg) {\n Object.assign(this, cfg);\n }\n }\n updateControlPoints(chartArea, indexAxis) {\n const options = this.options;\n if ((options.tension || options.cubicInterpolationMode === 'monotone') && !options.stepped && !this._pointsUpdated) {\n const loop = options.spanGaps ? this._loop : this._fullLoop;\n _updateBezierControlPoints(this._points, options, chartArea, loop, indexAxis);\n this._pointsUpdated = true;\n }\n }\n set points(points) {\n this._points = points;\n delete this._segments;\n delete this._path;\n this._pointsUpdated = false;\n }\n get points() {\n return this._points;\n }\n get segments() {\n return this._segments || (this._segments = _computeSegments(this, this.options.segment));\n }\n first() {\n const segments = this.segments;\n const points = this.points;\n return segments.length && points[segments[0].start];\n }\n last() {\n const segments = this.segments;\n const points = this.points;\n const count = segments.length;\n return count && points[segments[count - 1].end];\n }\n interpolate(point, property) {\n const options = this.options;\n const value = point[property];\n const points = this.points;\n const segments = _boundSegments(this, {\n property,\n start: value,\n end: value\n });\n if (!segments.length) {\n return;\n }\n const result = [];\n const _interpolate = _getInterpolationMethod(options);\n let i, ilen;\n for(i = 0, ilen = segments.length; i < ilen; ++i){\n const { start , end } = segments[i];\n const p1 = points[start];\n const p2 = points[end];\n if (p1 === p2) {\n result.push(p1);\n continue;\n }\n const t = Math.abs((value - p1[property]) / (p2[property] - p1[property]));\n const interpolated = _interpolate(p1, p2, t, options.stepped);\n interpolated[property] = point[property];\n result.push(interpolated);\n }\n return result.length === 1 ? result[0] : result;\n }\n pathSegment(ctx, segment, params) {\n const segmentMethod = _getSegmentMethod(this);\n return segmentMethod(ctx, this, segment, params);\n }\n path(ctx, start, count) {\n const segments = this.segments;\n const segmentMethod = _getSegmentMethod(this);\n let loop = this._loop;\n start = start || 0;\n count = count || this.points.length - start;\n for (const segment of segments){\n loop &= segmentMethod(ctx, this, segment, {\n start,\n end: start + count - 1\n });\n }\n return !!loop;\n }\n draw(ctx, chartArea, start, count) {\n const options = this.options || {};\n const points = this.points || [];\n if (points.length && options.borderWidth) {\n ctx.save();\n draw(ctx, this, start, count);\n ctx.restore();\n }\n if (this.animated) {\n this._pointsUpdated = false;\n this._path = undefined;\n }\n }\n}\n\nfunction inRange$1(el, pos, axis, useFinalPosition) {\n const options = el.options;\n const { [axis]: value } = el.getProps([\n axis\n ], useFinalPosition);\n return Math.abs(pos - value) < options.radius + options.hitRadius;\n}\nclass PointElement extends chart_Element {\n static id = 'point';\n parsed;\n skip;\n stop;\n /**\n * @type {any}\n */ static defaults = {\n borderWidth: 1,\n hitRadius: 1,\n hoverBorderWidth: 1,\n hoverRadius: 4,\n pointStyle: 'circle',\n radius: 3,\n rotation: 0\n };\n /**\n * @type {any}\n */ static defaultRoutes = {\n backgroundColor: 'backgroundColor',\n borderColor: 'borderColor'\n };\n constructor(cfg){\n super();\n this.options = undefined;\n this.parsed = undefined;\n this.skip = undefined;\n this.stop = undefined;\n if (cfg) {\n Object.assign(this, cfg);\n }\n }\n inRange(mouseX, mouseY, useFinalPosition) {\n const options = this.options;\n const { x , y } = this.getProps([\n 'x',\n 'y'\n ], useFinalPosition);\n return Math.pow(mouseX - x, 2) + Math.pow(mouseY - y, 2) < Math.pow(options.hitRadius + options.radius, 2);\n }\n inXRange(mouseX, useFinalPosition) {\n return inRange$1(this, mouseX, 'x', useFinalPosition);\n }\n inYRange(mouseY, useFinalPosition) {\n return inRange$1(this, mouseY, 'y', useFinalPosition);\n }\n getCenterPoint(useFinalPosition) {\n const { x , y } = this.getProps([\n 'x',\n 'y'\n ], useFinalPosition);\n return {\n x,\n y\n };\n }\n size(options) {\n options = options || this.options || {};\n let radius = options.radius || 0;\n radius = Math.max(radius, radius && options.hoverRadius || 0);\n const borderWidth = radius && options.borderWidth || 0;\n return (radius + borderWidth) * 2;\n }\n draw(ctx, area) {\n const options = this.options;\n if (this.skip || options.radius < 0.1 || !_isPointInArea(this, area, this.size(options) / 2)) {\n return;\n }\n ctx.strokeStyle = options.borderColor;\n ctx.lineWidth = options.borderWidth;\n ctx.fillStyle = options.backgroundColor;\n drawPoint(ctx, options, this.x, this.y);\n }\n getRange() {\n const options = this.options || {};\n // @ts-expect-error Fallbacks should never be hit in practice\n return options.radius + options.hitRadius;\n }\n}\n\nfunction getBarBounds(bar, useFinalPosition) {\n const { x , y , base , width , height } = bar.getProps([\n 'x',\n 'y',\n 'base',\n 'width',\n 'height'\n ], useFinalPosition);\n let left, right, top, bottom, half;\n if (bar.horizontal) {\n half = height / 2;\n left = Math.min(x, base);\n right = Math.max(x, base);\n top = y - half;\n bottom = y + half;\n } else {\n half = width / 2;\n left = x - half;\n right = x + half;\n top = Math.min(y, base);\n bottom = Math.max(y, base);\n }\n return {\n left,\n top,\n right,\n bottom\n };\n}\nfunction skipOrLimit(skip, value, min, max) {\n return skip ? 0 : _limitValue(value, min, max);\n}\nfunction parseBorderWidth(bar, maxW, maxH) {\n const value = bar.options.borderWidth;\n const skip = bar.borderSkipped;\n const o = toTRBL(value);\n return {\n t: skipOrLimit(skip.top, o.top, 0, maxH),\n r: skipOrLimit(skip.right, o.right, 0, maxW),\n b: skipOrLimit(skip.bottom, o.bottom, 0, maxH),\n l: skipOrLimit(skip.left, o.left, 0, maxW)\n };\n}\nfunction parseBorderRadius(bar, maxW, maxH) {\n const { enableBorderRadius } = bar.getProps([\n 'enableBorderRadius'\n ]);\n const value = bar.options.borderRadius;\n const o = toTRBLCorners(value);\n const maxR = Math.min(maxW, maxH);\n const skip = bar.borderSkipped;\n const enableBorder = enableBorderRadius || isObject(value);\n return {\n topLeft: skipOrLimit(!enableBorder || skip.top || skip.left, o.topLeft, 0, maxR),\n topRight: skipOrLimit(!enableBorder || skip.top || skip.right, o.topRight, 0, maxR),\n bottomLeft: skipOrLimit(!enableBorder || skip.bottom || skip.left, o.bottomLeft, 0, maxR),\n bottomRight: skipOrLimit(!enableBorder || skip.bottom || skip.right, o.bottomRight, 0, maxR)\n };\n}\nfunction boundingRects(bar) {\n const bounds = getBarBounds(bar);\n const width = bounds.right - bounds.left;\n const height = bounds.bottom - bounds.top;\n const border = parseBorderWidth(bar, width / 2, height / 2);\n const radius = parseBorderRadius(bar, width / 2, height / 2);\n return {\n outer: {\n x: bounds.left,\n y: bounds.top,\n w: width,\n h: height,\n radius\n },\n inner: {\n x: bounds.left + border.l,\n y: bounds.top + border.t,\n w: width - border.l - border.r,\n h: height - border.t - border.b,\n radius: {\n topLeft: Math.max(0, radius.topLeft - Math.max(border.t, border.l)),\n topRight: Math.max(0, radius.topRight - Math.max(border.t, border.r)),\n bottomLeft: Math.max(0, radius.bottomLeft - Math.max(border.b, border.l)),\n bottomRight: Math.max(0, radius.bottomRight - Math.max(border.b, border.r))\n }\n }\n };\n}\nfunction inRange(bar, x, y, useFinalPosition) {\n const skipX = x === null;\n const skipY = y === null;\n const skipBoth = skipX && skipY;\n const bounds = bar && !skipBoth && getBarBounds(bar, useFinalPosition);\n return bounds && (skipX || _isBetween(x, bounds.left, bounds.right)) && (skipY || _isBetween(y, bounds.top, bounds.bottom));\n}\nfunction hasRadius(radius) {\n return radius.topLeft || radius.topRight || radius.bottomLeft || radius.bottomRight;\n}\n function addNormalRectPath(ctx, rect) {\n ctx.rect(rect.x, rect.y, rect.w, rect.h);\n}\nfunction inflateRect(rect, amount, refRect = {}) {\n const x = rect.x !== refRect.x ? -amount : 0;\n const y = rect.y !== refRect.y ? -amount : 0;\n const w = (rect.x + rect.w !== refRect.x + refRect.w ? amount : 0) - x;\n const h = (rect.y + rect.h !== refRect.y + refRect.h ? amount : 0) - y;\n return {\n x: rect.x + x,\n y: rect.y + y,\n w: rect.w + w,\n h: rect.h + h,\n radius: rect.radius\n };\n}\nclass BarElement extends chart_Element {\n static id = 'bar';\n static defaults = {\n borderSkipped: 'start',\n borderWidth: 0,\n borderRadius: 0,\n inflateAmount: 'auto',\n pointStyle: undefined\n };\n static defaultRoutes = {\n backgroundColor: 'backgroundColor',\n borderColor: 'borderColor'\n };\n constructor(cfg){\n super();\n this.options = undefined;\n this.horizontal = undefined;\n this.base = undefined;\n this.width = undefined;\n this.height = undefined;\n this.inflateAmount = undefined;\n if (cfg) {\n Object.assign(this, cfg);\n }\n }\n draw(ctx) {\n const { inflateAmount , options: { borderColor , backgroundColor } } = this;\n const { inner , outer } = boundingRects(this);\n const addRectPath = hasRadius(outer.radius) ? addRoundedRectPath : addNormalRectPath;\n ctx.save();\n if (outer.w !== inner.w || outer.h !== inner.h) {\n ctx.beginPath();\n addRectPath(ctx, inflateRect(outer, inflateAmount, inner));\n ctx.clip();\n addRectPath(ctx, inflateRect(inner, -inflateAmount, outer));\n ctx.fillStyle = borderColor;\n ctx.fill('evenodd');\n }\n ctx.beginPath();\n addRectPath(ctx, inflateRect(inner, inflateAmount));\n ctx.fillStyle = backgroundColor;\n ctx.fill();\n ctx.restore();\n }\n inRange(mouseX, mouseY, useFinalPosition) {\n return inRange(this, mouseX, mouseY, useFinalPosition);\n }\n inXRange(mouseX, useFinalPosition) {\n return inRange(this, mouseX, null, useFinalPosition);\n }\n inYRange(mouseY, useFinalPosition) {\n return inRange(this, null, mouseY, useFinalPosition);\n }\n getCenterPoint(useFinalPosition) {\n const { x , y , base , horizontal } = this.getProps([\n 'x',\n 'y',\n 'base',\n 'horizontal'\n ], useFinalPosition);\n return {\n x: horizontal ? (x + base) / 2 : x,\n y: horizontal ? y : (y + base) / 2\n };\n }\n getRange(axis) {\n return axis === 'x' ? this.width / 2 : this.height / 2;\n }\n}\n\nvar chart_elements = /*#__PURE__*/Object.freeze({\n__proto__: null,\nArcElement: ArcElement,\nBarElement: BarElement,\nLineElement: LineElement,\nPointElement: PointElement\n});\n\nconst BORDER_COLORS = [\n 'rgb(54, 162, 235)',\n 'rgb(255, 99, 132)',\n 'rgb(255, 159, 64)',\n 'rgb(255, 205, 86)',\n 'rgb(75, 192, 192)',\n 'rgb(153, 102, 255)',\n 'rgb(201, 203, 207)' // grey\n];\n// Border colors with 50% transparency\nconst BACKGROUND_COLORS = /* #__PURE__ */ BORDER_COLORS.map((color)=>color.replace('rgb(', 'rgba(').replace(')', ', 0.5)'));\nfunction getBorderColor(i) {\n return BORDER_COLORS[i % BORDER_COLORS.length];\n}\nfunction getBackgroundColor(i) {\n return BACKGROUND_COLORS[i % BACKGROUND_COLORS.length];\n}\nfunction colorizeDefaultDataset(dataset, i) {\n dataset.borderColor = getBorderColor(i);\n dataset.backgroundColor = getBackgroundColor(i);\n return ++i;\n}\nfunction colorizeDoughnutDataset(dataset, i) {\n dataset.backgroundColor = dataset.data.map(()=>getBorderColor(i++));\n return i;\n}\nfunction colorizePolarAreaDataset(dataset, i) {\n dataset.backgroundColor = dataset.data.map(()=>getBackgroundColor(i++));\n return i;\n}\nfunction getColorizer(chart) {\n let i = 0;\n return (dataset, datasetIndex)=>{\n const controller = chart.getDatasetMeta(datasetIndex).controller;\n if (controller instanceof DoughnutController) {\n i = colorizeDoughnutDataset(dataset, i);\n } else if (controller instanceof PolarAreaController) {\n i = colorizePolarAreaDataset(dataset, i);\n } else if (controller) {\n i = colorizeDefaultDataset(dataset, i);\n }\n };\n}\nfunction containsColorsDefinitions(descriptors) {\n let k;\n for(k in descriptors){\n if (descriptors[k].borderColor || descriptors[k].backgroundColor) {\n return true;\n }\n }\n return false;\n}\nfunction containsColorsDefinition(descriptor) {\n return descriptor && (descriptor.borderColor || descriptor.backgroundColor);\n}\nvar plugin_colors = {\n id: 'colors',\n defaults: {\n enabled: true,\n forceOverride: false\n },\n beforeLayout (chart, _args, options) {\n if (!options.enabled) {\n return;\n }\n const { data: { datasets } , options: chartOptions } = chart.config;\n const { elements } = chartOptions;\n if (!options.forceOverride && (containsColorsDefinitions(datasets) || containsColorsDefinition(chartOptions) || elements && containsColorsDefinitions(elements))) {\n return;\n }\n const colorizer = getColorizer(chart);\n datasets.forEach(colorizer);\n }\n};\n\nfunction lttbDecimation(data, start, count, availableWidth, options) {\n const samples = options.samples || availableWidth;\n if (samples >= count) {\n return data.slice(start, start + count);\n }\n const decimated = [];\n const bucketWidth = (count - 2) / (samples - 2);\n let sampledIndex = 0;\n const endIndex = start + count - 1;\n let a = start;\n let i, maxAreaPoint, maxArea, area, nextA;\n decimated[sampledIndex++] = data[a];\n for(i = 0; i < samples - 2; i++){\n let avgX = 0;\n let avgY = 0;\n let j;\n const avgRangeStart = Math.floor((i + 1) * bucketWidth) + 1 + start;\n const avgRangeEnd = Math.min(Math.floor((i + 2) * bucketWidth) + 1, count) + start;\n const avgRangeLength = avgRangeEnd - avgRangeStart;\n for(j = avgRangeStart; j < avgRangeEnd; j++){\n avgX += data[j].x;\n avgY += data[j].y;\n }\n avgX /= avgRangeLength;\n avgY /= avgRangeLength;\n const rangeOffs = Math.floor(i * bucketWidth) + 1 + start;\n const rangeTo = Math.min(Math.floor((i + 1) * bucketWidth) + 1, count) + start;\n const { x: pointAx , y: pointAy } = data[a];\n maxArea = area = -1;\n for(j = rangeOffs; j < rangeTo; j++){\n area = 0.5 * Math.abs((pointAx - avgX) * (data[j].y - pointAy) - (pointAx - data[j].x) * (avgY - pointAy));\n if (area > maxArea) {\n maxArea = area;\n maxAreaPoint = data[j];\n nextA = j;\n }\n }\n decimated[sampledIndex++] = maxAreaPoint;\n a = nextA;\n }\n decimated[sampledIndex++] = data[endIndex];\n return decimated;\n}\nfunction minMaxDecimation(data, start, count, availableWidth) {\n let avgX = 0;\n let countX = 0;\n let i, point, x, y, prevX, minIndex, maxIndex, startIndex, minY, maxY;\n const decimated = [];\n const endIndex = start + count - 1;\n const xMin = data[start].x;\n const xMax = data[endIndex].x;\n const dx = xMax - xMin;\n for(i = start; i < start + count; ++i){\n point = data[i];\n x = (point.x - xMin) / dx * availableWidth;\n y = point.y;\n const truncX = x | 0;\n if (truncX === prevX) {\n if (y < minY) {\n minY = y;\n minIndex = i;\n } else if (y > maxY) {\n maxY = y;\n maxIndex = i;\n }\n avgX = (countX * avgX + point.x) / ++countX;\n } else {\n const lastIndex = i - 1;\n if (!isNullOrUndef(minIndex) && !isNullOrUndef(maxIndex)) {\n const intermediateIndex1 = Math.min(minIndex, maxIndex);\n const intermediateIndex2 = Math.max(minIndex, maxIndex);\n if (intermediateIndex1 !== startIndex && intermediateIndex1 !== lastIndex) {\n decimated.push({\n ...data[intermediateIndex1],\n x: avgX\n });\n }\n if (intermediateIndex2 !== startIndex && intermediateIndex2 !== lastIndex) {\n decimated.push({\n ...data[intermediateIndex2],\n x: avgX\n });\n }\n }\n if (i > 0 && lastIndex !== startIndex) {\n decimated.push(data[lastIndex]);\n }\n decimated.push(point);\n prevX = truncX;\n countX = 0;\n minY = maxY = y;\n minIndex = maxIndex = startIndex = i;\n }\n }\n return decimated;\n}\nfunction cleanDecimatedDataset(dataset) {\n if (dataset._decimated) {\n const data = dataset._data;\n delete dataset._decimated;\n delete dataset._data;\n Object.defineProperty(dataset, 'data', {\n configurable: true,\n enumerable: true,\n writable: true,\n value: data\n });\n }\n}\nfunction cleanDecimatedData(chart) {\n chart.data.datasets.forEach((dataset)=>{\n cleanDecimatedDataset(dataset);\n });\n}\nfunction getStartAndCountOfVisiblePointsSimplified(meta, points) {\n const pointCount = points.length;\n let start = 0;\n let count;\n const { iScale } = meta;\n const { min , max , minDefined , maxDefined } = iScale.getUserBounds();\n if (minDefined) {\n start = _limitValue(_lookupByKey(points, iScale.axis, min).lo, 0, pointCount - 1);\n }\n if (maxDefined) {\n count = _limitValue(_lookupByKey(points, iScale.axis, max).hi + 1, start, pointCount) - start;\n } else {\n count = pointCount - start;\n }\n return {\n start,\n count\n };\n}\nvar plugin_decimation = {\n id: 'decimation',\n defaults: {\n algorithm: 'min-max',\n enabled: false\n },\n beforeElementsUpdate: (chart, args, options)=>{\n if (!options.enabled) {\n cleanDecimatedData(chart);\n return;\n }\n const availableWidth = chart.width;\n chart.data.datasets.forEach((dataset, datasetIndex)=>{\n const { _data , indexAxis } = dataset;\n const meta = chart.getDatasetMeta(datasetIndex);\n const data = _data || dataset.data;\n if (resolve([\n indexAxis,\n chart.options.indexAxis\n ]) === 'y') {\n return;\n }\n if (!meta.controller.supportsDecimation) {\n return;\n }\n const xAxis = chart.scales[meta.xAxisID];\n if (xAxis.type !== 'linear' && xAxis.type !== 'time') {\n return;\n }\n if (chart.options.parsing) {\n return;\n }\n let { start , count } = getStartAndCountOfVisiblePointsSimplified(meta, data);\n const threshold = options.threshold || 4 * availableWidth;\n if (count <= threshold) {\n cleanDecimatedDataset(dataset);\n return;\n }\n if (isNullOrUndef(_data)) {\n dataset._data = data;\n delete dataset.data;\n Object.defineProperty(dataset, 'data', {\n configurable: true,\n enumerable: true,\n get: function() {\n return this._decimated;\n },\n set: function(d) {\n this._data = d;\n }\n });\n }\n let decimated;\n switch(options.algorithm){\n case 'lttb':\n decimated = lttbDecimation(data, start, count, availableWidth, options);\n break;\n case 'min-max':\n decimated = minMaxDecimation(data, start, count, availableWidth);\n break;\n default:\n throw new Error(`Unsupported decimation algorithm '${options.algorithm}'`);\n }\n dataset._decimated = decimated;\n });\n },\n destroy (chart) {\n cleanDecimatedData(chart);\n }\n};\n\nfunction _segments(line, target, property) {\n const segments = line.segments;\n const points = line.points;\n const tpoints = target.points;\n const parts = [];\n for (const segment of segments){\n let { start , end } = segment;\n end = _findSegmentEnd(start, end, points);\n const bounds = _getBounds(property, points[start], points[end], segment.loop);\n if (!target.segments) {\n parts.push({\n source: segment,\n target: bounds,\n start: points[start],\n end: points[end]\n });\n continue;\n }\n const targetSegments = _boundSegments(target, bounds);\n for (const tgt of targetSegments){\n const subBounds = _getBounds(property, tpoints[tgt.start], tpoints[tgt.end], tgt.loop);\n const fillSources = _boundSegment(segment, points, subBounds);\n for (const fillSource of fillSources){\n parts.push({\n source: fillSource,\n target: tgt,\n start: {\n [property]: _getEdge(bounds, subBounds, 'start', Math.max)\n },\n end: {\n [property]: _getEdge(bounds, subBounds, 'end', Math.min)\n }\n });\n }\n }\n }\n return parts;\n}\nfunction _getBounds(property, first, last, loop) {\n if (loop) {\n return;\n }\n let start = first[property];\n let end = last[property];\n if (property === 'angle') {\n start = _normalizeAngle(start);\n end = _normalizeAngle(end);\n }\n return {\n property,\n start,\n end\n };\n}\nfunction _pointsFromSegments(boundary, line) {\n const { x =null , y =null } = boundary || {};\n const linePoints = line.points;\n const points = [];\n line.segments.forEach(({ start , end })=>{\n end = _findSegmentEnd(start, end, linePoints);\n const first = linePoints[start];\n const last = linePoints[end];\n if (y !== null) {\n points.push({\n x: first.x,\n y\n });\n points.push({\n x: last.x,\n y\n });\n } else if (x !== null) {\n points.push({\n x,\n y: first.y\n });\n points.push({\n x,\n y: last.y\n });\n }\n });\n return points;\n}\nfunction _findSegmentEnd(start, end, points) {\n for(; end > start; end--){\n const point = points[end];\n if (!isNaN(point.x) && !isNaN(point.y)) {\n break;\n }\n }\n return end;\n}\nfunction _getEdge(a, b, prop, fn) {\n if (a && b) {\n return fn(a[prop], b[prop]);\n }\n return a ? a[prop] : b ? b[prop] : 0;\n}\n\nfunction _createBoundaryLine(boundary, line) {\n let points = [];\n let _loop = false;\n if (isArray(boundary)) {\n _loop = true;\n points = boundary;\n } else {\n points = _pointsFromSegments(boundary, line);\n }\n return points.length ? new LineElement({\n points,\n options: {\n tension: 0\n },\n _loop,\n _fullLoop: _loop\n }) : null;\n}\nfunction _shouldApplyFill(source) {\n return source && source.fill !== false;\n}\n\nfunction _resolveTarget(sources, index, propagate) {\n const source = sources[index];\n let fill = source.fill;\n const visited = [\n index\n ];\n let target;\n if (!propagate) {\n return fill;\n }\n while(fill !== false && visited.indexOf(fill) === -1){\n if (!isNumberFinite(fill)) {\n return fill;\n }\n target = sources[fill];\n if (!target) {\n return false;\n }\n if (target.visible) {\n return fill;\n }\n visited.push(fill);\n fill = target.fill;\n }\n return false;\n}\n function _decodeFill(line, index, count) {\n const fill = parseFillOption(line);\n if (isObject(fill)) {\n return isNaN(fill.value) ? false : fill;\n }\n let target = parseFloat(fill);\n if (isNumberFinite(target) && Math.floor(target) === target) {\n return decodeTargetIndex(fill[0], index, target, count);\n }\n return [\n 'origin',\n 'start',\n 'end',\n 'stack',\n 'shape'\n ].indexOf(fill) >= 0 && fill;\n}\nfunction decodeTargetIndex(firstCh, index, target, count) {\n if (firstCh === '-' || firstCh === '+') {\n target = index + target;\n }\n if (target === index || target < 0 || target >= count) {\n return false;\n }\n return target;\n}\n function _getTargetPixel(fill, scale) {\n let pixel = null;\n if (fill === 'start') {\n pixel = scale.bottom;\n } else if (fill === 'end') {\n pixel = scale.top;\n } else if (isObject(fill)) {\n pixel = scale.getPixelForValue(fill.value);\n } else if (scale.getBasePixel) {\n pixel = scale.getBasePixel();\n }\n return pixel;\n}\n function _getTargetValue(fill, scale, startValue) {\n let value;\n if (fill === 'start') {\n value = startValue;\n } else if (fill === 'end') {\n value = scale.options.reverse ? scale.min : scale.max;\n } else if (isObject(fill)) {\n value = fill.value;\n } else {\n value = scale.getBaseValue();\n }\n return value;\n}\n function parseFillOption(line) {\n const options = line.options;\n const fillOption = options.fill;\n let fill = valueOrDefault(fillOption && fillOption.target, fillOption);\n if (fill === undefined) {\n fill = !!options.backgroundColor;\n }\n if (fill === false || fill === null) {\n return false;\n }\n if (fill === true) {\n return 'origin';\n }\n return fill;\n}\n\nfunction _buildStackLine(source) {\n const { scale , index , line } = source;\n const points = [];\n const segments = line.segments;\n const sourcePoints = line.points;\n const linesBelow = getLinesBelow(scale, index);\n linesBelow.push(_createBoundaryLine({\n x: null,\n y: scale.bottom\n }, line));\n for(let i = 0; i < segments.length; i++){\n const segment = segments[i];\n for(let j = segment.start; j <= segment.end; j++){\n addPointsBelow(points, sourcePoints[j], linesBelow);\n }\n }\n return new LineElement({\n points,\n options: {}\n });\n}\n function getLinesBelow(scale, index) {\n const below = [];\n const metas = scale.getMatchingVisibleMetas('line');\n for(let i = 0; i < metas.length; i++){\n const meta = metas[i];\n if (meta.index === index) {\n break;\n }\n if (!meta.hidden) {\n below.unshift(meta.dataset);\n }\n }\n return below;\n}\n function addPointsBelow(points, sourcePoint, linesBelow) {\n const postponed = [];\n for(let j = 0; j < linesBelow.length; j++){\n const line = linesBelow[j];\n const { first , last , point } = findPoint(line, sourcePoint, 'x');\n if (!point || first && last) {\n continue;\n }\n if (first) {\n postponed.unshift(point);\n } else {\n points.push(point);\n if (!last) {\n break;\n }\n }\n }\n points.push(...postponed);\n}\n function findPoint(line, sourcePoint, property) {\n const point = line.interpolate(sourcePoint, property);\n if (!point) {\n return {};\n }\n const pointValue = point[property];\n const segments = line.segments;\n const linePoints = line.points;\n let first = false;\n let last = false;\n for(let i = 0; i < segments.length; i++){\n const segment = segments[i];\n const firstValue = linePoints[segment.start][property];\n const lastValue = linePoints[segment.end][property];\n if (_isBetween(pointValue, firstValue, lastValue)) {\n first = pointValue === firstValue;\n last = pointValue === lastValue;\n break;\n }\n }\n return {\n first,\n last,\n point\n };\n}\n\nclass simpleArc {\n constructor(opts){\n this.x = opts.x;\n this.y = opts.y;\n this.radius = opts.radius;\n }\n pathSegment(ctx, bounds, opts) {\n const { x , y , radius } = this;\n bounds = bounds || {\n start: 0,\n end: TAU\n };\n ctx.arc(x, y, radius, bounds.end, bounds.start, true);\n return !opts.bounds;\n }\n interpolate(point) {\n const { x , y , radius } = this;\n const angle = point.angle;\n return {\n x: x + Math.cos(angle) * radius,\n y: y + Math.sin(angle) * radius,\n angle\n };\n }\n}\n\nfunction _getTarget(source) {\n const { chart , fill , line } = source;\n if (isNumberFinite(fill)) {\n return getLineByIndex(chart, fill);\n }\n if (fill === 'stack') {\n return _buildStackLine(source);\n }\n if (fill === 'shape') {\n return true;\n }\n const boundary = computeBoundary(source);\n if (boundary instanceof simpleArc) {\n return boundary;\n }\n return _createBoundaryLine(boundary, line);\n}\n function getLineByIndex(chart, index) {\n const meta = chart.getDatasetMeta(index);\n const visible = meta && chart.isDatasetVisible(index);\n return visible ? meta.dataset : null;\n}\nfunction computeBoundary(source) {\n const scale = source.scale || {};\n if (scale.getPointPositionForValue) {\n return computeCircularBoundary(source);\n }\n return computeLinearBoundary(source);\n}\nfunction computeLinearBoundary(source) {\n const { scale ={} , fill } = source;\n const pixel = _getTargetPixel(fill, scale);\n if (isNumberFinite(pixel)) {\n const horizontal = scale.isHorizontal();\n return {\n x: horizontal ? pixel : null,\n y: horizontal ? null : pixel\n };\n }\n return null;\n}\nfunction computeCircularBoundary(source) {\n const { scale , fill } = source;\n const options = scale.options;\n const length = scale.getLabels().length;\n const start = options.reverse ? scale.max : scale.min;\n const value = _getTargetValue(fill, scale, start);\n const target = [];\n if (options.grid.circular) {\n const center = scale.getPointPositionForValue(0, start);\n return new simpleArc({\n x: center.x,\n y: center.y,\n radius: scale.getDistanceFromCenterForValue(value)\n });\n }\n for(let i = 0; i < length; ++i){\n target.push(scale.getPointPositionForValue(i, value));\n }\n return target;\n}\n\nfunction _drawfill(ctx, source, area) {\n const target = _getTarget(source);\n const { line , scale , axis } = source;\n const lineOpts = line.options;\n const fillOption = lineOpts.fill;\n const color = lineOpts.backgroundColor;\n const { above =color , below =color } = fillOption || {};\n if (target && line.points.length) {\n clipArea(ctx, area);\n doFill(ctx, {\n line,\n target,\n above,\n below,\n area,\n scale,\n axis\n });\n unclipArea(ctx);\n }\n}\nfunction doFill(ctx, cfg) {\n const { line , target , above , below , area , scale } = cfg;\n const property = line._loop ? 'angle' : cfg.axis;\n ctx.save();\n if (property === 'x' && below !== above) {\n clipVertical(ctx, target, area.top);\n fill(ctx, {\n line,\n target,\n color: above,\n scale,\n property\n });\n ctx.restore();\n ctx.save();\n clipVertical(ctx, target, area.bottom);\n }\n fill(ctx, {\n line,\n target,\n color: below,\n scale,\n property\n });\n ctx.restore();\n}\nfunction clipVertical(ctx, target, clipY) {\n const { segments , points } = target;\n let first = true;\n let lineLoop = false;\n ctx.beginPath();\n for (const segment of segments){\n const { start , end } = segment;\n const firstPoint = points[start];\n const lastPoint = points[_findSegmentEnd(start, end, points)];\n if (first) {\n ctx.moveTo(firstPoint.x, firstPoint.y);\n first = false;\n } else {\n ctx.lineTo(firstPoint.x, clipY);\n ctx.lineTo(firstPoint.x, firstPoint.y);\n }\n lineLoop = !!target.pathSegment(ctx, segment, {\n move: lineLoop\n });\n if (lineLoop) {\n ctx.closePath();\n } else {\n ctx.lineTo(lastPoint.x, clipY);\n }\n }\n ctx.lineTo(target.first().x, clipY);\n ctx.closePath();\n ctx.clip();\n}\nfunction fill(ctx, cfg) {\n const { line , target , property , color , scale } = cfg;\n const segments = _segments(line, target, property);\n for (const { source: src , target: tgt , start , end } of segments){\n const { style: { backgroundColor =color } = {} } = src;\n const notShape = target !== true;\n ctx.save();\n ctx.fillStyle = backgroundColor;\n clipBounds(ctx, scale, notShape && _getBounds(property, start, end));\n ctx.beginPath();\n const lineLoop = !!line.pathSegment(ctx, src);\n let loop;\n if (notShape) {\n if (lineLoop) {\n ctx.closePath();\n } else {\n interpolatedLineTo(ctx, target, end, property);\n }\n const targetLoop = !!target.pathSegment(ctx, tgt, {\n move: lineLoop,\n reverse: true\n });\n loop = lineLoop && targetLoop;\n if (!loop) {\n interpolatedLineTo(ctx, target, start, property);\n }\n }\n ctx.closePath();\n ctx.fill(loop ? 'evenodd' : 'nonzero');\n ctx.restore();\n }\n}\nfunction clipBounds(ctx, scale, bounds) {\n const { top , bottom } = scale.chart.chartArea;\n const { property , start , end } = bounds || {};\n if (property === 'x') {\n ctx.beginPath();\n ctx.rect(start, top, end - start, bottom - top);\n ctx.clip();\n }\n}\nfunction interpolatedLineTo(ctx, target, point, property) {\n const interpolatedPoint = target.interpolate(point, property);\n if (interpolatedPoint) {\n ctx.lineTo(interpolatedPoint.x, interpolatedPoint.y);\n }\n}\n\nvar index = {\n id: 'filler',\n afterDatasetsUpdate (chart, _args, options) {\n const count = (chart.data.datasets || []).length;\n const sources = [];\n let meta, i, line, source;\n for(i = 0; i < count; ++i){\n meta = chart.getDatasetMeta(i);\n line = meta.dataset;\n source = null;\n if (line && line.options && line instanceof LineElement) {\n source = {\n visible: chart.isDatasetVisible(i),\n index: i,\n fill: _decodeFill(line, i, count),\n chart,\n axis: meta.controller.options.indexAxis,\n scale: meta.vScale,\n line\n };\n }\n meta.$filler = source;\n sources.push(source);\n }\n for(i = 0; i < count; ++i){\n source = sources[i];\n if (!source || source.fill === false) {\n continue;\n }\n source.fill = _resolveTarget(sources, i, options.propagate);\n }\n },\n beforeDraw (chart, _args, options) {\n const draw = options.drawTime === 'beforeDraw';\n const metasets = chart.getSortedVisibleDatasetMetas();\n const area = chart.chartArea;\n for(let i = metasets.length - 1; i >= 0; --i){\n const source = metasets[i].$filler;\n if (!source) {\n continue;\n }\n source.line.updateControlPoints(area, source.axis);\n if (draw && source.fill) {\n _drawfill(chart.ctx, source, area);\n }\n }\n },\n beforeDatasetsDraw (chart, _args, options) {\n if (options.drawTime !== 'beforeDatasetsDraw') {\n return;\n }\n const metasets = chart.getSortedVisibleDatasetMetas();\n for(let i = metasets.length - 1; i >= 0; --i){\n const source = metasets[i].$filler;\n if (_shouldApplyFill(source)) {\n _drawfill(chart.ctx, source, chart.chartArea);\n }\n }\n },\n beforeDatasetDraw (chart, args, options) {\n const source = args.meta.$filler;\n if (!_shouldApplyFill(source) || options.drawTime !== 'beforeDatasetDraw') {\n return;\n }\n _drawfill(chart.ctx, source, chart.chartArea);\n },\n defaults: {\n propagate: true,\n drawTime: 'beforeDatasetDraw'\n }\n};\n\nconst getBoxSize = (labelOpts, fontSize)=>{\n let { boxHeight =fontSize , boxWidth =fontSize } = labelOpts;\n if (labelOpts.usePointStyle) {\n boxHeight = Math.min(boxHeight, fontSize);\n boxWidth = labelOpts.pointStyleWidth || Math.min(boxWidth, fontSize);\n }\n return {\n boxWidth,\n boxHeight,\n itemHeight: Math.max(fontSize, boxHeight)\n };\n};\nconst itemsEqual = (a, b)=>a !== null && b !== null && a.datasetIndex === b.datasetIndex && a.index === b.index;\nclass Legend extends chart_Element {\n constructor(config){\n super();\n this._added = false;\n this.legendHitBoxes = [];\n this._hoveredItem = null;\n this.doughnutMode = false;\n this.chart = config.chart;\n this.options = config.options;\n this.ctx = config.ctx;\n this.legendItems = undefined;\n this.columnSizes = undefined;\n this.lineWidths = undefined;\n this.maxHeight = undefined;\n this.maxWidth = undefined;\n this.top = undefined;\n this.bottom = undefined;\n this.left = undefined;\n this.right = undefined;\n this.height = undefined;\n this.width = undefined;\n this._margins = undefined;\n this.position = undefined;\n this.weight = undefined;\n this.fullSize = undefined;\n }\n update(maxWidth, maxHeight, margins) {\n this.maxWidth = maxWidth;\n this.maxHeight = maxHeight;\n this._margins = margins;\n this.setDimensions();\n this.buildLabels();\n this.fit();\n }\n setDimensions() {\n if (this.isHorizontal()) {\n this.width = this.maxWidth;\n this.left = this._margins.left;\n this.right = this.width;\n } else {\n this.height = this.maxHeight;\n this.top = this._margins.top;\n this.bottom = this.height;\n }\n }\n buildLabels() {\n const labelOpts = this.options.labels || {};\n let legendItems = callback(labelOpts.generateLabels, [\n this.chart\n ], this) || [];\n if (labelOpts.filter) {\n legendItems = legendItems.filter((item)=>labelOpts.filter(item, this.chart.data));\n }\n if (labelOpts.sort) {\n legendItems = legendItems.sort((a, b)=>labelOpts.sort(a, b, this.chart.data));\n }\n if (this.options.reverse) {\n legendItems.reverse();\n }\n this.legendItems = legendItems;\n }\n fit() {\n const { options , ctx } = this;\n if (!options.display) {\n this.width = this.height = 0;\n return;\n }\n const labelOpts = options.labels;\n const labelFont = toFont(labelOpts.font);\n const fontSize = labelFont.size;\n const titleHeight = this._computeTitleHeight();\n const { boxWidth , itemHeight } = getBoxSize(labelOpts, fontSize);\n let width, height;\n ctx.font = labelFont.string;\n if (this.isHorizontal()) {\n width = this.maxWidth;\n height = this._fitRows(titleHeight, fontSize, boxWidth, itemHeight) + 10;\n } else {\n height = this.maxHeight;\n width = this._fitCols(titleHeight, labelFont, boxWidth, itemHeight) + 10;\n }\n this.width = Math.min(width, options.maxWidth || this.maxWidth);\n this.height = Math.min(height, options.maxHeight || this.maxHeight);\n }\n _fitRows(titleHeight, fontSize, boxWidth, itemHeight) {\n const { ctx , maxWidth , options: { labels: { padding } } } = this;\n const hitboxes = this.legendHitBoxes = [];\n const lineWidths = this.lineWidths = [\n 0\n ];\n const lineHeight = itemHeight + padding;\n let totalHeight = titleHeight;\n ctx.textAlign = 'left';\n ctx.textBaseline = 'middle';\n let row = -1;\n let top = -lineHeight;\n this.legendItems.forEach((legendItem, i)=>{\n const itemWidth = boxWidth + fontSize / 2 + ctx.measureText(legendItem.text).width;\n if (i === 0 || lineWidths[lineWidths.length - 1] + itemWidth + 2 * padding > maxWidth) {\n totalHeight += lineHeight;\n lineWidths[lineWidths.length - (i > 0 ? 0 : 1)] = 0;\n top += lineHeight;\n row++;\n }\n hitboxes[i] = {\n left: 0,\n top,\n row,\n width: itemWidth,\n height: itemHeight\n };\n lineWidths[lineWidths.length - 1] += itemWidth + padding;\n });\n return totalHeight;\n }\n _fitCols(titleHeight, labelFont, boxWidth, _itemHeight) {\n const { ctx , maxHeight , options: { labels: { padding } } } = this;\n const hitboxes = this.legendHitBoxes = [];\n const columnSizes = this.columnSizes = [];\n const heightLimit = maxHeight - titleHeight;\n let totalWidth = padding;\n let currentColWidth = 0;\n let currentColHeight = 0;\n let left = 0;\n let col = 0;\n this.legendItems.forEach((legendItem, i)=>{\n const { itemWidth , itemHeight } = calculateItemSize(boxWidth, labelFont, ctx, legendItem, _itemHeight);\n if (i > 0 && currentColHeight + itemHeight + 2 * padding > heightLimit) {\n totalWidth += currentColWidth + padding;\n columnSizes.push({\n width: currentColWidth,\n height: currentColHeight\n });\n left += currentColWidth + padding;\n col++;\n currentColWidth = currentColHeight = 0;\n }\n hitboxes[i] = {\n left,\n top: currentColHeight,\n col,\n width: itemWidth,\n height: itemHeight\n };\n currentColWidth = Math.max(currentColWidth, itemWidth);\n currentColHeight += itemHeight + padding;\n });\n totalWidth += currentColWidth;\n columnSizes.push({\n width: currentColWidth,\n height: currentColHeight\n });\n return totalWidth;\n }\n adjustHitBoxes() {\n if (!this.options.display) {\n return;\n }\n const titleHeight = this._computeTitleHeight();\n const { legendHitBoxes: hitboxes , options: { align , labels: { padding } , rtl } } = this;\n const rtlHelper = getRtlAdapter(rtl, this.left, this.width);\n if (this.isHorizontal()) {\n let row = 0;\n let left = _alignStartEnd(align, this.left + padding, this.right - this.lineWidths[row]);\n for (const hitbox of hitboxes){\n if (row !== hitbox.row) {\n row = hitbox.row;\n left = _alignStartEnd(align, this.left + padding, this.right - this.lineWidths[row]);\n }\n hitbox.top += this.top + titleHeight + padding;\n hitbox.left = rtlHelper.leftForLtr(rtlHelper.x(left), hitbox.width);\n left += hitbox.width + padding;\n }\n } else {\n let col = 0;\n let top = _alignStartEnd(align, this.top + titleHeight + padding, this.bottom - this.columnSizes[col].height);\n for (const hitbox of hitboxes){\n if (hitbox.col !== col) {\n col = hitbox.col;\n top = _alignStartEnd(align, this.top + titleHeight + padding, this.bottom - this.columnSizes[col].height);\n }\n hitbox.top = top;\n hitbox.left += this.left + padding;\n hitbox.left = rtlHelper.leftForLtr(rtlHelper.x(hitbox.left), hitbox.width);\n top += hitbox.height + padding;\n }\n }\n }\n isHorizontal() {\n return this.options.position === 'top' || this.options.position === 'bottom';\n }\n draw() {\n if (this.options.display) {\n const ctx = this.ctx;\n clipArea(ctx, this);\n this._draw();\n unclipArea(ctx);\n }\n }\n _draw() {\n const { options: opts , columnSizes , lineWidths , ctx } = this;\n const { align , labels: labelOpts } = opts;\n const defaultColor = defaults.color;\n const rtlHelper = getRtlAdapter(opts.rtl, this.left, this.width);\n const labelFont = toFont(labelOpts.font);\n const { padding } = labelOpts;\n const fontSize = labelFont.size;\n const halfFontSize = fontSize / 2;\n let cursor;\n this.drawTitle();\n ctx.textAlign = rtlHelper.textAlign('left');\n ctx.textBaseline = 'middle';\n ctx.lineWidth = 0.5;\n ctx.font = labelFont.string;\n const { boxWidth , boxHeight , itemHeight } = getBoxSize(labelOpts, fontSize);\n const drawLegendBox = function(x, y, legendItem) {\n if (isNaN(boxWidth) || boxWidth <= 0 || isNaN(boxHeight) || boxHeight < 0) {\n return;\n }\n ctx.save();\n const lineWidth = valueOrDefault(legendItem.lineWidth, 1);\n ctx.fillStyle = valueOrDefault(legendItem.fillStyle, defaultColor);\n ctx.lineCap = valueOrDefault(legendItem.lineCap, 'butt');\n ctx.lineDashOffset = valueOrDefault(legendItem.lineDashOffset, 0);\n ctx.lineJoin = valueOrDefault(legendItem.lineJoin, 'miter');\n ctx.lineWidth = lineWidth;\n ctx.strokeStyle = valueOrDefault(legendItem.strokeStyle, defaultColor);\n ctx.setLineDash(valueOrDefault(legendItem.lineDash, []));\n if (labelOpts.usePointStyle) {\n const drawOptions = {\n radius: boxHeight * Math.SQRT2 / 2,\n pointStyle: legendItem.pointStyle,\n rotation: legendItem.rotation,\n borderWidth: lineWidth\n };\n const centerX = rtlHelper.xPlus(x, boxWidth / 2);\n const centerY = y + halfFontSize;\n drawPointLegend(ctx, drawOptions, centerX, centerY, labelOpts.pointStyleWidth && boxWidth);\n } else {\n const yBoxTop = y + Math.max((fontSize - boxHeight) / 2, 0);\n const xBoxLeft = rtlHelper.leftForLtr(x, boxWidth);\n const borderRadius = toTRBLCorners(legendItem.borderRadius);\n ctx.beginPath();\n if (Object.values(borderRadius).some((v)=>v !== 0)) {\n addRoundedRectPath(ctx, {\n x: xBoxLeft,\n y: yBoxTop,\n w: boxWidth,\n h: boxHeight,\n radius: borderRadius\n });\n } else {\n ctx.rect(xBoxLeft, yBoxTop, boxWidth, boxHeight);\n }\n ctx.fill();\n if (lineWidth !== 0) {\n ctx.stroke();\n }\n }\n ctx.restore();\n };\n const fillText = function(x, y, legendItem) {\n renderText(ctx, legendItem.text, x, y + itemHeight / 2, labelFont, {\n strikethrough: legendItem.hidden,\n textAlign: rtlHelper.textAlign(legendItem.textAlign)\n });\n };\n const isHorizontal = this.isHorizontal();\n const titleHeight = this._computeTitleHeight();\n if (isHorizontal) {\n cursor = {\n x: _alignStartEnd(align, this.left + padding, this.right - lineWidths[0]),\n y: this.top + padding + titleHeight,\n line: 0\n };\n } else {\n cursor = {\n x: this.left + padding,\n y: _alignStartEnd(align, this.top + titleHeight + padding, this.bottom - columnSizes[0].height),\n line: 0\n };\n }\n overrideTextDirection(this.ctx, opts.textDirection);\n const lineHeight = itemHeight + padding;\n this.legendItems.forEach((legendItem, i)=>{\n ctx.strokeStyle = legendItem.fontColor;\n ctx.fillStyle = legendItem.fontColor;\n const textWidth = ctx.measureText(legendItem.text).width;\n const textAlign = rtlHelper.textAlign(legendItem.textAlign || (legendItem.textAlign = labelOpts.textAlign));\n const width = boxWidth + halfFontSize + textWidth;\n let x = cursor.x;\n let y = cursor.y;\n rtlHelper.setWidth(this.width);\n if (isHorizontal) {\n if (i > 0 && x + width + padding > this.right) {\n y = cursor.y += lineHeight;\n cursor.line++;\n x = cursor.x = _alignStartEnd(align, this.left + padding, this.right - lineWidths[cursor.line]);\n }\n } else if (i > 0 && y + lineHeight > this.bottom) {\n x = cursor.x = x + columnSizes[cursor.line].width + padding;\n cursor.line++;\n y = cursor.y = _alignStartEnd(align, this.top + titleHeight + padding, this.bottom - columnSizes[cursor.line].height);\n }\n const realX = rtlHelper.x(x);\n drawLegendBox(realX, y, legendItem);\n x = _textX(textAlign, x + boxWidth + halfFontSize, isHorizontal ? x + width : this.right, opts.rtl);\n fillText(rtlHelper.x(x), y, legendItem);\n if (isHorizontal) {\n cursor.x += width + padding;\n } else if (typeof legendItem.text !== 'string') {\n const fontLineHeight = labelFont.lineHeight;\n cursor.y += calculateLegendItemHeight(legendItem, fontLineHeight) + padding;\n } else {\n cursor.y += lineHeight;\n }\n });\n restoreTextDirection(this.ctx, opts.textDirection);\n }\n drawTitle() {\n const opts = this.options;\n const titleOpts = opts.title;\n const titleFont = toFont(titleOpts.font);\n const titlePadding = toPadding(titleOpts.padding);\n if (!titleOpts.display) {\n return;\n }\n const rtlHelper = getRtlAdapter(opts.rtl, this.left, this.width);\n const ctx = this.ctx;\n const position = titleOpts.position;\n const halfFontSize = titleFont.size / 2;\n const topPaddingPlusHalfFontSize = titlePadding.top + halfFontSize;\n let y;\n let left = this.left;\n let maxWidth = this.width;\n if (this.isHorizontal()) {\n maxWidth = Math.max(...this.lineWidths);\n y = this.top + topPaddingPlusHalfFontSize;\n left = _alignStartEnd(opts.align, left, this.right - maxWidth);\n } else {\n const maxHeight = this.columnSizes.reduce((acc, size)=>Math.max(acc, size.height), 0);\n y = topPaddingPlusHalfFontSize + _alignStartEnd(opts.align, this.top, this.bottom - maxHeight - opts.labels.padding - this._computeTitleHeight());\n }\n const x = _alignStartEnd(position, left, left + maxWidth);\n ctx.textAlign = rtlHelper.textAlign(_toLeftRightCenter(position));\n ctx.textBaseline = 'middle';\n ctx.strokeStyle = titleOpts.color;\n ctx.fillStyle = titleOpts.color;\n ctx.font = titleFont.string;\n renderText(ctx, titleOpts.text, x, y, titleFont);\n }\n _computeTitleHeight() {\n const titleOpts = this.options.title;\n const titleFont = toFont(titleOpts.font);\n const titlePadding = toPadding(titleOpts.padding);\n return titleOpts.display ? titleFont.lineHeight + titlePadding.height : 0;\n }\n _getLegendItemAt(x, y) {\n let i, hitBox, lh;\n if (_isBetween(x, this.left, this.right) && _isBetween(y, this.top, this.bottom)) {\n lh = this.legendHitBoxes;\n for(i = 0; i < lh.length; ++i){\n hitBox = lh[i];\n if (_isBetween(x, hitBox.left, hitBox.left + hitBox.width) && _isBetween(y, hitBox.top, hitBox.top + hitBox.height)) {\n return this.legendItems[i];\n }\n }\n }\n return null;\n }\n handleEvent(e) {\n const opts = this.options;\n if (!isListened(e.type, opts)) {\n return;\n }\n const hoveredItem = this._getLegendItemAt(e.x, e.y);\n if (e.type === 'mousemove' || e.type === 'mouseout') {\n const previous = this._hoveredItem;\n const sameItem = itemsEqual(previous, hoveredItem);\n if (previous && !sameItem) {\n callback(opts.onLeave, [\n e,\n previous,\n this\n ], this);\n }\n this._hoveredItem = hoveredItem;\n if (hoveredItem && !sameItem) {\n callback(opts.onHover, [\n e,\n hoveredItem,\n this\n ], this);\n }\n } else if (hoveredItem) {\n callback(opts.onClick, [\n e,\n hoveredItem,\n this\n ], this);\n }\n }\n}\nfunction calculateItemSize(boxWidth, labelFont, ctx, legendItem, _itemHeight) {\n const itemWidth = calculateItemWidth(legendItem, boxWidth, labelFont, ctx);\n const itemHeight = calculateItemHeight(_itemHeight, legendItem, labelFont.lineHeight);\n return {\n itemWidth,\n itemHeight\n };\n}\nfunction calculateItemWidth(legendItem, boxWidth, labelFont, ctx) {\n let legendItemText = legendItem.text;\n if (legendItemText && typeof legendItemText !== 'string') {\n legendItemText = legendItemText.reduce((a, b)=>a.length > b.length ? a : b);\n }\n return boxWidth + labelFont.size / 2 + ctx.measureText(legendItemText).width;\n}\nfunction calculateItemHeight(_itemHeight, legendItem, fontLineHeight) {\n let itemHeight = _itemHeight;\n if (typeof legendItem.text !== 'string') {\n itemHeight = calculateLegendItemHeight(legendItem, fontLineHeight);\n }\n return itemHeight;\n}\nfunction calculateLegendItemHeight(legendItem, fontLineHeight) {\n const labelHeight = legendItem.text ? legendItem.text.length : 0;\n return fontLineHeight * labelHeight;\n}\nfunction isListened(type, opts) {\n if ((type === 'mousemove' || type === 'mouseout') && (opts.onHover || opts.onLeave)) {\n return true;\n }\n if (opts.onClick && (type === 'click' || type === 'mouseup')) {\n return true;\n }\n return false;\n}\nvar plugin_legend = {\n id: 'legend',\n _element: Legend,\n start (chart, _args, options) {\n const legend = chart.legend = new Legend({\n ctx: chart.ctx,\n options,\n chart\n });\n layouts.configure(chart, legend, options);\n layouts.addBox(chart, legend);\n },\n stop (chart) {\n layouts.removeBox(chart, chart.legend);\n delete chart.legend;\n },\n beforeUpdate (chart, _args, options) {\n const legend = chart.legend;\n layouts.configure(chart, legend, options);\n legend.options = options;\n },\n afterUpdate (chart) {\n const legend = chart.legend;\n legend.buildLabels();\n legend.adjustHitBoxes();\n },\n afterEvent (chart, args) {\n if (!args.replay) {\n chart.legend.handleEvent(args.event);\n }\n },\n defaults: {\n display: true,\n position: 'top',\n align: 'center',\n fullSize: true,\n reverse: false,\n weight: 1000,\n onClick (e, legendItem, legend) {\n const index = legendItem.datasetIndex;\n const ci = legend.chart;\n if (ci.isDatasetVisible(index)) {\n ci.hide(index);\n legendItem.hidden = true;\n } else {\n ci.show(index);\n legendItem.hidden = false;\n }\n },\n onHover: null,\n onLeave: null,\n labels: {\n color: (ctx)=>ctx.chart.options.color,\n boxWidth: 40,\n padding: 10,\n generateLabels (chart) {\n const datasets = chart.data.datasets;\n const { labels: { usePointStyle , pointStyle , textAlign , color , useBorderRadius , borderRadius } } = chart.legend.options;\n return chart._getSortedDatasetMetas().map((meta)=>{\n const style = meta.controller.getStyle(usePointStyle ? 0 : undefined);\n const borderWidth = toPadding(style.borderWidth);\n return {\n text: datasets[meta.index].label,\n fillStyle: style.backgroundColor,\n fontColor: color,\n hidden: !meta.visible,\n lineCap: style.borderCapStyle,\n lineDash: style.borderDash,\n lineDashOffset: style.borderDashOffset,\n lineJoin: style.borderJoinStyle,\n lineWidth: (borderWidth.width + borderWidth.height) / 4,\n strokeStyle: style.borderColor,\n pointStyle: pointStyle || style.pointStyle,\n rotation: style.rotation,\n textAlign: textAlign || style.textAlign,\n borderRadius: useBorderRadius && (borderRadius || style.borderRadius),\n datasetIndex: meta.index\n };\n }, this);\n }\n },\n title: {\n color: (ctx)=>ctx.chart.options.color,\n display: false,\n position: 'center',\n text: ''\n }\n },\n descriptors: {\n _scriptable: (name)=>!name.startsWith('on'),\n labels: {\n _scriptable: (name)=>![\n 'generateLabels',\n 'filter',\n 'sort'\n ].includes(name)\n }\n }\n};\n\nclass Title extends chart_Element {\n constructor(config){\n super();\n this.chart = config.chart;\n this.options = config.options;\n this.ctx = config.ctx;\n this._padding = undefined;\n this.top = undefined;\n this.bottom = undefined;\n this.left = undefined;\n this.right = undefined;\n this.width = undefined;\n this.height = undefined;\n this.position = undefined;\n this.weight = undefined;\n this.fullSize = undefined;\n }\n update(maxWidth, maxHeight) {\n const opts = this.options;\n this.left = 0;\n this.top = 0;\n if (!opts.display) {\n this.width = this.height = this.right = this.bottom = 0;\n return;\n }\n this.width = this.right = maxWidth;\n this.height = this.bottom = maxHeight;\n const lineCount = isArray(opts.text) ? opts.text.length : 1;\n this._padding = toPadding(opts.padding);\n const textSize = lineCount * toFont(opts.font).lineHeight + this._padding.height;\n if (this.isHorizontal()) {\n this.height = textSize;\n } else {\n this.width = textSize;\n }\n }\n isHorizontal() {\n const pos = this.options.position;\n return pos === 'top' || pos === 'bottom';\n }\n _drawArgs(offset) {\n const { top , left , bottom , right , options } = this;\n const align = options.align;\n let rotation = 0;\n let maxWidth, titleX, titleY;\n if (this.isHorizontal()) {\n titleX = _alignStartEnd(align, left, right);\n titleY = top + offset;\n maxWidth = right - left;\n } else {\n if (options.position === 'left') {\n titleX = left + offset;\n titleY = _alignStartEnd(align, bottom, top);\n rotation = PI * -0.5;\n } else {\n titleX = right - offset;\n titleY = _alignStartEnd(align, top, bottom);\n rotation = PI * 0.5;\n }\n maxWidth = bottom - top;\n }\n return {\n titleX,\n titleY,\n maxWidth,\n rotation\n };\n }\n draw() {\n const ctx = this.ctx;\n const opts = this.options;\n if (!opts.display) {\n return;\n }\n const fontOpts = toFont(opts.font);\n const lineHeight = fontOpts.lineHeight;\n const offset = lineHeight / 2 + this._padding.top;\n const { titleX , titleY , maxWidth , rotation } = this._drawArgs(offset);\n renderText(ctx, opts.text, 0, 0, fontOpts, {\n color: opts.color,\n maxWidth,\n rotation,\n textAlign: _toLeftRightCenter(opts.align),\n textBaseline: 'middle',\n translation: [\n titleX,\n titleY\n ]\n });\n }\n}\nfunction createTitle(chart, titleOpts) {\n const title = new Title({\n ctx: chart.ctx,\n options: titleOpts,\n chart\n });\n layouts.configure(chart, title, titleOpts);\n layouts.addBox(chart, title);\n chart.titleBlock = title;\n}\nvar plugin_title = {\n id: 'title',\n _element: Title,\n start (chart, _args, options) {\n createTitle(chart, options);\n },\n stop (chart) {\n const titleBlock = chart.titleBlock;\n layouts.removeBox(chart, titleBlock);\n delete chart.titleBlock;\n },\n beforeUpdate (chart, _args, options) {\n const title = chart.titleBlock;\n layouts.configure(chart, title, options);\n title.options = options;\n },\n defaults: {\n align: 'center',\n display: false,\n font: {\n weight: 'bold'\n },\n fullSize: true,\n padding: 10,\n position: 'top',\n text: '',\n weight: 2000\n },\n defaultRoutes: {\n color: 'color'\n },\n descriptors: {\n _scriptable: true,\n _indexable: false\n }\n};\n\nconst chart_map = new WeakMap();\nvar plugin_subtitle = {\n id: 'subtitle',\n start (chart, _args, options) {\n const title = new Title({\n ctx: chart.ctx,\n options,\n chart\n });\n layouts.configure(chart, title, options);\n layouts.addBox(chart, title);\n chart_map.set(chart, title);\n },\n stop (chart) {\n layouts.removeBox(chart, chart_map.get(chart));\n chart_map.delete(chart);\n },\n beforeUpdate (chart, _args, options) {\n const title = chart_map.get(chart);\n layouts.configure(chart, title, options);\n title.options = options;\n },\n defaults: {\n align: 'center',\n display: false,\n font: {\n weight: 'normal'\n },\n fullSize: true,\n padding: 0,\n position: 'top',\n text: '',\n weight: 1500\n },\n defaultRoutes: {\n color: 'color'\n },\n descriptors: {\n _scriptable: true,\n _indexable: false\n }\n};\n\nconst positioners = {\n average (items) {\n if (!items.length) {\n return false;\n }\n let i, len;\n let xSet = new Set();\n let y = 0;\n let count = 0;\n for(i = 0, len = items.length; i < len; ++i){\n const el = items[i].element;\n if (el && el.hasValue()) {\n const pos = el.tooltipPosition();\n xSet.add(pos.x);\n y += pos.y;\n ++count;\n }\n }\n if (count === 0 || xSet.size === 0) {\n return false;\n }\n const xAverage = [\n ...xSet\n ].reduce((a, b)=>a + b) / xSet.size;\n return {\n x: xAverage,\n y: y / count\n };\n },\n nearest (items, eventPosition) {\n if (!items.length) {\n return false;\n }\n let x = eventPosition.x;\n let y = eventPosition.y;\n let minDistance = Number.POSITIVE_INFINITY;\n let i, len, nearestElement;\n for(i = 0, len = items.length; i < len; ++i){\n const el = items[i].element;\n if (el && el.hasValue()) {\n const center = el.getCenterPoint();\n const d = distanceBetweenPoints(eventPosition, center);\n if (d < minDistance) {\n minDistance = d;\n nearestElement = el;\n }\n }\n }\n if (nearestElement) {\n const tp = nearestElement.tooltipPosition();\n x = tp.x;\n y = tp.y;\n }\n return {\n x,\n y\n };\n }\n};\nfunction pushOrConcat(base, toPush) {\n if (toPush) {\n if (isArray(toPush)) {\n Array.prototype.push.apply(base, toPush);\n } else {\n base.push(toPush);\n }\n }\n return base;\n}\n function splitNewlines(str) {\n if ((typeof str === 'string' || str instanceof String) && str.indexOf('\\n') > -1) {\n return str.split('\\n');\n }\n return str;\n}\n function createTooltipItem(chart, item) {\n const { element , datasetIndex , index } = item;\n const controller = chart.getDatasetMeta(datasetIndex).controller;\n const { label , value } = controller.getLabelAndValue(index);\n return {\n chart,\n label,\n parsed: controller.getParsed(index),\n raw: chart.data.datasets[datasetIndex].data[index],\n formattedValue: value,\n dataset: controller.getDataset(),\n dataIndex: index,\n datasetIndex,\n element\n };\n}\n function getTooltipSize(tooltip, options) {\n const ctx = tooltip.chart.ctx;\n const { body , footer , title } = tooltip;\n const { boxWidth , boxHeight } = options;\n const bodyFont = toFont(options.bodyFont);\n const titleFont = toFont(options.titleFont);\n const footerFont = toFont(options.footerFont);\n const titleLineCount = title.length;\n const footerLineCount = footer.length;\n const bodyLineItemCount = body.length;\n const padding = toPadding(options.padding);\n let height = padding.height;\n let width = 0;\n let combinedBodyLength = body.reduce((count, bodyItem)=>count + bodyItem.before.length + bodyItem.lines.length + bodyItem.after.length, 0);\n combinedBodyLength += tooltip.beforeBody.length + tooltip.afterBody.length;\n if (titleLineCount) {\n height += titleLineCount * titleFont.lineHeight + (titleLineCount - 1) * options.titleSpacing + options.titleMarginBottom;\n }\n if (combinedBodyLength) {\n const bodyLineHeight = options.displayColors ? Math.max(boxHeight, bodyFont.lineHeight) : bodyFont.lineHeight;\n height += bodyLineItemCount * bodyLineHeight + (combinedBodyLength - bodyLineItemCount) * bodyFont.lineHeight + (combinedBodyLength - 1) * options.bodySpacing;\n }\n if (footerLineCount) {\n height += options.footerMarginTop + footerLineCount * footerFont.lineHeight + (footerLineCount - 1) * options.footerSpacing;\n }\n let widthPadding = 0;\n const maxLineWidth = function(line) {\n width = Math.max(width, ctx.measureText(line).width + widthPadding);\n };\n ctx.save();\n ctx.font = titleFont.string;\n each(tooltip.title, maxLineWidth);\n ctx.font = bodyFont.string;\n each(tooltip.beforeBody.concat(tooltip.afterBody), maxLineWidth);\n widthPadding = options.displayColors ? boxWidth + 2 + options.boxPadding : 0;\n each(body, (bodyItem)=>{\n each(bodyItem.before, maxLineWidth);\n each(bodyItem.lines, maxLineWidth);\n each(bodyItem.after, maxLineWidth);\n });\n widthPadding = 0;\n ctx.font = footerFont.string;\n each(tooltip.footer, maxLineWidth);\n ctx.restore();\n width += padding.width;\n return {\n width,\n height\n };\n}\nfunction determineYAlign(chart, size) {\n const { y , height } = size;\n if (y < height / 2) {\n return 'top';\n } else if (y > chart.height - height / 2) {\n return 'bottom';\n }\n return 'center';\n}\nfunction doesNotFitWithAlign(xAlign, chart, options, size) {\n const { x , width } = size;\n const caret = options.caretSize + options.caretPadding;\n if (xAlign === 'left' && x + width + caret > chart.width) {\n return true;\n }\n if (xAlign === 'right' && x - width - caret < 0) {\n return true;\n }\n}\nfunction determineXAlign(chart, options, size, yAlign) {\n const { x , width } = size;\n const { width: chartWidth , chartArea: { left , right } } = chart;\n let xAlign = 'center';\n if (yAlign === 'center') {\n xAlign = x <= (left + right) / 2 ? 'left' : 'right';\n } else if (x <= width / 2) {\n xAlign = 'left';\n } else if (x >= chartWidth - width / 2) {\n xAlign = 'right';\n }\n if (doesNotFitWithAlign(xAlign, chart, options, size)) {\n xAlign = 'center';\n }\n return xAlign;\n}\n function determineAlignment(chart, options, size) {\n const yAlign = size.yAlign || options.yAlign || determineYAlign(chart, size);\n return {\n xAlign: size.xAlign || options.xAlign || determineXAlign(chart, options, size, yAlign),\n yAlign\n };\n}\nfunction alignX(size, xAlign) {\n let { x , width } = size;\n if (xAlign === 'right') {\n x -= width;\n } else if (xAlign === 'center') {\n x -= width / 2;\n }\n return x;\n}\nfunction alignY(size, yAlign, paddingAndSize) {\n let { y , height } = size;\n if (yAlign === 'top') {\n y += paddingAndSize;\n } else if (yAlign === 'bottom') {\n y -= height + paddingAndSize;\n } else {\n y -= height / 2;\n }\n return y;\n}\n function getBackgroundPoint(options, size, alignment, chart) {\n const { caretSize , caretPadding , cornerRadius } = options;\n const { xAlign , yAlign } = alignment;\n const paddingAndSize = caretSize + caretPadding;\n const { topLeft , topRight , bottomLeft , bottomRight } = toTRBLCorners(cornerRadius);\n let x = alignX(size, xAlign);\n const y = alignY(size, yAlign, paddingAndSize);\n if (yAlign === 'center') {\n if (xAlign === 'left') {\n x += paddingAndSize;\n } else if (xAlign === 'right') {\n x -= paddingAndSize;\n }\n } else if (xAlign === 'left') {\n x -= Math.max(topLeft, bottomLeft) + caretSize;\n } else if (xAlign === 'right') {\n x += Math.max(topRight, bottomRight) + caretSize;\n }\n return {\n x: _limitValue(x, 0, chart.width - size.width),\n y: _limitValue(y, 0, chart.height - size.height)\n };\n}\nfunction getAlignedX(tooltip, align, options) {\n const padding = toPadding(options.padding);\n return align === 'center' ? tooltip.x + tooltip.width / 2 : align === 'right' ? tooltip.x + tooltip.width - padding.right : tooltip.x + padding.left;\n}\n function getBeforeAfterBodyLines(callback) {\n return pushOrConcat([], splitNewlines(callback));\n}\nfunction createTooltipContext(parent, tooltip, tooltipItems) {\n return createContext(parent, {\n tooltip,\n tooltipItems,\n type: 'tooltip'\n });\n}\nfunction overrideCallbacks(callbacks, context) {\n const override = context && context.dataset && context.dataset.tooltip && context.dataset.tooltip.callbacks;\n return override ? callbacks.override(override) : callbacks;\n}\nconst defaultCallbacks = {\n beforeTitle: noop,\n title (tooltipItems) {\n if (tooltipItems.length > 0) {\n const item = tooltipItems[0];\n const labels = item.chart.data.labels;\n const labelCount = labels ? labels.length : 0;\n if (this && this.options && this.options.mode === 'dataset') {\n return item.dataset.label || '';\n } else if (item.label) {\n return item.label;\n } else if (labelCount > 0 && item.dataIndex < labelCount) {\n return labels[item.dataIndex];\n }\n }\n return '';\n },\n afterTitle: noop,\n beforeBody: noop,\n beforeLabel: noop,\n label (tooltipItem) {\n if (this && this.options && this.options.mode === 'dataset') {\n return tooltipItem.label + ': ' + tooltipItem.formattedValue || tooltipItem.formattedValue;\n }\n let label = tooltipItem.dataset.label || '';\n if (label) {\n label += ': ';\n }\n const value = tooltipItem.formattedValue;\n if (!isNullOrUndef(value)) {\n label += value;\n }\n return label;\n },\n labelColor (tooltipItem) {\n const meta = tooltipItem.chart.getDatasetMeta(tooltipItem.datasetIndex);\n const options = meta.controller.getStyle(tooltipItem.dataIndex);\n return {\n borderColor: options.borderColor,\n backgroundColor: options.backgroundColor,\n borderWidth: options.borderWidth,\n borderDash: options.borderDash,\n borderDashOffset: options.borderDashOffset,\n borderRadius: 0\n };\n },\n labelTextColor () {\n return this.options.bodyColor;\n },\n labelPointStyle (tooltipItem) {\n const meta = tooltipItem.chart.getDatasetMeta(tooltipItem.datasetIndex);\n const options = meta.controller.getStyle(tooltipItem.dataIndex);\n return {\n pointStyle: options.pointStyle,\n rotation: options.rotation\n };\n },\n afterLabel: noop,\n afterBody: noop,\n beforeFooter: noop,\n footer: noop,\n afterFooter: noop\n};\n function invokeCallbackWithFallback(callbacks, name, ctx, arg) {\n const result = callbacks[name].call(ctx, arg);\n if (typeof result === 'undefined') {\n return defaultCallbacks[name].call(ctx, arg);\n }\n return result;\n}\nclass Tooltip extends chart_Element {\n static positioners = positioners;\n constructor(config){\n super();\n this.opacity = 0;\n this._active = [];\n this._eventPosition = undefined;\n this._size = undefined;\n this._cachedAnimations = undefined;\n this._tooltipItems = [];\n this.$animations = undefined;\n this.$context = undefined;\n this.chart = config.chart;\n this.options = config.options;\n this.dataPoints = undefined;\n this.title = undefined;\n this.beforeBody = undefined;\n this.body = undefined;\n this.afterBody = undefined;\n this.footer = undefined;\n this.xAlign = undefined;\n this.yAlign = undefined;\n this.x = undefined;\n this.y = undefined;\n this.height = undefined;\n this.width = undefined;\n this.caretX = undefined;\n this.caretY = undefined;\n this.labelColors = undefined;\n this.labelPointStyles = undefined;\n this.labelTextColors = undefined;\n }\n initialize(options) {\n this.options = options;\n this._cachedAnimations = undefined;\n this.$context = undefined;\n }\n _resolveAnimations() {\n const cached = this._cachedAnimations;\n if (cached) {\n return cached;\n }\n const chart = this.chart;\n const options = this.options.setContext(this.getContext());\n const opts = options.enabled && chart.options.animation && options.animations;\n const animations = new Animations(this.chart, opts);\n if (opts._cacheable) {\n this._cachedAnimations = Object.freeze(animations);\n }\n return animations;\n }\n getContext() {\n return this.$context || (this.$context = createTooltipContext(this.chart.getContext(), this, this._tooltipItems));\n }\n getTitle(context, options) {\n const { callbacks } = options;\n const beforeTitle = invokeCallbackWithFallback(callbacks, 'beforeTitle', this, context);\n const title = invokeCallbackWithFallback(callbacks, 'title', this, context);\n const afterTitle = invokeCallbackWithFallback(callbacks, 'afterTitle', this, context);\n let lines = [];\n lines = pushOrConcat(lines, splitNewlines(beforeTitle));\n lines = pushOrConcat(lines, splitNewlines(title));\n lines = pushOrConcat(lines, splitNewlines(afterTitle));\n return lines;\n }\n getBeforeBody(tooltipItems, options) {\n return getBeforeAfterBodyLines(invokeCallbackWithFallback(options.callbacks, 'beforeBody', this, tooltipItems));\n }\n getBody(tooltipItems, options) {\n const { callbacks } = options;\n const bodyItems = [];\n each(tooltipItems, (context)=>{\n const bodyItem = {\n before: [],\n lines: [],\n after: []\n };\n const scoped = overrideCallbacks(callbacks, context);\n pushOrConcat(bodyItem.before, splitNewlines(invokeCallbackWithFallback(scoped, 'beforeLabel', this, context)));\n pushOrConcat(bodyItem.lines, invokeCallbackWithFallback(scoped, 'label', this, context));\n pushOrConcat(bodyItem.after, splitNewlines(invokeCallbackWithFallback(scoped, 'afterLabel', this, context)));\n bodyItems.push(bodyItem);\n });\n return bodyItems;\n }\n getAfterBody(tooltipItems, options) {\n return getBeforeAfterBodyLines(invokeCallbackWithFallback(options.callbacks, 'afterBody', this, tooltipItems));\n }\n getFooter(tooltipItems, options) {\n const { callbacks } = options;\n const beforeFooter = invokeCallbackWithFallback(callbacks, 'beforeFooter', this, tooltipItems);\n const footer = invokeCallbackWithFallback(callbacks, 'footer', this, tooltipItems);\n const afterFooter = invokeCallbackWithFallback(callbacks, 'afterFooter', this, tooltipItems);\n let lines = [];\n lines = pushOrConcat(lines, splitNewlines(beforeFooter));\n lines = pushOrConcat(lines, splitNewlines(footer));\n lines = pushOrConcat(lines, splitNewlines(afterFooter));\n return lines;\n }\n _createItems(options) {\n const active = this._active;\n const data = this.chart.data;\n const labelColors = [];\n const labelPointStyles = [];\n const labelTextColors = [];\n let tooltipItems = [];\n let i, len;\n for(i = 0, len = active.length; i < len; ++i){\n tooltipItems.push(createTooltipItem(this.chart, active[i]));\n }\n if (options.filter) {\n tooltipItems = tooltipItems.filter((element, index, array)=>options.filter(element, index, array, data));\n }\n if (options.itemSort) {\n tooltipItems = tooltipItems.sort((a, b)=>options.itemSort(a, b, data));\n }\n each(tooltipItems, (context)=>{\n const scoped = overrideCallbacks(options.callbacks, context);\n labelColors.push(invokeCallbackWithFallback(scoped, 'labelColor', this, context));\n labelPointStyles.push(invokeCallbackWithFallback(scoped, 'labelPointStyle', this, context));\n labelTextColors.push(invokeCallbackWithFallback(scoped, 'labelTextColor', this, context));\n });\n this.labelColors = labelColors;\n this.labelPointStyles = labelPointStyles;\n this.labelTextColors = labelTextColors;\n this.dataPoints = tooltipItems;\n return tooltipItems;\n }\n update(changed, replay) {\n const options = this.options.setContext(this.getContext());\n const active = this._active;\n let properties;\n let tooltipItems = [];\n if (!active.length) {\n if (this.opacity !== 0) {\n properties = {\n opacity: 0\n };\n }\n } else {\n const position = positioners[options.position].call(this, active, this._eventPosition);\n tooltipItems = this._createItems(options);\n this.title = this.getTitle(tooltipItems, options);\n this.beforeBody = this.getBeforeBody(tooltipItems, options);\n this.body = this.getBody(tooltipItems, options);\n this.afterBody = this.getAfterBody(tooltipItems, options);\n this.footer = this.getFooter(tooltipItems, options);\n const size = this._size = getTooltipSize(this, options);\n const positionAndSize = Object.assign({}, position, size);\n const alignment = determineAlignment(this.chart, options, positionAndSize);\n const backgroundPoint = getBackgroundPoint(options, positionAndSize, alignment, this.chart);\n this.xAlign = alignment.xAlign;\n this.yAlign = alignment.yAlign;\n properties = {\n opacity: 1,\n x: backgroundPoint.x,\n y: backgroundPoint.y,\n width: size.width,\n height: size.height,\n caretX: position.x,\n caretY: position.y\n };\n }\n this._tooltipItems = tooltipItems;\n this.$context = undefined;\n if (properties) {\n this._resolveAnimations().update(this, properties);\n }\n if (changed && options.external) {\n options.external.call(this, {\n chart: this.chart,\n tooltip: this,\n replay\n });\n }\n }\n drawCaret(tooltipPoint, ctx, size, options) {\n const caretPosition = this.getCaretPosition(tooltipPoint, size, options);\n ctx.lineTo(caretPosition.x1, caretPosition.y1);\n ctx.lineTo(caretPosition.x2, caretPosition.y2);\n ctx.lineTo(caretPosition.x3, caretPosition.y3);\n }\n getCaretPosition(tooltipPoint, size, options) {\n const { xAlign , yAlign } = this;\n const { caretSize , cornerRadius } = options;\n const { topLeft , topRight , bottomLeft , bottomRight } = toTRBLCorners(cornerRadius);\n const { x: ptX , y: ptY } = tooltipPoint;\n const { width , height } = size;\n let x1, x2, x3, y1, y2, y3;\n if (yAlign === 'center') {\n y2 = ptY + height / 2;\n if (xAlign === 'left') {\n x1 = ptX;\n x2 = x1 - caretSize;\n y1 = y2 + caretSize;\n y3 = y2 - caretSize;\n } else {\n x1 = ptX + width;\n x2 = x1 + caretSize;\n y1 = y2 - caretSize;\n y3 = y2 + caretSize;\n }\n x3 = x1;\n } else {\n if (xAlign === 'left') {\n x2 = ptX + Math.max(topLeft, bottomLeft) + caretSize;\n } else if (xAlign === 'right') {\n x2 = ptX + width - Math.max(topRight, bottomRight) - caretSize;\n } else {\n x2 = this.caretX;\n }\n if (yAlign === 'top') {\n y1 = ptY;\n y2 = y1 - caretSize;\n x1 = x2 - caretSize;\n x3 = x2 + caretSize;\n } else {\n y1 = ptY + height;\n y2 = y1 + caretSize;\n x1 = x2 + caretSize;\n x3 = x2 - caretSize;\n }\n y3 = y1;\n }\n return {\n x1,\n x2,\n x3,\n y1,\n y2,\n y3\n };\n }\n drawTitle(pt, ctx, options) {\n const title = this.title;\n const length = title.length;\n let titleFont, titleSpacing, i;\n if (length) {\n const rtlHelper = getRtlAdapter(options.rtl, this.x, this.width);\n pt.x = getAlignedX(this, options.titleAlign, options);\n ctx.textAlign = rtlHelper.textAlign(options.titleAlign);\n ctx.textBaseline = 'middle';\n titleFont = toFont(options.titleFont);\n titleSpacing = options.titleSpacing;\n ctx.fillStyle = options.titleColor;\n ctx.font = titleFont.string;\n for(i = 0; i < length; ++i){\n ctx.fillText(title[i], rtlHelper.x(pt.x), pt.y + titleFont.lineHeight / 2);\n pt.y += titleFont.lineHeight + titleSpacing;\n if (i + 1 === length) {\n pt.y += options.titleMarginBottom - titleSpacing;\n }\n }\n }\n }\n _drawColorBox(ctx, pt, i, rtlHelper, options) {\n const labelColor = this.labelColors[i];\n const labelPointStyle = this.labelPointStyles[i];\n const { boxHeight , boxWidth } = options;\n const bodyFont = toFont(options.bodyFont);\n const colorX = getAlignedX(this, 'left', options);\n const rtlColorX = rtlHelper.x(colorX);\n const yOffSet = boxHeight < bodyFont.lineHeight ? (bodyFont.lineHeight - boxHeight) / 2 : 0;\n const colorY = pt.y + yOffSet;\n if (options.usePointStyle) {\n const drawOptions = {\n radius: Math.min(boxWidth, boxHeight) / 2,\n pointStyle: labelPointStyle.pointStyle,\n rotation: labelPointStyle.rotation,\n borderWidth: 1\n };\n const centerX = rtlHelper.leftForLtr(rtlColorX, boxWidth) + boxWidth / 2;\n const centerY = colorY + boxHeight / 2;\n ctx.strokeStyle = options.multiKeyBackground;\n ctx.fillStyle = options.multiKeyBackground;\n drawPoint(ctx, drawOptions, centerX, centerY);\n ctx.strokeStyle = labelColor.borderColor;\n ctx.fillStyle = labelColor.backgroundColor;\n drawPoint(ctx, drawOptions, centerX, centerY);\n } else {\n ctx.lineWidth = isObject(labelColor.borderWidth) ? Math.max(...Object.values(labelColor.borderWidth)) : labelColor.borderWidth || 1;\n ctx.strokeStyle = labelColor.borderColor;\n ctx.setLineDash(labelColor.borderDash || []);\n ctx.lineDashOffset = labelColor.borderDashOffset || 0;\n const outerX = rtlHelper.leftForLtr(rtlColorX, boxWidth);\n const innerX = rtlHelper.leftForLtr(rtlHelper.xPlus(rtlColorX, 1), boxWidth - 2);\n const borderRadius = toTRBLCorners(labelColor.borderRadius);\n if (Object.values(borderRadius).some((v)=>v !== 0)) {\n ctx.beginPath();\n ctx.fillStyle = options.multiKeyBackground;\n addRoundedRectPath(ctx, {\n x: outerX,\n y: colorY,\n w: boxWidth,\n h: boxHeight,\n radius: borderRadius\n });\n ctx.fill();\n ctx.stroke();\n ctx.fillStyle = labelColor.backgroundColor;\n ctx.beginPath();\n addRoundedRectPath(ctx, {\n x: innerX,\n y: colorY + 1,\n w: boxWidth - 2,\n h: boxHeight - 2,\n radius: borderRadius\n });\n ctx.fill();\n } else {\n ctx.fillStyle = options.multiKeyBackground;\n ctx.fillRect(outerX, colorY, boxWidth, boxHeight);\n ctx.strokeRect(outerX, colorY, boxWidth, boxHeight);\n ctx.fillStyle = labelColor.backgroundColor;\n ctx.fillRect(innerX, colorY + 1, boxWidth - 2, boxHeight - 2);\n }\n }\n ctx.fillStyle = this.labelTextColors[i];\n }\n drawBody(pt, ctx, options) {\n const { body } = this;\n const { bodySpacing , bodyAlign , displayColors , boxHeight , boxWidth , boxPadding } = options;\n const bodyFont = toFont(options.bodyFont);\n let bodyLineHeight = bodyFont.lineHeight;\n let xLinePadding = 0;\n const rtlHelper = getRtlAdapter(options.rtl, this.x, this.width);\n const fillLineOfText = function(line) {\n ctx.fillText(line, rtlHelper.x(pt.x + xLinePadding), pt.y + bodyLineHeight / 2);\n pt.y += bodyLineHeight + bodySpacing;\n };\n const bodyAlignForCalculation = rtlHelper.textAlign(bodyAlign);\n let bodyItem, textColor, lines, i, j, ilen, jlen;\n ctx.textAlign = bodyAlign;\n ctx.textBaseline = 'middle';\n ctx.font = bodyFont.string;\n pt.x = getAlignedX(this, bodyAlignForCalculation, options);\n ctx.fillStyle = options.bodyColor;\n each(this.beforeBody, fillLineOfText);\n xLinePadding = displayColors && bodyAlignForCalculation !== 'right' ? bodyAlign === 'center' ? boxWidth / 2 + boxPadding : boxWidth + 2 + boxPadding : 0;\n for(i = 0, ilen = body.length; i < ilen; ++i){\n bodyItem = body[i];\n textColor = this.labelTextColors[i];\n ctx.fillStyle = textColor;\n each(bodyItem.before, fillLineOfText);\n lines = bodyItem.lines;\n if (displayColors && lines.length) {\n this._drawColorBox(ctx, pt, i, rtlHelper, options);\n bodyLineHeight = Math.max(bodyFont.lineHeight, boxHeight);\n }\n for(j = 0, jlen = lines.length; j < jlen; ++j){\n fillLineOfText(lines[j]);\n bodyLineHeight = bodyFont.lineHeight;\n }\n each(bodyItem.after, fillLineOfText);\n }\n xLinePadding = 0;\n bodyLineHeight = bodyFont.lineHeight;\n each(this.afterBody, fillLineOfText);\n pt.y -= bodySpacing;\n }\n drawFooter(pt, ctx, options) {\n const footer = this.footer;\n const length = footer.length;\n let footerFont, i;\n if (length) {\n const rtlHelper = getRtlAdapter(options.rtl, this.x, this.width);\n pt.x = getAlignedX(this, options.footerAlign, options);\n pt.y += options.footerMarginTop;\n ctx.textAlign = rtlHelper.textAlign(options.footerAlign);\n ctx.textBaseline = 'middle';\n footerFont = toFont(options.footerFont);\n ctx.fillStyle = options.footerColor;\n ctx.font = footerFont.string;\n for(i = 0; i < length; ++i){\n ctx.fillText(footer[i], rtlHelper.x(pt.x), pt.y + footerFont.lineHeight / 2);\n pt.y += footerFont.lineHeight + options.footerSpacing;\n }\n }\n }\n drawBackground(pt, ctx, tooltipSize, options) {\n const { xAlign , yAlign } = this;\n const { x , y } = pt;\n const { width , height } = tooltipSize;\n const { topLeft , topRight , bottomLeft , bottomRight } = toTRBLCorners(options.cornerRadius);\n ctx.fillStyle = options.backgroundColor;\n ctx.strokeStyle = options.borderColor;\n ctx.lineWidth = options.borderWidth;\n ctx.beginPath();\n ctx.moveTo(x + topLeft, y);\n if (yAlign === 'top') {\n this.drawCaret(pt, ctx, tooltipSize, options);\n }\n ctx.lineTo(x + width - topRight, y);\n ctx.quadraticCurveTo(x + width, y, x + width, y + topRight);\n if (yAlign === 'center' && xAlign === 'right') {\n this.drawCaret(pt, ctx, tooltipSize, options);\n }\n ctx.lineTo(x + width, y + height - bottomRight);\n ctx.quadraticCurveTo(x + width, y + height, x + width - bottomRight, y + height);\n if (yAlign === 'bottom') {\n this.drawCaret(pt, ctx, tooltipSize, options);\n }\n ctx.lineTo(x + bottomLeft, y + height);\n ctx.quadraticCurveTo(x, y + height, x, y + height - bottomLeft);\n if (yAlign === 'center' && xAlign === 'left') {\n this.drawCaret(pt, ctx, tooltipSize, options);\n }\n ctx.lineTo(x, y + topLeft);\n ctx.quadraticCurveTo(x, y, x + topLeft, y);\n ctx.closePath();\n ctx.fill();\n if (options.borderWidth > 0) {\n ctx.stroke();\n }\n }\n _updateAnimationTarget(options) {\n const chart = this.chart;\n const anims = this.$animations;\n const animX = anims && anims.x;\n const animY = anims && anims.y;\n if (animX || animY) {\n const position = positioners[options.position].call(this, this._active, this._eventPosition);\n if (!position) {\n return;\n }\n const size = this._size = getTooltipSize(this, options);\n const positionAndSize = Object.assign({}, position, this._size);\n const alignment = determineAlignment(chart, options, positionAndSize);\n const point = getBackgroundPoint(options, positionAndSize, alignment, chart);\n if (animX._to !== point.x || animY._to !== point.y) {\n this.xAlign = alignment.xAlign;\n this.yAlign = alignment.yAlign;\n this.width = size.width;\n this.height = size.height;\n this.caretX = position.x;\n this.caretY = position.y;\n this._resolveAnimations().update(this, point);\n }\n }\n }\n _willRender() {\n return !!this.opacity;\n }\n draw(ctx) {\n const options = this.options.setContext(this.getContext());\n let opacity = this.opacity;\n if (!opacity) {\n return;\n }\n this._updateAnimationTarget(options);\n const tooltipSize = {\n width: this.width,\n height: this.height\n };\n const pt = {\n x: this.x,\n y: this.y\n };\n opacity = Math.abs(opacity) < 1e-3 ? 0 : opacity;\n const padding = toPadding(options.padding);\n const hasTooltipContent = this.title.length || this.beforeBody.length || this.body.length || this.afterBody.length || this.footer.length;\n if (options.enabled && hasTooltipContent) {\n ctx.save();\n ctx.globalAlpha = opacity;\n this.drawBackground(pt, ctx, tooltipSize, options);\n overrideTextDirection(ctx, options.textDirection);\n pt.y += padding.top;\n this.drawTitle(pt, ctx, options);\n this.drawBody(pt, ctx, options);\n this.drawFooter(pt, ctx, options);\n restoreTextDirection(ctx, options.textDirection);\n ctx.restore();\n }\n }\n getActiveElements() {\n return this._active || [];\n }\n setActiveElements(activeElements, eventPosition) {\n const lastActive = this._active;\n const active = activeElements.map(({ datasetIndex , index })=>{\n const meta = this.chart.getDatasetMeta(datasetIndex);\n if (!meta) {\n throw new Error('Cannot find a dataset at index ' + datasetIndex);\n }\n return {\n datasetIndex,\n element: meta.data[index],\n index\n };\n });\n const changed = !_elementsEqual(lastActive, active);\n const positionChanged = this._positionChanged(active, eventPosition);\n if (changed || positionChanged) {\n this._active = active;\n this._eventPosition = eventPosition;\n this._ignoreReplayEvents = true;\n this.update(true);\n }\n }\n handleEvent(e, replay, inChartArea = true) {\n if (replay && this._ignoreReplayEvents) {\n return false;\n }\n this._ignoreReplayEvents = false;\n const options = this.options;\n const lastActive = this._active || [];\n const active = this._getActiveElements(e, lastActive, replay, inChartArea);\n const positionChanged = this._positionChanged(active, e);\n const changed = replay || !_elementsEqual(active, lastActive) || positionChanged;\n if (changed) {\n this._active = active;\n if (options.enabled || options.external) {\n this._eventPosition = {\n x: e.x,\n y: e.y\n };\n this.update(true, replay);\n }\n }\n return changed;\n }\n _getActiveElements(e, lastActive, replay, inChartArea) {\n const options = this.options;\n if (e.type === 'mouseout') {\n return [];\n }\n if (!inChartArea) {\n return lastActive.filter((i)=>this.chart.data.datasets[i.datasetIndex] && this.chart.getDatasetMeta(i.datasetIndex).controller.getParsed(i.index) !== undefined);\n }\n const active = this.chart.getElementsAtEventForMode(e, options.mode, options, replay);\n if (options.reverse) {\n active.reverse();\n }\n return active;\n }\n _positionChanged(active, e) {\n const { caretX , caretY , options } = this;\n const position = positioners[options.position].call(this, active, e);\n return position !== false && (caretX !== position.x || caretY !== position.y);\n }\n}\nvar plugin_tooltip = {\n id: 'tooltip',\n _element: Tooltip,\n positioners,\n afterInit (chart, _args, options) {\n if (options) {\n chart.tooltip = new Tooltip({\n chart,\n options\n });\n }\n },\n beforeUpdate (chart, _args, options) {\n if (chart.tooltip) {\n chart.tooltip.initialize(options);\n }\n },\n reset (chart, _args, options) {\n if (chart.tooltip) {\n chart.tooltip.initialize(options);\n }\n },\n afterDraw (chart) {\n const tooltip = chart.tooltip;\n if (tooltip && tooltip._willRender()) {\n const args = {\n tooltip\n };\n if (chart.notifyPlugins('beforeTooltipDraw', {\n ...args,\n cancelable: true\n }) === false) {\n return;\n }\n tooltip.draw(chart.ctx);\n chart.notifyPlugins('afterTooltipDraw', args);\n }\n },\n afterEvent (chart, args) {\n if (chart.tooltip) {\n const useFinalPosition = args.replay;\n if (chart.tooltip.handleEvent(args.event, useFinalPosition, args.inChartArea)) {\n args.changed = true;\n }\n }\n },\n defaults: {\n enabled: true,\n external: null,\n position: 'average',\n backgroundColor: 'rgba(0,0,0,0.8)',\n titleColor: '#fff',\n titleFont: {\n weight: 'bold'\n },\n titleSpacing: 2,\n titleMarginBottom: 6,\n titleAlign: 'left',\n bodyColor: '#fff',\n bodySpacing: 2,\n bodyFont: {},\n bodyAlign: 'left',\n footerColor: '#fff',\n footerSpacing: 2,\n footerMarginTop: 6,\n footerFont: {\n weight: 'bold'\n },\n footerAlign: 'left',\n padding: 6,\n caretPadding: 2,\n caretSize: 5,\n cornerRadius: 6,\n boxHeight: (ctx, opts)=>opts.bodyFont.size,\n boxWidth: (ctx, opts)=>opts.bodyFont.size,\n multiKeyBackground: '#fff',\n displayColors: true,\n boxPadding: 0,\n borderColor: 'rgba(0,0,0,0)',\n borderWidth: 0,\n animation: {\n duration: 400,\n easing: 'easeOutQuart'\n },\n animations: {\n numbers: {\n type: 'number',\n properties: [\n 'x',\n 'y',\n 'width',\n 'height',\n 'caretX',\n 'caretY'\n ]\n },\n opacity: {\n easing: 'linear',\n duration: 200\n }\n },\n callbacks: defaultCallbacks\n },\n defaultRoutes: {\n bodyFont: 'font',\n footerFont: 'font',\n titleFont: 'font'\n },\n descriptors: {\n _scriptable: (name)=>name !== 'filter' && name !== 'itemSort' && name !== 'external',\n _indexable: false,\n callbacks: {\n _scriptable: false,\n _indexable: false\n },\n animation: {\n _fallback: false\n },\n animations: {\n _fallback: 'animation'\n }\n },\n additionalOptionScopes: [\n 'interaction'\n ]\n};\n\nvar plugins = /*#__PURE__*/Object.freeze({\n__proto__: null,\nColors: plugin_colors,\nDecimation: plugin_decimation,\nFiller: index,\nLegend: plugin_legend,\nSubTitle: plugin_subtitle,\nTitle: plugin_title,\nTooltip: plugin_tooltip\n});\n\nconst addIfString = (labels, raw, index, addedLabels)=>{\n if (typeof raw === 'string') {\n index = labels.push(raw) - 1;\n addedLabels.unshift({\n index,\n label: raw\n });\n } else if (isNaN(raw)) {\n index = null;\n }\n return index;\n};\nfunction findOrAddLabel(labels, raw, index, addedLabels) {\n const first = labels.indexOf(raw);\n if (first === -1) {\n return addIfString(labels, raw, index, addedLabels);\n }\n const last = labels.lastIndexOf(raw);\n return first !== last ? index : first;\n}\nconst validIndex = (index, max)=>index === null ? null : _limitValue(Math.round(index), 0, max);\nfunction _getLabelForValue(value) {\n const labels = this.getLabels();\n if (value >= 0 && value < labels.length) {\n return labels[value];\n }\n return value;\n}\nclass CategoryScale extends Scale {\n static id = 'category';\n static defaults = {\n ticks: {\n callback: _getLabelForValue\n }\n };\n constructor(cfg){\n super(cfg);\n this._startValue = undefined;\n this._valueRange = 0;\n this._addedLabels = [];\n }\n init(scaleOptions) {\n const added = this._addedLabels;\n if (added.length) {\n const labels = this.getLabels();\n for (const { index , label } of added){\n if (labels[index] === label) {\n labels.splice(index, 1);\n }\n }\n this._addedLabels = [];\n }\n super.init(scaleOptions);\n }\n parse(raw, index) {\n if (isNullOrUndef(raw)) {\n return null;\n }\n const labels = this.getLabels();\n index = isFinite(index) && labels[index] === raw ? index : findOrAddLabel(labels, raw, valueOrDefault(index, raw), this._addedLabels);\n return validIndex(index, labels.length - 1);\n }\n determineDataLimits() {\n const { minDefined , maxDefined } = this.getUserBounds();\n let { min , max } = this.getMinMax(true);\n if (this.options.bounds === 'ticks') {\n if (!minDefined) {\n min = 0;\n }\n if (!maxDefined) {\n max = this.getLabels().length - 1;\n }\n }\n this.min = min;\n this.max = max;\n }\n buildTicks() {\n const min = this.min;\n const max = this.max;\n const offset = this.options.offset;\n const ticks = [];\n let labels = this.getLabels();\n labels = min === 0 && max === labels.length - 1 ? labels : labels.slice(min, max + 1);\n this._valueRange = Math.max(labels.length - (offset ? 0 : 1), 1);\n this._startValue = this.min - (offset ? 0.5 : 0);\n for(let value = min; value <= max; value++){\n ticks.push({\n value\n });\n }\n return ticks;\n }\n getLabelForValue(value) {\n return _getLabelForValue.call(this, value);\n }\n configure() {\n super.configure();\n if (!this.isHorizontal()) {\n this._reversePixels = !this._reversePixels;\n }\n }\n getPixelForValue(value) {\n if (typeof value !== 'number') {\n value = this.parse(value);\n }\n return value === null ? NaN : this.getPixelForDecimal((value - this._startValue) / this._valueRange);\n }\n getPixelForTick(index) {\n const ticks = this.ticks;\n if (index < 0 || index > ticks.length - 1) {\n return null;\n }\n return this.getPixelForValue(ticks[index].value);\n }\n getValueForPixel(pixel) {\n return Math.round(this._startValue + this.getDecimalForPixel(pixel) * this._valueRange);\n }\n getBasePixel() {\n return this.bottom;\n }\n}\n\nfunction generateTicks$1(generationOptions, dataRange) {\n const ticks = [];\n const MIN_SPACING = 1e-14;\n const { bounds , step , min , max , precision , count , maxTicks , maxDigits , includeBounds } = generationOptions;\n const unit = step || 1;\n const maxSpaces = maxTicks - 1;\n const { min: rmin , max: rmax } = dataRange;\n const minDefined = !isNullOrUndef(min);\n const maxDefined = !isNullOrUndef(max);\n const countDefined = !isNullOrUndef(count);\n const minSpacing = (rmax - rmin) / (maxDigits + 1);\n let spacing = niceNum((rmax - rmin) / maxSpaces / unit) * unit;\n let factor, niceMin, niceMax, numSpaces;\n if (spacing < MIN_SPACING && !minDefined && !maxDefined) {\n return [\n {\n value: rmin\n },\n {\n value: rmax\n }\n ];\n }\n numSpaces = Math.ceil(rmax / spacing) - Math.floor(rmin / spacing);\n if (numSpaces > maxSpaces) {\n spacing = niceNum(numSpaces * spacing / maxSpaces / unit) * unit;\n }\n if (!isNullOrUndef(precision)) {\n factor = Math.pow(10, precision);\n spacing = Math.ceil(spacing * factor) / factor;\n }\n if (bounds === 'ticks') {\n niceMin = Math.floor(rmin / spacing) * spacing;\n niceMax = Math.ceil(rmax / spacing) * spacing;\n } else {\n niceMin = rmin;\n niceMax = rmax;\n }\n if (minDefined && maxDefined && step && almostWhole((max - min) / step, spacing / 1000)) {\n numSpaces = Math.round(Math.min((max - min) / spacing, maxTicks));\n spacing = (max - min) / numSpaces;\n niceMin = min;\n niceMax = max;\n } else if (countDefined) {\n niceMin = minDefined ? min : niceMin;\n niceMax = maxDefined ? max : niceMax;\n numSpaces = count - 1;\n spacing = (niceMax - niceMin) / numSpaces;\n } else {\n numSpaces = (niceMax - niceMin) / spacing;\n if (almostEquals(numSpaces, Math.round(numSpaces), spacing / 1000)) {\n numSpaces = Math.round(numSpaces);\n } else {\n numSpaces = Math.ceil(numSpaces);\n }\n }\n const decimalPlaces = Math.max(_decimalPlaces(spacing), _decimalPlaces(niceMin));\n factor = Math.pow(10, isNullOrUndef(precision) ? decimalPlaces : precision);\n niceMin = Math.round(niceMin * factor) / factor;\n niceMax = Math.round(niceMax * factor) / factor;\n let j = 0;\n if (minDefined) {\n if (includeBounds && niceMin !== min) {\n ticks.push({\n value: min\n });\n if (niceMin < min) {\n j++;\n }\n if (almostEquals(Math.round((niceMin + j * spacing) * factor) / factor, min, relativeLabelSize(min, minSpacing, generationOptions))) {\n j++;\n }\n } else if (niceMin < min) {\n j++;\n }\n }\n for(; j < numSpaces; ++j){\n const tickValue = Math.round((niceMin + j * spacing) * factor) / factor;\n if (maxDefined && tickValue > max) {\n break;\n }\n ticks.push({\n value: tickValue\n });\n }\n if (maxDefined && includeBounds && niceMax !== max) {\n if (ticks.length && almostEquals(ticks[ticks.length - 1].value, max, relativeLabelSize(max, minSpacing, generationOptions))) {\n ticks[ticks.length - 1].value = max;\n } else {\n ticks.push({\n value: max\n });\n }\n } else if (!maxDefined || niceMax === max) {\n ticks.push({\n value: niceMax\n });\n }\n return ticks;\n}\nfunction relativeLabelSize(value, minSpacing, { horizontal , minRotation }) {\n const rad = toRadians(minRotation);\n const ratio = (horizontal ? Math.sin(rad) : Math.cos(rad)) || 0.001;\n const length = 0.75 * minSpacing * ('' + value).length;\n return Math.min(minSpacing / ratio, length);\n}\nclass LinearScaleBase extends Scale {\n constructor(cfg){\n super(cfg);\n this.start = undefined;\n this.end = undefined;\n this._startValue = undefined;\n this._endValue = undefined;\n this._valueRange = 0;\n }\n parse(raw, index) {\n if (isNullOrUndef(raw)) {\n return null;\n }\n if ((typeof raw === 'number' || raw instanceof Number) && !isFinite(+raw)) {\n return null;\n }\n return +raw;\n }\n handleTickRangeOptions() {\n const { beginAtZero } = this.options;\n const { minDefined , maxDefined } = this.getUserBounds();\n let { min , max } = this;\n const setMin = (v)=>min = minDefined ? min : v;\n const setMax = (v)=>max = maxDefined ? max : v;\n if (beginAtZero) {\n const minSign = sign(min);\n const maxSign = sign(max);\n if (minSign < 0 && maxSign < 0) {\n setMax(0);\n } else if (minSign > 0 && maxSign > 0) {\n setMin(0);\n }\n }\n if (min === max) {\n let offset = max === 0 ? 1 : Math.abs(max * 0.05);\n setMax(max + offset);\n if (!beginAtZero) {\n setMin(min - offset);\n }\n }\n this.min = min;\n this.max = max;\n }\n getTickLimit() {\n const tickOpts = this.options.ticks;\n let { maxTicksLimit , stepSize } = tickOpts;\n let maxTicks;\n if (stepSize) {\n maxTicks = Math.ceil(this.max / stepSize) - Math.floor(this.min / stepSize) + 1;\n if (maxTicks > 1000) {\n console.warn(`scales.${this.id}.ticks.stepSize: ${stepSize} would result generating up to ${maxTicks} ticks. Limiting to 1000.`);\n maxTicks = 1000;\n }\n } else {\n maxTicks = this.computeTickLimit();\n maxTicksLimit = maxTicksLimit || 11;\n }\n if (maxTicksLimit) {\n maxTicks = Math.min(maxTicksLimit, maxTicks);\n }\n return maxTicks;\n }\n computeTickLimit() {\n return Number.POSITIVE_INFINITY;\n }\n buildTicks() {\n const opts = this.options;\n const tickOpts = opts.ticks;\n let maxTicks = this.getTickLimit();\n maxTicks = Math.max(2, maxTicks);\n const numericGeneratorOptions = {\n maxTicks,\n bounds: opts.bounds,\n min: opts.min,\n max: opts.max,\n precision: tickOpts.precision,\n step: tickOpts.stepSize,\n count: tickOpts.count,\n maxDigits: this._maxDigits(),\n horizontal: this.isHorizontal(),\n minRotation: tickOpts.minRotation || 0,\n includeBounds: tickOpts.includeBounds !== false\n };\n const dataRange = this._range || this;\n const ticks = generateTicks$1(numericGeneratorOptions, dataRange);\n if (opts.bounds === 'ticks') {\n _setMinAndMaxByKey(ticks, this, 'value');\n }\n if (opts.reverse) {\n ticks.reverse();\n this.start = this.max;\n this.end = this.min;\n } else {\n this.start = this.min;\n this.end = this.max;\n }\n return ticks;\n }\n configure() {\n const ticks = this.ticks;\n let start = this.min;\n let end = this.max;\n super.configure();\n if (this.options.offset && ticks.length) {\n const offset = (end - start) / Math.max(ticks.length - 1, 1) / 2;\n start -= offset;\n end += offset;\n }\n this._startValue = start;\n this._endValue = end;\n this._valueRange = end - start;\n }\n getLabelForValue(value) {\n return formatNumber(value, this.chart.options.locale, this.options.ticks.format);\n }\n}\n\nclass LinearScale extends LinearScaleBase {\n static id = 'linear';\n static defaults = {\n ticks: {\n callback: Ticks.formatters.numeric\n }\n };\n determineDataLimits() {\n const { min , max } = this.getMinMax(true);\n this.min = isNumberFinite(min) ? min : 0;\n this.max = isNumberFinite(max) ? max : 1;\n this.handleTickRangeOptions();\n }\n computeTickLimit() {\n const horizontal = this.isHorizontal();\n const length = horizontal ? this.width : this.height;\n const minRotation = toRadians(this.options.ticks.minRotation);\n const ratio = (horizontal ? Math.sin(minRotation) : Math.cos(minRotation)) || 0.001;\n const tickFont = this._resolveTickFontOptions(0);\n return Math.ceil(length / Math.min(40, tickFont.lineHeight / ratio));\n }\n getPixelForValue(value) {\n return value === null ? NaN : this.getPixelForDecimal((value - this._startValue) / this._valueRange);\n }\n getValueForPixel(pixel) {\n return this._startValue + this.getDecimalForPixel(pixel) * this._valueRange;\n }\n}\n\nconst log10Floor = (v)=>Math.floor(log10(v));\nconst changeExponent = (v, m)=>Math.pow(10, log10Floor(v) + m);\nfunction isMajor(tickVal) {\n const remain = tickVal / Math.pow(10, log10Floor(tickVal));\n return remain === 1;\n}\nfunction steps(min, max, rangeExp) {\n const rangeStep = Math.pow(10, rangeExp);\n const start = Math.floor(min / rangeStep);\n const end = Math.ceil(max / rangeStep);\n return end - start;\n}\nfunction startExp(min, max) {\n const range = max - min;\n let rangeExp = log10Floor(range);\n while(steps(min, max, rangeExp) > 10){\n rangeExp++;\n }\n while(steps(min, max, rangeExp) < 10){\n rangeExp--;\n }\n return Math.min(rangeExp, log10Floor(min));\n}\n function generateTicks(generationOptions, { min , max }) {\n min = finiteOrDefault(generationOptions.min, min);\n const ticks = [];\n const minExp = log10Floor(min);\n let exp = startExp(min, max);\n let precision = exp < 0 ? Math.pow(10, Math.abs(exp)) : 1;\n const stepSize = Math.pow(10, exp);\n const base = minExp > exp ? Math.pow(10, minExp) : 0;\n const start = Math.round((min - base) * precision) / precision;\n const offset = Math.floor((min - base) / stepSize / 10) * stepSize * 10;\n let significand = Math.floor((start - offset) / Math.pow(10, exp));\n let value = finiteOrDefault(generationOptions.min, Math.round((base + offset + significand * Math.pow(10, exp)) * precision) / precision);\n while(value < max){\n ticks.push({\n value,\n major: isMajor(value),\n significand\n });\n if (significand >= 10) {\n significand = significand < 15 ? 15 : 20;\n } else {\n significand++;\n }\n if (significand >= 20) {\n exp++;\n significand = 2;\n precision = exp >= 0 ? 1 : precision;\n }\n value = Math.round((base + offset + significand * Math.pow(10, exp)) * precision) / precision;\n }\n const lastTick = finiteOrDefault(generationOptions.max, value);\n ticks.push({\n value: lastTick,\n major: isMajor(lastTick),\n significand\n });\n return ticks;\n}\nclass LogarithmicScale extends Scale {\n static id = 'logarithmic';\n static defaults = {\n ticks: {\n callback: Ticks.formatters.logarithmic,\n major: {\n enabled: true\n }\n }\n };\n constructor(cfg){\n super(cfg);\n this.start = undefined;\n this.end = undefined;\n this._startValue = undefined;\n this._valueRange = 0;\n }\n parse(raw, index) {\n const value = LinearScaleBase.prototype.parse.apply(this, [\n raw,\n index\n ]);\n if (value === 0) {\n this._zero = true;\n return undefined;\n }\n return isNumberFinite(value) && value > 0 ? value : null;\n }\n determineDataLimits() {\n const { min , max } = this.getMinMax(true);\n this.min = isNumberFinite(min) ? Math.max(0, min) : null;\n this.max = isNumberFinite(max) ? Math.max(0, max) : null;\n if (this.options.beginAtZero) {\n this._zero = true;\n }\n if (this._zero && this.min !== this._suggestedMin && !isNumberFinite(this._userMin)) {\n this.min = min === changeExponent(this.min, 0) ? changeExponent(this.min, -1) : changeExponent(this.min, 0);\n }\n this.handleTickRangeOptions();\n }\n handleTickRangeOptions() {\n const { minDefined , maxDefined } = this.getUserBounds();\n let min = this.min;\n let max = this.max;\n const setMin = (v)=>min = minDefined ? min : v;\n const setMax = (v)=>max = maxDefined ? max : v;\n if (min === max) {\n if (min <= 0) {\n setMin(1);\n setMax(10);\n } else {\n setMin(changeExponent(min, -1));\n setMax(changeExponent(max, +1));\n }\n }\n if (min <= 0) {\n setMin(changeExponent(max, -1));\n }\n if (max <= 0) {\n setMax(changeExponent(min, +1));\n }\n this.min = min;\n this.max = max;\n }\n buildTicks() {\n const opts = this.options;\n const generationOptions = {\n min: this._userMin,\n max: this._userMax\n };\n const ticks = generateTicks(generationOptions, this);\n if (opts.bounds === 'ticks') {\n _setMinAndMaxByKey(ticks, this, 'value');\n }\n if (opts.reverse) {\n ticks.reverse();\n this.start = this.max;\n this.end = this.min;\n } else {\n this.start = this.min;\n this.end = this.max;\n }\n return ticks;\n }\n getLabelForValue(value) {\n return value === undefined ? '0' : formatNumber(value, this.chart.options.locale, this.options.ticks.format);\n }\n configure() {\n const start = this.min;\n super.configure();\n this._startValue = log10(start);\n this._valueRange = log10(this.max) - log10(start);\n }\n getPixelForValue(value) {\n if (value === undefined || value === 0) {\n value = this.min;\n }\n if (value === null || isNaN(value)) {\n return NaN;\n }\n return this.getPixelForDecimal(value === this.min ? 0 : (log10(value) - this._startValue) / this._valueRange);\n }\n getValueForPixel(pixel) {\n const decimal = this.getDecimalForPixel(pixel);\n return Math.pow(10, this._startValue + decimal * this._valueRange);\n }\n}\n\nfunction getTickBackdropHeight(opts) {\n const tickOpts = opts.ticks;\n if (tickOpts.display && opts.display) {\n const padding = toPadding(tickOpts.backdropPadding);\n return valueOrDefault(tickOpts.font && tickOpts.font.size, defaults.font.size) + padding.height;\n }\n return 0;\n}\nfunction measureLabelSize(ctx, font, label) {\n label = isArray(label) ? label : [\n label\n ];\n return {\n w: _longestText(ctx, font.string, label),\n h: label.length * font.lineHeight\n };\n}\nfunction determineLimits(angle, pos, size, min, max) {\n if (angle === min || angle === max) {\n return {\n start: pos - size / 2,\n end: pos + size / 2\n };\n } else if (angle < min || angle > max) {\n return {\n start: pos - size,\n end: pos\n };\n }\n return {\n start: pos,\n end: pos + size\n };\n}\n function fitWithPointLabels(scale) {\n const orig = {\n l: scale.left + scale._padding.left,\n r: scale.right - scale._padding.right,\n t: scale.top + scale._padding.top,\n b: scale.bottom - scale._padding.bottom\n };\n const limits = Object.assign({}, orig);\n const labelSizes = [];\n const padding = [];\n const valueCount = scale._pointLabels.length;\n const pointLabelOpts = scale.options.pointLabels;\n const additionalAngle = pointLabelOpts.centerPointLabels ? PI / valueCount : 0;\n for(let i = 0; i < valueCount; i++){\n const opts = pointLabelOpts.setContext(scale.getPointLabelContext(i));\n padding[i] = opts.padding;\n const pointPosition = scale.getPointPosition(i, scale.drawingArea + padding[i], additionalAngle);\n const plFont = toFont(opts.font);\n const textSize = measureLabelSize(scale.ctx, plFont, scale._pointLabels[i]);\n labelSizes[i] = textSize;\n const angleRadians = _normalizeAngle(scale.getIndexAngle(i) + additionalAngle);\n const angle = Math.round(toDegrees(angleRadians));\n const hLimits = determineLimits(angle, pointPosition.x, textSize.w, 0, 180);\n const vLimits = determineLimits(angle, pointPosition.y, textSize.h, 90, 270);\n updateLimits(limits, orig, angleRadians, hLimits, vLimits);\n }\n scale.setCenterPoint(orig.l - limits.l, limits.r - orig.r, orig.t - limits.t, limits.b - orig.b);\n scale._pointLabelItems = buildPointLabelItems(scale, labelSizes, padding);\n}\nfunction updateLimits(limits, orig, angle, hLimits, vLimits) {\n const sin = Math.abs(Math.sin(angle));\n const cos = Math.abs(Math.cos(angle));\n let x = 0;\n let y = 0;\n if (hLimits.start < orig.l) {\n x = (orig.l - hLimits.start) / sin;\n limits.l = Math.min(limits.l, orig.l - x);\n } else if (hLimits.end > orig.r) {\n x = (hLimits.end - orig.r) / sin;\n limits.r = Math.max(limits.r, orig.r + x);\n }\n if (vLimits.start < orig.t) {\n y = (orig.t - vLimits.start) / cos;\n limits.t = Math.min(limits.t, orig.t - y);\n } else if (vLimits.end > orig.b) {\n y = (vLimits.end - orig.b) / cos;\n limits.b = Math.max(limits.b, orig.b + y);\n }\n}\nfunction createPointLabelItem(scale, index, itemOpts) {\n const outerDistance = scale.drawingArea;\n const { extra , additionalAngle , padding , size } = itemOpts;\n const pointLabelPosition = scale.getPointPosition(index, outerDistance + extra + padding, additionalAngle);\n const angle = Math.round(toDegrees(_normalizeAngle(pointLabelPosition.angle + HALF_PI)));\n const y = yForAngle(pointLabelPosition.y, size.h, angle);\n const textAlign = getTextAlignForAngle(angle);\n const left = leftForTextAlign(pointLabelPosition.x, size.w, textAlign);\n return {\n visible: true,\n x: pointLabelPosition.x,\n y,\n textAlign,\n left,\n top: y,\n right: left + size.w,\n bottom: y + size.h\n };\n}\nfunction isNotOverlapped(item, area) {\n if (!area) {\n return true;\n }\n const { left , top , right , bottom } = item;\n const apexesInArea = _isPointInArea({\n x: left,\n y: top\n }, area) || _isPointInArea({\n x: left,\n y: bottom\n }, area) || _isPointInArea({\n x: right,\n y: top\n }, area) || _isPointInArea({\n x: right,\n y: bottom\n }, area);\n return !apexesInArea;\n}\nfunction buildPointLabelItems(scale, labelSizes, padding) {\n const items = [];\n const valueCount = scale._pointLabels.length;\n const opts = scale.options;\n const { centerPointLabels , display } = opts.pointLabels;\n const itemOpts = {\n extra: getTickBackdropHeight(opts) / 2,\n additionalAngle: centerPointLabels ? PI / valueCount : 0\n };\n let area;\n for(let i = 0; i < valueCount; i++){\n itemOpts.padding = padding[i];\n itemOpts.size = labelSizes[i];\n const item = createPointLabelItem(scale, i, itemOpts);\n items.push(item);\n if (display === 'auto') {\n item.visible = isNotOverlapped(item, area);\n if (item.visible) {\n area = item;\n }\n }\n }\n return items;\n}\nfunction getTextAlignForAngle(angle) {\n if (angle === 0 || angle === 180) {\n return 'center';\n } else if (angle < 180) {\n return 'left';\n }\n return 'right';\n}\nfunction leftForTextAlign(x, w, align) {\n if (align === 'right') {\n x -= w;\n } else if (align === 'center') {\n x -= w / 2;\n }\n return x;\n}\nfunction yForAngle(y, h, angle) {\n if (angle === 90 || angle === 270) {\n y -= h / 2;\n } else if (angle > 270 || angle < 90) {\n y -= h;\n }\n return y;\n}\nfunction drawPointLabelBox(ctx, opts, item) {\n const { left , top , right , bottom } = item;\n const { backdropColor } = opts;\n if (!isNullOrUndef(backdropColor)) {\n const borderRadius = toTRBLCorners(opts.borderRadius);\n const padding = toPadding(opts.backdropPadding);\n ctx.fillStyle = backdropColor;\n const backdropLeft = left - padding.left;\n const backdropTop = top - padding.top;\n const backdropWidth = right - left + padding.width;\n const backdropHeight = bottom - top + padding.height;\n if (Object.values(borderRadius).some((v)=>v !== 0)) {\n ctx.beginPath();\n addRoundedRectPath(ctx, {\n x: backdropLeft,\n y: backdropTop,\n w: backdropWidth,\n h: backdropHeight,\n radius: borderRadius\n });\n ctx.fill();\n } else {\n ctx.fillRect(backdropLeft, backdropTop, backdropWidth, backdropHeight);\n }\n }\n}\nfunction drawPointLabels(scale, labelCount) {\n const { ctx , options: { pointLabels } } = scale;\n for(let i = labelCount - 1; i >= 0; i--){\n const item = scale._pointLabelItems[i];\n if (!item.visible) {\n continue;\n }\n const optsAtIndex = pointLabels.setContext(scale.getPointLabelContext(i));\n drawPointLabelBox(ctx, optsAtIndex, item);\n const plFont = toFont(optsAtIndex.font);\n const { x , y , textAlign } = item;\n renderText(ctx, scale._pointLabels[i], x, y + plFont.lineHeight / 2, plFont, {\n color: optsAtIndex.color,\n textAlign: textAlign,\n textBaseline: 'middle'\n });\n }\n}\nfunction pathRadiusLine(scale, radius, circular, labelCount) {\n const { ctx } = scale;\n if (circular) {\n ctx.arc(scale.xCenter, scale.yCenter, radius, 0, TAU);\n } else {\n let pointPosition = scale.getPointPosition(0, radius);\n ctx.moveTo(pointPosition.x, pointPosition.y);\n for(let i = 1; i < labelCount; i++){\n pointPosition = scale.getPointPosition(i, radius);\n ctx.lineTo(pointPosition.x, pointPosition.y);\n }\n }\n}\nfunction drawRadiusLine(scale, gridLineOpts, radius, labelCount, borderOpts) {\n const ctx = scale.ctx;\n const circular = gridLineOpts.circular;\n const { color , lineWidth } = gridLineOpts;\n if (!circular && !labelCount || !color || !lineWidth || radius < 0) {\n return;\n }\n ctx.save();\n ctx.strokeStyle = color;\n ctx.lineWidth = lineWidth;\n ctx.setLineDash(borderOpts.dash);\n ctx.lineDashOffset = borderOpts.dashOffset;\n ctx.beginPath();\n pathRadiusLine(scale, radius, circular, labelCount);\n ctx.closePath();\n ctx.stroke();\n ctx.restore();\n}\nfunction createPointLabelContext(parent, index, label) {\n return createContext(parent, {\n label,\n index,\n type: 'pointLabel'\n });\n}\nclass RadialLinearScale extends LinearScaleBase {\n static id = 'radialLinear';\n static defaults = {\n display: true,\n animate: true,\n position: 'chartArea',\n angleLines: {\n display: true,\n lineWidth: 1,\n borderDash: [],\n borderDashOffset: 0.0\n },\n grid: {\n circular: false\n },\n startAngle: 0,\n ticks: {\n showLabelBackdrop: true,\n callback: Ticks.formatters.numeric\n },\n pointLabels: {\n backdropColor: undefined,\n backdropPadding: 2,\n display: true,\n font: {\n size: 10\n },\n callback (label) {\n return label;\n },\n padding: 5,\n centerPointLabels: false\n }\n };\n static defaultRoutes = {\n 'angleLines.color': 'borderColor',\n 'pointLabels.color': 'color',\n 'ticks.color': 'color'\n };\n static descriptors = {\n angleLines: {\n _fallback: 'grid'\n }\n };\n constructor(cfg){\n super(cfg);\n this.xCenter = undefined;\n this.yCenter = undefined;\n this.drawingArea = undefined;\n this._pointLabels = [];\n this._pointLabelItems = [];\n }\n setDimensions() {\n const padding = this._padding = toPadding(getTickBackdropHeight(this.options) / 2);\n const w = this.width = this.maxWidth - padding.width;\n const h = this.height = this.maxHeight - padding.height;\n this.xCenter = Math.floor(this.left + w / 2 + padding.left);\n this.yCenter = Math.floor(this.top + h / 2 + padding.top);\n this.drawingArea = Math.floor(Math.min(w, h) / 2);\n }\n determineDataLimits() {\n const { min , max } = this.getMinMax(false);\n this.min = isNumberFinite(min) && !isNaN(min) ? min : 0;\n this.max = isNumberFinite(max) && !isNaN(max) ? max : 0;\n this.handleTickRangeOptions();\n }\n computeTickLimit() {\n return Math.ceil(this.drawingArea / getTickBackdropHeight(this.options));\n }\n generateTickLabels(ticks) {\n LinearScaleBase.prototype.generateTickLabels.call(this, ticks);\n this._pointLabels = this.getLabels().map((value, index)=>{\n const label = callback(this.options.pointLabels.callback, [\n value,\n index\n ], this);\n return label || label === 0 ? label : '';\n }).filter((v, i)=>this.chart.getDataVisibility(i));\n }\n fit() {\n const opts = this.options;\n if (opts.display && opts.pointLabels.display) {\n fitWithPointLabels(this);\n } else {\n this.setCenterPoint(0, 0, 0, 0);\n }\n }\n setCenterPoint(leftMovement, rightMovement, topMovement, bottomMovement) {\n this.xCenter += Math.floor((leftMovement - rightMovement) / 2);\n this.yCenter += Math.floor((topMovement - bottomMovement) / 2);\n this.drawingArea -= Math.min(this.drawingArea / 2, Math.max(leftMovement, rightMovement, topMovement, bottomMovement));\n }\n getIndexAngle(index) {\n const angleMultiplier = TAU / (this._pointLabels.length || 1);\n const startAngle = this.options.startAngle || 0;\n return _normalizeAngle(index * angleMultiplier + toRadians(startAngle));\n }\n getDistanceFromCenterForValue(value) {\n if (isNullOrUndef(value)) {\n return NaN;\n }\n const scalingFactor = this.drawingArea / (this.max - this.min);\n if (this.options.reverse) {\n return (this.max - value) * scalingFactor;\n }\n return (value - this.min) * scalingFactor;\n }\n getValueForDistanceFromCenter(distance) {\n if (isNullOrUndef(distance)) {\n return NaN;\n }\n const scaledDistance = distance / (this.drawingArea / (this.max - this.min));\n return this.options.reverse ? this.max - scaledDistance : this.min + scaledDistance;\n }\n getPointLabelContext(index) {\n const pointLabels = this._pointLabels || [];\n if (index >= 0 && index < pointLabels.length) {\n const pointLabel = pointLabels[index];\n return createPointLabelContext(this.getContext(), index, pointLabel);\n }\n }\n getPointPosition(index, distanceFromCenter, additionalAngle = 0) {\n const angle = this.getIndexAngle(index) - HALF_PI + additionalAngle;\n return {\n x: Math.cos(angle) * distanceFromCenter + this.xCenter,\n y: Math.sin(angle) * distanceFromCenter + this.yCenter,\n angle\n };\n }\n getPointPositionForValue(index, value) {\n return this.getPointPosition(index, this.getDistanceFromCenterForValue(value));\n }\n getBasePosition(index) {\n return this.getPointPositionForValue(index || 0, this.getBaseValue());\n }\n getPointLabelPosition(index) {\n const { left , top , right , bottom } = this._pointLabelItems[index];\n return {\n left,\n top,\n right,\n bottom\n };\n }\n drawBackground() {\n const { backgroundColor , grid: { circular } } = this.options;\n if (backgroundColor) {\n const ctx = this.ctx;\n ctx.save();\n ctx.beginPath();\n pathRadiusLine(this, this.getDistanceFromCenterForValue(this._endValue), circular, this._pointLabels.length);\n ctx.closePath();\n ctx.fillStyle = backgroundColor;\n ctx.fill();\n ctx.restore();\n }\n }\n drawGrid() {\n const ctx = this.ctx;\n const opts = this.options;\n const { angleLines , grid , border } = opts;\n const labelCount = this._pointLabels.length;\n let i, offset, position;\n if (opts.pointLabels.display) {\n drawPointLabels(this, labelCount);\n }\n if (grid.display) {\n this.ticks.forEach((tick, index)=>{\n if (index !== 0 || index === 0 && this.min < 0) {\n offset = this.getDistanceFromCenterForValue(tick.value);\n const context = this.getContext(index);\n const optsAtIndex = grid.setContext(context);\n const optsAtIndexBorder = border.setContext(context);\n drawRadiusLine(this, optsAtIndex, offset, labelCount, optsAtIndexBorder);\n }\n });\n }\n if (angleLines.display) {\n ctx.save();\n for(i = labelCount - 1; i >= 0; i--){\n const optsAtIndex = angleLines.setContext(this.getPointLabelContext(i));\n const { color , lineWidth } = optsAtIndex;\n if (!lineWidth || !color) {\n continue;\n }\n ctx.lineWidth = lineWidth;\n ctx.strokeStyle = color;\n ctx.setLineDash(optsAtIndex.borderDash);\n ctx.lineDashOffset = optsAtIndex.borderDashOffset;\n offset = this.getDistanceFromCenterForValue(opts.reverse ? this.min : this.max);\n position = this.getPointPosition(i, offset);\n ctx.beginPath();\n ctx.moveTo(this.xCenter, this.yCenter);\n ctx.lineTo(position.x, position.y);\n ctx.stroke();\n }\n ctx.restore();\n }\n }\n drawBorder() {}\n drawLabels() {\n const ctx = this.ctx;\n const opts = this.options;\n const tickOpts = opts.ticks;\n if (!tickOpts.display) {\n return;\n }\n const startAngle = this.getIndexAngle(0);\n let offset, width;\n ctx.save();\n ctx.translate(this.xCenter, this.yCenter);\n ctx.rotate(startAngle);\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n this.ticks.forEach((tick, index)=>{\n if (index === 0 && this.min >= 0 && !opts.reverse) {\n return;\n }\n const optsAtIndex = tickOpts.setContext(this.getContext(index));\n const tickFont = toFont(optsAtIndex.font);\n offset = this.getDistanceFromCenterForValue(this.ticks[index].value);\n if (optsAtIndex.showLabelBackdrop) {\n ctx.font = tickFont.string;\n width = ctx.measureText(tick.label).width;\n ctx.fillStyle = optsAtIndex.backdropColor;\n const padding = toPadding(optsAtIndex.backdropPadding);\n ctx.fillRect(-width / 2 - padding.left, -offset - tickFont.size / 2 - padding.top, width + padding.width, tickFont.size + padding.height);\n }\n renderText(ctx, tick.label, 0, -offset, tickFont, {\n color: optsAtIndex.color,\n strokeColor: optsAtIndex.textStrokeColor,\n strokeWidth: optsAtIndex.textStrokeWidth\n });\n });\n ctx.restore();\n }\n drawTitle() {}\n}\n\nconst INTERVALS = {\n millisecond: {\n common: true,\n size: 1,\n steps: 1000\n },\n second: {\n common: true,\n size: 1000,\n steps: 60\n },\n minute: {\n common: true,\n size: 60000,\n steps: 60\n },\n hour: {\n common: true,\n size: 3600000,\n steps: 24\n },\n day: {\n common: true,\n size: 86400000,\n steps: 30\n },\n week: {\n common: false,\n size: 604800000,\n steps: 4\n },\n month: {\n common: true,\n size: 2.628e9,\n steps: 12\n },\n quarter: {\n common: false,\n size: 7.884e9,\n steps: 4\n },\n year: {\n common: true,\n size: 3.154e10\n }\n};\n const UNITS = /* #__PURE__ */ Object.keys(INTERVALS);\n function sorter(a, b) {\n return a - b;\n}\n function parse(scale, input) {\n if (isNullOrUndef(input)) {\n return null;\n }\n const adapter = scale._adapter;\n const { parser , round , isoWeekday } = scale._parseOpts;\n let value = input;\n if (typeof parser === 'function') {\n value = parser(value);\n }\n if (!isNumberFinite(value)) {\n value = typeof parser === 'string' ? adapter.parse(value, parser) : adapter.parse(value);\n }\n if (value === null) {\n return null;\n }\n if (round) {\n value = round === 'week' && (isNumber(isoWeekday) || isoWeekday === true) ? adapter.startOf(value, 'isoWeek', isoWeekday) : adapter.startOf(value, round);\n }\n return +value;\n}\n function determineUnitForAutoTicks(minUnit, min, max, capacity) {\n const ilen = UNITS.length;\n for(let i = UNITS.indexOf(minUnit); i < ilen - 1; ++i){\n const interval = INTERVALS[UNITS[i]];\n const factor = interval.steps ? interval.steps : Number.MAX_SAFE_INTEGER;\n if (interval.common && Math.ceil((max - min) / (factor * interval.size)) <= capacity) {\n return UNITS[i];\n }\n }\n return UNITS[ilen - 1];\n}\n function determineUnitForFormatting(scale, numTicks, minUnit, min, max) {\n for(let i = UNITS.length - 1; i >= UNITS.indexOf(minUnit); i--){\n const unit = UNITS[i];\n if (INTERVALS[unit].common && scale._adapter.diff(max, min, unit) >= numTicks - 1) {\n return unit;\n }\n }\n return UNITS[minUnit ? UNITS.indexOf(minUnit) : 0];\n}\n function determineMajorUnit(unit) {\n for(let i = UNITS.indexOf(unit) + 1, ilen = UNITS.length; i < ilen; ++i){\n if (INTERVALS[UNITS[i]].common) {\n return UNITS[i];\n }\n }\n}\n function addTick(ticks, time, timestamps) {\n if (!timestamps) {\n ticks[time] = true;\n } else if (timestamps.length) {\n const { lo , hi } = _lookup(timestamps, time);\n const timestamp = timestamps[lo] >= time ? timestamps[lo] : timestamps[hi];\n ticks[timestamp] = true;\n }\n}\n function setMajorTicks(scale, ticks, map, majorUnit) {\n const adapter = scale._adapter;\n const first = +adapter.startOf(ticks[0].value, majorUnit);\n const last = ticks[ticks.length - 1].value;\n let major, index;\n for(major = first; major <= last; major = +adapter.add(major, 1, majorUnit)){\n index = map[major];\n if (index >= 0) {\n ticks[index].major = true;\n }\n }\n return ticks;\n}\n function ticksFromTimestamps(scale, values, majorUnit) {\n const ticks = [];\n const map = {};\n const ilen = values.length;\n let i, value;\n for(i = 0; i < ilen; ++i){\n value = values[i];\n map[value] = i;\n ticks.push({\n value,\n major: false\n });\n }\n return ilen === 0 || !majorUnit ? ticks : setMajorTicks(scale, ticks, map, majorUnit);\n}\nclass TimeScale extends Scale {\n static id = 'time';\n static defaults = {\n bounds: 'data',\n adapters: {},\n time: {\n parser: false,\n unit: false,\n round: false,\n isoWeekday: false,\n minUnit: 'millisecond',\n displayFormats: {}\n },\n ticks: {\n source: 'auto',\n callback: false,\n major: {\n enabled: false\n }\n }\n };\n constructor(props){\n super(props);\n this._cache = {\n data: [],\n labels: [],\n all: []\n };\n this._unit = 'day';\n this._majorUnit = undefined;\n this._offsets = {};\n this._normalized = false;\n this._parseOpts = undefined;\n }\n init(scaleOpts, opts = {}) {\n const time = scaleOpts.time || (scaleOpts.time = {});\n const adapter = this._adapter = new adapters._date(scaleOpts.adapters.date);\n adapter.init(opts);\n mergeIf(time.displayFormats, adapter.formats());\n this._parseOpts = {\n parser: time.parser,\n round: time.round,\n isoWeekday: time.isoWeekday\n };\n super.init(scaleOpts);\n this._normalized = opts.normalized;\n }\n parse(raw, index) {\n if (raw === undefined) {\n return null;\n }\n return parse(this, raw);\n }\n beforeLayout() {\n super.beforeLayout();\n this._cache = {\n data: [],\n labels: [],\n all: []\n };\n }\n determineDataLimits() {\n const options = this.options;\n const adapter = this._adapter;\n const unit = options.time.unit || 'day';\n let { min , max , minDefined , maxDefined } = this.getUserBounds();\n function _applyBounds(bounds) {\n if (!minDefined && !isNaN(bounds.min)) {\n min = Math.min(min, bounds.min);\n }\n if (!maxDefined && !isNaN(bounds.max)) {\n max = Math.max(max, bounds.max);\n }\n }\n if (!minDefined || !maxDefined) {\n _applyBounds(this._getLabelBounds());\n if (options.bounds !== 'ticks' || options.ticks.source !== 'labels') {\n _applyBounds(this.getMinMax(false));\n }\n }\n min = isNumberFinite(min) && !isNaN(min) ? min : +adapter.startOf(Date.now(), unit);\n max = isNumberFinite(max) && !isNaN(max) ? max : +adapter.endOf(Date.now(), unit) + 1;\n this.min = Math.min(min, max - 1);\n this.max = Math.max(min + 1, max);\n }\n _getLabelBounds() {\n const arr = this.getLabelTimestamps();\n let min = Number.POSITIVE_INFINITY;\n let max = Number.NEGATIVE_INFINITY;\n if (arr.length) {\n min = arr[0];\n max = arr[arr.length - 1];\n }\n return {\n min,\n max\n };\n }\n buildTicks() {\n const options = this.options;\n const timeOpts = options.time;\n const tickOpts = options.ticks;\n const timestamps = tickOpts.source === 'labels' ? this.getLabelTimestamps() : this._generate();\n if (options.bounds === 'ticks' && timestamps.length) {\n this.min = this._userMin || timestamps[0];\n this.max = this._userMax || timestamps[timestamps.length - 1];\n }\n const min = this.min;\n const max = this.max;\n const ticks = _filterBetween(timestamps, min, max);\n this._unit = timeOpts.unit || (tickOpts.autoSkip ? determineUnitForAutoTicks(timeOpts.minUnit, this.min, this.max, this._getLabelCapacity(min)) : determineUnitForFormatting(this, ticks.length, timeOpts.minUnit, this.min, this.max));\n this._majorUnit = !tickOpts.major.enabled || this._unit === 'year' ? undefined : determineMajorUnit(this._unit);\n this.initOffsets(timestamps);\n if (options.reverse) {\n ticks.reverse();\n }\n return ticksFromTimestamps(this, ticks, this._majorUnit);\n }\n afterAutoSkip() {\n if (this.options.offsetAfterAutoskip) {\n this.initOffsets(this.ticks.map((tick)=>+tick.value));\n }\n }\n initOffsets(timestamps = []) {\n let start = 0;\n let end = 0;\n let first, last;\n if (this.options.offset && timestamps.length) {\n first = this.getDecimalForValue(timestamps[0]);\n if (timestamps.length === 1) {\n start = 1 - first;\n } else {\n start = (this.getDecimalForValue(timestamps[1]) - first) / 2;\n }\n last = this.getDecimalForValue(timestamps[timestamps.length - 1]);\n if (timestamps.length === 1) {\n end = last;\n } else {\n end = (last - this.getDecimalForValue(timestamps[timestamps.length - 2])) / 2;\n }\n }\n const limit = timestamps.length < 3 ? 0.5 : 0.25;\n start = _limitValue(start, 0, limit);\n end = _limitValue(end, 0, limit);\n this._offsets = {\n start,\n end,\n factor: 1 / (start + 1 + end)\n };\n }\n _generate() {\n const adapter = this._adapter;\n const min = this.min;\n const max = this.max;\n const options = this.options;\n const timeOpts = options.time;\n const minor = timeOpts.unit || determineUnitForAutoTicks(timeOpts.minUnit, min, max, this._getLabelCapacity(min));\n const stepSize = valueOrDefault(options.ticks.stepSize, 1);\n const weekday = minor === 'week' ? timeOpts.isoWeekday : false;\n const hasWeekday = isNumber(weekday) || weekday === true;\n const ticks = {};\n let first = min;\n let time, count;\n if (hasWeekday) {\n first = +adapter.startOf(first, 'isoWeek', weekday);\n }\n first = +adapter.startOf(first, hasWeekday ? 'day' : minor);\n if (adapter.diff(max, min, minor) > 100000 * stepSize) {\n throw new Error(min + ' and ' + max + ' are too far apart with stepSize of ' + stepSize + ' ' + minor);\n }\n const timestamps = options.ticks.source === 'data' && this.getDataTimestamps();\n for(time = first, count = 0; time < max; time = +adapter.add(time, stepSize, minor), count++){\n addTick(ticks, time, timestamps);\n }\n if (time === max || options.bounds === 'ticks' || count === 1) {\n addTick(ticks, time, timestamps);\n }\n return Object.keys(ticks).sort(sorter).map((x)=>+x);\n }\n getLabelForValue(value) {\n const adapter = this._adapter;\n const timeOpts = this.options.time;\n if (timeOpts.tooltipFormat) {\n return adapter.format(value, timeOpts.tooltipFormat);\n }\n return adapter.format(value, timeOpts.displayFormats.datetime);\n }\n format(value, format) {\n const options = this.options;\n const formats = options.time.displayFormats;\n const unit = this._unit;\n const fmt = format || formats[unit];\n return this._adapter.format(value, fmt);\n }\n _tickFormatFunction(time, index, ticks, format) {\n const options = this.options;\n const formatter = options.ticks.callback;\n if (formatter) {\n return callback(formatter, [\n time,\n index,\n ticks\n ], this);\n }\n const formats = options.time.displayFormats;\n const unit = this._unit;\n const majorUnit = this._majorUnit;\n const minorFormat = unit && formats[unit];\n const majorFormat = majorUnit && formats[majorUnit];\n const tick = ticks[index];\n const major = majorUnit && majorFormat && tick && tick.major;\n return this._adapter.format(time, format || (major ? majorFormat : minorFormat));\n }\n generateTickLabels(ticks) {\n let i, ilen, tick;\n for(i = 0, ilen = ticks.length; i < ilen; ++i){\n tick = ticks[i];\n tick.label = this._tickFormatFunction(tick.value, i, ticks);\n }\n }\n getDecimalForValue(value) {\n return value === null ? NaN : (value - this.min) / (this.max - this.min);\n }\n getPixelForValue(value) {\n const offsets = this._offsets;\n const pos = this.getDecimalForValue(value);\n return this.getPixelForDecimal((offsets.start + pos) * offsets.factor);\n }\n getValueForPixel(pixel) {\n const offsets = this._offsets;\n const pos = this.getDecimalForPixel(pixel) / offsets.factor - offsets.end;\n return this.min + pos * (this.max - this.min);\n }\n _getLabelSize(label) {\n const ticksOpts = this.options.ticks;\n const tickLabelWidth = this.ctx.measureText(label).width;\n const angle = toRadians(this.isHorizontal() ? ticksOpts.maxRotation : ticksOpts.minRotation);\n const cosRotation = Math.cos(angle);\n const sinRotation = Math.sin(angle);\n const tickFontSize = this._resolveTickFontOptions(0).size;\n return {\n w: tickLabelWidth * cosRotation + tickFontSize * sinRotation,\n h: tickLabelWidth * sinRotation + tickFontSize * cosRotation\n };\n }\n _getLabelCapacity(exampleTime) {\n const timeOpts = this.options.time;\n const displayFormats = timeOpts.displayFormats;\n const format = displayFormats[timeOpts.unit] || displayFormats.millisecond;\n const exampleLabel = this._tickFormatFunction(exampleTime, 0, ticksFromTimestamps(this, [\n exampleTime\n ], this._majorUnit), format);\n const size = this._getLabelSize(exampleLabel);\n const capacity = Math.floor(this.isHorizontal() ? this.width / size.w : this.height / size.h) - 1;\n return capacity > 0 ? capacity : 1;\n }\n getDataTimestamps() {\n let timestamps = this._cache.data || [];\n let i, ilen;\n if (timestamps.length) {\n return timestamps;\n }\n const metas = this.getMatchingVisibleMetas();\n if (this._normalized && metas.length) {\n return this._cache.data = metas[0].controller.getAllParsedValues(this);\n }\n for(i = 0, ilen = metas.length; i < ilen; ++i){\n timestamps = timestamps.concat(metas[i].controller.getAllParsedValues(this));\n }\n return this._cache.data = this.normalize(timestamps);\n }\n getLabelTimestamps() {\n const timestamps = this._cache.labels || [];\n let i, ilen;\n if (timestamps.length) {\n return timestamps;\n }\n const labels = this.getLabels();\n for(i = 0, ilen = labels.length; i < ilen; ++i){\n timestamps.push(parse(this, labels[i]));\n }\n return this._cache.labels = this._normalized ? timestamps : this.normalize(timestamps);\n }\n normalize(values) {\n return _arrayUnique(values.sort(sorter));\n }\n}\n\nfunction chart_interpolate(table, val, reverse) {\n let lo = 0;\n let hi = table.length - 1;\n let prevSource, nextSource, prevTarget, nextTarget;\n if (reverse) {\n if (val >= table[lo].pos && val <= table[hi].pos) {\n ({ lo , hi } = _lookupByKey(table, 'pos', val));\n }\n ({ pos: prevSource , time: prevTarget } = table[lo]);\n ({ pos: nextSource , time: nextTarget } = table[hi]);\n } else {\n if (val >= table[lo].time && val <= table[hi].time) {\n ({ lo , hi } = _lookupByKey(table, 'time', val));\n }\n ({ time: prevSource , pos: prevTarget } = table[lo]);\n ({ time: nextSource , pos: nextTarget } = table[hi]);\n }\n const span = nextSource - prevSource;\n return span ? prevTarget + (nextTarget - prevTarget) * (val - prevSource) / span : prevTarget;\n}\nclass TimeSeriesScale extends TimeScale {\n static id = 'timeseries';\n static defaults = TimeScale.defaults;\n constructor(props){\n super(props);\n this._table = [];\n this._minPos = undefined;\n this._tableRange = undefined;\n }\n initOffsets() {\n const timestamps = this._getTimestampsForTable();\n const table = this._table = this.buildLookupTable(timestamps);\n this._minPos = chart_interpolate(table, this.min);\n this._tableRange = chart_interpolate(table, this.max) - this._minPos;\n super.initOffsets(timestamps);\n }\n buildLookupTable(timestamps) {\n const { min , max } = this;\n const items = [];\n const table = [];\n let i, ilen, prev, curr, next;\n for(i = 0, ilen = timestamps.length; i < ilen; ++i){\n curr = timestamps[i];\n if (curr >= min && curr <= max) {\n items.push(curr);\n }\n }\n if (items.length < 2) {\n return [\n {\n time: min,\n pos: 0\n },\n {\n time: max,\n pos: 1\n }\n ];\n }\n for(i = 0, ilen = items.length; i < ilen; ++i){\n next = items[i + 1];\n prev = items[i - 1];\n curr = items[i];\n if (Math.round((next + prev) / 2) !== curr) {\n table.push({\n time: curr,\n pos: i / (ilen - 1)\n });\n }\n }\n return table;\n }\n _generate() {\n const min = this.min;\n const max = this.max;\n let timestamps = super.getDataTimestamps();\n if (!timestamps.includes(min) || !timestamps.length) {\n timestamps.splice(0, 0, min);\n }\n if (!timestamps.includes(max) || timestamps.length === 1) {\n timestamps.push(max);\n }\n return timestamps.sort((a, b)=>a - b);\n }\n _getTimestampsForTable() {\n let timestamps = this._cache.all || [];\n if (timestamps.length) {\n return timestamps;\n }\n const data = this.getDataTimestamps();\n const label = this.getLabelTimestamps();\n if (data.length && label.length) {\n timestamps = this.normalize(data.concat(label));\n } else {\n timestamps = data.length ? data : label;\n }\n timestamps = this._cache.all = timestamps;\n return timestamps;\n }\n getDecimalForValue(value) {\n return (chart_interpolate(this._table, value) - this._minPos) / this._tableRange;\n }\n getValueForPixel(pixel) {\n const offsets = this._offsets;\n const decimal = this.getDecimalForPixel(pixel) / offsets.factor - offsets.end;\n return chart_interpolate(this._table, decimal * this._tableRange + this._minPos, true);\n }\n}\n\nvar scales = /*#__PURE__*/Object.freeze({\n__proto__: null,\nCategoryScale: CategoryScale,\nLinearScale: LinearScale,\nLogarithmicScale: LogarithmicScale,\nRadialLinearScale: RadialLinearScale,\nTimeScale: TimeScale,\nTimeSeriesScale: TimeSeriesScale\n});\n\nconst registerables = [\n controllers,\n chart_elements,\n plugins,\n scales\n];\n\n\n//# sourceMappingURL=chart.js.map\n\n;// ./node_modules/chart.js/auto/auto.js\n\n\nchart_Chart.register(...registerables);\n\n\n/* harmony default export */ const auto = ((/* unused pure expression or super */ null && (Chart)));\n\n// EXTERNAL MODULE: ./node_modules/nette-forms/src/assets/netteForms.js\nvar netteForms = __webpack_require__(53);\nvar netteForms_default = /*#__PURE__*/__webpack_require__.n(netteForms);\n// EXTERNAL MODULE: ./vendor/nasext/dependent-select-box/client-side/dependentSelectBox.js\nvar dependentSelectBox = __webpack_require__(566);\n// EXTERNAL MODULE: ./node_modules/nette.ajax.js/nette.ajax.js\nvar nette_ajax = __webpack_require__(612);\n// EXTERNAL MODULE: ./node_modules/adt-nette-ajax/extensions/live.js\nvar live = __webpack_require__(123);\n// EXTERNAL MODULE: ./assets/js/toggleMenu.js\nvar toggleMenu = __webpack_require__(425);\n// EXTERNAL MODULE: ./assets/js/history.ajax.js\nvar history_ajax = __webpack_require__(82);\n// EXTERNAL MODULE: ./node_modules/daterangepicker/daterangepicker.js\nvar daterangepicker = __webpack_require__(335);\n;// ./node_modules/@popperjs/core/lib/enums.js\nvar enums_top = 'top';\nvar bottom = 'bottom';\nvar right = 'right';\nvar left = 'left';\nvar enums_auto = 'auto';\nvar basePlacements = [enums_top, bottom, right, left];\nvar start = 'start';\nvar end = 'end';\nvar clippingParents = 'clippingParents';\nvar viewport = 'viewport';\nvar popper = 'popper';\nvar reference = 'reference';\nvar variationPlacements = /*#__PURE__*/basePlacements.reduce(function (acc, placement) {\n return acc.concat([placement + \"-\" + start, placement + \"-\" + end]);\n}, []);\nvar enums_placements = /*#__PURE__*/[].concat(basePlacements, [enums_auto]).reduce(function (acc, placement) {\n return acc.concat([placement, placement + \"-\" + start, placement + \"-\" + end]);\n}, []); // modifiers that need to read the DOM\n\nvar beforeRead = 'beforeRead';\nvar read = 'read';\nvar afterRead = 'afterRead'; // pure-logic modifiers\n\nvar beforeMain = 'beforeMain';\nvar main = 'main';\nvar afterMain = 'afterMain'; // modifier with the purpose to write to the DOM (or write into a framework state)\n\nvar beforeWrite = 'beforeWrite';\nvar write = 'write';\nvar afterWrite = 'afterWrite';\nvar modifierPhases = [beforeRead, read, afterRead, beforeMain, main, afterMain, beforeWrite, write, afterWrite];\n;// ./node_modules/@popperjs/core/lib/dom-utils/getNodeName.js\nfunction getNodeName(element) {\n return element ? (element.nodeName || '').toLowerCase() : null;\n}\n;// ./node_modules/@popperjs/core/lib/dom-utils/getWindow.js\nfunction getWindow(node) {\n if (node == null) {\n return window;\n }\n\n if (node.toString() !== '[object Window]') {\n var ownerDocument = node.ownerDocument;\n return ownerDocument ? ownerDocument.defaultView || window : window;\n }\n\n return node;\n}\n;// ./node_modules/@popperjs/core/lib/dom-utils/instanceOf.js\n\n\nfunction isElement(node) {\n var OwnElement = getWindow(node).Element;\n return node instanceof OwnElement || node instanceof Element;\n}\n\nfunction isHTMLElement(node) {\n var OwnElement = getWindow(node).HTMLElement;\n return node instanceof OwnElement || node instanceof HTMLElement;\n}\n\nfunction isShadowRoot(node) {\n // IE 11 has no ShadowRoot\n if (typeof ShadowRoot === 'undefined') {\n return false;\n }\n\n var OwnElement = getWindow(node).ShadowRoot;\n return node instanceof OwnElement || node instanceof ShadowRoot;\n}\n\n\n;// ./node_modules/@popperjs/core/lib/modifiers/applyStyles.js\n\n // This modifier takes the styles prepared by the `computeStyles` modifier\n// and applies them to the HTMLElements such as popper and arrow\n\nfunction applyStyles(_ref) {\n var state = _ref.state;\n Object.keys(state.elements).forEach(function (name) {\n var style = state.styles[name] || {};\n var attributes = state.attributes[name] || {};\n var element = state.elements[name]; // arrow is optional + virtual elements\n\n if (!isHTMLElement(element) || !getNodeName(element)) {\n return;\n } // Flow doesn't support to extend this property, but it's the most\n // effective way to apply styles to an HTMLElement\n // $FlowFixMe[cannot-write]\n\n\n Object.assign(element.style, style);\n Object.keys(attributes).forEach(function (name) {\n var value = attributes[name];\n\n if (value === false) {\n element.removeAttribute(name);\n } else {\n element.setAttribute(name, value === true ? '' : value);\n }\n });\n });\n}\n\nfunction effect(_ref2) {\n var state = _ref2.state;\n var initialStyles = {\n popper: {\n position: state.options.strategy,\n left: '0',\n top: '0',\n margin: '0'\n },\n arrow: {\n position: 'absolute'\n },\n reference: {}\n };\n Object.assign(state.elements.popper.style, initialStyles.popper);\n state.styles = initialStyles;\n\n if (state.elements.arrow) {\n Object.assign(state.elements.arrow.style, initialStyles.arrow);\n }\n\n return function () {\n Object.keys(state.elements).forEach(function (name) {\n var element = state.elements[name];\n var attributes = state.attributes[name] || {};\n var styleProperties = Object.keys(state.styles.hasOwnProperty(name) ? state.styles[name] : initialStyles[name]); // Set all values to an empty string to unset them\n\n var style = styleProperties.reduce(function (style, property) {\n style[property] = '';\n return style;\n }, {}); // arrow is optional + virtual elements\n\n if (!isHTMLElement(element) || !getNodeName(element)) {\n return;\n }\n\n Object.assign(element.style, style);\n Object.keys(attributes).forEach(function (attribute) {\n element.removeAttribute(attribute);\n });\n });\n };\n} // eslint-disable-next-line import/no-unused-modules\n\n\n/* harmony default export */ const modifiers_applyStyles = ({\n name: 'applyStyles',\n enabled: true,\n phase: 'write',\n fn: applyStyles,\n effect: effect,\n requires: ['computeStyles']\n});\n;// ./node_modules/@popperjs/core/lib/utils/getBasePlacement.js\n\nfunction getBasePlacement(placement) {\n return placement.split('-')[0];\n}\n;// ./node_modules/@popperjs/core/lib/utils/math.js\nvar math_max = Math.max;\nvar math_min = Math.min;\nvar math_round = Math.round;\n;// ./node_modules/@popperjs/core/lib/utils/userAgent.js\nfunction getUAString() {\n var uaData = navigator.userAgentData;\n\n if (uaData != null && uaData.brands && Array.isArray(uaData.brands)) {\n return uaData.brands.map(function (item) {\n return item.brand + \"/\" + item.version;\n }).join(' ');\n }\n\n return navigator.userAgent;\n}\n;// ./node_modules/@popperjs/core/lib/dom-utils/isLayoutViewport.js\n\nfunction isLayoutViewport() {\n return !/^((?!chrome|android).)*safari/i.test(getUAString());\n}\n;// ./node_modules/@popperjs/core/lib/dom-utils/getBoundingClientRect.js\n\n\n\n\nfunction getBoundingClientRect(element, includeScale, isFixedStrategy) {\n if (includeScale === void 0) {\n includeScale = false;\n }\n\n if (isFixedStrategy === void 0) {\n isFixedStrategy = false;\n }\n\n var clientRect = element.getBoundingClientRect();\n var scaleX = 1;\n var scaleY = 1;\n\n if (includeScale && isHTMLElement(element)) {\n scaleX = element.offsetWidth > 0 ? math_round(clientRect.width) / element.offsetWidth || 1 : 1;\n scaleY = element.offsetHeight > 0 ? math_round(clientRect.height) / element.offsetHeight || 1 : 1;\n }\n\n var _ref = isElement(element) ? getWindow(element) : window,\n visualViewport = _ref.visualViewport;\n\n var addVisualOffsets = !isLayoutViewport() && isFixedStrategy;\n var x = (clientRect.left + (addVisualOffsets && visualViewport ? visualViewport.offsetLeft : 0)) / scaleX;\n var y = (clientRect.top + (addVisualOffsets && visualViewport ? visualViewport.offsetTop : 0)) / scaleY;\n var width = clientRect.width / scaleX;\n var height = clientRect.height / scaleY;\n return {\n width: width,\n height: height,\n top: y,\n right: x + width,\n bottom: y + height,\n left: x,\n x: x,\n y: y\n };\n}\n;// ./node_modules/@popperjs/core/lib/dom-utils/getLayoutRect.js\n // Returns the layout rect of an element relative to its offsetParent. Layout\n// means it doesn't take into account transforms.\n\nfunction getLayoutRect(element) {\n var clientRect = getBoundingClientRect(element); // Use the clientRect sizes if it's not been transformed.\n // Fixes https://github.com/popperjs/popper-core/issues/1223\n\n var width = element.offsetWidth;\n var height = element.offsetHeight;\n\n if (Math.abs(clientRect.width - width) <= 1) {\n width = clientRect.width;\n }\n\n if (Math.abs(clientRect.height - height) <= 1) {\n height = clientRect.height;\n }\n\n return {\n x: element.offsetLeft,\n y: element.offsetTop,\n width: width,\n height: height\n };\n}\n;// ./node_modules/@popperjs/core/lib/dom-utils/contains.js\n\nfunction contains(parent, child) {\n var rootNode = child.getRootNode && child.getRootNode(); // First, attempt with faster native method\n\n if (parent.contains(child)) {\n return true;\n } // then fallback to custom implementation with Shadow DOM support\n else if (rootNode && isShadowRoot(rootNode)) {\n var next = child;\n\n do {\n if (next && parent.isSameNode(next)) {\n return true;\n } // $FlowFixMe[prop-missing]: need a better way to handle this...\n\n\n next = next.parentNode || next.host;\n } while (next);\n } // Give up, the result is false\n\n\n return false;\n}\n;// ./node_modules/@popperjs/core/lib/dom-utils/getComputedStyle.js\n\nfunction getComputedStyle_getComputedStyle(element) {\n return getWindow(element).getComputedStyle(element);\n}\n;// ./node_modules/@popperjs/core/lib/dom-utils/isTableElement.js\n\nfunction isTableElement(element) {\n return ['table', 'td', 'th'].indexOf(getNodeName(element)) >= 0;\n}\n;// ./node_modules/@popperjs/core/lib/dom-utils/getDocumentElement.js\n\nfunction getDocumentElement(element) {\n // $FlowFixMe[incompatible-return]: assume body is always available\n return ((isElement(element) ? element.ownerDocument : // $FlowFixMe[prop-missing]\n element.document) || window.document).documentElement;\n}\n;// ./node_modules/@popperjs/core/lib/dom-utils/getParentNode.js\n\n\n\nfunction getParentNode(element) {\n if (getNodeName(element) === 'html') {\n return element;\n }\n\n return (// this is a quicker (but less type safe) way to save quite some bytes from the bundle\n // $FlowFixMe[incompatible-return]\n // $FlowFixMe[prop-missing]\n element.assignedSlot || // step into the shadow DOM of the parent of a slotted node\n element.parentNode || ( // DOM Element detected\n isShadowRoot(element) ? element.host : null) || // ShadowRoot detected\n // $FlowFixMe[incompatible-call]: HTMLElement is a Node\n getDocumentElement(element) // fallback\n\n );\n}\n;// ./node_modules/@popperjs/core/lib/dom-utils/getOffsetParent.js\n\n\n\n\n\n\n\n\nfunction getTrueOffsetParent(element) {\n if (!isHTMLElement(element) || // https://github.com/popperjs/popper-core/issues/837\n getComputedStyle_getComputedStyle(element).position === 'fixed') {\n return null;\n }\n\n return element.offsetParent;\n} // `.offsetParent` reports `null` for fixed elements, while absolute elements\n// return the containing block\n\n\nfunction getContainingBlock(element) {\n var isFirefox = /firefox/i.test(getUAString());\n var isIE = /Trident/i.test(getUAString());\n\n if (isIE && isHTMLElement(element)) {\n // In IE 9, 10 and 11 fixed elements containing block is always established by the viewport\n var elementCss = getComputedStyle_getComputedStyle(element);\n\n if (elementCss.position === 'fixed') {\n return null;\n }\n }\n\n var currentNode = getParentNode(element);\n\n if (isShadowRoot(currentNode)) {\n currentNode = currentNode.host;\n }\n\n while (isHTMLElement(currentNode) && ['html', 'body'].indexOf(getNodeName(currentNode)) < 0) {\n var css = getComputedStyle_getComputedStyle(currentNode); // This is non-exhaustive but covers the most common CSS properties that\n // create a containing block.\n // https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#identifying_the_containing_block\n\n if (css.transform !== 'none' || css.perspective !== 'none' || css.contain === 'paint' || ['transform', 'perspective'].indexOf(css.willChange) !== -1 || isFirefox && css.willChange === 'filter' || isFirefox && css.filter && css.filter !== 'none') {\n return currentNode;\n } else {\n currentNode = currentNode.parentNode;\n }\n }\n\n return null;\n} // Gets the closest ancestor positioned element. Handles some edge cases,\n// such as table ancestors and cross browser bugs.\n\n\nfunction getOffsetParent(element) {\n var window = getWindow(element);\n var offsetParent = getTrueOffsetParent(element);\n\n while (offsetParent && isTableElement(offsetParent) && getComputedStyle_getComputedStyle(offsetParent).position === 'static') {\n offsetParent = getTrueOffsetParent(offsetParent);\n }\n\n if (offsetParent && (getNodeName(offsetParent) === 'html' || getNodeName(offsetParent) === 'body' && getComputedStyle_getComputedStyle(offsetParent).position === 'static')) {\n return window;\n }\n\n return offsetParent || getContainingBlock(element) || window;\n}\n;// ./node_modules/@popperjs/core/lib/utils/getMainAxisFromPlacement.js\nfunction getMainAxisFromPlacement(placement) {\n return ['top', 'bottom'].indexOf(placement) >= 0 ? 'x' : 'y';\n}\n;// ./node_modules/@popperjs/core/lib/utils/within.js\n\nfunction within(min, value, max) {\n return math_max(min, math_min(value, max));\n}\nfunction withinMaxClamp(min, value, max) {\n var v = within(min, value, max);\n return v > max ? max : v;\n}\n;// ./node_modules/@popperjs/core/lib/utils/getFreshSideObject.js\nfunction getFreshSideObject() {\n return {\n top: 0,\n right: 0,\n bottom: 0,\n left: 0\n };\n}\n;// ./node_modules/@popperjs/core/lib/utils/mergePaddingObject.js\n\nfunction mergePaddingObject(paddingObject) {\n return Object.assign({}, getFreshSideObject(), paddingObject);\n}\n;// ./node_modules/@popperjs/core/lib/utils/expandToHashMap.js\nfunction expandToHashMap(value, keys) {\n return keys.reduce(function (hashMap, key) {\n hashMap[key] = value;\n return hashMap;\n }, {});\n}\n;// ./node_modules/@popperjs/core/lib/modifiers/arrow.js\n\n\n\n\n\n\n\n\n // eslint-disable-next-line import/no-unused-modules\n\nvar toPaddingObject = function toPaddingObject(padding, state) {\n padding = typeof padding === 'function' ? padding(Object.assign({}, state.rects, {\n placement: state.placement\n })) : padding;\n return mergePaddingObject(typeof padding !== 'number' ? padding : expandToHashMap(padding, basePlacements));\n};\n\nfunction arrow(_ref) {\n var _state$modifiersData$;\n\n var state = _ref.state,\n name = _ref.name,\n options = _ref.options;\n var arrowElement = state.elements.arrow;\n var popperOffsets = state.modifiersData.popperOffsets;\n var basePlacement = getBasePlacement(state.placement);\n var axis = getMainAxisFromPlacement(basePlacement);\n var isVertical = [left, right].indexOf(basePlacement) >= 0;\n var len = isVertical ? 'height' : 'width';\n\n if (!arrowElement || !popperOffsets) {\n return;\n }\n\n var paddingObject = toPaddingObject(options.padding, state);\n var arrowRect = getLayoutRect(arrowElement);\n var minProp = axis === 'y' ? enums_top : left;\n var maxProp = axis === 'y' ? bottom : right;\n var endDiff = state.rects.reference[len] + state.rects.reference[axis] - popperOffsets[axis] - state.rects.popper[len];\n var startDiff = popperOffsets[axis] - state.rects.reference[axis];\n var arrowOffsetParent = getOffsetParent(arrowElement);\n var clientSize = arrowOffsetParent ? axis === 'y' ? arrowOffsetParent.clientHeight || 0 : arrowOffsetParent.clientWidth || 0 : 0;\n var centerToReference = endDiff / 2 - startDiff / 2; // Make sure the arrow doesn't overflow the popper if the center point is\n // outside of the popper bounds\n\n var min = paddingObject[minProp];\n var max = clientSize - arrowRect[len] - paddingObject[maxProp];\n var center = clientSize / 2 - arrowRect[len] / 2 + centerToReference;\n var offset = within(min, center, max); // Prevents breaking syntax highlighting...\n\n var axisProp = axis;\n state.modifiersData[name] = (_state$modifiersData$ = {}, _state$modifiersData$[axisProp] = offset, _state$modifiersData$.centerOffset = offset - center, _state$modifiersData$);\n}\n\nfunction arrow_effect(_ref2) {\n var state = _ref2.state,\n options = _ref2.options;\n var _options$element = options.element,\n arrowElement = _options$element === void 0 ? '[data-popper-arrow]' : _options$element;\n\n if (arrowElement == null) {\n return;\n } // CSS selector\n\n\n if (typeof arrowElement === 'string') {\n arrowElement = state.elements.popper.querySelector(arrowElement);\n\n if (!arrowElement) {\n return;\n }\n }\n\n if (!contains(state.elements.popper, arrowElement)) {\n return;\n }\n\n state.elements.arrow = arrowElement;\n} // eslint-disable-next-line import/no-unused-modules\n\n\n/* harmony default export */ const modifiers_arrow = ({\n name: 'arrow',\n enabled: true,\n phase: 'main',\n fn: arrow,\n effect: arrow_effect,\n requires: ['popperOffsets'],\n requiresIfExists: ['preventOverflow']\n});\n;// ./node_modules/@popperjs/core/lib/utils/getVariation.js\nfunction getVariation(placement) {\n return placement.split('-')[1];\n}\n;// ./node_modules/@popperjs/core/lib/modifiers/computeStyles.js\n\n\n\n\n\n\n\n // eslint-disable-next-line import/no-unused-modules\n\nvar unsetSides = {\n top: 'auto',\n right: 'auto',\n bottom: 'auto',\n left: 'auto'\n}; // Round the offsets to the nearest suitable subpixel based on the DPR.\n// Zooming can change the DPR, but it seems to report a value that will\n// cleanly divide the values into the appropriate subpixels.\n\nfunction roundOffsetsByDPR(_ref, win) {\n var x = _ref.x,\n y = _ref.y;\n var dpr = win.devicePixelRatio || 1;\n return {\n x: math_round(x * dpr) / dpr || 0,\n y: math_round(y * dpr) / dpr || 0\n };\n}\n\nfunction mapToStyles(_ref2) {\n var _Object$assign2;\n\n var popper = _ref2.popper,\n popperRect = _ref2.popperRect,\n placement = _ref2.placement,\n variation = _ref2.variation,\n offsets = _ref2.offsets,\n position = _ref2.position,\n gpuAcceleration = _ref2.gpuAcceleration,\n adaptive = _ref2.adaptive,\n roundOffsets = _ref2.roundOffsets,\n isFixed = _ref2.isFixed;\n var _offsets$x = offsets.x,\n x = _offsets$x === void 0 ? 0 : _offsets$x,\n _offsets$y = offsets.y,\n y = _offsets$y === void 0 ? 0 : _offsets$y;\n\n var _ref3 = typeof roundOffsets === 'function' ? roundOffsets({\n x: x,\n y: y\n }) : {\n x: x,\n y: y\n };\n\n x = _ref3.x;\n y = _ref3.y;\n var hasX = offsets.hasOwnProperty('x');\n var hasY = offsets.hasOwnProperty('y');\n var sideX = left;\n var sideY = enums_top;\n var win = window;\n\n if (adaptive) {\n var offsetParent = getOffsetParent(popper);\n var heightProp = 'clientHeight';\n var widthProp = 'clientWidth';\n\n if (offsetParent === getWindow(popper)) {\n offsetParent = getDocumentElement(popper);\n\n if (getComputedStyle_getComputedStyle(offsetParent).position !== 'static' && position === 'absolute') {\n heightProp = 'scrollHeight';\n widthProp = 'scrollWidth';\n }\n } // $FlowFixMe[incompatible-cast]: force type refinement, we compare offsetParent with window above, but Flow doesn't detect it\n\n\n offsetParent = offsetParent;\n\n if (placement === enums_top || (placement === left || placement === right) && variation === end) {\n sideY = bottom;\n var offsetY = isFixed && offsetParent === win && win.visualViewport ? win.visualViewport.height : // $FlowFixMe[prop-missing]\n offsetParent[heightProp];\n y -= offsetY - popperRect.height;\n y *= gpuAcceleration ? 1 : -1;\n }\n\n if (placement === left || (placement === enums_top || placement === bottom) && variation === end) {\n sideX = right;\n var offsetX = isFixed && offsetParent === win && win.visualViewport ? win.visualViewport.width : // $FlowFixMe[prop-missing]\n offsetParent[widthProp];\n x -= offsetX - popperRect.width;\n x *= gpuAcceleration ? 1 : -1;\n }\n }\n\n var commonStyles = Object.assign({\n position: position\n }, adaptive && unsetSides);\n\n var _ref4 = roundOffsets === true ? roundOffsetsByDPR({\n x: x,\n y: y\n }, getWindow(popper)) : {\n x: x,\n y: y\n };\n\n x = _ref4.x;\n y = _ref4.y;\n\n if (gpuAcceleration) {\n var _Object$assign;\n\n return Object.assign({}, commonStyles, (_Object$assign = {}, _Object$assign[sideY] = hasY ? '0' : '', _Object$assign[sideX] = hasX ? '0' : '', _Object$assign.transform = (win.devicePixelRatio || 1) <= 1 ? \"translate(\" + x + \"px, \" + y + \"px)\" : \"translate3d(\" + x + \"px, \" + y + \"px, 0)\", _Object$assign));\n }\n\n return Object.assign({}, commonStyles, (_Object$assign2 = {}, _Object$assign2[sideY] = hasY ? y + \"px\" : '', _Object$assign2[sideX] = hasX ? x + \"px\" : '', _Object$assign2.transform = '', _Object$assign2));\n}\n\nfunction computeStyles(_ref5) {\n var state = _ref5.state,\n options = _ref5.options;\n var _options$gpuAccelerat = options.gpuAcceleration,\n gpuAcceleration = _options$gpuAccelerat === void 0 ? true : _options$gpuAccelerat,\n _options$adaptive = options.adaptive,\n adaptive = _options$adaptive === void 0 ? true : _options$adaptive,\n _options$roundOffsets = options.roundOffsets,\n roundOffsets = _options$roundOffsets === void 0 ? true : _options$roundOffsets;\n var commonStyles = {\n placement: getBasePlacement(state.placement),\n variation: getVariation(state.placement),\n popper: state.elements.popper,\n popperRect: state.rects.popper,\n gpuAcceleration: gpuAcceleration,\n isFixed: state.options.strategy === 'fixed'\n };\n\n if (state.modifiersData.popperOffsets != null) {\n state.styles.popper = Object.assign({}, state.styles.popper, mapToStyles(Object.assign({}, commonStyles, {\n offsets: state.modifiersData.popperOffsets,\n position: state.options.strategy,\n adaptive: adaptive,\n roundOffsets: roundOffsets\n })));\n }\n\n if (state.modifiersData.arrow != null) {\n state.styles.arrow = Object.assign({}, state.styles.arrow, mapToStyles(Object.assign({}, commonStyles, {\n offsets: state.modifiersData.arrow,\n position: 'absolute',\n adaptive: false,\n roundOffsets: roundOffsets\n })));\n }\n\n state.attributes.popper = Object.assign({}, state.attributes.popper, {\n 'data-popper-placement': state.placement\n });\n} // eslint-disable-next-line import/no-unused-modules\n\n\n/* harmony default export */ const modifiers_computeStyles = ({\n name: 'computeStyles',\n enabled: true,\n phase: 'beforeWrite',\n fn: computeStyles,\n data: {}\n});\n;// ./node_modules/@popperjs/core/lib/modifiers/eventListeners.js\n // eslint-disable-next-line import/no-unused-modules\n\nvar passive = {\n passive: true\n};\n\nfunction eventListeners_effect(_ref) {\n var state = _ref.state,\n instance = _ref.instance,\n options = _ref.options;\n var _options$scroll = options.scroll,\n scroll = _options$scroll === void 0 ? true : _options$scroll,\n _options$resize = options.resize,\n resize = _options$resize === void 0 ? true : _options$resize;\n var window = getWindow(state.elements.popper);\n var scrollParents = [].concat(state.scrollParents.reference, state.scrollParents.popper);\n\n if (scroll) {\n scrollParents.forEach(function (scrollParent) {\n scrollParent.addEventListener('scroll', instance.update, passive);\n });\n }\n\n if (resize) {\n window.addEventListener('resize', instance.update, passive);\n }\n\n return function () {\n if (scroll) {\n scrollParents.forEach(function (scrollParent) {\n scrollParent.removeEventListener('scroll', instance.update, passive);\n });\n }\n\n if (resize) {\n window.removeEventListener('resize', instance.update, passive);\n }\n };\n} // eslint-disable-next-line import/no-unused-modules\n\n\n/* harmony default export */ const eventListeners = ({\n name: 'eventListeners',\n enabled: true,\n phase: 'write',\n fn: function fn() {},\n effect: eventListeners_effect,\n data: {}\n});\n;// ./node_modules/@popperjs/core/lib/utils/getOppositePlacement.js\nvar hash = {\n left: 'right',\n right: 'left',\n bottom: 'top',\n top: 'bottom'\n};\nfunction getOppositePlacement(placement) {\n return placement.replace(/left|right|bottom|top/g, function (matched) {\n return hash[matched];\n });\n}\n;// ./node_modules/@popperjs/core/lib/utils/getOppositeVariationPlacement.js\nvar getOppositeVariationPlacement_hash = {\n start: 'end',\n end: 'start'\n};\nfunction getOppositeVariationPlacement(placement) {\n return placement.replace(/start|end/g, function (matched) {\n return getOppositeVariationPlacement_hash[matched];\n });\n}\n;// ./node_modules/@popperjs/core/lib/dom-utils/getWindowScroll.js\n\nfunction getWindowScroll(node) {\n var win = getWindow(node);\n var scrollLeft = win.pageXOffset;\n var scrollTop = win.pageYOffset;\n return {\n scrollLeft: scrollLeft,\n scrollTop: scrollTop\n };\n}\n;// ./node_modules/@popperjs/core/lib/dom-utils/getWindowScrollBarX.js\n\n\n\nfunction getWindowScrollBarX(element) {\n // If has a CSS width greater than the viewport, then this will be\n // incorrect for RTL.\n // Popper 1 is broken in this case and never had a bug report so let's assume\n // it's not an issue. I don't think anyone ever specifies width on \n // anyway.\n // Browsers where the left scrollbar doesn't cause an issue report `0` for\n // this (e.g. Edge 2019, IE11, Safari)\n return getBoundingClientRect(getDocumentElement(element)).left + getWindowScroll(element).scrollLeft;\n}\n;// ./node_modules/@popperjs/core/lib/dom-utils/getViewportRect.js\n\n\n\n\nfunction getViewportRect(element, strategy) {\n var win = getWindow(element);\n var html = getDocumentElement(element);\n var visualViewport = win.visualViewport;\n var width = html.clientWidth;\n var height = html.clientHeight;\n var x = 0;\n var y = 0;\n\n if (visualViewport) {\n width = visualViewport.width;\n height = visualViewport.height;\n var layoutViewport = isLayoutViewport();\n\n if (layoutViewport || !layoutViewport && strategy === 'fixed') {\n x = visualViewport.offsetLeft;\n y = visualViewport.offsetTop;\n }\n }\n\n return {\n width: width,\n height: height,\n x: x + getWindowScrollBarX(element),\n y: y\n };\n}\n;// ./node_modules/@popperjs/core/lib/dom-utils/getDocumentRect.js\n\n\n\n\n // Gets the entire size of the scrollable document area, even extending outside\n// of the `` and `` rect bounds if horizontally scrollable\n\nfunction getDocumentRect(element) {\n var _element$ownerDocumen;\n\n var html = getDocumentElement(element);\n var winScroll = getWindowScroll(element);\n var body = (_element$ownerDocumen = element.ownerDocument) == null ? void 0 : _element$ownerDocumen.body;\n var width = math_max(html.scrollWidth, html.clientWidth, body ? body.scrollWidth : 0, body ? body.clientWidth : 0);\n var height = math_max(html.scrollHeight, html.clientHeight, body ? body.scrollHeight : 0, body ? body.clientHeight : 0);\n var x = -winScroll.scrollLeft + getWindowScrollBarX(element);\n var y = -winScroll.scrollTop;\n\n if (getComputedStyle_getComputedStyle(body || html).direction === 'rtl') {\n x += math_max(html.clientWidth, body ? body.clientWidth : 0) - width;\n }\n\n return {\n width: width,\n height: height,\n x: x,\n y: y\n };\n}\n;// ./node_modules/@popperjs/core/lib/dom-utils/isScrollParent.js\n\nfunction isScrollParent(element) {\n // Firefox wants us to check `-x` and `-y` variations as well\n var _getComputedStyle = getComputedStyle_getComputedStyle(element),\n overflow = _getComputedStyle.overflow,\n overflowX = _getComputedStyle.overflowX,\n overflowY = _getComputedStyle.overflowY;\n\n return /auto|scroll|overlay|hidden/.test(overflow + overflowY + overflowX);\n}\n;// ./node_modules/@popperjs/core/lib/dom-utils/getScrollParent.js\n\n\n\n\nfunction getScrollParent(node) {\n if (['html', 'body', '#document'].indexOf(getNodeName(node)) >= 0) {\n // $FlowFixMe[incompatible-return]: assume body is always available\n return node.ownerDocument.body;\n }\n\n if (isHTMLElement(node) && isScrollParent(node)) {\n return node;\n }\n\n return getScrollParent(getParentNode(node));\n}\n;// ./node_modules/@popperjs/core/lib/dom-utils/listScrollParents.js\n\n\n\n\n/*\ngiven a DOM element, return the list of all scroll parents, up the list of ancesors\nuntil we get to the top window object. This list is what we attach scroll listeners\nto, because if any of these parent elements scroll, we'll need to re-calculate the\nreference element's position.\n*/\n\nfunction listScrollParents(element, list) {\n var _element$ownerDocumen;\n\n if (list === void 0) {\n list = [];\n }\n\n var scrollParent = getScrollParent(element);\n var isBody = scrollParent === ((_element$ownerDocumen = element.ownerDocument) == null ? void 0 : _element$ownerDocumen.body);\n var win = getWindow(scrollParent);\n var target = isBody ? [win].concat(win.visualViewport || [], isScrollParent(scrollParent) ? scrollParent : []) : scrollParent;\n var updatedList = list.concat(target);\n return isBody ? updatedList : // $FlowFixMe[incompatible-call]: isBody tells us target will be an HTMLElement here\n updatedList.concat(listScrollParents(getParentNode(target)));\n}\n;// ./node_modules/@popperjs/core/lib/utils/rectToClientRect.js\nfunction rectToClientRect(rect) {\n return Object.assign({}, rect, {\n left: rect.x,\n top: rect.y,\n right: rect.x + rect.width,\n bottom: rect.y + rect.height\n });\n}\n;// ./node_modules/@popperjs/core/lib/dom-utils/getClippingRect.js\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nfunction getInnerBoundingClientRect(element, strategy) {\n var rect = getBoundingClientRect(element, false, strategy === 'fixed');\n rect.top = rect.top + element.clientTop;\n rect.left = rect.left + element.clientLeft;\n rect.bottom = rect.top + element.clientHeight;\n rect.right = rect.left + element.clientWidth;\n rect.width = element.clientWidth;\n rect.height = element.clientHeight;\n rect.x = rect.left;\n rect.y = rect.top;\n return rect;\n}\n\nfunction getClientRectFromMixedType(element, clippingParent, strategy) {\n return clippingParent === viewport ? rectToClientRect(getViewportRect(element, strategy)) : isElement(clippingParent) ? getInnerBoundingClientRect(clippingParent, strategy) : rectToClientRect(getDocumentRect(getDocumentElement(element)));\n} // A \"clipping parent\" is an overflowable container with the characteristic of\n// clipping (or hiding) overflowing elements with a position different from\n// `initial`\n\n\nfunction getClippingParents(element) {\n var clippingParents = listScrollParents(getParentNode(element));\n var canEscapeClipping = ['absolute', 'fixed'].indexOf(getComputedStyle_getComputedStyle(element).position) >= 0;\n var clipperElement = canEscapeClipping && isHTMLElement(element) ? getOffsetParent(element) : element;\n\n if (!isElement(clipperElement)) {\n return [];\n } // $FlowFixMe[incompatible-return]: https://github.com/facebook/flow/issues/1414\n\n\n return clippingParents.filter(function (clippingParent) {\n return isElement(clippingParent) && contains(clippingParent, clipperElement) && getNodeName(clippingParent) !== 'body';\n });\n} // Gets the maximum area that the element is visible in due to any number of\n// clipping parents\n\n\nfunction getClippingRect(element, boundary, rootBoundary, strategy) {\n var mainClippingParents = boundary === 'clippingParents' ? getClippingParents(element) : [].concat(boundary);\n var clippingParents = [].concat(mainClippingParents, [rootBoundary]);\n var firstClippingParent = clippingParents[0];\n var clippingRect = clippingParents.reduce(function (accRect, clippingParent) {\n var rect = getClientRectFromMixedType(element, clippingParent, strategy);\n accRect.top = math_max(rect.top, accRect.top);\n accRect.right = math_min(rect.right, accRect.right);\n accRect.bottom = math_min(rect.bottom, accRect.bottom);\n accRect.left = math_max(rect.left, accRect.left);\n return accRect;\n }, getClientRectFromMixedType(element, firstClippingParent, strategy));\n clippingRect.width = clippingRect.right - clippingRect.left;\n clippingRect.height = clippingRect.bottom - clippingRect.top;\n clippingRect.x = clippingRect.left;\n clippingRect.y = clippingRect.top;\n return clippingRect;\n}\n;// ./node_modules/@popperjs/core/lib/utils/computeOffsets.js\n\n\n\n\nfunction computeOffsets(_ref) {\n var reference = _ref.reference,\n element = _ref.element,\n placement = _ref.placement;\n var basePlacement = placement ? getBasePlacement(placement) : null;\n var variation = placement ? getVariation(placement) : null;\n var commonX = reference.x + reference.width / 2 - element.width / 2;\n var commonY = reference.y + reference.height / 2 - element.height / 2;\n var offsets;\n\n switch (basePlacement) {\n case enums_top:\n offsets = {\n x: commonX,\n y: reference.y - element.height\n };\n break;\n\n case bottom:\n offsets = {\n x: commonX,\n y: reference.y + reference.height\n };\n break;\n\n case right:\n offsets = {\n x: reference.x + reference.width,\n y: commonY\n };\n break;\n\n case left:\n offsets = {\n x: reference.x - element.width,\n y: commonY\n };\n break;\n\n default:\n offsets = {\n x: reference.x,\n y: reference.y\n };\n }\n\n var mainAxis = basePlacement ? getMainAxisFromPlacement(basePlacement) : null;\n\n if (mainAxis != null) {\n var len = mainAxis === 'y' ? 'height' : 'width';\n\n switch (variation) {\n case start:\n offsets[mainAxis] = offsets[mainAxis] - (reference[len] / 2 - element[len] / 2);\n break;\n\n case end:\n offsets[mainAxis] = offsets[mainAxis] + (reference[len] / 2 - element[len] / 2);\n break;\n\n default:\n }\n }\n\n return offsets;\n}\n;// ./node_modules/@popperjs/core/lib/utils/detectOverflow.js\n\n\n\n\n\n\n\n\n // eslint-disable-next-line import/no-unused-modules\n\nfunction detectOverflow(state, options) {\n if (options === void 0) {\n options = {};\n }\n\n var _options = options,\n _options$placement = _options.placement,\n placement = _options$placement === void 0 ? state.placement : _options$placement,\n _options$strategy = _options.strategy,\n strategy = _options$strategy === void 0 ? state.strategy : _options$strategy,\n _options$boundary = _options.boundary,\n boundary = _options$boundary === void 0 ? clippingParents : _options$boundary,\n _options$rootBoundary = _options.rootBoundary,\n rootBoundary = _options$rootBoundary === void 0 ? viewport : _options$rootBoundary,\n _options$elementConte = _options.elementContext,\n elementContext = _options$elementConte === void 0 ? popper : _options$elementConte,\n _options$altBoundary = _options.altBoundary,\n altBoundary = _options$altBoundary === void 0 ? false : _options$altBoundary,\n _options$padding = _options.padding,\n padding = _options$padding === void 0 ? 0 : _options$padding;\n var paddingObject = mergePaddingObject(typeof padding !== 'number' ? padding : expandToHashMap(padding, basePlacements));\n var altContext = elementContext === popper ? reference : popper;\n var popperRect = state.rects.popper;\n var element = state.elements[altBoundary ? altContext : elementContext];\n var clippingClientRect = getClippingRect(isElement(element) ? element : element.contextElement || getDocumentElement(state.elements.popper), boundary, rootBoundary, strategy);\n var referenceClientRect = getBoundingClientRect(state.elements.reference);\n var popperOffsets = computeOffsets({\n reference: referenceClientRect,\n element: popperRect,\n strategy: 'absolute',\n placement: placement\n });\n var popperClientRect = rectToClientRect(Object.assign({}, popperRect, popperOffsets));\n var elementClientRect = elementContext === popper ? popperClientRect : referenceClientRect; // positive = overflowing the clipping rect\n // 0 or negative = within the clipping rect\n\n var overflowOffsets = {\n top: clippingClientRect.top - elementClientRect.top + paddingObject.top,\n bottom: elementClientRect.bottom - clippingClientRect.bottom + paddingObject.bottom,\n left: clippingClientRect.left - elementClientRect.left + paddingObject.left,\n right: elementClientRect.right - clippingClientRect.right + paddingObject.right\n };\n var offsetData = state.modifiersData.offset; // Offsets can be applied only to the popper element\n\n if (elementContext === popper && offsetData) {\n var offset = offsetData[placement];\n Object.keys(overflowOffsets).forEach(function (key) {\n var multiply = [right, bottom].indexOf(key) >= 0 ? 1 : -1;\n var axis = [enums_top, bottom].indexOf(key) >= 0 ? 'y' : 'x';\n overflowOffsets[key] += offset[axis] * multiply;\n });\n }\n\n return overflowOffsets;\n}\n;// ./node_modules/@popperjs/core/lib/utils/computeAutoPlacement.js\n\n\n\n\nfunction computeAutoPlacement(state, options) {\n if (options === void 0) {\n options = {};\n }\n\n var _options = options,\n placement = _options.placement,\n boundary = _options.boundary,\n rootBoundary = _options.rootBoundary,\n padding = _options.padding,\n flipVariations = _options.flipVariations,\n _options$allowedAutoP = _options.allowedAutoPlacements,\n allowedAutoPlacements = _options$allowedAutoP === void 0 ? enums_placements : _options$allowedAutoP;\n var variation = getVariation(placement);\n var placements = variation ? flipVariations ? variationPlacements : variationPlacements.filter(function (placement) {\n return getVariation(placement) === variation;\n }) : basePlacements;\n var allowedPlacements = placements.filter(function (placement) {\n return allowedAutoPlacements.indexOf(placement) >= 0;\n });\n\n if (allowedPlacements.length === 0) {\n allowedPlacements = placements;\n } // $FlowFixMe[incompatible-type]: Flow seems to have problems with two array unions...\n\n\n var overflows = allowedPlacements.reduce(function (acc, placement) {\n acc[placement] = detectOverflow(state, {\n placement: placement,\n boundary: boundary,\n rootBoundary: rootBoundary,\n padding: padding\n })[getBasePlacement(placement)];\n return acc;\n }, {});\n return Object.keys(overflows).sort(function (a, b) {\n return overflows[a] - overflows[b];\n });\n}\n;// ./node_modules/@popperjs/core/lib/modifiers/flip.js\n\n\n\n\n\n\n // eslint-disable-next-line import/no-unused-modules\n\nfunction getExpandedFallbackPlacements(placement) {\n if (getBasePlacement(placement) === enums_auto) {\n return [];\n }\n\n var oppositePlacement = getOppositePlacement(placement);\n return [getOppositeVariationPlacement(placement), oppositePlacement, getOppositeVariationPlacement(oppositePlacement)];\n}\n\nfunction flip(_ref) {\n var state = _ref.state,\n options = _ref.options,\n name = _ref.name;\n\n if (state.modifiersData[name]._skip) {\n return;\n }\n\n var _options$mainAxis = options.mainAxis,\n checkMainAxis = _options$mainAxis === void 0 ? true : _options$mainAxis,\n _options$altAxis = options.altAxis,\n checkAltAxis = _options$altAxis === void 0 ? true : _options$altAxis,\n specifiedFallbackPlacements = options.fallbackPlacements,\n padding = options.padding,\n boundary = options.boundary,\n rootBoundary = options.rootBoundary,\n altBoundary = options.altBoundary,\n _options$flipVariatio = options.flipVariations,\n flipVariations = _options$flipVariatio === void 0 ? true : _options$flipVariatio,\n allowedAutoPlacements = options.allowedAutoPlacements;\n var preferredPlacement = state.options.placement;\n var basePlacement = getBasePlacement(preferredPlacement);\n var isBasePlacement = basePlacement === preferredPlacement;\n var fallbackPlacements = specifiedFallbackPlacements || (isBasePlacement || !flipVariations ? [getOppositePlacement(preferredPlacement)] : getExpandedFallbackPlacements(preferredPlacement));\n var placements = [preferredPlacement].concat(fallbackPlacements).reduce(function (acc, placement) {\n return acc.concat(getBasePlacement(placement) === enums_auto ? computeAutoPlacement(state, {\n placement: placement,\n boundary: boundary,\n rootBoundary: rootBoundary,\n padding: padding,\n flipVariations: flipVariations,\n allowedAutoPlacements: allowedAutoPlacements\n }) : placement);\n }, []);\n var referenceRect = state.rects.reference;\n var popperRect = state.rects.popper;\n var checksMap = new Map();\n var makeFallbackChecks = true;\n var firstFittingPlacement = placements[0];\n\n for (var i = 0; i < placements.length; i++) {\n var placement = placements[i];\n\n var _basePlacement = getBasePlacement(placement);\n\n var isStartVariation = getVariation(placement) === start;\n var isVertical = [enums_top, bottom].indexOf(_basePlacement) >= 0;\n var len = isVertical ? 'width' : 'height';\n var overflow = detectOverflow(state, {\n placement: placement,\n boundary: boundary,\n rootBoundary: rootBoundary,\n altBoundary: altBoundary,\n padding: padding\n });\n var mainVariationSide = isVertical ? isStartVariation ? right : left : isStartVariation ? bottom : enums_top;\n\n if (referenceRect[len] > popperRect[len]) {\n mainVariationSide = getOppositePlacement(mainVariationSide);\n }\n\n var altVariationSide = getOppositePlacement(mainVariationSide);\n var checks = [];\n\n if (checkMainAxis) {\n checks.push(overflow[_basePlacement] <= 0);\n }\n\n if (checkAltAxis) {\n checks.push(overflow[mainVariationSide] <= 0, overflow[altVariationSide] <= 0);\n }\n\n if (checks.every(function (check) {\n return check;\n })) {\n firstFittingPlacement = placement;\n makeFallbackChecks = false;\n break;\n }\n\n checksMap.set(placement, checks);\n }\n\n if (makeFallbackChecks) {\n // `2` may be desired in some cases – research later\n var numberOfChecks = flipVariations ? 3 : 1;\n\n var _loop = function _loop(_i) {\n var fittingPlacement = placements.find(function (placement) {\n var checks = checksMap.get(placement);\n\n if (checks) {\n return checks.slice(0, _i).every(function (check) {\n return check;\n });\n }\n });\n\n if (fittingPlacement) {\n firstFittingPlacement = fittingPlacement;\n return \"break\";\n }\n };\n\n for (var _i = numberOfChecks; _i > 0; _i--) {\n var _ret = _loop(_i);\n\n if (_ret === \"break\") break;\n }\n }\n\n if (state.placement !== firstFittingPlacement) {\n state.modifiersData[name]._skip = true;\n state.placement = firstFittingPlacement;\n state.reset = true;\n }\n} // eslint-disable-next-line import/no-unused-modules\n\n\n/* harmony default export */ const modifiers_flip = ({\n name: 'flip',\n enabled: true,\n phase: 'main',\n fn: flip,\n requiresIfExists: ['offset'],\n data: {\n _skip: false\n }\n});\n;// ./node_modules/@popperjs/core/lib/modifiers/hide.js\n\n\n\nfunction getSideOffsets(overflow, rect, preventedOffsets) {\n if (preventedOffsets === void 0) {\n preventedOffsets = {\n x: 0,\n y: 0\n };\n }\n\n return {\n top: overflow.top - rect.height - preventedOffsets.y,\n right: overflow.right - rect.width + preventedOffsets.x,\n bottom: overflow.bottom - rect.height + preventedOffsets.y,\n left: overflow.left - rect.width - preventedOffsets.x\n };\n}\n\nfunction isAnySideFullyClipped(overflow) {\n return [enums_top, right, bottom, left].some(function (side) {\n return overflow[side] >= 0;\n });\n}\n\nfunction hide(_ref) {\n var state = _ref.state,\n name = _ref.name;\n var referenceRect = state.rects.reference;\n var popperRect = state.rects.popper;\n var preventedOffsets = state.modifiersData.preventOverflow;\n var referenceOverflow = detectOverflow(state, {\n elementContext: 'reference'\n });\n var popperAltOverflow = detectOverflow(state, {\n altBoundary: true\n });\n var referenceClippingOffsets = getSideOffsets(referenceOverflow, referenceRect);\n var popperEscapeOffsets = getSideOffsets(popperAltOverflow, popperRect, preventedOffsets);\n var isReferenceHidden = isAnySideFullyClipped(referenceClippingOffsets);\n var hasPopperEscaped = isAnySideFullyClipped(popperEscapeOffsets);\n state.modifiersData[name] = {\n referenceClippingOffsets: referenceClippingOffsets,\n popperEscapeOffsets: popperEscapeOffsets,\n isReferenceHidden: isReferenceHidden,\n hasPopperEscaped: hasPopperEscaped\n };\n state.attributes.popper = Object.assign({}, state.attributes.popper, {\n 'data-popper-reference-hidden': isReferenceHidden,\n 'data-popper-escaped': hasPopperEscaped\n });\n} // eslint-disable-next-line import/no-unused-modules\n\n\n/* harmony default export */ const modifiers_hide = ({\n name: 'hide',\n enabled: true,\n phase: 'main',\n requiresIfExists: ['preventOverflow'],\n fn: hide\n});\n;// ./node_modules/@popperjs/core/lib/modifiers/offset.js\n\n // eslint-disable-next-line import/no-unused-modules\n\nfunction distanceAndSkiddingToXY(placement, rects, offset) {\n var basePlacement = getBasePlacement(placement);\n var invertDistance = [left, enums_top].indexOf(basePlacement) >= 0 ? -1 : 1;\n\n var _ref = typeof offset === 'function' ? offset(Object.assign({}, rects, {\n placement: placement\n })) : offset,\n skidding = _ref[0],\n distance = _ref[1];\n\n skidding = skidding || 0;\n distance = (distance || 0) * invertDistance;\n return [left, right].indexOf(basePlacement) >= 0 ? {\n x: distance,\n y: skidding\n } : {\n x: skidding,\n y: distance\n };\n}\n\nfunction offset(_ref2) {\n var state = _ref2.state,\n options = _ref2.options,\n name = _ref2.name;\n var _options$offset = options.offset,\n offset = _options$offset === void 0 ? [0, 0] : _options$offset;\n var data = enums_placements.reduce(function (acc, placement) {\n acc[placement] = distanceAndSkiddingToXY(placement, state.rects, offset);\n return acc;\n }, {});\n var _data$state$placement = data[state.placement],\n x = _data$state$placement.x,\n y = _data$state$placement.y;\n\n if (state.modifiersData.popperOffsets != null) {\n state.modifiersData.popperOffsets.x += x;\n state.modifiersData.popperOffsets.y += y;\n }\n\n state.modifiersData[name] = data;\n} // eslint-disable-next-line import/no-unused-modules\n\n\n/* harmony default export */ const modifiers_offset = ({\n name: 'offset',\n enabled: true,\n phase: 'main',\n requires: ['popperOffsets'],\n fn: offset\n});\n;// ./node_modules/@popperjs/core/lib/modifiers/popperOffsets.js\n\n\nfunction popperOffsets(_ref) {\n var state = _ref.state,\n name = _ref.name;\n // Offsets are the actual position the popper needs to have to be\n // properly positioned near its reference element\n // This is the most basic placement, and will be adjusted by\n // the modifiers in the next step\n state.modifiersData[name] = computeOffsets({\n reference: state.rects.reference,\n element: state.rects.popper,\n strategy: 'absolute',\n placement: state.placement\n });\n} // eslint-disable-next-line import/no-unused-modules\n\n\n/* harmony default export */ const modifiers_popperOffsets = ({\n name: 'popperOffsets',\n enabled: true,\n phase: 'read',\n fn: popperOffsets,\n data: {}\n});\n;// ./node_modules/@popperjs/core/lib/utils/getAltAxis.js\nfunction getAltAxis(axis) {\n return axis === 'x' ? 'y' : 'x';\n}\n;// ./node_modules/@popperjs/core/lib/modifiers/preventOverflow.js\n\n\n\n\n\n\n\n\n\n\n\n\nfunction preventOverflow(_ref) {\n var state = _ref.state,\n options = _ref.options,\n name = _ref.name;\n var _options$mainAxis = options.mainAxis,\n checkMainAxis = _options$mainAxis === void 0 ? true : _options$mainAxis,\n _options$altAxis = options.altAxis,\n checkAltAxis = _options$altAxis === void 0 ? false : _options$altAxis,\n boundary = options.boundary,\n rootBoundary = options.rootBoundary,\n altBoundary = options.altBoundary,\n padding = options.padding,\n _options$tether = options.tether,\n tether = _options$tether === void 0 ? true : _options$tether,\n _options$tetherOffset = options.tetherOffset,\n tetherOffset = _options$tetherOffset === void 0 ? 0 : _options$tetherOffset;\n var overflow = detectOverflow(state, {\n boundary: boundary,\n rootBoundary: rootBoundary,\n padding: padding,\n altBoundary: altBoundary\n });\n var basePlacement = getBasePlacement(state.placement);\n var variation = getVariation(state.placement);\n var isBasePlacement = !variation;\n var mainAxis = getMainAxisFromPlacement(basePlacement);\n var altAxis = getAltAxis(mainAxis);\n var popperOffsets = state.modifiersData.popperOffsets;\n var referenceRect = state.rects.reference;\n var popperRect = state.rects.popper;\n var tetherOffsetValue = typeof tetherOffset === 'function' ? tetherOffset(Object.assign({}, state.rects, {\n placement: state.placement\n })) : tetherOffset;\n var normalizedTetherOffsetValue = typeof tetherOffsetValue === 'number' ? {\n mainAxis: tetherOffsetValue,\n altAxis: tetherOffsetValue\n } : Object.assign({\n mainAxis: 0,\n altAxis: 0\n }, tetherOffsetValue);\n var offsetModifierState = state.modifiersData.offset ? state.modifiersData.offset[state.placement] : null;\n var data = {\n x: 0,\n y: 0\n };\n\n if (!popperOffsets) {\n return;\n }\n\n if (checkMainAxis) {\n var _offsetModifierState$;\n\n var mainSide = mainAxis === 'y' ? enums_top : left;\n var altSide = mainAxis === 'y' ? bottom : right;\n var len = mainAxis === 'y' ? 'height' : 'width';\n var offset = popperOffsets[mainAxis];\n var min = offset + overflow[mainSide];\n var max = offset - overflow[altSide];\n var additive = tether ? -popperRect[len] / 2 : 0;\n var minLen = variation === start ? referenceRect[len] : popperRect[len];\n var maxLen = variation === start ? -popperRect[len] : -referenceRect[len]; // We need to include the arrow in the calculation so the arrow doesn't go\n // outside the reference bounds\n\n var arrowElement = state.elements.arrow;\n var arrowRect = tether && arrowElement ? getLayoutRect(arrowElement) : {\n width: 0,\n height: 0\n };\n var arrowPaddingObject = state.modifiersData['arrow#persistent'] ? state.modifiersData['arrow#persistent'].padding : getFreshSideObject();\n var arrowPaddingMin = arrowPaddingObject[mainSide];\n var arrowPaddingMax = arrowPaddingObject[altSide]; // If the reference length is smaller than the arrow length, we don't want\n // to include its full size in the calculation. If the reference is small\n // and near the edge of a boundary, the popper can overflow even if the\n // reference is not overflowing as well (e.g. virtual elements with no\n // width or height)\n\n var arrowLen = within(0, referenceRect[len], arrowRect[len]);\n var minOffset = isBasePlacement ? referenceRect[len] / 2 - additive - arrowLen - arrowPaddingMin - normalizedTetherOffsetValue.mainAxis : minLen - arrowLen - arrowPaddingMin - normalizedTetherOffsetValue.mainAxis;\n var maxOffset = isBasePlacement ? -referenceRect[len] / 2 + additive + arrowLen + arrowPaddingMax + normalizedTetherOffsetValue.mainAxis : maxLen + arrowLen + arrowPaddingMax + normalizedTetherOffsetValue.mainAxis;\n var arrowOffsetParent = state.elements.arrow && getOffsetParent(state.elements.arrow);\n var clientOffset = arrowOffsetParent ? mainAxis === 'y' ? arrowOffsetParent.clientTop || 0 : arrowOffsetParent.clientLeft || 0 : 0;\n var offsetModifierValue = (_offsetModifierState$ = offsetModifierState == null ? void 0 : offsetModifierState[mainAxis]) != null ? _offsetModifierState$ : 0;\n var tetherMin = offset + minOffset - offsetModifierValue - clientOffset;\n var tetherMax = offset + maxOffset - offsetModifierValue;\n var preventedOffset = within(tether ? math_min(min, tetherMin) : min, offset, tether ? math_max(max, tetherMax) : max);\n popperOffsets[mainAxis] = preventedOffset;\n data[mainAxis] = preventedOffset - offset;\n }\n\n if (checkAltAxis) {\n var _offsetModifierState$2;\n\n var _mainSide = mainAxis === 'x' ? enums_top : left;\n\n var _altSide = mainAxis === 'x' ? bottom : right;\n\n var _offset = popperOffsets[altAxis];\n\n var _len = altAxis === 'y' ? 'height' : 'width';\n\n var _min = _offset + overflow[_mainSide];\n\n var _max = _offset - overflow[_altSide];\n\n var isOriginSide = [enums_top, left].indexOf(basePlacement) !== -1;\n\n var _offsetModifierValue = (_offsetModifierState$2 = offsetModifierState == null ? void 0 : offsetModifierState[altAxis]) != null ? _offsetModifierState$2 : 0;\n\n var _tetherMin = isOriginSide ? _min : _offset - referenceRect[_len] - popperRect[_len] - _offsetModifierValue + normalizedTetherOffsetValue.altAxis;\n\n var _tetherMax = isOriginSide ? _offset + referenceRect[_len] + popperRect[_len] - _offsetModifierValue - normalizedTetherOffsetValue.altAxis : _max;\n\n var _preventedOffset = tether && isOriginSide ? withinMaxClamp(_tetherMin, _offset, _tetherMax) : within(tether ? _tetherMin : _min, _offset, tether ? _tetherMax : _max);\n\n popperOffsets[altAxis] = _preventedOffset;\n data[altAxis] = _preventedOffset - _offset;\n }\n\n state.modifiersData[name] = data;\n} // eslint-disable-next-line import/no-unused-modules\n\n\n/* harmony default export */ const modifiers_preventOverflow = ({\n name: 'preventOverflow',\n enabled: true,\n phase: 'main',\n fn: preventOverflow,\n requiresIfExists: ['offset']\n});\n;// ./node_modules/@popperjs/core/lib/modifiers/index.js\n\n\n\n\n\n\n\n\n\n;// ./node_modules/@popperjs/core/lib/dom-utils/getHTMLElementScroll.js\nfunction getHTMLElementScroll(element) {\n return {\n scrollLeft: element.scrollLeft,\n scrollTop: element.scrollTop\n };\n}\n;// ./node_modules/@popperjs/core/lib/dom-utils/getNodeScroll.js\n\n\n\n\nfunction getNodeScroll(node) {\n if (node === getWindow(node) || !isHTMLElement(node)) {\n return getWindowScroll(node);\n } else {\n return getHTMLElementScroll(node);\n }\n}\n;// ./node_modules/@popperjs/core/lib/dom-utils/getCompositeRect.js\n\n\n\n\n\n\n\n\n\nfunction isElementScaled(element) {\n var rect = element.getBoundingClientRect();\n var scaleX = math_round(rect.width) / element.offsetWidth || 1;\n var scaleY = math_round(rect.height) / element.offsetHeight || 1;\n return scaleX !== 1 || scaleY !== 1;\n} // Returns the composite rect of an element relative to its offsetParent.\n// Composite means it takes into account transforms as well as layout.\n\n\nfunction getCompositeRect(elementOrVirtualElement, offsetParent, isFixed) {\n if (isFixed === void 0) {\n isFixed = false;\n }\n\n var isOffsetParentAnElement = isHTMLElement(offsetParent);\n var offsetParentIsScaled = isHTMLElement(offsetParent) && isElementScaled(offsetParent);\n var documentElement = getDocumentElement(offsetParent);\n var rect = getBoundingClientRect(elementOrVirtualElement, offsetParentIsScaled, isFixed);\n var scroll = {\n scrollLeft: 0,\n scrollTop: 0\n };\n var offsets = {\n x: 0,\n y: 0\n };\n\n if (isOffsetParentAnElement || !isOffsetParentAnElement && !isFixed) {\n if (getNodeName(offsetParent) !== 'body' || // https://github.com/popperjs/popper-core/issues/1078\n isScrollParent(documentElement)) {\n scroll = getNodeScroll(offsetParent);\n }\n\n if (isHTMLElement(offsetParent)) {\n offsets = getBoundingClientRect(offsetParent, true);\n offsets.x += offsetParent.clientLeft;\n offsets.y += offsetParent.clientTop;\n } else if (documentElement) {\n offsets.x = getWindowScrollBarX(documentElement);\n }\n }\n\n return {\n x: rect.left + scroll.scrollLeft - offsets.x,\n y: rect.top + scroll.scrollTop - offsets.y,\n width: rect.width,\n height: rect.height\n };\n}\n;// ./node_modules/@popperjs/core/lib/utils/orderModifiers.js\n // source: https://stackoverflow.com/questions/49875255\n\nfunction order(modifiers) {\n var map = new Map();\n var visited = new Set();\n var result = [];\n modifiers.forEach(function (modifier) {\n map.set(modifier.name, modifier);\n }); // On visiting object, check for its dependencies and visit them recursively\n\n function sort(modifier) {\n visited.add(modifier.name);\n var requires = [].concat(modifier.requires || [], modifier.requiresIfExists || []);\n requires.forEach(function (dep) {\n if (!visited.has(dep)) {\n var depModifier = map.get(dep);\n\n if (depModifier) {\n sort(depModifier);\n }\n }\n });\n result.push(modifier);\n }\n\n modifiers.forEach(function (modifier) {\n if (!visited.has(modifier.name)) {\n // check for visited object\n sort(modifier);\n }\n });\n return result;\n}\n\nfunction orderModifiers(modifiers) {\n // order based on dependencies\n var orderedModifiers = order(modifiers); // order based on phase\n\n return modifierPhases.reduce(function (acc, phase) {\n return acc.concat(orderedModifiers.filter(function (modifier) {\n return modifier.phase === phase;\n }));\n }, []);\n}\n;// ./node_modules/@popperjs/core/lib/utils/debounce.js\nfunction debounce_debounce(fn) {\n var pending;\n return function () {\n if (!pending) {\n pending = new Promise(function (resolve) {\n Promise.resolve().then(function () {\n pending = undefined;\n resolve(fn());\n });\n });\n }\n\n return pending;\n };\n}\n;// ./node_modules/@popperjs/core/lib/utils/mergeByName.js\nfunction mergeByName(modifiers) {\n var merged = modifiers.reduce(function (merged, current) {\n var existing = merged[current.name];\n merged[current.name] = existing ? Object.assign({}, existing, current, {\n options: Object.assign({}, existing.options, current.options),\n data: Object.assign({}, existing.data, current.data)\n }) : current;\n return merged;\n }, {}); // IE11 does not support Object.values\n\n return Object.keys(merged).map(function (key) {\n return merged[key];\n });\n}\n;// ./node_modules/@popperjs/core/lib/createPopper.js\n\n\n\n\n\n\n\n\n\nvar DEFAULT_OPTIONS = {\n placement: 'bottom',\n modifiers: [],\n strategy: 'absolute'\n};\n\nfunction areValidElements() {\n for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {\n args[_key] = arguments[_key];\n }\n\n return !args.some(function (element) {\n return !(element && typeof element.getBoundingClientRect === 'function');\n });\n}\n\nfunction popperGenerator(generatorOptions) {\n if (generatorOptions === void 0) {\n generatorOptions = {};\n }\n\n var _generatorOptions = generatorOptions,\n _generatorOptions$def = _generatorOptions.defaultModifiers,\n defaultModifiers = _generatorOptions$def === void 0 ? [] : _generatorOptions$def,\n _generatorOptions$def2 = _generatorOptions.defaultOptions,\n defaultOptions = _generatorOptions$def2 === void 0 ? DEFAULT_OPTIONS : _generatorOptions$def2;\n return function createPopper(reference, popper, options) {\n if (options === void 0) {\n options = defaultOptions;\n }\n\n var state = {\n placement: 'bottom',\n orderedModifiers: [],\n options: Object.assign({}, DEFAULT_OPTIONS, defaultOptions),\n modifiersData: {},\n elements: {\n reference: reference,\n popper: popper\n },\n attributes: {},\n styles: {}\n };\n var effectCleanupFns = [];\n var isDestroyed = false;\n var instance = {\n state: state,\n setOptions: function setOptions(setOptionsAction) {\n var options = typeof setOptionsAction === 'function' ? setOptionsAction(state.options) : setOptionsAction;\n cleanupModifierEffects();\n state.options = Object.assign({}, defaultOptions, state.options, options);\n state.scrollParents = {\n reference: isElement(reference) ? listScrollParents(reference) : reference.contextElement ? listScrollParents(reference.contextElement) : [],\n popper: listScrollParents(popper)\n }; // Orders the modifiers based on their dependencies and `phase`\n // properties\n\n var orderedModifiers = orderModifiers(mergeByName([].concat(defaultModifiers, state.options.modifiers))); // Strip out disabled modifiers\n\n state.orderedModifiers = orderedModifiers.filter(function (m) {\n return m.enabled;\n });\n runModifierEffects();\n return instance.update();\n },\n // Sync update – it will always be executed, even if not necessary. This\n // is useful for low frequency updates where sync behavior simplifies the\n // logic.\n // For high frequency updates (e.g. `resize` and `scroll` events), always\n // prefer the async Popper#update method\n forceUpdate: function forceUpdate() {\n if (isDestroyed) {\n return;\n }\n\n var _state$elements = state.elements,\n reference = _state$elements.reference,\n popper = _state$elements.popper; // Don't proceed if `reference` or `popper` are not valid elements\n // anymore\n\n if (!areValidElements(reference, popper)) {\n return;\n } // Store the reference and popper rects to be read by modifiers\n\n\n state.rects = {\n reference: getCompositeRect(reference, getOffsetParent(popper), state.options.strategy === 'fixed'),\n popper: getLayoutRect(popper)\n }; // Modifiers have the ability to reset the current update cycle. The\n // most common use case for this is the `flip` modifier changing the\n // placement, which then needs to re-run all the modifiers, because the\n // logic was previously ran for the previous placement and is therefore\n // stale/incorrect\n\n state.reset = false;\n state.placement = state.options.placement; // On each update cycle, the `modifiersData` property for each modifier\n // is filled with the initial data specified by the modifier. This means\n // it doesn't persist and is fresh on each update.\n // To ensure persistent data, use `${name}#persistent`\n\n state.orderedModifiers.forEach(function (modifier) {\n return state.modifiersData[modifier.name] = Object.assign({}, modifier.data);\n });\n\n for (var index = 0; index < state.orderedModifiers.length; index++) {\n if (state.reset === true) {\n state.reset = false;\n index = -1;\n continue;\n }\n\n var _state$orderedModifie = state.orderedModifiers[index],\n fn = _state$orderedModifie.fn,\n _state$orderedModifie2 = _state$orderedModifie.options,\n _options = _state$orderedModifie2 === void 0 ? {} : _state$orderedModifie2,\n name = _state$orderedModifie.name;\n\n if (typeof fn === 'function') {\n state = fn({\n state: state,\n options: _options,\n name: name,\n instance: instance\n }) || state;\n }\n }\n },\n // Async and optimistically optimized update – it will not be executed if\n // not necessary (debounced to run at most once-per-tick)\n update: debounce_debounce(function () {\n return new Promise(function (resolve) {\n instance.forceUpdate();\n resolve(state);\n });\n }),\n destroy: function destroy() {\n cleanupModifierEffects();\n isDestroyed = true;\n }\n };\n\n if (!areValidElements(reference, popper)) {\n return instance;\n }\n\n instance.setOptions(options).then(function (state) {\n if (!isDestroyed && options.onFirstUpdate) {\n options.onFirstUpdate(state);\n }\n }); // Modifiers have the ability to execute arbitrary code before the first\n // update cycle runs. They will be executed in the same order as the update\n // cycle. This is useful when a modifier adds some persistent data that\n // other modifiers need to use, but the modifier is run after the dependent\n // one.\n\n function runModifierEffects() {\n state.orderedModifiers.forEach(function (_ref) {\n var name = _ref.name,\n _ref$options = _ref.options,\n options = _ref$options === void 0 ? {} : _ref$options,\n effect = _ref.effect;\n\n if (typeof effect === 'function') {\n var cleanupFn = effect({\n state: state,\n name: name,\n instance: instance,\n options: options\n });\n\n var noopFn = function noopFn() {};\n\n effectCleanupFns.push(cleanupFn || noopFn);\n }\n });\n }\n\n function cleanupModifierEffects() {\n effectCleanupFns.forEach(function (fn) {\n return fn();\n });\n effectCleanupFns = [];\n }\n\n return instance;\n };\n}\nvar createPopper = /*#__PURE__*/popperGenerator(); // eslint-disable-next-line import/no-unused-modules\n\n\n;// ./node_modules/@popperjs/core/lib/popper.js\n\n\n\n\n\n\n\n\n\n\nvar defaultModifiers = [eventListeners, modifiers_popperOffsets, modifiers_computeStyles, modifiers_applyStyles, modifiers_offset, modifiers_flip, modifiers_preventOverflow, modifiers_arrow, modifiers_hide];\nvar popper_createPopper = /*#__PURE__*/popperGenerator({\n defaultModifiers: defaultModifiers\n}); // eslint-disable-next-line import/no-unused-modules\n\n // eslint-disable-next-line import/no-unused-modules\n\n // eslint-disable-next-line import/no-unused-modules\n\n\n;// ./node_modules/@popperjs/core/lib/popper-lite.js\n\n\n\n\n\nvar popper_lite_defaultModifiers = [eventListeners, modifiers_popperOffsets, modifiers_computeStyles, modifiers_applyStyles];\nvar popper_lite_createPopper = /*#__PURE__*/popperGenerator({\n defaultModifiers: popper_lite_defaultModifiers\n}); // eslint-disable-next-line import/no-unused-modules\n\n\n;// ./node_modules/@popperjs/core/lib/index.js\n\n // eslint-disable-next-line import/no-unused-modules\n\n // eslint-disable-next-line import/no-unused-modules\n\n // eslint-disable-next-line import/no-unused-modules\n\n\n;// ./node_modules/bootstrap/dist/js/bootstrap.esm.js\n/*!\n * Bootstrap v5.3.3 (https://getbootstrap.com/)\n * Copyright 2011-2024 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n */\n\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap dom/data.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n/**\n * Constants\n */\n\nconst elementMap = new Map();\nconst Data = {\n set(element, key, instance) {\n if (!elementMap.has(element)) {\n elementMap.set(element, new Map());\n }\n const instanceMap = elementMap.get(element);\n\n // make it clear we only want one instance per element\n // can be removed later when multiple key/instances are fine to be used\n if (!instanceMap.has(key) && instanceMap.size !== 0) {\n // eslint-disable-next-line no-console\n console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(instanceMap.keys())[0]}.`);\n return;\n }\n instanceMap.set(key, instance);\n },\n get(element, key) {\n if (elementMap.has(element)) {\n return elementMap.get(element).get(key) || null;\n }\n return null;\n },\n remove(element, key) {\n if (!elementMap.has(element)) {\n return;\n }\n const instanceMap = elementMap.get(element);\n instanceMap.delete(key);\n\n // free up element references if there are no instances left for an element\n if (instanceMap.size === 0) {\n elementMap.delete(element);\n }\n }\n};\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap util/index.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nconst MAX_UID = 1000000;\nconst MILLISECONDS_MULTIPLIER = 1000;\nconst TRANSITION_END = 'transitionend';\n\n/**\n * Properly escape IDs selectors to handle weird IDs\n * @param {string} selector\n * @returns {string}\n */\nconst parseSelector = selector => {\n if (selector && window.CSS && window.CSS.escape) {\n // document.querySelector needs escaping to handle IDs (html5+) containing for instance /\n selector = selector.replace(/#([^\\s\"#']+)/g, (match, id) => `#${CSS.escape(id)}`);\n }\n return selector;\n};\n\n// Shout-out Angus Croll (https://goo.gl/pxwQGp)\nconst toType = object => {\n if (object === null || object === undefined) {\n return `${object}`;\n }\n return Object.prototype.toString.call(object).match(/\\s([a-z]+)/i)[1].toLowerCase();\n};\n\n/**\n * Public Util API\n */\n\nconst getUID = prefix => {\n do {\n prefix += Math.floor(Math.random() * MAX_UID);\n } while (document.getElementById(prefix));\n return prefix;\n};\nconst getTransitionDurationFromElement = element => {\n if (!element) {\n return 0;\n }\n\n // Get transition-duration of the element\n let {\n transitionDuration,\n transitionDelay\n } = window.getComputedStyle(element);\n const floatTransitionDuration = Number.parseFloat(transitionDuration);\n const floatTransitionDelay = Number.parseFloat(transitionDelay);\n\n // Return 0 if element or transition duration is not found\n if (!floatTransitionDuration && !floatTransitionDelay) {\n return 0;\n }\n\n // If multiple durations are defined, take the first\n transitionDuration = transitionDuration.split(',')[0];\n transitionDelay = transitionDelay.split(',')[0];\n return (Number.parseFloat(transitionDuration) + Number.parseFloat(transitionDelay)) * MILLISECONDS_MULTIPLIER;\n};\nconst triggerTransitionEnd = element => {\n element.dispatchEvent(new Event(TRANSITION_END));\n};\nconst bootstrap_esm_isElement = object => {\n if (!object || typeof object !== 'object') {\n return false;\n }\n if (typeof object.jquery !== 'undefined') {\n object = object[0];\n }\n return typeof object.nodeType !== 'undefined';\n};\nconst getElement = object => {\n // it's a jQuery object or a node element\n if (bootstrap_esm_isElement(object)) {\n return object.jquery ? object[0] : object;\n }\n if (typeof object === 'string' && object.length > 0) {\n return document.querySelector(parseSelector(object));\n }\n return null;\n};\nconst isVisible = element => {\n if (!bootstrap_esm_isElement(element) || element.getClientRects().length === 0) {\n return false;\n }\n const elementIsVisible = getComputedStyle(element).getPropertyValue('visibility') === 'visible';\n // Handle `details` element as its content may falsie appear visible when it is closed\n const closedDetails = element.closest('details:not([open])');\n if (!closedDetails) {\n return elementIsVisible;\n }\n if (closedDetails !== element) {\n const summary = element.closest('summary');\n if (summary && summary.parentNode !== closedDetails) {\n return false;\n }\n if (summary === null) {\n return false;\n }\n }\n return elementIsVisible;\n};\nconst isDisabled = element => {\n if (!element || element.nodeType !== Node.ELEMENT_NODE) {\n return true;\n }\n if (element.classList.contains('disabled')) {\n return true;\n }\n if (typeof element.disabled !== 'undefined') {\n return element.disabled;\n }\n return element.hasAttribute('disabled') && element.getAttribute('disabled') !== 'false';\n};\nconst findShadowRoot = element => {\n if (!document.documentElement.attachShadow) {\n return null;\n }\n\n // Can find the shadow root otherwise it'll return the document\n if (typeof element.getRootNode === 'function') {\n const root = element.getRootNode();\n return root instanceof ShadowRoot ? root : null;\n }\n if (element instanceof ShadowRoot) {\n return element;\n }\n\n // when we don't find a shadow root\n if (!element.parentNode) {\n return null;\n }\n return findShadowRoot(element.parentNode);\n};\nconst bootstrap_esm_noop = () => {};\n\n/**\n * Trick to restart an element's animation\n *\n * @param {HTMLElement} element\n * @return void\n *\n * @see https://www.charistheo.io/blog/2021/02/restart-a-css-animation-with-javascript/#restarting-a-css-animation\n */\nconst reflow = element => {\n element.offsetHeight; // eslint-disable-line no-unused-expressions\n};\nconst getjQuery = () => {\n if (window.jQuery && !document.body.hasAttribute('data-bs-no-jquery')) {\n return window.jQuery;\n }\n return null;\n};\nconst DOMContentLoadedCallbacks = [];\nconst onDOMContentLoaded = callback => {\n if (document.readyState === 'loading') {\n // add listener on the first call when the document is in loading state\n if (!DOMContentLoadedCallbacks.length) {\n document.addEventListener('DOMContentLoaded', () => {\n for (const callback of DOMContentLoadedCallbacks) {\n callback();\n }\n });\n }\n DOMContentLoadedCallbacks.push(callback);\n } else {\n callback();\n }\n};\nconst isRTL = () => document.documentElement.dir === 'rtl';\nconst defineJQueryPlugin = plugin => {\n onDOMContentLoaded(() => {\n const $ = getjQuery();\n /* istanbul ignore if */\n if ($) {\n const name = plugin.NAME;\n const JQUERY_NO_CONFLICT = $.fn[name];\n $.fn[name] = plugin.jQueryInterface;\n $.fn[name].Constructor = plugin;\n $.fn[name].noConflict = () => {\n $.fn[name] = JQUERY_NO_CONFLICT;\n return plugin.jQueryInterface;\n };\n }\n });\n};\nconst execute = (possibleCallback, args = [], defaultValue = possibleCallback) => {\n return typeof possibleCallback === 'function' ? possibleCallback(...args) : defaultValue;\n};\nconst executeAfterTransition = (callback, transitionElement, waitForTransition = true) => {\n if (!waitForTransition) {\n execute(callback);\n return;\n }\n const durationPadding = 5;\n const emulatedDuration = getTransitionDurationFromElement(transitionElement) + durationPadding;\n let called = false;\n const handler = ({\n target\n }) => {\n if (target !== transitionElement) {\n return;\n }\n called = true;\n transitionElement.removeEventListener(TRANSITION_END, handler);\n execute(callback);\n };\n transitionElement.addEventListener(TRANSITION_END, handler);\n setTimeout(() => {\n if (!called) {\n triggerTransitionEnd(transitionElement);\n }\n }, emulatedDuration);\n};\n\n/**\n * Return the previous/next element of a list.\n *\n * @param {array} list The list of elements\n * @param activeElement The active element\n * @param shouldGetNext Choose to get next or previous element\n * @param isCycleAllowed\n * @return {Element|elem} The proper element\n */\nconst getNextActiveElement = (list, activeElement, shouldGetNext, isCycleAllowed) => {\n const listLength = list.length;\n let index = list.indexOf(activeElement);\n\n // if the element does not exist in the list return an element\n // depending on the direction and if cycle is allowed\n if (index === -1) {\n return !shouldGetNext && isCycleAllowed ? list[listLength - 1] : list[0];\n }\n index += shouldGetNext ? 1 : -1;\n if (isCycleAllowed) {\n index = (index + listLength) % listLength;\n }\n return list[Math.max(0, Math.min(index, listLength - 1))];\n};\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap dom/event-handler.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n\n/**\n * Constants\n */\n\nconst namespaceRegex = /[^.]*(?=\\..*)\\.|.*/;\nconst stripNameRegex = /\\..*/;\nconst stripUidRegex = /::\\d+$/;\nconst eventRegistry = {}; // Events storage\nlet uidEvent = 1;\nconst customEvents = {\n mouseenter: 'mouseover',\n mouseleave: 'mouseout'\n};\nconst nativeEvents = new Set(['click', 'dblclick', 'mouseup', 'mousedown', 'contextmenu', 'mousewheel', 'DOMMouseScroll', 'mouseover', 'mouseout', 'mousemove', 'selectstart', 'selectend', 'keydown', 'keypress', 'keyup', 'orientationchange', 'touchstart', 'touchmove', 'touchend', 'touchcancel', 'pointerdown', 'pointermove', 'pointerup', 'pointerleave', 'pointercancel', 'gesturestart', 'gesturechange', 'gestureend', 'focus', 'blur', 'change', 'reset', 'select', 'submit', 'focusin', 'focusout', 'load', 'unload', 'beforeunload', 'resize', 'move', 'DOMContentLoaded', 'readystatechange', 'error', 'abort', 'scroll']);\n\n/**\n * Private methods\n */\n\nfunction makeEventUid(element, uid) {\n return uid && `${uid}::${uidEvent++}` || element.uidEvent || uidEvent++;\n}\nfunction getElementEvents(element) {\n const uid = makeEventUid(element);\n element.uidEvent = uid;\n eventRegistry[uid] = eventRegistry[uid] || {};\n return eventRegistry[uid];\n}\nfunction bootstrapHandler(element, fn) {\n return function handler(event) {\n hydrateObj(event, {\n delegateTarget: element\n });\n if (handler.oneOff) {\n EventHandler.off(element, event.type, fn);\n }\n return fn.apply(element, [event]);\n };\n}\nfunction bootstrapDelegationHandler(element, selector, fn) {\n return function handler(event) {\n const domElements = element.querySelectorAll(selector);\n for (let {\n target\n } = event; target && target !== this; target = target.parentNode) {\n for (const domElement of domElements) {\n if (domElement !== target) {\n continue;\n }\n hydrateObj(event, {\n delegateTarget: target\n });\n if (handler.oneOff) {\n EventHandler.off(element, event.type, selector, fn);\n }\n return fn.apply(target, [event]);\n }\n }\n };\n}\nfunction findHandler(events, callable, delegationSelector = null) {\n return Object.values(events).find(event => event.callable === callable && event.delegationSelector === delegationSelector);\n}\nfunction normalizeParameters(originalTypeEvent, handler, delegationFunction) {\n const isDelegated = typeof handler === 'string';\n // TODO: tooltip passes `false` instead of selector, so we need to check\n const callable = isDelegated ? delegationFunction : handler || delegationFunction;\n let typeEvent = getTypeEvent(originalTypeEvent);\n if (!nativeEvents.has(typeEvent)) {\n typeEvent = originalTypeEvent;\n }\n return [isDelegated, callable, typeEvent];\n}\nfunction addHandler(element, originalTypeEvent, handler, delegationFunction, oneOff) {\n if (typeof originalTypeEvent !== 'string' || !element) {\n return;\n }\n let [isDelegated, callable, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction);\n\n // in case of mouseenter or mouseleave wrap the handler within a function that checks for its DOM position\n // this prevents the handler from being dispatched the same way as mouseover or mouseout does\n if (originalTypeEvent in customEvents) {\n const wrapFunction = fn => {\n return function (event) {\n if (!event.relatedTarget || event.relatedTarget !== event.delegateTarget && !event.delegateTarget.contains(event.relatedTarget)) {\n return fn.call(this, event);\n }\n };\n };\n callable = wrapFunction(callable);\n }\n const events = getElementEvents(element);\n const handlers = events[typeEvent] || (events[typeEvent] = {});\n const previousFunction = findHandler(handlers, callable, isDelegated ? handler : null);\n if (previousFunction) {\n previousFunction.oneOff = previousFunction.oneOff && oneOff;\n return;\n }\n const uid = makeEventUid(callable, originalTypeEvent.replace(namespaceRegex, ''));\n const fn = isDelegated ? bootstrapDelegationHandler(element, handler, callable) : bootstrapHandler(element, callable);\n fn.delegationSelector = isDelegated ? handler : null;\n fn.callable = callable;\n fn.oneOff = oneOff;\n fn.uidEvent = uid;\n handlers[uid] = fn;\n element.addEventListener(typeEvent, fn, isDelegated);\n}\nfunction removeHandler(element, events, typeEvent, handler, delegationSelector) {\n const fn = findHandler(events[typeEvent], handler, delegationSelector);\n if (!fn) {\n return;\n }\n element.removeEventListener(typeEvent, fn, Boolean(delegationSelector));\n delete events[typeEvent][fn.uidEvent];\n}\nfunction removeNamespacedHandlers(element, events, typeEvent, namespace) {\n const storeElementEvent = events[typeEvent] || {};\n for (const [handlerKey, event] of Object.entries(storeElementEvent)) {\n if (handlerKey.includes(namespace)) {\n removeHandler(element, events, typeEvent, event.callable, event.delegationSelector);\n }\n }\n}\nfunction getTypeEvent(event) {\n // allow to get the native events from namespaced events ('click.bs.button' --\x3e 'click')\n event = event.replace(stripNameRegex, '');\n return customEvents[event] || event;\n}\nconst EventHandler = {\n on(element, event, handler, delegationFunction) {\n addHandler(element, event, handler, delegationFunction, false);\n },\n one(element, event, handler, delegationFunction) {\n addHandler(element, event, handler, delegationFunction, true);\n },\n off(element, originalTypeEvent, handler, delegationFunction) {\n if (typeof originalTypeEvent !== 'string' || !element) {\n return;\n }\n const [isDelegated, callable, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction);\n const inNamespace = typeEvent !== originalTypeEvent;\n const events = getElementEvents(element);\n const storeElementEvent = events[typeEvent] || {};\n const isNamespace = originalTypeEvent.startsWith('.');\n if (typeof callable !== 'undefined') {\n // Simplest case: handler is passed, remove that listener ONLY.\n if (!Object.keys(storeElementEvent).length) {\n return;\n }\n removeHandler(element, events, typeEvent, callable, isDelegated ? handler : null);\n return;\n }\n if (isNamespace) {\n for (const elementEvent of Object.keys(events)) {\n removeNamespacedHandlers(element, events, elementEvent, originalTypeEvent.slice(1));\n }\n }\n for (const [keyHandlers, event] of Object.entries(storeElementEvent)) {\n const handlerKey = keyHandlers.replace(stripUidRegex, '');\n if (!inNamespace || originalTypeEvent.includes(handlerKey)) {\n removeHandler(element, events, typeEvent, event.callable, event.delegationSelector);\n }\n }\n },\n trigger(element, event, args) {\n if (typeof event !== 'string' || !element) {\n return null;\n }\n const $ = getjQuery();\n const typeEvent = getTypeEvent(event);\n const inNamespace = event !== typeEvent;\n let jQueryEvent = null;\n let bubbles = true;\n let nativeDispatch = true;\n let defaultPrevented = false;\n if (inNamespace && $) {\n jQueryEvent = $.Event(event, args);\n $(element).trigger(jQueryEvent);\n bubbles = !jQueryEvent.isPropagationStopped();\n nativeDispatch = !jQueryEvent.isImmediatePropagationStopped();\n defaultPrevented = jQueryEvent.isDefaultPrevented();\n }\n const evt = hydrateObj(new Event(event, {\n bubbles,\n cancelable: true\n }), args);\n if (defaultPrevented) {\n evt.preventDefault();\n }\n if (nativeDispatch) {\n element.dispatchEvent(evt);\n }\n if (evt.defaultPrevented && jQueryEvent) {\n jQueryEvent.preventDefault();\n }\n return evt;\n }\n};\nfunction hydrateObj(obj, meta = {}) {\n for (const [key, value] of Object.entries(meta)) {\n try {\n obj[key] = value;\n } catch (_unused) {\n Object.defineProperty(obj, key, {\n configurable: true,\n get() {\n return value;\n }\n });\n }\n }\n return obj;\n}\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap dom/manipulator.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nfunction normalizeData(value) {\n if (value === 'true') {\n return true;\n }\n if (value === 'false') {\n return false;\n }\n if (value === Number(value).toString()) {\n return Number(value);\n }\n if (value === '' || value === 'null') {\n return null;\n }\n if (typeof value !== 'string') {\n return value;\n }\n try {\n return JSON.parse(decodeURIComponent(value));\n } catch (_unused) {\n return value;\n }\n}\nfunction normalizeDataKey(key) {\n return key.replace(/[A-Z]/g, chr => `-${chr.toLowerCase()}`);\n}\nconst Manipulator = {\n setDataAttribute(element, key, value) {\n element.setAttribute(`data-bs-${normalizeDataKey(key)}`, value);\n },\n removeDataAttribute(element, key) {\n element.removeAttribute(`data-bs-${normalizeDataKey(key)}`);\n },\n getDataAttributes(element) {\n if (!element) {\n return {};\n }\n const attributes = {};\n const bsKeys = Object.keys(element.dataset).filter(key => key.startsWith('bs') && !key.startsWith('bsConfig'));\n for (const key of bsKeys) {\n let pureKey = key.replace(/^bs/, '');\n pureKey = pureKey.charAt(0).toLowerCase() + pureKey.slice(1, pureKey.length);\n attributes[pureKey] = normalizeData(element.dataset[key]);\n }\n return attributes;\n },\n getDataAttribute(element, key) {\n return normalizeData(element.getAttribute(`data-bs-${normalizeDataKey(key)}`));\n }\n};\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap util/config.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n\n/**\n * Class definition\n */\n\nclass bootstrap_esm_Config {\n // Getters\n static get Default() {\n return {};\n }\n static get DefaultType() {\n return {};\n }\n static get NAME() {\n throw new Error('You have to implement the static method \"NAME\", for each component!');\n }\n _getConfig(config) {\n config = this._mergeConfigObj(config);\n config = this._configAfterMerge(config);\n this._typeCheckConfig(config);\n return config;\n }\n _configAfterMerge(config) {\n return config;\n }\n _mergeConfigObj(config, element) {\n const jsonConfig = bootstrap_esm_isElement(element) ? Manipulator.getDataAttribute(element, 'config') : {}; // try to parse\n\n return {\n ...this.constructor.Default,\n ...(typeof jsonConfig === 'object' ? jsonConfig : {}),\n ...(bootstrap_esm_isElement(element) ? Manipulator.getDataAttributes(element) : {}),\n ...(typeof config === 'object' ? config : {})\n };\n }\n _typeCheckConfig(config, configTypes = this.constructor.DefaultType) {\n for (const [property, expectedTypes] of Object.entries(configTypes)) {\n const value = config[property];\n const valueType = bootstrap_esm_isElement(value) ? 'element' : toType(value);\n if (!new RegExp(expectedTypes).test(valueType)) {\n throw new TypeError(`${this.constructor.NAME.toUpperCase()}: Option \"${property}\" provided type \"${valueType}\" but expected type \"${expectedTypes}\".`);\n }\n }\n }\n}\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap base-component.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n\n/**\n * Constants\n */\n\nconst VERSION = '5.3.3';\n\n/**\n * Class definition\n */\n\nclass BaseComponent extends bootstrap_esm_Config {\n constructor(element, config) {\n super();\n element = getElement(element);\n if (!element) {\n return;\n }\n this._element = element;\n this._config = this._getConfig(config);\n Data.set(this._element, this.constructor.DATA_KEY, this);\n }\n\n // Public\n dispose() {\n Data.remove(this._element, this.constructor.DATA_KEY);\n EventHandler.off(this._element, this.constructor.EVENT_KEY);\n for (const propertyName of Object.getOwnPropertyNames(this)) {\n this[propertyName] = null;\n }\n }\n _queueCallback(callback, element, isAnimated = true) {\n executeAfterTransition(callback, element, isAnimated);\n }\n _getConfig(config) {\n config = this._mergeConfigObj(config, this._element);\n config = this._configAfterMerge(config);\n this._typeCheckConfig(config);\n return config;\n }\n\n // Static\n static getInstance(element) {\n return Data.get(getElement(element), this.DATA_KEY);\n }\n static getOrCreateInstance(element, config = {}) {\n return this.getInstance(element) || new this(element, typeof config === 'object' ? config : null);\n }\n static get VERSION() {\n return VERSION;\n }\n static get DATA_KEY() {\n return `bs.${this.NAME}`;\n }\n static get EVENT_KEY() {\n return `.${this.DATA_KEY}`;\n }\n static eventName(name) {\n return `${name}${this.EVENT_KEY}`;\n }\n}\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap dom/selector-engine.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nconst getSelector = element => {\n let selector = element.getAttribute('data-bs-target');\n if (!selector || selector === '#') {\n let hrefAttribute = element.getAttribute('href');\n\n // The only valid content that could double as a selector are IDs or classes,\n // so everything starting with `#` or `.`. If a \"real\" URL is used as the selector,\n // `document.querySelector` will rightfully complain it is invalid.\n // See https://github.com/twbs/bootstrap/issues/32273\n if (!hrefAttribute || !hrefAttribute.includes('#') && !hrefAttribute.startsWith('.')) {\n return null;\n }\n\n // Just in case some CMS puts out a full URL with the anchor appended\n if (hrefAttribute.includes('#') && !hrefAttribute.startsWith('#')) {\n hrefAttribute = `#${hrefAttribute.split('#')[1]}`;\n }\n selector = hrefAttribute && hrefAttribute !== '#' ? hrefAttribute.trim() : null;\n }\n return selector ? selector.split(',').map(sel => parseSelector(sel)).join(',') : null;\n};\nconst SelectorEngine = {\n find(selector, element = document.documentElement) {\n return [].concat(...Element.prototype.querySelectorAll.call(element, selector));\n },\n findOne(selector, element = document.documentElement) {\n return Element.prototype.querySelector.call(element, selector);\n },\n children(element, selector) {\n return [].concat(...element.children).filter(child => child.matches(selector));\n },\n parents(element, selector) {\n const parents = [];\n let ancestor = element.parentNode.closest(selector);\n while (ancestor) {\n parents.push(ancestor);\n ancestor = ancestor.parentNode.closest(selector);\n }\n return parents;\n },\n prev(element, selector) {\n let previous = element.previousElementSibling;\n while (previous) {\n if (previous.matches(selector)) {\n return [previous];\n }\n previous = previous.previousElementSibling;\n }\n return [];\n },\n // TODO: this is now unused; remove later along with prev()\n next(element, selector) {\n let next = element.nextElementSibling;\n while (next) {\n if (next.matches(selector)) {\n return [next];\n }\n next = next.nextElementSibling;\n }\n return [];\n },\n focusableChildren(element) {\n const focusables = ['a', 'button', 'input', 'textarea', 'select', 'details', '[tabindex]', '[contenteditable=\"true\"]'].map(selector => `${selector}:not([tabindex^=\"-\"])`).join(',');\n return this.find(focusables, element).filter(el => !isDisabled(el) && isVisible(el));\n },\n getSelectorFromElement(element) {\n const selector = getSelector(element);\n if (selector) {\n return SelectorEngine.findOne(selector) ? selector : null;\n }\n return null;\n },\n getElementFromSelector(element) {\n const selector = getSelector(element);\n return selector ? SelectorEngine.findOne(selector) : null;\n },\n getMultipleElementsFromSelector(element) {\n const selector = getSelector(element);\n return selector ? SelectorEngine.find(selector) : [];\n }\n};\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap util/component-functions.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nconst enableDismissTrigger = (component, method = 'hide') => {\n const clickEvent = `click.dismiss${component.EVENT_KEY}`;\n const name = component.NAME;\n EventHandler.on(document, clickEvent, `[data-bs-dismiss=\"${name}\"]`, function (event) {\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault();\n }\n if (isDisabled(this)) {\n return;\n }\n const target = SelectorEngine.getElementFromSelector(this) || this.closest(`.${name}`);\n const instance = component.getOrCreateInstance(target);\n\n // Method argument is left, for Alert and only, as it doesn't implement the 'hide' method\n instance[method]();\n });\n};\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap alert.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n\n/**\n * Constants\n */\n\nconst NAME$f = 'alert';\nconst DATA_KEY$a = 'bs.alert';\nconst EVENT_KEY$b = `.${DATA_KEY$a}`;\nconst EVENT_CLOSE = `close${EVENT_KEY$b}`;\nconst EVENT_CLOSED = `closed${EVENT_KEY$b}`;\nconst CLASS_NAME_FADE$5 = 'fade';\nconst CLASS_NAME_SHOW$8 = 'show';\n\n/**\n * Class definition\n */\n\nclass Alert extends BaseComponent {\n // Getters\n static get NAME() {\n return NAME$f;\n }\n\n // Public\n close() {\n const closeEvent = EventHandler.trigger(this._element, EVENT_CLOSE);\n if (closeEvent.defaultPrevented) {\n return;\n }\n this._element.classList.remove(CLASS_NAME_SHOW$8);\n const isAnimated = this._element.classList.contains(CLASS_NAME_FADE$5);\n this._queueCallback(() => this._destroyElement(), this._element, isAnimated);\n }\n\n // Private\n _destroyElement() {\n this._element.remove();\n EventHandler.trigger(this._element, EVENT_CLOSED);\n this.dispose();\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Alert.getOrCreateInstance(this);\n if (typeof config !== 'string') {\n return;\n }\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`);\n }\n data[config](this);\n });\n }\n}\n\n/**\n * Data API implementation\n */\n\nenableDismissTrigger(Alert, 'close');\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Alert);\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap button.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n\n/**\n * Constants\n */\n\nconst NAME$e = 'button';\nconst DATA_KEY$9 = 'bs.button';\nconst EVENT_KEY$a = `.${DATA_KEY$9}`;\nconst DATA_API_KEY$6 = '.data-api';\nconst CLASS_NAME_ACTIVE$3 = 'active';\nconst SELECTOR_DATA_TOGGLE$5 = '[data-bs-toggle=\"button\"]';\nconst EVENT_CLICK_DATA_API$6 = `click${EVENT_KEY$a}${DATA_API_KEY$6}`;\n\n/**\n * Class definition\n */\n\nclass Button extends BaseComponent {\n // Getters\n static get NAME() {\n return NAME$e;\n }\n\n // Public\n toggle() {\n // Toggle class and sync the `aria-pressed` attribute with the return value of the `.toggle()` method\n this._element.setAttribute('aria-pressed', this._element.classList.toggle(CLASS_NAME_ACTIVE$3));\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Button.getOrCreateInstance(this);\n if (config === 'toggle') {\n data[config]();\n }\n });\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API$6, SELECTOR_DATA_TOGGLE$5, event => {\n event.preventDefault();\n const button = event.target.closest(SELECTOR_DATA_TOGGLE$5);\n const data = Button.getOrCreateInstance(button);\n data.toggle();\n});\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Button);\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap util/swipe.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n\n/**\n * Constants\n */\n\nconst NAME$d = 'swipe';\nconst EVENT_KEY$9 = '.bs.swipe';\nconst EVENT_TOUCHSTART = `touchstart${EVENT_KEY$9}`;\nconst EVENT_TOUCHMOVE = `touchmove${EVENT_KEY$9}`;\nconst EVENT_TOUCHEND = `touchend${EVENT_KEY$9}`;\nconst EVENT_POINTERDOWN = `pointerdown${EVENT_KEY$9}`;\nconst EVENT_POINTERUP = `pointerup${EVENT_KEY$9}`;\nconst POINTER_TYPE_TOUCH = 'touch';\nconst POINTER_TYPE_PEN = 'pen';\nconst CLASS_NAME_POINTER_EVENT = 'pointer-event';\nconst SWIPE_THRESHOLD = 40;\nconst Default$c = {\n endCallback: null,\n leftCallback: null,\n rightCallback: null\n};\nconst DefaultType$c = {\n endCallback: '(function|null)',\n leftCallback: '(function|null)',\n rightCallback: '(function|null)'\n};\n\n/**\n * Class definition\n */\n\nclass Swipe extends bootstrap_esm_Config {\n constructor(element, config) {\n super();\n this._element = element;\n if (!element || !Swipe.isSupported()) {\n return;\n }\n this._config = this._getConfig(config);\n this._deltaX = 0;\n this._supportPointerEvents = Boolean(window.PointerEvent);\n this._initEvents();\n }\n\n // Getters\n static get Default() {\n return Default$c;\n }\n static get DefaultType() {\n return DefaultType$c;\n }\n static get NAME() {\n return NAME$d;\n }\n\n // Public\n dispose() {\n EventHandler.off(this._element, EVENT_KEY$9);\n }\n\n // Private\n _start(event) {\n if (!this._supportPointerEvents) {\n this._deltaX = event.touches[0].clientX;\n return;\n }\n if (this._eventIsPointerPenTouch(event)) {\n this._deltaX = event.clientX;\n }\n }\n _end(event) {\n if (this._eventIsPointerPenTouch(event)) {\n this._deltaX = event.clientX - this._deltaX;\n }\n this._handleSwipe();\n execute(this._config.endCallback);\n }\n _move(event) {\n this._deltaX = event.touches && event.touches.length > 1 ? 0 : event.touches[0].clientX - this._deltaX;\n }\n _handleSwipe() {\n const absDeltaX = Math.abs(this._deltaX);\n if (absDeltaX <= SWIPE_THRESHOLD) {\n return;\n }\n const direction = absDeltaX / this._deltaX;\n this._deltaX = 0;\n if (!direction) {\n return;\n }\n execute(direction > 0 ? this._config.rightCallback : this._config.leftCallback);\n }\n _initEvents() {\n if (this._supportPointerEvents) {\n EventHandler.on(this._element, EVENT_POINTERDOWN, event => this._start(event));\n EventHandler.on(this._element, EVENT_POINTERUP, event => this._end(event));\n this._element.classList.add(CLASS_NAME_POINTER_EVENT);\n } else {\n EventHandler.on(this._element, EVENT_TOUCHSTART, event => this._start(event));\n EventHandler.on(this._element, EVENT_TOUCHMOVE, event => this._move(event));\n EventHandler.on(this._element, EVENT_TOUCHEND, event => this._end(event));\n }\n }\n _eventIsPointerPenTouch(event) {\n return this._supportPointerEvents && (event.pointerType === POINTER_TYPE_PEN || event.pointerType === POINTER_TYPE_TOUCH);\n }\n\n // Static\n static isSupported() {\n return 'ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0;\n }\n}\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap carousel.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n\n/**\n * Constants\n */\n\nconst NAME$c = 'carousel';\nconst DATA_KEY$8 = 'bs.carousel';\nconst EVENT_KEY$8 = `.${DATA_KEY$8}`;\nconst DATA_API_KEY$5 = '.data-api';\nconst ARROW_LEFT_KEY$1 = 'ArrowLeft';\nconst ARROW_RIGHT_KEY$1 = 'ArrowRight';\nconst TOUCHEVENT_COMPAT_WAIT = 500; // Time for mouse compat events to fire after touch\n\nconst ORDER_NEXT = 'next';\nconst ORDER_PREV = 'prev';\nconst DIRECTION_LEFT = 'left';\nconst DIRECTION_RIGHT = 'right';\nconst EVENT_SLIDE = `slide${EVENT_KEY$8}`;\nconst EVENT_SLID = `slid${EVENT_KEY$8}`;\nconst EVENT_KEYDOWN$1 = `keydown${EVENT_KEY$8}`;\nconst EVENT_MOUSEENTER$1 = `mouseenter${EVENT_KEY$8}`;\nconst EVENT_MOUSELEAVE$1 = `mouseleave${EVENT_KEY$8}`;\nconst EVENT_DRAG_START = `dragstart${EVENT_KEY$8}`;\nconst EVENT_LOAD_DATA_API$3 = `load${EVENT_KEY$8}${DATA_API_KEY$5}`;\nconst EVENT_CLICK_DATA_API$5 = `click${EVENT_KEY$8}${DATA_API_KEY$5}`;\nconst CLASS_NAME_CAROUSEL = 'carousel';\nconst CLASS_NAME_ACTIVE$2 = 'active';\nconst CLASS_NAME_SLIDE = 'slide';\nconst CLASS_NAME_END = 'carousel-item-end';\nconst CLASS_NAME_START = 'carousel-item-start';\nconst CLASS_NAME_NEXT = 'carousel-item-next';\nconst CLASS_NAME_PREV = 'carousel-item-prev';\nconst SELECTOR_ACTIVE = '.active';\nconst SELECTOR_ITEM = '.carousel-item';\nconst SELECTOR_ACTIVE_ITEM = SELECTOR_ACTIVE + SELECTOR_ITEM;\nconst SELECTOR_ITEM_IMG = '.carousel-item img';\nconst SELECTOR_INDICATORS = '.carousel-indicators';\nconst SELECTOR_DATA_SLIDE = '[data-bs-slide], [data-bs-slide-to]';\nconst SELECTOR_DATA_RIDE = '[data-bs-ride=\"carousel\"]';\nconst KEY_TO_DIRECTION = {\n [ARROW_LEFT_KEY$1]: DIRECTION_RIGHT,\n [ARROW_RIGHT_KEY$1]: DIRECTION_LEFT\n};\nconst Default$b = {\n interval: 5000,\n keyboard: true,\n pause: 'hover',\n ride: false,\n touch: true,\n wrap: true\n};\nconst DefaultType$b = {\n interval: '(number|boolean)',\n // TODO:v6 remove boolean support\n keyboard: 'boolean',\n pause: '(string|boolean)',\n ride: '(boolean|string)',\n touch: 'boolean',\n wrap: 'boolean'\n};\n\n/**\n * Class definition\n */\n\nclass Carousel extends BaseComponent {\n constructor(element, config) {\n super(element, config);\n this._interval = null;\n this._activeElement = null;\n this._isSliding = false;\n this.touchTimeout = null;\n this._swipeHelper = null;\n this._indicatorsElement = SelectorEngine.findOne(SELECTOR_INDICATORS, this._element);\n this._addEventListeners();\n if (this._config.ride === CLASS_NAME_CAROUSEL) {\n this.cycle();\n }\n }\n\n // Getters\n static get Default() {\n return Default$b;\n }\n static get DefaultType() {\n return DefaultType$b;\n }\n static get NAME() {\n return NAME$c;\n }\n\n // Public\n next() {\n this._slide(ORDER_NEXT);\n }\n nextWhenVisible() {\n // FIXME TODO use `document.visibilityState`\n // Don't call next when the page isn't visible\n // or the carousel or its parent isn't visible\n if (!document.hidden && isVisible(this._element)) {\n this.next();\n }\n }\n prev() {\n this._slide(ORDER_PREV);\n }\n pause() {\n if (this._isSliding) {\n triggerTransitionEnd(this._element);\n }\n this._clearInterval();\n }\n cycle() {\n this._clearInterval();\n this._updateInterval();\n this._interval = setInterval(() => this.nextWhenVisible(), this._config.interval);\n }\n _maybeEnableCycle() {\n if (!this._config.ride) {\n return;\n }\n if (this._isSliding) {\n EventHandler.one(this._element, EVENT_SLID, () => this.cycle());\n return;\n }\n this.cycle();\n }\n to(index) {\n const items = this._getItems();\n if (index > items.length - 1 || index < 0) {\n return;\n }\n if (this._isSliding) {\n EventHandler.one(this._element, EVENT_SLID, () => this.to(index));\n return;\n }\n const activeIndex = this._getItemIndex(this._getActive());\n if (activeIndex === index) {\n return;\n }\n const order = index > activeIndex ? ORDER_NEXT : ORDER_PREV;\n this._slide(order, items[index]);\n }\n dispose() {\n if (this._swipeHelper) {\n this._swipeHelper.dispose();\n }\n super.dispose();\n }\n\n // Private\n _configAfterMerge(config) {\n config.defaultInterval = config.interval;\n return config;\n }\n _addEventListeners() {\n if (this._config.keyboard) {\n EventHandler.on(this._element, EVENT_KEYDOWN$1, event => this._keydown(event));\n }\n if (this._config.pause === 'hover') {\n EventHandler.on(this._element, EVENT_MOUSEENTER$1, () => this.pause());\n EventHandler.on(this._element, EVENT_MOUSELEAVE$1, () => this._maybeEnableCycle());\n }\n if (this._config.touch && Swipe.isSupported()) {\n this._addTouchEventListeners();\n }\n }\n _addTouchEventListeners() {\n for (const img of SelectorEngine.find(SELECTOR_ITEM_IMG, this._element)) {\n EventHandler.on(img, EVENT_DRAG_START, event => event.preventDefault());\n }\n const endCallBack = () => {\n if (this._config.pause !== 'hover') {\n return;\n }\n\n // If it's a touch-enabled device, mouseenter/leave are fired as\n // part of the mouse compatibility events on first tap - the carousel\n // would stop cycling until user tapped out of it;\n // here, we listen for touchend, explicitly pause the carousel\n // (as if it's the second time we tap on it, mouseenter compat event\n // is NOT fired) and after a timeout (to allow for mouse compatibility\n // events to fire) we explicitly restart cycling\n\n this.pause();\n if (this.touchTimeout) {\n clearTimeout(this.touchTimeout);\n }\n this.touchTimeout = setTimeout(() => this._maybeEnableCycle(), TOUCHEVENT_COMPAT_WAIT + this._config.interval);\n };\n const swipeConfig = {\n leftCallback: () => this._slide(this._directionToOrder(DIRECTION_LEFT)),\n rightCallback: () => this._slide(this._directionToOrder(DIRECTION_RIGHT)),\n endCallback: endCallBack\n };\n this._swipeHelper = new Swipe(this._element, swipeConfig);\n }\n _keydown(event) {\n if (/input|textarea/i.test(event.target.tagName)) {\n return;\n }\n const direction = KEY_TO_DIRECTION[event.key];\n if (direction) {\n event.preventDefault();\n this._slide(this._directionToOrder(direction));\n }\n }\n _getItemIndex(element) {\n return this._getItems().indexOf(element);\n }\n _setActiveIndicatorElement(index) {\n if (!this._indicatorsElement) {\n return;\n }\n const activeIndicator = SelectorEngine.findOne(SELECTOR_ACTIVE, this._indicatorsElement);\n activeIndicator.classList.remove(CLASS_NAME_ACTIVE$2);\n activeIndicator.removeAttribute('aria-current');\n const newActiveIndicator = SelectorEngine.findOne(`[data-bs-slide-to=\"${index}\"]`, this._indicatorsElement);\n if (newActiveIndicator) {\n newActiveIndicator.classList.add(CLASS_NAME_ACTIVE$2);\n newActiveIndicator.setAttribute('aria-current', 'true');\n }\n }\n _updateInterval() {\n const element = this._activeElement || this._getActive();\n if (!element) {\n return;\n }\n const elementInterval = Number.parseInt(element.getAttribute('data-bs-interval'), 10);\n this._config.interval = elementInterval || this._config.defaultInterval;\n }\n _slide(order, element = null) {\n if (this._isSliding) {\n return;\n }\n const activeElement = this._getActive();\n const isNext = order === ORDER_NEXT;\n const nextElement = element || getNextActiveElement(this._getItems(), activeElement, isNext, this._config.wrap);\n if (nextElement === activeElement) {\n return;\n }\n const nextElementIndex = this._getItemIndex(nextElement);\n const triggerEvent = eventName => {\n return EventHandler.trigger(this._element, eventName, {\n relatedTarget: nextElement,\n direction: this._orderToDirection(order),\n from: this._getItemIndex(activeElement),\n to: nextElementIndex\n });\n };\n const slideEvent = triggerEvent(EVENT_SLIDE);\n if (slideEvent.defaultPrevented) {\n return;\n }\n if (!activeElement || !nextElement) {\n // Some weirdness is happening, so we bail\n // TODO: change tests that use empty divs to avoid this check\n return;\n }\n const isCycling = Boolean(this._interval);\n this.pause();\n this._isSliding = true;\n this._setActiveIndicatorElement(nextElementIndex);\n this._activeElement = nextElement;\n const directionalClassName = isNext ? CLASS_NAME_START : CLASS_NAME_END;\n const orderClassName = isNext ? CLASS_NAME_NEXT : CLASS_NAME_PREV;\n nextElement.classList.add(orderClassName);\n reflow(nextElement);\n activeElement.classList.add(directionalClassName);\n nextElement.classList.add(directionalClassName);\n const completeCallBack = () => {\n nextElement.classList.remove(directionalClassName, orderClassName);\n nextElement.classList.add(CLASS_NAME_ACTIVE$2);\n activeElement.classList.remove(CLASS_NAME_ACTIVE$2, orderClassName, directionalClassName);\n this._isSliding = false;\n triggerEvent(EVENT_SLID);\n };\n this._queueCallback(completeCallBack, activeElement, this._isAnimated());\n if (isCycling) {\n this.cycle();\n }\n }\n _isAnimated() {\n return this._element.classList.contains(CLASS_NAME_SLIDE);\n }\n _getActive() {\n return SelectorEngine.findOne(SELECTOR_ACTIVE_ITEM, this._element);\n }\n _getItems() {\n return SelectorEngine.find(SELECTOR_ITEM, this._element);\n }\n _clearInterval() {\n if (this._interval) {\n clearInterval(this._interval);\n this._interval = null;\n }\n }\n _directionToOrder(direction) {\n if (isRTL()) {\n return direction === DIRECTION_LEFT ? ORDER_PREV : ORDER_NEXT;\n }\n return direction === DIRECTION_LEFT ? ORDER_NEXT : ORDER_PREV;\n }\n _orderToDirection(order) {\n if (isRTL()) {\n return order === ORDER_PREV ? DIRECTION_LEFT : DIRECTION_RIGHT;\n }\n return order === ORDER_PREV ? DIRECTION_RIGHT : DIRECTION_LEFT;\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Carousel.getOrCreateInstance(this, config);\n if (typeof config === 'number') {\n data.to(config);\n return;\n }\n if (typeof config === 'string') {\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`);\n }\n data[config]();\n }\n });\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API$5, SELECTOR_DATA_SLIDE, function (event) {\n const target = SelectorEngine.getElementFromSelector(this);\n if (!target || !target.classList.contains(CLASS_NAME_CAROUSEL)) {\n return;\n }\n event.preventDefault();\n const carousel = Carousel.getOrCreateInstance(target);\n const slideIndex = this.getAttribute('data-bs-slide-to');\n if (slideIndex) {\n carousel.to(slideIndex);\n carousel._maybeEnableCycle();\n return;\n }\n if (Manipulator.getDataAttribute(this, 'slide') === 'next') {\n carousel.next();\n carousel._maybeEnableCycle();\n return;\n }\n carousel.prev();\n carousel._maybeEnableCycle();\n});\nEventHandler.on(window, EVENT_LOAD_DATA_API$3, () => {\n const carousels = SelectorEngine.find(SELECTOR_DATA_RIDE);\n for (const carousel of carousels) {\n Carousel.getOrCreateInstance(carousel);\n }\n});\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Carousel);\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap collapse.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n\n/**\n * Constants\n */\n\nconst NAME$b = 'collapse';\nconst DATA_KEY$7 = 'bs.collapse';\nconst EVENT_KEY$7 = `.${DATA_KEY$7}`;\nconst DATA_API_KEY$4 = '.data-api';\nconst EVENT_SHOW$6 = `show${EVENT_KEY$7}`;\nconst EVENT_SHOWN$6 = `shown${EVENT_KEY$7}`;\nconst EVENT_HIDE$6 = `hide${EVENT_KEY$7}`;\nconst EVENT_HIDDEN$6 = `hidden${EVENT_KEY$7}`;\nconst EVENT_CLICK_DATA_API$4 = `click${EVENT_KEY$7}${DATA_API_KEY$4}`;\nconst CLASS_NAME_SHOW$7 = 'show';\nconst CLASS_NAME_COLLAPSE = 'collapse';\nconst CLASS_NAME_COLLAPSING = 'collapsing';\nconst CLASS_NAME_COLLAPSED = 'collapsed';\nconst CLASS_NAME_DEEPER_CHILDREN = `:scope .${CLASS_NAME_COLLAPSE} .${CLASS_NAME_COLLAPSE}`;\nconst CLASS_NAME_HORIZONTAL = 'collapse-horizontal';\nconst WIDTH = 'width';\nconst HEIGHT = 'height';\nconst SELECTOR_ACTIVES = '.collapse.show, .collapse.collapsing';\nconst SELECTOR_DATA_TOGGLE$4 = '[data-bs-toggle=\"collapse\"]';\nconst Default$a = {\n parent: null,\n toggle: true\n};\nconst DefaultType$a = {\n parent: '(null|element)',\n toggle: 'boolean'\n};\n\n/**\n * Class definition\n */\n\nclass Collapse extends BaseComponent {\n constructor(element, config) {\n super(element, config);\n this._isTransitioning = false;\n this._triggerArray = [];\n const toggleList = SelectorEngine.find(SELECTOR_DATA_TOGGLE$4);\n for (const elem of toggleList) {\n const selector = SelectorEngine.getSelectorFromElement(elem);\n const filterElement = SelectorEngine.find(selector).filter(foundElement => foundElement === this._element);\n if (selector !== null && filterElement.length) {\n this._triggerArray.push(elem);\n }\n }\n this._initializeChildren();\n if (!this._config.parent) {\n this._addAriaAndCollapsedClass(this._triggerArray, this._isShown());\n }\n if (this._config.toggle) {\n this.toggle();\n }\n }\n\n // Getters\n static get Default() {\n return Default$a;\n }\n static get DefaultType() {\n return DefaultType$a;\n }\n static get NAME() {\n return NAME$b;\n }\n\n // Public\n toggle() {\n if (this._isShown()) {\n this.hide();\n } else {\n this.show();\n }\n }\n show() {\n if (this._isTransitioning || this._isShown()) {\n return;\n }\n let activeChildren = [];\n\n // find active children\n if (this._config.parent) {\n activeChildren = this._getFirstLevelChildren(SELECTOR_ACTIVES).filter(element => element !== this._element).map(element => Collapse.getOrCreateInstance(element, {\n toggle: false\n }));\n }\n if (activeChildren.length && activeChildren[0]._isTransitioning) {\n return;\n }\n const startEvent = EventHandler.trigger(this._element, EVENT_SHOW$6);\n if (startEvent.defaultPrevented) {\n return;\n }\n for (const activeInstance of activeChildren) {\n activeInstance.hide();\n }\n const dimension = this._getDimension();\n this._element.classList.remove(CLASS_NAME_COLLAPSE);\n this._element.classList.add(CLASS_NAME_COLLAPSING);\n this._element.style[dimension] = 0;\n this._addAriaAndCollapsedClass(this._triggerArray, true);\n this._isTransitioning = true;\n const complete = () => {\n this._isTransitioning = false;\n this._element.classList.remove(CLASS_NAME_COLLAPSING);\n this._element.classList.add(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW$7);\n this._element.style[dimension] = '';\n EventHandler.trigger(this._element, EVENT_SHOWN$6);\n };\n const capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1);\n const scrollSize = `scroll${capitalizedDimension}`;\n this._queueCallback(complete, this._element, true);\n this._element.style[dimension] = `${this._element[scrollSize]}px`;\n }\n hide() {\n if (this._isTransitioning || !this._isShown()) {\n return;\n }\n const startEvent = EventHandler.trigger(this._element, EVENT_HIDE$6);\n if (startEvent.defaultPrevented) {\n return;\n }\n const dimension = this._getDimension();\n this._element.style[dimension] = `${this._element.getBoundingClientRect()[dimension]}px`;\n reflow(this._element);\n this._element.classList.add(CLASS_NAME_COLLAPSING);\n this._element.classList.remove(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW$7);\n for (const trigger of this._triggerArray) {\n const element = SelectorEngine.getElementFromSelector(trigger);\n if (element && !this._isShown(element)) {\n this._addAriaAndCollapsedClass([trigger], false);\n }\n }\n this._isTransitioning = true;\n const complete = () => {\n this._isTransitioning = false;\n this._element.classList.remove(CLASS_NAME_COLLAPSING);\n this._element.classList.add(CLASS_NAME_COLLAPSE);\n EventHandler.trigger(this._element, EVENT_HIDDEN$6);\n };\n this._element.style[dimension] = '';\n this._queueCallback(complete, this._element, true);\n }\n _isShown(element = this._element) {\n return element.classList.contains(CLASS_NAME_SHOW$7);\n }\n\n // Private\n _configAfterMerge(config) {\n config.toggle = Boolean(config.toggle); // Coerce string values\n config.parent = getElement(config.parent);\n return config;\n }\n _getDimension() {\n return this._element.classList.contains(CLASS_NAME_HORIZONTAL) ? WIDTH : HEIGHT;\n }\n _initializeChildren() {\n if (!this._config.parent) {\n return;\n }\n const children = this._getFirstLevelChildren(SELECTOR_DATA_TOGGLE$4);\n for (const element of children) {\n const selected = SelectorEngine.getElementFromSelector(element);\n if (selected) {\n this._addAriaAndCollapsedClass([element], this._isShown(selected));\n }\n }\n }\n _getFirstLevelChildren(selector) {\n const children = SelectorEngine.find(CLASS_NAME_DEEPER_CHILDREN, this._config.parent);\n // remove children if greater depth\n return SelectorEngine.find(selector, this._config.parent).filter(element => !children.includes(element));\n }\n _addAriaAndCollapsedClass(triggerArray, isOpen) {\n if (!triggerArray.length) {\n return;\n }\n for (const element of triggerArray) {\n element.classList.toggle(CLASS_NAME_COLLAPSED, !isOpen);\n element.setAttribute('aria-expanded', isOpen);\n }\n }\n\n // Static\n static jQueryInterface(config) {\n const _config = {};\n if (typeof config === 'string' && /show|hide/.test(config)) {\n _config.toggle = false;\n }\n return this.each(function () {\n const data = Collapse.getOrCreateInstance(this, _config);\n if (typeof config === 'string') {\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`);\n }\n data[config]();\n }\n });\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API$4, SELECTOR_DATA_TOGGLE$4, function (event) {\n // preventDefault only for elements (which change the URL) not inside the collapsible element\n if (event.target.tagName === 'A' || event.delegateTarget && event.delegateTarget.tagName === 'A') {\n event.preventDefault();\n }\n for (const element of SelectorEngine.getMultipleElementsFromSelector(this)) {\n Collapse.getOrCreateInstance(element, {\n toggle: false\n }).toggle();\n }\n});\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Collapse);\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap dropdown.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n\n/**\n * Constants\n */\n\nconst NAME$a = 'dropdown';\nconst DATA_KEY$6 = 'bs.dropdown';\nconst EVENT_KEY$6 = `.${DATA_KEY$6}`;\nconst DATA_API_KEY$3 = '.data-api';\nconst ESCAPE_KEY$2 = 'Escape';\nconst TAB_KEY$1 = 'Tab';\nconst ARROW_UP_KEY$1 = 'ArrowUp';\nconst ARROW_DOWN_KEY$1 = 'ArrowDown';\nconst RIGHT_MOUSE_BUTTON = 2; // MouseEvent.button value for the secondary button, usually the right button\n\nconst EVENT_HIDE$5 = `hide${EVENT_KEY$6}`;\nconst EVENT_HIDDEN$5 = `hidden${EVENT_KEY$6}`;\nconst EVENT_SHOW$5 = `show${EVENT_KEY$6}`;\nconst EVENT_SHOWN$5 = `shown${EVENT_KEY$6}`;\nconst EVENT_CLICK_DATA_API$3 = `click${EVENT_KEY$6}${DATA_API_KEY$3}`;\nconst EVENT_KEYDOWN_DATA_API = `keydown${EVENT_KEY$6}${DATA_API_KEY$3}`;\nconst EVENT_KEYUP_DATA_API = `keyup${EVENT_KEY$6}${DATA_API_KEY$3}`;\nconst CLASS_NAME_SHOW$6 = 'show';\nconst CLASS_NAME_DROPUP = 'dropup';\nconst CLASS_NAME_DROPEND = 'dropend';\nconst CLASS_NAME_DROPSTART = 'dropstart';\nconst CLASS_NAME_DROPUP_CENTER = 'dropup-center';\nconst CLASS_NAME_DROPDOWN_CENTER = 'dropdown-center';\nconst SELECTOR_DATA_TOGGLE$3 = '[data-bs-toggle=\"dropdown\"]:not(.disabled):not(:disabled)';\nconst SELECTOR_DATA_TOGGLE_SHOWN = `${SELECTOR_DATA_TOGGLE$3}.${CLASS_NAME_SHOW$6}`;\nconst SELECTOR_MENU = '.dropdown-menu';\nconst SELECTOR_NAVBAR = '.navbar';\nconst SELECTOR_NAVBAR_NAV = '.navbar-nav';\nconst SELECTOR_VISIBLE_ITEMS = '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)';\nconst PLACEMENT_TOP = isRTL() ? 'top-end' : 'top-start';\nconst PLACEMENT_TOPEND = isRTL() ? 'top-start' : 'top-end';\nconst PLACEMENT_BOTTOM = isRTL() ? 'bottom-end' : 'bottom-start';\nconst PLACEMENT_BOTTOMEND = isRTL() ? 'bottom-start' : 'bottom-end';\nconst PLACEMENT_RIGHT = isRTL() ? 'left-start' : 'right-start';\nconst PLACEMENT_LEFT = isRTL() ? 'right-start' : 'left-start';\nconst PLACEMENT_TOPCENTER = 'top';\nconst PLACEMENT_BOTTOMCENTER = 'bottom';\nconst Default$9 = {\n autoClose: true,\n boundary: 'clippingParents',\n display: 'dynamic',\n offset: [0, 2],\n popperConfig: null,\n reference: 'toggle'\n};\nconst DefaultType$9 = {\n autoClose: '(boolean|string)',\n boundary: '(string|element)',\n display: 'string',\n offset: '(array|string|function)',\n popperConfig: '(null|object|function)',\n reference: '(string|element|object)'\n};\n\n/**\n * Class definition\n */\n\nclass Dropdown extends BaseComponent {\n constructor(element, config) {\n super(element, config);\n this._popper = null;\n this._parent = this._element.parentNode; // dropdown wrapper\n // TODO: v6 revert #37011 & change markup https://getbootstrap.com/docs/5.3/forms/input-group/\n this._menu = SelectorEngine.next(this._element, SELECTOR_MENU)[0] || SelectorEngine.prev(this._element, SELECTOR_MENU)[0] || SelectorEngine.findOne(SELECTOR_MENU, this._parent);\n this._inNavbar = this._detectNavbar();\n }\n\n // Getters\n static get Default() {\n return Default$9;\n }\n static get DefaultType() {\n return DefaultType$9;\n }\n static get NAME() {\n return NAME$a;\n }\n\n // Public\n toggle() {\n return this._isShown() ? this.hide() : this.show();\n }\n show() {\n if (isDisabled(this._element) || this._isShown()) {\n return;\n }\n const relatedTarget = {\n relatedTarget: this._element\n };\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW$5, relatedTarget);\n if (showEvent.defaultPrevented) {\n return;\n }\n this._createPopper();\n\n // If this is a touch-enabled device we add extra\n // empty mouseover listeners to the body's immediate children;\n // only needed because of broken event delegation on iOS\n // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html\n if ('ontouchstart' in document.documentElement && !this._parent.closest(SELECTOR_NAVBAR_NAV)) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.on(element, 'mouseover', bootstrap_esm_noop);\n }\n }\n this._element.focus();\n this._element.setAttribute('aria-expanded', true);\n this._menu.classList.add(CLASS_NAME_SHOW$6);\n this._element.classList.add(CLASS_NAME_SHOW$6);\n EventHandler.trigger(this._element, EVENT_SHOWN$5, relatedTarget);\n }\n hide() {\n if (isDisabled(this._element) || !this._isShown()) {\n return;\n }\n const relatedTarget = {\n relatedTarget: this._element\n };\n this._completeHide(relatedTarget);\n }\n dispose() {\n if (this._popper) {\n this._popper.destroy();\n }\n super.dispose();\n }\n update() {\n this._inNavbar = this._detectNavbar();\n if (this._popper) {\n this._popper.update();\n }\n }\n\n // Private\n _completeHide(relatedTarget) {\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE$5, relatedTarget);\n if (hideEvent.defaultPrevented) {\n return;\n }\n\n // If this is a touch-enabled device we remove the extra\n // empty mouseover listeners we added for iOS support\n if ('ontouchstart' in document.documentElement) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.off(element, 'mouseover', bootstrap_esm_noop);\n }\n }\n if (this._popper) {\n this._popper.destroy();\n }\n this._menu.classList.remove(CLASS_NAME_SHOW$6);\n this._element.classList.remove(CLASS_NAME_SHOW$6);\n this._element.setAttribute('aria-expanded', 'false');\n Manipulator.removeDataAttribute(this._menu, 'popper');\n EventHandler.trigger(this._element, EVENT_HIDDEN$5, relatedTarget);\n }\n _getConfig(config) {\n config = super._getConfig(config);\n if (typeof config.reference === 'object' && !bootstrap_esm_isElement(config.reference) && typeof config.reference.getBoundingClientRect !== 'function') {\n // Popper virtual elements require a getBoundingClientRect method\n throw new TypeError(`${NAME$a.toUpperCase()}: Option \"reference\" provided type \"object\" without a required \"getBoundingClientRect\" method.`);\n }\n return config;\n }\n _createPopper() {\n if (typeof lib_namespaceObject === 'undefined') {\n throw new TypeError('Bootstrap\\'s dropdowns require Popper (https://popper.js.org)');\n }\n let referenceElement = this._element;\n if (this._config.reference === 'parent') {\n referenceElement = this._parent;\n } else if (bootstrap_esm_isElement(this._config.reference)) {\n referenceElement = getElement(this._config.reference);\n } else if (typeof this._config.reference === 'object') {\n referenceElement = this._config.reference;\n }\n const popperConfig = this._getPopperConfig();\n this._popper = popper_createPopper(referenceElement, this._menu, popperConfig);\n }\n _isShown() {\n return this._menu.classList.contains(CLASS_NAME_SHOW$6);\n }\n _getPlacement() {\n const parentDropdown = this._parent;\n if (parentDropdown.classList.contains(CLASS_NAME_DROPEND)) {\n return PLACEMENT_RIGHT;\n }\n if (parentDropdown.classList.contains(CLASS_NAME_DROPSTART)) {\n return PLACEMENT_LEFT;\n }\n if (parentDropdown.classList.contains(CLASS_NAME_DROPUP_CENTER)) {\n return PLACEMENT_TOPCENTER;\n }\n if (parentDropdown.classList.contains(CLASS_NAME_DROPDOWN_CENTER)) {\n return PLACEMENT_BOTTOMCENTER;\n }\n\n // We need to trim the value because custom properties can also include spaces\n const isEnd = getComputedStyle(this._menu).getPropertyValue('--bs-position').trim() === 'end';\n if (parentDropdown.classList.contains(CLASS_NAME_DROPUP)) {\n return isEnd ? PLACEMENT_TOPEND : PLACEMENT_TOP;\n }\n return isEnd ? PLACEMENT_BOTTOMEND : PLACEMENT_BOTTOM;\n }\n _detectNavbar() {\n return this._element.closest(SELECTOR_NAVBAR) !== null;\n }\n _getOffset() {\n const {\n offset\n } = this._config;\n if (typeof offset === 'string') {\n return offset.split(',').map(value => Number.parseInt(value, 10));\n }\n if (typeof offset === 'function') {\n return popperData => offset(popperData, this._element);\n }\n return offset;\n }\n _getPopperConfig() {\n const defaultBsPopperConfig = {\n placement: this._getPlacement(),\n modifiers: [{\n name: 'preventOverflow',\n options: {\n boundary: this._config.boundary\n }\n }, {\n name: 'offset',\n options: {\n offset: this._getOffset()\n }\n }]\n };\n\n // Disable Popper if we have a static display or Dropdown is in Navbar\n if (this._inNavbar || this._config.display === 'static') {\n Manipulator.setDataAttribute(this._menu, 'popper', 'static'); // TODO: v6 remove\n defaultBsPopperConfig.modifiers = [{\n name: 'applyStyles',\n enabled: false\n }];\n }\n return {\n ...defaultBsPopperConfig,\n ...execute(this._config.popperConfig, [defaultBsPopperConfig])\n };\n }\n _selectMenuItem({\n key,\n target\n }) {\n const items = SelectorEngine.find(SELECTOR_VISIBLE_ITEMS, this._menu).filter(element => isVisible(element));\n if (!items.length) {\n return;\n }\n\n // if target isn't included in items (e.g. when expanding the dropdown)\n // allow cycling to get the last item in case key equals ARROW_UP_KEY\n getNextActiveElement(items, target, key === ARROW_DOWN_KEY$1, !items.includes(target)).focus();\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Dropdown.getOrCreateInstance(this, config);\n if (typeof config !== 'string') {\n return;\n }\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`);\n }\n data[config]();\n });\n }\n static clearMenus(event) {\n if (event.button === RIGHT_MOUSE_BUTTON || event.type === 'keyup' && event.key !== TAB_KEY$1) {\n return;\n }\n const openToggles = SelectorEngine.find(SELECTOR_DATA_TOGGLE_SHOWN);\n for (const toggle of openToggles) {\n const context = Dropdown.getInstance(toggle);\n if (!context || context._config.autoClose === false) {\n continue;\n }\n const composedPath = event.composedPath();\n const isMenuTarget = composedPath.includes(context._menu);\n if (composedPath.includes(context._element) || context._config.autoClose === 'inside' && !isMenuTarget || context._config.autoClose === 'outside' && isMenuTarget) {\n continue;\n }\n\n // Tab navigation through the dropdown menu or events from contained inputs shouldn't close the menu\n if (context._menu.contains(event.target) && (event.type === 'keyup' && event.key === TAB_KEY$1 || /input|select|option|textarea|form/i.test(event.target.tagName))) {\n continue;\n }\n const relatedTarget = {\n relatedTarget: context._element\n };\n if (event.type === 'click') {\n relatedTarget.clickEvent = event;\n }\n context._completeHide(relatedTarget);\n }\n }\n static dataApiKeydownHandler(event) {\n // If not an UP | DOWN | ESCAPE key => not a dropdown command\n // If input/textarea && if key is other than ESCAPE => not a dropdown command\n\n const isInput = /input|textarea/i.test(event.target.tagName);\n const isEscapeEvent = event.key === ESCAPE_KEY$2;\n const isUpOrDownEvent = [ARROW_UP_KEY$1, ARROW_DOWN_KEY$1].includes(event.key);\n if (!isUpOrDownEvent && !isEscapeEvent) {\n return;\n }\n if (isInput && !isEscapeEvent) {\n return;\n }\n event.preventDefault();\n\n // TODO: v6 revert #37011 & change markup https://getbootstrap.com/docs/5.3/forms/input-group/\n const getToggleButton = this.matches(SELECTOR_DATA_TOGGLE$3) ? this : SelectorEngine.prev(this, SELECTOR_DATA_TOGGLE$3)[0] || SelectorEngine.next(this, SELECTOR_DATA_TOGGLE$3)[0] || SelectorEngine.findOne(SELECTOR_DATA_TOGGLE$3, event.delegateTarget.parentNode);\n const instance = Dropdown.getOrCreateInstance(getToggleButton);\n if (isUpOrDownEvent) {\n event.stopPropagation();\n instance.show();\n instance._selectMenuItem(event);\n return;\n }\n if (instance._isShown()) {\n // else is escape and we check if it is shown\n event.stopPropagation();\n instance.hide();\n getToggleButton.focus();\n }\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_DATA_TOGGLE$3, Dropdown.dataApiKeydownHandler);\nEventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_MENU, Dropdown.dataApiKeydownHandler);\nEventHandler.on(document, EVENT_CLICK_DATA_API$3, Dropdown.clearMenus);\nEventHandler.on(document, EVENT_KEYUP_DATA_API, Dropdown.clearMenus);\nEventHandler.on(document, EVENT_CLICK_DATA_API$3, SELECTOR_DATA_TOGGLE$3, function (event) {\n event.preventDefault();\n Dropdown.getOrCreateInstance(this).toggle();\n});\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Dropdown);\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap util/backdrop.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n\n/**\n * Constants\n */\n\nconst NAME$9 = 'backdrop';\nconst CLASS_NAME_FADE$4 = 'fade';\nconst CLASS_NAME_SHOW$5 = 'show';\nconst EVENT_MOUSEDOWN = `mousedown.bs.${NAME$9}`;\nconst Default$8 = {\n className: 'modal-backdrop',\n clickCallback: null,\n isAnimated: false,\n isVisible: true,\n // if false, we use the backdrop helper without adding any element to the dom\n rootElement: 'body' // give the choice to place backdrop under different elements\n};\nconst DefaultType$8 = {\n className: 'string',\n clickCallback: '(function|null)',\n isAnimated: 'boolean',\n isVisible: 'boolean',\n rootElement: '(element|string)'\n};\n\n/**\n * Class definition\n */\n\nclass Backdrop extends bootstrap_esm_Config {\n constructor(config) {\n super();\n this._config = this._getConfig(config);\n this._isAppended = false;\n this._element = null;\n }\n\n // Getters\n static get Default() {\n return Default$8;\n }\n static get DefaultType() {\n return DefaultType$8;\n }\n static get NAME() {\n return NAME$9;\n }\n\n // Public\n show(callback) {\n if (!this._config.isVisible) {\n execute(callback);\n return;\n }\n this._append();\n const element = this._getElement();\n if (this._config.isAnimated) {\n reflow(element);\n }\n element.classList.add(CLASS_NAME_SHOW$5);\n this._emulateAnimation(() => {\n execute(callback);\n });\n }\n hide(callback) {\n if (!this._config.isVisible) {\n execute(callback);\n return;\n }\n this._getElement().classList.remove(CLASS_NAME_SHOW$5);\n this._emulateAnimation(() => {\n this.dispose();\n execute(callback);\n });\n }\n dispose() {\n if (!this._isAppended) {\n return;\n }\n EventHandler.off(this._element, EVENT_MOUSEDOWN);\n this._element.remove();\n this._isAppended = false;\n }\n\n // Private\n _getElement() {\n if (!this._element) {\n const backdrop = document.createElement('div');\n backdrop.className = this._config.className;\n if (this._config.isAnimated) {\n backdrop.classList.add(CLASS_NAME_FADE$4);\n }\n this._element = backdrop;\n }\n return this._element;\n }\n _configAfterMerge(config) {\n // use getElement() with the default \"body\" to get a fresh Element on each instantiation\n config.rootElement = getElement(config.rootElement);\n return config;\n }\n _append() {\n if (this._isAppended) {\n return;\n }\n const element = this._getElement();\n this._config.rootElement.append(element);\n EventHandler.on(element, EVENT_MOUSEDOWN, () => {\n execute(this._config.clickCallback);\n });\n this._isAppended = true;\n }\n _emulateAnimation(callback) {\n executeAfterTransition(callback, this._getElement(), this._config.isAnimated);\n }\n}\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap util/focustrap.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n\n/**\n * Constants\n */\n\nconst NAME$8 = 'focustrap';\nconst DATA_KEY$5 = 'bs.focustrap';\nconst EVENT_KEY$5 = `.${DATA_KEY$5}`;\nconst EVENT_FOCUSIN$2 = `focusin${EVENT_KEY$5}`;\nconst EVENT_KEYDOWN_TAB = `keydown.tab${EVENT_KEY$5}`;\nconst TAB_KEY = 'Tab';\nconst TAB_NAV_FORWARD = 'forward';\nconst TAB_NAV_BACKWARD = 'backward';\nconst Default$7 = {\n autofocus: true,\n trapElement: null // The element to trap focus inside of\n};\nconst DefaultType$7 = {\n autofocus: 'boolean',\n trapElement: 'element'\n};\n\n/**\n * Class definition\n */\n\nclass FocusTrap extends bootstrap_esm_Config {\n constructor(config) {\n super();\n this._config = this._getConfig(config);\n this._isActive = false;\n this._lastTabNavDirection = null;\n }\n\n // Getters\n static get Default() {\n return Default$7;\n }\n static get DefaultType() {\n return DefaultType$7;\n }\n static get NAME() {\n return NAME$8;\n }\n\n // Public\n activate() {\n if (this._isActive) {\n return;\n }\n if (this._config.autofocus) {\n this._config.trapElement.focus();\n }\n EventHandler.off(document, EVENT_KEY$5); // guard against infinite focus loop\n EventHandler.on(document, EVENT_FOCUSIN$2, event => this._handleFocusin(event));\n EventHandler.on(document, EVENT_KEYDOWN_TAB, event => this._handleKeydown(event));\n this._isActive = true;\n }\n deactivate() {\n if (!this._isActive) {\n return;\n }\n this._isActive = false;\n EventHandler.off(document, EVENT_KEY$5);\n }\n\n // Private\n _handleFocusin(event) {\n const {\n trapElement\n } = this._config;\n if (event.target === document || event.target === trapElement || trapElement.contains(event.target)) {\n return;\n }\n const elements = SelectorEngine.focusableChildren(trapElement);\n if (elements.length === 0) {\n trapElement.focus();\n } else if (this._lastTabNavDirection === TAB_NAV_BACKWARD) {\n elements[elements.length - 1].focus();\n } else {\n elements[0].focus();\n }\n }\n _handleKeydown(event) {\n if (event.key !== TAB_KEY) {\n return;\n }\n this._lastTabNavDirection = event.shiftKey ? TAB_NAV_BACKWARD : TAB_NAV_FORWARD;\n }\n}\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap util/scrollBar.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n\n/**\n * Constants\n */\n\nconst SELECTOR_FIXED_CONTENT = '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top';\nconst SELECTOR_STICKY_CONTENT = '.sticky-top';\nconst PROPERTY_PADDING = 'padding-right';\nconst PROPERTY_MARGIN = 'margin-right';\n\n/**\n * Class definition\n */\n\nclass ScrollBarHelper {\n constructor() {\n this._element = document.body;\n }\n\n // Public\n getWidth() {\n // https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth#usage_notes\n const documentWidth = document.documentElement.clientWidth;\n return Math.abs(window.innerWidth - documentWidth);\n }\n hide() {\n const width = this.getWidth();\n this._disableOverFlow();\n // give padding to element to balance the hidden scrollbar width\n this._setElementAttributes(this._element, PROPERTY_PADDING, calculatedValue => calculatedValue + width);\n // trick: We adjust positive paddingRight and negative marginRight to sticky-top elements to keep showing fullwidth\n this._setElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING, calculatedValue => calculatedValue + width);\n this._setElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN, calculatedValue => calculatedValue - width);\n }\n reset() {\n this._resetElementAttributes(this._element, 'overflow');\n this._resetElementAttributes(this._element, PROPERTY_PADDING);\n this._resetElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING);\n this._resetElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN);\n }\n isOverflowing() {\n return this.getWidth() > 0;\n }\n\n // Private\n _disableOverFlow() {\n this._saveInitialAttribute(this._element, 'overflow');\n this._element.style.overflow = 'hidden';\n }\n _setElementAttributes(selector, styleProperty, callback) {\n const scrollbarWidth = this.getWidth();\n const manipulationCallBack = element => {\n if (element !== this._element && window.innerWidth > element.clientWidth + scrollbarWidth) {\n return;\n }\n this._saveInitialAttribute(element, styleProperty);\n const calculatedValue = window.getComputedStyle(element).getPropertyValue(styleProperty);\n element.style.setProperty(styleProperty, `${callback(Number.parseFloat(calculatedValue))}px`);\n };\n this._applyManipulationCallback(selector, manipulationCallBack);\n }\n _saveInitialAttribute(element, styleProperty) {\n const actualValue = element.style.getPropertyValue(styleProperty);\n if (actualValue) {\n Manipulator.setDataAttribute(element, styleProperty, actualValue);\n }\n }\n _resetElementAttributes(selector, styleProperty) {\n const manipulationCallBack = element => {\n const value = Manipulator.getDataAttribute(element, styleProperty);\n // We only want to remove the property if the value is `null`; the value can also be zero\n if (value === null) {\n element.style.removeProperty(styleProperty);\n return;\n }\n Manipulator.removeDataAttribute(element, styleProperty);\n element.style.setProperty(styleProperty, value);\n };\n this._applyManipulationCallback(selector, manipulationCallBack);\n }\n _applyManipulationCallback(selector, callBack) {\n if (bootstrap_esm_isElement(selector)) {\n callBack(selector);\n return;\n }\n for (const sel of SelectorEngine.find(selector, this._element)) {\n callBack(sel);\n }\n }\n}\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap modal.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n\n/**\n * Constants\n */\n\nconst NAME$7 = 'modal';\nconst DATA_KEY$4 = 'bs.modal';\nconst EVENT_KEY$4 = `.${DATA_KEY$4}`;\nconst DATA_API_KEY$2 = '.data-api';\nconst ESCAPE_KEY$1 = 'Escape';\nconst EVENT_HIDE$4 = `hide${EVENT_KEY$4}`;\nconst EVENT_HIDE_PREVENTED$1 = `hidePrevented${EVENT_KEY$4}`;\nconst EVENT_HIDDEN$4 = `hidden${EVENT_KEY$4}`;\nconst EVENT_SHOW$4 = `show${EVENT_KEY$4}`;\nconst EVENT_SHOWN$4 = `shown${EVENT_KEY$4}`;\nconst EVENT_RESIZE$1 = `resize${EVENT_KEY$4}`;\nconst EVENT_CLICK_DISMISS = `click.dismiss${EVENT_KEY$4}`;\nconst EVENT_MOUSEDOWN_DISMISS = `mousedown.dismiss${EVENT_KEY$4}`;\nconst EVENT_KEYDOWN_DISMISS$1 = `keydown.dismiss${EVENT_KEY$4}`;\nconst EVENT_CLICK_DATA_API$2 = `click${EVENT_KEY$4}${DATA_API_KEY$2}`;\nconst CLASS_NAME_OPEN = 'modal-open';\nconst CLASS_NAME_FADE$3 = 'fade';\nconst CLASS_NAME_SHOW$4 = 'show';\nconst CLASS_NAME_STATIC = 'modal-static';\nconst OPEN_SELECTOR$1 = '.modal.show';\nconst SELECTOR_DIALOG = '.modal-dialog';\nconst SELECTOR_MODAL_BODY = '.modal-body';\nconst SELECTOR_DATA_TOGGLE$2 = '[data-bs-toggle=\"modal\"]';\nconst Default$6 = {\n backdrop: true,\n focus: true,\n keyboard: true\n};\nconst DefaultType$6 = {\n backdrop: '(boolean|string)',\n focus: 'boolean',\n keyboard: 'boolean'\n};\n\n/**\n * Class definition\n */\n\nclass Modal extends BaseComponent {\n constructor(element, config) {\n super(element, config);\n this._dialog = SelectorEngine.findOne(SELECTOR_DIALOG, this._element);\n this._backdrop = this._initializeBackDrop();\n this._focustrap = this._initializeFocusTrap();\n this._isShown = false;\n this._isTransitioning = false;\n this._scrollBar = new ScrollBarHelper();\n this._addEventListeners();\n }\n\n // Getters\n static get Default() {\n return Default$6;\n }\n static get DefaultType() {\n return DefaultType$6;\n }\n static get NAME() {\n return NAME$7;\n }\n\n // Public\n toggle(relatedTarget) {\n return this._isShown ? this.hide() : this.show(relatedTarget);\n }\n show(relatedTarget) {\n if (this._isShown || this._isTransitioning) {\n return;\n }\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW$4, {\n relatedTarget\n });\n if (showEvent.defaultPrevented) {\n return;\n }\n this._isShown = true;\n this._isTransitioning = true;\n this._scrollBar.hide();\n document.body.classList.add(CLASS_NAME_OPEN);\n this._adjustDialog();\n this._backdrop.show(() => this._showElement(relatedTarget));\n }\n hide() {\n if (!this._isShown || this._isTransitioning) {\n return;\n }\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE$4);\n if (hideEvent.defaultPrevented) {\n return;\n }\n this._isShown = false;\n this._isTransitioning = true;\n this._focustrap.deactivate();\n this._element.classList.remove(CLASS_NAME_SHOW$4);\n this._queueCallback(() => this._hideModal(), this._element, this._isAnimated());\n }\n dispose() {\n EventHandler.off(window, EVENT_KEY$4);\n EventHandler.off(this._dialog, EVENT_KEY$4);\n this._backdrop.dispose();\n this._focustrap.deactivate();\n super.dispose();\n }\n handleUpdate() {\n this._adjustDialog();\n }\n\n // Private\n _initializeBackDrop() {\n return new Backdrop({\n isVisible: Boolean(this._config.backdrop),\n // 'static' option will be translated to true, and booleans will keep their value,\n isAnimated: this._isAnimated()\n });\n }\n _initializeFocusTrap() {\n return new FocusTrap({\n trapElement: this._element\n });\n }\n _showElement(relatedTarget) {\n // try to append dynamic modal\n if (!document.body.contains(this._element)) {\n document.body.append(this._element);\n }\n this._element.style.display = 'block';\n this._element.removeAttribute('aria-hidden');\n this._element.setAttribute('aria-modal', true);\n this._element.setAttribute('role', 'dialog');\n this._element.scrollTop = 0;\n const modalBody = SelectorEngine.findOne(SELECTOR_MODAL_BODY, this._dialog);\n if (modalBody) {\n modalBody.scrollTop = 0;\n }\n reflow(this._element);\n this._element.classList.add(CLASS_NAME_SHOW$4);\n const transitionComplete = () => {\n if (this._config.focus) {\n this._focustrap.activate();\n }\n this._isTransitioning = false;\n EventHandler.trigger(this._element, EVENT_SHOWN$4, {\n relatedTarget\n });\n };\n this._queueCallback(transitionComplete, this._dialog, this._isAnimated());\n }\n _addEventListeners() {\n EventHandler.on(this._element, EVENT_KEYDOWN_DISMISS$1, event => {\n if (event.key !== ESCAPE_KEY$1) {\n return;\n }\n if (this._config.keyboard) {\n this.hide();\n return;\n }\n this._triggerBackdropTransition();\n });\n EventHandler.on(window, EVENT_RESIZE$1, () => {\n if (this._isShown && !this._isTransitioning) {\n this._adjustDialog();\n }\n });\n EventHandler.on(this._element, EVENT_MOUSEDOWN_DISMISS, event => {\n // a bad trick to segregate clicks that may start inside dialog but end outside, and avoid listen to scrollbar clicks\n EventHandler.one(this._element, EVENT_CLICK_DISMISS, event2 => {\n if (this._element !== event.target || this._element !== event2.target) {\n return;\n }\n if (this._config.backdrop === 'static') {\n this._triggerBackdropTransition();\n return;\n }\n if (this._config.backdrop) {\n this.hide();\n }\n });\n });\n }\n _hideModal() {\n this._element.style.display = 'none';\n this._element.setAttribute('aria-hidden', true);\n this._element.removeAttribute('aria-modal');\n this._element.removeAttribute('role');\n this._isTransitioning = false;\n this._backdrop.hide(() => {\n document.body.classList.remove(CLASS_NAME_OPEN);\n this._resetAdjustments();\n this._scrollBar.reset();\n EventHandler.trigger(this._element, EVENT_HIDDEN$4);\n });\n }\n _isAnimated() {\n return this._element.classList.contains(CLASS_NAME_FADE$3);\n }\n _triggerBackdropTransition() {\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED$1);\n if (hideEvent.defaultPrevented) {\n return;\n }\n const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight;\n const initialOverflowY = this._element.style.overflowY;\n // return if the following background transition hasn't yet completed\n if (initialOverflowY === 'hidden' || this._element.classList.contains(CLASS_NAME_STATIC)) {\n return;\n }\n if (!isModalOverflowing) {\n this._element.style.overflowY = 'hidden';\n }\n this._element.classList.add(CLASS_NAME_STATIC);\n this._queueCallback(() => {\n this._element.classList.remove(CLASS_NAME_STATIC);\n this._queueCallback(() => {\n this._element.style.overflowY = initialOverflowY;\n }, this._dialog);\n }, this._dialog);\n this._element.focus();\n }\n\n /**\n * The following methods are used to handle overflowing modals\n */\n\n _adjustDialog() {\n const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight;\n const scrollbarWidth = this._scrollBar.getWidth();\n const isBodyOverflowing = scrollbarWidth > 0;\n if (isBodyOverflowing && !isModalOverflowing) {\n const property = isRTL() ? 'paddingLeft' : 'paddingRight';\n this._element.style[property] = `${scrollbarWidth}px`;\n }\n if (!isBodyOverflowing && isModalOverflowing) {\n const property = isRTL() ? 'paddingRight' : 'paddingLeft';\n this._element.style[property] = `${scrollbarWidth}px`;\n }\n }\n _resetAdjustments() {\n this._element.style.paddingLeft = '';\n this._element.style.paddingRight = '';\n }\n\n // Static\n static jQueryInterface(config, relatedTarget) {\n return this.each(function () {\n const data = Modal.getOrCreateInstance(this, config);\n if (typeof config !== 'string') {\n return;\n }\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`);\n }\n data[config](relatedTarget);\n });\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API$2, SELECTOR_DATA_TOGGLE$2, function (event) {\n const target = SelectorEngine.getElementFromSelector(this);\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault();\n }\n EventHandler.one(target, EVENT_SHOW$4, showEvent => {\n if (showEvent.defaultPrevented) {\n // only register focus restorer if modal will actually get shown\n return;\n }\n EventHandler.one(target, EVENT_HIDDEN$4, () => {\n if (isVisible(this)) {\n this.focus();\n }\n });\n });\n\n // avoid conflict when clicking modal toggler while another one is open\n const alreadyOpen = SelectorEngine.findOne(OPEN_SELECTOR$1);\n if (alreadyOpen) {\n Modal.getInstance(alreadyOpen).hide();\n }\n const data = Modal.getOrCreateInstance(target);\n data.toggle(this);\n});\nenableDismissTrigger(Modal);\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Modal);\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap offcanvas.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n\n/**\n * Constants\n */\n\nconst NAME$6 = 'offcanvas';\nconst DATA_KEY$3 = 'bs.offcanvas';\nconst EVENT_KEY$3 = `.${DATA_KEY$3}`;\nconst DATA_API_KEY$1 = '.data-api';\nconst EVENT_LOAD_DATA_API$2 = `load${EVENT_KEY$3}${DATA_API_KEY$1}`;\nconst ESCAPE_KEY = 'Escape';\nconst CLASS_NAME_SHOW$3 = 'show';\nconst CLASS_NAME_SHOWING$1 = 'showing';\nconst CLASS_NAME_HIDING = 'hiding';\nconst CLASS_NAME_BACKDROP = 'offcanvas-backdrop';\nconst OPEN_SELECTOR = '.offcanvas.show';\nconst EVENT_SHOW$3 = `show${EVENT_KEY$3}`;\nconst EVENT_SHOWN$3 = `shown${EVENT_KEY$3}`;\nconst EVENT_HIDE$3 = `hide${EVENT_KEY$3}`;\nconst EVENT_HIDE_PREVENTED = `hidePrevented${EVENT_KEY$3}`;\nconst EVENT_HIDDEN$3 = `hidden${EVENT_KEY$3}`;\nconst EVENT_RESIZE = `resize${EVENT_KEY$3}`;\nconst EVENT_CLICK_DATA_API$1 = `click${EVENT_KEY$3}${DATA_API_KEY$1}`;\nconst EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY$3}`;\nconst SELECTOR_DATA_TOGGLE$1 = '[data-bs-toggle=\"offcanvas\"]';\nconst Default$5 = {\n backdrop: true,\n keyboard: true,\n scroll: false\n};\nconst DefaultType$5 = {\n backdrop: '(boolean|string)',\n keyboard: 'boolean',\n scroll: 'boolean'\n};\n\n/**\n * Class definition\n */\n\nclass Offcanvas extends BaseComponent {\n constructor(element, config) {\n super(element, config);\n this._isShown = false;\n this._backdrop = this._initializeBackDrop();\n this._focustrap = this._initializeFocusTrap();\n this._addEventListeners();\n }\n\n // Getters\n static get Default() {\n return Default$5;\n }\n static get DefaultType() {\n return DefaultType$5;\n }\n static get NAME() {\n return NAME$6;\n }\n\n // Public\n toggle(relatedTarget) {\n return this._isShown ? this.hide() : this.show(relatedTarget);\n }\n show(relatedTarget) {\n if (this._isShown) {\n return;\n }\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW$3, {\n relatedTarget\n });\n if (showEvent.defaultPrevented) {\n return;\n }\n this._isShown = true;\n this._backdrop.show();\n if (!this._config.scroll) {\n new ScrollBarHelper().hide();\n }\n this._element.setAttribute('aria-modal', true);\n this._element.setAttribute('role', 'dialog');\n this._element.classList.add(CLASS_NAME_SHOWING$1);\n const completeCallBack = () => {\n if (!this._config.scroll || this._config.backdrop) {\n this._focustrap.activate();\n }\n this._element.classList.add(CLASS_NAME_SHOW$3);\n this._element.classList.remove(CLASS_NAME_SHOWING$1);\n EventHandler.trigger(this._element, EVENT_SHOWN$3, {\n relatedTarget\n });\n };\n this._queueCallback(completeCallBack, this._element, true);\n }\n hide() {\n if (!this._isShown) {\n return;\n }\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE$3);\n if (hideEvent.defaultPrevented) {\n return;\n }\n this._focustrap.deactivate();\n this._element.blur();\n this._isShown = false;\n this._element.classList.add(CLASS_NAME_HIDING);\n this._backdrop.hide();\n const completeCallback = () => {\n this._element.classList.remove(CLASS_NAME_SHOW$3, CLASS_NAME_HIDING);\n this._element.removeAttribute('aria-modal');\n this._element.removeAttribute('role');\n if (!this._config.scroll) {\n new ScrollBarHelper().reset();\n }\n EventHandler.trigger(this._element, EVENT_HIDDEN$3);\n };\n this._queueCallback(completeCallback, this._element, true);\n }\n dispose() {\n this._backdrop.dispose();\n this._focustrap.deactivate();\n super.dispose();\n }\n\n // Private\n _initializeBackDrop() {\n const clickCallback = () => {\n if (this._config.backdrop === 'static') {\n EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED);\n return;\n }\n this.hide();\n };\n\n // 'static' option will be translated to true, and booleans will keep their value\n const isVisible = Boolean(this._config.backdrop);\n return new Backdrop({\n className: CLASS_NAME_BACKDROP,\n isVisible,\n isAnimated: true,\n rootElement: this._element.parentNode,\n clickCallback: isVisible ? clickCallback : null\n });\n }\n _initializeFocusTrap() {\n return new FocusTrap({\n trapElement: this._element\n });\n }\n _addEventListeners() {\n EventHandler.on(this._element, EVENT_KEYDOWN_DISMISS, event => {\n if (event.key !== ESCAPE_KEY) {\n return;\n }\n if (this._config.keyboard) {\n this.hide();\n return;\n }\n EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED);\n });\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Offcanvas.getOrCreateInstance(this, config);\n if (typeof config !== 'string') {\n return;\n }\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`);\n }\n data[config](this);\n });\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API$1, SELECTOR_DATA_TOGGLE$1, function (event) {\n const target = SelectorEngine.getElementFromSelector(this);\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault();\n }\n if (isDisabled(this)) {\n return;\n }\n EventHandler.one(target, EVENT_HIDDEN$3, () => {\n // focus on trigger when it is closed\n if (isVisible(this)) {\n this.focus();\n }\n });\n\n // avoid conflict when clicking a toggler of an offcanvas, while another is open\n const alreadyOpen = SelectorEngine.findOne(OPEN_SELECTOR);\n if (alreadyOpen && alreadyOpen !== target) {\n Offcanvas.getInstance(alreadyOpen).hide();\n }\n const data = Offcanvas.getOrCreateInstance(target);\n data.toggle(this);\n});\nEventHandler.on(window, EVENT_LOAD_DATA_API$2, () => {\n for (const selector of SelectorEngine.find(OPEN_SELECTOR)) {\n Offcanvas.getOrCreateInstance(selector).show();\n }\n});\nEventHandler.on(window, EVENT_RESIZE, () => {\n for (const element of SelectorEngine.find('[aria-modal][class*=show][class*=offcanvas-]')) {\n if (getComputedStyle(element).position !== 'fixed') {\n Offcanvas.getOrCreateInstance(element).hide();\n }\n }\n});\nenableDismissTrigger(Offcanvas);\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Offcanvas);\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap util/sanitizer.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n// js-docs-start allow-list\nconst ARIA_ATTRIBUTE_PATTERN = /^aria-[\\w-]*$/i;\nconst DefaultAllowlist = {\n // Global attributes allowed on any supplied element below.\n '*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN],\n a: ['target', 'href', 'title', 'rel'],\n area: [],\n b: [],\n br: [],\n col: [],\n code: [],\n dd: [],\n div: [],\n dl: [],\n dt: [],\n em: [],\n hr: [],\n h1: [],\n h2: [],\n h3: [],\n h4: [],\n h5: [],\n h6: [],\n i: [],\n img: ['src', 'srcset', 'alt', 'title', 'width', 'height'],\n li: [],\n ol: [],\n p: [],\n pre: [],\n s: [],\n small: [],\n span: [],\n sub: [],\n sup: [],\n strong: [],\n u: [],\n ul: []\n};\n// js-docs-end allow-list\n\nconst uriAttributes = new Set(['background', 'cite', 'href', 'itemtype', 'longdesc', 'poster', 'src', 'xlink:href']);\n\n/**\n * A pattern that recognizes URLs that are safe wrt. XSS in URL navigation\n * contexts.\n *\n * Shout-out to Angular https://github.com/angular/angular/blob/15.2.8/packages/core/src/sanitization/url_sanitizer.ts#L38\n */\n// eslint-disable-next-line unicorn/better-regex\nconst SAFE_URL_PATTERN = /^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:/?#]*(?:[/?#]|$))/i;\nconst allowedAttribute = (attribute, allowedAttributeList) => {\n const attributeName = attribute.nodeName.toLowerCase();\n if (allowedAttributeList.includes(attributeName)) {\n if (uriAttributes.has(attributeName)) {\n return Boolean(SAFE_URL_PATTERN.test(attribute.nodeValue));\n }\n return true;\n }\n\n // Check if a regular expression validates the attribute.\n return allowedAttributeList.filter(attributeRegex => attributeRegex instanceof RegExp).some(regex => regex.test(attributeName));\n};\nfunction sanitizeHtml(unsafeHtml, allowList, sanitizeFunction) {\n if (!unsafeHtml.length) {\n return unsafeHtml;\n }\n if (sanitizeFunction && typeof sanitizeFunction === 'function') {\n return sanitizeFunction(unsafeHtml);\n }\n const domParser = new window.DOMParser();\n const createdDocument = domParser.parseFromString(unsafeHtml, 'text/html');\n const elements = [].concat(...createdDocument.body.querySelectorAll('*'));\n for (const element of elements) {\n const elementName = element.nodeName.toLowerCase();\n if (!Object.keys(allowList).includes(elementName)) {\n element.remove();\n continue;\n }\n const attributeList = [].concat(...element.attributes);\n const allowedAttributes = [].concat(allowList['*'] || [], allowList[elementName] || []);\n for (const attribute of attributeList) {\n if (!allowedAttribute(attribute, allowedAttributes)) {\n element.removeAttribute(attribute.nodeName);\n }\n }\n }\n return createdDocument.body.innerHTML;\n}\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap util/template-factory.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n\n/**\n * Constants\n */\n\nconst NAME$5 = 'TemplateFactory';\nconst Default$4 = {\n allowList: DefaultAllowlist,\n content: {},\n // { selector : text , selector2 : text2 , }\n extraClass: '',\n html: false,\n sanitize: true,\n sanitizeFn: null,\n template: '
'\n};\nconst DefaultType$4 = {\n allowList: 'object',\n content: 'object',\n extraClass: '(string|function)',\n html: 'boolean',\n sanitize: 'boolean',\n sanitizeFn: '(null|function)',\n template: 'string'\n};\nconst DefaultContentType = {\n entry: '(string|element|function|null)',\n selector: '(string|element)'\n};\n\n/**\n * Class definition\n */\n\nclass TemplateFactory extends bootstrap_esm_Config {\n constructor(config) {\n super();\n this._config = this._getConfig(config);\n }\n\n // Getters\n static get Default() {\n return Default$4;\n }\n static get DefaultType() {\n return DefaultType$4;\n }\n static get NAME() {\n return NAME$5;\n }\n\n // Public\n getContent() {\n return Object.values(this._config.content).map(config => this._resolvePossibleFunction(config)).filter(Boolean);\n }\n hasContent() {\n return this.getContent().length > 0;\n }\n changeContent(content) {\n this._checkContent(content);\n this._config.content = {\n ...this._config.content,\n ...content\n };\n return this;\n }\n toHtml() {\n const templateWrapper = document.createElement('div');\n templateWrapper.innerHTML = this._maybeSanitize(this._config.template);\n for (const [selector, text] of Object.entries(this._config.content)) {\n this._setContent(templateWrapper, text, selector);\n }\n const template = templateWrapper.children[0];\n const extraClass = this._resolvePossibleFunction(this._config.extraClass);\n if (extraClass) {\n template.classList.add(...extraClass.split(' '));\n }\n return template;\n }\n\n // Private\n _typeCheckConfig(config) {\n super._typeCheckConfig(config);\n this._checkContent(config.content);\n }\n _checkContent(arg) {\n for (const [selector, content] of Object.entries(arg)) {\n super._typeCheckConfig({\n selector,\n entry: content\n }, DefaultContentType);\n }\n }\n _setContent(template, content, selector) {\n const templateElement = SelectorEngine.findOne(selector, template);\n if (!templateElement) {\n return;\n }\n content = this._resolvePossibleFunction(content);\n if (!content) {\n templateElement.remove();\n return;\n }\n if (bootstrap_esm_isElement(content)) {\n this._putElementInTemplate(getElement(content), templateElement);\n return;\n }\n if (this._config.html) {\n templateElement.innerHTML = this._maybeSanitize(content);\n return;\n }\n templateElement.textContent = content;\n }\n _maybeSanitize(arg) {\n return this._config.sanitize ? sanitizeHtml(arg, this._config.allowList, this._config.sanitizeFn) : arg;\n }\n _resolvePossibleFunction(arg) {\n return execute(arg, [this]);\n }\n _putElementInTemplate(element, templateElement) {\n if (this._config.html) {\n templateElement.innerHTML = '';\n templateElement.append(element);\n return;\n }\n templateElement.textContent = element.textContent;\n }\n}\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap tooltip.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n\n/**\n * Constants\n */\n\nconst NAME$4 = 'tooltip';\nconst DISALLOWED_ATTRIBUTES = new Set(['sanitize', 'allowList', 'sanitizeFn']);\nconst CLASS_NAME_FADE$2 = 'fade';\nconst CLASS_NAME_MODAL = 'modal';\nconst CLASS_NAME_SHOW$2 = 'show';\nconst SELECTOR_TOOLTIP_INNER = '.tooltip-inner';\nconst SELECTOR_MODAL = `.${CLASS_NAME_MODAL}`;\nconst EVENT_MODAL_HIDE = 'hide.bs.modal';\nconst TRIGGER_HOVER = 'hover';\nconst TRIGGER_FOCUS = 'focus';\nconst TRIGGER_CLICK = 'click';\nconst TRIGGER_MANUAL = 'manual';\nconst EVENT_HIDE$2 = 'hide';\nconst EVENT_HIDDEN$2 = 'hidden';\nconst EVENT_SHOW$2 = 'show';\nconst EVENT_SHOWN$2 = 'shown';\nconst EVENT_INSERTED = 'inserted';\nconst EVENT_CLICK$1 = 'click';\nconst EVENT_FOCUSIN$1 = 'focusin';\nconst EVENT_FOCUSOUT$1 = 'focusout';\nconst EVENT_MOUSEENTER = 'mouseenter';\nconst EVENT_MOUSELEAVE = 'mouseleave';\nconst AttachmentMap = {\n AUTO: 'auto',\n TOP: 'top',\n RIGHT: isRTL() ? 'left' : 'right',\n BOTTOM: 'bottom',\n LEFT: isRTL() ? 'right' : 'left'\n};\nconst Default$3 = {\n allowList: DefaultAllowlist,\n animation: true,\n boundary: 'clippingParents',\n container: false,\n customClass: '',\n delay: 0,\n fallbackPlacements: ['top', 'right', 'bottom', 'left'],\n html: false,\n offset: [0, 6],\n placement: 'top',\n popperConfig: null,\n sanitize: true,\n sanitizeFn: null,\n selector: false,\n template: '
' + '
' + '
' + '
',\n title: '',\n trigger: 'hover focus'\n};\nconst DefaultType$3 = {\n allowList: 'object',\n animation: 'boolean',\n boundary: '(string|element)',\n container: '(string|element|boolean)',\n customClass: '(string|function)',\n delay: '(number|object)',\n fallbackPlacements: 'array',\n html: 'boolean',\n offset: '(array|string|function)',\n placement: '(string|function)',\n popperConfig: '(null|object|function)',\n sanitize: 'boolean',\n sanitizeFn: '(null|function)',\n selector: '(string|boolean)',\n template: 'string',\n title: '(string|element|function)',\n trigger: 'string'\n};\n\n/**\n * Class definition\n */\n\nclass bootstrap_esm_Tooltip extends BaseComponent {\n constructor(element, config) {\n if (typeof lib_namespaceObject === 'undefined') {\n throw new TypeError('Bootstrap\\'s tooltips require Popper (https://popper.js.org)');\n }\n super(element, config);\n\n // Private\n this._isEnabled = true;\n this._timeout = 0;\n this._isHovered = null;\n this._activeTrigger = {};\n this._popper = null;\n this._templateFactory = null;\n this._newContent = null;\n\n // Protected\n this.tip = null;\n this._setListeners();\n if (!this._config.selector) {\n this._fixTitle();\n }\n }\n\n // Getters\n static get Default() {\n return Default$3;\n }\n static get DefaultType() {\n return DefaultType$3;\n }\n static get NAME() {\n return NAME$4;\n }\n\n // Public\n enable() {\n this._isEnabled = true;\n }\n disable() {\n this._isEnabled = false;\n }\n toggleEnabled() {\n this._isEnabled = !this._isEnabled;\n }\n toggle() {\n if (!this._isEnabled) {\n return;\n }\n this._activeTrigger.click = !this._activeTrigger.click;\n if (this._isShown()) {\n this._leave();\n return;\n }\n this._enter();\n }\n dispose() {\n clearTimeout(this._timeout);\n EventHandler.off(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler);\n if (this._element.getAttribute('data-bs-original-title')) {\n this._element.setAttribute('title', this._element.getAttribute('data-bs-original-title'));\n }\n this._disposePopper();\n super.dispose();\n }\n show() {\n if (this._element.style.display === 'none') {\n throw new Error('Please use show on visible elements');\n }\n if (!(this._isWithContent() && this._isEnabled)) {\n return;\n }\n const showEvent = EventHandler.trigger(this._element, this.constructor.eventName(EVENT_SHOW$2));\n const shadowRoot = findShadowRoot(this._element);\n const isInTheDom = (shadowRoot || this._element.ownerDocument.documentElement).contains(this._element);\n if (showEvent.defaultPrevented || !isInTheDom) {\n return;\n }\n\n // TODO: v6 remove this or make it optional\n this._disposePopper();\n const tip = this._getTipElement();\n this._element.setAttribute('aria-describedby', tip.getAttribute('id'));\n const {\n container\n } = this._config;\n if (!this._element.ownerDocument.documentElement.contains(this.tip)) {\n container.append(tip);\n EventHandler.trigger(this._element, this.constructor.eventName(EVENT_INSERTED));\n }\n this._popper = this._createPopper(tip);\n tip.classList.add(CLASS_NAME_SHOW$2);\n\n // If this is a touch-enabled device we add extra\n // empty mouseover listeners to the body's immediate children;\n // only needed because of broken event delegation on iOS\n // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html\n if ('ontouchstart' in document.documentElement) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.on(element, 'mouseover', bootstrap_esm_noop);\n }\n }\n const complete = () => {\n EventHandler.trigger(this._element, this.constructor.eventName(EVENT_SHOWN$2));\n if (this._isHovered === false) {\n this._leave();\n }\n this._isHovered = false;\n };\n this._queueCallback(complete, this.tip, this._isAnimated());\n }\n hide() {\n if (!this._isShown()) {\n return;\n }\n const hideEvent = EventHandler.trigger(this._element, this.constructor.eventName(EVENT_HIDE$2));\n if (hideEvent.defaultPrevented) {\n return;\n }\n const tip = this._getTipElement();\n tip.classList.remove(CLASS_NAME_SHOW$2);\n\n // If this is a touch-enabled device we remove the extra\n // empty mouseover listeners we added for iOS support\n if ('ontouchstart' in document.documentElement) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.off(element, 'mouseover', bootstrap_esm_noop);\n }\n }\n this._activeTrigger[TRIGGER_CLICK] = false;\n this._activeTrigger[TRIGGER_FOCUS] = false;\n this._activeTrigger[TRIGGER_HOVER] = false;\n this._isHovered = null; // it is a trick to support manual triggering\n\n const complete = () => {\n if (this._isWithActiveTrigger()) {\n return;\n }\n if (!this._isHovered) {\n this._disposePopper();\n }\n this._element.removeAttribute('aria-describedby');\n EventHandler.trigger(this._element, this.constructor.eventName(EVENT_HIDDEN$2));\n };\n this._queueCallback(complete, this.tip, this._isAnimated());\n }\n update() {\n if (this._popper) {\n this._popper.update();\n }\n }\n\n // Protected\n _isWithContent() {\n return Boolean(this._getTitle());\n }\n _getTipElement() {\n if (!this.tip) {\n this.tip = this._createTipElement(this._newContent || this._getContentForTemplate());\n }\n return this.tip;\n }\n _createTipElement(content) {\n const tip = this._getTemplateFactory(content).toHtml();\n\n // TODO: remove this check in v6\n if (!tip) {\n return null;\n }\n tip.classList.remove(CLASS_NAME_FADE$2, CLASS_NAME_SHOW$2);\n // TODO: v6 the following can be achieved with CSS only\n tip.classList.add(`bs-${this.constructor.NAME}-auto`);\n const tipId = getUID(this.constructor.NAME).toString();\n tip.setAttribute('id', tipId);\n if (this._isAnimated()) {\n tip.classList.add(CLASS_NAME_FADE$2);\n }\n return tip;\n }\n setContent(content) {\n this._newContent = content;\n if (this._isShown()) {\n this._disposePopper();\n this.show();\n }\n }\n _getTemplateFactory(content) {\n if (this._templateFactory) {\n this._templateFactory.changeContent(content);\n } else {\n this._templateFactory = new TemplateFactory({\n ...this._config,\n // the `content` var has to be after `this._config`\n // to override config.content in case of popover\n content,\n extraClass: this._resolvePossibleFunction(this._config.customClass)\n });\n }\n return this._templateFactory;\n }\n _getContentForTemplate() {\n return {\n [SELECTOR_TOOLTIP_INNER]: this._getTitle()\n };\n }\n _getTitle() {\n return this._resolvePossibleFunction(this._config.title) || this._element.getAttribute('data-bs-original-title');\n }\n\n // Private\n _initializeOnDelegatedTarget(event) {\n return this.constructor.getOrCreateInstance(event.delegateTarget, this._getDelegateConfig());\n }\n _isAnimated() {\n return this._config.animation || this.tip && this.tip.classList.contains(CLASS_NAME_FADE$2);\n }\n _isShown() {\n return this.tip && this.tip.classList.contains(CLASS_NAME_SHOW$2);\n }\n _createPopper(tip) {\n const placement = execute(this._config.placement, [this, tip, this._element]);\n const attachment = AttachmentMap[placement.toUpperCase()];\n return popper_createPopper(this._element, tip, this._getPopperConfig(attachment));\n }\n _getOffset() {\n const {\n offset\n } = this._config;\n if (typeof offset === 'string') {\n return offset.split(',').map(value => Number.parseInt(value, 10));\n }\n if (typeof offset === 'function') {\n return popperData => offset(popperData, this._element);\n }\n return offset;\n }\n _resolvePossibleFunction(arg) {\n return execute(arg, [this._element]);\n }\n _getPopperConfig(attachment) {\n const defaultBsPopperConfig = {\n placement: attachment,\n modifiers: [{\n name: 'flip',\n options: {\n fallbackPlacements: this._config.fallbackPlacements\n }\n }, {\n name: 'offset',\n options: {\n offset: this._getOffset()\n }\n }, {\n name: 'preventOverflow',\n options: {\n boundary: this._config.boundary\n }\n }, {\n name: 'arrow',\n options: {\n element: `.${this.constructor.NAME}-arrow`\n }\n }, {\n name: 'preSetPlacement',\n enabled: true,\n phase: 'beforeMain',\n fn: data => {\n // Pre-set Popper's placement attribute in order to read the arrow sizes properly.\n // Otherwise, Popper mixes up the width and height dimensions since the initial arrow style is for top placement\n this._getTipElement().setAttribute('data-popper-placement', data.state.placement);\n }\n }]\n };\n return {\n ...defaultBsPopperConfig,\n ...execute(this._config.popperConfig, [defaultBsPopperConfig])\n };\n }\n _setListeners() {\n const triggers = this._config.trigger.split(' ');\n for (const trigger of triggers) {\n if (trigger === 'click') {\n EventHandler.on(this._element, this.constructor.eventName(EVENT_CLICK$1), this._config.selector, event => {\n const context = this._initializeOnDelegatedTarget(event);\n context.toggle();\n });\n } else if (trigger !== TRIGGER_MANUAL) {\n const eventIn = trigger === TRIGGER_HOVER ? this.constructor.eventName(EVENT_MOUSEENTER) : this.constructor.eventName(EVENT_FOCUSIN$1);\n const eventOut = trigger === TRIGGER_HOVER ? this.constructor.eventName(EVENT_MOUSELEAVE) : this.constructor.eventName(EVENT_FOCUSOUT$1);\n EventHandler.on(this._element, eventIn, this._config.selector, event => {\n const context = this._initializeOnDelegatedTarget(event);\n context._activeTrigger[event.type === 'focusin' ? TRIGGER_FOCUS : TRIGGER_HOVER] = true;\n context._enter();\n });\n EventHandler.on(this._element, eventOut, this._config.selector, event => {\n const context = this._initializeOnDelegatedTarget(event);\n context._activeTrigger[event.type === 'focusout' ? TRIGGER_FOCUS : TRIGGER_HOVER] = context._element.contains(event.relatedTarget);\n context._leave();\n });\n }\n }\n this._hideModalHandler = () => {\n if (this._element) {\n this.hide();\n }\n };\n EventHandler.on(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler);\n }\n _fixTitle() {\n const title = this._element.getAttribute('title');\n if (!title) {\n return;\n }\n if (!this._element.getAttribute('aria-label') && !this._element.textContent.trim()) {\n this._element.setAttribute('aria-label', title);\n }\n this._element.setAttribute('data-bs-original-title', title); // DO NOT USE IT. Is only for backwards compatibility\n this._element.removeAttribute('title');\n }\n _enter() {\n if (this._isShown() || this._isHovered) {\n this._isHovered = true;\n return;\n }\n this._isHovered = true;\n this._setTimeout(() => {\n if (this._isHovered) {\n this.show();\n }\n }, this._config.delay.show);\n }\n _leave() {\n if (this._isWithActiveTrigger()) {\n return;\n }\n this._isHovered = false;\n this._setTimeout(() => {\n if (!this._isHovered) {\n this.hide();\n }\n }, this._config.delay.hide);\n }\n _setTimeout(handler, timeout) {\n clearTimeout(this._timeout);\n this._timeout = setTimeout(handler, timeout);\n }\n _isWithActiveTrigger() {\n return Object.values(this._activeTrigger).includes(true);\n }\n _getConfig(config) {\n const dataAttributes = Manipulator.getDataAttributes(this._element);\n for (const dataAttribute of Object.keys(dataAttributes)) {\n if (DISALLOWED_ATTRIBUTES.has(dataAttribute)) {\n delete dataAttributes[dataAttribute];\n }\n }\n config = {\n ...dataAttributes,\n ...(typeof config === 'object' && config ? config : {})\n };\n config = this._mergeConfigObj(config);\n config = this._configAfterMerge(config);\n this._typeCheckConfig(config);\n return config;\n }\n _configAfterMerge(config) {\n config.container = config.container === false ? document.body : getElement(config.container);\n if (typeof config.delay === 'number') {\n config.delay = {\n show: config.delay,\n hide: config.delay\n };\n }\n if (typeof config.title === 'number') {\n config.title = config.title.toString();\n }\n if (typeof config.content === 'number') {\n config.content = config.content.toString();\n }\n return config;\n }\n _getDelegateConfig() {\n const config = {};\n for (const [key, value] of Object.entries(this._config)) {\n if (this.constructor.Default[key] !== value) {\n config[key] = value;\n }\n }\n config.selector = false;\n config.trigger = 'manual';\n\n // In the future can be replaced with:\n // const keysWithDifferentValues = Object.entries(this._config).filter(entry => this.constructor.Default[entry[0]] !== this._config[entry[0]])\n // `Object.fromEntries(keysWithDifferentValues)`\n return config;\n }\n _disposePopper() {\n if (this._popper) {\n this._popper.destroy();\n this._popper = null;\n }\n if (this.tip) {\n this.tip.remove();\n this.tip = null;\n }\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = bootstrap_esm_Tooltip.getOrCreateInstance(this, config);\n if (typeof config !== 'string') {\n return;\n }\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`);\n }\n data[config]();\n });\n }\n}\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(bootstrap_esm_Tooltip);\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap popover.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n\n/**\n * Constants\n */\n\nconst NAME$3 = 'popover';\nconst SELECTOR_TITLE = '.popover-header';\nconst SELECTOR_CONTENT = '.popover-body';\nconst Default$2 = {\n ...bootstrap_esm_Tooltip.Default,\n content: '',\n offset: [0, 8],\n placement: 'right',\n template: '
' + '
' + '

' + '
' + '
',\n trigger: 'click'\n};\nconst DefaultType$2 = {\n ...bootstrap_esm_Tooltip.DefaultType,\n content: '(null|string|element|function)'\n};\n\n/**\n * Class definition\n */\n\nclass Popover extends bootstrap_esm_Tooltip {\n // Getters\n static get Default() {\n return Default$2;\n }\n static get DefaultType() {\n return DefaultType$2;\n }\n static get NAME() {\n return NAME$3;\n }\n\n // Overrides\n _isWithContent() {\n return this._getTitle() || this._getContent();\n }\n\n // Private\n _getContentForTemplate() {\n return {\n [SELECTOR_TITLE]: this._getTitle(),\n [SELECTOR_CONTENT]: this._getContent()\n };\n }\n _getContent() {\n return this._resolvePossibleFunction(this._config.content);\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Popover.getOrCreateInstance(this, config);\n if (typeof config !== 'string') {\n return;\n }\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`);\n }\n data[config]();\n });\n }\n}\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Popover);\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap scrollspy.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n\n/**\n * Constants\n */\n\nconst NAME$2 = 'scrollspy';\nconst DATA_KEY$2 = 'bs.scrollspy';\nconst EVENT_KEY$2 = `.${DATA_KEY$2}`;\nconst DATA_API_KEY = '.data-api';\nconst EVENT_ACTIVATE = `activate${EVENT_KEY$2}`;\nconst EVENT_CLICK = `click${EVENT_KEY$2}`;\nconst EVENT_LOAD_DATA_API$1 = `load${EVENT_KEY$2}${DATA_API_KEY}`;\nconst CLASS_NAME_DROPDOWN_ITEM = 'dropdown-item';\nconst CLASS_NAME_ACTIVE$1 = 'active';\nconst SELECTOR_DATA_SPY = '[data-bs-spy=\"scroll\"]';\nconst SELECTOR_TARGET_LINKS = '[href]';\nconst SELECTOR_NAV_LIST_GROUP = '.nav, .list-group';\nconst SELECTOR_NAV_LINKS = '.nav-link';\nconst SELECTOR_NAV_ITEMS = '.nav-item';\nconst SELECTOR_LIST_ITEMS = '.list-group-item';\nconst SELECTOR_LINK_ITEMS = `${SELECTOR_NAV_LINKS}, ${SELECTOR_NAV_ITEMS} > ${SELECTOR_NAV_LINKS}, ${SELECTOR_LIST_ITEMS}`;\nconst SELECTOR_DROPDOWN = '.dropdown';\nconst SELECTOR_DROPDOWN_TOGGLE$1 = '.dropdown-toggle';\nconst Default$1 = {\n offset: null,\n // TODO: v6 @deprecated, keep it for backwards compatibility reasons\n rootMargin: '0px 0px -25%',\n smoothScroll: false,\n target: null,\n threshold: [0.1, 0.5, 1]\n};\nconst DefaultType$1 = {\n offset: '(number|null)',\n // TODO v6 @deprecated, keep it for backwards compatibility reasons\n rootMargin: 'string',\n smoothScroll: 'boolean',\n target: 'element',\n threshold: 'array'\n};\n\n/**\n * Class definition\n */\n\nclass ScrollSpy extends BaseComponent {\n constructor(element, config) {\n super(element, config);\n\n // this._element is the observablesContainer and config.target the menu links wrapper\n this._targetLinks = new Map();\n this._observableSections = new Map();\n this._rootElement = getComputedStyle(this._element).overflowY === 'visible' ? null : this._element;\n this._activeTarget = null;\n this._observer = null;\n this._previousScrollData = {\n visibleEntryTop: 0,\n parentScrollTop: 0\n };\n this.refresh(); // initialize\n }\n\n // Getters\n static get Default() {\n return Default$1;\n }\n static get DefaultType() {\n return DefaultType$1;\n }\n static get NAME() {\n return NAME$2;\n }\n\n // Public\n refresh() {\n this._initializeTargetsAndObservables();\n this._maybeEnableSmoothScroll();\n if (this._observer) {\n this._observer.disconnect();\n } else {\n this._observer = this._getNewObserver();\n }\n for (const section of this._observableSections.values()) {\n this._observer.observe(section);\n }\n }\n dispose() {\n this._observer.disconnect();\n super.dispose();\n }\n\n // Private\n _configAfterMerge(config) {\n // TODO: on v6 target should be given explicitly & remove the {target: 'ss-target'} case\n config.target = getElement(config.target) || document.body;\n\n // TODO: v6 Only for backwards compatibility reasons. Use rootMargin only\n config.rootMargin = config.offset ? `${config.offset}px 0px -30%` : config.rootMargin;\n if (typeof config.threshold === 'string') {\n config.threshold = config.threshold.split(',').map(value => Number.parseFloat(value));\n }\n return config;\n }\n _maybeEnableSmoothScroll() {\n if (!this._config.smoothScroll) {\n return;\n }\n\n // unregister any previous listeners\n EventHandler.off(this._config.target, EVENT_CLICK);\n EventHandler.on(this._config.target, EVENT_CLICK, SELECTOR_TARGET_LINKS, event => {\n const observableSection = this._observableSections.get(event.target.hash);\n if (observableSection) {\n event.preventDefault();\n const root = this._rootElement || window;\n const height = observableSection.offsetTop - this._element.offsetTop;\n if (root.scrollTo) {\n root.scrollTo({\n top: height,\n behavior: 'smooth'\n });\n return;\n }\n\n // Chrome 60 doesn't support `scrollTo`\n root.scrollTop = height;\n }\n });\n }\n _getNewObserver() {\n const options = {\n root: this._rootElement,\n threshold: this._config.threshold,\n rootMargin: this._config.rootMargin\n };\n return new IntersectionObserver(entries => this._observerCallback(entries), options);\n }\n\n // The logic of selection\n _observerCallback(entries) {\n const targetElement = entry => this._targetLinks.get(`#${entry.target.id}`);\n const activate = entry => {\n this._previousScrollData.visibleEntryTop = entry.target.offsetTop;\n this._process(targetElement(entry));\n };\n const parentScrollTop = (this._rootElement || document.documentElement).scrollTop;\n const userScrollsDown = parentScrollTop >= this._previousScrollData.parentScrollTop;\n this._previousScrollData.parentScrollTop = parentScrollTop;\n for (const entry of entries) {\n if (!entry.isIntersecting) {\n this._activeTarget = null;\n this._clearActiveClass(targetElement(entry));\n continue;\n }\n const entryIsLowerThanPrevious = entry.target.offsetTop >= this._previousScrollData.visibleEntryTop;\n // if we are scrolling down, pick the bigger offsetTop\n if (userScrollsDown && entryIsLowerThanPrevious) {\n activate(entry);\n // if parent isn't scrolled, let's keep the first visible item, breaking the iteration\n if (!parentScrollTop) {\n return;\n }\n continue;\n }\n\n // if we are scrolling up, pick the smallest offsetTop\n if (!userScrollsDown && !entryIsLowerThanPrevious) {\n activate(entry);\n }\n }\n }\n _initializeTargetsAndObservables() {\n this._targetLinks = new Map();\n this._observableSections = new Map();\n const targetLinks = SelectorEngine.find(SELECTOR_TARGET_LINKS, this._config.target);\n for (const anchor of targetLinks) {\n // ensure that the anchor has an id and is not disabled\n if (!anchor.hash || isDisabled(anchor)) {\n continue;\n }\n const observableSection = SelectorEngine.findOne(decodeURI(anchor.hash), this._element);\n\n // ensure that the observableSection exists & is visible\n if (isVisible(observableSection)) {\n this._targetLinks.set(decodeURI(anchor.hash), anchor);\n this._observableSections.set(anchor.hash, observableSection);\n }\n }\n }\n _process(target) {\n if (this._activeTarget === target) {\n return;\n }\n this._clearActiveClass(this._config.target);\n this._activeTarget = target;\n target.classList.add(CLASS_NAME_ACTIVE$1);\n this._activateParents(target);\n EventHandler.trigger(this._element, EVENT_ACTIVATE, {\n relatedTarget: target\n });\n }\n _activateParents(target) {\n // Activate dropdown parents\n if (target.classList.contains(CLASS_NAME_DROPDOWN_ITEM)) {\n SelectorEngine.findOne(SELECTOR_DROPDOWN_TOGGLE$1, target.closest(SELECTOR_DROPDOWN)).classList.add(CLASS_NAME_ACTIVE$1);\n return;\n }\n for (const listGroup of SelectorEngine.parents(target, SELECTOR_NAV_LIST_GROUP)) {\n // Set triggered links parents as active\n // With both
    and