answer-perfect-form-component
Version:
A simple standalone Angular form question component that makes API calls on blur with AI-powered text cleanup - Updated for Angular 18.2.x compatibility
1 lines • 34.8 kB
Source Map (JSON)
{"version":3,"file":"answer-perfect-form-component.mjs","sources":["../../src/form-question.component.ts","../../src/answer-perfect-form-component.ts"],"sourcesContent":["import {\r\n Component,\r\n Input,\r\n OnInit,\r\n inject,\r\n OnDestroy,\r\n ElementRef,\r\n ViewChild,\r\n AfterViewInit,\r\n} from '@angular/core';\r\nimport { HttpClient, HttpHeaders } from '@angular/common/http';\r\nimport { CommonModule } from '@angular/common';\r\nimport { FormsModule } from '@angular/forms';\r\nimport { Subject } from 'rxjs';\r\nimport { takeUntil } from 'rxjs/operators';\r\n\r\n/**\r\n * Rating enum matching the backend\r\n */\r\nexport enum Rating {\r\n NoRating = 'No rating',\r\n Weak = 'Weak',\r\n Sufficient = 'Sufficient',\r\n Strong = 'Strong',\r\n}\r\n\r\n/**\r\n * Configuration interface for the FormQuestionComponent\r\n */\r\nexport interface FormQuestionConfig {\r\n /** API key for authentication */\r\n apiKey: string;\r\n /** Base URL of the API endpoint */\r\n endpoint: string;\r\n /** Unique identifier for the question */\r\n questionId: string;\r\n /** The answer text (handled internally) */\r\n answerText: string;\r\n}\r\n\r\n/**\r\n * API response interface for form submissions\r\n */\r\nexport interface ApiResponse {\r\n /** Whether the submission was successful */\r\n success: boolean;\r\n /** Optional error message */\r\n error?: string;\r\n /** AI feedback text */\r\n feedbackText?: string;\r\n /** AI rating */\r\n rating?: Rating;\r\n}\r\n\r\n@Component({\r\n selector: 'app-form-question',\r\n template: `\r\n <div class=\"form-question-container\">\r\n <!-- Hidden audio element for streaming audio -->\r\n <audio #hoverAudio preload=\"none\"></audio>\r\n\r\n <div class=\"form-field\">\r\n <div class=\"textarea-container\">\r\n <textarea\r\n id=\"answer-textarea\"\r\n [(ngModel)]=\"answerText\"\r\n (blur)=\"onBlur()\"\r\n (input)=\"onInput()\"\r\n rows=\"3\"\r\n placeholder=\"Type your answer here...\"\r\n class=\"answer-textarea\"\r\n >\r\n </textarea>\r\n\r\n <!-- Rating bar - always visible (shows branding when empty, rating when has content) -->\r\n <div class=\"rating-container\">\r\n <!-- Edit icon for text cleanup -->\r\n <button\r\n *ngIf=\"!isCleaning\"\r\n class=\"edit-icon\"\r\n [class.disabled]=\"!answerText.trim()\"\r\n (click)=\"cleanupText()\"\r\n [title]=\"\r\n answerText.trim()\r\n ? 'Fix spelling and grammar with AI'\r\n : 'Add text to enable AI editing'\r\n \"\r\n >\r\n ✏️\r\n </button>\r\n <div\r\n *ngIf=\"isCleaning\"\r\n class=\"cleaning-spinner\"\r\n title=\"AI is fixing your text...\"\r\n >\r\n ✨\r\n </div>\r\n <div\r\n class=\"feedback-bar\"\r\n (mouseenter)=\"onRatingBarHover()\"\r\n (mouseleave)=\"onRatingBarLeave()\"\r\n [ngClass]=\"{\r\n outline:\r\n !rating || rating === 'No rating' || !answerText.trim(),\r\n weak:\r\n rating === 'Weak' &&\r\n answerText.trim() &&\r\n !isTyping &&\r\n !isSubmitting,\r\n sufficient:\r\n rating === 'Sufficient' &&\r\n answerText.trim() &&\r\n !isTyping &&\r\n !isSubmitting,\r\n strong:\r\n rating === 'Strong' &&\r\n answerText.trim() &&\r\n !isTyping &&\r\n !isSubmitting,\r\n noRating:\r\n rating === 'No rating' &&\r\n answerText.trim() &&\r\n !isTyping &&\r\n !isSubmitting,\r\n branding: !answerText.trim(),\r\n typing: (isTyping || isSubmitting) && answerText.trim(),\r\n error: errorMessage && answerText.trim()\r\n }\"\r\n >\r\n <span\r\n class=\"rating-label\"\r\n *ngIf=\"\r\n answerText.trim() &&\r\n rating &&\r\n !isTyping &&\r\n !isSubmitting &&\r\n !errorMessage\r\n \"\r\n >{{ rating }}</span\r\n >\r\n <span\r\n class=\"typing-label\"\r\n *ngIf=\"\r\n answerText.trim() &&\r\n (isTyping || isSubmitting) &&\r\n !errorMessage\r\n \"\r\n ><span class=\"dot1\">.</span><span class=\"dot2\">.</span\r\n ><span class=\"dot3\">.</span></span\r\n >\r\n <span\r\n class=\"error-label\"\r\n *ngIf=\"answerText.trim() && errorMessage\"\r\n >Error</span\r\n >\r\n <span class=\"branding-label\" *ngIf=\"!answerText.trim()\"\r\n >AnswerPerfect AI\r\n <!-- Branding tooltip -->\r\n <div class=\"branding-tooltip\">\r\n AI-powered feedback to help you write better answers\r\n </div>\r\n </span>\r\n <!-- Tooltip feedback text on hover (only show if feedback exists) -->\r\n <div\r\n class=\"feedback-tooltip\"\r\n *ngIf=\"feedbackText && answerText.trim()\"\r\n >\r\n {{ feedbackText }}\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n `,\r\n styles: [\r\n `\r\n .form-question-container {\r\n margin-bottom: 1rem;\r\n }\r\n\r\n .form-field {\r\n display: flex;\r\n flex-direction: column;\r\n margin-bottom: 0.5rem;\r\n }\r\n\r\n .textarea-container {\r\n position: relative;\r\n display: block;\r\n }\r\n\r\n .answer-textarea {\r\n width: 100%;\r\n padding: 0.75rem;\r\n border: 1px solid #ccc;\r\n border-radius: 4px;\r\n font-family: inherit;\r\n font-size: 1rem;\r\n resize: vertical;\r\n min-height: 80px;\r\n }\r\n\r\n .answer-textarea:focus {\r\n outline: none;\r\n border-color: #1976d2;\r\n box-shadow: 0 0 0 2px rgba(25, 118, 210, 0.2);\r\n }\r\n\r\n .rating-container {\r\n display: flex;\r\n justify-content: flex-end;\r\n align-items: center;\r\n gap: 8px;\r\n margin-top: 8px;\r\n position: relative;\r\n }\r\n\r\n .edit-icon {\r\n background: none;\r\n border: none;\r\n cursor: pointer;\r\n font-size: 16px;\r\n padding: 4px;\r\n border-radius: 4px;\r\n transition: background-color 0.2s ease;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n min-width: 24px;\r\n height: 24px;\r\n }\r\n\r\n .edit-icon:hover {\r\n background-color: rgba(0, 0, 0, 0.1);\r\n }\r\n\r\n .edit-icon.disabled {\r\n opacity: 0.3;\r\n cursor: not-allowed;\r\n pointer-events: none;\r\n }\r\n\r\n .edit-icon.disabled:hover {\r\n background-color: transparent;\r\n }\r\n\r\n .cleaning-spinner {\r\n font-size: 16px;\r\n animation: spin 1s linear infinite;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n min-width: 24px;\r\n height: 24px;\r\n }\r\n\r\n @keyframes spin {\r\n from {\r\n transform: rotate(0deg);\r\n }\r\n to {\r\n transform: rotate(360deg);\r\n }\r\n }\r\n\r\n .feedback-bar {\r\n height: 20px;\r\n width: 120px;\r\n background: #e0e0e0;\r\n border-radius: 9px;\r\n position: relative;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n cursor: pointer;\r\n transition: transform 0.2s ease;\r\n }\r\n\r\n .feedback-bar:hover {\r\n transform: scale(1.05);\r\n }\r\n\r\n .feedback-bar::before {\r\n content: '';\r\n position: absolute;\r\n left: 0;\r\n top: 0;\r\n height: 100%;\r\n transition: width 0.6s ease-in-out;\r\n border-radius: 9px;\r\n }\r\n\r\n .feedback-bar.weak::before {\r\n background: linear-gradient(to right, #ff6b6b, #ff8e8e);\r\n width: 33%;\r\n }\r\n\r\n .feedback-bar.sufficient::before {\r\n background: linear-gradient(to right, #ffd93d, #ffe066);\r\n width: 66%;\r\n }\r\n\r\n .feedback-bar.strong::before {\r\n background: linear-gradient(to right, #6bcf7f, #8ed99e);\r\n width: 100%;\r\n }\r\n\r\n .feedback-bar.outline::before {\r\n background: transparent;\r\n width: 0%;\r\n }\r\n\r\n .feedback-bar.noRating::before {\r\n background: linear-gradient(to right, #9e9e9e, #bdbdbd);\r\n width: 0%;\r\n }\r\n .feedback-bar.error::before {\r\n background: linear-gradient(to right, #f44336, #ef5350);\r\n width: 100%;\r\n }\r\n\r\n .rating-label {\r\n font-weight: 600;\r\n font-size: 11px;\r\n text-align: center;\r\n color: #333;\r\n text-shadow: 0 1px 2px rgba(255, 255, 255, 0.8);\r\n z-index: 1;\r\n position: relative;\r\n }\r\n\r\n .branding-label {\r\n font-weight: 600;\r\n font-size: 10px;\r\n text-align: center;\r\n color: #666;\r\n z-index: 1;\r\n position: relative;\r\n letter-spacing: 0.5px;\r\n cursor: pointer;\r\n }\r\n\r\n .branding-tooltip {\r\n position: absolute;\r\n bottom: 100%;\r\n right: 0;\r\n background: #333;\r\n color: white;\r\n padding: 12px 16px;\r\n border-radius: 8px;\r\n font-size: 12px;\r\n opacity: 0;\r\n visibility: hidden;\r\n transition: opacity 0.3s ease, visibility 0.3s ease;\r\n z-index: 1000;\r\n margin-bottom: 8px;\r\n width: 280px;\r\n white-space: normal;\r\n line-height: 1.4;\r\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);\r\n font-weight: 500;\r\n letter-spacing: normal;\r\n }\r\n\r\n .branding-tooltip::after {\r\n content: '';\r\n position: absolute;\r\n top: 100%;\r\n right: 20px;\r\n border: 5px solid transparent;\r\n border-top-color: #333;\r\n }\r\n\r\n .branding-label:hover .branding-tooltip {\r\n opacity: 1;\r\n visibility: visible;\r\n }\r\n\r\n .feedback-tooltip {\r\n position: absolute;\r\n bottom: 100%;\r\n right: 0;\r\n transform: translateX(0);\r\n background: #333;\r\n color: white;\r\n padding: 18px 24px;\r\n border-radius: 10px;\r\n font-size: 14px;\r\n opacity: 0;\r\n visibility: hidden;\r\n transition: opacity 0.3s ease, visibility 0.3s ease;\r\n z-index: 1000;\r\n margin-bottom: 12px;\r\n width: 450px;\r\n white-space: normal;\r\n line-height: 1.6;\r\n box-shadow: 0 6px 20px rgba(0, 0, 0, 0.2);\r\n }\r\n\r\n .feedback-tooltip::after {\r\n content: '';\r\n position: absolute;\r\n top: 100%;\r\n right: 20px;\r\n border: 6px solid transparent;\r\n border-top-color: #333;\r\n }\r\n\r\n .typing-label {\r\n font-weight: 700;\r\n font-size: 14px;\r\n text-align: center;\r\n color: #222;\r\n z-index: 1;\r\n position: relative;\r\n display: flex;\r\n justify-content: center;\r\n gap: 2px;\r\n }\r\n\r\n .typing-label .dot1,\r\n .typing-label .dot2,\r\n .typing-label .dot3 {\r\n animation: typing-pulse 1.2s infinite;\r\n }\r\n\r\n .typing-label .dot1 {\r\n animation-delay: 0s;\r\n }\r\n\r\n .typing-label .dot2 {\r\n animation-delay: 0.15s;\r\n }\r\n\r\n .typing-label .dot3 {\r\n animation-delay: 0.3s;\r\n }\r\n\r\n .feedback-bar.typing::before {\r\n background: #e0e0e0;\r\n width: 0%;\r\n }\r\n\r\n @keyframes typing-pulse {\r\n 0%,\r\n 70%,\r\n 100% {\r\n opacity: 0.2;\r\n transform: scale(0.8);\r\n }\r\n 35% {\r\n opacity: 1;\r\n transform: scale(1.4);\r\n }\r\n }\r\n\r\n .error-label {\r\n font-weight: 600;\r\n font-size: 11px;\r\n text-align: center;\r\n color: #333;\r\n text-shadow: 0 1px 2px rgba(255, 255, 255, 0.8);\r\n z-index: 1;\r\n position: relative;\r\n }\r\n\r\n .feedback-bar:hover .feedback-tooltip {\r\n opacity: 1;\r\n visibility: visible;\r\n }\r\n\r\n .error-message {\r\n color: #f44336;\r\n font-size: 0.875rem;\r\n margin-top: 0.25rem;\r\n }\r\n `,\r\n ],\r\n standalone: true,\r\n imports: [CommonModule, FormsModule],\r\n})\r\n/**\r\n * A reusable Angular component that provides a textarea input for answering questions.\r\n * Automatically submits answers to an AI evaluation API when the user stops typing.\r\n * Displays AI feedback in a tooltip on hover over the rating bar.\r\n * Streams audio of the feedback text when hovering over the rating bar (configurable).\r\n */\r\nexport class FormQuestionComponent implements OnInit, OnDestroy, AfterViewInit {\r\n private readonly http = inject(HttpClient);\r\n\r\n /** API key for authentication with the backend */\r\n @Input() apiKey!: string;\r\n\r\n /** Base URL of the API endpoint (e.g., \"https://your-api.com/api\") */\r\n @Input() endpoint!: string;\r\n\r\n /** Unique identifier for the question */\r\n @Input() questionId!: string;\r\n\r\n /** Whether to enable audio feedback on hover (default: true) */\r\n @Input() enableAudio: boolean = true;\r\n\r\n /** Reference to the audio element for hover sounds */\r\n @ViewChild('hoverAudio', { static: false })\r\n hoverAudio!: ElementRef<HTMLAudioElement>;\r\n\r\n answerText: string = '';\r\n isSubmitting: boolean = false;\r\n errorMessage: string = '';\r\n feedbackText: string = '';\r\n rating: Rating | null = null;\r\n isTyping: boolean = false;\r\n isCleaning: boolean = false;\r\n\r\n private debounceTimeout: any = null;\r\n private cancelRequest$ = new Subject<void>();\r\n private currentAudioUrl: string | null = null;\r\n private currentAudioRequest$ = new Subject<void>();\r\n\r\n ngOnInit() {\r\n // Validate required inputs\r\n if (!this.apiKey || !this.endpoint || !this.questionId) {\r\n console.error('FormQuestionComponent: Missing required inputs');\r\n }\r\n\r\n console.log('FormQuestionComponent initialized');\r\n console.log('enableAudio:', this.enableAudio);\r\n }\r\n\r\n ngAfterViewInit() {\r\n console.log('View initialized, hoverAudio element:', this.hoverAudio);\r\n if (this.hoverAudio && this.hoverAudio.nativeElement) {\r\n console.log('Audio element is available and ready');\r\n } else {\r\n console.warn('Audio element not found or not ready');\r\n }\r\n }\r\n\r\n ngOnDestroy() {\r\n this.clearDebounceTimeout();\r\n this.cancelRequest$.next();\r\n this.cancelRequest$.complete();\r\n this.currentAudioRequest$.next();\r\n this.currentAudioRequest$.complete();\r\n\r\n // Clean up any existing audio blob URL\r\n if (this.currentAudioUrl) {\r\n URL.revokeObjectURL(this.currentAudioUrl);\r\n this.currentAudioUrl = null;\r\n }\r\n }\r\n\r\n /**\r\n * Play streaming audio when mouse enters the rating bar\r\n */\r\n onRatingBarHover() {\r\n console.log('Rating bar hover detected');\r\n console.log('enableAudio:', this.enableAudio);\r\n console.log('feedbackText:', this.feedbackText);\r\n console.log('feedbackText.trim():', this.feedbackText?.trim());\r\n console.log('hoverAudio:', this.hoverAudio);\r\n console.log('hoverAudio.nativeElement:', this.hoverAudio?.nativeElement);\r\n\r\n // Wait for audio element to be available if it's not ready yet\r\n if (!this.hoverAudio || !this.hoverAudio.nativeElement) {\r\n console.log('Audio element not ready, waiting...');\r\n setTimeout(() => {\r\n this.onRatingBarHover();\r\n }, 100);\r\n return;\r\n }\r\n\r\n if (\r\n this.enableAudio &&\r\n this.feedbackText &&\r\n this.feedbackText.trim() &&\r\n this.hoverAudio &&\r\n this.hoverAudio.nativeElement\r\n ) {\r\n console.log('All conditions met, calling playFeedbackAudio');\r\n this.playFeedbackAudio(this.feedbackText);\r\n } else {\r\n console.log('Conditions not met for audio playback');\r\n if (!this.enableAudio) console.log('Audio disabled');\r\n if (!this.feedbackText) console.log('No feedback text');\r\n if (!this.feedbackText?.trim()) console.log('Feedback text is empty');\r\n if (!this.hoverAudio) console.log('No hover audio element');\r\n if (!this.hoverAudio?.nativeElement)\r\n console.log('No hover audio native element');\r\n }\r\n }\r\n\r\n /**\r\n * Stop audio when mouse leaves the rating bar\r\n */\r\n onRatingBarLeave() {\r\n console.log('Rating bar leave detected');\r\n if (this.enableAudio && this.hoverAudio && this.hoverAudio.nativeElement) {\r\n // Cancel any ongoing audio request\r\n this.currentAudioRequest$.next();\r\n\r\n // Pause and reset audio\r\n this.hoverAudio.nativeElement.pause();\r\n this.hoverAudio.nativeElement.currentTime = 0;\r\n\r\n // Clean up the current audio blob URL\r\n if (this.currentAudioUrl) {\r\n URL.revokeObjectURL(this.currentAudioUrl);\r\n this.currentAudioUrl = null;\r\n }\r\n } else {\r\n console.log('Cannot stop audio - conditions not met');\r\n }\r\n }\r\n\r\n /**\r\n * Play streaming audio for the given feedback text\r\n */\r\n private playFeedbackAudio(feedbackText: string) {\r\n console.log('playFeedbackAudio called with:', feedbackText);\r\n console.log('endpoint:', this.endpoint);\r\n console.log('apiKey:', this.apiKey ? 'Present' : 'Missing');\r\n\r\n if (!this.hoverAudio || !this.hoverAudio.nativeElement) {\r\n console.log('Audio element not available');\r\n return;\r\n }\r\n\r\n const headers = new HttpHeaders({\r\n 'Content-Type': 'application/json',\r\n Authorization: `Bearer ${this.apiKey}`,\r\n });\r\n\r\n const payload = {\r\n textToSpeak: feedbackText,\r\n };\r\n\r\n console.log('Making API call to:', `${this.endpoint}/audio/stream`);\r\n console.log('Payload:', payload);\r\n\r\n // Create a blob URL from the streaming audio response\r\n this.http\r\n .post(`${this.endpoint}/audio/stream`, payload, {\r\n headers,\r\n responseType: 'blob',\r\n })\r\n .pipe(takeUntil(this.currentAudioRequest$))\r\n .subscribe({\r\n next: (blob: Blob) => {\r\n console.log('Audio stream received, blob size:', blob.size);\r\n // Clean up previous audio URL if it exists\r\n if (this.currentAudioUrl) {\r\n URL.revokeObjectURL(this.currentAudioUrl);\r\n }\r\n\r\n const audioUrl = URL.createObjectURL(blob);\r\n this.currentAudioUrl = audioUrl;\r\n this.hoverAudio.nativeElement.src = audioUrl;\r\n this.hoverAudio.nativeElement.play().catch((error) => {\r\n console.warn('Could not play feedback audio:', error);\r\n });\r\n },\r\n error: (error: any) => {\r\n console.warn('Could not stream feedback audio:', error);\r\n },\r\n });\r\n }\r\n\r\n onBlur() {\r\n // Just clear typing state when focus is lost, no immediate submission\r\n this.isTyping = false;\r\n }\r\n\r\n onInput() {\r\n // Clear any existing timer and cancel ongoing API requests\r\n this.clearDebounceTimeout();\r\n this.cancelRequest$.next();\r\n\r\n // Set typing state\r\n this.isTyping = true;\r\n\r\n // Clear feedback when user deletes all text\r\n if (!this.answerText.trim()) {\r\n this.feedbackText = '';\r\n this.rating = null;\r\n this.isTyping = false;\r\n return;\r\n }\r\n\r\n // Single timer: 2 seconds after user stops typing\r\n this.debounceTimeout = setTimeout(() => {\r\n this.isTyping = false;\r\n\r\n if (this.answerText.trim() && !this.isSubmitting) {\r\n // Clear old rating before submitting for new one\r\n this.feedbackText = '';\r\n this.rating = null;\r\n this.submitAnswer();\r\n }\r\n }, 2000);\r\n }\r\n\r\n private clearDebounceTimeout() {\r\n if (this.debounceTimeout) {\r\n clearTimeout(this.debounceTimeout);\r\n this.debounceTimeout = null;\r\n }\r\n }\r\n\r\n private submitAnswer() {\r\n // Clear timer when submitting\r\n this.clearDebounceTimeout();\r\n\r\n this.isSubmitting = true;\r\n this.errorMessage = '';\r\n\r\n const headers = new HttpHeaders({\r\n 'Content-Type': 'application/json',\r\n Authorization: `Bearer ${this.apiKey}`,\r\n });\r\n\r\n const payload = {\r\n questionId: this.questionId,\r\n answerText: this.answerText.trim(),\r\n };\r\n\r\n this.http\r\n .post<ApiResponse>(`${this.endpoint}/submitAnswer`, payload, { headers })\r\n .pipe(takeUntil(this.cancelRequest$))\r\n .subscribe({\r\n next: (response: ApiResponse) => {\r\n this.isSubmitting = false;\r\n\r\n // Display feedback and rating from AI\r\n if (response.feedbackText) {\r\n this.feedbackText = response.feedbackText;\r\n console.log('Feedback text received:', this.feedbackText);\r\n }\r\n if (response.rating) {\r\n this.rating = response.rating;\r\n console.log('Rating received:', this.rating);\r\n }\r\n },\r\n error: (error: any) => {\r\n this.isSubmitting = false;\r\n\r\n // Clear any existing rating/feedback and show error in rating bar\r\n this.feedbackText = '';\r\n this.rating = null;\r\n this.errorMessage = 'Connection error';\r\n\r\n // Clear error message after 3 seconds and clear text to show branding\r\n setTimeout(() => {\r\n this.errorMessage = '';\r\n this.answerText = ''; // Clear text to revert to AnswerPerfect AI branding\r\n }, 3000);\r\n },\r\n });\r\n }\r\n\r\n cleanupText() {\r\n if (!this.answerText.trim() || this.isCleaning) {\r\n return;\r\n }\r\n\r\n this.isCleaning = true;\r\n\r\n const headers = new HttpHeaders({\r\n 'Content-Type': 'application/json',\r\n Authorization: `Bearer ${this.apiKey}`,\r\n });\r\n\r\n const payload = {\r\n text: this.answerText.trim(),\r\n };\r\n\r\n this.http\r\n .post<{ success: boolean; cleanedText?: string; error?: string }>(\r\n `${this.endpoint}/cleanupText`,\r\n payload,\r\n { headers }\r\n )\r\n .pipe(takeUntil(this.cancelRequest$))\r\n .subscribe({\r\n next: (response) => {\r\n this.isCleaning = false;\r\n if (response.success && response.cleanedText) {\r\n this.answerText = response.cleanedText;\r\n // The text change will automatically trigger onInput() via ngModel\r\n }\r\n },\r\n error: (error: any) => {\r\n this.isCleaning = false;\r\n console.error('Text cleanup failed:', error);\r\n },\r\n });\r\n }\r\n}\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}