@syndew/oluso-plugin-saml 0.0.0-stage → 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"syndew-oluso-plugin-saml.mjs","sources":["../../../../../libs/plugins/saml/src/lib/models/saml.model.ts","../../../../../libs/plugins/saml/src/lib/services/saml.service.ts","../../../../../libs/plugins/saml/src/lib/pages/saml-dashboard/saml-dashboard.component.ts","../../../../../libs/plugins/saml/src/lib/pages/service-providers/service-providers-page.component.ts","../../../../../libs/plugins/saml/src/lib/pages/service-provider-details/service-provider-details-page.component.ts","../../../../../libs/plugins/saml/src/lib/components/saml-idp-settings-tab/saml-idp-settings-tab.component.ts","../../../../../libs/plugins/saml/src/lib/saml.routes.ts","../../../../../libs/plugins/saml/src/lib/saml.plugin.ts","../../../../../libs/plugins/saml/src/index.ts","../../../../../libs/plugins/saml/src/syndew-oluso-plugin-saml.ts"],"sourcesContent":["/**\n * SAML Service Provider model\n */\nexport interface SamlServiceProvider {\n id: number;\n entityId: string;\n displayName?: string;\n description?: string;\n enabled: boolean;\n metadataUrl?: string;\n assertionConsumerServiceUrl?: string;\n singleLogoutServiceUrl?: string;\n hasSigningCertificate: boolean;\n hasEncryptionCertificate: boolean;\n encryptAssertions: boolean;\n nameIdFormat?: string;\n requireVerifiedEmail: boolean;\n allowedClaims?: string[];\n claimMappings?: Record<string, string>;\n ssoBinding: string;\n signResponses: boolean;\n signAssertions: boolean;\n requireSignedAuthnRequests: boolean;\n defaultRelayState?: string;\n nonEditable: boolean;\n created: string;\n updated?: string;\n lastAccessed?: string;\n}\n\n/**\n * SAML Service Provider for editing (includes certificates)\n */\nexport interface SamlServiceProviderEdit {\n id: number;\n entityId: string;\n displayName?: string;\n description?: string;\n enabled: boolean;\n metadataUrl?: string;\n assertionConsumerServiceUrl?: string;\n singleLogoutServiceUrl?: string;\n signingCertificate?: string;\n encryptionCertificate?: string;\n encryptAssertions: boolean;\n nameIdFormat?: string;\n requireVerifiedEmail: boolean;\n allowedClaims?: string[];\n claimMappings?: Record<string, string>;\n ssoBinding: string;\n signResponses: boolean;\n signAssertions: boolean;\n requireSignedAuthnRequests: boolean;\n defaultRelayState?: string;\n nonEditable: boolean;\n}\n\n/**\n * SAML Identity Provider info\n */\nexport interface SamlIdpInfo {\n enabled: boolean;\n entityId: string;\n singleSignOnServiceUrl: string;\n singleLogoutServiceUrl: string;\n metadataUrl: string;\n supportedNameIdFormats: string[];\n}\n\n/**\n * Request to create a SAML Service Provider\n */\nexport interface CreateSamlServiceProviderRequest {\n entityId: string;\n displayName?: string;\n description?: string;\n enabled?: boolean;\n metadataUrl?: string;\n assertionConsumerServiceUrl?: string;\n singleLogoutServiceUrl?: string;\n signingCertificate?: string;\n encryptionCertificate?: string;\n encryptAssertions?: boolean;\n nameIdFormat?: string;\n requireVerifiedEmail?: boolean;\n allowedClaims?: string[];\n claimMappings?: Record<string, string>;\n ssoBinding?: string;\n signResponses?: boolean;\n signAssertions?: boolean;\n requireSignedAuthnRequests?: boolean;\n defaultRelayState?: string;\n}\n\n/**\n * Test result for SAML configuration\n */\nexport interface SamlTestResult {\n success: boolean;\n message: string;\n}\n\n/**\n * SAML IdP Configuration\n */\nexport interface SamlIdpConfiguration {\n enabled: boolean;\n loginJourneyName?: string;\n}\n\n/**\n * SAML Certificate info\n */\nexport interface SamlCertificateInfo {\n source: 'Global' | 'Auto' | 'Uploaded';\n certificateId?: string;\n subject?: string;\n issuer?: string;\n notBefore?: string;\n notAfter?: string;\n thumbprint?: string;\n status: string;\n isRevoked: boolean;\n isExpired: boolean;\n isExpiringSoon: boolean;\n hasCertificate: boolean;\n}\n\n/**\n * Request to upload a certificate\n */\nexport interface UploadCertificateRequest {\n base64Pfx: string;\n password?: string;\n}\n\n/**\n * Entity ID availability check result\n */\nexport interface EntityIdAvailability {\n available: boolean;\n message?: string;\n}\n\n/**\n * Name ID format options\n */\nexport const NAME_ID_FORMATS = [\n { value: '', label: 'Default (emailAddress)' },\n { value: 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress', label: 'Email Address' },\n { value: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent', label: 'Persistent' },\n { value: 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient', label: 'Transient' },\n { value: 'urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified', label: 'Unspecified' },\n];\n\n/**\n * SSO Binding options\n */\nexport const SSO_BINDINGS = [\n { value: 'POST', label: 'HTTP-POST' },\n { value: 'Redirect', label: 'HTTP-Redirect' },\n];\n","import { Injectable, inject } from '@angular/core';\nimport { Observable } from 'rxjs';\nimport { ApiService } from '@syndew/oluso-admin-ui';\nimport {\n SamlServiceProvider,\n SamlServiceProviderEdit,\n SamlIdpInfo,\n CreateSamlServiceProviderRequest,\n SamlTestResult,\n SamlIdpConfiguration,\n SamlCertificateInfo,\n UploadCertificateRequest,\n EntityIdAvailability,\n} from '../models/saml.model';\n\n/**\n * SAML Service\n *\n * Provides HTTP methods for managing SAML Service Providers and IdP configuration.\n */\n@Injectable({ providedIn: 'root' })\nexport class SamlService {\n private readonly api = inject(ApiService);\n private readonly basePath = '/saml/service-providers';\n\n /**\n * Get IdP info\n */\n getIdpInfo(): Observable<SamlIdpInfo> {\n return this.api.get<SamlIdpInfo>(`${this.basePath}/idp-info`);\n }\n\n /**\n * Check if an entity ID is available\n */\n checkEntityIdAvailability(entityId: string, excludeId?: number): Observable<EntityIdAvailability> {\n const params: Record<string, string | number | boolean> = {};\n if (excludeId) {\n params['excludeId'] = excludeId;\n }\n return this.api.get<EntityIdAvailability>(\n `${this.basePath}/check-entity-id/${encodeURIComponent(entityId)}`,\n params\n );\n }\n\n /**\n * Get all service providers\n */\n getAll(includeDisabled = false): Observable<SamlServiceProvider[]> {\n return this.api.get<SamlServiceProvider[]>(this.basePath, { includeDisabled });\n }\n\n /**\n * Get a service provider by ID\n */\n getById(id: number): Observable<SamlServiceProvider> {\n return this.api.get<SamlServiceProvider>(`${this.basePath}/${id}`);\n }\n\n /**\n * Get a service provider for editing (includes certificates)\n */\n getForEdit(id: number): Observable<SamlServiceProviderEdit> {\n return this.api.get<SamlServiceProviderEdit>(`${this.basePath}/${id}/edit`);\n }\n\n /**\n * Create a new service provider\n */\n create(data: CreateSamlServiceProviderRequest): Observable<SamlServiceProvider> {\n return this.api.post<SamlServiceProvider>(this.basePath, data);\n }\n\n /**\n * Update a service provider\n */\n update(id: number, data: SamlServiceProviderEdit): Observable<SamlServiceProvider> {\n return this.api.put<SamlServiceProvider>(`${this.basePath}/${id}`, data);\n }\n\n /**\n * Delete a service provider\n */\n delete(id: number): Observable<void> {\n return this.api.delete<void>(`${this.basePath}/${id}`);\n }\n\n /**\n * Toggle a service provider's enabled status\n */\n toggle(id: number): Observable<SamlServiceProvider> {\n return this.api.post<SamlServiceProvider>(`${this.basePath}/${id}/toggle`, {});\n }\n\n /**\n * Test a service provider configuration\n */\n test(id: number): Observable<SamlTestResult> {\n return this.api.post<SamlTestResult>(`${this.basePath}/${id}/test`, {});\n }\n\n // SAML IdP Configuration\n\n /**\n * Get IdP configuration\n */\n getIdpConfiguration(): Observable<SamlIdpConfiguration> {\n return this.api.get<SamlIdpConfiguration>(`${this.basePath}/idp-configuration`);\n }\n\n /**\n * Update IdP configuration\n */\n updateIdpConfiguration(data: SamlIdpConfiguration): Observable<SamlIdpConfiguration> {\n return this.api.put<SamlIdpConfiguration>(`${this.basePath}/idp-configuration`, data);\n }\n\n // IdP Certificate Management\n\n /**\n * Get signing certificate info\n */\n getSigningCertificate(): Observable<SamlCertificateInfo> {\n return this.api.get<SamlCertificateInfo>(`${this.basePath}/idp-certificate/signing`);\n }\n\n /**\n * Get encryption certificate info\n */\n getEncryptionCertificate(): Observable<SamlCertificateInfo> {\n return this.api.get<SamlCertificateInfo>(`${this.basePath}/idp-certificate/encryption`);\n }\n\n /**\n * Generate a new signing certificate\n */\n generateSigningCertificate(): Observable<SamlCertificateInfo> {\n return this.api.post<SamlCertificateInfo>(`${this.basePath}/idp-certificate/signing/generate`, {});\n }\n\n /**\n * Generate a new encryption certificate\n */\n generateEncryptionCertificate(): Observable<SamlCertificateInfo> {\n return this.api.post<SamlCertificateInfo>(`${this.basePath}/idp-certificate/encryption/generate`, {});\n }\n\n /**\n * Upload a signing certificate\n */\n uploadSigningCertificate(data: UploadCertificateRequest): Observable<SamlCertificateInfo> {\n return this.api.post<SamlCertificateInfo>(`${this.basePath}/idp-certificate/signing/upload`, data);\n }\n\n /**\n * Upload an encryption certificate\n */\n uploadEncryptionCertificate(data: UploadCertificateRequest): Observable<SamlCertificateInfo> {\n return this.api.post<SamlCertificateInfo>(`${this.basePath}/idp-certificate/encryption/upload`, data);\n }\n\n /**\n * Reset signing certificate to global\n */\n resetSigningCertificate(): Observable<void> {\n return this.api.post<void>(`${this.basePath}/idp-certificate/signing/reset`, {});\n }\n\n /**\n * Reset encryption certificate to global\n */\n resetEncryptionCertificate(): Observable<void> {\n return this.api.post<void>(`${this.basePath}/idp-certificate/encryption/reset`, {});\n }\n}\n","import { Component, OnInit, inject, signal } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { RouterLink } from '@angular/router';\nimport { ButtonComponent, IconComponent } from '@syndew/oluso-ui-core';\nimport { SamlService } from '../../services/saml.service';\nimport { SamlIdpInfo, SamlServiceProvider } from '../../models/saml.model';\nimport { forkJoin } from 'rxjs';\n\n@Component({\n selector: 'saml-dashboard',\n standalone: true,\n imports: [CommonModule, RouterLink, ButtonComponent, IconComponent],\n template: `\n <div class=\"space-y-6\">\n <div class=\"flex items-center justify-between\">\n <h1 class=\"text-2xl font-bold text-gray-900\">SAML Identity Provider</h1>\n <a routerLink=\"/saml/service-providers\">\n <ui-button>Manage Service Providers</ui-button>\n </a>\n </div>\n\n @if (loading()) {\n <div class=\"space-y-6\">\n <div class=\"h-8 w-48 bg-gray-200 rounded animate-pulse\"></div>\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-6\">\n @for (i of [1, 2]; track i) {\n <div class=\"h-48 bg-gray-200 rounded-lg animate-pulse\"></div>\n }\n </div>\n </div>\n } @else if (error()) {\n <div class=\"bg-red-50 border border-red-200 rounded-lg p-4\">\n <p class=\"text-red-700\">{{ error() }}</p>\n </div>\n } @else {\n <!-- IdP Status -->\n <div [class]=\"idpInfo()?.enabled ? 'bg-green-50 border border-green-200' : 'bg-yellow-50 border border-yellow-200'\" class=\"rounded-lg p-4\">\n <div class=\"flex items-center space-x-2\">\n @if (idpInfo()?.enabled) {\n <ui-icon name=\"check-circle\" class=\"h-5 w-5 text-green-600\" />\n <span class=\"text-green-700 font-medium\">SAML IdP is enabled</span>\n } @else {\n <ui-icon name=\"x-circle\" class=\"h-5 w-5 text-yellow-600\" />\n <span class=\"text-yellow-700 font-medium\">SAML IdP is disabled</span>\n }\n </div>\n </div>\n\n <!-- IdP Configuration Info -->\n @if (idpInfo()) {\n <div class=\"bg-white shadow rounded-lg\">\n <div class=\"px-6 py-4 border-b border-gray-200\">\n <h2 class=\"text-lg font-medium text-gray-900\">IdP Configuration</h2>\n <p class=\"mt-1 text-sm text-gray-500\">Share these URLs with Service Providers to configure SSO</p>\n </div>\n <div class=\"px-6 py-4 space-y-4\">\n <div class=\"flex items-center justify-between\">\n <div class=\"flex-1 min-w-0\">\n <span class=\"text-sm font-medium text-gray-500\">Entity ID (Issuer):</span>\n <div class=\"flex items-center space-x-2 mt-1\">\n <code class=\"text-sm text-gray-900 bg-gray-100 px-2 py-1 rounded truncate\">{{ idpInfo()?.entityId }}</code>\n </div>\n </div>\n <button (click)=\"copyToClipboard(idpInfo()?.entityId || '', 'entityId')\" class=\"ml-4 p-2 text-gray-400 hover:text-gray-600 hover:bg-gray-100 rounded\">\n @if (copied() === 'entityId') {\n <ui-icon name=\"check-circle\" class=\"h-5 w-5 text-green-500\" />\n } @else {\n <ui-icon name=\"clipboard-document\" class=\"h-5 w-5\" />\n }\n </button>\n </div>\n\n <div class=\"flex items-center justify-between\">\n <div class=\"flex-1 min-w-0\">\n <span class=\"text-sm font-medium text-gray-500\">SSO URL:</span>\n <div class=\"flex items-center space-x-2 mt-1\">\n <code class=\"text-sm text-gray-900 bg-gray-100 px-2 py-1 rounded truncate\">{{ idpInfo()?.singleSignOnServiceUrl }}</code>\n </div>\n </div>\n <button (click)=\"copyToClipboard(idpInfo()?.singleSignOnServiceUrl || '', 'ssoUrl')\" class=\"ml-4 p-2 text-gray-400 hover:text-gray-600 hover:bg-gray-100 rounded\">\n @if (copied() === 'ssoUrl') {\n <ui-icon name=\"check-circle\" class=\"h-5 w-5 text-green-500\" />\n } @else {\n <ui-icon name=\"clipboard-document\" class=\"h-5 w-5\" />\n }\n </button>\n </div>\n\n <div class=\"flex items-center justify-between\">\n <div class=\"flex-1 min-w-0\">\n <span class=\"text-sm font-medium text-gray-500\">Metadata URL:</span>\n <div class=\"flex items-center space-x-2 mt-1\">\n <a [href]=\"idpInfo()?.metadataUrl\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"text-sm text-primary-600 hover:text-primary-700 truncate\">\n {{ idpInfo()?.metadataUrl }}\n </a>\n </div>\n </div>\n <button (click)=\"copyToClipboard(idpInfo()?.metadataUrl || '', 'metadataUrl')\" class=\"ml-4 p-2 text-gray-400 hover:text-gray-600 hover:bg-gray-100 rounded\">\n @if (copied() === 'metadataUrl') {\n <ui-icon name=\"check-circle\" class=\"h-5 w-5 text-green-500\" />\n } @else {\n <ui-icon name=\"clipboard-document\" class=\"h-5 w-5\" />\n }\n </button>\n </div>\n\n <div class=\"pt-2\">\n <span class=\"text-sm font-medium text-gray-500\">Supported Name ID Formats:</span>\n <ul class=\"mt-1 text-sm text-gray-700 list-disc list-inside\">\n @for (format of idpInfo()?.supportedNameIdFormats || []; track format) {\n <li>{{ getFormatName(format) }}</li>\n }\n </ul>\n </div>\n </div>\n </div>\n }\n\n <!-- Service Provider Stats -->\n <div class=\"grid grid-cols-1 md:grid-cols-3 gap-6\">\n <a routerLink=\"/saml/service-providers\" class=\"bg-white shadow rounded-lg p-6 hover:shadow-md transition-shadow\">\n <div class=\"flex items-center\">\n <div class=\"flex-shrink-0\">\n <ui-icon name=\"building\" class=\"h-8 w-8 text-gray-400\" />\n </div>\n <div class=\"ml-4\">\n <p class=\"text-sm font-medium text-gray-500\">Total Service Providers</p>\n <p class=\"text-2xl font-semibold text-gray-900\">{{ serviceProviders().length }}</p>\n </div>\n </div>\n </a>\n\n <div class=\"bg-white shadow rounded-lg p-6\">\n <div class=\"flex items-center\">\n <div class=\"flex-shrink-0\">\n <ui-icon name=\"check-circle\" class=\"h-8 w-8 text-green-500\" />\n </div>\n <div class=\"ml-4\">\n <p class=\"text-sm font-medium text-gray-500\">Enabled</p>\n <p class=\"text-2xl font-semibold text-gray-900\">{{ enabledCount() }}</p>\n </div>\n </div>\n </div>\n\n <div class=\"bg-white shadow rounded-lg p-6\">\n <div class=\"flex items-center\">\n <div class=\"flex-shrink-0\">\n <ui-icon name=\"x-circle\" class=\"h-8 w-8 text-gray-400\" />\n </div>\n <div class=\"ml-4\">\n <p class=\"text-sm font-medium text-gray-500\">Disabled</p>\n <p class=\"text-2xl font-semibold text-gray-900\">{{ disabledCount() }}</p>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Recent Service Providers -->\n @if (serviceProviders().length > 0) {\n <div class=\"bg-white shadow rounded-lg\">\n <div class=\"px-6 py-4 border-b border-gray-200\">\n <h2 class=\"text-lg font-medium text-gray-900\">Service Providers</h2>\n </div>\n <ul class=\"divide-y divide-gray-200\">\n @for (sp of serviceProviders().slice(0, 5); track sp.id) {\n <li class=\"px-6 py-4 hover:bg-gray-50\">\n <a [routerLink]=\"['/saml/service-providers', sp.id]\" class=\"flex items-center justify-between\">\n <div class=\"flex items-center space-x-3\">\n <ui-icon name=\"building\" class=\"h-6 w-6 text-gray-400\" />\n <div>\n <p class=\"font-medium text-gray-900\">{{ sp.displayName || sp.entityId }}</p>\n <p class=\"text-sm text-gray-500 truncate max-w-md\">{{ sp.entityId }}</p>\n </div>\n </div>\n <span [class]=\"sp.enabled ? 'bg-green-100 text-green-800' : 'bg-gray-100 text-gray-800'\" class=\"inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium\">\n {{ sp.enabled ? 'Enabled' : 'Disabled' }}\n </span>\n </a>\n </li>\n }\n </ul>\n @if (serviceProviders().length > 5) {\n <div class=\"px-6 py-3 border-t border-gray-200 bg-gray-50\">\n <a routerLink=\"/saml/service-providers\" class=\"text-sm text-primary-600 hover:text-primary-700\">\n View all {{ serviceProviders().length }} service providers\n </a>\n </div>\n }\n </div>\n } @else {\n <div class=\"text-center py-12 bg-white rounded-lg shadow\">\n <ui-icon name=\"building\" class=\"mx-auto h-12 w-12 text-gray-400\" />\n <h3 class=\"mt-2 text-sm font-medium text-gray-900\">No Service Providers</h3>\n <p class=\"mt-1 text-sm text-gray-500\">Get started by adding a SAML Service Provider.</p>\n <div class=\"mt-6\">\n <a routerLink=\"/saml/service-providers/new\">\n <ui-button>Add Service Provider</ui-button>\n </a>\n </div>\n </div>\n }\n }\n </div>\n `,\n})\nexport class SamlDashboardComponent implements OnInit {\n private readonly samlService = inject(SamlService);\n\n readonly loading = signal(true);\n readonly error = signal<string | null>(null);\n readonly idpInfo = signal<SamlIdpInfo | null>(null);\n readonly serviceProviders = signal<SamlServiceProvider[]>([]);\n readonly copied = signal<string | null>(null);\n\n readonly enabledCount = () => this.serviceProviders().filter((sp) => sp.enabled).length;\n readonly disabledCount = () => this.serviceProviders().length - this.enabledCount();\n\n ngOnInit(): void {\n this.loadData();\n }\n\n loadData(): void {\n this.loading.set(true);\n forkJoin({\n idpInfo: this.samlService.getIdpInfo(),\n serviceProviders: this.samlService.getAll(),\n }).subscribe({\n next: (data) => {\n this.idpInfo.set(data.idpInfo);\n this.serviceProviders.set(data.serviceProviders);\n this.error.set(null);\n this.loading.set(false);\n },\n error: (err) => {\n console.error('Error loading SAML data:', err);\n this.error.set('Failed to load SAML configuration');\n this.loading.set(false);\n },\n });\n }\n\n copyToClipboard(value: string, label: string): void {\n navigator.clipboard.writeText(value).then(() => {\n this.copied.set(label);\n setTimeout(() => this.copied.set(null), 2000);\n });\n }\n\n getFormatName(format: string): string {\n return format.split(':').pop() || format;\n }\n}\n","import { Component, OnInit, inject, signal } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { FormsModule } from '@angular/forms';\nimport { RouterLink } from '@angular/router';\nimport { ButtonComponent, IconComponent, ModalComponent } from '@syndew/oluso-ui-core';\nimport { SamlService } from '../../services/saml.service';\nimport { SamlServiceProvider, SamlTestResult } from '../../models/saml.model';\n\n@Component({\n selector: 'saml-service-providers-page',\n standalone: true,\n imports: [CommonModule, FormsModule, RouterLink, ButtonComponent, IconComponent, ModalComponent],\n template: `\n <div class=\"space-y-6\">\n <div class=\"flex items-center justify-between\">\n <div>\n <h1 class=\"text-2xl font-bold text-gray-900\">SAML Service Providers</h1>\n <p class=\"mt-1 text-sm text-gray-500\">Applications that use this system as their SAML Identity Provider</p>\n </div>\n <a routerLink=\"/saml/service-providers/new\">\n <ui-button>\n <ui-icon name=\"plus\" class=\"-ml-1 mr-2 h-5 w-5\" />\n Add Service Provider\n </ui-button>\n </a>\n </div>\n\n <!-- Filters -->\n <div class=\"flex items-center space-x-4\">\n <div class=\"flex-1 max-w-md\">\n <div class=\"relative\">\n <ui-icon name=\"search\" class=\"absolute left-3 top-1/2 transform -translate-y-1/2 h-5 w-5 text-gray-400\" />\n <input\n type=\"text\"\n [(ngModel)]=\"search\"\n (ngModelChange)=\"onSearchChange()\"\n placeholder=\"Search by Entity ID, name, or description...\"\n class=\"w-full pl-10 pr-4 py-2 border border-gray-300 rounded-md focus:ring-primary-500 focus:border-primary-500\"\n />\n </div>\n </div>\n <label class=\"flex items-center space-x-2 text-sm text-gray-700\">\n <input\n type=\"checkbox\"\n [(ngModel)]=\"showDisabled\"\n (ngModelChange)=\"loadServiceProviders()\"\n class=\"rounded border-gray-300 text-primary-600 focus:ring-primary-500\"\n />\n <span>Show disabled</span>\n </label>\n </div>\n\n @if (error()) {\n <div class=\"bg-red-50 border border-red-200 rounded-lg p-4\">\n <p class=\"text-red-700\">{{ error() }}</p>\n </div>\n }\n\n <!-- Test Result Toast -->\n @if (testResult()) {\n <div [class]=\"testResult()?.success ? 'bg-green-50 border-green-200' : 'bg-red-50 border-red-200'\" class=\"rounded-lg p-4 border\">\n <div class=\"flex items-center justify-between\">\n <div class=\"flex items-center space-x-2\">\n @if (testResult()?.success) {\n <ui-icon name=\"check-circle\" class=\"h-5 w-5 text-green-600\" />\n } @else {\n <ui-icon name=\"x-circle\" class=\"h-5 w-5 text-red-600\" />\n }\n <span [class]=\"testResult()?.success ? 'text-green-700' : 'text-red-700'\">{{ testResult()?.message }}</span>\n </div>\n <button (click)=\"testResult.set(null)\" class=\"text-gray-400 hover:text-gray-600\">×</button>\n </div>\n </div>\n }\n\n @if (loading()) {\n <div class=\"space-y-4\">\n @for (i of [1, 2, 3]; track i) {\n <div class=\"bg-gray-200 h-24 rounded-lg animate-pulse\"></div>\n }\n </div>\n } @else if (filteredProviders().length === 0) {\n <div class=\"text-center py-12 bg-white rounded-lg shadow\">\n <ui-icon name=\"building\" class=\"mx-auto h-12 w-12 text-gray-400\" />\n <h3 class=\"mt-2 text-sm font-medium text-gray-900\">No Service Providers</h3>\n <p class=\"mt-1 text-sm text-gray-500\">\n {{ search ? 'No service providers match your search.' : 'Get started by adding a SAML Service Provider.' }}\n </p>\n @if (!search) {\n <div class=\"mt-6\">\n <a routerLink=\"/saml/service-providers/new\">\n <ui-button>Add Service Provider</ui-button>\n </a>\n </div>\n }\n </div>\n } @else {\n <div class=\"bg-white shadow overflow-hidden rounded-lg\">\n <table class=\"min-w-full divide-y divide-gray-200\">\n <thead class=\"bg-gray-50\">\n <tr>\n <th class=\"px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider\">Service Provider</th>\n <th class=\"px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider\">Status</th>\n <th class=\"px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider\">Configuration</th>\n <th class=\"px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider\">Last Accessed</th>\n <th class=\"px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider\">Actions</th>\n </tr>\n </thead>\n <tbody class=\"bg-white divide-y divide-gray-200\">\n @for (sp of filteredProviders(); track sp.id) {\n <tr class=\"hover:bg-gray-50\">\n <td class=\"px-6 py-4\">\n <div class=\"flex items-center\">\n <ui-icon name=\"building\" class=\"h-8 w-8 text-gray-400 flex-shrink-0\" />\n <div class=\"ml-4\">\n <div class=\"text-sm font-medium text-gray-900\">{{ sp.displayName || sp.entityId }}</div>\n <div class=\"text-sm text-gray-500 max-w-xs truncate\" [title]=\"sp.entityId\">{{ sp.entityId }}</div>\n @if (sp.description) {\n <div class=\"text-xs text-gray-400 max-w-xs truncate\">{{ sp.description }}</div>\n }\n </div>\n </div>\n </td>\n <td class=\"px-6 py-4 whitespace-nowrap\">\n <span [class]=\"sp.enabled ? 'bg-green-100 text-green-800' : 'bg-gray-100 text-gray-800'\" class=\"inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium\">\n {{ sp.enabled ? 'Enabled' : 'Disabled' }}\n </span>\n </td>\n <td class=\"px-6 py-4\">\n <div class=\"flex items-center space-x-2 text-xs text-gray-500\">\n @if (sp.metadataUrl) {\n <span class=\"bg-blue-100 text-blue-800 px-2 py-0.5 rounded\">Metadata</span>\n } @else {\n <span class=\"bg-gray-100 text-gray-600 px-2 py-0.5 rounded\">Manual</span>\n }\n @if (sp.encryptAssertions) {\n <span class=\"bg-purple-100 text-purple-800 px-2 py-0.5 rounded\">Encrypted</span>\n }\n @if (sp.requireSignedAuthnRequests) {\n <span class=\"bg-yellow-100 text-yellow-800 px-2 py-0.5 rounded\">Signed Requests</span>\n }\n </div>\n </td>\n <td class=\"px-6 py-4 whitespace-nowrap text-sm text-gray-500\">\n {{ sp.lastAccessed ? formatDate(sp.lastAccessed) : 'Never' }}\n </td>\n <td class=\"px-6 py-4 whitespace-nowrap text-right text-sm font-medium\">\n <div class=\"flex items-center justify-end space-x-2\">\n <button (click)=\"handleTest(sp)\" [disabled]=\"actionLoading() === sp.id\" class=\"p-1.5 text-gray-400 hover:text-blue-600 hover:bg-blue-50 rounded\" title=\"Test configuration\">\n <svg class=\"h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M19.428 15.428a2 2 0 00-1.022-.547l-2.387-.477a6 6 0 00-3.86.517l-.318.158a6 6 0 01-3.86.517L6.05 15.21a2 2 0 00-1.806.547M8 4h8l-1 1v5.172a2 2 0 00.586 1.414l5 5c1.26 1.26.367 3.414-1.415 3.414H4.828c-1.782 0-2.674-2.154-1.414-3.414l5-5A2 2 0 009 10.172V5L8 4z\" />\n </svg>\n </button>\n <button (click)=\"handleToggle(sp)\" [disabled]=\"actionLoading() === sp.id || sp.nonEditable\" [class]=\"sp.enabled ? 'text-gray-400 hover:text-yellow-600 hover:bg-yellow-50' : 'text-gray-400 hover:text-green-600 hover:bg-green-50'\" class=\"p-1.5 rounded\" [class.opacity-50]=\"sp.nonEditable\" [class.cursor-not-allowed]=\"sp.nonEditable\" [title]=\"sp.enabled ? 'Disable' : 'Enable'\">\n @if (sp.enabled) {\n <ui-icon name=\"pause-circle\" class=\"h-4 w-4\" />\n } @else {\n <ui-icon name=\"play-circle\" class=\"h-4 w-4\" />\n }\n </button>\n <a [routerLink]=\"['/saml/service-providers', sp.id]\" class=\"p-1.5 text-gray-400 hover:text-primary-600 hover:bg-primary-50 rounded\" title=\"Edit\">\n <ui-icon name=\"pencil\" class=\"h-4 w-4\" />\n </a>\n <button (click)=\"confirmDelete(sp)\" [disabled]=\"actionLoading() === sp.id || sp.nonEditable\" class=\"p-1.5 text-gray-400 hover:text-red-600 hover:bg-red-50 rounded\" [class.opacity-50]=\"sp.nonEditable\" [class.cursor-not-allowed]=\"sp.nonEditable\" title=\"Delete\">\n <ui-icon name=\"trash\" class=\"h-4 w-4\" />\n </button>\n </div>\n </td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n\n <!-- Delete Confirmation Modal -->\n <ui-modal [open]=\"showDeleteModal()\" title=\"Delete Service Provider\" (closed)=\"showDeleteModal.set(false)\">\n <p class=\"text-sm text-gray-500\">\n Are you sure you want to delete \"{{ deleteTarget()?.displayName || deleteTarget()?.entityId }}\"?\n This action cannot be undone.\n </p>\n <div class=\"mt-4 flex justify-end gap-3\">\n <ui-button variant=\"secondary\" (clicked)=\"showDeleteModal.set(false)\">Cancel</ui-button>\n <ui-button variant=\"danger\" [disabled]=\"!!actionLoading()\" (clicked)=\"handleDelete()\">\n {{ actionLoading() ? 'Deleting...' : 'Delete' }}\n </ui-button>\n </div>\n </ui-modal>\n </div>\n `,\n})\nexport class ServiceProvidersPageComponent implements OnInit {\n private readonly samlService = inject(SamlService);\n\n readonly loading = signal(true);\n readonly error = signal<string | null>(null);\n readonly serviceProviders = signal<SamlServiceProvider[]>([]);\n readonly actionLoading = signal<number | null>(null);\n readonly testResult = signal<SamlTestResult | null>(null);\n readonly showDeleteModal = signal(false);\n readonly deleteTarget = signal<SamlServiceProvider | null>(null);\n\n search = '';\n showDisabled = true;\n\n readonly filteredProviders = () => {\n if (!this.search) return this.serviceProviders();\n const searchLower = this.search.toLowerCase();\n return this.serviceProviders().filter(\n (sp) =>\n sp.entityId.toLowerCase().includes(searchLower) ||\n sp.displayName?.toLowerCase().includes(searchLower) ||\n sp.description?.toLowerCase().includes(searchLower)\n );\n };\n\n ngOnInit(): void {\n this.loadServiceProviders();\n }\n\n loadServiceProviders(): void {\n this.loading.set(true);\n this.samlService.getAll(this.showDisabled).subscribe({\n next: (data) => {\n this.serviceProviders.set(data);\n this.error.set(null);\n this.loading.set(false);\n },\n error: (err) => {\n console.error('Error loading service providers:', err);\n this.error.set('Failed to load Service Providers');\n this.loading.set(false);\n },\n });\n }\n\n onSearchChange(): void {\n // Filtering is handled reactively\n }\n\n handleToggle(sp: SamlServiceProvider): void {\n this.actionLoading.set(sp.id);\n this.samlService.toggle(sp.id).subscribe({\n next: () => {\n this.loadServiceProviders();\n this.actionLoading.set(null);\n },\n error: (err) => {\n console.error('Error toggling service provider:', err);\n this.actionLoading.set(null);\n },\n });\n }\n\n confirmDelete(sp: SamlServiceProvider): void {\n this.deleteTarget.set(sp);\n this.showDeleteModal.set(true);\n }\n\n handleDelete(): void {\n const sp = this.deleteTarget();\n if (!sp) return;\n\n this.actionLoading.set(sp.id);\n this.samlService.delete(sp.id).subscribe({\n next: () => {\n this.showDeleteModal.set(false);\n this.deleteTarget.set(null);\n this.loadServiceProviders();\n this.actionLoading.set(null);\n },\n error: (err) => {\n console.error('Error deleting service provider:', err);\n this.actionLoading.set(null);\n },\n });\n }\n\n handleTest(sp: SamlServiceProvider): void {\n this.actionLoading.set(sp.id);\n this.testResult.set(null);\n this.samlService.test(sp.id).subscribe({\n next: (result) => {\n this.testResult.set(result);\n this.actionLoading.set(null);\n },\n error: () => {\n this.testResult.set({ success: false, message: 'Failed to run test' });\n this.actionLoading.set(null);\n },\n });\n }\n\n formatDate(dateStr: string): string {\n return new Date(dateStr).toLocaleDateString();\n }\n}\n","import { Component, OnInit, inject, signal } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { FormsModule } from '@angular/forms';\nimport { ActivatedRoute, Router, RouterLink } from '@angular/router';\nimport { ButtonComponent, IconComponent } from '@syndew/oluso-ui-core';\nimport { SamlService } from '../../services/saml.service';\nimport {\n CreateSamlServiceProviderRequest,\n SamlServiceProviderEdit,\n SamlTestResult,\n NAME_ID_FORMATS,\n SSO_BINDINGS,\n} from '../../models/saml.model';\nimport { Subject, debounceTime, distinctUntilChanged } from 'rxjs';\n\ninterface FormData {\n entityId: string;\n displayName: string;\n description: string;\n enabled: boolean;\n metadataUrl: string;\n assertionConsumerServiceUrl: string;\n singleLogoutServiceUrl: string;\n signingCertificate: string;\n encryptionCertificate: string;\n encryptAssertions: boolean;\n nameIdFormat: string;\n requireVerifiedEmail: boolean;\n allowedClaims: string;\n claimMappings: string;\n ssoBinding: string;\n signResponses: boolean;\n signAssertions: boolean;\n requireSignedAuthnRequests: boolean;\n defaultRelayState: string;\n}\n\nconst defaultFormData: FormData = {\n entityId: '',\n displayName: '',\n description: '',\n enabled: true,\n metadataUrl: '',\n assertionConsumerServiceUrl: '',\n singleLogoutServiceUrl: '',\n signingCertificate: '',\n encryptionCertificate: '',\n encryptAssertions: false,\n nameIdFormat: '',\n requireVerifiedEmail: false,\n allowedClaims: '',\n claimMappings: '',\n ssoBinding: 'POST',\n signResponses: true,\n signAssertions: true,\n requireSignedAuthnRequests: false,\n defaultRelayState: '',\n};\n\n@Component({\n selector: 'saml-service-provider-details-page',\n standalone: true,\n imports: [CommonModule, FormsModule, RouterLink, ButtonComponent, IconComponent],\n template: `\n <div class=\"space-y-6\">\n <div class=\"flex items-center space-x-4\">\n <a routerLink=\"/saml/service-providers\" class=\"p-2 text-gray-400 hover:text-gray-600 hover:bg-gray-100 rounded\">\n <ui-icon name=\"arrow-left\" class=\"h-5 w-5\" />\n </a>\n <h1 class=\"text-2xl font-bold text-gray-900\">{{ isNew ? 'Add Service Provider' : 'Edit Service Provider' }}</h1>\n </div>\n\n @if (loading()) {\n <div class=\"space-y-6\">\n <div class=\"h-8 w-48 bg-gray-200 rounded animate-pulse\"></div>\n <div class=\"bg-white shadow rounded-lg p-6 space-y-4\">\n @for (i of [1, 2, 3, 4]; track i) {\n <div class=\"h-12 bg-gray-200 rounded animate-pulse\"></div>\n }\n </div>\n </div>\n } @else {\n @if (error()) {\n <div class=\"bg-red-50 border border-red-200 rounded-lg p-4\">\n <div class=\"flex items-center space-x-2\">\n <ui-icon name=\"x-circle\" class=\"h-5 w-5 text-red-600\" />\n <span class=\"text-red-700\">{{ error() }}</span>\n </div>\n </div>\n }\n\n @if (nonEditable()) {\n <div class=\"bg-yellow-50 border border-yellow-200 rounded-lg p-4\">\n <div class=\"flex items-center space-x-2\">\n <ui-icon name=\"exclamation-triangle\" class=\"h-5 w-5 text-yellow-600\" />\n <span class=\"text-yellow-700\">This service provider is system-managed and cannot be modified.</span>\n </div>\n </div>\n }\n\n @if (testResult()) {\n <div [class]=\"testResult()?.success ? 'bg-green-50 border-green-200' : 'bg-red-50 border-red-200'\" class=\"rounded-lg p-4 border\">\n <div class=\"flex items-center justify-between\">\n <div class=\"flex items-center space-x-2\">\n @if (testResult()?.success) {\n <ui-icon name=\"check-circle\" class=\"h-5 w-5 text-green-600\" />\n } @else {\n <ui-icon name=\"x-circle\" class=\"h-5 w-5 text-red-600\" />\n }\n <span [class]=\"testResult()?.success ? 'text-green-700' : 'text-red-700'\">{{ testResult()?.message }}</span>\n </div>\n <button (click)=\"testResult.set(null)\" class=\"text-gray-400 hover:text-gray-600\">×</button>\n </div>\n </div>\n }\n\n <form (ngSubmit)=\"handleSubmit()\" class=\"space-y-6\">\n <!-- Basic Information -->\n <div class=\"bg-white shadow rounded-lg\">\n <div class=\"px-6 py-4 border-b border-gray-200\">\n <h2 class=\"text-lg font-medium text-gray-900\">Basic Information</h2>\n </div>\n <div class=\"px-6 py-4 space-y-4\">\n <div>\n <label for=\"entityId\" class=\"block text-sm font-medium text-gray-700\">\n Entity ID <span class=\"text-red-500\">*</span>\n </label>\n <input\n type=\"text\"\n id=\"entityId\"\n [(ngModel)]=\"formData.entityId\"\n name=\"entityId\"\n (ngModelChange)=\"onEntityIdChange($event)\"\n [disabled]=\"!isNew || nonEditable()\"\n required\n class=\"mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-primary-500 focus:ring-primary-500\"\n [class.border-red-500]=\"entityIdError()\"\n [class.bg-gray-100]=\"!isNew\"\n placeholder=\"https://sp.example.com/saml\"\n />\n @if (checkingEntityId()) {\n <p class=\"mt-1 text-sm text-gray-500\">Checking availability...</p>\n }\n @if (entityIdError()) {\n <p class=\"mt-1 text-sm text-red-600\">{{ entityIdError() }}</p>\n }\n <p class=\"mt-1 text-xs text-gray-500\">The unique SAML Entity ID for this Service Provider</p>\n </div>\n\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n <div>\n <label for=\"displayName\" class=\"block text-sm font-medium text-gray-700\">Display Name</label>\n <input\n type=\"text\"\n id=\"displayName\"\n [(ngModel)]=\"formData.displayName\"\n name=\"displayName\"\n [disabled]=\"nonEditable()\"\n class=\"mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-primary-500 focus:ring-primary-500\"\n placeholder=\"My Application\"\n />\n </div>\n\n <div>\n <label for=\"enabled\" class=\"block text-sm font-medium text-gray-700\">Status</label>\n <div class=\"mt-2\">\n <label class=\"inline-flex items-center\">\n <input\n type=\"checkbox\"\n [(ngModel)]=\"formData.enabled\"\n name=\"enabled\"\n [disabled]=\"nonEditable()\"\n class=\"rounded border-gray-300 text-primary-600 focus:ring-primary-500\"\n />\n <span class=\"ml-2 text-sm text-gray-700\">Enabled</span>\n </label>\n </div>\n </div>\n </div>\n\n <div>\n <label for=\"description\" class=\"block text-sm font-medium text-gray-700\">Description</label>\n <textarea\n id=\"description\"\n [(ngModel)]=\"formData.description\"\n name=\"description\"\n [disabled]=\"nonEditable()\"\n rows=\"2\"\n class=\"mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-primary-500 focus:ring-primary-500\"\n placeholder=\"Optional description of this service provider\"\n ></textarea>\n </div>\n </div>\n </div>\n\n <!-- Endpoints -->\n <div class=\"bg-white shadow rounded-lg\">\n <div class=\"px-6 py-4 border-b border-gray-200\">\n <h2 class=\"text-lg font-medium text-gray-900\">Endpoints</h2>\n <p class=\"mt-1 text-sm text-gray-500\">You can provide a metadata URL to auto-configure, or manually specify endpoints</p>\n </div>\n <div class=\"px-6 py-4 space-y-4\">\n <div>\n <label for=\"metadataUrl\" class=\"block text-sm font-medium text-gray-700\">Metadata URL</label>\n <input\n type=\"url\"\n id=\"metadataUrl\"\n [(ngModel)]=\"formData.metadataUrl\"\n name=\"metadataUrl\"\n [disabled]=\"nonEditable()\"\n class=\"mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-primary-500 focus:ring-primary-500\"\n placeholder=\"https://sp.example.com/saml/metadata\"\n />\n <p class=\"mt-1 text-xs text-gray-500\">If provided, endpoints and certificates will be fetched from metadata</p>\n </div>\n\n <div>\n <label for=\"assertionConsumerServiceUrl\" class=\"block text-sm font-medium text-gray-700\">Assertion Consumer Service (ACS) URL</label>\n <input\n type=\"url\"\n id=\"assertionConsumerServiceUrl\"\n [(ngModel)]=\"formData.assertionConsumerServiceUrl\"\n name=\"assertionConsumerServiceUrl\"\n [disabled]=\"nonEditable()\"\n class=\"mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-primary-500 focus:ring-primary-500\"\n placeholder=\"https://sp.example.com/saml/acs\"\n />\n <p class=\"mt-1 text-xs text-gray-500\">Where SAML responses should be sent (required if no metadata URL)</p>\n </div>\n\n <div>\n <label for=\"singleLogoutServiceUrl\" class=\"block text-sm font-medium text-gray-700\">Single Logout Service URL</label>\n <input\n type=\"url\"\n id=\"singleLogoutServiceUrl\"\n [(ngModel)]=\"formData.singleLogoutServiceUrl\"\n name=\"singleLogoutServiceUrl\"\n [disabled]=\"nonEditable()\"\n class=\"mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-primary-500 focus:ring-primary-500\"\n placeholder=\"https://sp.example.com/saml/slo\"\n />\n </div>\n\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n <div>\n <label for=\"ssoBinding\" class=\"block text-sm font-medium text-gray-700\">SSO Binding</label>\n <select\n id=\"ssoBinding\"\n [(ngModel)]=\"formData.ssoBinding\"\n name=\"ssoBinding\"\n [disabled]=\"nonEditable()\"\n class=\"mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-primary-500 focus:ring-primary-500\"\n >\n @for (binding of ssoBindings; track binding.value) {\n <option [value]=\"binding.value\">{{ binding.label }}</option>\n }\n </select>\n </div>\n\n <div>\n <label for=\"nameIdFormat\" class=\"block text-sm font-medium text-gray-700\">Name ID Format</label>\n <select\n id=\"nameIdFormat\"\n [(ngModel)]=\"formData.nameIdFormat\"\n name=\"nameIdFormat\"\n [disabled]=\"nonEditable()\"\n class=\"mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-primary-500 focus:ring-primary-500\"\n >\n @for (format of nameIdFormats; track format.value) {\n <option [value]=\"format.value\">{{ format.label }}</option>\n }\n </select>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Security -->\n <div class=\"bg-white shadow rounded-lg\">\n <div class=\"px-6 py-4 border-b border-gray-200\">\n <h2 class=\"text-lg font-medium text-gray-900\">Security</h2>\n </div>\n <div class=\"px-6 py-4 space-y-4\">\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n <label class=\"flex items-center\">\n <input\n type=\"checkbox\"\n [(ngModel)]=\"formData.signResponses\"\n name=\"signResponses\"\n [disabled]=\"nonEditable()\"\n class=\"rounded border-gray-300 text-primary-600 focus:ring-primary-500\"\n />\n <span class=\"ml-2 text-sm text-gray-700\">Sign SAML Responses</span>\n </label>\n\n <label class=\"flex items-center\">\n <input\n type=\"checkbox\"\n [(ngModel)]=\"formData.signAssertions\"\n name=\"signAssertions\"\n [disabled]=\"nonEditable()\"\n class=\"rounded border-gray-300 text-primary-600 focus:ring-primary-500\"\n />\n <span class=\"ml-2 text-sm text-gray-700\">Sign SAML Assertions</span>\n </label>\n\n <label class=\"flex items-center\">\n <input\n type=\"checkbox\"\n [(ngModel)]=\"formData.requireSignedAuthnRequests\"\n name=\"requireSignedAuthnRequests\"\n [disabled]=\"nonEditable()\"\n class=\"rounded border-gray-300 text-primary-600 focus:ring-primary-500\"\n />\n <span class=\"ml-2 text-sm text-gray-700\">Require Signed AuthnRequests</span>\n </label>\n\n <label class=\"flex items-center\">\n <input\n type=\"checkbox\"\n [(ngModel)]=\"formData.encryptAssertions\"\n name=\"encryptAssertions\"\n [disabled]=\"nonEditable()\"\n class=\"rounded border-gray-300 text-primary-600 focus:ring-primary-500\"\n />\n <span class=\"ml-2 text-sm text-gray-700\">Encrypt Assertions</span>\n </label>\n\n <label class=\"flex items-start md:col-span-2\">\n <input\n type=\"checkbox\"\n [(ngModel)]=\"formData.requireVerifiedEmail\"\n name=\"requireVerifiedEmail\"\n [disabled]=\"nonEditable()\"\n class=\"mt-0.5 rounded border-gray-300 text-primary-600 focus:ring-primary-500\"\n />\n <span class=\"ml-2 text-sm text-gray-700\">\n Require a verified email address\n <span class=\"block text-xs text-gray-500\">\n Only people whose email is verified get assertions for this service provider. Always applies\n when the Name ID format is the email address.\n </span>\n </span>\n </label>\n </div>\n\n <div>\n <label for=\"signingCertificate\" class=\"block text-sm font-medium text-gray-700\">SP Signing Certificate (Base64)</label>\n <textarea\n id=\"signingCertificate\"\n [(ngModel)]=\"formData.signingCertificate\"\n name=\"signingCertificate\"\n [disabled]=\"nonEditable()\"\n rows=\"3\"\n class=\"mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-primary-500 focus:ring-primary-500 font-mono text-xs\"\n placeholder=\"MIIDx...\"\n ></textarea>\n <p class=\"mt-1 text-xs text-gray-500\">Public certificate for verifying signed AuthnRequests from this SP</p>\n </div>\n\n <div>\n <label for=\"encryptionCertificate\" class=\"block text-sm font-medium text-gray-700\">SP Encryption Certificate (Base64)</label>\n <textarea\n id=\"encryptionCertificate\"\n [(ngModel)]=\"formData.encryptionCertificate\"\n name=\"encryptionCertificate\"\n [disabled]=\"nonEditable()\"\n rows=\"3\"\n class=\"mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-primary-500 focus:ring-primary-500 font-mono text-xs\"\n placeholder=\"MIIDx...\"\n ></textarea>\n <p class=\"mt-1 text-xs text-gray-500\">Public certificate for encrypting assertions sent to this SP</p>\n </div>\n </div>\n </div>\n\n <!-- Claims -->\n <div class=\"bg-white shadow rounded-lg\">\n <div class=\"px-6 py-4 border-b border-gray-200\">\n <h2 class=\"text-lg font-medium text-gray-900\">Claims Configuration</h2>\n </div>\n <div class=\"px-6 py-4 space-y-4\">\n <div>\n <label for=\"allowedClaims\" class=\"block text-sm font-medium text-gray-700\">Allowed Claims</label>\n <input\n type=\"text\"\n id=\"allowedClaims\"\n [(ngModel)]=\"formData.allowedClaims\"\n name=\"allowedClaims\"\n [disabled]=\"nonEditable()\"\n class=\"mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-primary-500 focus:ring-primary-500\"\n placeholder=\"email, name, given_name, family_name\"\n />\n <p class=\"mt-1 text-xs text-gray-500\">Comma-separated list of claim types to include in assertions (empty = all claims)</p>\n </div>\n\n <div>\n <label for=\"claimMappings\" class=\"block text-sm font-medium text-gray-700\">Claim Mappings</label>\n <textarea\n id=\"claimMappings\"\n [(ngModel)]=\"formData.claimMappings\"\n name=\"claimMappings\"\n [disabled]=\"nonEditable()\"\n rows=\"4\"\n class=\"mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-primary-500 focus:ring-primary-500 font-mono text-sm\"\n placeholder=\"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress=email\"\n ></textarea>\n <p class=\"mt-1 text-xs text-gray-500\">Map SAML attribute names to claim types (one per line: samlAttribute=claimType)</p>\n </div>\n\n <div>\n <label for=\"defaultRelayState\" class=\"block text-sm font-medium text-gray-700\">Default RelayState</label>\n <input\n type=\"text\"\n id=\"defaultRelayState\"\n [(ngModel)]=\"formData.defaultRelayState\"\n name=\"defaultRelayState\"\n [disabled]=\"nonEditable()\"\n class=\"mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-primary-500 focus:ring-primary-500\"\n placeholder=\"https://sp.example.com/dashboard\"\n />\n <p class=\"mt-1 text-xs text-gray-500\">Default redirect URL if the SP doesn't provide a RelayState</p>\n </div>\n </div>\n </div>\n\n <!-- Actions -->\n <div class=\"flex items-center justify-between\">\n <div>\n @if (!isNew) {\n <ui-button type=\"button\" variant=\"secondary\" (clicked)=\"handleTest()\">Test Configuration</ui-button>\n }\n </div>\n <div class=\"flex items-center space-x-4\">\n <a routerLink=\"/saml/service-providers\">\n <ui-button type=\"button\" variant=\"secondary\">Cancel</ui-button>\n </a>\n <ui-button type=\"submit\" [disabled]=\"saving() || nonEditable() || !!entityIdError()\">\n {{ saving() ? 'Saving...' : isNew ? 'Create Service Provider' : 'Save Changes' }}\n </ui-button>\n </div>\n </div>\n </form>\n }\n </div>\n `,\n})\nexport class ServiceProviderDetailsPageComponent implements OnInit {\n private readonly samlService = inject(SamlService);\n private readonly route = inject(ActivatedRoute);\n private readonly router = inject(Router);\n private readonly entityIdCheck$ = new Subject<string>();\n\n readonly loading = signal(false);\n readonly saving = signal(false);\n readonly error = signal<string | null>(null);\n readonly entityIdError = signal<string | null>(null);\n readonly checkingEntityId = signal(false);\n readonly testResult = signal<SamlTestResult | null>(null);\n readonly nonEditable = signal(false);\n\n formData: FormData = { ...defaultFormData };\n isNew = true;\n private id: number | null = null;\n\n readonly nameIdFormats = NAME_ID_FORMATS;\n readonly ssoBindings = SSO_BINDINGS;\n\n ngOnInit(): void {\n const idParam = this.route.snapshot.paramMap.get('id');\n this.isNew = !idParam || idParam === 'new';\n\n if (!this.isNew && idParam) {\n this.id = parseInt(idParam, 10);\n this.loadServiceProvider();\n }\n\n // Set up entity ID availability checking with debounce\n this.entityIdCheck$\n .pipe(debounceTime(500), distinctUntilChanged())\n .subscribe((entityId) => this.checkEntityIdAvailability(entityId));\n }\n\n loadServiceProvider(): void {\n if (!this.id) return;\n\n this.loading.set(true);\n this.samlService.getForEdit(this.id).subscribe({\n next: (sp) => {\n this.formData = {\n entityId: sp.entityId,\n displayName: sp.displayName || '',\n description: sp.description || '',\n enabled: sp.enabled,\n metadataUrl: sp.metadataUrl || '',\n assertionConsumerServiceUrl: sp.assertionConsumerServiceUrl || '',\n singleLogoutServiceUrl: sp.singleLogoutServiceUrl || '',\n signingCertificate: sp.signingCertificate || '',\n encryptionCertificate: sp.encryptionCertificate || '',\n encryptAssertions: sp.encryptAssertions,\n requireVerifiedEmail: sp.requireVerifiedEmail ?? false,\n nameIdFormat: sp.nameIdFormat || '',\n allowedClaims: sp.allowedClaims?.join(', ') || '',\n claimMappings: sp.claimMappings\n ? Object.entries(sp.claimMappings)\n .map(([k, v]) => `${k}=${v}`)\n .join('\\n')\n : '',\n ssoBinding: sp.ssoBinding,\n signResponses: sp.signResponses,\n signAssertions: sp.signAssertions,\n requireSignedAuthnRequests: sp.requireSignedAuthnRequests,\n defaultRelayState: sp.defaultRelayState || '',\n };\n this.nonEditable.set(sp.nonEditable);\n this.error.set(null);\n this.loading.set(false);\n },\n error: (err) => {\n console.error('Error loading service provider:', err);\n this.error.set('Failed to load service provider');\n this.loading.set(false);\n },\n });\n }\n\n onEntityIdChange(entityId: string): void {\n if (this.isNew && entityId) {\n this.entityIdCheck$.next(entityId);\n }\n }\n\n checkEntityIdAvailability(entityId: string): void {\n if (!entityId) return;\n\n this.checkingEntityId.set(true);\n this.samlService.checkEntityIdAvailability(entityId, this.isNew ? undefined : this.id!).subscribe({\n next: (result) => {\n if (!result.available) {\n this.entityIdError.set(result.message || 'Entity ID is already in use');\n } else {\n this.entityIdError.set(null);\n }\n this.checkingEntityId.set(false);\n },\n error: (err) => {\n console.error('Error checking entity ID:', err);\n this.checkingEntityId.set(false);\n },\n });\n }\n\n parseAllowedClaims(value: string): string[] | undefined {\n if (!value.trim()) return undefined;\n return value\n .split(',')\n .map((s) => s.trim())\n .filter((s) => s);\n }\n\n parseClaimMappings(value: string): Record<string, string> | undefined {\n if (!value.trim()) return undefined;\n const mappings: Record<string, string> = {};\n for (const line of value.split('\\n')) {\n const [key, val] = line.split('=').map((s) => s.trim());\n if (key && val) {\n mappings[key] = val;\n }\n }\n return Object.keys(mappings).length > 0 ? mappings : undefined;\n }\n\n handleSubmit(): void {\n if (this.entityIdError()) return;\n\n this.saving.set(true);\n this.error.set(null);\n\n if (this.isNew) {\n const request: CreateSamlServiceProviderRequest = {\n entityId: this.formData.entityId,\n displayName: this.formData.displayName || undefined,\n description: this.formData.description || undefined,\n enabled: this.formData.enabled,\n metadataUrl: this.formData.metadataUrl || undefined,\n assertionConsumerServiceUrl: this.formData.assertionConsumerServiceUrl || undefined,\n singleLogoutServiceUrl: this.formData.singleLogoutServiceUrl || undefined,\n signingCertificate: this.formData.signingCertificate || undefined,\n encryptionCertificate: this.formData.encryptionCertificate || undefined,\n encryptAssertions: this.formData.encryptAssertions,\n requireVerifiedEmail: this.formData.requireVerifiedEmail,\n nameIdFormat: this.formData.nameIdFormat || undefined,\n allowedClaims: this.parseAllowedClaims(this.formData.allowedClaims),\n claimMappings: this.parseClaimMappings(this.formData.claimMappings),\n ssoBinding: this.formData.ssoBinding,\n signResponses: this.formData.signResponses,\n signAssertions: this.formData.signAssertions,\n requireSignedAuthnRequests: this.formData.requireSignedAuthnRequests,\n defaultRelayState: this.formData.defaultRelayState || undefined,\n };\n\n this.samlService.create(request).subscribe({\n next: (created) => {\n this.router.navigate(['/saml/service-providers', created.id]);\n },\n error: (err) => {\n console.error('Error creating service provider:', err);\n this.error.set(err.error?.error || 'Failed to create service provider');\n this.saving.set(false);\n },\n });\n } else {\n const request: SamlServiceProviderEdit = {\n id: this.id!,\n entityId: this.formData.entityId,\n displayName: this.formData.displayName || undefined,\n description: this.formData.description || undefined,\n enabled: this.formData.enabled,\n metadataUrl: this.formData.metadataUrl || undefined,\n assertionConsumerServiceUrl: this.formData.assertionConsumerServiceUrl || undefined,\n singleLogoutServiceUrl: this.formData.singleLogoutServiceUrl || undefined,\n signingCertificate: this.formData.signingCertificate || undefined,\n encryptionCertificate: this.formData.encryptionCertificate || undefined,\n encryptAssertions: this.formData.encryptAssertions,\n requireVerifiedEmail: this.formData.requireVerifiedEmail,\n nameIdFormat: this.formData.nameIdFormat || undefined,\n allowedClaims: this.parseAllowedClaims(this.formData.allowedClaims),\n claimMappings: this.parseClaimMappings(this.formData.claimMappings),\n ssoBinding: this.formData.ssoBinding,\n signResponses: this.formData.signResponses,\n signAssertions: this.formData.signAssertions,\n requireSignedAuthnRequests: this.formData.requireSignedAuthnRequests,\n defaultRelayState: this.formData.defaultRelayState || undefined,\n nonEditable: this.nonEditable(),\n };\n\n this.samlService.update(this.id!, request).subscribe({\n next: () => {\n this.router.navigate(['/saml/service-providers']);\n },\n error: (err) => {\n console.error('Error updating service provider:', err);\n this.error.set(err.error?.error || 'Failed to save service provider');\n this.saving.set(false);\n },\n });\n }\n }\n\n handleTest(): void {\n if (this.isNew || !this.id) return;\n\n this.testResult.set(null);\n this.samlService.test(this.id).subscribe({\n next: (result) => this.testResult.set(result),\n error: () => this.testResult.set({ success: false, message: 'Failed to run test' }),\n });\n }\n}\n","import { Component, OnInit, inject, signal } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { FormsModule } from '@angular/forms';\nimport { ButtonComponent, IconComponent, TAB_CONTEXT } from '@syndew/oluso-ui-core';\nimport { SamlService } from '../../services/saml.service';\nimport { SamlIdpConfiguration, SamlIdpInfo, SamlCertificateInfo } from '../../models/saml.model';\nimport { forkJoin, catchError, of } from 'rxjs';\n\n@Component({\n selector: 'saml-idp-settings-tab',\n standalone: true,\n imports: [CommonModule, FormsModule, ButtonComponent, IconComponent],\n template: `\n <div class=\"space-y-6\">\n @if (error()) {\n <div class=\"bg-red-50 border border-red-200 rounded-lg p-4 flex items-center space-x-2\">\n <ui-icon name=\"exclamation-circle\" class=\"h-5 w-5 text-red-500\" />\n <p class=\"text-red-700\">{{ error() }}</p>\n </div>\n }\n\n @if (success()) {\n <div class=\"bg-green-50 border border-green-200 rounded-lg p-4 flex items-center space-x-2\">\n <ui-icon name=\"check-circle\" class=\"h-5 w-5 text-green-500\" />\n <p class=\"text-green-700\">{{ success() }}</p>\n </div>\n }\n\n @if (loading()) {\n <div class=\"space-y-6\">\n <div class=\"h-8 w-64 bg-gray-200 rounded animate-pulse\"></div>\n <div class=\"h-48 bg-gray-200 rounded-lg animate-pulse\"></div>\n </div>\n } @else {\n <!-- SAML IdP Settings -->\n <div class=\"space-y-6\">\n <div>\n <h3 class=\"text-lg font-medium text-gray-900\">SAML IdP Configuration</h3>\n <p class=\"mt-1 text-sm text-gray-500\">Enable and configure SAML Identity Provider functionality for this tenant</p>\n </div>\n\n <!-- Enable Toggle -->\n <div class=\"flex items-center justify-between\">\n <div>\n <p class=\"text-sm font-medium text-gray-700\">Enable SAML IdP</p>\n <p class=\"text-sm text-gray-500\">Allow external Service Providers to authenticate users via SAML</p>\n </div>\n <button\n type=\"button\"\n (click)=\"toggleEnabled()\"\n [class]=\"config.enabled ? 'bg-primary-600' : 'bg-gray-200'\"\n class=\"relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-primary-500 focus:ring-offset-2\"\n role=\"switch\"\n [attr.aria-checked]=\"config.enabled\"\n >\n <span\n [class]=\"config.enabled ? 'translate-x-5' : 'translate-x-0'\"\n class=\"pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out\"\n ></span>\n </button>\n </div>\n\n <!-- Login Journey Name -->\n <div>\n <label for=\"loginJourneyName\" class=\"block text-sm font-medium text-gray-700\">Login Journey Name</label>\n <input\n type=\"text\"\n id=\"loginJourneyName\"\n [(ngModel)]=\"config.loginJourneyName\"\n (ngModelChange)=\"onConfigChange()\"\n placeholder=\"default-login\"\n [disabled]=\"!config.enabled\"\n class=\"mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-primary-500 focus:ring-primary-500 sm:text-sm disabled:bg-gray-100 disabled:text-gray-500\"\n />\n <p class=\"mt-2 text-sm text-gray-500\">\n Journey to use for SAML SSO authentication. Leave empty to use the standalone login page at\n <code class=\"text-xs bg-gray-100 px-1 py-0.5 rounded\">/account/login</code>.\n </p>\n </div>\n\n <!-- Info Box -->\n <div class=\"bg-blue-50 border border-blue-200 rounded-lg p-4\">\n <div class=\"flex\">\n <ui-icon name=\"information-circle\" class=\"h-5 w-5 text-blue-500 flex-shrink-0\" />\n <div class=\"ml-3\">\n <h4 class=\"text-sm font-medium text-blue-800\">How SAML IdP Authentication Works</h4>\n <p class=\"mt-1 text-sm text-blue-700\">\n When a Service Provider sends an authentication request, users will be redirected to\n the configured login journey (or the standalone login page if not specified). After\n authentication, users are returned to the Service Provider with a SAML assertion.\n </p>\n </div>\n </div>\n </div>\n </div>\n\n <!-- IdP Endpoints Info - Only show when enabled and info available -->\n @if (config.enabled && idpInfo()) {\n <div class=\"space-y-4\">\n <div>\n <h3 class=\"text-lg font-medium text-gray-900\">IdP Endpoints</h3>\n <p class=\"mt-1 text-sm text-gray-500\">Share these URLs with Service Providers to configure SSO</p>\n </div>\n <div class=\"space-y-3\">\n <div class=\"flex items-center justify-between\">\n <div class=\"flex-1 min-w-0\">\n <span class=\"text-sm font-medium text-gray-500\">Metadata URL:</span>\n <code class=\"ml-2 text-sm text-gray-900 bg-gray-100 px-2 py-1 rounded\">{{ idpInfo()?.metadataUrl }}</code>\n </div>\n <button (click)=\"copyToClipboard(idpInfo()?.metadataUrl || '', 'metadata')\" class=\"ml-4 text-sm text-primary-600 hover:text-primary-700\">\n {{ copied() === 'metadata' ? 'Copied!' : 'Copy' }}\n </button>\n </div>\n <div class=\"flex items-center justify-between\">\n <div class=\"flex-1 min-w-0\">\n <span class=\"text-sm font-medium text-gray-500\">SSO Endpoint:</span>\n <code class=\"ml-2 text-sm text-gray-900 bg-gray-100 px-2 py-1 rounded\">{{ idpInfo()?.singleSignOnServiceUrl }}</code>\n </div>\n <button (click)=\"copyToClipboard(idpInfo()?.singleSignOnServiceUrl || '', 'sso')\" class=\"ml-4 text-sm text-primary-600 hover:text-primary-700\">\n {{ copied() === 'sso' ? 'Copied!' : 'Copy' }}\n </button>\n </div>\n <div class=\"flex items-center justify-between\">\n <div class=\"flex-1 min-w-0\">\n <span class=\"text-sm font-medium text-gray-500\">SLO Endpoint:</span>\n <code class=\"ml-2 text-sm text-gray-900 bg-gray-100 px-2 py-1 rounded\">{{ idpInfo()?.singleLogoutServiceUrl }}</code>\n </div>\n <button (click)=\"copyToClipboard(idpInfo()?.singleLogoutServiceUrl || '', 'slo')\" class=\"ml-4 text-sm text-primary-600 hover:text-primary-700\">\n {{ copied() === 'slo' ? 'Copied!' : 'Copy' }}\n </button>\n </div>\n <div class=\"flex items-center justify-between\">\n <div class=\"flex-1 min-w-0\">\n <span class=\"text-sm font-medium text-gray-500\">Entity ID:</span>\n <code class=\"ml-2 text-sm text-gray-900 bg-gray-100 px-2 py-1 rounded\">{{ idpInfo()?.entityId }}</code>\n </div>\n <button (click)=\"copyToClipboard(idpInfo()?.entityId || '', 'entity')\" class=\"ml-4 text-sm text-primary-600 hover:text-primary-700\">\n {{ copied() === 'entity' ? 'Copied!' : 'Copy' }}\n </button>\n </div>\n </div>\n </div>\n }\n\n <!-- Endpoints Preview - Show when enabled but IdP info not available -->\n @if (config.enabled && !idpInfo()) {\n <div class=\"space-y-4\">\n <div>\n <h3 class=\"text-lg font-medium text-gray-900\">IdP Endpoints</h3>\n <p class=\"mt-1 text-sm text-gray-500\">These endpoints will be available once SAML IdP is enabled</p>\n </div>\n <div class=\"space-y-3\">\n <div class=\"flex items-center justify-between\">\n <div class=\"flex-1 min-w-0\">\n <span class=\"text-sm font-medium text-gray-500\">Metadata:</span>\n <code class=\"ml-2 text-sm text-gray-900 bg-gray-100 px-2 py-1 rounded\">/saml/idp/metadata</code>\n </div>\n </div>\n <div class=\"flex items-center justify-between\">\n <div class=\"flex-1 min-w-0\">\n <span class=\"text-sm font-medium text-gray-500\">SSO Endpoint:</span>\n <code class=\"ml-2 text-sm text-gray-900 bg-gray-100 px-2 py-1 rounded\">/saml/idp/sso</code>\n </div>\n </div>\n <div class=\"flex items-center justify-between\">\n <div class=\"flex-1 min-w-0\">\n <span class=\"text-sm font-medium text-gray-500\">SLO Endpoint:</span>\n <code class=\"ml-2 text-sm text-gray-900 bg-gray-100 px-2 py-1 rounded\">/saml/idp/slo</code>\n </div>\n </div>\n </div>\n </div>\n }\n\n <!-- IdP Certificates - Show when enabled -->\n @if (config.enabled) {\n <div class=\"space-y-4\">\n <div>\n <h3 class=\"text-lg font-medium text-gray-900\">IdP Certificates</h3>\n <p class=\"mt-1 text-sm text-gray-500\">Configure certificates for signing SAML assertions and decrypting requests</p>\n </div>\n\n <!-- Signing Certificate -->\n <div class=\"bg-gray-50 rounded-lg p-4 space-y-3\">\n <div class=\"flex items-start justify-between\">\n <div>\n <div class=\"flex items-center gap-2\">\n <ui-icon name=\"shield-check\" class=\"h-5 w-5 text-gray-400\" />\n <h4 class=\"text-sm font-medium text-gray-900\">Signing Certificate</h4>\n @if (signingCert()) {\n <span [class]=\"getSourceBadgeClass(signingCert()?.source || '')\" class=\"inline-flex items-center px-2 py-0.5 rounded text-xs font-medium\">\n {{ getSourceBadgeText(signingCert()?.source || '') }}\n </span>\n }\n </div>\n <p class=\"text-sm text-gray-500 mt-1\">Used to sign SAML assertions sent to Service Providers</p>\n </div>\n </div>\n\n @if (signingCert()?.hasCertificate) {\n <div [class]=\"signingCert()?.isRevoked ? 'bg-red-50 rounded border border-red-300 p-3 space-y-2' : 'bg-white rounded border border-gray-200 p-3 space-y-2'\">\n @if (signingCert()?.isRevoked) {\n <div class=\"flex items-center gap-2 text-red-700 bg-red-100 rounded px-2 py-1 mb-2\">\n <ui-icon name=\"warning\" class=\"h-4 w-4\" />\n <span class=\"text-sm font-medium\">Certificate Revoked - Please generate a new certificate</span>\n </div>\n }\n <div class=\"grid grid-cols-2 gap-x-4 gap-y-2 text-sm\">\n <div>\n <span class=\"text-gray-500\">Subject:</span>\n <span class=\"ml-2 text-gray-900 font-mono text-xs\">{{ signingCert()?.subject || 'N/A' }}</span>\n </div>\n <div>\n <span class=\"text-gray-500\">Thumbprint:</span>\n <span class=\"ml-2 text-gray-900 font-mono text-xs\">{{ truncateThumbprint(signingCert()?.thumbprint) }}</span>\n </div>\n <div>\n <span class=\"text-gray-500\">Valid From:</span>\n <span class=\"ml-2 text-gray-900\">{{ formatDate(signingCert()?.notBefore) }}</span>\n </div>\n <div class=\"flex items-center gap-2\">\n <span class=\"text-gray-500\">Valid Until:</span>\n <span [class]=\"signingCert()?.isRevoked ? 'text-red-600' : signingCert()?.isExpired ? 'text-red-600' : signingCert()?.isExpiringSoon ? 'text-yellow-600' : 'text-gray-900'\" class=\"ml-2\">\n {{ formatDate(signingCert()?.notAfter) }}\n </span>\n @if (signingCert()?.isRevoked) {\n <span class=\"inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-red-100 text-red-800\">Revoked</span>\n }\n @if (!signingCert()?.isRevoked && signingCert()?.isExpired) {\n <ui-icon name=\"warning\" class=\"h-4 w-4 text-red-500\" />\n }\n @if (!signingCert()?.isRevoked && signingCert()?.isExpiringSoon && !signingCert()?.isExpired) {\n <ui-icon name=\"warning\" class=\"h-4 w-4 text-yellow-500\" />\n }\n </div>\n </div>\n </div>\n } @else {\n <div class=\"text-sm text-gray-500 italic\">No certificate configured. Using global certificate.</div>\n }\n\n <!-- Action buttons -->\n <div class=\"flex items-center gap-2 pt-2\">\n <ui-button variant=\"secondary\" size=\"sm\" [disabled]=\"certLoading() === 'signing'\" (clicked)=\"generateSigningCert()\">\n @if (certLoading() === 'signing') {\n <svg class=\"h-4 w-4 mr-1.5 animate-spin\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15\" />\n </svg>\n } @else {\n <ui-icon name=\"refresh\" class=\"h-4 w-4 mr-1.5\" />\n }\n Generate New\n </ui-button>\n <ui-button variant=\"secondary\" size=\"sm\" [disabled]=\"certLoading() === 'signing'\" (clicked)=\"toggleSigningUpload()\">\n <ui-icon name=\"arrow-up-tray\" class=\"h-4 w-4 mr-1.5\" />\n Upload PFX\n </ui-button>\n @if (signingCert()?.source !== 'Global') {\n <ui-button variant=\"secondary\" size=\"sm\" [disabled]=\"certLoading() === 'signing'\" (clicked)=\"resetSigningCert()\">\n Reset to Global\n </ui-button>\n }\n </div>\n\n <!-- Upload form for signing cert -->\n @if (showSigningUpload()) {\n <div class=\"bg-white rounded border border-gray-200 p-3 space-y-3\">\n <div>\n <label class=\"block text-sm font-medium text-gray-700\">PFX Password (optional)</label>\n <input\n type=\"password\"\n [(ngModel)]=\"signingPassword\"\n placeholder=\"Enter password if PFX is protected\"\n class=\"mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-primary-500 focus:ring-primary-500 sm:text-sm\"\n />\n </div>\n <div>\n <label class=\"block text-sm font-medium text-gray-700\">Select PFX File</label>\n <input\n type=\"file\"\n accept=\".pfx,.p12\"\n (change)=\"onSigningFileSelect($event)\"\n [disabled]=\"certLoading() === 'signing'\"\n class=\"mt-1 block w-full text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded-md file:border-0 file:text-sm file:font-medium file:bg-primary-50 file:text-primary-700 hover:file:bg-primary-100\"\n />\n </div>\n <button\n type=\"button\"\n (click)=\"toggleSigningUpload()\"\n class=\"text-sm text-gray-500 hover:text-gray-700\"\n >\n Cancel\n </button>\n </div>\n }\n </div>\n\n <!-- Encryption Certificate -->\n <div class=\"bg-gray-50 rounded-lg p-4 space-y-3\">\n <div class=\"flex items-start justify-between\">\n <div>\n <div class=\"flex items-center gap-2\">\n <ui-icon name=\"shield-check\" class=\"h-5 w-5 text-gray-400\" />\n <h4 class=\"text-sm font-medium text-gray-900\">Encryption Certificate</h4>\n @if (encryptionCert()) {\n <span [class]=\"getSourceBadgeClass(encryptionCert()?.source || '')\" class=\"inline-flex items-center px-2 py-0.5 rounded text-xs font-medium\">\n {{ getSourceBadgeText(encryptionCert()?.source || '') }}\n </span>\n }\n </div>\n <p class=\"text-sm text-gray-500 mt-1\">Used to decrypt incoming encrypted SAML requests (optional)</p>\n </div>\n </div>\n\n @if (encryptionCert()?.hasCertificate) {\n <div [class]=\"encryptionCert()?.isRevoked ? 'bg-red-50 rounded border border-red-300 p-3 space-y-2' : 'bg-white rounded border border-gray-200 p-3 space-y-2'\">\n @if (encryptionCert()?.isRevoked) {\n <div class=\"flex items-center gap-2 text-red-700 bg-red-100 rounded px-2 py-1 mb-2\">\n <ui-icon name=\"warning\" class=\"h-4 w-4\" />\n <span class=\"text-sm font-medium\">Certificate Revoked - Please generate a new certificate</span>\n </div>\n }\n <div class=\"grid grid-cols-2 gap-x-4 gap-y-2 text-sm\">\n <div>\n <span class=\"text-gray-500\">Subject:</span>\n <span class=\"ml-2 text-gray-900 font-mono text-xs\">{{ encryptionCert()?.subject || 'N/A' }}</span>\n </div>\n <div>\n <span class=\"text-gray-500\">Thumbprint:</span>\n <span class=\"ml-2 text-gray-900 font-mono text-xs\">{{ truncateThumbprint(encryptionCert()?.thumbprint) }}</span>\n </div>\n <div>\n <span class=\"text-gray-500\">Valid From:</span>\n <span class=\"ml-2 text-gray-900\">{{ formatDate(encryptionCert()?.notBefore) }}</span>\n </div>\n <div class=\"flex items-center gap-2\">\n <span class=\"text-gray-500\">Valid Until:</span>\n <span [class]=\"encryptionCert()?.isRevoked ? 'text-red-600' : encryptionCert()?.isExpired ? 'text-red-600' : encryptionCert()?.isExpiringSoon ? 'text-yellow-600' : 'text-gray-900'\" class=\"ml-2\">\n {{ formatDate(encryptionCert()?.notAfter) }}\n </span>\n @if (encryptionCert()?.isRevoked) {\n <span class=\"inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-red-100 text-red-800\">Revoked</span>\n }\n @if (!encryptionCert()?.isRevoked && encryptionCert()?.isExpired) {\n <ui-icon name=\"warning\" class=\"h-4 w-4 text-red-500\" />\n }\n @if (!encryptionCert()?.isRevoked && encryptionCert()?.isExpiringSoon && !encryptionCert()?.isExpired) {\n <ui-icon name=\"warning\" class=\"h-4 w-4 text-yellow-500\" />\n }\n </div>\n </div>\n </div>\n } @else {\n <div class=\"text-sm text-gray-500 italic\">No certificate configured. Using global certificate.</div>\n }\n\n <!-- Action buttons -->\n <div class=\"flex items-center gap-2 pt-2\">\n <ui-button variant=\"secondary\" size=\"sm\" [disabled]=\"certLoading() === 'encryption'\" (clicked)=\"generateEncryptionCert()\">\n @if (certLoading() === 'encryption') {\n <svg class=\"h-4 w-4 mr-1.5 animate-spin\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15\" />\n </svg>\n } @else {\n <ui-icon name=\"refresh\" class=\"h-4 w-4 mr-1.5\" />\n }\n Generate New\n </ui-button>\n <ui-button variant=\"secondary\" size=\"sm\" [disabled]=\"certLoading() === 'encryption'\" (clicked)=\"toggleEncryptionUpload()\">\n <ui-icon name=\"arrow-up-tray\" class=\"h-4 w-4 mr-1.5\" />\n Upload PFX\n </ui-button>\n @if (encryptionCert()?.source !== 'Global') {\n <ui-button variant=\"secondary\" size=\"sm\" [disabled]=\"certLoading() === 'encryption'\" (clicked)=\"resetEncryptionCert()\">\n Reset to Global\n </ui-button>\n }\n </div>\n\n <!-- Upload form for encryption cert -->\n @if (showEncryptionUpload()) {\n <div class=\"bg-white rounded border border-gray-200 p-3 space-y-3\">\n <div>\n <label class=\"block text-sm font-medium text-gray-700\">PFX Password (optional)</label>\n <input\n type=\"password\"\n [(ngModel)]=\"encryptionPassword\"\n placeholder=\"Enter password if PFX is protected\"\n class=\"mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-primary-500 focus:ring-primary-500 sm:text-sm\"\n />\n </div>\n <div>\n <label class=\"block text-sm font-medium text-gray-700\">Select PFX File</label>\n <input\n type=\"file\"\n accept=\".pfx,.p12\"\n (change)=\"onEncryptionFileSelect($event)\"\n [disabled]=\"certLoading() === 'encryption'\"\n class=\"mt-1 block w-full text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded-md file:border-0 file:text-sm file:font-medium file:bg-primary-50 file:text-primary-700 hover:file:bg-primary-100\"\n />\n </div>\n <button\n type=\"button\"\n (click)=\"toggleEncryptionUpload()\"\n class=\"text-sm text-gray-500 hover:text-gray-700\"\n >\n Cancel\n </button>\n </div>\n }\n </div>\n </div>\n }\n\n <!-- Save Button -->\n <div class=\"flex justify-end items-center gap-4 pt-4 border-t border-gray-200\">\n @if (hasChanges()) {\n <span class=\"text-sm text-gray-500\">You have unsaved changes</span>\n }\n <ui-button [disabled]=\"!hasChanges() || saving()\" (clicked)=\"handleSave()\">\n {{ saving() ? 'Saving...' : 'Save Settings' }}\n </ui-button>\n </div>\n }\n </div>\n `,\n})\nexport class SamlIdpSettingsTabComponent implements OnInit {\n private readonly samlService = inject(SamlService);\n private readonly tabContext = inject(TAB_CONTEXT, { optional: true });\n\n readonly loading = signal(true);\n readonly saving = signal(false);\n readonly error = signal<string | null>(null);\n readonly success = signal<string | null>(null);\n readonly hasChanges = signal(false);\n readonly idpInfo = signal<SamlIdpInfo | null>(null);\n readonly signingCert = signal<SamlCertificateInfo | null>(null);\n readonly encryptionCert = signal<SamlCertificateInfo | null>(null);\n readonly certLoading = signal<'signing' | 'encryption' | null>(null);\n readonly copied = signal<string | null>(null);\n readonly showSigningUpload = signal(false);\n readonly showEncryptionUpload = signal(false);\n\n config: SamlIdpConfiguration = {\n enabled: false,\n loginJourneyName: undefined,\n };\n\n signingPassword = '';\n encryptionPassword = '';\n\n ngOnInit(): void {\n this.loadData();\n }\n\n loadData(): void {\n this.loading.set(true);\n forkJoin({\n config: this.samlService.getIdpConfiguration(),\n idpInfo: this.samlService.getIdpInfo().pipe(catchError(() => of(null))),\n signingCert: this.samlService.getSigningCertificate().pipe(catchError(() => of(null))),\n encryptionCert: this.samlService.getEncryptionCertificate().pipe(catchError(() => of(null))),\n }).subscribe({\n next: (data) => {\n this.config = data.config;\n this.idpInfo.set(data.idpInfo);\n this.signingCert.set(data.signingCert);\n this.encryptionCert.set(data.encryptionCert);\n this.error.set(null);\n this.loading.set(false);\n },\n error: (err) => {\n console.error('Error loading SAML IdP config:', err);\n this.error.set('Failed to load SAML IdP configuration');\n this.loading.set(false);\n },\n });\n }\n\n toggleEnabled(): void {\n this.config.enabled = !this.config.enabled;\n this.onConfigChange();\n }\n\n onConfigChange(): void {\n this.hasChanges.set(true);\n this.success.set(null);\n }\n\n handleSave(): void {\n this.saving.set(true);\n this.error.set(null);\n this.samlService.updateIdpConfiguration(this.config).subscribe({\n next: () => {\n this.success.set('SAML IdP settings saved successfully');\n this.hasChanges.set(false);\n this.saving.set(false);\n // Reload IdP info in case endpoints changed\n this.samlService.getIdpInfo().subscribe({\n next: (info) => this.idpInfo.set(info),\n error: () => {},\n });\n },\n error: (err) => {\n console.error('Error saving SAML IdP config:', err);\n this.error.set('Failed to save SAML IdP configuration');\n this.saving.set(false);\n },\n });\n }\n\n // Signing Certificate Methods\n generateSigningCert(): void {\n this.certLoading.set('signing');\n this.samlService.generateSigningCertificate().subscribe({\n next: (cert) => {\n this.signingCert.set(cert);\n this.success.set('Signing certificate generated successfully');\n this.certLoading.set(null);\n },\n error: (err) => {\n console.error('Error generating signing certificate:', err);\n this.error.set('Failed to generate signing certificate');\n this.certLoading.set(null);\n },\n });\n }\n\n resetSigningCert(): void {\n this.certLoading.set('signing');\n this.samlService.resetSigningCertificate().subscribe({\n next: () => {\n this.loadCertificates();\n this.success.set('Signing certificate reset to global');\n this.certLoading.set(null);\n },\n error: (err) => {\n console.error('Error resetting signing certificate:', err);\n this.error.set('Failed to reset signing certificate');\n this.certLoading.set(null);\n },\n });\n }\n\n toggleSigningUpload(): void {\n this.showSigningUpload.update((v) => !v);\n if (!this.showSigningUpload()) {\n this.signingPassword = '';\n }\n }\n\n onSigningFileSelect(event: Event): void {\n const input = event.target as HTMLInputElement;\n const file = input.files?.[0];\n if (!file) return;\n\n this.certLoading.set('signing');\n const reader = new FileReader();\n reader.onload = () => {\n const arrayBuffer = reader.result as ArrayBuffer;\n const bytes = new Uint8Array(arrayBuffer);\n const base64 = btoa(String.fromCharCode(...bytes));\n\n this.samlService.uploadSigningCertificate({\n base64Pfx: base64,\n password: this.signingPassword || undefined,\n }).subscribe({\n next: (cert) => {\n this.signingCert.set(cert);\n this.success.set('Signing certificate uploaded successfully');\n this.certLoading.set(null);\n this.showSigningUpload.set(false);\n this.signingPassword = '';\n },\n error: (err) => {\n console.error('Error uploading signing certificate:', err);\n this.error.set('Failed to upload signing certificate');\n this.certLoading.set(null);\n },\n });\n };\n reader.readAsArrayBuffer(file);\n input.value = '';\n }\n\n // Encryption Certificate Methods\n generateEncryptionCert(): void {\n this.certLoading.set('encryption');\n this.samlService.generateEncryptionCertificate().subscribe({\n next: (cert) => {\n this.encryptionCert.set(cert);\n this.success.set('Encryption certificate generated successfully');\n this.certLoading.set(null);\n },\n error: (err) => {\n console.error('Error generating encryption certificate:', err);\n this.error.set('Failed to generate encryption certificate');\n this.certLoading.set(null);\n },\n });\n }\n\n resetEncryptionCert(): void {\n this.certLoading.set('encryption');\n this.samlService.resetEncryptionCertificate().subscribe({\n next: () => {\n this.loadCertificates();\n this.success.set('Encryption certificate reset to global');\n this.certLoading.set(null);\n },\n error: (err) => {\n console.error('Error resetting encryption certificate:', err);\n this.error.set('Failed to reset encryption certificate');\n this.certLoading.set(null);\n },\n });\n }\n\n toggleEncryptionUpload(): void {\n this.showEncryptionUpload.update((v) => !v);\n if (!this.showEncryptionUpload()) {\n this.encryptionPassword = '';\n }\n }\n\n onEncryptionFileSelect(event: Event): void {\n const input = event.target as HTMLInputElement;\n const file = input.files?.[0];\n if (!file) return;\n\n this.certLoading.set('encryption');\n const reader = new FileReader();\n reader.onload = () => {\n const arrayBuffer = reader.result as ArrayBuffer;\n const bytes = new Uint8Array(arrayBuffer);\n const base64 = btoa(String.fromCharCode(...bytes));\n\n this.samlService.uploadEncryptionCertificate({\n base64Pfx: base64,\n password: this.encryptionPassword || undefined,\n }).subscribe({\n next: (cert) => {\n this.encryptionCert.set(cert);\n this.success.set('Encryption certificate uploaded successfully');\n this.certLoading.set(null);\n this.showEncryptionUpload.set(false);\n this.encryptionPassword = '';\n },\n error: (err) => {\n console.error('Error uploading encryption certificate:', err);\n this.error.set('Failed to upload encryption certificate');\n this.certLoading.set(null);\n },\n });\n };\n reader.readAsArrayBuffer(file);\n input.value = '';\n }\n\n private loadCertificates(): void {\n forkJoin({\n signing: this.samlService.getSigningCertificate().pipe(catchError(() => of(null))),\n encryption: this.samlService.getEncryptionCertificate().pipe(catchError(() => of(null))),\n }).subscribe({\n next: (data) => {\n this.signingCert.set(data.signing);\n this.encryptionCert.set(data.encryption);\n },\n error: (err) => {\n console.error('Error loading certificates:', err);\n },\n });\n }\n\n copyToClipboard(value: string, key = 'metadata'): void {\n navigator.clipboard.writeText(value).then(() => {\n this.copied.set(key);\n setTimeout(() => this.copied.set(null), 2000);\n });\n }\n\n formatDate(dateStr?: string): string {\n if (!dateStr) return 'N/A';\n return new Date(dateStr).toLocaleDateString(undefined, {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n });\n }\n\n truncateThumbprint(thumbprint?: string): string {\n if (!thumbprint) return 'N/A';\n return thumbprint.substring(0, 16) + '...';\n }\n\n getSourceBadgeClass(source: string): string {\n switch (source) {\n case 'Global':\n return 'bg-gray-100 text-gray-800';\n case 'Auto':\n return 'bg-blue-100 text-blue-800';\n case 'Uploaded':\n return 'bg-green-100 text-green-800';\n default:\n return 'bg-gray-100 text-gray-800';\n }\n }\n\n getSourceBadgeText(source: string): string {\n switch (source) {\n case 'Auto':\n return 'Auto-generated';\n default:\n return source;\n }\n }\n}\n","import { Routes } from '@angular/router';\nimport { SamlDashboardComponent } from './pages/saml-dashboard/saml-dashboard.component';\nimport { ServiceProvidersPageComponent } from './pages/service-providers/service-providers-page.component';\nimport { ServiceProviderDetailsPageComponent } from './pages/service-provider-details/service-provider-details-page.component';\n\nexport const SAML_ROUTES: Routes = [\n {\n path: '',\n redirectTo: 'dashboard',\n pathMatch: 'full',\n },\n {\n path: 'dashboard',\n component: SamlDashboardComponent,\n },\n {\n path: 'service-providers',\n component: ServiceProvidersPageComponent,\n },\n {\n path: 'service-providers/new',\n component: ServiceProviderDetailsPageComponent,\n },\n {\n path: 'service-providers/:id',\n component: ServiceProviderDetailsPageComponent,\n },\n];\n","import { AdminPlugin, NavItem } from '@syndew/oluso-ui-core';\nimport { SamlIdpSettingsTabComponent } from './components/saml-idp-settings-tab/saml-idp-settings-tab.component';\nimport { SAML_ROUTES } from './saml.routes';\n\n/**\n * SAML Admin Plugin\n *\n * Provides SAML Identity Provider management functionality:\n * - Dashboard with IdP info and stats\n * - Service Provider management (CRUD)\n * - Settings tab for IdP configuration\n */\nexport const SAML_PLUGIN: AdminPlugin = {\n name: 'oluso-saml',\n version: '1.0.0',\n\n // Plugin routes - will be automatically added under /saml path\n routes: [\n {\n path: 'saml',\n children: SAML_ROUTES,\n },\n ],\n\n navItems: [\n {\n id: 'saml',\n label: 'SAML',\n path: '/saml',\n icon: 'shield-check',\n order: 10,\n mergeIntoPath: '/identity-providers',\n children: [\n { label: 'SAML Dashboard', path: '/saml/dashboard', icon: 'shield-check', permission: 'saml.read', order: 10 },\n { label: 'Service Providers', path: '/saml/service-providers', icon: 'shield-check', permission: 'saml.read', order: 20 },\n ],\n } as NavItem,\n ],\n\n settingsTabs: [\n {\n id: 'saml-idp',\n label: 'SAML IdP',\n icon: 'shield-check',\n component: SamlIdpSettingsTabComponent,\n order: 400,\n },\n ],\n};\n\n/**\n * Helper function to get SAML navigation items\n */\nexport function getSamlNavItems(): NavItem[] {\n return SAML_PLUGIN.navItems ?? [];\n}\n","// Models\nexport * from './lib/models/saml.model';\n\n// Services\nexport * from './lib/services/saml.service';\n\n// Pages\nexport * from './lib/pages/saml-dashboard/saml-dashboard.component';\nexport * from './lib/pages/service-providers/service-providers-page.component';\nexport * from './lib/pages/service-provider-details/service-provider-details-page.component';\n\n// Components\nexport * from './lib/components/saml-idp-settings-tab/saml-idp-settings-tab.component';\n\n// Routes\nexport * from './lib/saml.routes';\n\n// Plugin registration\nexport * from './lib/saml.plugin';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;;;;;;;AAgJA;;AAEG;AACI,MAAM,eAAe,GAAG;AAC7B,IAAA,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,wBAAwB,EAAE;AAC9C,IAAA,EAAE,KAAK,EAAE,wDAAwD,EAAE,KAAK,EAAE,eAAe,EAAE;AAC3F,IAAA,EAAE,KAAK,EAAE,sDAAsD,EAAE,KAAK,EAAE,YAAY,EAAE;AACtF,IAAA,EAAE,KAAK,EAAE,qDAAqD,EAAE,KAAK,EAAE,WAAW,EAAE;AACpF,IAAA,EAAE,KAAK,EAAE,uDAAuD,EAAE,KAAK,EAAE,aAAa,EAAE;;AAG1F;;AAEG;AACI,MAAM,YAAY,GAAG;AAC1B,IAAA,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE;AACrC,IAAA,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,eAAe,EAAE;;;ACjJ/C;;;;AAIG;MAEU,WAAW,CAAA;AACL,IAAA,GAAG,GAAG,MAAM,CAAC,UAAU,CAAC;IACxB,QAAQ,GAAG,yBAAyB;AAErD;;AAEG;IACH,UAAU,GAAA;AACR,QAAA,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,CAAc,CAAA,EAAG,IAAI,CAAC,QAAQ,CAAA,SAAA,CAAW,CAAC;IAC/D;AAEA;;AAEG;IACH,yBAAyB,CAAC,QAAgB,EAAE,SAAkB,EAAA;QAC5D,MAAM,MAAM,GAA8C,EAAE;QAC5D,IAAI,SAAS,EAAE;AACb,YAAA,MAAM,CAAC,WAAW,CAAC,GAAG,SAAS;QACjC;AACA,QAAA,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,CACjB,GAAG,IAAI,CAAC,QAAQ,CAAA,iBAAA,EAAoB,kBAAkB,CAAC,QAAQ,CAAC,EAAE,EAClE,MAAM,CACP;IACH;AAEA;;AAEG;IACH,MAAM,CAAC,eAAe,GAAG,KAAK,EAAA;AAC5B,QAAA,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,CAAwB,IAAI,CAAC,QAAQ,EAAE,EAAE,eAAe,EAAE,CAAC;IAChF;AAEA;;AAEG;AACH,IAAA,OAAO,CAAC,EAAU,EAAA;AAChB,QAAA,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,CAAsB,CAAA,EAAG,IAAI,CAAC,QAAQ,CAAA,CAAA,EAAI,EAAE,CAAA,CAAE,CAAC;IACpE;AAEA;;AAEG;AACH,IAAA,UAAU,CAAC,EAAU,EAAA;AACnB,QAAA,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,CAA0B,CAAA,EAAG,IAAI,CAAC,QAAQ,CAAA,CAAA,EAAI,EAAE,CAAA,KAAA,CAAO,CAAC;IAC7E;AAEA;;AAEG;AACH,IAAA,MAAM,CAAC,IAAsC,EAAA;AAC3C,QAAA,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAsB,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC;IAChE;AAEA;;AAEG;IACH,MAAM,CAAC,EAAU,EAAE,IAA6B,EAAA;AAC9C,QAAA,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,CAAsB,CAAA,EAAG,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAA,CAAE,EAAE,IAAI,CAAC;IAC1E;AAEA;;AAEG;AACH,IAAA,MAAM,CAAC,EAAU,EAAA;AACf,QAAA,OAAO,IAAI,CAAC,GAAG,CAAC,MAAM,CAAO,CAAA,EAAG,IAAI,CAAC,QAAQ,CAAA,CAAA,EAAI,EAAE,CAAA,CAAE,CAAC;IACxD;AAEA;;AAEG;AACH,IAAA,MAAM,CAAC,EAAU,EAAA;AACf,QAAA,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAsB,CAAA,EAAG,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAA,OAAA,CAAS,EAAE,EAAE,CAAC;IAChF;AAEA;;AAEG;AACH,IAAA,IAAI,CAAC,EAAU,EAAA;AACb,QAAA,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAiB,CAAA,EAAG,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAA,KAAA,CAAO,EAAE,EAAE,CAAC;IACzE;;AAIA;;AAEG;IACH,mBAAmB,GAAA;AACjB,QAAA,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,CAAuB,CAAA,EAAG,IAAI,CAAC,QAAQ,CAAA,kBAAA,CAAoB,CAAC;IACjF;AAEA;;AAEG;AACH,IAAA,sBAAsB,CAAC,IAA0B,EAAA;AAC/C,QAAA,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,CAAuB,CAAA,EAAG,IAAI,CAAC,QAAQ,CAAA,kBAAA,CAAoB,EAAE,IAAI,CAAC;IACvF;;AAIA;;AAEG;IACH,qBAAqB,GAAA;AACnB,QAAA,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,CAAsB,CAAA,EAAG,IAAI,CAAC,QAAQ,CAAA,wBAAA,CAA0B,CAAC;IACtF;AAEA;;AAEG;IACH,wBAAwB,GAAA;AACtB,QAAA,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,CAAsB,CAAA,EAAG,IAAI,CAAC,QAAQ,CAAA,2BAAA,CAA6B,CAAC;IACzF;AAEA;;AAEG;IACH,0BAA0B,GAAA;AACxB,QAAA,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAsB,CAAA,EAAG,IAAI,CAAC,QAAQ,CAAA,iCAAA,CAAmC,EAAE,EAAE,CAAC;IACpG;AAEA;;AAEG;IACH,6BAA6B,GAAA;AAC3B,QAAA,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAsB,CAAA,EAAG,IAAI,CAAC,QAAQ,CAAA,oCAAA,CAAsC,EAAE,EAAE,CAAC;IACvG;AAEA;;AAEG;AACH,IAAA,wBAAwB,CAAC,IAA8B,EAAA;AACrD,QAAA,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAsB,CAAA,EAAG,IAAI,CAAC,QAAQ,CAAA,+BAAA,CAAiC,EAAE,IAAI,CAAC;IACpG;AAEA;;AAEG;AACH,IAAA,2BAA2B,CAAC,IAA8B,EAAA;AACxD,QAAA,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAsB,CAAA,EAAG,IAAI,CAAC,QAAQ,CAAA,kCAAA,CAAoC,EAAE,IAAI,CAAC;IACvG;AAEA;;AAEG;IACH,uBAAuB,GAAA;AACrB,QAAA,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAO,CAAA,EAAG,IAAI,CAAC,QAAQ,CAAA,8BAAA,CAAgC,EAAE,EAAE,CAAC;IAClF;AAEA;;AAEG;IACH,0BAA0B,GAAA;AACxB,QAAA,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAO,CAAA,EAAG,IAAI,CAAC,QAAQ,CAAA,iCAAA,CAAmC,EAAE,EAAE,CAAC;IACrF;wGAzJW,WAAW,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;AAAX,IAAA,OAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAW,cADE,MAAM,EAAA,CAAA;;4FACnB,WAAW,EAAA,UAAA,EAAA,CAAA;kBADvB,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE;;;MCyLrB,sBAAsB,CAAA;AAChB,IAAA,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC;AAEzC,IAAA,OAAO,GAAG,MAAM,CAAC,IAAI,8EAAC;AACtB,IAAA,KAAK,GAAG,MAAM,CAAgB,IAAI,4EAAC;AACnC,IAAA,OAAO,GAAG,MAAM,CAAqB,IAAI,8EAAC;AAC1C,IAAA,gBAAgB,GAAG,MAAM,CAAwB,EAAE,uFAAC;AACpD,IAAA,MAAM,GAAG,MAAM,CAAgB,IAAI,6EAAC;IAEpC,YAAY,GAAG,MAAM,IAAI,CAAC,gBAAgB,EAAE,CAAC,MAAM,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,OAAO,CAAC,CAAC,MAAM;AAC9E,IAAA,aAAa,GAAG,MAAM,IAAI,CAAC,gBAAgB,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,YAAY,EAAE;IAEnF,QAAQ,GAAA;QACN,IAAI,CAAC,QAAQ,EAAE;IACjB;IAEA,QAAQ,GAAA;AACN,QAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;AACtB,QAAA,QAAQ,CAAC;AACP,YAAA,OAAO,EAAE,IAAI,CAAC,WAAW,CAAC,UAAU,EAAE;AACtC,YAAA,gBAAgB,EAAE,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE;SAC5C,CAAC,CAAC,SAAS,CAAC;AACX,YAAA,IAAI,EAAE,CAAC,IAAI,KAAI;gBACb,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC;gBAC9B,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,gBAAgB,CAAC;AAChD,gBAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC;AACpB,gBAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC;YACzB,CAAC;AACD,YAAA,KAAK,EAAE,CAAC,GAAG,KAAI;AACb,gBAAA,OAAO,CAAC,KAAK,CAAC,0BAA0B,EAAE,GAAG,CAAC;AAC9C,gBAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,mCAAmC,CAAC;AACnD,gBAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC;YACzB,CAAC;AACF,SAAA,CAAC;IACJ;IAEA,eAAe,CAAC,KAAa,EAAE,KAAa,EAAA;QAC1C,SAAS,CAAC,SAAS,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAK;AAC7C,YAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;AACtB,YAAA,UAAU,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC;AAC/C,QAAA,CAAC,CAAC;IACJ;AAEA,IAAA,aAAa,CAAC,MAAc,EAAA;QAC1B,OAAO,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,MAAM;IAC1C;wGA7CW,sBAAsB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAtB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,sBAAsB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,gBAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EAjMvB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+LT,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAhMS,YAAY,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAE,UAAU,EAAA,QAAA,EAAA,cAAA,EAAA,MAAA,EAAA,CAAA,QAAA,EAAA,aAAA,EAAA,UAAA,EAAA,qBAAA,EAAA,OAAA,EAAA,MAAA,EAAA,YAAA,EAAA,kBAAA,EAAA,oBAAA,EAAA,YAAA,EAAA,YAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAE,eAAe,qJAAE,aAAa,EAAA,QAAA,EAAA,SAAA,EAAA,MAAA,EAAA,CAAA,MAAA,EAAA,aAAA,CAAA,EAAA,CAAA,EAAA,CAAA;;4FAkMvD,sBAAsB,EAAA,UAAA,EAAA,CAAA;kBArMlC,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,gBAAgB;AAC1B,oBAAA,UAAU,EAAE,IAAI;oBAChB,OAAO,EAAE,CAAC,YAAY,EAAE,UAAU,EAAE,eAAe,EAAE,aAAa,CAAC;AACnE,oBAAA,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+LT,EAAA,CAAA;AACF,iBAAA;;;MCbY,6BAA6B,CAAA;AACvB,IAAA,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC;AAEzC,IAAA,OAAO,GAAG,MAAM,CAAC,IAAI,8EAAC;AACtB,IAAA,KAAK,GAAG,MAAM,CAAgB,IAAI,4EAAC;AACnC,IAAA,gBAAgB,GAAG,MAAM,CAAwB,EAAE,uFAAC;AACpD,IAAA,aAAa,GAAG,MAAM,CAAgB,IAAI,oFAAC;AAC3C,IAAA,UAAU,GAAG,MAAM,CAAwB,IAAI,iFAAC;AAChD,IAAA,eAAe,GAAG,MAAM,CAAC,KAAK,sFAAC;AAC/B,IAAA,YAAY,GAAG,MAAM,CAA6B,IAAI,mFAAC;IAEhE,MAAM,GAAG,EAAE;IACX,YAAY,GAAG,IAAI;IAEV,iBAAiB,GAAG,MAAK;QAChC,IAAI,CAAC,IAAI,CAAC,MAAM;AAAE,YAAA,OAAO,IAAI,CAAC,gBAAgB,EAAE;QAChD,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE;QAC7C,OAAO,IAAI,CAAC,gBAAgB,EAAE,CAAC,MAAM,CACnC,CAAC,EAAE,KACD,EAAE,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC;YAC/C,EAAE,CAAC,WAAW,EAAE,WAAW,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC;YACnD,EAAE,CAAC,WAAW,EAAE,WAAW,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC,CACtD;AACH,IAAA,CAAC;IAED,QAAQ,GAAA;QACN,IAAI,CAAC,oBAAoB,EAAE;IAC7B;IAEA,oBAAoB,GAAA;AAClB,QAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;QACtB,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,SAAS,CAAC;AACnD,YAAA,IAAI,EAAE,CAAC,IAAI,KAAI;AACb,gBAAA,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC;AAC/B,gBAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC;AACpB,gBAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC;YACzB,CAAC;AACD,YAAA,KAAK,EAAE,CAAC,GAAG,KAAI;AACb,gBAAA,OAAO,CAAC,KAAK,CAAC,kCAAkC,EAAE,GAAG,CAAC;AACtD,gBAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,kCAAkC,CAAC;AAClD,gBAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC;YACzB,CAAC;AACF,SAAA,CAAC;IACJ;IAEA,cAAc,GAAA;;IAEd;AAEA,IAAA,YAAY,CAAC,EAAuB,EAAA;QAClC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;QAC7B,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC;YACvC,IAAI,EAAE,MAAK;gBACT,IAAI,CAAC,oBAAoB,EAAE;AAC3B,gBAAA,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC;YAC9B,CAAC;AACD,YAAA,KAAK,EAAE,CAAC,GAAG,KAAI;AACb,gBAAA,OAAO,CAAC,KAAK,CAAC,kCAAkC,EAAE,GAAG,CAAC;AACtD,gBAAA,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC;YAC9B,CAAC;AACF,SAAA,CAAC;IACJ;AAEA,IAAA,aAAa,CAAC,EAAuB,EAAA;AACnC,QAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC;AACzB,QAAA,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC;IAChC;IAEA,YAAY,GAAA;AACV,QAAA,MAAM,EAAE,GAAG,IAAI,CAAC,YAAY,EAAE;AAC9B,QAAA,IAAI,CAAC,EAAE;YAAE;QAET,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;QAC7B,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC;YACvC,IAAI,EAAE,MAAK;AACT,gBAAA,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC;AAC/B,gBAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC;gBAC3B,IAAI,CAAC,oBAAoB,EAAE;AAC3B,gBAAA,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC;YAC9B,CAAC;AACD,YAAA,KAAK,EAAE,CAAC,GAAG,KAAI;AACb,gBAAA,OAAO,CAAC,KAAK,CAAC,kCAAkC,EAAE,GAAG,CAAC;AACtD,gBAAA,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC;YAC9B,CAAC;AACF,SAAA,CAAC;IACJ;AAEA,IAAA,UAAU,CAAC,EAAuB,EAAA;QAChC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;AAC7B,QAAA,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC;QACzB,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC;AACrC,YAAA,IAAI,EAAE,CAAC,MAAM,KAAI;AACf,gBAAA,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC;AAC3B,gBAAA,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC;YAC9B,CAAC;YACD,KAAK,EAAE,MAAK;AACV,gBAAA,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,oBAAoB,EAAE,CAAC;AACtE,gBAAA,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC;YAC9B,CAAC;AACF,SAAA,CAAC;IACJ;AAEA,IAAA,UAAU,CAAC,OAAe,EAAA;QACxB,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC,kBAAkB,EAAE;IAC/C;wGAxGW,6BAA6B,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAA7B,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,6BAA6B,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,6BAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EAnL9B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiLT,EAAA,QAAA,EAAA,IAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAlLS,YAAY,EAAA,EAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAE,WAAW,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,oBAAA,EAAA,QAAA,EAAA,8MAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,4BAAA,EAAA,QAAA,EAAA,uGAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,eAAA,EAAA,QAAA,EAAA,2CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,OAAA,EAAA,QAAA,EAAA,qDAAA,EAAA,MAAA,EAAA,CAAA,MAAA,EAAA,UAAA,EAAA,SAAA,EAAA,gBAAA,CAAA,EAAA,OAAA,EAAA,CAAA,eAAA,CAAA,EAAA,QAAA,EAAA,CAAA,SAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAE,UAAU,oOAAE,eAAe,EAAA,QAAA,EAAA,WAAA,EAAA,MAAA,EAAA,CAAA,SAAA,EAAA,MAAA,EAAA,UAAA,EAAA,SAAA,EAAA,MAAA,EAAA,WAAA,CAAA,EAAA,OAAA,EAAA,CAAA,SAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAE,aAAa,EAAA,QAAA,EAAA,SAAA,EAAA,MAAA,EAAA,CAAA,MAAA,EAAA,aAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAE,cAAc,EAAA,QAAA,EAAA,UAAA,EAAA,MAAA,EAAA,CAAA,MAAA,EAAA,OAAA,EAAA,MAAA,EAAA,iBAAA,EAAA,iBAAA,EAAA,eAAA,EAAA,YAAA,CAAA,EAAA,OAAA,EAAA,CAAA,QAAA,CAAA,EAAA,CAAA,EAAA,CAAA;;4FAoLpF,6BAA6B,EAAA,UAAA,EAAA,CAAA;kBAvLzC,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,6BAA6B;AACvC,oBAAA,UAAU,EAAE,IAAI;AAChB,oBAAA,OAAO,EAAE,CAAC,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,eAAe,EAAE,aAAa,EAAE,cAAc,CAAC;AAChG,oBAAA,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiLT,EAAA,CAAA;AACF,iBAAA;;;ACzJD,MAAM,eAAe,GAAa;AAChC,IAAA,QAAQ,EAAE,EAAE;AACZ,IAAA,WAAW,EAAE,EAAE;AACf,IAAA,WAAW,EAAE,EAAE;AACf,IAAA,OAAO,EAAE,IAAI;AACb,IAAA,WAAW,EAAE,EAAE;AACf,IAAA,2BAA2B,EAAE,EAAE;AAC/B,IAAA,sBAAsB,EAAE,EAAE;AAC1B,IAAA,kBAAkB,EAAE,EAAE;AACtB,IAAA,qBAAqB,EAAE,EAAE;AACzB,IAAA,iBAAiB,EAAE,KAAK;AACxB,IAAA,YAAY,EAAE,EAAE;AAChB,IAAA,oBAAoB,EAAE,KAAK;AAC3B,IAAA,aAAa,EAAE,EAAE;AACjB,IAAA,aAAa,EAAE,EAAE;AACjB,IAAA,UAAU,EAAE,MAAM;AAClB,IAAA,aAAa,EAAE,IAAI;AACnB,IAAA,cAAc,EAAE,IAAI;AACpB,IAAA,0BAA0B,EAAE,KAAK;AACjC,IAAA,iBAAiB,EAAE,EAAE;CACtB;MAsYY,mCAAmC,CAAA;AAC7B,IAAA,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC;AACjC,IAAA,KAAK,GAAG,MAAM,CAAC,cAAc,CAAC;AAC9B,IAAA,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;AACvB,IAAA,cAAc,GAAG,IAAI,OAAO,EAAU;AAE9C,IAAA,OAAO,GAAG,MAAM,CAAC,KAAK,8EAAC;AACvB,IAAA,MAAM,GAAG,MAAM,CAAC,KAAK,6EAAC;AACtB,IAAA,KAAK,GAAG,MAAM,CAAgB,IAAI,4EAAC;AACnC,IAAA,aAAa,GAAG,MAAM,CAAgB,IAAI,oFAAC;AAC3C,IAAA,gBAAgB,GAAG,MAAM,CAAC,KAAK,uFAAC;AAChC,IAAA,UAAU,GAAG,MAAM,CAAwB,IAAI,iFAAC;AAChD,IAAA,WAAW,GAAG,MAAM,CAAC,KAAK,kFAAC;AAEpC,IAAA,QAAQ,GAAa,EAAE,GAAG,eAAe,EAAE;IAC3C,KAAK,GAAG,IAAI;IACJ,EAAE,GAAkB,IAAI;IAEvB,aAAa,GAAG,eAAe;IAC/B,WAAW,GAAG,YAAY;IAEnC,QAAQ,GAAA;AACN,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC;QACtD,IAAI,CAAC,KAAK,GAAG,CAAC,OAAO,IAAI,OAAO,KAAK,KAAK;AAE1C,QAAA,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,OAAO,EAAE;YAC1B,IAAI,CAAC,EAAE,GAAG,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC;YAC/B,IAAI,CAAC,mBAAmB,EAAE;QAC5B;;AAGA,QAAA,IAAI,CAAC;aACF,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,oBAAoB,EAAE;AAC9C,aAAA,SAAS,CAAC,CAAC,QAAQ,KAAK,IAAI,CAAC,yBAAyB,CAAC,QAAQ,CAAC,CAAC;IACtE;IAEA,mBAAmB,GAAA;QACjB,IAAI,CAAC,IAAI,CAAC,EAAE;YAAE;AAEd,QAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;QACtB,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC;AAC7C,YAAA,IAAI,EAAE,CAAC,EAAE,KAAI;gBACX,IAAI,CAAC,QAAQ,GAAG;oBACd,QAAQ,EAAE,EAAE,CAAC,QAAQ;AACrB,oBAAA,WAAW,EAAE,EAAE,CAAC,WAAW,IAAI,EAAE;AACjC,oBAAA,WAAW,EAAE,EAAE,CAAC,WAAW,IAAI,EAAE;oBACjC,OAAO,EAAE,EAAE,CAAC,OAAO;AACnB,oBAAA,WAAW,EAAE,EAAE,CAAC,WAAW,IAAI,EAAE;AACjC,oBAAA,2BAA2B,EAAE,EAAE,CAAC,2BAA2B,IAAI,EAAE;AACjE,oBAAA,sBAAsB,EAAE,EAAE,CAAC,sBAAsB,IAAI,EAAE;AACvD,oBAAA,kBAAkB,EAAE,EAAE,CAAC,kBAAkB,IAAI,EAAE;AAC/C,oBAAA,qBAAqB,EAAE,EAAE,CAAC,qBAAqB,IAAI,EAAE;oBACrD,iBAAiB,EAAE,EAAE,CAAC,iBAAiB;AACvC,oBAAA,oBAAoB,EAAE,EAAE,CAAC,oBAAoB,IAAI,KAAK;AACtD,oBAAA,YAAY,EAAE,EAAE,CAAC,YAAY,IAAI,EAAE;oBACnC,aAAa,EAAE,EAAE,CAAC,aAAa,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;oBACjD,aAAa,EAAE,EAAE,CAAC;0BACd,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,aAAa;AAC5B,6BAAA,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAA,EAAG,CAAC,CAAA,CAAA,EAAI,CAAC,EAAE;6BAC3B,IAAI,CAAC,IAAI;AACd,0BAAE,EAAE;oBACN,UAAU,EAAE,EAAE,CAAC,UAAU;oBACzB,aAAa,EAAE,EAAE,CAAC,aAAa;oBAC/B,cAAc,EAAE,EAAE,CAAC,cAAc;oBACjC,0BAA0B,EAAE,EAAE,CAAC,0BAA0B;AACzD,oBAAA,iBAAiB,EAAE,EAAE,CAAC,iBAAiB,IAAI,EAAE;iBAC9C;gBACD,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,WAAW,CAAC;AACpC,gBAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC;AACpB,gBAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC;YACzB,CAAC;AACD,YAAA,KAAK,EAAE,CAAC,GAAG,KAAI;AACb,gBAAA,OAAO,CAAC,KAAK,CAAC,iCAAiC,EAAE,GAAG,CAAC;AACrD,gBAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,iCAAiC,CAAC;AACjD,gBAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC;YACzB,CAAC;AACF,SAAA,CAAC;IACJ;AAEA,IAAA,gBAAgB,CAAC,QAAgB,EAAA;AAC/B,QAAA,IAAI,IAAI,CAAC,KAAK,IAAI,QAAQ,EAAE;AAC1B,YAAA,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC;QACpC;IACF;AAEA,IAAA,yBAAyB,CAAC,QAAgB,EAAA;AACxC,QAAA,IAAI,CAAC,QAAQ;YAAE;AAEf,QAAA,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC;QAC/B,IAAI,CAAC,WAAW,CAAC,yBAAyB,CAAC,QAAQ,EAAE,IAAI,CAAC,KAAK,GAAG,SAAS,GAAG,IAAI,CAAC,EAAG,CAAC,CAAC,SAAS,CAAC;AAChG,YAAA,IAAI,EAAE,CAAC,MAAM,KAAI;AACf,gBAAA,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE;oBACrB,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,IAAI,6BAA6B,CAAC;gBACzE;qBAAO;AACL,oBAAA,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC;gBAC9B;AACA,gBAAA,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,KAAK,CAAC;YAClC,CAAC;AACD,YAAA,KAAK,EAAE,CAAC,GAAG,KAAI;AACb,gBAAA,OAAO,CAAC,KAAK,CAAC,2BAA2B,EAAE,GAAG,CAAC;AAC/C,gBAAA,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,KAAK,CAAC;YAClC,CAAC;AACF,SAAA,CAAC;IACJ;AAEA,IAAA,kBAAkB,CAAC,KAAa,EAAA;AAC9B,QAAA,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE;AAAE,YAAA,OAAO,SAAS;AACnC,QAAA,OAAO;aACJ,KAAK,CAAC,GAAG;aACT,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE;aACnB,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IACrB;AAEA,IAAA,kBAAkB,CAAC,KAAa,EAAA;AAC9B,QAAA,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE;AAAE,YAAA,OAAO,SAAS;QACnC,MAAM,QAAQ,GAA2B,EAAE;QAC3C,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE;YACpC,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC;AACvD,YAAA,IAAI,GAAG,IAAI,GAAG,EAAE;AACd,gBAAA,QAAQ,CAAC,GAAG,CAAC,GAAG,GAAG;YACrB;QACF;AACA,QAAA,OAAO,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM,GAAG,CAAC,GAAG,QAAQ,GAAG,SAAS;IAChE;IAEA,YAAY,GAAA;QACV,IAAI,IAAI,CAAC,aAAa,EAAE;YAAE;AAE1B,QAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC;AACrB,QAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC;AAEpB,QAAA,IAAI,IAAI,CAAC,KAAK,EAAE;AACd,YAAA,MAAM,OAAO,GAAqC;AAChD,gBAAA,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,QAAQ;AAChC,gBAAA,WAAW,EAAE,IAAI,CAAC,QAAQ,CAAC,WAAW,IAAI,SAAS;AACnD,gBAAA,WAAW,EAAE,IAAI,CAAC,QAAQ,CAAC,WAAW,IAAI,SAAS;AACnD,gBAAA,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,OAAO;AAC9B,gBAAA,WAAW,EAAE,IAAI,CAAC,QAAQ,CAAC,WAAW,IAAI,SAAS;AACnD,gBAAA,2BAA2B,EAAE,IAAI,CAAC,QAAQ,CAAC,2BAA2B,IAAI,SAAS;AACnF,gBAAA,sBAAsB,EAAE,IAAI,CAAC,QAAQ,CAAC,sBAAsB,IAAI,SAAS;AACzE,gBAAA,kBAAkB,EAAE,IAAI,CAAC,QAAQ,CAAC,kBAAkB,IAAI,SAAS;AACjE,gBAAA,qBAAqB,EAAE,IAAI,CAAC,QAAQ,CAAC,qBAAqB,IAAI,SAAS;AACvE,gBAAA,iBAAiB,EAAE,IAAI,CAAC,QAAQ,CAAC,iBAAiB;AAClD,gBAAA,oBAAoB,EAAE,IAAI,CAAC,QAAQ,CAAC,oBAAoB;AACxD,gBAAA,YAAY,EAAE,IAAI,CAAC,QAAQ,CAAC,YAAY,IAAI,SAAS;gBACrD,aAAa,EAAE,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC;gBACnE,aAAa,EAAE,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC;AACnE,gBAAA,UAAU,EAAE,IAAI,CAAC,QAAQ,CAAC,UAAU;AACpC,gBAAA,aAAa,EAAE,IAAI,CAAC,QAAQ,CAAC,aAAa;AAC1C,gBAAA,cAAc,EAAE,IAAI,CAAC,QAAQ,CAAC,cAAc;AAC5C,gBAAA,0BAA0B,EAAE,IAAI,CAAC,QAAQ,CAAC,0BAA0B;AACpE,gBAAA,iBAAiB,EAAE,IAAI,CAAC,QAAQ,CAAC,iBAAiB,IAAI,SAAS;aAChE;YAED,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC;AACzC,gBAAA,IAAI,EAAE,CAAC,OAAO,KAAI;AAChB,oBAAA,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,yBAAyB,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC;gBAC/D,CAAC;AACD,gBAAA,KAAK,EAAE,CAAC,GAAG,KAAI;AACb,oBAAA,OAAO,CAAC,KAAK,CAAC,kCAAkC,EAAE,GAAG,CAAC;AACtD,oBAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,IAAI,mCAAmC,CAAC;AACvE,oBAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;gBACxB,CAAC;AACF,aAAA,CAAC;QACJ;aAAO;AACL,YAAA,MAAM,OAAO,GAA4B;gBACvC,EAAE,EAAE,IAAI,CAAC,EAAG;AACZ,gBAAA,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,QAAQ;AAChC,gBAAA,WAAW,EAAE,IAAI,CAAC,QAAQ,CAAC,WAAW,IAAI,SAAS;AACnD,gBAAA,WAAW,EAAE,IAAI,CAAC,QAAQ,CAAC,WAAW,IAAI,SAAS;AACnD,gBAAA,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,OAAO;AAC9B,gBAAA,WAAW,EAAE,IAAI,CAAC,QAAQ,CAAC,WAAW,IAAI,SAAS;AACnD,gBAAA,2BAA2B,EAAE,IAAI,CAAC,QAAQ,CAAC,2BAA2B,IAAI,SAAS;AACnF,gBAAA,sBAAsB,EAAE,IAAI,CAAC,QAAQ,CAAC,sBAAsB,IAAI,SAAS;AACzE,gBAAA,kBAAkB,EAAE,IAAI,CAAC,QAAQ,CAAC,kBAAkB,IAAI,SAAS;AACjE,gBAAA,qBAAqB,EAAE,IAAI,CAAC,QAAQ,CAAC,qBAAqB,IAAI,SAAS;AACvE,gBAAA,iBAAiB,EAAE,IAAI,CAAC,QAAQ,CAAC,iBAAiB;AAClD,gBAAA,oBAAoB,EAAE,IAAI,CAAC,QAAQ,CAAC,oBAAoB;AACxD,gBAAA,YAAY,EAAE,IAAI,CAAC,QAAQ,CAAC,YAAY,IAAI,SAAS;gBACrD,aAAa,EAAE,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC;gBACnE,aAAa,EAAE,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC;AACnE,gBAAA,UAAU,EAAE,IAAI,CAAC,QAAQ,CAAC,UAAU;AACpC,gBAAA,aAAa,EAAE,IAAI,CAAC,QAAQ,CAAC,aAAa;AAC1C,gBAAA,cAAc,EAAE,IAAI,CAAC,QAAQ,CAAC,cAAc;AAC5C,gBAAA,0BAA0B,EAAE,IAAI,CAAC,QAAQ,CAAC,0BAA0B;AACpE,gBAAA,iBAAiB,EAAE,IAAI,CAAC,QAAQ,CAAC,iBAAiB,IAAI,SAAS;AAC/D,gBAAA,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE;aAChC;AAED,YAAA,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,EAAG,EAAE,OAAO,CAAC,CAAC,SAAS,CAAC;gBACnD,IAAI,EAAE,MAAK;oBACT,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,yBAAyB,CAAC,CAAC;gBACnD,CAAC;AACD,gBAAA,KAAK,EAAE,CAAC,GAAG,KAAI;AACb,oBAAA,OAAO,CAAC,KAAK,CAAC,kCAAkC,EAAE,GAAG,CAAC;AACtD,oBAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,IAAI,iCAAiC,CAAC;AACrE,oBAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;gBACxB,CAAC;AACF,aAAA,CAAC;QACJ;IACF;IAEA,UAAU,GAAA;AACR,QAAA,IAAI,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,EAAE;YAAE;AAE5B,QAAA,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC;QACzB,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC;AACvC,YAAA,IAAI,EAAE,CAAC,MAAM,KAAK,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC;AAC7C,YAAA,KAAK,EAAE,MAAM,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,oBAAoB,EAAE,CAAC;AACpF,SAAA,CAAC;IACJ;wGAlNW,mCAAmC,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAnC,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,mCAAmC,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,oCAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EAhYpC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8XT,EAAA,QAAA,EAAA,IAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EA/XS,YAAY,8BAAE,WAAW,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,aAAA,EAAA,QAAA,EAAA,8CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,cAAA,EAAA,QAAA,EAAA,QAAA,EAAA,MAAA,EAAA,CAAA,SAAA,EAAA,OAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,uBAAA,EAAA,QAAA,EAAA,QAAA,EAAA,MAAA,EAAA,CAAA,SAAA,EAAA,OAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,oBAAA,EAAA,QAAA,EAAA,8MAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,4BAAA,EAAA,QAAA,EAAA,uGAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,0BAAA,EAAA,QAAA,EAAA,6GAAA,EAAA,MAAA,EAAA,CAAA,aAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,eAAA,EAAA,QAAA,EAAA,2CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,oBAAA,EAAA,QAAA,EAAA,sGAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,iBAAA,EAAA,QAAA,EAAA,wIAAA,EAAA,MAAA,EAAA,CAAA,UAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,OAAA,EAAA,QAAA,EAAA,qDAAA,EAAA,MAAA,EAAA,CAAA,MAAA,EAAA,UAAA,EAAA,SAAA,EAAA,gBAAA,CAAA,EAAA,OAAA,EAAA,CAAA,eAAA,CAAA,EAAA,QAAA,EAAA,CAAA,SAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,MAAA,EAAA,QAAA,EAAA,yEAAA,EAAA,MAAA,EAAA,CAAA,eAAA,CAAA,EAAA,OAAA,EAAA,CAAA,UAAA,CAAA,EAAA,QAAA,EAAA,CAAA,QAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAE,UAAU,EAAA,QAAA,EAAA,cAAA,EAAA,MAAA,EAAA,CAAA,QAAA,EAAA,aAAA,EAAA,UAAA,EAAA,qBAAA,EAAA,OAAA,EAAA,MAAA,EAAA,YAAA,EAAA,kBAAA,EAAA,oBAAA,EAAA,YAAA,EAAA,YAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAE,eAAe,qJAAE,aAAa,EAAA,QAAA,EAAA,SAAA,EAAA,MAAA,EAAA,CAAA,MAAA,EAAA,aAAA,CAAA,EAAA,CAAA,EAAA,CAAA;;4FAiYpE,mCAAmC,EAAA,UAAA,EAAA,CAAA;kBApY/C,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,oCAAoC;AAC9C,oBAAA,UAAU,EAAE,IAAI;oBAChB,OAAO,EAAE,CAAC,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,eAAe,EAAE,aAAa,CAAC;AAChF,oBAAA,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8XT,EAAA,CAAA;AACF,iBAAA;;;MCnBY,2BAA2B,CAAA;AACrB,IAAA,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC;IACjC,UAAU,GAAG,MAAM,CAAC,WAAW,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AAE5D,IAAA,OAAO,GAAG,MAAM,CAAC,IAAI,8EAAC;AACtB,IAAA,MAAM,GAAG,MAAM,CAAC,KAAK,6EAAC;AACtB,IAAA,KAAK,GAAG,MAAM,CAAgB,IAAI,4EAAC;AACnC,IAAA,OAAO,GAAG,MAAM,CAAgB,IAAI,8EAAC;AACrC,IAAA,UAAU,GAAG,MAAM,CAAC,KAAK,iFAAC;AAC1B,IAAA,OAAO,GAAG,MAAM,CAAqB,IAAI,8EAAC;AAC1C,IAAA,WAAW,GAAG,MAAM,CAA6B,IAAI,kFAAC;AACtD,IAAA,cAAc,GAAG,MAAM,CAA6B,IAAI,qFAAC;AACzD,IAAA,WAAW,GAAG,MAAM,CAAkC,IAAI,kFAAC;AAC3D,IAAA,MAAM,GAAG,MAAM,CAAgB,IAAI,6EAAC;AACpC,IAAA,iBAAiB,GAAG,MAAM,CAAC,KAAK,wFAAC;AACjC,IAAA,oBAAoB,GAAG,MAAM,CAAC,KAAK,2FAAC;AAE7C,IAAA,MAAM,GAAyB;AAC7B,QAAA,OAAO,EAAE,KAAK;AACd,QAAA,gBAAgB,EAAE,SAAS;KAC5B;IAED,eAAe,GAAG,EAAE;IACpB,kBAAkB,GAAG,EAAE;IAEvB,QAAQ,GAAA;QACN,IAAI,CAAC,QAAQ,EAAE;IACjB;IAEA,QAAQ,GAAA;AACN,QAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;AACtB,QAAA,QAAQ,CAAC;AACP,YAAA,MAAM,EAAE,IAAI,CAAC,WAAW,CAAC,mBAAmB,EAAE;YAC9C,OAAO,EAAE,IAAI,CAAC,WAAW,CAAC,UAAU,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;YACvE,WAAW,EAAE,IAAI,CAAC,WAAW,CAAC,qBAAqB,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;YACtF,cAAc,EAAE,IAAI,CAAC,WAAW,CAAC,wBAAwB,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;SAC7F,CAAC,CAAC,SAAS,CAAC;AACX,YAAA,IAAI,EAAE,CAAC,IAAI,KAAI;AACb,gBAAA,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM;gBACzB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC;gBAC9B,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC;gBACtC,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC;AAC5C,gBAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC;AACpB,gBAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC;YACzB,CAAC;AACD,YAAA,KAAK,EAAE,CAAC,GAAG,KAAI;AACb,gBAAA,OAAO,CAAC,KAAK,CAAC,gCAAgC,EAAE,GAAG,CAAC;AACpD,gBAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,uCAAuC,CAAC;AACvD,gBAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC;YACzB,CAAC;AACF,SAAA,CAAC;IACJ;IAEA,aAAa,GAAA;QACX,IAAI,CAAC,MAAM,CAAC,OAAO,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO;QAC1C,IAAI,CAAC,cAAc,EAAE;IACvB;IAEA,cAAc,GAAA;AACZ,QAAA,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC;AACzB,QAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;IACxB;IAEA,UAAU,GAAA;AACR,QAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC;AACrB,QAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC;QACpB,IAAI,CAAC,WAAW,CAAC,sBAAsB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC;YAC7D,IAAI,EAAE,MAAK;AACT,gBAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,sCAAsC,CAAC;AACxD,gBAAA,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC;AAC1B,gBAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;;AAEtB,gBAAA,IAAI,CAAC,WAAW,CAAC,UAAU,EAAE,CAAC,SAAS,CAAC;AACtC,oBAAA,IAAI,EAAE,CAAC,IAAI,KAAK,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;AACtC,oBAAA,KAAK,EAAE,MAAK,EAAE,CAAC;AAChB,iBAAA,CAAC;YACJ,CAAC;AACD,YAAA,KAAK,EAAE,CAAC,GAAG,KAAI;AACb,gBAAA,OAAO,CAAC,KAAK,CAAC,+BAA+B,EAAE,GAAG,CAAC;AACnD,gBAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,uCAAuC,CAAC;AACvD,gBAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;YACxB,CAAC;AACF,SAAA,CAAC;IACJ;;IAGA,mBAAmB,GAAA;AACjB,QAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC;AAC/B,QAAA,IAAI,CAAC,WAAW,CAAC,0BAA0B,EAAE,CAAC,SAAS,CAAC;AACtD,YAAA,IAAI,EAAE,CAAC,IAAI,KAAI;AACb,gBAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC;AAC1B,gBAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,4CAA4C,CAAC;AAC9D,gBAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC;YAC5B,CAAC;AACD,YAAA,KAAK,EAAE,CAAC,GAAG,KAAI;AACb,gBAAA,OAAO,CAAC,KAAK,CAAC,uCAAuC,EAAE,GAAG,CAAC;AAC3D,gBAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,wCAAwC,CAAC;AACxD,gBAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC;YAC5B,CAAC;AACF,SAAA,CAAC;IACJ;IAEA,gBAAgB,GAAA;AACd,QAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC;AAC/B,QAAA,IAAI,CAAC,WAAW,CAAC,uBAAuB,EAAE,CAAC,SAAS,CAAC;YACnD,IAAI,EAAE,MAAK;gBACT,IAAI,CAAC,gBAAgB,EAAE;AACvB,gBAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,qCAAqC,CAAC;AACvD,gBAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC;YAC5B,CAAC;AACD,YAAA,KAAK,EAAE,CAAC,GAAG,KAAI;AACb,gBAAA,OAAO,CAAC,KAAK,CAAC,sCAAsC,EAAE,GAAG,CAAC;AAC1D,gBAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,qCAAqC,CAAC;AACrD,gBAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC;YAC5B,CAAC;AACF,SAAA,CAAC;IACJ;IAEA,mBAAmB,GAAA;AACjB,QAAA,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AACxC,QAAA,IAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE,EAAE;AAC7B,YAAA,IAAI,CAAC,eAAe,GAAG,EAAE;QAC3B;IACF;AAEA,IAAA,mBAAmB,CAAC,KAAY,EAAA;AAC9B,QAAA,MAAM,KAAK,GAAG,KAAK,CAAC,MAA0B;QAC9C,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC;AAC7B,QAAA,IAAI,CAAC,IAAI;YAAE;AAEX,QAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC;AAC/B,QAAA,MAAM,MAAM,GAAG,IAAI,UAAU,EAAE;AAC/B,QAAA,MAAM,CAAC,MAAM,GAAG,MAAK;AACnB,YAAA,MAAM,WAAW,GAAG,MAAM,CAAC,MAAqB;AAChD,YAAA,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,WAAW,CAAC;AACzC,YAAA,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG,KAAK,CAAC,CAAC;AAElD,YAAA,IAAI,CAAC,WAAW,CAAC,wBAAwB,CAAC;AACxC,gBAAA,SAAS,EAAE,MAAM;AACjB,gBAAA,QAAQ,EAAE,IAAI,CAAC,eAAe,IAAI,SAAS;aAC5C,CAAC,CAAC,SAAS,CAAC;AACX,gBAAA,IAAI,EAAE,CAAC,IAAI,KAAI;AACb,oBAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC;AAC1B,oBAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,2CAA2C,CAAC;AAC7D,oBAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC;AAC1B,oBAAA,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,KAAK,CAAC;AACjC,oBAAA,IAAI,CAAC,eAAe,GAAG,EAAE;gBAC3B,CAAC;AACD,gBAAA,KAAK,EAAE,CAAC,GAAG,KAAI;AACb,oBAAA,OAAO,CAAC,KAAK,CAAC,sCAAsC,EAAE,GAAG,CAAC;AAC1D,oBAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,sCAAsC,CAAC;AACtD,oBAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC;gBAC5B,CAAC;AACF,aAAA,CAAC;AACJ,QAAA,CAAC;AACD,QAAA,MAAM,CAAC,iBAAiB,CAAC,IAAI,CAAC;AAC9B,QAAA,KAAK,CAAC,KAAK,GAAG,EAAE;IAClB;;IAGA,sBAAsB,GAAA;AACpB,QAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,YAAY,CAAC;AAClC,QAAA,IAAI,CAAC,WAAW,CAAC,6BAA6B,EAAE,CAAC,SAAS,CAAC;AACzD,YAAA,IAAI,EAAE,CAAC,IAAI,KAAI;AACb,gBAAA,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC;AAC7B,gBAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,+CAA+C,CAAC;AACjE,gBAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC;YAC5B,CAAC;AACD,YAAA,KAAK,EAAE,CAAC,GAAG,KAAI;AACb,gBAAA,OAAO,CAAC,KAAK,CAAC,0CAA0C,EAAE,GAAG,CAAC;AAC9D,gBAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,2CAA2C,CAAC;AAC3D,gBAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC;YAC5B,CAAC;AACF,SAAA,CAAC;IACJ;IAEA,mBAAmB,GAAA;AACjB,QAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,YAAY,CAAC;AAClC,QAAA,IAAI,CAAC,WAAW,CAAC,0BAA0B,EAAE,CAAC,SAAS,CAAC;YACtD,IAAI,EAAE,MAAK;gBACT,IAAI,CAAC,gBAAgB,EAAE;AACvB,gBAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,wCAAwC,CAAC;AAC1D,gBAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC;YAC5B,CAAC;AACD,YAAA,KAAK,EAAE,CAAC,GAAG,KAAI;AACb,gBAAA,OAAO,CAAC,KAAK,CAAC,yCAAyC,EAAE,GAAG,CAAC;AAC7D,gBAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,wCAAwC,CAAC;AACxD,gBAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC;YAC5B,CAAC;AACF,SAAA,CAAC;IACJ;IAEA,sBAAsB,GAAA;AACpB,QAAA,IAAI,CAAC,oBAAoB,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AAC3C,QAAA,IAAI,CAAC,IAAI,CAAC,oBAAoB,EAAE,EAAE;AAChC,YAAA,IAAI,CAAC,kBAAkB,GAAG,EAAE;QAC9B;IACF;AAEA,IAAA,sBAAsB,CAAC,KAAY,EAAA;AACjC,QAAA,MAAM,KAAK,GAAG,KAAK,CAAC,MAA0B;QAC9C,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC;AAC7B,QAAA,IAAI,CAAC,IAAI;YAAE;AAEX,QAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,YAAY,CAAC;AAClC,QAAA,MAAM,MAAM,GAAG,IAAI,UAAU,EAAE;AAC/B,QAAA,MAAM,CAAC,MAAM,GAAG,MAAK;AACnB,YAAA,MAAM,WAAW,GAAG,MAAM,CAAC,MAAqB;AAChD,YAAA,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,WAAW,CAAC;AACzC,YAAA,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG,KAAK,CAAC,CAAC;AAElD,YAAA,IAAI,CAAC,WAAW,CAAC,2BAA2B,CAAC;AAC3C,gBAAA,SAAS,EAAE,MAAM;AACjB,gBAAA,QAAQ,EAAE,IAAI,CAAC,kBAAkB,IAAI,SAAS;aAC/C,CAAC,CAAC,SAAS,CAAC;AACX,gBAAA,IAAI,EAAE,CAAC,IAAI,KAAI;AACb,oBAAA,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC;AAC7B,oBAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,8CAA8C,CAAC;AAChE,oBAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC;AAC1B,oBAAA,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,KAAK,CAAC;AACpC,oBAAA,IAAI,CAAC,kBAAkB,GAAG,EAAE;gBAC9B,CAAC;AACD,gBAAA,KAAK,EAAE,CAAC,GAAG,KAAI;AACb,oBAAA,OAAO,CAAC,KAAK,CAAC,yCAAyC,EAAE,GAAG,CAAC;AAC7D,oBAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,yCAAyC,CAAC;AACzD,oBAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC;gBAC5B,CAAC;AACF,aAAA,CAAC;AACJ,QAAA,CAAC;AACD,QAAA,MAAM,CAAC,iBAAiB,CAAC,IAAI,CAAC;AAC9B,QAAA,KAAK,CAAC,KAAK,GAAG,EAAE;IAClB;IAEQ,gBAAgB,GAAA;AACtB,QAAA,QAAQ,CAAC;YACP,OAAO,EAAE,IAAI,CAAC,WAAW,CAAC,qBAAqB,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;YAClF,UAAU,EAAE,IAAI,CAAC,WAAW,CAAC,wBAAwB,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;SACzF,CAAC,CAAC,SAAS,CAAC;AACX,YAAA,IAAI,EAAE,CAAC,IAAI,KAAI;gBACb,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC;gBAClC,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC;YAC1C,CAAC;AACD,YAAA,KAAK,EAAE,CAAC,GAAG,KAAI;AACb,gBAAA,OAAO,CAAC,KAAK,CAAC,6BAA6B,EAAE,GAAG,CAAC;YACnD,CAAC;AACF,SAAA,CAAC;IACJ;AAEA,IAAA,eAAe,CAAC,KAAa,EAAE,GAAG,GAAG,UAAU,EAAA;QAC7C,SAAS,CAAC,SAAS,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAK;AAC7C,YAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC;AACpB,YAAA,UAAU,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC;AAC/C,QAAA,CAAC,CAAC;IACJ;AAEA,IAAA,UAAU,CAAC,OAAgB,EAAA;AACzB,QAAA,IAAI,CAAC,OAAO;AAAE,YAAA,OAAO,KAAK;QAC1B,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC,kBAAkB,CAAC,SAAS,EAAE;AACrD,YAAA,IAAI,EAAE,SAAS;AACf,YAAA,KAAK,EAAE,OAAO;AACd,YAAA,GAAG,EAAE,SAAS;AACf,SAAA,CAAC;IACJ;AAEA,IAAA,kBAAkB,CAAC,UAAmB,EAAA;AACpC,QAAA,IAAI,CAAC,UAAU;AAAE,YAAA,OAAO,KAAK;QAC7B,OAAO,UAAU,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,KAAK;IAC5C;AAEA,IAAA,mBAAmB,CAAC,MAAc,EAAA;QAChC,QAAQ,MAAM;AACZ,YAAA,KAAK,QAAQ;AACX,gBAAA,OAAO,2BAA2B;AACpC,YAAA,KAAK,MAAM;AACT,gBAAA,OAAO,2BAA2B;AACpC,YAAA,KAAK,UAAU;AACb,gBAAA,OAAO,6BAA6B;AACtC,YAAA;AACE,gBAAA,OAAO,2BAA2B;;IAExC;AAEA,IAAA,kBAAkB,CAAC,MAAc,EAAA;QAC/B,QAAQ,MAAM;AACZ,YAAA,KAAK,MAAM;AACT,gBAAA,OAAO,gBAAgB;AACzB,YAAA;AACE,gBAAA,OAAO,MAAM;;IAEnB;wGAjSW,2BAA2B,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAA3B,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,2BAA2B,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,uBAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EA/Z5B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6ZT,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EA9ZS,YAAY,EAAA,EAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAE,WAAW,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,oBAAA,EAAA,QAAA,EAAA,8MAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,eAAA,EAAA,QAAA,EAAA,2CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,OAAA,EAAA,QAAA,EAAA,qDAAA,EAAA,MAAA,EAAA,CAAA,MAAA,EAAA,UAAA,EAAA,SAAA,EAAA,gBAAA,CAAA,EAAA,OAAA,EAAA,CAAA,eAAA,CAAA,EAAA,QAAA,EAAA,CAAA,SAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAE,eAAe,qJAAE,aAAa,EAAA,QAAA,EAAA,SAAA,EAAA,MAAA,EAAA,CAAA,MAAA,EAAA,aAAA,CAAA,EAAA,CAAA,EAAA,CAAA;;4FAgaxD,2BAA2B,EAAA,UAAA,EAAA,CAAA;kBAnavC,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,uBAAuB;AACjC,oBAAA,UAAU,EAAE,IAAI;oBAChB,OAAO,EAAE,CAAC,YAAY,EAAE,WAAW,EAAE,eAAe,EAAE,aAAa,CAAC;AACpE,oBAAA,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6ZT,EAAA,CAAA;AACF,iBAAA;;;ACraM,MAAM,WAAW,GAAW;AACjC,IAAA;AACE,QAAA,IAAI,EAAE,EAAE;AACR,QAAA,UAAU,EAAE,WAAW;AACvB,QAAA,SAAS,EAAE,MAAM;AAClB,KAAA;AACD,IAAA;AACE,QAAA,IAAI,EAAE,WAAW;AACjB,QAAA,SAAS,EAAE,sBAAsB;AAClC,KAAA;AACD,IAAA;AACE,QAAA,IAAI,EAAE,mBAAmB;AACzB,QAAA,SAAS,EAAE,6BAA6B;AACzC,KAAA;AACD,IAAA;AACE,QAAA,IAAI,EAAE,uBAAuB;AAC7B,QAAA,SAAS,EAAE,mCAAmC;AAC/C,KAAA;AACD,IAAA;AACE,QAAA,IAAI,EAAE,uBAAuB;AAC7B,QAAA,SAAS,EAAE,mCAAmC;AAC/C,KAAA;;;ACtBH;;;;;;;AAOG;AACI,MAAM,WAAW,GAAgB;AACtC,IAAA,IAAI,EAAE,YAAY;AAClB,IAAA,OAAO,EAAE,OAAO;;AAGhB,IAAA,MAAM,EAAE;AACN,QAAA;AACE,YAAA,IAAI,EAAE,MAAM;AACZ,YAAA,QAAQ,EAAE,WAAW;AACtB,SAAA;AACF,KAAA;AAED,IAAA,QAAQ,EAAE;AACR,QAAA;AACE,YAAA,EAAE,EAAE,MAAM;AACV,YAAA,KAAK,EAAE,MAAM;AACb,YAAA,IAAI,EAAE,OAAO;AACb,YAAA,IAAI,EAAE,cAAc;AACpB,YAAA,KAAK,EAAE,EAAE;AACT,YAAA,aAAa,EAAE,qBAAqB;AACpC,YAAA,QAAQ,EAAE;AACR,gBAAA,EAAE,KAAK,EAAE,gBAAgB,EAAE,IAAI,EAAE,iBAAiB,EAAE,IAAI,EAAE,cAAc,EAAE,UAAU,EAAE,WAAW,EAAE,KAAK,EAAE,EAAE,EAAE;AAC9G,gBAAA,EAAE,KAAK,EAAE,mBAAmB,EAAE,IAAI,EAAE,yBAAyB,EAAE,IAAI,EAAE,cAAc,EAAE,UAAU,EAAE,WAAW,EAAE,KAAK,EAAE,EAAE,EAAE;AAC1H,aAAA;AACS,SAAA;AACb,KAAA;AAED,IAAA,YAAY,EAAE;AACZ,QAAA;AACE,YAAA,EAAE,EAAE,UAAU;AACd,YAAA,KAAK,EAAE,UAAU;AACjB,YAAA,IAAI,EAAE,cAAc;AACpB,YAAA,SAAS,EAAE,2BAA2B;AACtC,YAAA,KAAK,EAAE,GAAG;AACX,SAAA;AACF,KAAA;;AAGH;;AAEG;SACa,eAAe,GAAA;AAC7B,IAAA,OAAO,WAAW,CAAC,QAAQ,IAAI,EAAE;AACnC;;ACvDA;;ACAA;;AAEG;;;;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,35 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@syndew/oluso-plugin-saml",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"
|
|
5
|
-
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"repository": {
|
|
5
|
+
"type": "git",
|
|
6
|
+
"url": "git+https://github.com/SyndewTech/Oluso.git",
|
|
7
|
+
"directory": "src/frontend/libs/plugins/saml"
|
|
8
|
+
},
|
|
9
|
+
"peerDependencies": {
|
|
10
|
+
"@angular/common": "^21.1.0",
|
|
11
|
+
"@angular/core": "^21.1.0",
|
|
12
|
+
"@syndew/oluso-admin-ui": "*",
|
|
13
|
+
"@syndew/oluso-ui-core": "*"
|
|
14
|
+
},
|
|
15
|
+
"sideEffects": false,
|
|
16
|
+
"publishConfig": {
|
|
17
|
+
"access": "public",
|
|
18
|
+
"registry": "https://registry.npmjs.org/"
|
|
19
|
+
},
|
|
20
|
+
"module": "fesm2022/syndew-oluso-plugin-saml.mjs",
|
|
21
|
+
"typings": "types/syndew-oluso-plugin-saml.d.ts",
|
|
22
|
+
"exports": {
|
|
23
|
+
"./package.json": {
|
|
24
|
+
"default": "./package.json"
|
|
25
|
+
},
|
|
26
|
+
".": {
|
|
27
|
+
"types": "./types/syndew-oluso-plugin-saml.d.ts",
|
|
28
|
+
"default": "./fesm2022/syndew-oluso-plugin-saml.mjs"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"type": "module",
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"tslib": "^2.3.0"
|
|
34
|
+
}
|
|
6
35
|
}
|