mdas-jsview-sdk 1.0.13-uat.0 → 1.0.14-uat.0

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.
@@ -1,4 +1,4 @@
1
- !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).MdasSDK={})}(this,(function(t){"use strict";class e{constructor(){this.state=new Map,this.listeners=new Map}setState(t,e){this.state.set(t,e),this.notifyListeners(t,e)}getState(t){return this.state.get(t)}subscribe(t,e){return this.listeners.has(t)||this.listeners.set(t,new Set),this.listeners.get(t).add(e),()=>{const n=this.listeners.get(t);n&&n.delete(e)}}notifyListeners(t,e){const n=this.listeners.get(t);n&&n.forEach((t=>t(e)))}clear(){this.state.clear(),this.listeners.clear()}}class n{constructor(t,e,n){this.setContainer(t),this.options=e,this.widgetId=n,this.isDestroyed=!1,this.lastData=null,this.lastDataTimestamp=null,this.connectionQuality="disconnected",this.eventListeners=[],this.timeouts=[],this.intervals=[]}setContainer(t){if(!t)throw new Error("DOM element is required for widget");if("string"==typeof t){const e=document.querySelector(t);if(!e)throw new Error(`Element not found: ${t}`);this.container=e}else{if(t.nodeType!==Node.ELEMENT_NODE)throw new Error("Invalid element provided to widget");this.container=t}}showLoading(){const t=this.container.querySelector(".widget-loading-overlay");t&&t.classList.remove("hidden")}hideLoading(){const t=this.container.querySelector(".widget-loading-overlay");t&&t.classList.add("hidden")}showError(t){this.hideLoading(),this.clearError();const e=document.createElement("div");e.className="widget-error",e.textContent=`Error: ${t}`,this.container.appendChild(e)}clearError(){const t=this.container.querySelector(".widget-error");t&&t.remove()}showConnectionQuality(){const t=this.container.querySelector(".connection-quality");if(t&&t.remove(),"live"===this.connectionQuality)return;const e=this.container.querySelector('.last-update, [class*="last-update"], [class*="timestamp"]');if(e){const t=document.createElement("span");switch(t.className="connection-quality",this.connectionQuality){case"offline":t.textContent=" (disconnected)",t.style.color="#dc2626",t.style.fontWeight="500";break;case"reconnecting":t.textContent=" (reconnecting...)",t.style.color="#d97706"}t.style.fontSize="11px",e.appendChild(t)}}handleMessage(t){if(!this.isDestroyed)try{const{event:e,data:n}=t;if(console.log("[BaseWidget] handleMessage called with event:",e,"data:",n),this.debug&&console.log(`[${this.type}] Received:`,e,n),"connection"===e)return void this.handleConnectionStatus(n);if("data"===e)return console.log("[BaseWidget] Caching live data"),this.lastData=n,this.lastDataTimestamp=Date.now(),this.connectionQuality="live",void this.handleData(n);if("session_revoked"===e)return void this.handleSessionRevoked(n);this.handleCustomEvent&&this.handleCustomEvent(e,n)}catch(t){console.error(`[${this.constructor.name}] Error handling message:`,t),this.showError("Error processing data")}}handleSessionRevoked(t){"attempting_relogin"===t.status?(this.connectionQuality="reconnecting",this.lastData?this.showCachedData():this.showLoading()):"relogin_failed"===t.status?(this.connectionQuality="offline",this.showError(t.error||"Session expired. Please refresh the page.")):"relogin_successful"===t.status&&(this.connectionQuality="live",this.hideLoading(),this.clearError())}handleData(t){throw new Error("handleData must be implemented by child widget")}handleConnectionStatus(t){"connected"===t.status?(this.connectionQuality="live",this.clearError(),this.hideLoading()):"reconnecting"===t.status?(this.connectionQuality="reconnecting",this.lastData?this.showCachedData():this.showLoading()):"disconnected"===t.status?(this.connectionQuality="offline",this.lastData?this.showCachedData():this.hideLoading()):"failed"===t.status?(this.connectionQuality="offline",this.handleConnectionFailed(t),this.showConnectionQuality()):"error"===t.status&&(this.connectionQuality="offline",this.lastData?this.showCachedData():this.hideLoading())}showCachedData(){if(this.lastData&&this.lastDataTimestamp){const t=Date.now()-this.lastDataTimestamp,e=t>3e5,n={...this.lastData,_cached:!0,_cacheAge:t,_isStale:e,_quality:this.connectionQuality};this.handleData(n)}}addEventListener(t,e,n){let i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{};t&&e&&n?(t.addEventListener(e,n,i),this.eventListeners.push({element:t,event:e,handler:n,options:i})):console.warn("[BaseWidget] Invalid addEventListener parameters")}setTimeout(t,e){const n=setTimeout(t,e);return this.timeouts.push(n),n}setInterval(t,e){const n=setInterval(t,e);return this.intervals.push(n),n}clearTimeout(t){clearTimeout(t);const e=this.timeouts.indexOf(t);e>-1&&this.timeouts.splice(e,1)}clearInterval(t){clearInterval(t);const e=this.intervals.indexOf(t);e>-1&&this.intervals.splice(e,1)}showInputError(t,e){if(!t)return;this.clearInputError(t);const n=document.createElement("div");n.className="input-error-message",n.textContent=e,n.style.cssText="\n color: #dc2626;\n font-size: 12px;\n margin-top: 4px;\n animation: slideDown 0.2s ease-out;\n ",t.classList.add("input-error"),t.style.borderColor="#dc2626",t.parentNode&&t.parentNode.insertBefore(n,t.nextSibling),t.errorElement=n}clearInputError(t){t&&(t.errorElement&&(t.errorElement.remove(),t.errorElement=null),t.classList.remove("input-error"),t.style.borderColor="")}destroy(){this.isDestroyed||(this.isDestroyed=!0,this.eventListeners.forEach((t=>{let{element:e,event:n,handler:i,options:s}=t;try{e.removeEventListener(n,i,s)}catch(t){console.error("[BaseWidget] Error removing event listener:",t)}})),this.eventListeners=[],this.timeouts.forEach((t=>{clearTimeout(t)})),this.timeouts=[],this.intervals.forEach((t=>{clearInterval(t)})),this.intervals=[],this.lastData=null,this.container&&(this.container.innerHTML=""),this.debug&&console.log(`[${this.constructor.name}] Widget destroyed and cleaned up`))}handleConnectionFailed(t){this.connectionQuality="offline",this.lastData?(this.showCachedData(),this.hideLoading()):this.hideLoading(),this.debug&&console.log(`[${this.constructor.name}] Connection failed after ${t.maxAttempts} attempts`)}}class i{constructor(){let t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};this.symbol=t.Symbol||"",this.companyName=t.CompName||"",this.companyDescription=t.CompDesc||"",this.instrumentType=t.InstrType||"",this.lastPrice=t.LastPx||0,this.previousClose=t.YestClosePx||0,this.open=t.OpenPx||0,this.high=t.HighPx||0,this.low=t.LowPx||0,this.close=t.ClosingPx||0,this.change=t.Change||0,this.changePercent=t.ChangePercent||0,this.vwap=t.VWAP||0,this.volume=t.Volume||0,this.averageVolume=t.AvgVol30d||0,this.yesterdayVolume=t.YesterdayTradeVolume||0,this.bidPrice=t.BidPx||0,this.bidSize=t.BidSz||0,this.bidExchange=t.BidExch||"",this.askPrice=t.AskPx||0,this.askSize=t.AskSz||0,this.askExchange=t.AskExch||"",this.issueMarket=t.IssueMarket||"",this.marketName=t.MarketName||"",this.marketDescription=t.MarketDesc||"",this.mic=t.MIC||"",this.countryCode=t.CountryCode||"",this.timeZone=t.TimeZone||"",this.tradePrice=t.TradePx||0,this.tradeSize=t.TradeSz||0,this.tradeCondition=t.Condition||0,this.tradeTime=t.TradeTime||"",this.tradeRegion=t.TradeRegion||"",this.tradeRegionName=t.TradeRegionName||"",this.preMarketPrice=t.PreLastPx||0,this.preMarketTradeTime=t.PreTradeTime||"",this.postMarketPrice=t.PostLastPx||0,this.postMarketTradeTime=t.PostTradeTime||"",this.high52Week=t.High52wPx||0,this.low52Week=t.Low52wPx||0,this.high52WeekDate=t.High52wDate||"",this.low52WeekDate=t.Low52wDate||"",this.calendarYearHigh=t.CalendarYearHigh||0,this.calendarYearLow=t.CalendarYearLow||0,this.calendarYearHighDate=t.CalendarYearHighDate||"",this.calendarYearLowDate=t.CalendarYearLowDate||"",this.marketCap=t.MktCap||0,this.peRatio=t.PeRatio||0,this.beta=t.FundBeta||0,this.sharesOutstanding=t.ComShrsOut||0,this.dividendYield=t.DivYield||0,this.dividendAmount=t.DivAmt||0,this.dividendRate=t.DividendRate||0,this.dividendPaymentDate=t.DividendPaymentDate||t.PayDate||"",this.dividendExDate=t.DividendExDate||t.DivDateEx||"",this.isin=t.ISIN||"",this.cusip=t.CUSIP||"",this.sedol=t.SEDOL||"",this.gics=t.GICS||"",this.status=t.Status||"",this.dataSource=t.DataSource||"",this.quoteTime=t.QuoteTime||"",this.infoTime=t.InfoTime||""}get openPrice(){return this.open}get description(){return this.companyDescription}get lastUpdate(){return this.quoteTime||this.infoTime}getSecurityType(){return{257:"Stock",262:"ETF",261:"Mutual Fund",258:"Bond",260:"Option",263:"Future",259:"Index"}[this.instrumentType]||"Stock"}getPriceChange(){return this.change}getPriceChangePercent(){return 100*this.changePercent}getDataSource(){return"delay"===this.dataSource.toLowerCase()?"20 mins delayed":"real-time"===this.dataSource.toLowerCase()?"Real-time":null!==this.dataSource&&""!==this.dataSource?this.dataSource:"MDAS Server"}getCurrentPrice(){return this.lastPrice}get52WeekRange(){return`${this.low52Week.toFixed(2)} - ${this.high52Week.toFixed(2)}`}getMarketCapFormatted(){return this.formatMarketCap()}formatPrice(){return`$${(arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.lastPrice).toFixed(2)}`}formatPriceChange(){const t=this.getPriceChange();return`${t>=0?"+":""} ${t.toFixed(2)}`}formatPriceChangePercent(){const t=this.getPriceChangePercent();return`${t>=0?"+":""}${t.toFixed(2)}%`}formatBidAsk(){return`$${this.bidPrice.toFixed(2)} x ${this.bidSize} / $${this.askPrice.toFixed(2)} x ${this.askSize}`}formatVolume(){return 0===this.volume?"N/A":this.volume.toLocaleString()}formatAvgVolume(){return 0===this.averageVolume?"N/A":this.averageVolume.toLocaleString()}formatAverageVolume(){return 0===this.averageVolume?"N/A":this.averageVolume.toLocaleString()}formatDayRange(){return 0===this.low&&0===this.high?"N/A":`$${this.low.toFixed(2)} - $${this.high.toFixed(2)}`}format52WeekRange(){return 0===this.low52Week&&0===this.high52Week?"N/A":`${this.low52Week.toFixed(2)} - ${this.high52Week.toFixed(2)}`}formatMarketCap(){if(0===this.marketCap)return"N/A";const t=1e6*this.marketCap;return t>=1e12?`$${(t/1e12).toFixed(2)}T`:t>=1e9?`$${(t/1e9).toFixed(2)}B`:t>=1e6?`$${(t/1e6).toFixed(2)}M`:t>=1e3?`$${(t/1e3).toFixed(2)}K`:`$${t.toFixed(2)}`}formatAvg30DayVolume(){return this.formatAverageVolume()}static fromApiResponse(t){return new i(t)}}class s{constructor(t){let e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};this.widget=t,this.options={maxLength:e.maxLength||10,placeholder:e.placeholder||"Enter symbol...",onSymbolChange:e.onSymbolChange||(()=>{}),debug:e.debug||!1,autoUppercase:!1!==e.autoUppercase,...e},this.symbolType=e.symbolType||null,this.apiService=this.widget.wsManager.getApiService(),this.isEditing=!1,this.isValidating=!1,this.originalSymbol="",this.elements={},this.addStyles(),this.initialize()}initialize(){this.setupElements(),this.attachEventListeners()}setupElements(){if(this.elements.symbolDisplay=this.widget.container.querySelector(".editable-symbol"),!this.elements.symbolDisplay)throw new Error('No element with class "editable-symbol" found in widget');this.originalSymbol=this.elements.symbolDisplay.textContent.trim(),this.elements.symbolDisplay.dataset.originalSymbol=this.originalSymbol}attachEventListeners(){this.startEditing=this.startEditing.bind(this),this.handleKeydown=this.handleKeydown.bind(this),this.handleInput=this.handleInput.bind(this),this.handleBlur=this.handleBlur.bind(this),this.handleClickOutside=this.handleClickOutside.bind(this),this.elements.symbolDisplay.addEventListener("dblclick",this.startEditing)}startEditing(){this.isEditing||this.isValidating||(this.isEditing=!0,this.originalSymbol=this.elements.symbolDisplay.textContent.trim(),this.options.debug&&(console.log(this.widget.connectionQuality),console.log("[SymbolEditor] Starting edit mode for:",this.originalSymbol)),this.transformToInput())}transformToInput(){const t=this.elements.symbolDisplay,e=window.getComputedStyle(t),n=document.createElement("div");n.className="symbol-edit-container",n.style.display="inline-flex",n.style.alignItems="center",n.style.gap="8px",n.style.verticalAlign="baseline";const i=document.createElement("input");i.type="text",i.value=this.originalSymbol,i.className=t.className+" symbol-input-mode",i.style.fontSize=e.fontSize,i.style.fontWeight=e.fontWeight,i.style.fontFamily=e.fontFamily,i.style.color=e.color,i.style.backgroundColor="transparent",i.style.border="2px solid #3b82f6",i.style.borderRadius="4px",i.style.padding="2px 6px",i.style.margin="0",i.style.outline="none",i.style.width="auto",i.style.minWidth="120px",i.style.maxWidth="200px",i.style.flexShrink="0";const s=document.createElement("button");s.className="symbol-save-btn",s.innerHTML="✓",s.title="Save symbol",s.style.width="28px",s.style.height="28px",s.style.border="none",s.style.borderRadius="4px",s.style.backgroundColor="#059669",s.style.color="white",s.style.cursor="pointer",s.style.fontSize="12px",s.style.display="inline-flex",s.style.alignItems="center",s.style.justifyContent="center",s.style.flexShrink="0",n.appendChild(i),n.appendChild(s),t.style.display="none",t.parentNode.insertBefore(n,t.nextSibling),this.elements.symbolInput=i,this.elements.saveBtn=s,this.elements.editContainer=n,i.focus(),i.select(),i.addEventListener("keydown",this.handleKeydown),i.addEventListener("input",this.handleInput),i.addEventListener("blur",this.handleBlur),document.addEventListener("click",this.handleClickOutside),s.addEventListener("click",(t=>{t.stopPropagation(),this.saveSymbol()}))}async saveSymbol(){if(this.isValidating)return;const t=this.elements.symbolInput.value.trim(),e=await this.validateSymbol(t);if(!e.isValid)return this.showError(e.message),void setTimeout((()=>{this.elements.symbolInput&&(this.elements.symbolInput.value=this.originalSymbol,this.clearError(),this.cancelEditing())}),2e3);this.setLoadingState(!0);try{const n=await this.options.onSymbolChange(t,this.originalSymbol,e.data);if(n&&n.success)this.finishEditing(t),this.showSuccess("Symbol updated successfully");else{const t=n?.message||"Failed to update symbol";this.showError(t)}}catch(t){console.error("[SymbolEditor] Error changing symbol:",t),this.showError("Error updating symbol")}finally{this.setLoadingState(!1)}}cancelEditing(){this.options.debug&&console.log("[SymbolEditor] Cancelling edit mode"),this.finishEditing(this.originalSymbol)}finishEditing(){let t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null;this.isEditing=!1;const e=t||this.originalSymbol;this.elements.symbolDisplay.textContent=e,this.elements.symbolDisplay.dataset.originalSymbol=e,this.elements.symbolDisplay.style.display="",this.elements.editContainer&&(this.elements.editContainer.remove(),this.elements.editContainer=null),this.elements.symbolInput=null,this.elements.saveBtn=null,document.removeEventListener("click",this.handleClickOutside)}handleKeydown(t){"Enter"===t.key?(t.preventDefault(),this.saveSymbol()):"Escape"===t.key&&(t.preventDefault(),this.cancelEditing())}handleInput(t){if(this.options.autoUppercase){const e=t.target,n=e.selectionStart,i=e.selectionEnd;e.value=e.value.toUpperCase(),e.setSelectionRange(n,i)}this.clearError()}handleBlur(t){t.relatedTarget&&t.relatedTarget===this.elements.saveBtn||setTimeout((()=>{this.isEditing&&this.cancelEditing()}),150)}handleClickOutside(t){if(!this.isEditing)return;this.elements.symbolInput?.contains(t.target)||this.elements.saveBtn?.contains(t.target)||this.cancelEditing()}async validateSymbol(t){if("live"!==this.widget.connectionQuality)return{isValid:!1,message:"Not connected to data service"};if(!t||0===t.trim().length)return{isValid:!1,message:"Symbol cannot be empty"};const e=t.trim().toUpperCase();try{if("optionsl1"==this.symbolType){const t=await this.apiService.quoteOptionl1(e);return t[0]&&(t[0].error||1==t[0].not_found)?1==t[0].not_found?{isValid:!1,message:"Symbol not found"}:{isValid:!1,message:t[0].error}:{isValid:!0,data:t[0]}}if("quotel1"==this.symbolType||"nightsession"==this.symbolType){const t=await this.apiService.quotel1(e);return t&&t.message?t.message.includes("no data")?{isValid:!1,message:"Symbol not found"}:{isValid:!1,message:t.message}:{isValid:!0,data:t.data[0]}}if("nightsession"==this.symbolType){const t=await this.apiService.quoteBlueOcean(e);return t[0]&&1==t[0].not_found?{isValid:!1,message:"Symbol not found"}:t[0]&&0==t[0].not_found?{isValid:!0,data:t[0]}:{isValid:!1,message:t[0].error}}}catch(t){return console.warn("[SymbolEditor] API validation failed, falling back to basic validation:",t),this.defaultValidator(e)}return this.defaultValidator(e)}defaultValidator(t){return t&&0!==t.length?t.length>this.options.maxLength?{isValid:!1,message:`Symbol too long (max ${this.options.maxLength} chars)`}:{isValid:!0,data:null}:{isValid:!1,message:"Symbol cannot be empty"}}setLoadingState(t){this.isValidating=t,this.elements.saveBtn&&(t?(this.elements.saveBtn.innerHTML='<div class="loading-spinner"></div>',this.elements.saveBtn.disabled=!0):(this.elements.saveBtn.innerHTML="✓",this.elements.saveBtn.disabled=!1)),this.elements.symbolInput&&(this.elements.symbolInput.disabled=t)}showError(t){if(this.elements.symbolInput){this.elements.symbolInput.style.borderColor="#dc2626",this.elements.symbolInput.style.boxShadow="0 0 0 3px rgba(220, 38, 38, 0.1)",this.removeErrorMessage();const e=document.createElement("div");e.className="symbol-error-message",e.textContent=t,e.style.cssText="\n color: #dc2626;\n font-size: 12px;\n margin-bottom: 2px;\n position: absolute;\n background: white;\n z-index: 1000;\n transform: translateY(-100%);\n top: -4px;\n left: 0; // Align with input box\n ";const n=this.elements.editContainer;n&&(n.style.position="relative",n.appendChild(e)),this.elements.errorMessage=e,this.elements.symbolInput.focus()}}removeErrorMessage(){this.elements.errorMessage&&(this.elements.errorMessage.remove(),this.elements.errorMessage=null)}clearError(){this.elements.symbolInput&&(this.elements.symbolInput.style.borderColor="#3b82f6",this.elements.symbolInput.style.boxShadow="0 0 0 3px rgba(59, 130, 246, 0.1)",this.elements.symbolInput.title=""),this.removeErrorMessage()}showSuccess(t){this.options.debug&&console.log("[SymbolEditor] Success:",t)}updateSymbol(t){const e=this.options.autoUppercase?t.toUpperCase():t;this.elements.symbolDisplay.textContent=e,this.elements.symbolDisplay.dataset.originalSymbol=e,this.options.debug&&console.log("[SymbolEditor] Symbol updated externally:",e)}destroy(){this.finishEditing(),this.elements.symbolDisplay?.removeEventListener("dblclick",this.startEditing)}addStyles(){if(document.querySelector("#symbol-editor-styles"))return;const t=document.createElement("style");t.id="symbol-editor-styles",t.textContent='\n .editable-symbol {\n cursor: pointer;\n transition: all 0.2s ease;\n position: relative;\n }\n\n .editable-symbol:hover {\n opacity: 0.8;\n transform: scale(1.02);\n }\n\n .editable-symbol:hover::after {\n content: "✎";\n position: absolute;\n top: -8px;\n right: -8px;\n background: #3b82f6;\n color: white;\n font-size: 10px;\n padding: 2px 4px;\n border-radius: 4px;\n opacity: 0.8;\n pointer-events: none;\n }\n\n .symbol-input-mode {\n text-transform: uppercase;\n }\n\n .symbol-save-btn:hover {\n background-color: #047857 !important;\n transform: scale(1.05);\n }\n\n .symbol-save-btn:disabled {\n background-color: #9ca3af !important;\n cursor: not-allowed !important;\n transform: none !important;\n }\n\n .loading-spinner {\n width: 12px;\n height: 12px;\n border: 2px solid rgba(255, 255, 255, 0.3);\n border-top-color: white;\n border-radius: 50%;\n animation: spin 1s linear infinite;\n }\n\n @keyframes spin {\n to { transform: rotate(360deg); }\n }\n ',document.head.appendChild(t)}}const o='\n /* ========================================\n FONT SIZE SYSTEM - CSS Variables\n Adjust --mdas-base-font-size to scale all fonts\n ======================================== */\n :root {\n /* Base font size - change this to scale everything */\n --mdas-base-font-size: 14px;\n\n /* Relative font sizes (in em, scales with base) */\n --mdas-company-name-size: 1.43em; /* 20px at base 14px */\n --mdas-symbol-size: 1.79em; /* 25px at base 14px */\n --mdas-price-size: 2.29em; /* 32px at base 14px */\n --mdas-price-change-size: 1.14em; /* 16px at base 14px */\n --mdas-section-title-size: 1em; /* 14px at base 14px */\n --mdas-data-label-size: 0.93em; /* 13px at base 14px */\n --mdas-data-value-size: 1em; /* 14px at base 14px */\n --mdas-bid-ask-size: 1.07em; /* 15px at base 14px */\n --mdas-small-text-size: 0.86em; /* 12px at base 14px */\n --mdas-badge-size: 0.86em; /* 12px at base 14px */\n --mdas-loading-text-size: 1.14em; /* 16px at base 14px */\n --mdas-no-data-title-size: 1.14em; /* 16px at base 14px */\n --mdas-edit-icon-size: 0.71em; /* 10px at base 14px */\n }\n\n /* Apply base font size to widgets */\n .widget {\n font-size: var(--mdas-base-font-size);\n }\n\n /* ========================================\n OPTIONAL CARD STYLING\n Add \'widget-styled\' class for card design\n ======================================== */\n .widget-styled {\n background: white;\n border-radius: 12px;\n padding: 24px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);\n border: 1px solid #e5e7eb;\n }\n\n /* Base widget styles */\n .widget-loading-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(255, 255, 255, 0.95);\n backdrop-filter: blur(2px);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10;\n border-radius: 12px;\n }\n\n .widget-loading-overlay.hidden {\n display: none;\n }\n\n .widget {\n font-family: -apple-system, BlinkMacSystemFont, \'Segoe UI\', Roboto, sans-serif;\n width: 100%;\n max-width: 1400px;\n }\n\n /* HEADER STYLES */\n\n .widget-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 20px;\n gap: 16px;\n }\n\n .symbol-section {\n display: flex;\n flex-direction: column;\n gap: 4px;\n }\n\n .night-company-name {\n font-size: var(--mdas-company-name-size);\n font-weight: 500;\n color: #111827;\n cursor: pointer;\n transition: all 0.2s ease;\n position: relative;\n }\n\n .symbol {\n font-size: var(--mdas-symbol-size);\n font-weight: 700;\n color: #111827;\n cursor: pointer;\n transition: all 0.2s ease;\n position: relative;\n }\n\n .symbol:hover {\n opacity: 0.8;\n transform: scale(1.02);\n }\n\n .symbol:hover::after {\n content: "✎";\n position: absolute;\n top: -8px;\n right: -8px;\n background: #3b82f6;\n color: white;\n font-size: var(--mdas-edit-icon-size);\n padding: 2px 4px;\n border-radius: 4px;\n opacity: 0.8;\n }\n\n .data-type {\n background:rgb(214, 228, 250);\n padding: 2px 8px;\n border-radius: 6px;\n font-size: var(--mdas-badge-size);\n font-weight: 500;\n color: #3b82f6;\n }\n\n .price-section {\n text-align: right;\n }\n\n .current-price {\n font-size: var(--mdas-price-size);\n font-weight: 700;\n color: #111827;\n line-height: 1;\n }\n\n .price-change {\n font-size: var(--mdas-price-change-size);\n font-weight: 600;\n margin-top: 4px;\n display: flex;\n align-items: center;\n justify-content: flex-end;\n gap: 4px;\n }\n\n .price-change.positive { \n color: #10b981; \n }\n\n .price-change.negative { \n color: #ef4444; \n }\n\n .price-change.neutral { \n color: #6b7280; \n }\n\n .market-data-widget .price-change.positive::before,\n .night-session-widget .price-change.positive::before,\n .options-widget .price-change.positive::before{\n content: "↗";\n }\n\n .market-data-widget .price-change.negative::before,\n .night-session-widget .price-change.negative::before,\n .options-widget .price-change.negative::before {\n content: "↘";\n }\n\n /* BODY SECTION STYLES */\n\n .data-grid {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 32px;\n margin-bottom: 24px;\n }\n\n .data-section {\n display: flex;\n flex-direction: column;\n gap: 16px;\n }\n\n .section-title {\n font-size: var(--mdas-section-title-size);\n font-weight: 600;\n color: #6b7280;\n margin: 0;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n border-bottom: 1px solid #e5e7eb;\n padding-bottom: 8px;\n }\n\n .data-row {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 16px;\n }\n\n .data-item {\n display: flex;\n flex-direction: column;\n gap: 4px;\n }\n\n .price-metadata,\n .data-label {\n font-size: var(--mdas-data-label-size);\n color: #6b7280;\n font-weight: 500;\n }\n\n .data-value {\n font-size: var(--mdas-data-value-size);\n font-weight: 600;\n color: #111827;\n text-align: right;\n flex-shrink: 0;\n }\n\n\n /* Footer */\n .widget-footer {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding-top: 16px;\n border-top: 1px solid #e5e7eb;\n font-size: var(--mdas-small-text-size);\n color: #9ca3af;\n }\n \n\n /* LOADING STYLES */\n\n\n .loading-content {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 16px;\n }\n\n .loading-spinner {\n width: 40px;\n height: 40px;\n border: 4px solid #e5e7eb;\n border-top-color: #3b82f6;\n border-radius: 50%;\n animation: spin 1s linear infinite;\n }\n\n .loading-text {\n color: #6b7280;\n font-size: var(--mdas-loading-text-size);\n font-weight: 500;\n }\n\n @keyframes spin {\n to { transform: rotate(360deg); }\n }\n\n .widget-error {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n background: #fef2f2;\n border: 1px solid #fecaca;\n border-radius: 8px;\n padding: 16px;\n color: #dc2626;\n font-size: var(--mdas-data-value-size);\n font-weight: 600;\n text-align: center;\n z-index: 10;\n max-width: 80%;\n }\n\n /* Price change colors */\n .positive {\n color: #059669;\n }\n\n .negative {\n color: #dc2626;\n }\n\n \n\n /* No data state */\n .no-data-state {\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 160px;\n margin: 16px 0;\n background: #f9fafb;\n border: 1px solid #e5e7eb;\n border-radius: 12px;\n padding: 24px 16px;\n width: 100%;\n box-sizing: border-box;\n overflow: hidden;\n }\n\n .no-data-content {\n text-align: center;\n max-width: 280px;\n width: 100%;\n word-wrap: break-word;\n overflow-wrap: break-word;\n }\n\n .no-data-icon {\n margin-bottom: 16px;\n display: flex;\n justify-content: center;\n }\n\n .no-data-icon svg {\n opacity: 0.6;\n }\n\n .no-data-title {\n font-size: var(--mdas-no-data-title-size);\n font-weight: 600;\n color: #6b7280;\n margin: 0 0 8px 0;\n }\n\n .no-data-description {\n font-size: var(--mdas-data-value-size);\n color: #9ca3af;\n margin: 0 0 12px 0;\n line-height: 1.4;\n }\n\n .no-data-description strong {\n color: #6b7280;\n font-weight: 600;\n }\n\n .no-data-guidance {\n font-size: var(--mdas-small-text-size);\n color: #9ca3af;\n margin: 0;\n font-style: italic;\n }\n\n /* Error Access State */\n .no-data-state.error-access {\n border: 1px solid #fecaca;\n background:rgb(255, 255, 255);\n \n }\n\n .no-data-title.error {\n color: #ef4444;\n }\n\n .no-data-icon.error svg {\n stroke: #ef4444;\n }\n\n .no-data-icon.error svg circle[fill] {\n fill: #ef4444;\n }\n',a=`\n ${o}\n\n /* Reset and base styles for widget */\n\n .night-session-widget {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n line-height: 1.5;\n max-width: 800px;\n position: relative;\n }\n\n /* STANDARDIZED HEADER LAYOUT */\n\n\n .symbol-section {\n display: flex;\n flex-direction: column;\n gap: 4px;\n }\n\n .night-session-widget .symbol {\n font-size: var(--mdas-symbol-size);\n font-weight: 700;\n color: #111827;\n cursor: pointer;\n transition: all 0.2s ease;\n position: relative;\n }\n\n .night-session-widget .symbol:hover {\n opacity: 0.8;\n transform: scale(1.02);\n }\n\n .night-session-widget .symbol:hover::after {\n content: "✎";\n position: absolute;\n top: -8px;\n right: -8px;\n background: #3b82f6;\n color: white;\n font-size: var(--mdas-edit-icon-size);\n padding: 2px 4px;\n border-radius: 4px;\n opacity: 0.8;\n }\n\n .company-info {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: var(--mdas-section-title-size);\n color: #6b7280;\n }\n\n .market-name {\n font-weight: 600;\n text-transform: uppercase;\n }\n\n /* Company and market info styling */\n .company-market-info {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: var(--mdas-small-text-size);\n color: #6b7280;\n margin-bottom: 4px;\n }\n\n .company-market-info .market-name {\n font-weight: 600;\n }\n\n .company-market-info .market-name::before {\n content: '|';\n margin-right: 8px;\n color: #9ca3af;\n }\n\n .company-market-info .market-mic {\n font-weight: 600;\n }\n\n .company-market-info .market-mic::before {\n content: '•';\n margin-right: 8px;\n }\n\n /* Price metadata (source and last update) */\n .price-metadata {\n margin-top: 8px;\n display: flex;\n flex-direction: column;\n gap: 4px;\n }\n\n \n\n /* STANDARDIZED GRID LAYOUT */\n .data-grid {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 24px;\n margin-top: 24px;\n }\n\n .data-section {\n display: flex;\n flex-direction: column;\n gap: 12px;\n }\n\n .night-session-widget .section-title {\n font-size: var(--mdas-small-text-size);\n font-weight: 600;\n color: #6b7280;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n border-bottom: 1px solid #e5e7eb;\n padding-bottom: 8px;\n }\n\n .night-session-widget .data-row {\n display: flex;\n justify-content: space-between;\n align-items: center;\n min-height: 20px;\n }\n\n\n\n .night-session-widget .data-value {\n font-size: var(--mdas-data-value-size);\n font-weight: 600;\n color: #111827;\n text-align: right;\n }\n\n /* SPECIAL FORMATTING FOR DIFFERENT DATA TYPES */\n .night-session-widget .bid-ask-value {\n font-size: var(--mdas-bid-ask-size);\n font-weight: 700;\n }\n\n .night-session-widget .size-info {\n font-size: var(--mdas-small-text-size);\n color: #6b7280;\n margin-left: 4px;\n }\n\n /* Footer */\n .night-session-widget .widget-footer {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-top: 24px;\n padding-top: 16px;\n border-top: 1px solid #e5e7eb;\n font-size: var(--mdas-small-text-size);\n color: #9ca3af;\n grid-column: 1 / -1;\n }\n\n /* Loading Overlay */\n .widget-loading-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(255, 255, 255, 0.95);\n backdrop-filter: blur(2px);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10;\n border-radius: 12px;\n }\n\n .widget-loading-overlay.hidden {\n display: none;\n }\n\n .loading-content {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 12px;\n }\n\n .loading-spinner {\n width: 32px;\n height: 32px;\n border: 3px solid #f3f4f6;\n border-top-color: #3b82f6;\n border-radius: 50%;\n animation: spin 1s linear infinite;\n }\n\n .night-session-widget .loading-text {\n color: #6b7280;\n font-size: var(--mdas-data-value-size);\n font-weight: 500;\n }\n\n @keyframes spin {\n to { transform: rotate(360deg); }\n }\n\n /* Widget Error Styles */\n .night-session-widget .widget-error {\n background: #fef2f2;\n color: #9ca3af;\n padding: 12px;\n border-radius: 8px;\n border: 1px solid #fecaca;\n margin-top: 16px;\n font-size: var(--mdas-data-value-size);\n font-weight: 500;\n }\n\n /* No Data State */\n .night-session-widget .no-data-state {\n padding: 24px;\n text-align: center;\n color: #6b7280;\n grid-column: 1 / -1;\n }\n\n .night-session-widget .no-data-content {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 12px;\n }\n\n .night-session-widget .no-data-icon {\n font-size: 3.43em;\n opacity: 0.5;\n }\n\n .night-session-widget .no-data-title {\n font-size: 1.29em;\n font-weight: 600;\n color: #374151;\n }\n\n .night-session-widget .no-data-message {\n font-size: var(--mdas-data-value-size);\n max-width: 300px;\n line-height: 1.5;\n }\n\n .night-session-widget .no-data-suggestion {\n font-size: var(--mdas-small-text-size);\n color: #9ca3af;\n max-width: 350px;\n line-height: 1.4;\n }\n\n /* Dimmed state for no data */\n .widget-header.dimmed,\n .price-section.dimmed {\n opacity: 0.6;\n }\n\n /* Responsive Design */\n @media (max-width: 768px) {\n :root {\n --mdas-base-font-size: 13px; /* Slightly smaller on tablets */\n }\n\n .widget-styled {\n padding: 16px;\n }\n\n .widget-header {\n grid-template-columns: 1fr;\n gap: 12px;\n text-align: center;\n }\n\n .symbol-section {\n align-items: center;\n }\n\n .price-section {\n text-align: center;\n }\n\n .data-grid {\n grid-template-columns: 1fr;\n gap: 16px;\n }\n\n .widget-footer {\n flex-direction: column;\n gap: 8px;\n text-align: center;\n }\n }\n\n @media (max-width: 480px) {\n :root {\n --mdas-base-font-size: 12px; /* Smaller on mobile */\n }\n }\n\n \n`,r=`\n ${o}\n\n /* Reset and base styles for widget */\n\n .market-data-widget {\n color: #333;\n margin: 0 auto;\n position: relative;\n overflow: hidden;\n }\n\n /* MARKET DATA HEADER STYLES */\n\n\n .market-data-widget .company-info {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: var(--mdas-section-title-size);\n color: #6b7280;\n }\n\n .company-name {\n position: relative;\n cursor: help;\n transition: all 0.2s ease;\n }\n\n .company-name:hover {\n border-bottom-color: #3b82f6;\n color: #3b82f6;\n }\n\n\n /* STANDARDIZED GRID LAYOUT */\n \n .data-section {\n display: flex;\n flex-direction: column;\n gap: 12px;\n min-width: 0;\n overflow: hidden;\n }\n\n .market-data-widget .section-title {\n font-size: var(--mdas-small-text-size);\n font-weight: 600;\n color: #6b7280;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n padding-bottom: 8px;\n }\n\n\n\n /* SPECIAL FORMATTING FOR DIFFERENT DATA TYPES */\n .market-data-widget .bid-ask-value {\n font-size: var(--mdas-bid-ask-size);\n font-weight: 700;\n }\n\n .market-data-widget .size-info {\n font-size: var(--mdas-small-text-size);\n color: #6b7280;\n margin-left: 4px;\n }\n\n .market-data-widget .range-value {\n font-size: var(--mdas-data-label-size);\n }\n\n \n\n /* Tooltip Styles */\n .company-name::after {\n content: attr(data-tooltip);\n position: absolute;\n bottom: 100%;\n left: 50%;\n transform: translateX(-50%);\n background: #1f2937;\n color: white;\n padding: 8px 12px;\n border-radius: 6px;\n font-size: var(--mdas-small-text-size);\n font-weight: normal;\n white-space: nowrap;\n max-width: 300px;\n white-space: normal;\n line-height: 1.4;\n z-index: 1000;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n opacity: 0;\n visibility: hidden;\n transition: all 0.2s ease;\n pointer-events: none;\n margin-bottom: 5px;\n }\n\n .company-name:hover::after {\n opacity: 1;\n visibility: visible;\n }\n\n .company-name::before {\n content: '';\n position: absolute;\n bottom: 100%;\n left: 50%;\n transform: translateX(-50%);\n border: 5px solid transparent;\n border-top-color: #1f2937;\n opacity: 0;\n visibility: hidden;\n transition: all 0.2s ease;\n pointer-events: none;\n }\n\n .company-name:hover::before {\n opacity: 1;\n visibility: visible;\n }\n\n /* Loading Overlay */\n .widget-loading-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(255, 255, 255, 0.95);\n backdrop-filter: blur(2px);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10;\n border-radius: 12px;\n }\n\n .widget-loading-overlay.hidden {\n display: none;\n }\n\n .loading-content {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 12px;\n }\n\n .loading-spinner {\n width: 32px;\n height: 32px;\n border: 3px solid #f3f4f6;\n border-top-color: #3b82f6;\n border-radius: 50%;\n animation: spin 1s linear infinite;\n }\n\n .market-data-widget .loading-text {\n color: #6b7280;\n font-size: var(--mdas-data-value-size);\n font-weight: 500;\n }\n\n @keyframes spin {\n to { transform: rotate(360deg); }\n }\n\n /* Widget Error Styles */\n .market-data-widget .widget-error {\n background: #fef2f2;\n color: #dc2626;\n padding: 12px;\n border-radius: 8px;\n border: 1px solid #fecaca;\n margin-top: 16px;\n font-size: var(--mdas-data-value-size);\n font-weight: 500;\n }\n\n /* Responsive Design */\n\n\n @media (max-width: 600px) {\n .widget-header {\n grid-template-columns: 1fr;\n gap: 12px;\n text-align: center;\n }\n\n .symbol-section {\n align-items: center;\n }\n\n .price-section {\n text-align: center;\n }\n\n .data-grid {\n grid-template-columns: 1fr;\n gap: 16px;\n }\n\n .widget-footer {\n flex-direction: column;\n gap: 8px;\n text-align: center;\n }\n }\n\n @media (max-width: 480px) {\n .company-name::after {\n left: 0;\n transform: none;\n max-width: 250px;\n }\n\n .company-name::before {\n left: 20px;\n transform: none;\n }\n }\n`,c=`\n ${o}\n\n .options-widget {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n color: #333;\n max-width: 1400px;\n width: 100%;\n margin: 0 auto;\n position: relative;\n overflow: hidden;\n }\n\n .widget-content {\n position: relative;\n z-index: 1;\n }\n\n \n .options-widget .symbol-info .symbol {\n font-size: var(--mdas-symbol-size);\n font-weight: 700;\n margin: 0 0 8px 0;\n color: #1f2937;\n }\n\n .options-widget .option-info {\n display: flex;\n align-items: center;\n gap: 8px;\n color: #6b7280;\n font-size: var(--mdas-price-change-size);\n }\n\n .options-widget .underlying-symbol {\n font-weight: 600;\n color: #6b7280;\n }\n\n .options-widget .option-details-section {\n display: flex;\n gap: 24px;\n margin-bottom: 24px;\n padding-bottom: 20px;\n border-bottom: 1px solid #e5e7eb;\n }\n\n .options-widget .option-details-section .detail-item {\n display: flex;\n flex-direction: column;\n gap: 4px;\n }\n\n .options-widget .option-details-section .detail-item label {\n font-size: var(--mdas-small-text-size);\n color: #6b7280;\n font-weight: 500;\n text-transform: uppercase;\n letter-spacing: 0.3px;\n }\n\n .options-widget .option-details-section .detail-item span {\n font-size: var(--mdas-price-change-size);\n font-weight: 600;\n color: #1f2937;\n }\n\n\n .options-widget .widget-footer {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding-top: 16px;\n border-top: 1px solid #e5e7eb;\n font-size: var(--mdas-small-text-size);\n color: #9ca3af;\n }\n\n /* Dimmed state for no-data */\n .widget-header.dimmed {\n opacity: 0.6;\n }\n\n .widget-header.dimmed .symbol {\n color: #9ca3af;\n }\n\n /* Responsive design */\n @media (max-width: 768px) {\n .widget-header {\n flex-direction: column;\n gap: 16px;\n text-align: left;\n }\n\n .price-info {\n text-align: left;\n }\n\n .data-grid {\n grid-template-columns: 1fr;\n gap: 20px;\n }\n\n .option-details-section {\n flex-wrap: wrap;\n gap: 16px;\n }\n\n .current-price {\n font-size: 32px;\n }\n\n .symbol {\n font-size: 20px !important;\n }\n }\n\n @media (max-width: 480px) {\n .widget-styled {\n padding: 12px;\n }\n\n .widget-header {\n margin-bottom: 16px;\n padding-bottom: 16px;\n }\n\n .current-price {\n font-size: 28px;\n }\n\n .data-row {\n grid-template-columns: 1fr;\n gap: 12px;\n }\n\n .option-details-section {\n flex-direction: column;\n gap: 12px;\n }\n\n .no-data-state {\n min-height: 120px;\n padding: 20px 12px;\n }\n\n .no-data-title {\n font-size: 14px;\n }\n\n .no-data-description {\n font-size: 12px;\n }\n\n .no-data-guidance {\n font-size: 11px;\n }\n }\n`;function l(t){let e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"";const i=document.createElement(t);return n&&(i.className=n),e&&(i.textContent=e),i}function d(t){let e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:2,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"--";if(null==t||""===t)return n;const i=parseFloat(t);return isNaN(i)?n:i.toFixed(e)}function h(t){if(!t)return"";return String(t).replace(/[^A-Za-z0-9.\-_+ ]/g,"").substring(0,50)}function u(t){if(t)for(;t.firstChild;)t.removeChild(t.firstChild)}function g(t){if(!t||"string"!=typeof t)return{valid:!1,error:"Symbol is required",sanitized:""};const e=t.trim().toUpperCase();return 0===e.length?{valid:!1,error:"Symbol cannot be empty",sanitized:""}:e.length>10?{valid:!1,error:"Symbol too long (max 10 characters)",sanitized:""}:{valid:!0,sanitized:e}}function p(t){if(!t||"string"!=typeof t)return{valid:!1,error:"Option symbol is required",sanitized:""};const e=t.trim().toUpperCase();if(e.length<15||e.length>21)return{valid:!1,error:"Invalid option symbol length",sanitized:e};const n=e.match(/^([A-Z]{1,6})(\d{2})(0[1-9]|1[0-2])([0-2][0-9]|3[01])([CP])(\d{8})$/);if(!n)return{valid:!1,error:"Invalid option symbol format. Expected: SYMBOL+YYMMDD+C/P+STRIKE",sanitized:e};const[,i,s,o,a,r,c]=n,l=2e3+parseInt(s,10),d=parseInt(o,10),h=parseInt(a,10),u=new Date(l,d-1,h);if(u.getMonth()+1!==d||u.getDate()!==h)return{valid:!1,error:"Invalid expiration date in option symbol",sanitized:e};const g=new Date;g.setHours(0,0,0,0),u<g&&console.warn("Option symbol has expired");return{valid:!0,sanitized:e,parsed:{underlying:i,expiry:u,type:"C"===r?"call":"put",strike:parseInt(c,10)/1e3}}}function m(t){if(!t)return"ET";const[e,n,i]=t.split("-").map(Number),s=new Date(e,n-1,i),o=function(t,e){const n=new Date(t,e,1),i=1+(7-n.getDay())%7;return new Date(t,e,i+7)}(e,2),a=function(t,e){const n=new Date(t,e,1),i=1+(7-n.getDay())%7;return new Date(t,e,i)}(e,10);return s>=o&&s<a?"EDT":"EST"}function f(t){let e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const{includeSeconds:n=!0,includeTimezone:i=!0,format:s="short"}=e;let o;if(t||(t=Date.now()),o=t instanceof Date?t:new Date(t),isNaN(o.getTime()))return"Invalid Date";const a=o.getUTCFullYear(),r=o.getUTCMonth(),c=o.getUTCDate(),l=o.getUTCHours(),d=o.getUTCMinutes(),h=o.getUTCSeconds(),u=function(t){const e=t.getUTCFullYear(),n=t.getUTCMonth(),i=t.getUTCDate(),s=new Date(Date.UTC(e,n,i)),o=function(t,e){const n=new Date(Date.UTC(t,e,1)),i=1+(7-n.getUTCDay())%7;return new Date(Date.UTC(t,e,i+7))}(e,2),a=function(t,e){const n=new Date(Date.UTC(t,e,1)),i=1+(7-n.getUTCDay())%7;return new Date(Date.UTC(t,e,i))}(e,10);return s>=o&&s<a}(o),g=u?-4:-5,p=new Date(Date.UTC(a,r,c,l+g,d,h)),m=p.getUTCFullYear(),f=p.getUTCMonth()+1,b=p.getUTCDate(),y=p.getUTCHours(),x=p.getUTCMinutes(),v=p.getUTCSeconds(),w=y%12||12,S=y>=12?"PM":"AM",k=x.toString().padStart(2,"0"),M=v.toString().padStart(2,"0"),C=n?`${w}:${k}:${M} ${S}`:`${w}:${k} ${S}`,_=i?u?" EDT":" EST":"";if("long"===s){return`${["January","February","March","April","May","June","July","August","September","Oct","November","December"][f-1]} ${b}, ${m}, ${C}${_}`}return`${f}/${b}/${m}, ${C}${_}`}class b extends n{constructor(t,e,n){if(super(t,e,n),!e.symbol)throw new Error("Symbol is required for MarketDataWidget");if(!e.wsManager)throw new Error("WebSocketManager is required for MarketDataWidget");this.type="marketdata";const i=g(e.symbol);if(!i.valid)throw new Error(`Invalid symbol: ${i.error}`);this.symbol=i.sanitized,this.wsManager=e.wsManager,this.debug=e.debug||!1,this.styled=void 0===e.styled||e.styled,this.data=null,this.isDestroyed=!1,this.unsubscribe=null,this.loadingTimeout=null,this.createWidgetStructure(),this.initializeSymbolEditor(),this.initialize()}createWidgetStructure(){if(this.container.innerHTML='\n <div class="market-data-widget widget">\n <div class="widget-content">\n \x3c!-- Header Section --\x3e\n <div class="widget-header">\n <div class="symbol-section">\n <h1 class="symbol editable-symbol" \n title="Double-click to edit symbol" \n data-original-symbol="">\n </h1>\n <div class="company-info">\n <span class="company-name" \n title="" \n data-tooltip="">\n </span>\n <span class="data-type">STOCK</span>\n </div>\n </div>\n <div class="price-section">\n <div class="current-price"></div>\n <div class="price-change">\n <span class="change-value"></span>\n <span class="change-percent"></span>\n </div>\n </div>\n </div>\n\n \x3c!-- Data Grid Section --\x3e\n <div class="data-grid">\n <div class="data-section">\n <div class="section-title">Quote</div>\n <div class="data-row">\n <span class="data-label">Bid</span>\n <span class="data-value bid-ask-value bid-data"></span>\n </div>\n <div class="data-row">\n <span class="data-label">Ask</span>\n <span class="data-value bid-ask-value ask-data"></span>\n </div>\n </div>\n\n <div class="data-section">\n <div class="section-title">Trading Activity</div>\n <div class="data-row">\n <span class="data-label">Volume</span>\n <span class="data-value volume"></span>\n </div>\n <div class="data-row">\n <span class="data-label">Average Volume</span>\n <span class="data-value avg-volume"></span>\n </div>\n </div>\n\n <div class="data-section">\n <div class="section-title">Performance</div>\n <div class="data-row">\n <span class="data-label">Previous Close</span>\n <span class="data-value prev-close"></span>\n </div>\n <div class="data-row">\n <span class="data-label">Open</span>\n <span class="data-value open-price"></span>\n </div>\n <div class="data-row">\n <span class="data-label">Day Range</span>\n <span class="data-value range-value day-range"></span>\n </div>\n <div class="data-row">\n <span class="data-label">52-Week Range</span>\n <span class="data-value range-value week-range"></span>\n </div>\n </div>\n\n <div class="data-section">\n <div class="section-title">Key Metrics</div>\n <div class="data-row">\n <span class="data-label">Market Cap</span>\n <span class="data-value market-cap"></span>\n </div>\n <div class="data-row">\n <span class="data-label">P/E Ratio</span>\n <span class="data-value pe-ratio"></span>\n </div>\n <div class="data-row">\n <span class="data-label">Dividend Yield</span>\n <span class="data-value dividend-yield"></span>\n </div>\n <div class="data-row">\n <span class="data-label">Beta</span>\n <span class="data-value beta"></span>\n </div>\n </div>\n </div>\n\n \x3c!-- Footer --\x3e\n <div class="widget-footer">\n <span class="last-update"></span>\n <span class="data-source"></span>\n </div>\n </div>\n \n \x3c!-- Loading Overlay --\x3e\n <div class="widget-loading-overlay">\n <div class="loading-content">\n <div class="loading-spinner"></div>\n <span class="loading-text">Loading market data...</span>\n </div>\n </div>\n </div>\n',this.styled){const t=this.container.querySelector(".market-data-widget");t&&t.classList.add("widget-styled")}this.addStyles()}addStyles(){if(!document.querySelector("#market-data-styles")){const t=document.createElement("style");t.id="market-data-styles",t.textContent=r,document.head.appendChild(t)}}initializeSymbolEditor(){this.symbolEditor=new s(this,{maxLength:10,placeholder:"Enter symbol...",onSymbolChange:this.handleSymbolChange.bind(this),debug:this.debug,autoUppercase:!0,symbolType:"quotel1"});const t=this.container.querySelector(".symbol");t&&(t.textContent=this.symbol,t.dataset.originalSymbol=this.symbol)}async handleSymbolChange(t){this.debug&&console.log("[MarketDataWidget] Symbol change requested:",t);const e=g(t);if(!e.valid)return this.debug&&console.log("[MarketDataWidget] Invalid symbol:",e.error),{success:!1,error:e.error};const n=e.sanitized;if(n===this.symbol)return this.debug&&console.log("[MarketDataWidget] Same symbol, no change needed"),{success:!0};try{const t=this.symbol;return this.showLoading(),this.loadingTimeout&&this.clearTimeout(this.loadingTimeout),this.loadingTimeout=this.setTimeout((()=>{this.debug&&console.log("[MarketDataWidget] Loading timeout for symbol:",n),this.hideLoading(),this.showError(`No data received for ${n}. Please try again.`)}),1e4),this.unsubscribe&&(this.debug&&console.log(`[MarketDataWidget] Unsubscribing from ${t}`),this.wsManager.sendUnsubscribe("queryl1",t),this.unsubscribe(),this.unsubscribe=null),this.symbol=n,this.debug&&console.log(`[MarketDataWidget] Subscribing to ${n}`),this.subscribeToData(),this.debug&&console.log(`[MarketDataWidget] Successfully changed symbol from ${t} to ${n}`),{success:!0}}catch(t){return console.error("[MarketDataWidget] Error changing symbol:",t),this.hideLoading(),this.showError(`Failed to load data for ${n}`),{success:!1,error:`Failed to load ${n}`}}}async initialize(){this.showLoading(),await this.validateInitialSymbol(),this.subscribeToData()}async validateInitialSymbol(){try{const t=this.wsManager.getApiService();if(!t)return void(this.debug&&console.log("[MarketDataWidget] API service not available for initial validation"));const e=await t.quotel1(this.symbol);if(e&&e.data&&e.data[0]){const t=e.data[0];this.initialValidationData=t,this.debug&&console.log("[MarketDataWidget] Initial symbol validated:",{symbol:this.symbol,companyName:t.comp_name,exchangeName:t.market_name})}}catch(t){this.debug&&console.warn("[MarketDataWidget] Initial symbol validation failed:",t)}}subscribeToData(){this.unsubscribe=this.wsManager.subscribe(this.widgetId,["queryl1"],this.handleMessage.bind(this),this.symbol)}handleData(t){if(this.loadingTimeout&&(clearTimeout(this.loadingTimeout),this.loadingTimeout=null),"error"===t.type&&t.noData)return this.debug&&console.log("[MarketDataWidget] Received no data message:",t.message),void(this.data?(this.hideLoading(),this.debug&&console.log("[MarketDataWidget] No new data, keeping cached data visible")):this.showNoDataState({Symbol:this.symbol,NotFound:!0,message:t.message}));if("error"!==t.type){if("object"==typeof t&&t.Message){const e=t.Message.toLowerCase();if(e.includes("no data")||e.includes("not found"))return this.debug&&console.log("[MarketDataWidget] Received no data message:",t.Message),void(this.data?(this.hideLoading(),this.debug&&console.log("[MarketDataWidget] No new data, keeping cached data visible")):this.showNoDataState({Symbol:this.symbol,NotFound:!0,message:t.Message}))}if(t.Data&&t.Data.length>0){const e=t.Data.find((t=>t.Symbol===this.symbol));if(e){const t=new i(e);this.data=t,this.updateWidget(t)}else this.debug&&console.log("[MarketDataWidget] No data for symbol in response, keeping cached data"),this.hideLoading()}t._cached&&this.showConnectionQuality()}else{const e=t.message||"Server error";this.data?(this.hideLoading(),this.debug&&console.log("[MarketDataWidget] Error received but keeping cached data:",e)):this.showError(e)}}showNoDataState(){let t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};if(!this.isDestroyed)try{this.hideLoading(),this.clearError();const e=t.Symbol||this.symbol,n=this.container.querySelector(".symbol");n&&(n.textContent=e);const i=this.container.querySelector(".company-name");i&&(i.textContent=`${e} Inc`);const s=this.container.querySelector(".current-price");s&&(s.textContent="$0.00");const o=this.container.querySelector(".price-change");if(o){const t=o.querySelector(".change-value"),e=o.querySelector(".change-percent");t&&(t.textContent="+0.00"),e&&(e.textContent=" (0.00%)"),o.classList.remove("positive","negative"),o.classList.add("neutral")}const a=this.container.querySelector(".widget-header");a&&a.classList.add("dimmed"),this.showNoDataMessage(e,t);const r=this.container.querySelector(".last-update");if(r){const t=f();r.textContent=`Checked: ${t}`}const c=this.container.querySelector(".data-source");c&&(c.textContent="Source: No data available")}catch(t){console.error("Error showing no data state:",t),this.showError("Error displaying no data state")}}showNoDataMessage(t){const e=this.container.querySelector(".data-grid");e&&(e.style.display="none");const n=this.container.querySelector(".no-data-state");n&&n.remove();const i=l("div","","no-data-state"),s=l("div","","no-data-content"),o=document.createElement("div");o.className="no-data-icon",o.innerHTML='<svg width="32" height="32" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">\n <circle cx="12" cy="12" r="10" stroke="#9ca3af" stroke-width="2"/>\n <path d="M12 8v4" stroke="#9ca3af" stroke-width="2" stroke-linecap="round"/>\n <circle cx="12" cy="16" r="1" fill="#9ca3af"/>\n </svg>',s.appendChild(o);const a=l("h3","No Market Data","no-data-title");s.appendChild(a);const r=l("p","","no-data-description");r.appendChild(document.createTextNode("Market data for "));const c=l("strong",h(t));r.appendChild(c),r.appendChild(document.createTextNode(" was not found")),s.appendChild(r);const d=l("p","Please check the symbol spelling or try a different symbol","no-data-guidance");s.appendChild(d),i.appendChild(s);const u=this.container.querySelector(".widget-footer");u&&u.parentNode?u.parentNode.insertBefore(i,u):this.container.appendChild(i)}updateWidget(t){if(!this.isDestroyed)try{this.loadingTimeout&&(clearTimeout(this.loadingTimeout),this.loadingTimeout=null),this.clearError(),this.hideLoading();const e=this.container.querySelector(".widget-header");e&&e.classList.remove("dimmed");const n=this.container.querySelector(".data-grid");n&&(n.style.display="");const i=this.container.querySelector(".no-data-state");i&&i.remove();const s=this.container.querySelector(".symbol");s&&(s.textContent=t.symbol,s.dataset.originalSymbol=t.symbol);const o=this.container.querySelector(".company-name");if(o){const e=t.companyName||`${t.symbol} Inc`,n=t.companyDescription||`${t.symbol} designs, manufactures, and markets consumer electronics and software.`;o.textContent=e,o.setAttribute("title",n),o.setAttribute("data-tooltip",n)}const a=this.container.querySelector(".current-price");a&&(a.textContent=t.formatPrice());const r=t.getPriceChange(),c=this.container.querySelector(".price-change");if(c){const e=c.querySelector(".change-value"),n=c.querySelector(".change-percent");e&&(e.textContent=t.formatPriceChange()),n&&(n.textContent=` (${t.formatPriceChangePercent()})`),c.classList.remove("positive","negative","neutral"),r>0?c.classList.add("positive"):r<0?c.classList.add("negative"):c.classList.add("neutral")}const h=this.container.querySelector(".bid-data");if(h){u(h);const e=d(t.bidPrice,2,"0.00"),n=t.bidSize||0;h.appendChild(document.createTextNode(`$${e}`));const i=l("span",`× ${n}`,"size-info");h.appendChild(i)}const g=this.container.querySelector(".ask-data");if(g){u(g);const e=d(t.askPrice,2,"0.00"),n=t.askSize||0;g.appendChild(document.createTextNode(`$${e}`));const i=l("span",`× ${n}`,"size-info");g.appendChild(i)}const p=this.container.querySelector(".volume");p&&(p.textContent=t.formatVolume());const m=this.container.querySelector(".avg-volume");m&&(m.textContent=t.formatAverageVolume());const b=this.container.querySelector(".prev-close");b&&(b.textContent=`$${t.previousClose?.toFixed(2)||"0.00"}`);const y=this.container.querySelector(".open-price");y&&(y.textContent=`$${t.openPrice?.toFixed(2)||"0.00"}`);const x=this.container.querySelector(".day-range");x&&(x.textContent=t.formatDayRange());const v=this.container.querySelector(".week-range");v&&(v.textContent=t.format52WeekRange());const w=this.container.querySelector(".market-cap");w&&(w.textContent=t.formatMarketCap());const S=this.container.querySelector(".pe-ratio");S&&(S.textContent=t.peRatio?.toFixed(2)||"N/A");const k=this.container.querySelector(".dividend-yield");k&&(k.textContent=t.dividendYield?`${t.dividendYield.toFixed(2)}%`:"N/A");const M=this.container.querySelector(".beta");M&&(M.textContent=t.beta?.toFixed(2)||"N/A");const C=f(t.quoteTime),_=this.container.querySelector(".last-update");_&&(_.textContent=`Last update: ${C}`);const D=this.container.querySelector(".data-source");D&&(D.textContent=`Source: ${t.getDataSource()}`)}catch(t){console.error("Error updating widget:",t),this.showError("Error updating data")}}showLoading(){const t=this.container.querySelector(".widget-loading-overlay");t&&t.classList.remove("hidden")}hideLoading(){const t=this.container.querySelector(".widget-loading-overlay");t&&t.classList.add("hidden")}showError(t){this.hideLoading(),this.clearError();const e=document.createElement("div");e.className="widget-error",e.textContent=`Error: ${t}`,e.style.cssText="\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n padding: 15px 20px;\n background: #fee;\n border: 1px solid #f5c6cb;\n border-radius: 6px;\n color: #721c24;\n text-align: center;\n font-size: 14px;\n z-index: 100;\n ",this.container.appendChild(e)}clearError(){const t=this.container.querySelector(".widget-error"),e=this.container.querySelector(".widget-error-container");t&&t.remove(),e&&e.remove()}destroy(){this.isDestroyed=!0,this.loadingTimeout&&(this.clearTimeout(this.loadingTimeout),this.loadingTimeout=null),this.unsubscribe&&(this.unsubscribe(),this.unsubscribe=null),this.symbolEditor&&(this.symbolEditor.destroy(),this.symbolEditor=null),super.destroy()}}class y{constructor(){let t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};this.symbol=t.Symbol||"",this.marketName=t.MarketName||("bruce"===t.Source?.toLowerCase()?"Bruce":"Blue Ocean"),this.marketDesc=null!==t.MarketDesc?t.MarketDesc||"":null,this.countryCode=null!==t.CountryCode?t.CountryCode||"":null,this.volume=null!==t.Volume?t.Volume||0:null,this.askPrice=null!==t.AskPx?t.AskPx||0:null,this.askSize=null!==t.AskSz?t.AskSz||0:null,this.bidPrice=null!==t.BidPx?t.BidPx||0:null,this.bidSize=null!==t.BidSz?t.BidSz||0:null,this.lastPrice=null!==t.LastPx?t.LastPx||0:null,this.quoteTime=null!==t.QuoteTime?t.QuoteTime:null,this.activityTimestamp=null!==t.ActivityTimestamp?t.ActivityTimestamp||"":null,this.tradeSize=null!==t.TradeSz?t.TradeSz||0:null,this.bidExchange=null!==t.BidExch?t.BidExch||"":null,this.askExchange=null!==t.AskExch?t.AskExch||"":null,this.notFound=t.NotFound||!1,this.source=t.Source||"",this.accuAmount=null!==t.AccuAmmount?t.AccuAmmount||0:null,this.change=null!==t.Change?t.Change||0:null,this.changePercent=null!==t.ChangePercent?t.ChangePercent||0:null,this.closingPrice=null!==t.ClosingPx?t.ClosingPx:null!==t.PreviousClose?t.PreviousClose:null,this.highPrice=null!==t.HighPx?t.HighPx||0:null,this.lowPrice=null!==t.LowPx?t.LowPx||0:null,this.openPrice=null!==t.OpenPx?t.OpenPx||0:null,this.tradePrice=null!==t.TradePx?t.TradePx||0:null,this.tradeRegionName=null!==t.TradeRegionName?t.TradeRegionName||"":null,this.companyName=t.comp_name||t.CompanyName||"",this.exchangeName=t.market_name||t.Exchange||"",this.mic=t.mic||""}formatPrice(){return`$${this.lastPrice.toFixed(2)}`}formatBidAsk(){return`$${this.bidPrice.toFixed(2)} × ${this.bidSize} / $${this.askPrice.toFixed(2)} × ${this.askSize}`}formatVolume(){return this.volume.toLocaleString()}formatPriceChange(){if(null===this.change||void 0===this.change)return"--";return`${this.change>0?"+":""}${this.change.toFixed(2)}`}formatPriceChangePercent(){if(null===this.changePercent||void 0===this.changePercent)return"--";return`${this.changePercent>0?"+":""}${this.getPriceChangePercent().toFixed(2)}%`}getDataSource(){return"blueocean-d"===this.source.toLowerCase()||"bruce-d"===this.source.toLowerCase()?"bruce-d"===this.source.toLowerCase()?"Bruce 20 mins delayed":"BlueOcean 20 mins delayed":this.source.toLowerCase().includes("bruce")||this.source.toLowerCase().includes("blueocean")?"bruce"===this.source.toLowerCase()?"Bruce Real-time":"BlueOcean Real-time":null!==this.source&&""!==this.source?this.source:"MDAS"}getPriceChangePercent(){return null===this.changePercent||void 0===this.changePercent?0:Math.abs(this.changePercent)>1?this.changePercent:100*this.changePercent}}class x extends n{constructor(t,e,n){if(super(t,e,n),!e.symbol)throw new Error("Symbol is required for NightSessionWidget");if(!e.wsManager)throw new Error("WebSocketManager is required for NightSessionWidget");if(!e.source||"blueocean"!==e.source.toLowerCase()&&"bruce"!==e.source.toLowerCase())throw new Error('Source should be either "blueocean" or "bruce"');this.type="nightsession "+e.source;const i=g(e.symbol);if(!i.valid)throw new Error(`Invalid symbol: ${i.error}`);this.symbol=i.sanitized,this.source=e.source||"blueocean",this.wsManager=e.wsManager,this.debug=e.debug||!1,this.styled=void 0===e.styled||e.styled,this.data=null,this.isDestroyed=!1,this.unsubscribe=null,this.symbolEditor=null,this.loadingTimeout=null,this.companyName="",this.exchangeName="",this.mic="",this.createWidgetStructure(),this.initialize()}createWidgetStructure(){if(this.container.innerHTML='\n <div class="night-session-widget widget">\n <div class="widget-content">\n \x3c!-- Header Section --\x3e\n <div class="widget-header">\n <div class="symbol-section">\n <div class="company-market-info">\n <span class="night-company-name"></span>\n <span class="market-name"></span>\n </div>\n <h1 class="symbol editable-symbol"\n title="Double-click to edit symbol"\n data-original-symbol="">\n </h1>\n\n </div>\n <div class="price-section">\n <div class="current-price"></div>\n <div class="price-change">\n <span class="change-value"></span>\n <span class="change-percent"></span>\n </div>\n <div class="price-metadata">\n <div class="last-update"></div>\n <div class="data-source"></div>\n </div>\n </div>\n </div>\n\n \x3c!-- Data Grid Section --\x3e\n <div class="data-grid">\n <div class="data-section">\n <div class="section-title">Quote</div>\n <div class="data-row">\n <span class="data-label">Bid</span>\n <span class="data-value bid-ask-value">\n <span class="bid-price"></span>\n <span class="size-info bid-size"></span>\n </span>\n </div>\n <div class="data-row">\n <span class="data-label">Ask</span>\n <span class="data-value bid-ask-value">\n <span class="ask-price"></span>\n <span class="size-info ask-size"></span>\n </span>\n </div>\n </div>\n\n <div class="data-section">\n <div class="section-title">Trading Activity</div>\n <div class="data-row">\n <span class="data-label">Volume</span>\n <span class="data-value volume"></span>\n </div>\n <div class="data-row">\n <span class="data-label">Accumulated Amount</span>\n <span class="data-value accu-amount"></span>\n </div>\n </div>\n\n <div class="data-section">\n <div class="section-title">Performance</div>\n <div class="data-row">\n <span class="data-label">Previous Close</span>\n <span class="data-value previous-close"></span>\n </div>\n <div class="data-row at-close-row">\n <span class="data-label">At close</span>\n <span class="data-value at-close-time"></span>\n </div>\n <div class="data-row">\n <span class="data-label">Open</span>\n <span class="data-value open-price"></span>\n </div>\n <div class="data-row">\n <span class="data-label">Day Range</span>\n <span class="data-value range-value day-range"></span>\n </div>\n </div>\n </div>\n </div>\n\n \x3c!-- Loading Overlay --\x3e\n <div class="widget-loading-overlay">\n <div class="loading-content">\n <div class="loading-spinner"></div>\n <span class="loading-text">Loading night session data...</span>\n </div>\n </div>\n </div>\n',this.styled){const t=this.container.querySelector(".night-session-widget");t&&t.classList.add("widget-styled")}this.addStyles(),this.setupSymbolEditor()}addStyles(){if(!document.querySelector("#night-session-styles")){const t=document.createElement("style");t.id="night-session-styles",t.textContent=a,document.head.appendChild(t)}}setupSymbolEditor(){this.symbolEditor=new s(this,{maxLength:10,placeholder:"Enter symbol...",onSymbolChange:this.handleSymbolChange.bind(this),debug:this.debug,autoUppercase:!0,cancelOnBlur:!1,symbolType:"nightsession"})}async handleSymbolChange(t,e){let n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;this.debug&&(console.log("[NightSessionWidget] Symbol change requested:",t),console.log("[NightSessionWidget] Validation data:",n));const i=g(t);if(!i.valid)return this.debug&&console.log("[NightSessionWidget] Invalid symbol:",i.error),{success:!1,error:i.error};const s=i.sanitized;if(n&&(this.companyName=n.comp_name||"",this.exchangeName=n.market_name||"",this.mic=n.mic||"",this.debug&&console.log("[NightSessionWidget] Extracted company info:",{companyName:this.companyName,exchangeName:this.exchangeName},n)),s===this.symbol)return this.debug&&console.log("[NightSessionWidget] Same symbol, no change needed"),{success:!0};try{const t=this.symbol;return this.showLoading(),this.loadingTimeout&&this.clearTimeout(this.loadingTimeout),this.loadingTimeout=this.setTimeout((()=>{this.debug&&console.log("[NightSessionWidget] Loading timeout for symbol:",s),this.hideLoading(),this.showError(`No data received for ${s}. Please try again.`)}),1e4),this.unsubscribe&&(this.debug&&console.log(`[NightSessionWidget] Unsubscribing from ${t}`),this.unsubscribe(),this.unsubscribe=null),this.symbol=s,this.debug&&console.log(`[NightSessionWidget] Subscribing to ${s}`),this.subscribeToData(),this.debug&&console.log(`[NightSessionWidget] Successfully changed symbol from ${t} to ${s}`),{success:!0}}catch(t){return console.error("[NightSessionWidget] Error changing symbol:",t),this.showError(`Failed to load data for ${s}`),{success:!1,error:`Failed to load ${s}`}}}async initialize(){this.showLoading(),await this.validateInitialSymbol(),this.loadingTimeout=setTimeout((()=>{this.debug&&console.log("[NightSessionWidget] Loading timeout - no data received for:",this.symbol),this.hideLoading(),this.showNoDataState({Symbol:this.symbol,NotFound:!0,message:"No data available for this symbol"})}),1e4),this.subscribeToData()}async validateInitialSymbol(){try{const t=this.wsManager.getApiService();if(!t)return void(this.debug&&console.log("[NightSessionWidget] API service not available for initial validation"));const e=await t.quotel1(this.symbol);if(e&&e.data&&e.data[0]){const t=e.data[0];this.companyName=t.comp_name||"",this.exchangeName=t.market_name||"",this.mic=t.mic||"",this.debug&&console.log("[NightSessionWidget] Initial symbol validated:",{symbol:this.symbol,companyName:this.companyName,exchangeName:this.exchangeName,mic:this.mic})}}catch(t){this.debug&&console.warn("[NightSessionWidget] Initial symbol validation failed:",t)}}subscribeToData(){const t="bruce"===this.source?"querybrucel1":"queryblueoceanl1";this.unsubscribe=this.wsManager.subscribe(this.widgetId,[t],this.handleMessage.bind(this),this.symbol)}handleData(t){if(this.loadingTimeout&&(clearTimeout(this.loadingTimeout),this.loadingTimeout=null),"error"===t.type&&t.noData)return this.debug&&console.log("[NightSessionWidget] Received no data message:",t.message),void(this.data?(this.hideLoading(),this.debug&&console.log("[NightSessionWidget] No new data, keeping cached data visible")):this.showNoDataState({Symbol:this.symbol,NotFound:!0,message:t.message}));if("error"!==t.type){if(Array.isArray(t)){const e=t.find((t=>t.Symbol===this.symbol));if(e){if(this.debug&&console.log("[NightSessionWidget] Found data for symbol:",e),!0===e.NotFound)this.data?(this.hideLoading(),this.debug&&console.log("[NightSessionWidget] No new data, keeping cached data visible")):this.showNoDataState(e);else{const t=new y(e);this.data=t,this.updateWidget(t)}return}this.data?(this.hideLoading(),this.debug&&console.log("[NightSessionWidget] No matching data in response, keeping cached data")):this.showNoDataState({Symbol:this.symbol,NotFound:!0})}else if("queryblueoceanl1"===t.type||"querybrucel1"===t.type)if(t[0]?.Symbol===this.symbol)if(!0!==t[0].NotFound&&t[0].MarketName&&"BLUE"===t[0].MarketName){const e=new y(t[0]);this.data=e,this.updateWidget(e)}else this.data?(this.hideLoading(),this.debug&&console.log("[NightSessionWidget] No new data, keeping cached data visible")):this.showNoDataState(t[0]);else this.debug&&console.log("[NightSessionWidget] No matching symbol in response, keeping cached data"),this.hideLoading();t._cached}else{const e=t.message||"Server error";e.toLowerCase().includes("access")||e.toLowerCase().includes("permission")||e.toLowerCase().includes("denied")?this.data?(this.hideLoading(),this.debug&&console.log("[NightSessionWidget] Access error but keeping cached data")):this.showNoDataState({Symbol:this.symbol,NotFound:!0,isAccessError:!0,message:e}):this.data?(this.hideLoading(),this.debug&&console.log("[NightSessionWidget] Error received but keeping cached data:",e)):(console.log("errorMsg",e),this.showError(e))}}updateWidget(t){if(!this.isDestroyed)try{this.hideLoading(),this.clearError();const e=this.container.querySelector(".widget-header");e&&e.classList.remove("dimmed");const n=this.container.querySelector(".price-section");n&&n.classList.remove("dimmed");const i=this.container.querySelector(".data-grid");i&&(i.style.display="grid");const s=this.container.querySelector(".no-data-state");s&&s.remove();const o=this.container.querySelector(".symbol");o&&(o.textContent=t.symbol);const a=this.container.querySelector(".night-company-name");a&&(a.textContent=this.companyName||t.companyName||"");const r=this.container.querySelector(".market-name");r&&(r.textContent=this.exchangeName||t.exchangeName||"");const c=this.container.querySelector(".current-price");c&&(c.textContent=null!==t.lastPrice?t.formatPrice():"--");const l=t.change,d=this.container.querySelector(".price-change");if(d){const e=d.querySelector(".change-value"),n=d.querySelector(".change-percent");e&&(e.textContent=null!==l&&0!==l?l:"--"),n&&(0!==t.changePercent?n.textContent=` (${t.getPriceChangePercent().toFixed(2)}%)`:n.textContent=" (0.00%)"),d.classList.remove("positive","negative","neutral"),l>0?d.classList.add("positive"):l<0?d.classList.add("negative"):d.classList.add("neutral")}const h=this.container.querySelector(".bid-price");h&&(h.textContent=null!==t.bidPrice?`$${t.bidPrice.toFixed(2)} `:"-- ×");const u=this.container.querySelector(".bid-size");u&&(u.textContent=null!==t.bidSize?`× ${t.bidSize}`:"--");const g=this.container.querySelector(".ask-price");g&&(g.textContent=null!==t.askPrice?`$${t.askPrice.toFixed(2)} `:"-- ×");const p=this.container.querySelector(".ask-size");p&&(p.textContent=null!==t.askSize?`× ${t.askSize}`:"--");const m=this.container.querySelector(".volume");m&&(m.textContent=null!==t.volume?t.formatVolume():"--");const b=this.container.querySelector(".accu-amount");b&&(b.textContent=null!==t.accuAmount?`$${t.accuAmount.toLocaleString()}`:"--");const y=this.container.querySelector(".open-price");y&&(y.textContent=null!==t.openPrice?`$${t.openPrice.toFixed(2)}`:"--");const x=this.container.querySelector(".previous-close");x&&(x.textContent=null!==t.closingPrice?`$${t.closingPrice.toFixed(2)}`:"--");const v=this.container.querySelector(".at-close-time");if(v){const e=t.quoteTime?f(new Date(t.quoteTime)):"--";v.textContent=e}const w=this.container.querySelector(".day-range");w&&(null!==t.highPrice&&null!==t.lowPrice?w.textContent=`$${t.lowPrice.toFixed(2)} - $${t.highPrice.toFixed(2)}`:w.textContent="--");const S=this.container.querySelector(".data-source");S&&(S.textContent="Source: "+t.getDataSource());const k=(t=>{if(!t)return f();const e=new Date(t);return isNaN(e.getTime())?f():f(e)})(t.quoteTime),M=this.container.querySelector(".last-update");M&&(M.textContent=`Overnight: ${k}`)}catch(t){console.error("Error updating widget:",t),this.showError("Error updating data")}}showLoading(){const t=this.container.querySelector(".widget-loading-overlay");t&&t.classList.remove("hidden")}hideLoading(){const t=this.container.querySelector(".widget-loading-overlay");t&&t.classList.add("hidden")}showError(t){this.hideLoading(),this.clearError();const e=document.createElement("div");e.className="widget-error",e.textContent=`Error: ${t}`,e.style.cssText="\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n padding: 15px 20px;\n background: #fee;\n border: 1px solid #f5c6cb;\n border-radius: 6px;\n color: #721c24;\n text-align: center;\n font-size: 14px;\n z-index: 100;\n ",this.container.appendChild(e)}clearError(){const t=this.container.querySelector(".widget-error"),e=this.container.querySelector(".widget-error-container");t&&t.remove(),e&&e.remove()}showNoDataState(){let t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};if(!this.isDestroyed)try{this.hideLoading(),this.clearError();const e=t.Symbol||this.symbol,n=this.container.querySelector(".symbol");n&&(n.textContent=e);const i=this.container.querySelector(".current-price");i&&(i.textContent="$0.00");const s=this.container.querySelector(".price-change");if(s){const t=s.querySelector(".change-value");t&&(t.textContent="+0.00");const e=s.querySelector(".change-percent");e&&(e.textContent=" (0.00%)"),s.classList.remove("positive","negative")}const o=this.container.querySelector(".widget-header");o&&o.classList.add("dimmed");const a=this.container.querySelector(".price-section");a&&a.classList.add("dimmed"),this.showNoDataMessage(e,t);const r=f(),c=this.container.querySelector(".last-update");c&&(c.textContent=`Overnight: ${r}`)}catch(t){console.error("Error showing no data state:",t),this.showError("Error displaying no data state")}}showNoDataMessage(t){let e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const n=this.container.querySelector(".data-grid");n&&(n.style.display="none");const i=this.container.querySelector(".no-data-state");i&&i.remove();const s=e.isAccessError||e.message&&e.message.toLowerCase().includes("access"),o=l("div","","no-data-state"),a=l("div","","no-data-content");if(s){const n=document.createElement("div");n.className="no-data-icon error",n.innerHTML='<svg width="32" height="32" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">\n <circle cx="12" cy="12" r="10" stroke="#ef4444" stroke-width="2"/>\n <path d="M12 8v4" stroke="#ef4444" stroke-width="2" stroke-linecap="round"/>\n <circle cx="12" cy="16" r="1" fill="#ef4444"/>\n </svg>',a.appendChild(n);const i=l("h3",String(e.message||"Access Denied"),"no-data-title error");a.appendChild(i);const s=l("p","","no-data-description");s.appendChild(document.createTextNode("You do not have permission to view night session data for "));const o=l("strong",h(t));s.appendChild(o),a.appendChild(s);const r=l("p","Contact your administrator or try a different symbol","no-data-guidance");a.appendChild(r)}else{const n=document.createElement("div");n.className="no-data-icon",n.innerHTML='<svg width="32" height="32" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">\n <circle cx="12" cy="12" r="10" stroke="#9ca3af" stroke-width="2"/>\n <path d="M12 6v6l4 2" stroke="#9ca3af" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>\n </svg>',a.appendChild(n);const i=l("h3",String(e.message||"No Data Available"),"no-data-title");a.appendChild(i);const s=l("p","","no-data-description");s.appendChild(document.createTextNode("Night session data for "));const o=l("strong",h(t));s.appendChild(o),s.appendChild(document.createTextNode(" was not found")),a.appendChild(s);const r=l("p","Please check the symbol or try again later","no-data-guidance");a.appendChild(r)}o.appendChild(a);const r=this.container.querySelector(".widget-footer");r&&r.parentNode?r.parentNode.insertBefore(o,r):this.container.appendChild(o)}destroy(){this.isDestroyed=!0,this.loadingTimeout&&(this.clearTimeout(this.loadingTimeout),this.loadingTimeout=null),this.unsubscribe&&(this.unsubscribe(),this.unsubscribe=null),this.symbolEditor&&(this.symbolEditor.destroy(),this.symbolEditor=null),super.destroy()}updateSymbol(t){this.handleSymbolChange(t)}}class v{constructor(){let t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};this.rawData=t,this.symbol=t.Symbol||"",this.rootSymbol=t.RootSymbol||"",this.underlying=t.Underlying||"",this.expire=t.Expire||"",this.strike=t.Strike||0,this.type=this.determineOptionType(),this.lastPrice=t.LastPx||0,this.closePx=t.ClosePx||0,this.yestClosePx=t.YestClosePx||0,this.openPx=t.OpenPx||0,this.highPx=t.HighPx||0,this.lowPx=t.LowPx||0,this.bidPx=t.BidPx||0,this.bidSz=t.BidSz||0,this.bidExch=t.BidExch||"",this.askPx=t.AskPx||0,this.askSz=t.AskSz||0,this.askExch=t.AskExch||"",this.volume=t.Volume||0,this.openInterest=t.OpenInst||0,this.primeShare=t.PrimeShare||0,this.exch=t.Exch||"",this.dataSource=t.DataSource||"",this.quoteTime=t.QuoteTime||"",this.notFound=t.NotFound||!1}determineOptionType(){return this.symbol?this.symbol.includes("C")?"call":this.symbol.includes("P")?"put":"unknown":"unknown"}getChange(){return this.lastPrice-this.yestClosePx}getChangePercent(){return 0===this.yestClosePx?0:(this.lastPrice-this.yestClosePx)/this.yestClosePx*100}getSpread(){return this.askPx-this.bidPx}getSpreadPercent(){const t=(this.askPx+this.bidPx)/2;return 0===t?0:(this.askPx-this.bidPx)/t*100}getMidPrice(){return(this.askPx+this.bidPx)/2}formatPrice(t){return t?t.toFixed(2):"0.00"}formatStrike(){return`$${this.formatPrice(this.strike)}`}formatLastPrice(){return`$${this.formatPrice(this.lastPrice)}`}formatClosePx(){return`$${this.formatPrice(this.closePx)}`}formatYestClosePx(){return`$${this.formatPrice(this.yestClosePx)}`}formatOpenPx(){return`$${this.formatPrice(this.openPx)}`}formatHighPx(){return`$${this.formatPrice(this.highPx)}`}formatLowPx(){return`$${this.formatPrice(this.lowPx)}`}formatBid(){return`$${this.formatPrice(this.bidPx)}`}formatAsk(){return`$${this.formatPrice(this.askPx)}`}formatBidSize(){return this.bidSz.toString()}formatAskSize(){return this.askSz.toString()}formatSpread(){return`$${this.formatPrice(this.getSpread())}`}formatMidPrice(){return`$${this.formatPrice(this.getMidPrice())}`}formatChange(){const t=this.getChange();return`${t>=0?"+":""}${this.formatPrice(t)}`}formatChangePercent(){const t=this.getChangePercent();return`${t>=0?"+":""}${t.toFixed(2)}%`}formatVolume(){return this.volume.toLocaleString()}formatOpenInterest(){return this.openInterest.toLocaleString()}formatPrimeShare(){return this.primeShare.toString()}formatExpirationDate(){if(!this.expire)return"N/A";try{return new Date(this.expire).toLocaleDateString("en-US",{year:"numeric",month:"short",day:"numeric"})}catch(t){return this.expire}}formatQuoteTime(){if(!this.quoteTime)return"N/A";try{return new Date(this.quoteTime).toLocaleString("en-US",{year:"numeric",month:"short",day:"numeric",hour:"2-digit",minute:"2-digit",second:"2-digit"})}catch(t){return this.quoteTime}}formatExchange(){return this.exch||"N/A"}formatDataSource(){return this.dataSource||"N/A"}formatDayRange(){return`$${this.formatPrice(this.lowPx)} - $${this.formatPrice(this.highPx)}`}formatOptionType(){return this.type.toUpperCase()}getDaysToExpiration(){if(!this.expire)return 0;try{const t=new Date(this.expire),e=new Date,n=t.getTime()-e.getTime(),i=Math.ceil(n/864e5);return Math.max(0,i)}catch(t){return 0}}formatDaysToExpiration(){const t=this.getDaysToExpiration();return`${t} day${1!==t?"s":""}`}getMoneyness(t){return t&&0!==this.strike?"call"===this.type?t-this.strike:"put"===this.type?this.strike-t:0:0}isInTheMoney(t){return this.getMoneyness(t)>0}parseSymbol(){return{underlying:this.rootSymbol||"",expirationDate:this.expire||"",type:this.type||"",strikePrice:this.strike||0,fullSymbol:this.symbol||""}}getSummary(){return{symbol:this.symbol,underlying:this.underlying,type:this.formatOptionType(),strike:this.formatStrike(),expiration:this.formatExpirationDate(),lastPrice:this.formatLastPrice(),change:this.formatChange(),changePercent:this.formatChangePercent(),volume:this.formatVolume(),openInterest:this.formatOpenInterest(),bid:this.formatBid(),ask:this.formatAsk(),exchange:this.formatExchange()}}getDataSource(){return"opra-d"===this.dataSource.toLowerCase()?"20 mins delayed":"real-time"===this.dataSource.toLowerCase()?"Real-time":"MDAS Server"}static fromApiResponse(t){return new v(t)}isValid(){return!this.notFound&&this.symbol&&this.strike>0}}class w extends n{constructor(t,e,n){if(super(t,e,n),!e.symbol)throw new Error("Symbol is required for OptionsWidget");if(!e.wsManager)throw new Error("WebSocketManager is required for OptionsWidget");this.type="options";const i=p(e.symbol);if(!i.valid)throw new Error(`Invalid option symbol: ${i.error}`);this.symbol=i.sanitized,this.wsManager=e.wsManager,this.debug=e.debug||!1,this.styled=void 0===e.styled||e.styled,this.data=null,this.isDestroyed=!1,this.unsubscribe=null,this.loadingTimeout=null,this.createWidgetStructure(),this.initializeSymbolEditor(),this.initialize()}createWidgetStructure(){if(this.container.innerHTML='\n <div class="options-widget widget">\n <div class="widget-content">\n \x3c!-- Header Section with Purple Background --\x3e\n <div class="widget-header">\n <div class="symbol-section">\n <h1 class="symbol editable-symbol" \n title="Double-click to edit symbol" \n data-original-symbol="">\n </h1>\n <div class="option-info">\n <span class="underlying-symbol"></span>\n <span class="data-type">OPTIONS</span>\n </div>\n </div>\n <div class="price-section">\n <div class="current-price"></div>\n <div class="price-change">\n <span class="change-value"></span>\n <span class="change-percent"></span>\n </div>\n </div>\n </div>\n\n \x3c!-- Data Grid Section --\x3e\n <div class="data-grid">\n <div class="data-section">\n <div class="section-title">Quote</div>\n <div class="data-row">\n <span class="data-label">Bid</span>\n <span class="data-value bid-ask-value bid-data"></span>\n </div>\n <div class="data-row">\n <span class="data-label">Ask</span>\n <span class="data-value bid-ask-value ask-data"></span>\n </div>\n </div>\n\n <div class="data-section">\n <div class="section-title">Trading Activity</div>\n <div class="data-row">\n <span class="data-label">Volume</span>\n <span class="data-value volume"></span>\n </div>\n <div class="data-row">\n <span class="data-label">Open Interest</span>\n <span class="data-value open-interest"></span>\n </div>\n </div>\n\n <div class="data-section">\n <div class="section-title">Performance</div>\n <div class="data-row">\n <span class="data-label">Previous Close</span>\n <span class="data-value yesterday-close"></span>\n </div>\n <div class="data-row">\n <span class="data-label">Open</span>\n <span class="data-value open-price"></span>\n </div>\n <div class="data-row">\n <span class="data-label">Day Range</span>\n <span class="data-value range-value day-range"></span>\n </div>\n </div>\n\n <div class="data-section">\n <div class="section-title">Contract Info</div>\n <div class="data-row">\n <span class="data-label">Strike Price</span>\n <span class="data-value strike-price"></span>\n </div>\n <div class="data-row">\n <span class="data-label">Expiration</span>\n <span class="data-value expiry-date"></span>\n </div>\n <div class="data-row">\n <span class="data-label">Prime Share</span>\n <span class="data-value prime-share"></span>\n </div>\n </div>\n </div>\n\n \x3c!-- Footer --\x3e\n <div class="widget-footer">\n <span class="last-update"></span>\n <span class="data-source"></span>\n </div>\n </div>\n \n \x3c!-- Loading Overlay --\x3e\n <div class="widget-loading-overlay">\n <div class="loading-content">\n <div class="loading-spinner"></div>\n <span class="loading-text">Loading options data...</span>\n </div>\n </div>\n </div>\n',this.styled){const t=this.container.querySelector(".options-widget");t&&t.classList.add("widget-styled")}this.addStyles()}addStyles(){if(!document.querySelector("#options-widget-styles")){const t=document.createElement("style");t.id="options-widget-styles",t.textContent=c,document.head.appendChild(t)}}initializeSymbolEditor(){this.symbolEditor=new s(this,{maxLength:20,placeholder:"Enter option contract...",onSymbolChange:this.handleSymbolChange.bind(this),debug:this.debug,autoUppercase:!0,symbolType:"optionsl1"});const t=this.container.querySelector(".symbol");t&&(t.textContent=this.symbol,t.dataset.originalSymbol=this.symbol)}async handleSymbolChange(t){this.debug&&console.log("[OptionsWidget] Symbol change requested:",t);const e=p(t);if(!e.valid)return this.debug&&console.log("[OptionsWidget] Invalid option symbol:",e.error),{success:!1,error:e.error};const n=e.sanitized;if(n===this.symbol)return this.debug&&console.log("[OptionsWidget] Same symbol, no change needed"),{success:!0};try{const t=this.symbol;return this.showLoading(),this.loadingTimeout&&this.clearTimeout(this.loadingTimeout),this.loadingTimeout=this.setTimeout((()=>{this.debug&&console.log("[OptionsWidget] Loading timeout for symbol:",n),this.hideLoading(),this.showError(`No data received for ${n}. Please try again.`)}),1e4),this.unsubscribe&&(this.debug&&console.log(`[OptionsWidget] Unsubscribing from ${t}`),this.wsManager.sendUnsubscribe("queryoptionl1",t),this.unsubscribe(),this.unsubscribe=null),this.symbol=n,this.debug&&console.log(`[OptionsWidget] Subscribing to ${n}`),this.subscribeToData(),this.debug&&console.log(`[OptionsWidget] Successfully changed symbol from ${t} to ${n}`),{success:!0}}catch(t){return console.error("[OptionsWidget] Error changing symbol:",t),this.showError(`Failed to load data for ${n}`),{success:!1,error:`Failed to load ${n}`}}}async initialize(){this.showLoading(),await this.validateInitialSymbol(),this.subscribeToData()}async validateInitialSymbol(){try{const t=this.wsManager.getApiService();if(!t)return void(this.debug&&console.log("[OptionsWidget] API service not available for initial validation"));const e=await t.quoteOptionl1(this.symbol);if(e&&e[0]&&!e[0].error&&!e[0].not_found){const t=e[0];this.initialValidationData=t,this.debug&&console.log("[OptionsWidget] Initial symbol validated:",{symbol:this.symbol,underlying:t.Underlying||t.RootSymbol})}}catch(t){this.debug&&console.warn("[OptionsWidget] Initial symbol validation failed:",t)}}subscribeToData(){this.unsubscribe=this.wsManager.subscribe(this.widgetId,["queryoptionl1"],this.handleMessage.bind(this),this.symbol)}handleData(t){if(this.loadingTimeout&&(clearTimeout(this.loadingTimeout),this.loadingTimeout=null),"error"!==t.type){if(t.RootSymbol===this.symbol||t.Underlying===this.symbol||t.Symbol?.includes(this.symbol))if(this.debug&&console.log("[OptionsWidget] Found matching options data for",this.symbol,":",t),!0===t.NotFound)this.data?(this.hideLoading(),this.debug&&console.log("[OptionsWidget] No new data, keeping cached data visible")):this.showNoDataState(t);else{const e=new v(t);this.data=e,this.updateWidget(e)}else if(Array.isArray(t)){const e=t.find((t=>t.RootSymbol===this.symbol||t.Underlying===this.symbol||t.Symbol?.includes(this.symbol)));if(e)if(!0===e.NotFound)this.data?(this.hideLoading(),this.debug&&console.log("[OptionsWidget] No new data, keeping cached data visible")):this.showNoDataState(e);else{const t=new v(e);this.data=t,this.updateWidget(t)}else this.debug&&console.log("[OptionsWidget] No matching data in response, keeping cached data"),this.hideLoading()}t._cached&&this.showConnectionQuality()}else{const e=t.message||"Server error";this.data?(this.hideLoading(),this.debug&&console.log("[OptionsWidget] Error received but keeping cached data:",e)):this.showError(e)}}showNoDataState(t){if(!this.isDestroyed)try{this.hideLoading();const e=t.Symbol||this.symbol,n=this.container.querySelector(".symbol");n&&(n.textContent=e);const i=this.container.querySelector(".underlying-symbol");i&&(i.textContent=t.RootSymbol||this.symbol);const s=this.container.querySelector(".current-price");s&&(s.textContent="$0.00");const o=this.container.querySelector(".price-change");if(o){const t=o.querySelector(".change-value");t&&(t.textContent="+0.00");const e=o.querySelector(".change-percent");e&&(e.textContent=" (0.00%)"),o.classList.remove("positive","negative")}const a=this.container.querySelector(".widget-header");a&&a.classList.add("dimmed"),this.showNoDataMessage(e);const r=f(),c=this.container.querySelector(".last-update");c&&(c.textContent=`Checked: ${r}`)}catch(t){console.error("Error showing no data state:",t),this.showError("Error displaying no data state")}}showNoDataMessage(t){const e=this.container.querySelector(".data-grid"),n=this.container.querySelector(".option-details-section");e&&(e.style.display="none"),n&&(n.style.display="none");const i=this.container.querySelector(".no-data-state");i&&i.remove();const s=l("div","","no-data-state"),o=l("div","","no-data-content"),a=document.createElement("div");a.className="no-data-icon",a.innerHTML='<svg width="48" height="48" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">\n <circle cx="12" cy="12" r="10" stroke="#9ca3af" stroke-width="2"/>\n <path d="M12 6v6l4 2" stroke="#9ca3af" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>\n </svg>',o.appendChild(a);const r=l("h3","No Data Available","no-data-title");o.appendChild(r);const c=l("p","","no-data-description");c.appendChild(document.createTextNode("Data for "));const d=l("strong",String(t));c.appendChild(d),c.appendChild(document.createTextNode(" was not found")),o.appendChild(c);const h=l("p","Please check the symbol or try again later","no-data-guidance");o.appendChild(h),s.appendChild(o);const u=this.container.querySelector(".widget-footer");u&&u.parentNode?u.parentNode.insertBefore(s,u):this.container.appendChild(s)}updateWidget(t){if(!this.isDestroyed)try{this.loadingTimeout&&(clearTimeout(this.loadingTimeout),this.loadingTimeout=null),this.hideLoading(),this.clearError();const e=this.container.querySelector(".widget-header");e&&e.classList.remove("dimmed");const n=this.container.querySelector(".data-grid");n&&(n.style.display="grid");const i=this.container.querySelector(".no-data-state");i&&i.remove();const s=this.container.querySelector(".symbol");s&&(s.textContent=t.symbol,s.dataset.originalSymbol=t.symbol);const o=this.container.querySelector(".underlying-symbol");o&&(o.textContent=t.rootSymbol||t.underlying||"QQQ");const a=this.container.querySelector(".current-price");a&&(a.textContent=t.formatLastPrice());const r=t.getChange(),c=this.container.querySelector(".price-change");if(c){const e=c.querySelector(".change-value"),n=c.querySelector(".change-percent");e&&(e.textContent=t.formatChange()),n&&(n.textContent=` (${t.formatChangePercent()})`),c.classList.remove("positive","negative","neutral"),r>0?c.classList.add("positive"):r<0?c.classList.add("negative"):c.classList.add("neutral")}const d=this.container.querySelector(".bid-data");if(d){u(d),d.appendChild(document.createTextNode(t.formatBid()));const e=l("span",`× ${t.bidSz}`,"size-info");d.appendChild(e)}const h=this.container.querySelector(".ask-data");if(h){u(h),h.appendChild(document.createTextNode(t.formatAsk()));const e=l("span",`× ${t.askSz}`,"size-info");h.appendChild(e)}const g=this.container.querySelector(".volume");g&&(g.textContent=t.formatVolume());const p=this.container.querySelector(".open-interest");p&&(p.textContent=t.formatOpenInterest());const m=this.container.querySelector(".day-range");m&&(m.textContent=t.formatDayRange());const b=this.container.querySelector(".open-price");b&&(b.textContent=t.formatOpenPx());const y=this.container.querySelector(".yesterday-close");y&&(y.textContent=t.formatYestClosePx());const x=this.container.querySelector(".strike-price");x&&(x.textContent=t.formatStrike());const v=this.container.querySelector(".expiry-date");v&&(v.textContent=t.formatExpirationDate());const w=this.container.querySelector(".prime-share");w&&(w.textContent=t.formatPrimeShare());const S=f(t.quoteTime||Date.now()),k=this.container.querySelector(".last-update");k&&(k.textContent=`Last update: ${S}`);const M=this.container.querySelector(".data-source");M&&(M.textContent=`Source: ${t.getDataSource()}`)}catch(t){console.error("Error updating options widget:",t),this.showError("Error updating data")}}formatPrice(t){return t?t.toFixed(2):"0.00"}formatPriceChange(t){return`${t>=0?"+":""}${t.toFixed(2)}`}showLoading(){const t=this.container.querySelector(".widget-loading-overlay");t&&t.classList.remove("hidden")}hideLoading(){const t=this.container.querySelector(".widget-loading-overlay");t&&t.classList.add("hidden")}showError(t){this.hideLoading(),this.clearError();const e=document.createElement("div");e.className="widget-error",e.textContent=`Error: ${t}`,e.style.cssText="\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n padding: 15px 20px;\n background: #fee;\n border: 1px solid #f5c6cb;\n border-radius: 6px;\n color: #721c24;\n text-align: center;\n font-size: 14px;\n z-index: 100;\n ",this.container.appendChild(e)}clearError(){const t=this.container.querySelector(".widget-error"),e=this.container.querySelector(".widget-error-container");t&&t.remove(),e&&e.remove()}destroy(){this.isDestroyed=!0,this.loadingTimeout&&(this.clearTimeout(this.loadingTimeout),this.loadingTimeout=null),this.unsubscribe&&(this.unsubscribe(),this.unsubscribe=null),this.symbolEditor&&(this.symbolEditor.destroy(),this.symbolEditor=null),super.destroy()}}class S{constructor(){let t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};this.openInterest=t.OpenInst||0,this.volume=t.Vol||0,this.askSize=t.AskSz||0,this.bidSize=t.BidSz||0,this.strike=t.Strike||0,this.askPrice=t.AskPx||0,this.bidPrice=t.BidPx||0,this.lastChange=t.LastChg||0,this.lastPrice=t.LastPx||0,this.dataSource=t.DataSource||"",this.expire=t.Expire||"",this.symbol=t.Symbol||""}}const k=`\n${o}\n\n/* Base styles remain the same until responsive section */\n.option-chain-widget {\n border: 1px solid #e5e7eb;\n border-radius: 8px;\n background: white;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n font-size: 13px;\n max-width: 100%;\n overflow: hidden;\n position: relative;\n}\n\n.option-chain-widget .widget-header {\n background: #f9fafb;\n padding: 16px;\n border-bottom: 1px solid #e5e7eb;\n}\n\n.option-chain-widget .input-section {\n display: flex;\n gap: 12px;\n align-items: center;\n flex-wrap: wrap;\n}\n\n.option-chain-widget .symbol-input,\n.option-chain-widget .date-select {\n padding: 8px 12px;\n border: 1px solid #d1d5db;\n border-radius: 4px;\n font-size: 14px;\n font-family: inherit;\n min-width: 0;\n flex: 1;\n}\n\n.option-chain-widget .symbol-input {\n text-transform: uppercase;\n min-width: 100px;\n max-width: 120px;\n}\n\n.option-chain-widget .date-select {\n min-width: 140px;\n background: white;\n}\n\n.option-chain-widget .fetch-button {\n padding: 8px 16px;\n background: #3b82f6;\n color: white;\n border: none;\n border-radius: 4px;\n font-size: 14px;\n cursor: pointer;\n font-family: inherit;\n white-space: nowrap;\n}\n\n.option-chain-widget .fetch-button:hover {\n background: #2563eb;\n}\n\n.option-chain-widget .fetch-button:disabled {\n background: #9ca3af;\n cursor: not-allowed;\n}\n\n.option-chain-widget .date-select:disabled {\n background: #f3f4f6;\n color: #9ca3af;\n cursor: not-allowed;\n}\n\n.option-chain-widget .option-chain-table {\n max-height: 800px;\n overflow-x: auto; /* Enable horizontal scrolling */\n overflow-y: auto; /* Enable vertical scrolling if needed */\n -webkit-overflow-scrolling: touch; /* Smooth scrolling on iOS */\n width: 100%; /* Ensure full width */\n position: relative; /* Establish positioning context */\n box-sizing: border-box; /* Include padding and border in the element's total width and height */\n}\n\n.option-chain-widget .table-header {\n background: #f3f4f6;\n font-weight: 600;\n border-bottom: 2px solid #d1d5db;\n position: sticky;\n top: 0;\n z-index: 10;\n width: fit-content; /* Ensure it spans the full width */\n box-sizing: border-box; /* Include padding and border in the element's total width and height */\n}\n\n.option-chain-widget .price-change.positive::before,\n.option-chain-widget .price-change.negative::before {\n content: none;\n}\n \n\n/* Better approach - make section headers align with actual column structure */\n.option-chain-widget .section-headers,\n.option-chain-widget .column-headers {\n\n display: grid;\n grid-template-columns: minmax(160px, 1fr) repeat(6, minmax(80px, 1fr)) 80px minmax(160px, 1fr) repeat(6, minmax(80px, 1fr));\n border-bottom: 1px solid #d1d5db;\n background: #f3f4f6;\n position: sticky;\n top: 0;\n z-index: 12;\n box-sizing: border-box; /* Include padding and border in the element's total width and height */\n margin: 0;\n padding: 0;\n min-width: fit-content;\n}\n\n.option-chain-widget .calls-header {\n grid-column: 1 / 8; /* Span across first 7 columns */\n padding: 8px;\n text-align: center;\n font-weight: 600;\n font-size: 14px;\n color: #374151;\n display: flex;\n align-items: center;\n justify-content: center;\n background: #f3f4f6;\n}\n\n.option-chain-widget .strike-header {\n grid-column: 8 / 9; /* Strike column */\n background: #e5e7eb;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.option-chain-widget .puts-header {\n grid-column: 9 / -1; /* Span from column 9 to the end */\n padding: 8px;\n text-align: center;\n font-weight: 600;\n font-size: 14px;\n color: #374151;\n display: flex;\n align-items: center;\n justify-content: center;\n background: #f3f4f6;\n}\n\n.option-chain-widget .column-headers {\n display: grid;\n grid-template-columns: minmax(160px, 1fr) repeat(6, minmax(80px, 1fr)) 80px minmax(160px, 1fr) repeat(6, minmax(80px, 1fr));\n position: sticky;\n top: 40px;\n z-index: 11;\n background: #f3f4f6;\n}\n\n.option-chain-widget .calls-columns,\n.option-chain-widget .puts-columns {\n display: contents; /* Remove their own grid, use parent grid */\n}\n\n.option-chain-widget .strike-column {\n display: flex;\n align-items: center;\n justify-content: center;\n background: #e5e7eb !important;\n font-weight: bold;\n color: #374151;\n font-size: 11px;\n text-transform: uppercase;\n}\n\n.option-chain-widget .strike-column span {\n background: transparent !important; /* Ensure span doesn't override parent background */\n}\n\n.option-chain-widget .column-headers span {\n padding: 6px 2px; /* Reduce padding to prevent text overflow */\n text-align: center;\n font-size: 11px; /* Reduce font size */\n text-transform: uppercase;\n color: #6b7280;\n font-weight: 600;\n letter-spacing: 0.3px; /* Reduce letter spacing */\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n background: #f3f4f6;\n}\n\n.option-chain-widget .option-row {\n display: grid;\n grid-template-columns: minmax(160px, 1fr) repeat(6, minmax(80px, 1fr)) 80px minmax(160px, 1fr) repeat(6, minmax(80px, 1fr));\n border-bottom: 1px solid #f3f4f6;\n min-height: 32px;\n}\n\n.option-chain-widget .option-row:hover {\n background: #f9fafb;\n}\n .option-chain-widget .option-row:hover .calls-data span,\n.option-chain-widget .option-row:hover .puts-data span,\n.option-chain-widget .option-row:hover .strike-data {\n background: #f9fafb;\n}\n\n.option-chain-widget .calls-data,\n.option-chain-widget .puts-data {\n display: contents; /* Make children participate in parent grid */\n}\n\n.option-chain-widget .strike-data {\n display: flex;\n align-items: center;\n justify-content: center;\n background: #f9fafb;\n font-weight: 600; /* Changed from bold to 600 for consistency */\n color: #6b7280; /* Changed from #1f2937 to match other widgets */\n}\n\n.option-chain-widget .calls-data span,\n.option-chain-widget .puts-data span {\n padding: 6px 4px;\n text-align: center;\n font-size: 12px; /* Changed from 12px to 14px */\n font-weight: 400; /* Added to match data values in other widgets */\n color: #111827; /* Changed from #374151 to match other widgets */\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.option-chain-widget .contract-cell {\n font-size: 10px;\n color: #6b7280;\n text-align: left;\n padding: 4px 6px;\n font-family: monospace;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.option-chain-widget .positive {\n color: #059669;\n}\n\n.option-chain-widget .negative {\n color: #dc2626;\n}\n\n.option-chain-widget .neutral {\n color: #6b7280;\n}\n\n.option-chain-widget .widget-footer {\n background: #f9fafb;\n padding: 8px 16px;\n border-top: 1px solid #e5e7eb;\n text-align: center;\n font-size: 11px;\n color: #6b7280;\n}\n\n.option-chain-widget .widget-loading-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(255, 255, 255, 0.9);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 20;\n}\n\n.option-chain-widget .widget-loading-overlay.hidden {\n display: none;\n}\n\n.option-chain-widget .loading-content {\n text-align: center;\n}\n\n.option-chain-widget .loading-spinner {\n width: 32px;\n height: 32px;\n border: 3px solid #e5e7eb;\n border-top: 3px solid #3b82f6;\n border-radius: 50%;\n animation: spin 1s linear infinite;\n margin: 0 auto 12px;\n}\n\n@keyframes spin {\n 0% { transform: rotate(0deg); }\n 100% { transform: rotate(360deg); }\n}\n\n.option-chain-widget .no-data-state {\n padding: 40px;\n text-align: center;\n color: #6b7280;\n}\n\n.option-chain-widget .widget-error {\n padding: 20px;\n background: #fef2f2;\n color: #dc2626;\n border: 1px solid #fecaca;\n margin: 16px;\n border-radius: 4px;\n text-align: center;\n}\n\n/* RESPONSIVE STYLES */\n\n/* Tablet styles (768px and down) */\n@media (max-width: 768px) {\n .option-chain-widget .input-section {\n flex-direction: column;\n align-items: stretch;\n gap: 8px;\n }\n \n .option-chain-widget .symbol-input,\n .option-chain-widget .date-select {\n width: 100%;\n max-width: none;\n }\n \n .option-chain-widget .fetch-button {\n width: 100%;\n }\n \n .option-chain-widget .calls-columns,\n .option-chain-widget .puts-columns {\n grid-template-columns: 120px repeat(6, minmax(50px, 1fr));\n }\n \n .option-chain-widget .calls-data,\n .option-chain-widget .puts-data {\n grid-template-columns: 120px repeat(6, minmax(50px, 1fr));\n }\n \n .option-chain-widget .column-headers span {\n font-size: 10px;\n padding: 6px 2px;\n }\n \n .option-chain-widget .calls-data span,\n .option-chain-widget .puts-data span {\n font-size: 11px;\n padding: 4px 2px;\n }\n \n .option-chain-widget .contract-cell {\n font-size: 9px;\n padding: 4px 4px;\n }\n \n .option-chain-widget .strike-data {\n font-size: 12px;\n }\n\n /* Update responsive breakpoints to match */\n .option-chain-widget .section-headers {\n grid-template-columns: 1fr 80px 1fr;\n background: #f3f4f6;\n width: 100%;\n\n }\n}\n\n/* Mobile styles (480px and down) */\n@media (max-width: 480px) {\n .option-chain-widget {\n font-size: 12px;\n }\n \n .option-chain-widget .widget-header {\n padding: 12px;\n }\n \n .option-chain-widget .section-headers {\n grid-template-columns: 1fr 60px 1fr;\n background: #f3f4f6;\n }\n \n .option-chain-widget .column-headers {\n grid-template-columns: 1fr 60px 1fr;\n }\n \n .option-chain-widget .option-row {\n grid-template-columns: 1fr 60px 1fr;\n min-height: 28px;\n }\n \n .option-chain-widget .calls-columns,\n .option-chain-widget .puts-columns {\n grid-template-columns: 100px repeat(6, minmax(40px, 1fr));\n }\n \n .option-chain-widget .calls-data,\n .option-chain-widget .puts-data {\n grid-template-columns: 100px repeat(6, minmax(40px, 1fr));\n }\n \n .option-chain-widget .column-headers span {\n font-size: 9px;\n padding: 4px 1px;\n }\n \n .option-chain-widget .calls-data span,\n .option-chain-widget .puts-data span {\n font-size: 10px;\n padding: 3px 1px;\n }\n \n .option-chain-widget .contract-cell {\n font-size: 8px;\n padding: 3px 2px;\n }\n \n .option-chain-widget .strike-data {\n font-size: 11px;\n padding: 3px;\n }\n \n \n .option-chain-widget .option-chain-table {\n max-height: 400px;\n }\n \n .option-chain-widget .no-data-state {\n padding: 20px;\n font-size: 12px;\n }\n \n .option-chain-widget .widget-error {\n margin: 8px;\n padding: 12px;\n font-size: 12px;\n }\n}\n\n/* Very small mobile (320px and down) */\n@media (max-width: 320px) {\n .option-chain-widget .section-headers {\n grid-template-columns: 1fr 50px 1fr;\n }\n \n .option-chain-widget .column-headers {\n grid-template-columns: 1fr 50px 1fr;\n }\n \n .option-chain-widget .option-row {\n grid-template-columns: 1fr 50px 1fr;\n }\n \n .option-chain-widget .calls-columns,\n .option-chain-widget .puts-columns {\n grid-template-columns: 80px repeat(6, minmax(35px, 1fr));\n }\n \n .option-chain-widget .calls-data,\n .option-chain-widget .puts-data {\n grid-template-columns: 80px repeat(6, minmax(35px, 1fr));\n }\n \n .option-chain-widget .column-headers span {\n font-size: 8px;\n padding: 3px 1px;\n }\n \n .option-chain-widget .calls-data span,\n .option-chain-widget .puts-data span {\n font-size: 9px;\n padding: 2px 1px;\n }\n \n .option-chain-widget .contract-cell {\n font-size: 7px;\n padding: 2px 1px;\n }\n}\n`;class M extends n{constructor(t,e,n){if(super(t,e,n),!e.wsManager)throw new Error("WebSocketManager is required for OptionChainWidget");if(this.type="optionchain",this.wsManager=e.wsManager,this.debug=e.debug||!1,this.data=null,this.isDestroyed=!1,this.unsubscribe=null,this.loadingTimeout=null,e.symbol){const t=g(e.symbol);t.valid?this.symbol=t.sanitized:(console.warn("[OptionChainWidget] Invalid initial symbol:",t.error),this.symbol="")}else this.symbol="";this.date="",this.availableDates={},this.fetchRateLimiter=function(){let t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:500,e=0;return()=>{const n=Date.now(),i=n-e;return i<t?{valid:!1,error:`Please wait ${Math.ceil((t-i)/1e3)} seconds`,remainingMs:t-i}:(e=n,{valid:!0})}}(1e3),this.createWidgetStructure(),this.initialize()}createWidgetStructure(){this.container.innerHTML='\n <div class="option-chain-widget widget">\n <div class="widget-content">\n \x3c!-- Header Section --\x3e\n <div class="widget-header">\n <div class="input-section">\n <input type="text" class="symbol-input" placeholder="Enter Symbol" value="" />\n <select class="date-select" disabled>\n <option value="">Select a date...</option>\n </select>\n <button class="fetch-button" disabled>Search</button>\n </div>\n </div>\n\n \x3c!-- Data Grid Section --\x3e\n <div class="option-chain-table">\n <div class="table-header">\n <div class="section-headers">\n <div class="calls-header">Calls</div>\n <div class="strike-header"></div>\n <div class="puts-header">Puts</div>\n </div>\n <div class="column-headers">\n <div class="calls-columns">\n <span>Contract</span>\n <span>Last</span>\n <span>Change</span>\n <span>Bid</span>\n <span>Ask</span>\n <span>Volume</span>\n <span>Open Int.</span>\n </div>\n <div class="strike-column">\n <span>Strike</span>\n </div>\n <div class="puts-columns">\n <span>Contract</span>\n <span>Last</span>\n <span>Change</span>\n <span>Bid</span>\n <span>Ask</span>\n <span>Volume</span>\n <span>Open Int.</span>\n </div>\n </div>\n </div>\n <div class="option-chain-data-grid">\n \x3c!-- Option chain data will be populated here --\x3e\n </div>\n </div>\n\n \x3c!-- Footer --\x3e\n <div class="widget-footer">\n <span class="last-update"></span>\n <span class="data-source"></span>\n </div>\n </div>\n \n \x3c!-- Loading Overlay --\x3e\n <div class="widget-loading-overlay hidden">\n <div class="loading-content">\n <div class="loading-spinner"></div>\n <span class="loading-text">Loading option chain data...</span>\n </div>\n </div>\n </div>\n',this.addStyles(),this.setupEventListeners()}addStyles(){if(!document.querySelector("#option-chain-styles")){const t=document.createElement("style");t.id="option-chain-styles",t.textContent=k,document.head.appendChild(t)}}setupEventListeners(){this.symbolInput=this.container.querySelector(".symbol-input"),this.dateSelect=this.container.querySelector(".date-select"),this.fetchButton=this.container.querySelector(".fetch-button"),this.dataGrid=this.container.querySelector(".option-chain-data-grid"),this.symbol&&(this.symbolInput.value=this.symbol,this.fetchButton.disabled=!1,this.dateSelect.innerHTML='<option value="">Click search to load dates...</option>'),this.addEventListener(this.symbolInput,"input",(t=>{const e=t.target.value,n=g(e);this.clearInputError(this.symbolInput),n.valid?(this.symbol=n.sanitized,this.symbolInput.value=n.sanitized,this.dateSelect.innerHTML='<option value="">Click search to load dates...</option>',this.dateSelect.disabled=!0,this.fetchButton.disabled=!1,this.availableDates={},this.date=""):""!==e.trim()?(this.showInputError(this.symbolInput,n.error),this.fetchButton.disabled=!0):this.clearDateOptions()})),this.addEventListener(this.dateSelect,"change",(t=>{const e=t.target.value;if(!e)return void(this.date="");const n=function(t){if(!t||"string"!=typeof t)return{valid:!1,error:"Date is required",normalized:""};const e=t.trim();let n;if(/^\d{4}-\d{2}-\d{2}$/.test(e))n=new Date(e);else if(/^\d{2}\/\d{2}\/\d{4}$/.test(e)){const[t,i,s]=e.split("/");n=new Date(s,parseInt(t,10)-1,parseInt(i,10))}else{if(!/^\d+$/.test(e))return{valid:!1,error:"Invalid date format. Use YYYY-MM-DD or MM/DD/YYYY",normalized:""};n=new Date(parseInt(e,10))}return isNaN(n.getTime())?{valid:!1,error:"Invalid date",normalized:""}:{valid:!0,normalized:n.toISOString().split("T")[0]}}(e);n.valid?(this.date=n.normalized,this.symbol&&this.fetchOptionChain()):(this.showError(n.error),this.date="")})),this.addEventListener(this.fetchButton,"click",(()=>{const t=g(this.symbol);if(!t.valid)return void this.showError(t.error||"Please enter a valid symbol first");const e=this.fetchRateLimiter();e.valid?this.loadAvailableDates(t.sanitized):this.showError(e.error)}))}async loadAvailableDates(t){if(t)try{this.symbol=t,this.symbolInput.value=t,this.dateSelect.disabled=!0,this.dateSelect.innerHTML='<option value="">Loading dates...</option>',this.fetchButton.disabled=!0;const e=this.wsManager.getApiService(),n=await e.getOptionChainDates(t);console.log("Available dates:",n.dates_dictionary),this.availableDates=n.dates_dictionary||{},this.populateDateOptions()}catch(e){console.error("[OptionChainWidget] Error loading dates:",e),this.dateSelect.innerHTML='<option value="">Error loading dates</option>',this.fetchButton.disabled=!1,this.showError(`Failed to load dates for ${t}: ${e.message}`)}}populateDateOptions(){this.dateSelect.innerHTML='<option value="">Select expiration date...</option>';const t=Object.keys(this.availableDates).sort();if(0===t.length)return this.dateSelect.innerHTML='<option value="">No dates available</option>',void(this.fetchButton.disabled=!1);t.forEach((t=>{const e=document.createElement("option");e.value=t;const n=this.availableDates[t],i=function(t){let e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const{timezone:n="ET",format:i="short"}=e;if(!t||"string"!=typeof t)return"";const s=t.split("-");if(3!==s.length)return t;const[o,a,r]=s,c=parseInt(a,10)-1,l=parseInt(r,10),d=("long"===i?["January","February","March","April","May","June","July","August","September","October","November","December"]:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"])[c];return`${d} ${l}, ${o}`}(t,{timezone:m(t),format:"short"});e.textContent=i,e.className=`date-option ${n}`,this.dateSelect.appendChild(e)})),this.dateSelect.disabled=!1,this.fetchButton.disabled=!1,t.length>0&&(this.dateSelect.value=t[0],this.date=t[0],this.fetchOptionChain())}clearDateOptions(){this.dateSelect.innerHTML='<option value="">Click fetch to load dates...</option>',this.dateSelect.disabled=!0,this.fetchButton.disabled=!this.symbol,this.symbol=this.symbolInput.value.trim().toUpperCase()||"",this.date="",this.availableDates={}}initialize(){this.hideLoading(),this.symbol&&this.loadAvailableDates(this.symbol)}fetchOptionChain(){if(this.symbol&&this.date)try{this.showLoading(),this.loadingTimeout&&this.clearTimeout(this.loadingTimeout),this.loadingTimeout=this.setTimeout((()=>{this.debug&&console.log("[OptionChainWidget] Loading timeout for:",this.symbol,this.date),this.hideLoading(),this.showError(`No data received for ${this.symbol} on ${this.date}. Please try again.`)}),1e4),this.unsubscribe&&(this.unsubscribe(),this.unsubscribe=null),this.subscribeToData()}catch(t){console.error("[OptionChainWidget] Error fetching option chain:",t),this.showError(`Failed to load data for ${this.symbol}`)}else console.warn("[OptionChainWidget] Missing symbol or date")}subscribeToData(){this.unsubscribe=this.wsManager.subscribe(this.widgetId,["queryoptionchain"],this.handleMessage.bind(this),this.symbol,{date:this.date})}handleData(t){if(this.loadingTimeout&&(clearTimeout(this.loadingTimeout),this.loadingTimeout=null),"error"!==t.type)Array.isArray(t)?0===t.length?this.data?(this.hideLoading(),this.debug&&console.log("[OptionChainWidget] No new data, keeping cached data visible")):this.showNoDataState():(this.data=t,this.displayOptionChain(t)):"queryoptionchain"===t.type&&Array.isArray(t.data)&&(0===t.data.length?this.data?(this.hideLoading(),this.debug&&console.log("[OptionChainWidget] No new data, keeping cached data visible")):this.showNoDataState():(this.data=t.data,this.displayOptionChain(t.data))),t._cached&&this.showConnectionQuality();else{const e=t.message||"Server error";this.data?(this.hideLoading(),this.debug&&console.log("[OptionChainWidget] Error received but keeping cached data:",e)):this.showError(e)}}displayOptionChain(t){if(!this.isDestroyed)try{this.hideLoading(),this.clearError(),this.dataGrid.innerHTML="";const e={};t.forEach((t=>{const n=new S(t),i=n.strike;e[i]||(e[i]={call:null,put:null});"call"===C(n.symbol)?e[i].call=n:e[i].put=n}));if(Object.keys(e).sort(((t,e)=>parseFloat(t)-parseFloat(e))).forEach((t=>{const{call:n,put:i}=e[t],s=document.createElement("div");s.classList.add("option-row");const o=t=>{const e=document.createElement("span");if(!t||0===t)return e.className="neutral",e.textContent="0.00",e;const n=parseFloat(t).toFixed(2),i=t>0?"positive":t<0?"negative":"neutral",s=t>0?"+":"";return e.className=`option-chain-${i}`,e.textContent=`${s}${n}`,e},a=t=>d(t,2,"0.00"),r=document.createElement("div");r.className="calls-data",r.appendChild(l("span",n?h(n.symbol):"--","contract-cell")),r.appendChild(l("span",a(n?.lastPrice)));const c=document.createElement("span");n?c.appendChild(o(n.lastChange)):(c.textContent="0.00",c.className="neutral"),r.appendChild(c),r.appendChild(l("span",a(n?.bidPrice))),r.appendChild(l("span",a(n?.askPrice))),r.appendChild(l("span",n?String(n.volume):"0")),r.appendChild(l("span",n?String(n.openInterest):"0"));const u=document.createElement("div");u.className="strike-data",u.textContent=t;const g=document.createElement("div");g.className="puts-data",g.appendChild(l("span",i?h(i.symbol):"","contract-cell")),g.appendChild(l("span",a(i?.lastPrice)));const p=document.createElement("span");i?p.appendChild(o(i.lastChange)):(p.textContent="0.00",p.className="neutral"),g.appendChild(p),g.appendChild(l("span",a(i?.bidPrice))),g.appendChild(l("span",a(i?.askPrice))),g.appendChild(l("span",i?String(i.volume):"0")),g.appendChild(l("span",i?String(i.openInterest):"0")),s.appendChild(r),s.appendChild(u),s.appendChild(g),this.dataGrid.appendChild(s)})),t&&t.length>0){const e=f(t[0].quoteTime||Date.now()),n=this.container.querySelector(".last-update");n&&(n.textContent=`Last update: ${e}`);const i="OPRA-D"===t[0].DataSource?"20 mins delayed":"Real-time",s=this.container.querySelector(".data-source");s&&(s.textContent=`Source: ${i}`)}}catch(t){console.error("Error displaying option chain:",t),this.showError("Error displaying data")}}showLoading(){const t=this.container.querySelector(".widget-loading-overlay");t&&t.classList.remove("hidden")}hideLoading(){const t=this.container.querySelector(".widget-loading-overlay");t&&t.classList.add("hidden")}showError(t){this.hideLoading(),this.clearError();const e=document.createElement("div");e.className="widget-error",e.textContent=`Error: ${t}`,e.style.cssText="\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n padding: 15px 20px;\n background: #fee;\n border: 1px solid #f5c6cb;\n border-radius: 6px;\n color: #721c24;\n text-align: center;\n font-size: 14px;\n z-index: 100;\n ",this.container.appendChild(e)}clearError(){const t=this.container.querySelector(".widget-error"),e=this.container.querySelector(".widget-error-container");t&&t.remove(),e&&e.remove()}showNoDataState(){this.hideLoading(),this.clearError();const t=l("div","","no-data-state"),e=l("div","","no-data-content"),n=document.createElement("div");n.className="no-data-icon",n.innerHTML='<svg width="32" height="32" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">\n <circle cx="12" cy="12" r="10" stroke="#9ca3af" stroke-width="2"/>\n <path d="M12 6v6l4 2" stroke="#9ca3af" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>\n </svg>',e.appendChild(n);const i=l("h3","No Option Chain Data","no-data-title");e.appendChild(i);const s=l("p","","no-data-description");s.appendChild(document.createTextNode("Option chain data for "));const o=l("strong",h(this.symbol));s.appendChild(o),s.appendChild(document.createTextNode(" on "));const a=l("strong",String(this.date));s.appendChild(a),s.appendChild(document.createTextNode(" was not found")),e.appendChild(s);const r=l("p","Please check the symbol and date or try again later","no-data-guidance");e.appendChild(r),t.appendChild(e);const c=this.container.querySelector(".widget-footer");c&&c.parentNode?c.parentNode.insertBefore(t,c):this.container.appendChild(t)}destroy(){this.isDestroyed=!0,this.unsubscribe&&(this.unsubscribe(),this.unsubscribe=null),this.loadingTimeout&&(this.clearTimeout(this.loadingTimeout),this.loadingTimeout=null),super.destroy()}}const C=t=>{const e=t.match(/^(.+?)(\d{6})([CP])(\d{8})$/);if(e){const[,t,n,i,s]=e;return"C"===i?"call":"put"}return null};class _ extends n{constructor(t,e,n){if(super(t,e,n),!e.symbol)throw new Error("Symbol is required for DataWidget");if(!e.wsManager)throw new Error("WebSocketManager is required for DataWidget");this.type="data",this.symbol=(e.symbol||"").toString().toUpperCase(),this.wsManager=e.wsManager,this.dataSource=e.dataSource||"queryl1",this.debug=e.debug||!1,this.data=null,this.isDestroyed=!1,this.unsubscribe=null,this.loadingTimeout=null,this.createWidgetStructure(),this.initializeSymbolEditor(),this.initialize()}createWidgetStructure(){this.container.innerHTML='\n <div class="data-widget widget">\n <div class="widget-content">\n \x3c!-- Header Section --\x3e\n <div class="widget-header">\n <div class="symbol-section">\n <h1 class="symbol editable-symbol" \n title="Double-click to edit symbol" \n data-original-symbol="">\n </h1>\n <div class="company-info">\n <span class="data-type">Stock</span>\n <span class="company-name"></span>\n </div>\n </div>\n </div>\n\n \x3c!-- Price Section --\x3e\n <div class="price-section">\n <div class="current-price"></div>\n <div class="price-change">\n <span class="change-value"></span>\n <span class="change-percent"></span>\n </div>\n </div>\n\n \x3c!-- Bid/Ask Section --\x3e\n <div class="bid-ask-section">\n <div class="ask">\n <span class="label">Ask</span>\n <span class="value ask-price"></span>\n <span class="size ask-size"></span>\n </div>\n <div class="bid">\n <span class="label">Bid</span>\n <span class="value bid-price"></span>\n <span class="size bid-size"></span>\n </div>\n </div>\n\n \x3c!-- Footer --\x3e\n <div class="widget-footer">\n <span class="last-size">Last Size: <span class="trade-size"></span></span>\n <span class="source">Market Data Powered by MDAS</span>\n </div>\n </div>\n\n \n </div>\n',this.addStyles()}addStyles(){if(!document.querySelector("#data-styles")){const t=document.createElement("style");t.id="data-styles",t.textContent="\n .data-widget {\n position: relative;\n border: 1px solid #ddd;\n border-radius: 8px;\n overflow: hidden;\n background-color: #fff;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);\n padding: 10px;\n font-family: Arial, sans-serif;\n }\n\n .widget-header {\n display: flex;\n flex-direction: column;\n margin-bottom: 10px;\n }\n\n .symbol {\n font-size: 24px;\n font-weight: bold;\n margin-right: 10px;\n }\n\n .company-info {\n font-size: 12px;\n color: #666;\n }\n\n .trading-info {\n font-size: 12px;\n color: #999;\n }\n\n .price-section {\n display: flex;\n align-items: baseline;\n margin-bottom: 10px;\n }\n\n .current-price {\n font-size: 36px;\n font-weight: bold;\n margin-right: 10px;\n }\n\n .price-change {\n font-size: 18px;\n }\n\n .price-change.positive {\n color: green;\n }\n\n .price-change.negative {\n color: red;\n }\n\n .bid-ask-section {\n display: flex;\n justify-content: space-between;\n margin-bottom: 10px;\n }\n\n .ask, .bid {\n display: flex;\n align-items: center;\n }\n\n .label {\n font-size: 14px;\n margin-right: 5px;\n }\n\n .value {\n font-size: 16px;\n font-weight: bold;\n margin-right: 5px;\n }\n\n .size {\n font-size: 14px;\n color: red;\n }\n\n .widget-footer {\n font-size: 12px;\n color: #333;\n }\n",document.head.appendChild(t)}}initializeSymbolEditor(){this.symbolEditor=new s(this,{maxLength:10,placeholder:"Enter symbol...",onSymbolChange:this.handleSymbolChange.bind(this),debug:this.debug,autoUppercase:!0,symbolType:"quotel1"});const t=this.container.querySelector(".symbol");t&&(t.textContent=this.symbol,t.dataset.originalSymbol=this.symbol)}async handleSymbolChange(t){this.debug&&console.log("[DataWidget] Symbol change requested:",t);const e=t.toUpperCase();if(e===this.symbol)return this.debug&&console.log("[DataWidget] Same symbol, no change needed"),{success:!0};try{const t=this.symbol;return this.showLoading(),this.loadingTimeout&&clearTimeout(this.loadingTimeout),this.loadingTimeout=setTimeout((()=>{this.debug&&console.log("[DataWidget] Loading timeout for symbol:",e),this.hideLoading(),this.showError(`No data received for ${e}. Please try again.`)}),1e4),this.unsubscribe&&(this.debug&&console.log(`[DataWidget] Unsubscribing from ${t}`),this.wsManager.sendUnsubscribe(this.dataSource,t),this.unsubscribe(),this.unsubscribe=null),this.symbol=e,this.debug&&console.log(`[DataWidget] Subscribing to ${e}`),this.subscribeToData(),this.debug&&console.log(`[DataWidget] Successfully changed symbol from ${t} to ${e}`),{success:!0}}catch(t){return console.error("[DataWidget] Error changing symbol:",t),this.hideLoading(),this.showError(`Failed to load data for ${e}`),{success:!1,error:`Failed to load ${e}`}}}initialize(){this.showLoading(),this.subscribeToData()}subscribeToData(){this.unsubscribe=this.wsManager.subscribe(this.widgetId,[this.dataSource],this.handleMessage.bind(this),this.symbol)}showNoDataState(t){let{Symbol:e,NotFound:n,message:i}=t;this.clearError(),this.hideLoading();const s=document.createElement("div");s.className="no-data-state",s.innerHTML=`\n <div class="no-data-content">\n <div class="no-data-icon">\n <svg width="32" height="32" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">\n <circle cx="12" cy="12" r="10" stroke="#9ca3af" stroke-width="2"/>\n <path d="M12 6v6l4 2" stroke="#9ca3af" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>\n </svg>\n </div>\n <h3 class="no-data-title">No Data Available</h3>\n <p class="no-data-description">Data for <strong>${e}</strong> was not found.</p>\n <p class="no-data-guidance">${i||"Please check the symbol or try again later."}</p>\n </div>\n `,this.container.appendChild(s)}handleData(t){if(this.loadingTimeout&&(clearTimeout(this.loadingTimeout),this.loadingTimeout=null),"error"===t.type&&t.noData)return this.debug&&console.log("[DataWidget] Received no data message:",t.message),void this.showNoDataState({Symbol:this.symbol,NotFound:!0,message:t.message});if("error"!==t.type){if(t.Data&&t.Data.length>0){const e=t.Data.find((t=>t.Symbol===this.symbol));if(e){const t=new i(e);this.updateWidget(t)}else console.log("hereee"),this.showNoDataState({Symbol:this.symbol,NotFound:!0,message:`No data found for ${this.symbol}`})}t._cached&&this.showConnectionQuality()}else{const e=t.message||"Server error";this.showError(e)}}updateWidget(t){if(!this.isDestroyed)try{this.clearError(),this.hideLoading();const e=this.container.querySelector(".symbol");e&&(e.textContent=t.symbol,e.dataset.originalSymbol=t.symbol);const n=this.container.querySelector(".current-price");n&&(n.textContent=t.formatPrice());const i=this.container.querySelector(".price-change"),s=i.querySelector(".change-value"),o=i.querySelector(".change-percent");s.textContent=t.formatPriceChange(),o.textContent=` (${t.formatPriceChangePercent()})`,i.classList.remove("positive","negative","neutral"),t.getPriceChange()>0?i.classList.add("positive"):t.getPriceChange()<0?i.classList.add("negative"):i.classList.add("neutral");const a=this.container.querySelector(".bid-price");a&&(a.textContent=t.bidPrice.toFixed(2));const r=this.container.querySelector(".ask-price");r&&(r.textContent=t.askPrice.toFixed(2));const c=this.container.querySelector(".bid-size");c&&(c.textContent=`× ${t.bidSize}`);const l=this.container.querySelector(".ask-size");l&&(l.textContent=`× ${t.askSize}`);const d=this.container.querySelector(".trade-size");d&&(d.textContent=t.tradeSize);const h=this.container.querySelector(".last-update");if(h){const e=f(t.quoteTime);h.textContent=`Last update: ${e}`}const u=this.container.querySelector(".data-source");u&&(u.textContent=`Source: ${t.getDataSource()}`)}catch(t){console.error("Error updating widget:",t),this.showError("Error updating data")}}}class D extends n{constructor(t,e,n){if(super(t,e,n),!e.symbol)throw new Error("Symbol is required for CombinedMarketWidget");if(!e.wsManager)throw new Error("WebSocketManager is required for CombinedMarketWidget");const i=g(e.symbol);if(!i.valid)throw new Error(`Invalid symbol: ${i.error}`);this.type="combined-market",this.wsManager=e.wsManager,this.symbol=i.sanitized,this.debug=e.debug||!1,this.removeNightSession=!0,this.marketData=null,this.nightSessionData=null,this.unsubscribeMarket=null,this.unsubscribeNight=null,this.createWidgetStructure(),this.initializeSymbolEditor(),this.subscribeToData()}createWidgetStructure(){this.container.innerHTML='\n <div class="combined-market-widget">\n <div class="combined-market-header">\n <div class="combined-symbol-section">\n <h1 class="combined-symbol editable-symbol"\n title="Double-click to edit symbol"\n data-original-symbol="">\n </h1>\n <div class="combined-company-info">\n <span class="company-name">\n </span>\n </div>\n </div>\n </div>\n\n <div class="combined-data-container">\n \x3c!-- Regular Market Data (Left) --\x3e\n <div class="combined-market-section regular-market">\n <div class="combined-price-info">\n <div class="combined-current-price">--</div>\n <div class="combined-price-change neutral">\n <span class="combined-change-value">--</span>\n <span class="combined-change-percent">(--)</span>\n </div>\n </div>\n <div class="combined-market-status"><span class="market-status-label"></span> <span class="combined-timestamp">--</span></div>\n </div>\n\n \x3c!-- Night Session Data (Right) --\x3e\n <div class="combined-market-section night-session">\n\n <div class="combined-price-info">\n <div class="combined-current-price">--</div>\n <div class="combined-price-change neutral">\n <span class="combined-change-value">--</span>\n <span class="combined-change-percent">(--)</span>\n </div>\n </div>\n <div class="combined-market-status">Overnight: <span class="combined-timestamp">--</span></div>\n </div>\n </div>\n\n <div class="combined-loading-overlay hidden">\n <div class="combined-loading-content">\n <div class="combined-loading-spinner"></div>\n <span class="combined-loading-text">Loading market data...</span>\n </div>\n </div>\n </div>\n';const t=this.container.querySelector(".combined-symbol");if(t&&(t.textContent=this.symbol,t.dataset.originalSymbol=this.symbol),this.removeNightSession&&!this.isNightSessionActive()){const t=this.container.querySelector(".night-session");t&&(t.style.display="none")}this.addStyles()}addStyles(){if(!document.querySelector("#combined-market-styles")){const t=document.createElement("style");t.id="combined-market-styles",t.textContent='\n .combined-market-widget {\n background: #ffffff;\n color: #111827;\n padding: 24px;\n border-radius: 12px;\n border: 1px solid #e5e7eb;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);\n font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;\n position: relative;\n }\n\n .combined-market-widget .combined-market-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 24px;\n padding-bottom: 16px;\n border-bottom: 1px solid #e5e7eb;\n }\n\n .combined-market-widget .combined-symbol-section {\n display: flex;\n flex-direction: column;\n gap: 4px;\n }\n\n .combined-market-widget .combined-symbol {\n font-size: 24px;\n font-weight: 700;\n margin: 0;\n color: #111827;\n cursor: pointer;\n transition: all 0.2s ease;\n position: relative;\n }\n\n .combined-market-widget .combined-symbol:hover {\n opacity: 0.8;\n transform: scale(1.02);\n }\n\n .combined-market-widget .combined-symbol:hover::after {\n content: "✎";\n position: absolute;\n top: -8px;\n right: -8px;\n background: #3b82f6;\n color: white;\n font-size: 10px;\n padding: 2px 4px;\n border-radius: 4px;\n opacity: 0.8;\n pointer-events: none;\n }\n\n .combined-market-widget .follow-btn {\n background: #ffffff;\n border: 1px solid #d1d5db;\n color: #374151;\n padding: 8px 16px;\n border-radius: 20px;\n cursor: pointer;\n font-size: 14px;\n font-weight: 500;\n transition: all 0.2s;\n }\n\n .combined-market-widget .follow-btn:hover {\n border-color: #9ca3af;\n background: #f9fafb;\n }\n\n .combined-market-widget .combined-data-container {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 40px;\n }\n\n .combined-market-widget .combined-market-section {\n display: flex;\n flex-direction: column;\n gap: 8px;\n }\n\n .combined-market-widget .combined-price-info {\n display: flex;\n flex-direction: column;\n min-height: 90px;\n }\n\n .combined-market-widget .session-label {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 14px;\n color: #6b7280;\n margin-bottom: 4px;\n font-weight: 500;\n }\n\n .combined-market-widget .session-label .icon {\n font-size: 16px;\n }\n\n .combined-market-widget .combined-current-price {\n font-size: 48px;\n font-weight: 700;\n line-height: 1;\n color: #111827;\n }\n\n .combined-market-widget .combined-price-change {\n display: flex;\n gap: 8px;\n font-size: 20px;\n font-weight: 600;\n margin-top: 4px;\n }\n\n .combined-market-widget .combined-price-change.positive {\n color: #059669;\n }\n\n .combined-market-widget .combined-price-change.negative {\n color: #dc2626;\n }\n\n .combined-market-widget .combined-price-change.neutral {\n color: #6b7280;\n }\n\n .combined-market-widget .combined-market-status {\n font-size: 14px;\n color: #6b7280;\n margin-top: 8px;\n }\n\n .combined-market-widget .combined-timestamp {\n color: #9ca3af;\n font-weight: 400;\n }\n\n /* Loading overlay */\n .combined-market-widget .combined-loading-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(255, 255, 255, 0.95);\n backdrop-filter: blur(2px);\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 12px;\n z-index: 10;\n }\n\n .combined-market-widget .combined-loading-overlay.hidden {\n display: none;\n }\n\n .combined-market-widget .combined-loading-content {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 12px;\n }\n\n .combined-market-widget .combined-loading-spinner {\n width: 40px;\n height: 40px;\n border: 3px solid #e5e7eb;\n border-top-color: #3b82f6;\n border-radius: 50%;\n animation: combined-market-spin 1s linear infinite;\n }\n\n .combined-market-widget .combined-loading-text {\n color: #6b7280;\n font-size: 14px;\n font-weight: 500;\n }\n\n @keyframes combined-market-spin {\n to { transform: rotate(360deg); }\n }\n\n /* Responsive */\n @media (max-width: 768px) {\n .combined-market-widget .combined-data-container {\n grid-template-columns: 1fr;\n gap: 30px;\n }\n\n .combined-market-widget .combined-current-price {\n font-size: 36px;\n }\n\n .combined-market-widget .combined-price-change {\n font-size: 16px;\n }\n }\n',document.head.appendChild(t)}}initializeSymbolEditor(){this.symbolEditor=new s(this,{maxLength:10,placeholder:"Enter symbol...",onSymbolChange:this.handleSymbolChange.bind(this),debug:this.debug,autoUppercase:!0,symbolType:"quotel1"});const t=this.container.querySelector(".combined-symbol");t&&(t.textContent=this.symbol,t.dataset.originalSymbol=this.symbol)}async handleSymbolChange(t){this.debug&&console.log("[CombinedMarketWidget] Symbol change requested:",t);const e=g(t);if(!e.valid)return this.debug&&console.log("[CombinedMarketWidget] Invalid symbol:",e.error),{success:!1,error:e.error};const n=e.sanitized;if(n===this.symbol)return this.debug&&console.log("[CombinedMarketWidget] Same symbol, no change needed"),{success:!0};try{const t=this.symbol;return this.showLoading(),this.unsubscribeMarket&&(this.debug&&console.log(`[CombinedMarketWidget] Unsubscribing from market data: ${t}`),this.wsManager.sendUnsubscribe("queryl1",t),this.unsubscribeMarket(),this.unsubscribeMarket=null),this.unsubscribeNight&&(this.debug&&console.log(`[CombinedMarketWidget] Unsubscribing from night session: ${t}`),this.wsManager.sendUnsubscribe("queryblueoceanl1",t),this.unsubscribeNight(),this.unsubscribeNight=null),this.symbol=n,this.marketData=null,this.nightSessionData=null,this.debug&&console.log(`[CombinedMarketWidget] Subscribing to new symbol: ${n}`),this.subscribeToData(),this.debug&&console.log(`[CombinedMarketWidget] Successfully changed symbol from ${t} to ${n}`),{success:!0}}catch(t){return console.error("[CombinedMarketWidget] Error changing symbol:",t),this.hideLoading(),{success:!1,error:`Failed to load ${n}`}}}subscribeToData(){this.showLoading(),this.unsubscribeMarket=this.wsManager.subscribe(`${this.widgetId}-market`,["queryl1"],(t=>{const{event:e,data:n}=t;"connection"!==e?"data"===e&&(n._dataType="market",this.handleMessage({event:e,data:n})):this.handleConnectionStatus(n)}),this.symbol),this.unsubscribeNight=this.wsManager.subscribe(`${this.widgetId}-night`,["queryblueoceanl1"],(t=>{const{event:e,data:n}=t;"connection"!==e&&"data"===e&&(n._dataType="night",this.handleMessage({event:e,data:n}))}),this.symbol)}handleData(t){const e=t._dataType;if(this.debug&&console.log(`[CombinedMarketWidget] handleData called with type: ${e}`,t),e){if("error"===t.type&&t.noData)return this.debug&&console.log(`[CombinedMarketWidget] Received no data message for ${e}:`,t.message),"market"!==e||this.marketData?"night"!==e||this.nightSessionData||this.debug&&console.log("[CombinedMarketWidget] No night session data available"):this.debug&&console.log("[CombinedMarketWidget] No market data available"),void this.hideLoading();if("error"===t.type){const n=t.message||"Server error";return this.debug&&console.log(`[CombinedMarketWidget] Error received for ${e}:`,n),void this.hideLoading()}if("object"==typeof t&&t.Message){const n=t.Message.toLowerCase();if(n.includes("no data")||n.includes("not found"))return this.debug&&console.log(`[CombinedMarketWidget] No data message for ${e}:`,t.Message),void this.hideLoading()}if("market"===e){if(t.Data&&Array.isArray(t.Data)){const e=t.Data.find((t=>t.Symbol===this.symbol));e?(this.debug&&console.log("[CombinedMarketWidget] Market data received:",e),this.marketData=new i(e),this.updateMarketSection(),this.hideLoading()):(this.debug&&console.log("[CombinedMarketWidget] No market data for symbol in response, keeping cached data"),this.hideLoading())}delete t._dataType}if("night"===e){if(Array.isArray(t)){const e=t.find((t=>t.Symbol===this.symbol));e?!0!==e.NotFound&&e.MarketName&&"BLUE"===e.MarketName?(this.debug&&console.log("[CombinedMarketWidget] Night session data received:",e),this.nightSessionData=new y(e),this.updateNightSessionSection(),this.hideLoading()):(this.debug&&console.log("[CombinedMarketWidget] Night session data not found or not available"),this.hideLoading()):(this.debug&&console.log("[CombinedMarketWidget] No night session data for symbol in response, keeping cached data"),this.hideLoading())}else"queryblueoceanl1"!==t.type&&"querybrucel1"!==t.type||(t[0]?.Symbol===this.symbol?!0!==t[0].NotFound&&t[0].MarketName&&"BLUE"===t[0].MarketName?(this.debug&&console.log("[CombinedMarketWidget] Night session data received (wrapped format):",t[0]),this.nightSessionData=new y(t[0]),this.updateNightSessionSection(),this.hideLoading()):(this.debug&&console.log("[CombinedMarketWidget] Night session data not found or not available (wrapped format)"),this.hideLoading()):(this.debug&&console.log("[CombinedMarketWidget] No matching symbol in wrapped response, keeping cached data"),this.hideLoading()));delete t._dataType}t._cached&&this.showConnectionQuality()}else this.debug&&console.warn("[CombinedMarketWidget] No data type specified, attempting to infer from structure")}updateMarketSection(){if(!this.marketData)return;const t=this.container.querySelector(".regular-market"),e=this.container.querySelector(".company-name");if(e){const t=this.marketData.companyName||`${this.marketData.symbol} Inc.`,n=this.marketData.companyDescription||`${this.marketData.symbol}`;e.textContent=t,e.setAttribute("title",n),e.setAttribute("data-tooltip",n)}t.querySelector(".combined-current-price").textContent=this.marketData.formatPrice();const n=t.querySelector(".combined-price-change"),i=t.querySelector(".combined-change-value"),s=t.querySelector(".combined-change-percent"),o=this.marketData.change,a=o>0?"positive":o<0?"negative":"neutral";n.className=`combined-price-change ${a}`,i.textContent=this.marketData.formatPriceChange(),s.textContent=`(${this.marketData.formatPriceChangePercent()})`;const r=t.querySelector(".market-status-label");r&&(r.textContent=`${this.getSessionType()}:`);t.querySelector(".combined-timestamp").textContent=f(this.marketData.quoteTime,{format:"long"}),this.debug&&console.log("[CombinedMarketWidget] Updated market section:",this.marketData)}updateNightSessionSection(){if(!this.nightSessionData)return;const t=this.container.querySelector(".night-session");if(this.removeNightSession&&!this.isNightSessionActive())return t.style.display="none",void(this.debug&&console.log("[CombinedMarketWidget] Night session hidden (market closed)"));t.style.display="";const e=t.querySelector(".combined-current-price");e&&(e.textContent=this.nightSessionData.lastPrice?this.nightSessionData.formatPrice():"--");const n=t.querySelector(".combined-price-change"),i=t.querySelector(".combined-change-value"),s=t.querySelector(".combined-change-percent"),o=this.nightSessionData.change,a=o>0?"positive":o<0?"negative":"neutral";n.className=`combined-price-change ${a}`,i.textContent=null!==this.nightSessionData.change?this.nightSessionData.formatPriceChange():"--",s.textContent=`(${this.nightSessionData.formatPriceChangePercent()})`;t.querySelector(".combined-timestamp").textContent=f(this.nightSessionData.quoteTime,{format:"long"}),this.debug&&(console.log("connection quality:",this.connectionQuality),console.log("[CombinedMarketWidget] Updated night session section:",this.nightSessionData))}getSessionType(){const t=(new Date).toLocaleString("en-US",{timeZone:"America/New_York"}),e=new Date(t),n=e.getHours(),i=e.getMinutes(),s=60*n+i;return console.log("Current EST time:",n+":"+(i<10?"0":"")+i),s>=240&&s<570?"Pre-Market":s>=570&&s<960?"Market Hours":s>=960&&s<1200?"Post-Market":"Market Closed"}isNightSessionActive(){return"Market Closed"===this.getSessionType()}destroy(){this.unsubscribeMarket&&(this.unsubscribeMarket(),this.unsubscribeMarket=null),this.unsubscribeNight&&(this.unsubscribeNight(),this.unsubscribeNight=null),this.symbolEditor&&(this.symbolEditor.destroy(),this.symbolEditor=null),super.destroy()}}class T{constructor(t){Array.isArray(t)?(console.log("[IntradayChartModel] Processing",t.length,"raw data points"),t.length>0&&console.log("[IntradayChartModel] Sample raw point:",t[0]),this.dataPoints=t.map(((t,e)=>{const n={symbol:t.symbol||t.Symbol,time:t.time||t.Time||t.timestamp||t.Timestamp,open:parseFloat(t.open||t.Open)||0,high:parseFloat(t.high||t.High)||0,low:parseFloat(t.low||t.Low)||0,close:parseFloat(t.close||t.Close)||0,volume:parseInt(t.volume||t.Volume)||0,source:t.source||t.Source};return e<2&&console.log(`[IntradayChartModel] Processed point ${e}:`,n),n.time||console.warn(`[IntradayChartModel] Point ${e} missing time:`,t),0===n.close&&console.warn(`[IntradayChartModel] Point ${e} has zero close price:`,t),n})).filter((t=>{if(!t.time||t.close<=0)return!1;const e=new Date(t.time).getTime();return!(isNaN(e)||e<9466848e5)||(console.warn("[IntradayChartModel] Invalid timestamp:",t.time),!1)})),this.dataPoints.sort(((t,e)=>new Date(t.time).getTime()-new Date(e.time).getTime())),console.log("[IntradayChartModel] Valid data points after filtering:",this.dataPoints.length),this.dataPoints.length>0&&console.log("[IntradayChartModel] Time range:",this.dataPoints[0].time,"to",this.dataPoints[this.dataPoints.length-1].time)):(console.warn("[IntradayChartModel] Expected array of data points, got:",typeof t),this.dataPoints=[]),this.symbol=this.dataPoints.length>0?this.dataPoints[0].symbol:null,this.source=this.dataPoints.length>0?this.dataPoints[0].source:null}getTimeLabels(){return this.dataPoints.map((t=>{const e=new Date(t.time);let n=e.getHours();const i=n>=12?"PM":"AM";n%=12,n=n||12;return[`${n}:${e.getMinutes().toString().padStart(2,"0")} ${i}`,`${(e.getMonth()+1).toString().padStart(2,"0")}/${e.getDate().toString().padStart(2,"0")}`]}))}getOHLCData(){return this.dataPoints.map((t=>({x:new Date(t.time).getTime(),o:t.open,h:t.high,l:t.low,c:t.close})))}getClosePrices(){return this.dataPoints.map((t=>t.close))}getVolumeData(){return this.dataPoints.map((t=>t.volume))}getHighPrices(){return this.dataPoints.map((t=>t.high))}getLowPrices(){return this.dataPoints.map((t=>t.low))}getOpenPrices(){return this.dataPoints.map((t=>t.open))}getStats(){if(0===this.dataPoints.length)return{high:0,low:0,open:0,close:0,change:0,changePercent:0,volume:0};this.getClosePrices();const t=this.getHighPrices(),e=this.getLowPrices(),n=this.getVolumeData(),i=this.dataPoints[0],s=this.dataPoints[this.dataPoints.length-1],o=s.close-i.open,a=0!==i.open?o/i.open*100:0;return{high:Math.max(...t),low:Math.min(...e),open:i.open,close:s.close,change:o,changePercent:a,volume:n.reduce(((t,e)=>t+e),0),dataPoints:this.dataPoints.length}}formatPrice(t){return t.toFixed(2)}formatVolume(t){return t>=1e6?(t/1e6).toFixed(2)+"M":t>=1e3?(t/1e3).toFixed(2)+"K":t.toString()}}
1
+ !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).MdasSDK={})}(this,(function(t){"use strict";class e{constructor(){this.state=new Map,this.listeners=new Map}setState(t,e){this.state.set(t,e),this.notifyListeners(t,e)}getState(t){return this.state.get(t)}subscribe(t,e){return this.listeners.has(t)||this.listeners.set(t,new Set),this.listeners.get(t).add(e),()=>{const n=this.listeners.get(t);n&&n.delete(e)}}notifyListeners(t,e){const n=this.listeners.get(t);n&&n.forEach((t=>t(e)))}clear(){this.state.clear(),this.listeners.clear()}}class n{constructor(t,e,n){this.setContainer(t),this.options=e,this.widgetId=n,this.isDestroyed=!1,this.lastData=null,this.lastDataTimestamp=null,this.connectionQuality="disconnected",this.eventListeners=[],this.timeouts=[],this.intervals=[]}setContainer(t){if(!t)throw new Error("DOM element is required for widget");if("string"==typeof t){const e=document.querySelector(t);if(!e)throw new Error(`Element not found: ${t}`);this.container=e}else{if(t.nodeType!==Node.ELEMENT_NODE)throw new Error("Invalid element provided to widget");this.container=t}}showLoading(){const t=this.container.querySelector(".widget-loading-overlay");t&&t.classList.remove("hidden")}hideLoading(){const t=this.container.querySelector(".widget-loading-overlay");t&&t.classList.add("hidden")}showError(t){this.hideLoading(),this.clearError();const e=document.createElement("div");e.className="widget-error",e.textContent=`Error: ${t}`,this.container.appendChild(e)}clearError(){const t=this.container.querySelector(".widget-error");t&&t.remove()}showConnectionQuality(){const t=this.container.querySelector(".connection-quality");if(t&&t.remove(),"live"===this.connectionQuality)return;const e=this.container.querySelector('.last-update, [class*="last-update"], [class*="timestamp"]');if(e){const t=document.createElement("span");switch(t.className="connection-quality",this.connectionQuality){case"offline":t.textContent=" (disconnected)",t.style.color="#dc2626",t.style.fontWeight="500";break;case"reconnecting":t.textContent=" (reconnecting...)",t.style.color="#d97706"}t.style.fontSize="11px",e.appendChild(t)}}handleMessage(t){if(!this.isDestroyed)try{const{event:e,data:n}=t;if(console.log("[BaseWidget] handleMessage called with event:",e,"data:",n),this.debug&&console.log(`[${this.type}] Received:`,e,n),"connection"===e)return void this.handleConnectionStatus(n);if("data"===e)return console.log("[BaseWidget] Caching live data"),this.lastData=n,this.lastDataTimestamp=Date.now(),this.connectionQuality="live",void this.handleData(n);if("session_revoked"===e)return void this.handleSessionRevoked(n);this.handleCustomEvent&&this.handleCustomEvent(e,n)}catch(t){console.error(`[${this.constructor.name}] Error handling message:`,t),this.showError("Error processing data")}}handleSessionRevoked(t){"attempting_relogin"===t.status?(this.connectionQuality="reconnecting",this.lastData?this.showCachedData():this.showLoading()):"relogin_failed"===t.status?(this.connectionQuality="offline",this.showError(t.error||"Session expired. Please refresh the page.")):"relogin_successful"===t.status&&(this.connectionQuality="live",this.hideLoading(),this.clearError())}handleData(t){throw new Error("handleData must be implemented by child widget")}handleConnectionStatus(t){"connected"===t.status?(this.connectionQuality="live",this.clearError(),this.hideLoading()):"reconnecting"===t.status?(this.connectionQuality="reconnecting",this.lastData?this.showCachedData():this.showLoading()):"disconnected"===t.status?(this.connectionQuality="offline",this.lastData?this.showCachedData():this.hideLoading()):"failed"===t.status?(this.connectionQuality="offline",this.handleConnectionFailed(t),this.showConnectionQuality()):"error"===t.status&&(this.connectionQuality="offline",this.lastData?this.showCachedData():this.hideLoading())}showCachedData(){if(this.lastData&&this.lastDataTimestamp){const t=Date.now()-this.lastDataTimestamp,e=t>3e5,n={...this.lastData,_cached:!0,_cacheAge:t,_isStale:e,_quality:this.connectionQuality};this.handleData(n)}}addEventListener(t,e,n){let i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{};t&&e&&n?(t.addEventListener(e,n,i),this.eventListeners.push({element:t,event:e,handler:n,options:i})):console.warn("[BaseWidget] Invalid addEventListener parameters")}setTimeout(t,e){const n=setTimeout(t,e);return this.timeouts.push(n),n}setInterval(t,e){const n=setInterval(t,e);return this.intervals.push(n),n}clearTimeout(t){clearTimeout(t);const e=this.timeouts.indexOf(t);e>-1&&this.timeouts.splice(e,1)}clearInterval(t){clearInterval(t);const e=this.intervals.indexOf(t);e>-1&&this.intervals.splice(e,1)}showInputError(t,e){if(!t)return;this.clearInputError(t);const n=document.createElement("div");n.className="input-error-message",n.textContent=e,n.style.cssText="\n color: #dc2626;\n font-size: 12px;\n margin-top: 4px;\n animation: slideDown 0.2s ease-out;\n ",t.classList.add("input-error"),t.style.borderColor="#dc2626",t.parentNode&&t.parentNode.insertBefore(n,t.nextSibling),t.errorElement=n}clearInputError(t){t&&(t.errorElement&&(t.errorElement.remove(),t.errorElement=null),t.classList.remove("input-error"),t.style.borderColor="")}destroy(){this.isDestroyed||(this.isDestroyed=!0,this.eventListeners.forEach((t=>{let{element:e,event:n,handler:i,options:s}=t;try{e.removeEventListener(n,i,s)}catch(t){console.error("[BaseWidget] Error removing event listener:",t)}})),this.eventListeners=[],this.timeouts.forEach((t=>{clearTimeout(t)})),this.timeouts=[],this.intervals.forEach((t=>{clearInterval(t)})),this.intervals=[],this.lastData=null,this.container&&(this.container.innerHTML=""),this.debug&&console.log(`[${this.constructor.name}] Widget destroyed and cleaned up`))}handleConnectionFailed(t){this.connectionQuality="offline",this.lastData?(this.showCachedData(),this.hideLoading()):this.hideLoading(),this.debug&&console.log(`[${this.constructor.name}] Connection failed after ${t.maxAttempts} attempts`)}}class i{constructor(){let t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};this.symbol=t.Symbol||"",this.companyName=t.CompName||"",this.companyDescription=t.CompDesc||"",this.instrumentType=t.InstrType||"",this.lastPrice=t.LastPx||0,this.previousClose=t.YestClosePx||0,this.open=t.OpenPx||0,this.high=t.HighPx||0,this.low=t.LowPx||0,this.close=t.ClosingPx||0,this.change=t.Change||0,this.changePercent=t.ChangePercent||0,this.vwap=t.VWAP||0,this.volume=t.Volume||0,this.averageVolume=t.AvgVol30d||0,this.yesterdayVolume=t.YesterdayTradeVolume||0,this.bidPrice=t.BidPx||0,this.bidSize=t.BidSz||0,this.bidExchange=t.BidExch||"",this.askPrice=t.AskPx||0,this.askSize=t.AskSz||0,this.askExchange=t.AskExch||"",this.issueMarket=t.IssueMarket||"",this.marketName=t.MarketName||"",this.marketDescription=t.MarketDesc||"",this.mic=t.MIC||"",this.countryCode=t.CountryCode||"",this.timeZone=t.TimeZone||"",this.tradePrice=t.TradePx||0,this.tradeSize=t.TradeSz||0,this.tradeCondition=t.Condition||0,this.tradeTime=t.TradeTime||"",this.tradeRegion=t.TradeRegion||"",this.tradeRegionName=t.TradeRegionName||"",this.preMarketPrice=t.PreLastPx||0,this.preMarketTradeTime=t.PreTradeTime||"",this.postMarketPrice=t.PostLastPx||0,this.postMarketTradeTime=t.PostTradeTime||"",this.high52Week=t.High52wPx||0,this.low52Week=t.Low52wPx||0,this.high52WeekDate=t.High52wDate||"",this.low52WeekDate=t.Low52wDate||"",this.calendarYearHigh=t.CalendarYearHigh||0,this.calendarYearLow=t.CalendarYearLow||0,this.calendarYearHighDate=t.CalendarYearHighDate||"",this.calendarYearLowDate=t.CalendarYearLowDate||"",this.marketCap=t.MktCap||0,this.peRatio=t.PeRatio||0,this.beta=t.FundBeta||0,this.sharesOutstanding=t.ComShrsOut||0,this.dividendYield=t.DivYield||0,this.dividendAmount=t.DivAmt||0,this.dividendRate=t.DividendRate||0,this.dividendPaymentDate=t.DividendPaymentDate||t.PayDate||"",this.dividendExDate=t.DividendExDate||t.DivDateEx||"",this.isin=t.ISIN||"",this.cusip=t.CUSIP||"",this.sedol=t.SEDOL||"",this.gics=t.GICS||"",this.status=t.Status||"",this.dataSource=t.DataSource||"",this.quoteTime=t.QuoteTime||"",this.infoTime=t.InfoTime||""}get openPrice(){return this.open}get description(){return this.companyDescription}get lastUpdate(){return this.quoteTime||this.infoTime}getSecurityType(){return{257:"Stock",262:"ETF",261:"Mutual Fund",258:"Bond",260:"Option",263:"Future",259:"Index"}[this.instrumentType]||"Stock"}getPriceChange(){return this.change}getPriceChangePercent(){return 100*this.changePercent}getDataSource(){return"delay"===this.dataSource.toLowerCase()?"20 mins delayed":"real-time"===this.dataSource.toLowerCase()?"Real-time":null!==this.dataSource&&""!==this.dataSource?this.dataSource:"MDAS Server"}getCurrentPrice(){return this.lastPrice}get52WeekRange(){return`${this.low52Week.toFixed(2)} - ${this.high52Week.toFixed(2)}`}getMarketCapFormatted(){return this.formatMarketCap()}formatPrice(){return`$${(arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.lastPrice).toFixed(2)}`}formatPriceChange(){const t=this.getPriceChange();return`${t>=0?"+":""} ${t.toFixed(2)}`}formatPriceChangePercent(){const t=this.getPriceChangePercent();return`${t>=0?"+":""}${t.toFixed(2)}%`}formatBidAsk(){return`$${this.bidPrice.toFixed(2)} x ${this.bidSize} / $${this.askPrice.toFixed(2)} x ${this.askSize}`}formatVolume(){return 0===this.volume?"N/A":this.volume.toLocaleString()}formatAvgVolume(){return 0===this.averageVolume?"N/A":this.averageVolume.toLocaleString()}formatAverageVolume(){return 0===this.averageVolume?"N/A":this.averageVolume.toLocaleString()}formatDayRange(){return 0===this.low&&0===this.high?"N/A":`$${this.low.toFixed(2)} - $${this.high.toFixed(2)}`}format52WeekRange(){return 0===this.low52Week&&0===this.high52Week?"N/A":`${this.low52Week.toFixed(2)} - ${this.high52Week.toFixed(2)}`}formatMarketCap(){if(0===this.marketCap)return"N/A";const t=1e6*this.marketCap;return t>=1e12?`$${(t/1e12).toFixed(2)}T`:t>=1e9?`$${(t/1e9).toFixed(2)}B`:t>=1e6?`$${(t/1e6).toFixed(2)}M`:t>=1e3?`$${(t/1e3).toFixed(2)}K`:`$${t.toFixed(2)}`}formatAvg30DayVolume(){return this.formatAverageVolume()}static fromApiResponse(t){return new i(t)}}class s{constructor(t){let e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};this.widget=t,this.options={maxLength:e.maxLength||10,placeholder:e.placeholder||"Enter symbol...",onSymbolChange:e.onSymbolChange||(()=>{}),debug:e.debug||!1,autoUppercase:!1!==e.autoUppercase,...e},this.symbolType=e.symbolType||null,this.apiService=this.widget.wsManager.getApiService(),this.isEditing=!1,this.isValidating=!1,this.originalSymbol="",this.elements={},this.addStyles(),this.initialize()}initialize(){this.setupElements(),this.attachEventListeners()}setupElements(){if(this.elements.symbolDisplay=this.widget.container.querySelector(".editable-symbol"),!this.elements.symbolDisplay)throw new Error('No element with class "editable-symbol" found in widget');this.originalSymbol=this.elements.symbolDisplay.textContent.trim(),this.elements.symbolDisplay.dataset.originalSymbol=this.originalSymbol}attachEventListeners(){this.startEditing=this.startEditing.bind(this),this.handleKeydown=this.handleKeydown.bind(this),this.handleInput=this.handleInput.bind(this),this.handleBlur=this.handleBlur.bind(this),this.handleClickOutside=this.handleClickOutside.bind(this),this.elements.symbolDisplay.addEventListener("dblclick",this.startEditing)}startEditing(){this.isEditing||this.isValidating||(this.isEditing=!0,this.originalSymbol=this.elements.symbolDisplay.textContent.trim(),this.options.debug&&(console.log(this.widget.connectionQuality),console.log("[SymbolEditor] Starting edit mode for:",this.originalSymbol)),this.transformToInput())}transformToInput(){const t=this.elements.symbolDisplay,e=window.getComputedStyle(t),n=document.createElement("div");n.className="symbol-edit-container",n.style.display="inline-flex",n.style.alignItems="center",n.style.gap="8px",n.style.verticalAlign="baseline";const i=document.createElement("input");i.type="text",i.value=this.originalSymbol,i.className=t.className+" symbol-input-mode",i.style.fontSize=e.fontSize,i.style.fontWeight=e.fontWeight,i.style.fontFamily=e.fontFamily,i.style.color=e.color,i.style.backgroundColor="transparent",i.style.border="2px solid #3b82f6",i.style.borderRadius="4px",i.style.padding="2px 6px",i.style.margin="0",i.style.outline="none",i.style.width="auto",i.style.minWidth="120px",i.style.maxWidth="200px",i.style.flexShrink="0";const s=document.createElement("button");s.className="symbol-save-btn",s.innerHTML="✓",s.title="Save symbol",s.style.width="28px",s.style.height="28px",s.style.border="none",s.style.borderRadius="4px",s.style.backgroundColor="#059669",s.style.color="white",s.style.cursor="pointer",s.style.fontSize="12px",s.style.display="inline-flex",s.style.alignItems="center",s.style.justifyContent="center",s.style.flexShrink="0",n.appendChild(i),n.appendChild(s),t.style.display="none",t.parentNode.insertBefore(n,t.nextSibling),this.elements.symbolInput=i,this.elements.saveBtn=s,this.elements.editContainer=n,i.focus(),i.select(),i.addEventListener("keydown",this.handleKeydown),i.addEventListener("input",this.handleInput),i.addEventListener("blur",this.handleBlur),document.addEventListener("click",this.handleClickOutside),s.addEventListener("click",(t=>{t.stopPropagation(),this.saveSymbol()}))}async saveSymbol(){if(this.isValidating)return;const t=this.elements.symbolInput.value.trim(),e=await this.validateSymbol(t);if(!e.isValid)return this.showError(e.message),void setTimeout((()=>{this.elements.symbolInput&&(this.elements.symbolInput.value=this.originalSymbol,this.clearError(),this.cancelEditing())}),2e3);this.setLoadingState(!0);try{const n=await this.options.onSymbolChange(t,this.originalSymbol,e.data);if(n&&n.success)this.finishEditing(t),this.showSuccess("Symbol updated successfully");else{const t=n?.message||"Failed to update symbol";this.showError(t)}}catch(t){console.error("[SymbolEditor] Error changing symbol:",t),this.showError("Error updating symbol")}finally{this.setLoadingState(!1)}}cancelEditing(){this.options.debug&&console.log("[SymbolEditor] Cancelling edit mode"),this.finishEditing(this.originalSymbol)}finishEditing(){let t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null;this.isEditing=!1;const e=t||this.originalSymbol;this.elements.symbolDisplay.textContent=e,this.elements.symbolDisplay.dataset.originalSymbol=e,this.elements.symbolDisplay.style.display="",this.elements.editContainer&&(this.elements.editContainer.remove(),this.elements.editContainer=null),this.elements.symbolInput=null,this.elements.saveBtn=null,document.removeEventListener("click",this.handleClickOutside)}handleKeydown(t){"Enter"===t.key?(t.preventDefault(),this.saveSymbol()):"Escape"===t.key&&(t.preventDefault(),this.cancelEditing())}handleInput(t){if(this.options.autoUppercase){const e=t.target,n=e.selectionStart,i=e.selectionEnd;e.value=e.value.toUpperCase(),e.setSelectionRange(n,i)}this.clearError()}handleBlur(t){t.relatedTarget&&t.relatedTarget===this.elements.saveBtn||setTimeout((()=>{this.isEditing&&this.cancelEditing()}),150)}handleClickOutside(t){if(!this.isEditing)return;this.elements.symbolInput?.contains(t.target)||this.elements.saveBtn?.contains(t.target)||this.cancelEditing()}async validateSymbol(t){if("live"!==this.widget.connectionQuality)return{isValid:!1,message:"Not connected to data service"};if(!t||0===t.trim().length)return{isValid:!1,message:"Symbol cannot be empty"};const e=t.trim().toUpperCase();try{if("optionsl1"==this.symbolType){const t=await this.apiService.quoteOptionl1(e);return t[0]&&(t[0].error||1==t[0].not_found)?1==t[0].not_found?{isValid:!1,message:"Symbol not found"}:{isValid:!1,message:t[0].error}:{isValid:!0,data:t[0]}}if("quotel1"==this.symbolType||"nightsession"==this.symbolType){const t=await this.apiService.quotel1(e);return t&&t.message?t.message.includes("no data")?{isValid:!1,message:"Symbol not found"}:{isValid:!1,message:t.message}:{isValid:!0,data:t.data[0]}}if("nightsession"==this.symbolType){const t=await this.apiService.quoteBlueOcean(e);return t[0]&&1==t[0].not_found?{isValid:!1,message:"Symbol not found"}:t[0]&&0==t[0].not_found?{isValid:!0,data:t[0]}:{isValid:!1,message:t[0].error}}}catch(t){return console.warn("[SymbolEditor] API validation failed, falling back to basic validation:",t),this.defaultValidator(e)}return this.defaultValidator(e)}defaultValidator(t){return t&&0!==t.length?t.length>this.options.maxLength?{isValid:!1,message:`Symbol too long (max ${this.options.maxLength} chars)`}:{isValid:!0,data:null}:{isValid:!1,message:"Symbol cannot be empty"}}setLoadingState(t){this.isValidating=t,this.elements.saveBtn&&(t?(this.elements.saveBtn.innerHTML='<div class="loading-spinner"></div>',this.elements.saveBtn.disabled=!0):(this.elements.saveBtn.innerHTML="✓",this.elements.saveBtn.disabled=!1)),this.elements.symbolInput&&(this.elements.symbolInput.disabled=t)}showError(t){if(this.elements.symbolInput){this.elements.symbolInput.style.borderColor="#dc2626",this.elements.symbolInput.style.boxShadow="0 0 0 3px rgba(220, 38, 38, 0.1)",this.removeErrorMessage();const e=document.createElement("div");e.className="symbol-error-message",e.textContent=t,e.style.cssText="\n color: #dc2626;\n font-size: 12px;\n margin-bottom: 2px;\n position: absolute;\n background: white;\n z-index: 1000;\n transform: translateY(-100%);\n top: -4px;\n left: 0; // Align with input box\n ";const n=this.elements.editContainer;n&&(n.style.position="relative",n.appendChild(e)),this.elements.errorMessage=e,this.elements.symbolInput.focus()}}removeErrorMessage(){this.elements.errorMessage&&(this.elements.errorMessage.remove(),this.elements.errorMessage=null)}clearError(){this.elements.symbolInput&&(this.elements.symbolInput.style.borderColor="#3b82f6",this.elements.symbolInput.style.boxShadow="0 0 0 3px rgba(59, 130, 246, 0.1)",this.elements.symbolInput.title=""),this.removeErrorMessage()}showSuccess(t){this.options.debug&&console.log("[SymbolEditor] Success:",t)}updateSymbol(t){const e=this.options.autoUppercase?t.toUpperCase():t;this.elements.symbolDisplay.textContent=e,this.elements.symbolDisplay.dataset.originalSymbol=e,this.options.debug&&console.log("[SymbolEditor] Symbol updated externally:",e)}destroy(){this.finishEditing(),this.elements.symbolDisplay?.removeEventListener("dblclick",this.startEditing)}addStyles(){if(document.querySelector("#symbol-editor-styles"))return;const t=document.createElement("style");t.id="symbol-editor-styles",t.textContent='\n .editable-symbol {\n cursor: pointer;\n transition: all 0.2s ease;\n position: relative;\n }\n\n .editable-symbol:hover {\n opacity: 0.8;\n transform: scale(1.02);\n }\n\n .editable-symbol:hover::after {\n content: "✎";\n position: absolute;\n top: -8px;\n right: -8px;\n background: #3b82f6;\n color: white;\n font-size: 10px;\n padding: 2px 4px;\n border-radius: 4px;\n opacity: 0.8;\n pointer-events: none;\n }\n\n .symbol-input-mode {\n text-transform: uppercase;\n }\n\n .symbol-save-btn:hover {\n background-color: #047857 !important;\n transform: scale(1.05);\n }\n\n .symbol-save-btn:disabled {\n background-color: #9ca3af !important;\n cursor: not-allowed !important;\n transform: none !important;\n }\n\n .loading-spinner {\n width: 12px;\n height: 12px;\n border: 2px solid rgba(255, 255, 255, 0.3);\n border-top-color: white;\n border-radius: 50%;\n animation: spin 1s linear infinite;\n }\n\n @keyframes spin {\n to { transform: rotate(360deg); }\n }\n ',document.head.appendChild(t)}}const o='\n /* ========================================\n FONT SIZE SYSTEM - CSS Variables\n Adjust --mdas-base-font-size to scale all fonts\n ======================================== */\n :root {\n /* Base font size - change this to scale everything */\n --mdas-base-font-size: 14px;\n\n /* Relative font sizes (in em, scales with base) */\n --mdas-company-name-size: 1.43em; /* 20px at base 14px */\n --mdas-symbol-size: 1.79em; /* 25px at base 14px */\n --mdas-price-size: 2.29em; /* 32px at base 14px */\n --mdas-price-change-size: 1.14em; /* 16px at base 14px */\n --mdas-section-title-size: 1em; /* 14px at base 14px */\n --mdas-data-label-size: 0.93em; /* 13px at base 14px */\n --mdas-data-value-size: 1em; /* 14px at base 14px */\n --mdas-bid-ask-size: 1.07em; /* 15px at base 14px */\n --mdas-small-text-size: 0.86em; /* 12px at base 14px */\n --mdas-badge-size: 0.86em; /* 12px at base 14px */\n --mdas-loading-text-size: 1.14em; /* 16px at base 14px */\n --mdas-no-data-title-size: 1.14em; /* 16px at base 14px */\n --mdas-edit-icon-size: 0.71em; /* 10px at base 14px */\n }\n\n /* Apply base font size to widgets */\n .widget {\n font-size: var(--mdas-base-font-size);\n }\n\n /* ========================================\n OPTIONAL CARD STYLING\n Add \'widget-styled\' class for card design\n ======================================== */\n .widget-styled {\n background: white;\n border-radius: 12px;\n padding: 24px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);\n border: 1px solid #e5e7eb;\n }\n\n /* Base widget styles */\n .widget-loading-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(255, 255, 255, 0.95);\n backdrop-filter: blur(2px);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10;\n border-radius: 12px;\n }\n\n .widget-loading-overlay.hidden {\n display: none;\n }\n\n .widget {\n font-family: -apple-system, BlinkMacSystemFont, \'Segoe UI\', Roboto, sans-serif;\n width: 100%;\n max-width: 1400px;\n }\n\n /* HEADER STYLES */\n\n .widget-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 20px;\n gap: 16px;\n }\n\n .symbol-section {\n display: flex;\n flex-direction: column;\n gap: 4px;\n }\n\n .night-company-name {\n font-size: var(--mdas-company-name-size);\n font-weight: 500;\n color: #111827;\n cursor: pointer;\n transition: all 0.2s ease;\n position: relative;\n }\n\n .symbol {\n font-size: var(--mdas-symbol-size);\n font-weight: 700;\n color: #111827;\n cursor: pointer;\n transition: all 0.2s ease;\n position: relative;\n }\n\n .symbol:hover {\n opacity: 0.8;\n transform: scale(1.02);\n }\n\n .symbol:hover::after {\n content: "✎";\n position: absolute;\n top: -8px;\n right: -8px;\n background: #3b82f6;\n color: white;\n font-size: var(--mdas-edit-icon-size);\n padding: 2px 4px;\n border-radius: 4px;\n opacity: 0.8;\n }\n\n .data-type {\n background:rgb(214, 228, 250);\n padding: 2px 8px;\n border-radius: 6px;\n font-size: var(--mdas-badge-size);\n font-weight: 500;\n color: #3b82f6;\n }\n\n .price-section {\n text-align: right;\n }\n\n .current-price {\n font-size: var(--mdas-price-size);\n font-weight: 700;\n color: #111827;\n line-height: 1;\n }\n\n .price-change {\n font-size: var(--mdas-price-change-size);\n font-weight: 600;\n margin-top: 4px;\n display: flex;\n align-items: center;\n justify-content: flex-end;\n gap: 4px;\n }\n\n .price-change.positive { \n color: #10b981; \n }\n\n .price-change.negative { \n color: #ef4444; \n }\n\n .price-change.neutral { \n color: #6b7280; \n }\n\n .market-data-widget .price-change.positive::before,\n .night-session-widget .price-change.positive::before,\n .options-widget .price-change.positive::before{\n content: "↗";\n }\n\n .market-data-widget .price-change.negative::before,\n .night-session-widget .price-change.negative::before,\n .options-widget .price-change.negative::before {\n content: "↘";\n }\n\n /* BODY SECTION STYLES */\n\n .data-grid {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 32px;\n margin-bottom: 24px;\n }\n\n .data-section {\n display: flex;\n flex-direction: column;\n gap: 16px;\n }\n\n .section-title {\n font-size: var(--mdas-section-title-size);\n font-weight: 600;\n color: #6b7280;\n margin: 0;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n border-bottom: 1px solid #e5e7eb;\n padding-bottom: 8px;\n }\n\n .data-row {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 16px;\n }\n\n .data-item {\n display: flex;\n flex-direction: column;\n gap: 4px;\n }\n\n .price-metadata,\n .data-label {\n font-size: var(--mdas-data-label-size);\n color: #6b7280;\n font-weight: 500;\n }\n\n .data-value {\n font-size: var(--mdas-data-value-size);\n font-weight: 600;\n color: #111827;\n text-align: right;\n flex-shrink: 0;\n }\n\n\n /* Footer */\n .widget-footer {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding-top: 16px;\n border-top: 1px solid #e5e7eb;\n font-size: var(--mdas-small-text-size);\n color: #9ca3af;\n }\n \n\n /* LOADING STYLES */\n\n\n .loading-content {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 16px;\n }\n\n .loading-spinner {\n width: 40px;\n height: 40px;\n border: 4px solid #e5e7eb;\n border-top-color: #3b82f6;\n border-radius: 50%;\n animation: spin 1s linear infinite;\n }\n\n .loading-text {\n color: #6b7280;\n font-size: var(--mdas-loading-text-size);\n font-weight: 500;\n }\n\n @keyframes spin {\n to { transform: rotate(360deg); }\n }\n\n .widget-error {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n background: #fef2f2;\n border: 1px solid #fecaca;\n border-radius: 8px;\n padding: 16px;\n color: #dc2626;\n font-size: var(--mdas-data-value-size);\n font-weight: 600;\n text-align: center;\n z-index: 10;\n max-width: 80%;\n }\n\n /* Price change colors */\n .positive {\n color: #059669;\n }\n\n .negative {\n color: #dc2626;\n }\n\n \n\n /* No data state */\n .no-data-state {\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 160px;\n margin: 16px 0;\n background: #f9fafb;\n border: 1px solid #e5e7eb;\n border-radius: 12px;\n padding: 24px 16px;\n width: 100%;\n box-sizing: border-box;\n overflow: hidden;\n }\n\n .no-data-content {\n text-align: center;\n max-width: 280px;\n width: 100%;\n word-wrap: break-word;\n overflow-wrap: break-word;\n }\n\n .no-data-icon {\n margin-bottom: 16px;\n display: flex;\n justify-content: center;\n }\n\n .no-data-icon svg {\n opacity: 0.6;\n }\n\n .no-data-title {\n font-size: var(--mdas-no-data-title-size);\n font-weight: 600;\n color: #6b7280;\n margin: 0 0 8px 0;\n }\n\n .no-data-description {\n font-size: var(--mdas-data-value-size);\n color: #9ca3af;\n margin: 0 0 12px 0;\n line-height: 1.4;\n }\n\n .no-data-description strong {\n color: #6b7280;\n font-weight: 600;\n }\n\n .no-data-guidance {\n font-size: var(--mdas-small-text-size);\n color: #9ca3af;\n margin: 0;\n font-style: italic;\n }\n\n /* Error Access State */\n .no-data-state.error-access {\n border: 1px solid #fecaca;\n background:rgb(255, 255, 255);\n \n }\n\n .no-data-title.error {\n color: #ef4444;\n }\n\n .no-data-icon.error svg {\n stroke: #ef4444;\n }\n\n .no-data-icon.error svg circle[fill] {\n fill: #ef4444;\n }\n',a=`\n ${o}\n\n /* Reset and base styles for widget */\n\n .night-session-widget {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n line-height: 1.5;\n max-width: 800px;\n position: relative;\n }\n\n /* STANDARDIZED HEADER LAYOUT */\n\n\n .symbol-section {\n display: flex;\n flex-direction: column;\n gap: 4px;\n }\n\n .night-session-widget .symbol {\n font-size: var(--mdas-symbol-size);\n font-weight: 700;\n color: #111827;\n cursor: pointer;\n transition: all 0.2s ease;\n position: relative;\n }\n\n .night-session-widget .symbol:hover {\n opacity: 0.8;\n transform: scale(1.02);\n }\n\n .night-session-widget .symbol:hover::after {\n content: "✎";\n position: absolute;\n top: -8px;\n right: -8px;\n background: #3b82f6;\n color: white;\n font-size: var(--mdas-edit-icon-size);\n padding: 2px 4px;\n border-radius: 4px;\n opacity: 0.8;\n }\n\n .company-info {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: var(--mdas-section-title-size);\n color: #6b7280;\n }\n\n .market-name {\n font-weight: 600;\n text-transform: uppercase;\n }\n\n /* Company and market info styling */\n .company-market-info {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: var(--mdas-small-text-size);\n color: #6b7280;\n margin-bottom: 4px;\n }\n\n .company-market-info .market-name {\n font-weight: 600;\n }\n\n .company-market-info .market-name::before {\n content: '|';\n margin-right: 8px;\n color: #9ca3af;\n }\n\n .company-market-info .market-mic {\n font-weight: 600;\n }\n\n .company-market-info .market-mic::before {\n content: '•';\n margin-right: 8px;\n }\n\n /* Price metadata (source and last update) */\n .price-metadata {\n margin-top: 8px;\n display: flex;\n flex-direction: column;\n gap: 4px;\n }\n\n \n\n /* STANDARDIZED GRID LAYOUT */\n .data-grid {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 24px;\n margin-top: 24px;\n }\n\n .data-section {\n display: flex;\n flex-direction: column;\n gap: 12px;\n }\n\n .night-session-widget .section-title {\n font-size: var(--mdas-small-text-size);\n font-weight: 600;\n color: #6b7280;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n border-bottom: 1px solid #e5e7eb;\n padding-bottom: 8px;\n }\n\n .night-session-widget .data-row {\n display: flex;\n justify-content: space-between;\n align-items: center;\n min-height: 20px;\n }\n\n\n\n .night-session-widget .data-value {\n font-size: var(--mdas-data-value-size);\n font-weight: 600;\n color: #111827;\n text-align: right;\n }\n\n /* SPECIAL FORMATTING FOR DIFFERENT DATA TYPES */\n .night-session-widget .bid-ask-value {\n font-size: var(--mdas-bid-ask-size);\n font-weight: 700;\n }\n\n .night-session-widget .size-info {\n font-size: var(--mdas-small-text-size);\n color: #6b7280;\n margin-left: 4px;\n }\n\n /* Footer */\n .night-session-widget .widget-footer {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-top: 24px;\n padding-top: 16px;\n border-top: 1px solid #e5e7eb;\n font-size: var(--mdas-small-text-size);\n color: #9ca3af;\n grid-column: 1 / -1;\n }\n\n /* Loading Overlay */\n .widget-loading-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(255, 255, 255, 0.95);\n backdrop-filter: blur(2px);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10;\n border-radius: 12px;\n }\n\n .widget-loading-overlay.hidden {\n display: none;\n }\n\n .loading-content {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 12px;\n }\n\n .loading-spinner {\n width: 32px;\n height: 32px;\n border: 3px solid #f3f4f6;\n border-top-color: #3b82f6;\n border-radius: 50%;\n animation: spin 1s linear infinite;\n }\n\n .night-session-widget .loading-text {\n color: #6b7280;\n font-size: var(--mdas-data-value-size);\n font-weight: 500;\n }\n\n @keyframes spin {\n to { transform: rotate(360deg); }\n }\n\n /* Widget Error Styles */\n .night-session-widget .widget-error {\n background: #fef2f2;\n color: #9ca3af;\n padding: 12px;\n border-radius: 8px;\n border: 1px solid #fecaca;\n margin-top: 16px;\n font-size: var(--mdas-data-value-size);\n font-weight: 500;\n }\n\n /* No Data State */\n .night-session-widget .no-data-state {\n padding: 24px;\n text-align: center;\n color: #6b7280;\n grid-column: 1 / -1;\n }\n\n .night-session-widget .no-data-content {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 12px;\n }\n\n .night-session-widget .no-data-icon {\n font-size: 3.43em;\n opacity: 0.5;\n }\n\n .night-session-widget .no-data-title {\n font-size: 1.29em;\n font-weight: 600;\n color: #374151;\n }\n\n .night-session-widget .no-data-message {\n font-size: var(--mdas-data-value-size);\n max-width: 300px;\n line-height: 1.5;\n }\n\n .night-session-widget .no-data-suggestion {\n font-size: var(--mdas-small-text-size);\n color: #9ca3af;\n max-width: 350px;\n line-height: 1.4;\n }\n\n /* Dimmed state for no data */\n .widget-header.dimmed,\n .price-section.dimmed {\n opacity: 0.6;\n }\n\n /* Responsive Design */\n @media (max-width: 768px) {\n :root {\n --mdas-base-font-size: 13px; /* Slightly smaller on tablets */\n }\n\n .widget-styled {\n padding: 16px;\n }\n\n .widget-header {\n grid-template-columns: 1fr;\n gap: 12px;\n text-align: center;\n }\n\n .symbol-section {\n align-items: center;\n }\n\n .price-section {\n text-align: center;\n }\n\n .data-grid {\n grid-template-columns: 1fr;\n gap: 16px;\n }\n\n .widget-footer {\n flex-direction: column;\n gap: 8px;\n text-align: center;\n }\n }\n\n @media (max-width: 480px) {\n :root {\n --mdas-base-font-size: 12px; /* Smaller on mobile */\n }\n }\n\n \n`,r=`\n ${o}\n\n /* Reset and base styles for widget */\n\n .market-data-widget {\n color: #333;\n margin: 0 auto;\n position: relative;\n overflow: hidden;\n }\n\n /* MARKET DATA HEADER STYLES */\n\n\n .market-data-widget .company-info {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: var(--mdas-section-title-size);\n color: #6b7280;\n }\n\n .company-name {\n position: relative;\n cursor: help;\n transition: all 0.2s ease;\n }\n\n .company-name:hover {\n border-bottom-color: #3b82f6;\n color: #3b82f6;\n }\n\n\n /* STANDARDIZED GRID LAYOUT */\n \n .data-section {\n display: flex;\n flex-direction: column;\n gap: 12px;\n min-width: 0;\n overflow: hidden;\n }\n\n .market-data-widget .section-title {\n font-size: var(--mdas-small-text-size);\n font-weight: 600;\n color: #6b7280;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n padding-bottom: 8px;\n }\n\n\n\n /* SPECIAL FORMATTING FOR DIFFERENT DATA TYPES */\n .market-data-widget .bid-ask-value {\n font-size: var(--mdas-bid-ask-size);\n font-weight: 700;\n }\n\n .market-data-widget .size-info {\n font-size: var(--mdas-small-text-size);\n color: #6b7280;\n margin-left: 4px;\n }\n\n .market-data-widget .range-value {\n font-size: var(--mdas-data-label-size);\n }\n\n \n\n /* Tooltip Styles */\n .company-name::after {\n content: attr(data-tooltip);\n position: absolute;\n bottom: 100%;\n left: 50%;\n transform: translateX(-50%);\n background: #1f2937;\n color: white;\n padding: 8px 12px;\n border-radius: 6px;\n font-size: var(--mdas-small-text-size);\n font-weight: normal;\n white-space: nowrap;\n max-width: 300px;\n white-space: normal;\n line-height: 1.4;\n z-index: 1000;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n opacity: 0;\n visibility: hidden;\n transition: all 0.2s ease;\n pointer-events: none;\n margin-bottom: 5px;\n }\n\n .company-name:hover::after {\n opacity: 1;\n visibility: visible;\n }\n\n .company-name::before {\n content: '';\n position: absolute;\n bottom: 100%;\n left: 50%;\n transform: translateX(-50%);\n border: 5px solid transparent;\n border-top-color: #1f2937;\n opacity: 0;\n visibility: hidden;\n transition: all 0.2s ease;\n pointer-events: none;\n }\n\n .company-name:hover::before {\n opacity: 1;\n visibility: visible;\n }\n\n /* Loading Overlay */\n .widget-loading-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(255, 255, 255, 0.95);\n backdrop-filter: blur(2px);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10;\n border-radius: 12px;\n }\n\n .widget-loading-overlay.hidden {\n display: none;\n }\n\n .loading-content {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 12px;\n }\n\n .loading-spinner {\n width: 32px;\n height: 32px;\n border: 3px solid #f3f4f6;\n border-top-color: #3b82f6;\n border-radius: 50%;\n animation: spin 1s linear infinite;\n }\n\n .market-data-widget .loading-text {\n color: #6b7280;\n font-size: var(--mdas-data-value-size);\n font-weight: 500;\n }\n\n @keyframes spin {\n to { transform: rotate(360deg); }\n }\n\n /* Widget Error Styles */\n .market-data-widget .widget-error {\n background: #fef2f2;\n color: #dc2626;\n padding: 12px;\n border-radius: 8px;\n border: 1px solid #fecaca;\n margin-top: 16px;\n font-size: var(--mdas-data-value-size);\n font-weight: 500;\n }\n\n /* Responsive Design */\n\n\n @media (max-width: 600px) {\n .widget-header {\n grid-template-columns: 1fr;\n gap: 12px;\n text-align: center;\n }\n\n .symbol-section {\n align-items: center;\n }\n\n .price-section {\n text-align: center;\n }\n\n .data-grid {\n grid-template-columns: 1fr;\n gap: 16px;\n }\n\n .widget-footer {\n flex-direction: column;\n gap: 8px;\n text-align: center;\n }\n }\n\n @media (max-width: 480px) {\n .company-name::after {\n left: 0;\n transform: none;\n max-width: 250px;\n }\n\n .company-name::before {\n left: 20px;\n transform: none;\n }\n }\n`,c=`\n ${o}\n\n .options-widget {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n color: #333;\n max-width: 1400px;\n width: 100%;\n margin: 0 auto;\n position: relative;\n overflow: hidden;\n }\n\n .widget-content {\n position: relative;\n z-index: 1;\n }\n\n \n .options-widget .symbol-info .symbol {\n font-size: var(--mdas-symbol-size);\n font-weight: 700;\n margin: 0 0 8px 0;\n color: #1f2937;\n }\n\n .options-widget .option-info {\n display: flex;\n align-items: center;\n gap: 8px;\n color: #6b7280;\n font-size: var(--mdas-price-change-size);\n }\n\n .options-widget .underlying-symbol {\n font-weight: 600;\n color: #6b7280;\n }\n\n .options-widget .option-details-section {\n display: flex;\n gap: 24px;\n margin-bottom: 24px;\n padding-bottom: 20px;\n border-bottom: 1px solid #e5e7eb;\n }\n\n .options-widget .option-details-section .detail-item {\n display: flex;\n flex-direction: column;\n gap: 4px;\n }\n\n .options-widget .option-details-section .detail-item label {\n font-size: var(--mdas-small-text-size);\n color: #6b7280;\n font-weight: 500;\n text-transform: uppercase;\n letter-spacing: 0.3px;\n }\n\n .options-widget .option-details-section .detail-item span {\n font-size: var(--mdas-price-change-size);\n font-weight: 600;\n color: #1f2937;\n }\n\n\n .options-widget .widget-footer {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding-top: 16px;\n border-top: 1px solid #e5e7eb;\n font-size: var(--mdas-small-text-size);\n color: #9ca3af;\n }\n\n /* Dimmed state for no-data */\n .widget-header.dimmed {\n opacity: 0.6;\n }\n\n .widget-header.dimmed .symbol {\n color: #9ca3af;\n }\n\n /* Responsive design */\n @media (max-width: 768px) {\n .widget-header {\n flex-direction: column;\n gap: 16px;\n text-align: left;\n }\n\n .price-info {\n text-align: left;\n }\n\n .data-grid {\n grid-template-columns: 1fr;\n gap: 20px;\n }\n\n .option-details-section {\n flex-wrap: wrap;\n gap: 16px;\n }\n\n .current-price {\n font-size: 32px;\n }\n\n .symbol {\n font-size: 20px !important;\n }\n }\n\n @media (max-width: 480px) {\n .widget-styled {\n padding: 12px;\n }\n\n .widget-header {\n margin-bottom: 16px;\n padding-bottom: 16px;\n }\n\n .current-price {\n font-size: 28px;\n }\n\n .data-row {\n grid-template-columns: 1fr;\n gap: 12px;\n }\n\n .option-details-section {\n flex-direction: column;\n gap: 12px;\n }\n\n .no-data-state {\n min-height: 120px;\n padding: 20px 12px;\n }\n\n .no-data-title {\n font-size: 14px;\n }\n\n .no-data-description {\n font-size: 12px;\n }\n\n .no-data-guidance {\n font-size: 11px;\n }\n }\n`;function l(t){let e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"";const i=document.createElement(t);return n&&(i.className=n),e&&(i.textContent=e),i}function d(t){let e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:2,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"--";if(null==t||""===t)return n;const i=parseFloat(t);return isNaN(i)?n:i.toFixed(e)}function h(t){if(!t)return"";return String(t).replace(/[^A-Za-z0-9.\-_+ ]/g,"").substring(0,50)}function u(t){if(t)for(;t.firstChild;)t.removeChild(t.firstChild)}function g(t){if(!t||"string"!=typeof t)return{valid:!1,error:"Symbol is required",sanitized:""};const e=t.trim().toUpperCase();return 0===e.length?{valid:!1,error:"Symbol cannot be empty",sanitized:""}:e.length>10?{valid:!1,error:"Symbol too long (max 10 characters)",sanitized:""}:{valid:!0,sanitized:e}}function p(t){if(!t||"string"!=typeof t)return{valid:!1,error:"Option symbol is required",sanitized:""};const e=t.trim().toUpperCase();if(e.length<15||e.length>21)return{valid:!1,error:"Invalid option symbol length",sanitized:e};const n=e.match(/^([A-Z]{1,6})(\d{2})(0[1-9]|1[0-2])([0-2][0-9]|3[01])([CP])(\d{8})$/);if(!n)return{valid:!1,error:"Invalid option symbol format. Expected: SYMBOL+YYMMDD+C/P+STRIKE",sanitized:e};const[,i,s,o,a,r,c]=n,l=2e3+parseInt(s,10),d=parseInt(o,10),h=parseInt(a,10),u=new Date(l,d-1,h);if(u.getMonth()+1!==d||u.getDate()!==h)return{valid:!1,error:"Invalid expiration date in option symbol",sanitized:e};const g=new Date;g.setHours(0,0,0,0),u<g&&console.warn("Option symbol has expired");return{valid:!0,sanitized:e,parsed:{underlying:i,expiry:u,type:"C"===r?"call":"put",strike:parseInt(c,10)/1e3}}}function m(t){if(!t)return"ET";const[e,n,i]=t.split("-").map(Number),s=new Date(e,n-1,i),o=function(t,e){const n=new Date(t,e,1),i=1+(7-n.getDay())%7;return new Date(t,e,i+7)}(e,2),a=function(t,e){const n=new Date(t,e,1),i=1+(7-n.getDay())%7;return new Date(t,e,i)}(e,10);return s>=o&&s<a?"EDT":"EST"}function f(t){let e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const{includeSeconds:n=!0,includeTimezone:i=!0,format:s="short"}=e;let o;if(t||(t=Date.now()),o=t instanceof Date?t:new Date(t),isNaN(o.getTime()))return"Invalid Date";const a=o.getUTCFullYear(),r=o.getUTCMonth(),c=o.getUTCDate(),l=o.getUTCHours(),d=o.getUTCMinutes(),h=o.getUTCSeconds(),u=function(t){const e=t.getUTCFullYear(),n=t.getUTCMonth(),i=t.getUTCDate(),s=new Date(Date.UTC(e,n,i)),o=function(t,e){const n=new Date(Date.UTC(t,e,1)),i=1+(7-n.getUTCDay())%7;return new Date(Date.UTC(t,e,i+7))}(e,2),a=function(t,e){const n=new Date(Date.UTC(t,e,1)),i=1+(7-n.getUTCDay())%7;return new Date(Date.UTC(t,e,i))}(e,10);return s>=o&&s<a}(o),g=u?-4:-5,p=new Date(Date.UTC(a,r,c,l+g,d,h)),m=p.getUTCFullYear(),f=p.getUTCMonth()+1,b=p.getUTCDate(),y=p.getUTCHours(),x=p.getUTCMinutes(),v=p.getUTCSeconds(),w=y%12||12,S=y>=12?"PM":"AM",k=x.toString().padStart(2,"0"),M=v.toString().padStart(2,"0"),C=n?`${w}:${k}:${M} ${S}`:`${w}:${k} ${S}`,_=i?u?" EDT":" EST":"";if("long"===s){return`${["January","February","March","April","May","June","July","August","September","Oct","November","December"][f-1]} ${b}, ${m}, ${C}${_}`}return`${f}/${b}/${m}, ${C}${_}`}class b extends n{constructor(t,e,n){if(super(t,e,n),!e.symbol)throw new Error("Symbol is required for MarketDataWidget");if(!e.wsManager)throw new Error("WebSocketManager is required for MarketDataWidget");this.type="marketdata";const i=g(e.symbol);if(!i.valid)throw new Error(`Invalid symbol: ${i.error}`);this.symbol=i.sanitized,this.wsManager=e.wsManager,this.debug=e.debug||!1,this.styled=void 0===e.styled||e.styled,this.data=null,this.isDestroyed=!1,this.unsubscribe=null,this.loadingTimeout=null,this.createWidgetStructure(),this.initializeSymbolEditor(),this.initialize()}createWidgetStructure(){if(this.container.innerHTML='\n <div class="market-data-widget widget">\n <div class="widget-content">\n \x3c!-- Header Section --\x3e\n <div class="widget-header">\n <div class="symbol-section">\n <h1 class="symbol editable-symbol" \n title="Double-click to edit symbol" \n data-original-symbol="">\n </h1>\n <div class="company-info">\n <span class="company-name" \n title="" \n data-tooltip="">\n </span>\n <span class="data-type">STOCK</span>\n </div>\n </div>\n <div class="price-section">\n <div class="current-price"></div>\n <div class="price-change">\n <span class="change-value"></span>\n <span class="change-percent"></span>\n </div>\n </div>\n </div>\n\n \x3c!-- Data Grid Section --\x3e\n <div class="data-grid">\n <div class="data-section">\n <div class="section-title">Quote</div>\n <div class="data-row">\n <span class="data-label">Bid</span>\n <span class="data-value bid-ask-value bid-data"></span>\n </div>\n <div class="data-row">\n <span class="data-label">Ask</span>\n <span class="data-value bid-ask-value ask-data"></span>\n </div>\n </div>\n\n <div class="data-section">\n <div class="section-title">Trading Activity</div>\n <div class="data-row">\n <span class="data-label">Volume</span>\n <span class="data-value volume"></span>\n </div>\n <div class="data-row">\n <span class="data-label">Average Volume</span>\n <span class="data-value avg-volume"></span>\n </div>\n </div>\n\n <div class="data-section">\n <div class="section-title">Performance</div>\n <div class="data-row">\n <span class="data-label">Previous Close</span>\n <span class="data-value prev-close"></span>\n </div>\n <div class="data-row">\n <span class="data-label">Open</span>\n <span class="data-value open-price"></span>\n </div>\n <div class="data-row">\n <span class="data-label">Day Range</span>\n <span class="data-value range-value day-range"></span>\n </div>\n <div class="data-row">\n <span class="data-label">52-Week Range</span>\n <span class="data-value range-value week-range"></span>\n </div>\n </div>\n\n <div class="data-section">\n <div class="section-title">Key Metrics</div>\n <div class="data-row">\n <span class="data-label">Market Cap</span>\n <span class="data-value market-cap"></span>\n </div>\n <div class="data-row">\n <span class="data-label">P/E Ratio</span>\n <span class="data-value pe-ratio"></span>\n </div>\n <div class="data-row">\n <span class="data-label">Dividend Yield</span>\n <span class="data-value dividend-yield"></span>\n </div>\n <div class="data-row">\n <span class="data-label">Beta</span>\n <span class="data-value beta"></span>\n </div>\n </div>\n </div>\n\n \x3c!-- Footer --\x3e\n <div class="widget-footer">\n <span class="last-update"></span>\n <span class="data-source"></span>\n </div>\n </div>\n \n \x3c!-- Loading Overlay --\x3e\n <div class="widget-loading-overlay">\n <div class="loading-content">\n <div class="loading-spinner"></div>\n <span class="loading-text">Loading market data...</span>\n </div>\n </div>\n </div>\n',this.styled){const t=this.container.querySelector(".market-data-widget");t&&t.classList.add("widget-styled")}this.addStyles()}addStyles(){if(!document.querySelector("#market-data-styles")){const t=document.createElement("style");t.id="market-data-styles",t.textContent=r,document.head.appendChild(t)}}initializeSymbolEditor(){this.symbolEditor=new s(this,{maxLength:10,placeholder:"Enter symbol...",onSymbolChange:this.handleSymbolChange.bind(this),debug:this.debug,autoUppercase:!0,symbolType:"quotel1"});const t=this.container.querySelector(".symbol");t&&(t.textContent=this.symbol,t.dataset.originalSymbol=this.symbol)}async handleSymbolChange(t){this.debug&&console.log("[MarketDataWidget] Symbol change requested:",t);const e=g(t);if(!e.valid)return this.debug&&console.log("[MarketDataWidget] Invalid symbol:",e.error),{success:!1,error:e.error};const n=e.sanitized;if(n===this.symbol)return this.debug&&console.log("[MarketDataWidget] Same symbol, no change needed"),{success:!0};try{const t=this.symbol;return this.showLoading(),this.loadingTimeout&&this.clearTimeout(this.loadingTimeout),this.loadingTimeout=this.setTimeout((()=>{this.debug&&console.log("[MarketDataWidget] Loading timeout for symbol:",n),this.hideLoading(),this.showError(`No data received for ${n}. Please try again.`)}),1e4),this.unsubscribe&&(this.debug&&console.log(`[MarketDataWidget] Unsubscribing from ${t}`),this.wsManager.sendUnsubscribe("queryl1",t),this.unsubscribe(),this.unsubscribe=null),this.symbol=n,this.debug&&console.log(`[MarketDataWidget] Subscribing to ${n}`),this.subscribeToData(),this.debug&&console.log(`[MarketDataWidget] Successfully changed symbol from ${t} to ${n}`),{success:!0}}catch(t){return console.error("[MarketDataWidget] Error changing symbol:",t),this.hideLoading(),this.showError(`Failed to load data for ${n}`),{success:!1,error:`Failed to load ${n}`}}}async initialize(){this.showLoading(),await this.validateInitialSymbol(),this.subscribeToData()}async validateInitialSymbol(){try{const t=this.wsManager.getApiService();if(!t)return void(this.debug&&console.log("[MarketDataWidget] API service not available for initial validation"));const e=await t.quotel1(this.symbol);if(e&&e.data&&e.data[0]){const t=e.data[0];this.initialValidationData=t,this.debug&&console.log("[MarketDataWidget] Initial symbol validated:",{symbol:this.symbol,companyName:t.comp_name,exchangeName:t.market_name})}}catch(t){this.debug&&console.warn("[MarketDataWidget] Initial symbol validation failed:",t)}}subscribeToData(){this.unsubscribe=this.wsManager.subscribe(this.widgetId,["queryl1"],this.handleMessage.bind(this),this.symbol)}handleData(t){if(this.loadingTimeout&&(clearTimeout(this.loadingTimeout),this.loadingTimeout=null),"error"===t.type&&t.noData)return this.debug&&console.log("[MarketDataWidget] Received no data message:",t.message),void(this.data?(this.hideLoading(),this.debug&&console.log("[MarketDataWidget] No new data, keeping cached data visible")):this.showNoDataState({Symbol:this.symbol,NotFound:!0,message:t.message}));if("error"!==t.type){if("object"==typeof t&&t.Message){const e=t.Message.toLowerCase();if(e.includes("no data")||e.includes("not found"))return this.debug&&console.log("[MarketDataWidget] Received no data message:",t.Message),void(this.data?(this.hideLoading(),this.debug&&console.log("[MarketDataWidget] No new data, keeping cached data visible")):this.showNoDataState({Symbol:this.symbol,NotFound:!0,message:t.Message}))}if(t.Data&&t.Data.length>0){const e=t.Data.find((t=>t.Symbol===this.symbol));if(e){const t=new i(e);this.data=t,this.updateWidget(t)}else this.debug&&console.log("[MarketDataWidget] No data for symbol in response, keeping cached data"),this.hideLoading()}t._cached&&this.showConnectionQuality()}else{const e=t.message||"Server error";this.data?(this.hideLoading(),this.debug&&console.log("[MarketDataWidget] Error received but keeping cached data:",e)):this.showError(e)}}showNoDataState(){let t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};if(!this.isDestroyed)try{this.hideLoading(),this.clearError();const e=t.Symbol||this.symbol,n=this.container.querySelector(".symbol");n&&(n.textContent=e);const i=this.container.querySelector(".company-name");i&&(i.textContent=`${e} Inc`);const s=this.container.querySelector(".current-price");s&&(s.textContent="$0.00");const o=this.container.querySelector(".price-change");if(o){const t=o.querySelector(".change-value"),e=o.querySelector(".change-percent");t&&(t.textContent="+0.00"),e&&(e.textContent=" (0.00%)"),o.classList.remove("positive","negative"),o.classList.add("neutral")}const a=this.container.querySelector(".widget-header");a&&a.classList.add("dimmed"),this.showNoDataMessage(e,t);const r=this.container.querySelector(".last-update");if(r){const t=f();r.textContent=`Checked: ${t}`}const c=this.container.querySelector(".data-source");c&&(c.textContent="Source: No data available")}catch(t){console.error("Error showing no data state:",t),this.showError("Error displaying no data state")}}showNoDataMessage(t){const e=this.container.querySelector(".data-grid");e&&(e.style.display="none");const n=this.container.querySelector(".no-data-state");n&&n.remove();const i=l("div","","no-data-state"),s=l("div","","no-data-content"),o=document.createElement("div");o.className="no-data-icon",o.innerHTML='<svg width="32" height="32" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">\n <circle cx="12" cy="12" r="10" stroke="#9ca3af" stroke-width="2"/>\n <path d="M12 8v4" stroke="#9ca3af" stroke-width="2" stroke-linecap="round"/>\n <circle cx="12" cy="16" r="1" fill="#9ca3af"/>\n </svg>',s.appendChild(o);const a=l("h3","No Market Data","no-data-title");s.appendChild(a);const r=l("p","","no-data-description");r.appendChild(document.createTextNode("Market data for "));const c=l("strong",h(t));r.appendChild(c),r.appendChild(document.createTextNode(" was not found")),s.appendChild(r);const d=l("p","Please check the symbol spelling or try a different symbol","no-data-guidance");s.appendChild(d),i.appendChild(s);const u=this.container.querySelector(".widget-footer");u&&u.parentNode?u.parentNode.insertBefore(i,u):this.container.appendChild(i)}updateWidget(t){if(!this.isDestroyed)try{this.loadingTimeout&&(clearTimeout(this.loadingTimeout),this.loadingTimeout=null),this.clearError(),this.hideLoading();const e=this.container.querySelector(".widget-header");e&&e.classList.remove("dimmed");const n=this.container.querySelector(".data-grid");n&&(n.style.display="");const i=this.container.querySelector(".no-data-state");i&&i.remove();const s=this.container.querySelector(".symbol");s&&(s.textContent=t.symbol,s.dataset.originalSymbol=t.symbol);const o=this.container.querySelector(".company-name");if(o){const e=t.companyName||`${t.symbol} Inc`,n=t.companyDescription||`${t.symbol} designs, manufactures, and markets consumer electronics and software.`;o.textContent=e,o.setAttribute("title",n),o.setAttribute("data-tooltip",n)}const a=this.container.querySelector(".current-price");a&&(a.textContent=t.formatPrice());const r=t.getPriceChange(),c=this.container.querySelector(".price-change");if(c){const e=c.querySelector(".change-value"),n=c.querySelector(".change-percent");e&&(e.textContent=t.formatPriceChange()),n&&(n.textContent=` (${t.formatPriceChangePercent()})`),c.classList.remove("positive","negative","neutral"),r>0?c.classList.add("positive"):r<0?c.classList.add("negative"):c.classList.add("neutral")}const h=this.container.querySelector(".bid-data");if(h){u(h);const e=d(t.bidPrice,2,"0.00"),n=t.bidSize||0;h.appendChild(document.createTextNode(`$${e}`));const i=l("span",`× ${n}`,"size-info");h.appendChild(i)}const g=this.container.querySelector(".ask-data");if(g){u(g);const e=d(t.askPrice,2,"0.00"),n=t.askSize||0;g.appendChild(document.createTextNode(`$${e}`));const i=l("span",`× ${n}`,"size-info");g.appendChild(i)}const p=this.container.querySelector(".volume");p&&(p.textContent=t.formatVolume());const m=this.container.querySelector(".avg-volume");m&&(m.textContent=t.formatAverageVolume());const b=this.container.querySelector(".prev-close");b&&(b.textContent=`$${t.previousClose?.toFixed(2)||"0.00"}`);const y=this.container.querySelector(".open-price");y&&(y.textContent=`$${t.openPrice?.toFixed(2)||"0.00"}`);const x=this.container.querySelector(".day-range");x&&(x.textContent=t.formatDayRange());const v=this.container.querySelector(".week-range");v&&(v.textContent=t.format52WeekRange());const w=this.container.querySelector(".market-cap");w&&(w.textContent=t.formatMarketCap());const S=this.container.querySelector(".pe-ratio");S&&(S.textContent=t.peRatio?.toFixed(2)||"N/A");const k=this.container.querySelector(".dividend-yield");k&&(k.textContent=t.dividendYield?`${t.dividendYield.toFixed(2)}%`:"N/A");const M=this.container.querySelector(".beta");M&&(M.textContent=t.beta?.toFixed(2)||"N/A");const C=f(t.quoteTime),_=this.container.querySelector(".last-update");_&&(_.textContent=`Last update: ${C}`);const D=this.container.querySelector(".data-source");D&&(D.textContent=`Source: ${t.getDataSource()}`)}catch(t){console.error("Error updating widget:",t),this.showError("Error updating data")}}showLoading(){const t=this.container.querySelector(".widget-loading-overlay");t&&t.classList.remove("hidden")}hideLoading(){const t=this.container.querySelector(".widget-loading-overlay");t&&t.classList.add("hidden")}showError(t){this.hideLoading(),this.clearError();const e=document.createElement("div");e.className="widget-error",e.textContent=`Error: ${t}`,e.style.cssText="\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n padding: 15px 20px;\n background: #fee;\n border: 1px solid #f5c6cb;\n border-radius: 6px;\n color: #721c24;\n text-align: center;\n font-size: 14px;\n z-index: 100;\n ",this.container.appendChild(e)}clearError(){const t=this.container.querySelector(".widget-error"),e=this.container.querySelector(".widget-error-container");t&&t.remove(),e&&e.remove()}destroy(){this.isDestroyed=!0,this.loadingTimeout&&(this.clearTimeout(this.loadingTimeout),this.loadingTimeout=null),this.unsubscribe&&(this.unsubscribe(),this.unsubscribe=null),this.symbolEditor&&(this.symbolEditor.destroy(),this.symbolEditor=null),super.destroy()}}class y{constructor(){let t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};this.symbol=t.Symbol||"",this.marketName=t.MarketName||("bruce"===t.Source?.toLowerCase()?"Bruce":"Blue Ocean"),this.marketDesc=null!==t.MarketDesc?t.MarketDesc||"":null,this.countryCode=null!==t.CountryCode?t.CountryCode||"":null,this.volume=null!==t.Volume?t.Volume||0:null,this.askPrice=null!==t.AskPx?t.AskPx||0:null,this.askSize=null!==t.AskSz?t.AskSz||0:null,this.bidPrice=null!==t.BidPx?t.BidPx||0:null,this.bidSize=null!==t.BidSz?t.BidSz||0:null,this.lastPrice=null!==t.LastPx?t.LastPx||0:null,this.quoteTime=null!==t.QuoteTime?t.QuoteTime:null,this.activityTimestamp=null!==t.ActivityTimestamp?t.ActivityTimestamp||"":null,this.tradeSize=null!==t.TradeSz?t.TradeSz||0:null,this.bidExchange=null!==t.BidExch?t.BidExch||"":null,this.askExchange=null!==t.AskExch?t.AskExch||"":null,this.notFound=t.NotFound||!1,this.source=t.Source||"",this.accuAmount=null!==t.AccuAmmount?t.AccuAmmount||0:null,this.change=null!==t.Change?t.Change||0:null,this.changePercent=null!==t.ChangePercent?t.ChangePercent||0:null,this.closingPrice=null!==t.ClosingPx?t.ClosingPx:null!==t.PreviousClose?t.PreviousClose:null,this.highPrice=null!==t.HighPx?t.HighPx||0:null,this.lowPrice=null!==t.LowPx?t.LowPx||0:null,this.openPrice=null!==t.OpenPx?t.OpenPx||0:null,this.tradePrice=null!==t.TradePx?t.TradePx||0:null,this.tradeRegionName=null!==t.TradeRegionName?t.TradeRegionName||"":null,this.companyName=t.comp_name||t.CompanyName||"",this.exchangeName=t.market_name||t.Exchange||"",this.mic=t.mic||""}formatPrice(){return`$${this.lastPrice.toFixed(2)}`}formatBidAsk(){return`$${this.bidPrice.toFixed(2)} × ${this.bidSize} / $${this.askPrice.toFixed(2)} × ${this.askSize}`}formatVolume(){return this.volume.toLocaleString()}formatPriceChange(){if(null===this.change||void 0===this.change)return"--";return`${this.change>0?"+":""}${this.change.toFixed(2)}`}formatPriceChangePercent(){if(null===this.changePercent||void 0===this.changePercent)return"--";return`${this.changePercent>0?"+":""}${this.getPriceChangePercent().toFixed(2)}%`}getDataSource(){return"blueocean-d"===this.source.toLowerCase()||"bruce-d"===this.source.toLowerCase()?"bruce-d"===this.source.toLowerCase()?"Bruce 20 mins delayed":"BlueOcean 20 mins delayed":this.source.toLowerCase().includes("bruce")||this.source.toLowerCase().includes("blueocean")||this.source.toLowerCase().includes("onbbo")?"bruce"===this.source.toLowerCase()?"Bruce Real-time":"onbbo"===this.source.toLowerCase()?"ONBBO Real-time":"BlueOcean Real-time":null!==this.source&&""!==this.source?this.source:"MDAS"}getPriceChangePercent(){return null===this.changePercent||void 0===this.changePercent?0:Math.abs(this.changePercent)>1?this.changePercent:100*this.changePercent}}class x extends n{constructor(t,e,n){if(super(t,e,n),!e.symbol)throw new Error("Symbol is required for NightSessionWidget");if(!e.wsManager)throw new Error("WebSocketManager is required for NightSessionWidget");if(!e.source||"blueocean"!==e.source.toLowerCase()&&"bruce"!==e.source.toLowerCase()&&"onbbo"!==e.source.toLowerCase())throw new Error('Source should be either "blueocean", "bruce", or "onbbo"');this.type="nightsession "+e.source;const i=g(e.symbol);if(!i.valid)throw new Error(`Invalid symbol: ${i.error}`);this.symbol=i.sanitized,this.source=e.source||"blueocean",this.wsManager=e.wsManager,this.debug=e.debug||!1,this.styled=void 0===e.styled||e.styled,this.data=null,this.isDestroyed=!1,this.unsubscribe=null,this.symbolEditor=null,this.loadingTimeout=null,this.companyName="",this.exchangeName="",this.mic="",this.createWidgetStructure(),this.initialize()}createWidgetStructure(){if(this.container.innerHTML='\n <div class="night-session-widget widget">\n <div class="widget-content">\n \x3c!-- Header Section --\x3e\n <div class="widget-header">\n <div class="symbol-section">\n <div class="company-market-info">\n <span class="night-company-name"></span>\n <span class="market-name"></span>\n </div>\n <h1 class="symbol editable-symbol"\n title="Double-click to edit symbol"\n data-original-symbol="">\n </h1>\n\n </div>\n <div class="price-section">\n <div class="current-price"></div>\n <div class="price-change">\n <span class="change-value"></span>\n <span class="change-percent"></span>\n </div>\n <div class="price-metadata">\n <div class="last-update"></div>\n <div class="data-source"></div>\n </div>\n </div>\n </div>\n\n \x3c!-- Data Grid Section --\x3e\n <div class="data-grid">\n <div class="data-section">\n <div class="section-title">Quote</div>\n <div class="data-row">\n <span class="data-label">Bid</span>\n <span class="data-value bid-ask-value">\n <span class="bid-price"></span>\n <span class="size-info bid-size"></span>\n </span>\n </div>\n <div class="data-row">\n <span class="data-label">Ask</span>\n <span class="data-value bid-ask-value">\n <span class="ask-price"></span>\n <span class="size-info ask-size"></span>\n </span>\n </div>\n </div>\n\n <div class="data-section">\n <div class="section-title">Trading Activity</div>\n <div class="data-row">\n <span class="data-label">Volume</span>\n <span class="data-value volume"></span>\n </div>\n <div class="data-row">\n <span class="data-label">Accumulated Amount</span>\n <span class="data-value accu-amount"></span>\n </div>\n </div>\n\n <div class="data-section">\n <div class="section-title">Performance</div>\n <div class="data-row">\n <span class="data-label">Previous Close</span>\n <span class="data-value previous-close"></span>\n </div>\n <div class="data-row at-close-row">\n <span class="data-label">At close</span>\n <span class="data-value at-close-time"></span>\n </div>\n <div class="data-row">\n <span class="data-label">Open</span>\n <span class="data-value open-price"></span>\n </div>\n <div class="data-row">\n <span class="data-label">Day Range</span>\n <span class="data-value range-value day-range"></span>\n </div>\n </div>\n </div>\n </div>\n\n \x3c!-- Loading Overlay --\x3e\n <div class="widget-loading-overlay">\n <div class="loading-content">\n <div class="loading-spinner"></div>\n <span class="loading-text">Loading night session data...</span>\n </div>\n </div>\n </div>\n',this.styled){const t=this.container.querySelector(".night-session-widget");t&&t.classList.add("widget-styled")}this.addStyles(),this.setupSymbolEditor()}addStyles(){if(!document.querySelector("#night-session-styles")){const t=document.createElement("style");t.id="night-session-styles",t.textContent=a,document.head.appendChild(t)}}setupSymbolEditor(){this.symbolEditor=new s(this,{maxLength:10,placeholder:"Enter symbol...",onSymbolChange:this.handleSymbolChange.bind(this),debug:this.debug,autoUppercase:!0,cancelOnBlur:!1,symbolType:"nightsession"})}async handleSymbolChange(t,e){let n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;this.debug&&(console.log("[NightSessionWidget] Symbol change requested:",t),console.log("[NightSessionWidget] Validation data:",n));const i=g(t);if(!i.valid)return this.debug&&console.log("[NightSessionWidget] Invalid symbol:",i.error),{success:!1,error:i.error};const s=i.sanitized;if(n&&(this.companyName=n.comp_name||"",this.exchangeName=n.market_name||"",this.mic=n.mic||"",this.debug&&console.log("[NightSessionWidget] Extracted company info:",{companyName:this.companyName,exchangeName:this.exchangeName},n)),s===this.symbol)return this.debug&&console.log("[NightSessionWidget] Same symbol, no change needed"),{success:!0};try{const t=this.symbol;return this.showLoading(),this.loadingTimeout&&this.clearTimeout(this.loadingTimeout),this.loadingTimeout=this.setTimeout((()=>{this.debug&&console.log("[NightSessionWidget] Loading timeout for symbol:",s),this.hideLoading(),this.showError(`No data received for ${s}. Please try again.`)}),1e4),this.unsubscribe&&(this.debug&&console.log(`[NightSessionWidget] Unsubscribing from ${t}`),this.unsubscribe(),this.unsubscribe=null),this.symbol=s,this.debug&&console.log(`[NightSessionWidget] Subscribing to ${s}`),this.subscribeToData(),this.debug&&console.log(`[NightSessionWidget] Successfully changed symbol from ${t} to ${s}`),{success:!0}}catch(t){return console.error("[NightSessionWidget] Error changing symbol:",t),this.showError(`Failed to load data for ${s}`),{success:!1,error:`Failed to load ${s}`}}}async initialize(){this.showLoading(),await this.validateInitialSymbol(),this.loadingTimeout=setTimeout((()=>{this.debug&&console.log("[NightSessionWidget] Loading timeout - no data received for:",this.symbol),this.hideLoading(),this.showNoDataState({Symbol:this.symbol,NotFound:!0,message:"No data available for this symbol"})}),1e4),this.subscribeToData()}async validateInitialSymbol(){try{const t=this.wsManager.getApiService();if(!t)return void(this.debug&&console.log("[NightSessionWidget] API service not available for initial validation"));const e=await t.quotel1(this.symbol);if(e&&e.data&&e.data[0]){const t=e.data[0];this.companyName=t.comp_name||"",this.exchangeName=t.market_name||"",this.mic=t.mic||"",this.debug&&console.log("[NightSessionWidget] Initial symbol validated:",{symbol:this.symbol,companyName:this.companyName,exchangeName:this.exchangeName,mic:this.mic})}}catch(t){this.debug&&console.warn("[NightSessionWidget] Initial symbol validation failed:",t)}}subscribeToData(){let t;t="bruce"===this.source?"querybrucel1":"onbbo"===this.source?"queryonbbol1":"queryblueoceanl1",this.unsubscribe=this.wsManager.subscribe(this.widgetId,[t],this.handleMessage.bind(this),this.symbol)}handleData(t){if(this.loadingTimeout&&(clearTimeout(this.loadingTimeout),this.loadingTimeout=null),"error"===t.type&&t.noData)return this.debug&&console.log("[NightSessionWidget] Received no data message:",t.message),void(this.data?(this.hideLoading(),this.debug&&console.log("[NightSessionWidget] No new data, keeping cached data visible")):this.showNoDataState({Symbol:this.symbol,NotFound:!0,message:t.message}));if("error"!==t.type){if(Array.isArray(t)){const e=t.find((t=>t.Symbol===this.symbol));if(e){if(this.debug&&console.log("[NightSessionWidget] Found data for symbol:",e),!0===e.NotFound)this.data?(this.hideLoading(),this.debug&&console.log("[NightSessionWidget] No new data, keeping cached data visible")):this.showNoDataState(e);else{const t=new y(e);this.data=t,this.updateWidget(t)}return}this.data?(this.hideLoading(),this.debug&&console.log("[NightSessionWidget] No matching data in response, keeping cached data")):this.showNoDataState({Symbol:this.symbol,NotFound:!0})}else if("queryblueoceanl1"===t.type||"querybrucel1"===t.type||"queryonbbol1"===t.type)if(t[0]?.Symbol===this.symbol){const e="queryonbbol1"===t.type;if(!0===t[0].NotFound||!e&&(!t[0].MarketName||"BLUE"!==t[0].MarketName))this.data?(this.hideLoading(),this.debug&&console.log("[NightSessionWidget] No new data, keeping cached data visible")):this.showNoDataState(t[0]);else{const e=new y(t[0]);this.data=e,this.updateWidget(e)}}else this.debug&&console.log("[NightSessionWidget] No matching symbol in response, keeping cached data"),this.hideLoading();t._cached}else{const e=t.message||"Server error";e.toLowerCase().includes("access")||e.toLowerCase().includes("permission")||e.toLowerCase().includes("denied")?this.data?(this.hideLoading(),this.debug&&console.log("[NightSessionWidget] Access error but keeping cached data")):this.showNoDataState({Symbol:this.symbol,NotFound:!0,isAccessError:!0,message:e}):this.data?(this.hideLoading(),this.debug&&console.log("[NightSessionWidget] Error received but keeping cached data:",e)):(console.log("errorMsg",e),this.showError(e))}}updateWidget(t){if(!this.isDestroyed)try{this.hideLoading(),this.clearError();const e=this.container.querySelector(".widget-header");e&&e.classList.remove("dimmed");const n=this.container.querySelector(".price-section");n&&n.classList.remove("dimmed");const i=this.container.querySelector(".data-grid");i&&(i.style.display="grid");const s=this.container.querySelector(".no-data-state");s&&s.remove();const o=this.container.querySelector(".symbol");o&&(o.textContent=t.symbol);const a=this.container.querySelector(".night-company-name");a&&(a.textContent=this.companyName||t.companyName||"");const r=this.container.querySelector(".market-name");r&&(r.textContent=this.exchangeName||t.exchangeName||"");const c=this.container.querySelector(".current-price");c&&(c.textContent=null!==t.lastPrice?t.formatPrice():"--");const l=t.change,d=this.container.querySelector(".price-change");if(d){const e=d.querySelector(".change-value"),n=d.querySelector(".change-percent");e&&(e.textContent=null!==l&&0!==l?l:"--"),n&&(0!==t.changePercent?n.textContent=` (${t.getPriceChangePercent().toFixed(2)}%)`:n.textContent=" (0.00%)"),d.classList.remove("positive","negative","neutral"),l>0?d.classList.add("positive"):l<0?d.classList.add("negative"):d.classList.add("neutral")}const h=this.container.querySelector(".bid-price");h&&(h.textContent=null!==t.bidPrice?`$${t.bidPrice.toFixed(2)} `:"-- ×");const u=this.container.querySelector(".bid-size");u&&(u.textContent=null!==t.bidSize?`× ${t.bidSize}`:"--");const g=this.container.querySelector(".ask-price");g&&(g.textContent=null!==t.askPrice?`$${t.askPrice.toFixed(2)} `:"-- ×");const p=this.container.querySelector(".ask-size");p&&(p.textContent=null!==t.askSize?`× ${t.askSize}`:"--");const m=this.container.querySelector(".volume");m&&(m.textContent=null!==t.volume?t.formatVolume():"--");const b=this.container.querySelector(".accu-amount");b&&(b.textContent=null!==t.accuAmount?`$${t.accuAmount.toLocaleString()}`:"--");const y=this.container.querySelector(".open-price");y&&(y.textContent=null!==t.openPrice?`$${t.openPrice.toFixed(2)}`:"--");const x=this.container.querySelector(".previous-close");x&&(x.textContent=null!==t.closingPrice?`$${t.closingPrice.toFixed(2)}`:"--");const v=this.container.querySelector(".at-close-time");if(v){const e=t.quoteTime?f(new Date(t.quoteTime)):"--";v.textContent=e}const w=this.container.querySelector(".day-range");w&&(null!==t.highPrice&&null!==t.lowPrice?w.textContent=`$${t.lowPrice.toFixed(2)} - $${t.highPrice.toFixed(2)}`:w.textContent="--");const S=this.container.querySelector(".data-source");S&&(S.textContent="Source: "+t.getDataSource());const k=(t=>{if(!t)return f();const e=new Date(t);return isNaN(e.getTime())?f():f(e)})(t.quoteTime),M=this.container.querySelector(".last-update");M&&(M.textContent=`Overnight: ${k}`)}catch(t){console.error("Error updating widget:",t),this.showError("Error updating data")}}showLoading(){const t=this.container.querySelector(".widget-loading-overlay");t&&t.classList.remove("hidden")}hideLoading(){const t=this.container.querySelector(".widget-loading-overlay");t&&t.classList.add("hidden")}showError(t){this.hideLoading(),this.clearError();const e=document.createElement("div");e.className="widget-error",e.textContent=`Error: ${t}`,e.style.cssText="\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n padding: 15px 20px;\n background: #fee;\n border: 1px solid #f5c6cb;\n border-radius: 6px;\n color: #721c24;\n text-align: center;\n font-size: 14px;\n z-index: 100;\n ",this.container.appendChild(e)}clearError(){const t=this.container.querySelector(".widget-error"),e=this.container.querySelector(".widget-error-container");t&&t.remove(),e&&e.remove()}showNoDataState(){let t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};if(!this.isDestroyed)try{this.hideLoading(),this.clearError();const e=t.Symbol||this.symbol,n=this.container.querySelector(".symbol");n&&(n.textContent=e);const i=this.container.querySelector(".current-price");i&&(i.textContent="$0.00");const s=this.container.querySelector(".price-change");if(s){const t=s.querySelector(".change-value");t&&(t.textContent="+0.00");const e=s.querySelector(".change-percent");e&&(e.textContent=" (0.00%)"),s.classList.remove("positive","negative")}const o=this.container.querySelector(".widget-header");o&&o.classList.add("dimmed");const a=this.container.querySelector(".price-section");a&&a.classList.add("dimmed"),this.showNoDataMessage(e,t);const r=f(),c=this.container.querySelector(".last-update");c&&(c.textContent=`Overnight: ${r}`)}catch(t){console.error("Error showing no data state:",t),this.showError("Error displaying no data state")}}showNoDataMessage(t){let e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const n=this.container.querySelector(".data-grid");n&&(n.style.display="none");const i=this.container.querySelector(".no-data-state");i&&i.remove();const s=e.isAccessError||e.message&&e.message.toLowerCase().includes("access"),o=l("div","","no-data-state"),a=l("div","","no-data-content");if(s){const n=document.createElement("div");n.className="no-data-icon error",n.innerHTML='<svg width="32" height="32" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">\n <circle cx="12" cy="12" r="10" stroke="#ef4444" stroke-width="2"/>\n <path d="M12 8v4" stroke="#ef4444" stroke-width="2" stroke-linecap="round"/>\n <circle cx="12" cy="16" r="1" fill="#ef4444"/>\n </svg>',a.appendChild(n);const i=l("h3",String(e.message||"Access Denied"),"no-data-title error");a.appendChild(i);const s=l("p","","no-data-description");s.appendChild(document.createTextNode("You do not have permission to view night session data for "));const o=l("strong",h(t));s.appendChild(o),a.appendChild(s);const r=l("p","Contact your administrator or try a different symbol","no-data-guidance");a.appendChild(r)}else{const n=document.createElement("div");n.className="no-data-icon",n.innerHTML='<svg width="32" height="32" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">\n <circle cx="12" cy="12" r="10" stroke="#9ca3af" stroke-width="2"/>\n <path d="M12 6v6l4 2" stroke="#9ca3af" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>\n </svg>',a.appendChild(n);const i=l("h3",String(e.message||"No Data Available"),"no-data-title");a.appendChild(i);const s=l("p","","no-data-description");s.appendChild(document.createTextNode("Night session data for "));const o=l("strong",h(t));s.appendChild(o),s.appendChild(document.createTextNode(" was not found")),a.appendChild(s);const r=l("p","Please check the symbol or try again later","no-data-guidance");a.appendChild(r)}o.appendChild(a);const r=this.container.querySelector(".widget-footer");r&&r.parentNode?r.parentNode.insertBefore(o,r):this.container.appendChild(o)}destroy(){this.isDestroyed=!0,this.loadingTimeout&&(this.clearTimeout(this.loadingTimeout),this.loadingTimeout=null),this.unsubscribe&&(this.unsubscribe(),this.unsubscribe=null),this.symbolEditor&&(this.symbolEditor.destroy(),this.symbolEditor=null),super.destroy()}updateSymbol(t){this.handleSymbolChange(t)}}class v{constructor(){let t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};this.rawData=t,this.symbol=t.Symbol||"",this.rootSymbol=t.RootSymbol||"",this.underlying=t.Underlying||"",this.expire=t.Expire||"",this.strike=t.Strike||0,this.type=this.determineOptionType(),this.lastPrice=t.LastPx||0,this.closePx=t.ClosePx||0,this.yestClosePx=t.YestClosePx||0,this.openPx=t.OpenPx||0,this.highPx=t.HighPx||0,this.lowPx=t.LowPx||0,this.bidPx=t.BidPx||0,this.bidSz=t.BidSz||0,this.bidExch=t.BidExch||"",this.askPx=t.AskPx||0,this.askSz=t.AskSz||0,this.askExch=t.AskExch||"",this.volume=t.Volume||0,this.openInterest=t.OpenInst||0,this.primeShare=t.PrimeShare||0,this.exch=t.Exch||"",this.dataSource=t.DataSource||"",this.quoteTime=t.QuoteTime||"",this.notFound=t.NotFound||!1}determineOptionType(){return this.symbol?this.symbol.includes("C")?"call":this.symbol.includes("P")?"put":"unknown":"unknown"}getChange(){return this.lastPrice-this.yestClosePx}getChangePercent(){return 0===this.yestClosePx?0:(this.lastPrice-this.yestClosePx)/this.yestClosePx*100}getSpread(){return this.askPx-this.bidPx}getSpreadPercent(){const t=(this.askPx+this.bidPx)/2;return 0===t?0:(this.askPx-this.bidPx)/t*100}getMidPrice(){return(this.askPx+this.bidPx)/2}formatPrice(t){return t?t.toFixed(2):"0.00"}formatStrike(){return`$${this.formatPrice(this.strike)}`}formatLastPrice(){return`$${this.formatPrice(this.lastPrice)}`}formatClosePx(){return`$${this.formatPrice(this.closePx)}`}formatYestClosePx(){return`$${this.formatPrice(this.yestClosePx)}`}formatOpenPx(){return`$${this.formatPrice(this.openPx)}`}formatHighPx(){return`$${this.formatPrice(this.highPx)}`}formatLowPx(){return`$${this.formatPrice(this.lowPx)}`}formatBid(){return`$${this.formatPrice(this.bidPx)}`}formatAsk(){return`$${this.formatPrice(this.askPx)}`}formatBidSize(){return this.bidSz.toString()}formatAskSize(){return this.askSz.toString()}formatSpread(){return`$${this.formatPrice(this.getSpread())}`}formatMidPrice(){return`$${this.formatPrice(this.getMidPrice())}`}formatChange(){const t=this.getChange();return`${t>=0?"+":""}${this.formatPrice(t)}`}formatChangePercent(){const t=this.getChangePercent();return`${t>=0?"+":""}${t.toFixed(2)}%`}formatVolume(){return this.volume.toLocaleString()}formatOpenInterest(){return this.openInterest.toLocaleString()}formatPrimeShare(){return this.primeShare.toString()}formatExpirationDate(){if(!this.expire)return"N/A";try{return new Date(this.expire).toLocaleDateString("en-US",{year:"numeric",month:"short",day:"numeric"})}catch(t){return this.expire}}formatQuoteTime(){if(!this.quoteTime)return"N/A";try{return new Date(this.quoteTime).toLocaleString("en-US",{year:"numeric",month:"short",day:"numeric",hour:"2-digit",minute:"2-digit",second:"2-digit"})}catch(t){return this.quoteTime}}formatExchange(){return this.exch||"N/A"}formatDataSource(){return this.dataSource||"N/A"}formatDayRange(){return`$${this.formatPrice(this.lowPx)} - $${this.formatPrice(this.highPx)}`}formatOptionType(){return this.type.toUpperCase()}getDaysToExpiration(){if(!this.expire)return 0;try{const t=new Date(this.expire),e=new Date,n=t.getTime()-e.getTime(),i=Math.ceil(n/864e5);return Math.max(0,i)}catch(t){return 0}}formatDaysToExpiration(){const t=this.getDaysToExpiration();return`${t} day${1!==t?"s":""}`}getMoneyness(t){return t&&0!==this.strike?"call"===this.type?t-this.strike:"put"===this.type?this.strike-t:0:0}isInTheMoney(t){return this.getMoneyness(t)>0}parseSymbol(){return{underlying:this.rootSymbol||"",expirationDate:this.expire||"",type:this.type||"",strikePrice:this.strike||0,fullSymbol:this.symbol||""}}getSummary(){return{symbol:this.symbol,underlying:this.underlying,type:this.formatOptionType(),strike:this.formatStrike(),expiration:this.formatExpirationDate(),lastPrice:this.formatLastPrice(),change:this.formatChange(),changePercent:this.formatChangePercent(),volume:this.formatVolume(),openInterest:this.formatOpenInterest(),bid:this.formatBid(),ask:this.formatAsk(),exchange:this.formatExchange()}}getDataSource(){return"opra-d"===this.dataSource.toLowerCase()?"20 mins delayed":"real-time"===this.dataSource.toLowerCase()?"Real-time":"MDAS Server"}static fromApiResponse(t){return new v(t)}isValid(){return!this.notFound&&this.symbol&&this.strike>0}}class w extends n{constructor(t,e,n){if(super(t,e,n),!e.symbol)throw new Error("Symbol is required for OptionsWidget");if(!e.wsManager)throw new Error("WebSocketManager is required for OptionsWidget");this.type="options";const i=p(e.symbol);if(!i.valid)throw new Error(`Invalid option symbol: ${i.error}`);this.symbol=i.sanitized,this.wsManager=e.wsManager,this.debug=e.debug||!1,this.styled=void 0===e.styled||e.styled,this.data=null,this.isDestroyed=!1,this.unsubscribe=null,this.loadingTimeout=null,this.createWidgetStructure(),this.initializeSymbolEditor(),this.initialize()}createWidgetStructure(){if(this.container.innerHTML='\n <div class="options-widget widget">\n <div class="widget-content">\n \x3c!-- Header Section with Purple Background --\x3e\n <div class="widget-header">\n <div class="symbol-section">\n <h1 class="symbol editable-symbol" \n title="Double-click to edit symbol" \n data-original-symbol="">\n </h1>\n <div class="option-info">\n <span class="underlying-symbol"></span>\n <span class="data-type">OPTIONS</span>\n </div>\n </div>\n <div class="price-section">\n <div class="current-price"></div>\n <div class="price-change">\n <span class="change-value"></span>\n <span class="change-percent"></span>\n </div>\n </div>\n </div>\n\n \x3c!-- Data Grid Section --\x3e\n <div class="data-grid">\n <div class="data-section">\n <div class="section-title">Quote</div>\n <div class="data-row">\n <span class="data-label">Bid</span>\n <span class="data-value bid-ask-value bid-data"></span>\n </div>\n <div class="data-row">\n <span class="data-label">Ask</span>\n <span class="data-value bid-ask-value ask-data"></span>\n </div>\n </div>\n\n <div class="data-section">\n <div class="section-title">Trading Activity</div>\n <div class="data-row">\n <span class="data-label">Volume</span>\n <span class="data-value volume"></span>\n </div>\n <div class="data-row">\n <span class="data-label">Open Interest</span>\n <span class="data-value open-interest"></span>\n </div>\n </div>\n\n <div class="data-section">\n <div class="section-title">Performance</div>\n <div class="data-row">\n <span class="data-label">Previous Close</span>\n <span class="data-value yesterday-close"></span>\n </div>\n <div class="data-row">\n <span class="data-label">Open</span>\n <span class="data-value open-price"></span>\n </div>\n <div class="data-row">\n <span class="data-label">Day Range</span>\n <span class="data-value range-value day-range"></span>\n </div>\n </div>\n\n <div class="data-section">\n <div class="section-title">Contract Info</div>\n <div class="data-row">\n <span class="data-label">Strike Price</span>\n <span class="data-value strike-price"></span>\n </div>\n <div class="data-row">\n <span class="data-label">Expiration</span>\n <span class="data-value expiry-date"></span>\n </div>\n <div class="data-row">\n <span class="data-label">Prime Share</span>\n <span class="data-value prime-share"></span>\n </div>\n </div>\n </div>\n\n \x3c!-- Footer --\x3e\n <div class="widget-footer">\n <span class="last-update"></span>\n <span class="data-source"></span>\n </div>\n </div>\n \n \x3c!-- Loading Overlay --\x3e\n <div class="widget-loading-overlay">\n <div class="loading-content">\n <div class="loading-spinner"></div>\n <span class="loading-text">Loading options data...</span>\n </div>\n </div>\n </div>\n',this.styled){const t=this.container.querySelector(".options-widget");t&&t.classList.add("widget-styled")}this.addStyles()}addStyles(){if(!document.querySelector("#options-widget-styles")){const t=document.createElement("style");t.id="options-widget-styles",t.textContent=c,document.head.appendChild(t)}}initializeSymbolEditor(){this.symbolEditor=new s(this,{maxLength:20,placeholder:"Enter option contract...",onSymbolChange:this.handleSymbolChange.bind(this),debug:this.debug,autoUppercase:!0,symbolType:"optionsl1"});const t=this.container.querySelector(".symbol");t&&(t.textContent=this.symbol,t.dataset.originalSymbol=this.symbol)}async handleSymbolChange(t){this.debug&&console.log("[OptionsWidget] Symbol change requested:",t);const e=p(t);if(!e.valid)return this.debug&&console.log("[OptionsWidget] Invalid option symbol:",e.error),{success:!1,error:e.error};const n=e.sanitized;if(n===this.symbol)return this.debug&&console.log("[OptionsWidget] Same symbol, no change needed"),{success:!0};try{const t=this.symbol;return this.showLoading(),this.loadingTimeout&&this.clearTimeout(this.loadingTimeout),this.loadingTimeout=this.setTimeout((()=>{this.debug&&console.log("[OptionsWidget] Loading timeout for symbol:",n),this.hideLoading(),this.showError(`No data received for ${n}. Please try again.`)}),1e4),this.unsubscribe&&(this.debug&&console.log(`[OptionsWidget] Unsubscribing from ${t}`),this.wsManager.sendUnsubscribe("queryoptionl1",t),this.unsubscribe(),this.unsubscribe=null),this.symbol=n,this.debug&&console.log(`[OptionsWidget] Subscribing to ${n}`),this.subscribeToData(),this.debug&&console.log(`[OptionsWidget] Successfully changed symbol from ${t} to ${n}`),{success:!0}}catch(t){return console.error("[OptionsWidget] Error changing symbol:",t),this.showError(`Failed to load data for ${n}`),{success:!1,error:`Failed to load ${n}`}}}async initialize(){this.showLoading(),await this.validateInitialSymbol(),this.subscribeToData()}async validateInitialSymbol(){try{const t=this.wsManager.getApiService();if(!t)return void(this.debug&&console.log("[OptionsWidget] API service not available for initial validation"));const e=await t.quoteOptionl1(this.symbol);if(e&&e[0]&&!e[0].error&&!e[0].not_found){const t=e[0];this.initialValidationData=t,this.debug&&console.log("[OptionsWidget] Initial symbol validated:",{symbol:this.symbol,underlying:t.Underlying||t.RootSymbol})}}catch(t){this.debug&&console.warn("[OptionsWidget] Initial symbol validation failed:",t)}}subscribeToData(){this.unsubscribe=this.wsManager.subscribe(this.widgetId,["queryoptionl1"],this.handleMessage.bind(this),this.symbol)}handleData(t){if(this.loadingTimeout&&(clearTimeout(this.loadingTimeout),this.loadingTimeout=null),"error"!==t.type){if(t.RootSymbol===this.symbol||t.Underlying===this.symbol||t.Symbol?.includes(this.symbol))if(this.debug&&console.log("[OptionsWidget] Found matching options data for",this.symbol,":",t),!0===t.NotFound)this.data?(this.hideLoading(),this.debug&&console.log("[OptionsWidget] No new data, keeping cached data visible")):this.showNoDataState(t);else{const e=new v(t);this.data=e,this.updateWidget(e)}else if(Array.isArray(t)){const e=t.find((t=>t.RootSymbol===this.symbol||t.Underlying===this.symbol||t.Symbol?.includes(this.symbol)));if(e)if(!0===e.NotFound)this.data?(this.hideLoading(),this.debug&&console.log("[OptionsWidget] No new data, keeping cached data visible")):this.showNoDataState(e);else{const t=new v(e);this.data=t,this.updateWidget(t)}else this.debug&&console.log("[OptionsWidget] No matching data in response, keeping cached data"),this.hideLoading()}t._cached&&this.showConnectionQuality()}else{const e=t.message||"Server error";this.data?(this.hideLoading(),this.debug&&console.log("[OptionsWidget] Error received but keeping cached data:",e)):this.showError(e)}}showNoDataState(t){if(!this.isDestroyed)try{this.hideLoading();const e=t.Symbol||this.symbol,n=this.container.querySelector(".symbol");n&&(n.textContent=e);const i=this.container.querySelector(".underlying-symbol");i&&(i.textContent=t.RootSymbol||this.symbol);const s=this.container.querySelector(".current-price");s&&(s.textContent="$0.00");const o=this.container.querySelector(".price-change");if(o){const t=o.querySelector(".change-value");t&&(t.textContent="+0.00");const e=o.querySelector(".change-percent");e&&(e.textContent=" (0.00%)"),o.classList.remove("positive","negative")}const a=this.container.querySelector(".widget-header");a&&a.classList.add("dimmed"),this.showNoDataMessage(e);const r=f(),c=this.container.querySelector(".last-update");c&&(c.textContent=`Checked: ${r}`)}catch(t){console.error("Error showing no data state:",t),this.showError("Error displaying no data state")}}showNoDataMessage(t){const e=this.container.querySelector(".data-grid"),n=this.container.querySelector(".option-details-section");e&&(e.style.display="none"),n&&(n.style.display="none");const i=this.container.querySelector(".no-data-state");i&&i.remove();const s=l("div","","no-data-state"),o=l("div","","no-data-content"),a=document.createElement("div");a.className="no-data-icon",a.innerHTML='<svg width="48" height="48" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">\n <circle cx="12" cy="12" r="10" stroke="#9ca3af" stroke-width="2"/>\n <path d="M12 6v6l4 2" stroke="#9ca3af" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>\n </svg>',o.appendChild(a);const r=l("h3","No Data Available","no-data-title");o.appendChild(r);const c=l("p","","no-data-description");c.appendChild(document.createTextNode("Data for "));const d=l("strong",String(t));c.appendChild(d),c.appendChild(document.createTextNode(" was not found")),o.appendChild(c);const h=l("p","Please check the symbol or try again later","no-data-guidance");o.appendChild(h),s.appendChild(o);const u=this.container.querySelector(".widget-footer");u&&u.parentNode?u.parentNode.insertBefore(s,u):this.container.appendChild(s)}updateWidget(t){if(!this.isDestroyed)try{this.loadingTimeout&&(clearTimeout(this.loadingTimeout),this.loadingTimeout=null),this.hideLoading(),this.clearError();const e=this.container.querySelector(".widget-header");e&&e.classList.remove("dimmed");const n=this.container.querySelector(".data-grid");n&&(n.style.display="grid");const i=this.container.querySelector(".no-data-state");i&&i.remove();const s=this.container.querySelector(".symbol");s&&(s.textContent=t.symbol,s.dataset.originalSymbol=t.symbol);const o=this.container.querySelector(".underlying-symbol");o&&(o.textContent=t.rootSymbol||t.underlying||"QQQ");const a=this.container.querySelector(".current-price");a&&(a.textContent=t.formatLastPrice());const r=t.getChange(),c=this.container.querySelector(".price-change");if(c){const e=c.querySelector(".change-value"),n=c.querySelector(".change-percent");e&&(e.textContent=t.formatChange()),n&&(n.textContent=` (${t.formatChangePercent()})`),c.classList.remove("positive","negative","neutral"),r>0?c.classList.add("positive"):r<0?c.classList.add("negative"):c.classList.add("neutral")}const d=this.container.querySelector(".bid-data");if(d){u(d),d.appendChild(document.createTextNode(t.formatBid()));const e=l("span",`× ${t.bidSz}`,"size-info");d.appendChild(e)}const h=this.container.querySelector(".ask-data");if(h){u(h),h.appendChild(document.createTextNode(t.formatAsk()));const e=l("span",`× ${t.askSz}`,"size-info");h.appendChild(e)}const g=this.container.querySelector(".volume");g&&(g.textContent=t.formatVolume());const p=this.container.querySelector(".open-interest");p&&(p.textContent=t.formatOpenInterest());const m=this.container.querySelector(".day-range");m&&(m.textContent=t.formatDayRange());const b=this.container.querySelector(".open-price");b&&(b.textContent=t.formatOpenPx());const y=this.container.querySelector(".yesterday-close");y&&(y.textContent=t.formatYestClosePx());const x=this.container.querySelector(".strike-price");x&&(x.textContent=t.formatStrike());const v=this.container.querySelector(".expiry-date");v&&(v.textContent=t.formatExpirationDate());const w=this.container.querySelector(".prime-share");w&&(w.textContent=t.formatPrimeShare());const S=f(t.quoteTime||Date.now()),k=this.container.querySelector(".last-update");k&&(k.textContent=`Last update: ${S}`);const M=this.container.querySelector(".data-source");M&&(M.textContent=`Source: ${t.getDataSource()}`)}catch(t){console.error("Error updating options widget:",t),this.showError("Error updating data")}}formatPrice(t){return t?t.toFixed(2):"0.00"}formatPriceChange(t){return`${t>=0?"+":""}${t.toFixed(2)}`}showLoading(){const t=this.container.querySelector(".widget-loading-overlay");t&&t.classList.remove("hidden")}hideLoading(){const t=this.container.querySelector(".widget-loading-overlay");t&&t.classList.add("hidden")}showError(t){this.hideLoading(),this.clearError();const e=document.createElement("div");e.className="widget-error",e.textContent=`Error: ${t}`,e.style.cssText="\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n padding: 15px 20px;\n background: #fee;\n border: 1px solid #f5c6cb;\n border-radius: 6px;\n color: #721c24;\n text-align: center;\n font-size: 14px;\n z-index: 100;\n ",this.container.appendChild(e)}clearError(){const t=this.container.querySelector(".widget-error"),e=this.container.querySelector(".widget-error-container");t&&t.remove(),e&&e.remove()}destroy(){this.isDestroyed=!0,this.loadingTimeout&&(this.clearTimeout(this.loadingTimeout),this.loadingTimeout=null),this.unsubscribe&&(this.unsubscribe(),this.unsubscribe=null),this.symbolEditor&&(this.symbolEditor.destroy(),this.symbolEditor=null),super.destroy()}}class S{constructor(){let t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};this.openInterest=t.OpenInst||0,this.volume=t.Vol||0,this.askSize=t.AskSz||0,this.bidSize=t.BidSz||0,this.strike=t.Strike||0,this.askPrice=t.AskPx||0,this.bidPrice=t.BidPx||0,this.lastChange=t.LastChg||0,this.lastPrice=t.LastPx||0,this.dataSource=t.DataSource||"",this.expire=t.Expire||"",this.symbol=t.Symbol||""}}const k=`\n${o}\n\n/* Base styles remain the same until responsive section */\n.option-chain-widget {\n border: 1px solid #e5e7eb;\n border-radius: 8px;\n background: white;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n font-size: 13px;\n max-width: 100%;\n overflow: hidden;\n position: relative;\n}\n\n.option-chain-widget .widget-header {\n background: #f9fafb;\n padding: 16px;\n border-bottom: 1px solid #e5e7eb;\n}\n\n.option-chain-widget .input-section {\n display: flex;\n gap: 12px;\n align-items: center;\n flex-wrap: wrap;\n}\n\n.option-chain-widget .symbol-input,\n.option-chain-widget .date-select {\n padding: 8px 12px;\n border: 1px solid #d1d5db;\n border-radius: 4px;\n font-size: 14px;\n font-family: inherit;\n min-width: 0;\n flex: 1;\n}\n\n.option-chain-widget .symbol-input {\n text-transform: uppercase;\n min-width: 100px;\n max-width: 120px;\n}\n\n.option-chain-widget .date-select {\n min-width: 140px;\n background: white;\n}\n\n.option-chain-widget .fetch-button {\n padding: 8px 16px;\n background: #3b82f6;\n color: white;\n border: none;\n border-radius: 4px;\n font-size: 14px;\n cursor: pointer;\n font-family: inherit;\n white-space: nowrap;\n}\n\n.option-chain-widget .fetch-button:hover {\n background: #2563eb;\n}\n\n.option-chain-widget .fetch-button:disabled {\n background: #9ca3af;\n cursor: not-allowed;\n}\n\n.option-chain-widget .date-select:disabled {\n background: #f3f4f6;\n color: #9ca3af;\n cursor: not-allowed;\n}\n\n.option-chain-widget .option-chain-table {\n max-height: 800px;\n overflow-x: auto; /* Enable horizontal scrolling */\n overflow-y: auto; /* Enable vertical scrolling if needed */\n -webkit-overflow-scrolling: touch; /* Smooth scrolling on iOS */\n width: 100%; /* Ensure full width */\n position: relative; /* Establish positioning context */\n box-sizing: border-box; /* Include padding and border in the element's total width and height */\n}\n\n.option-chain-widget .table-header {\n background: #f3f4f6;\n font-weight: 600;\n border-bottom: 2px solid #d1d5db;\n position: sticky;\n top: 0;\n z-index: 10;\n width: fit-content; /* Ensure it spans the full width */\n box-sizing: border-box; /* Include padding and border in the element's total width and height */\n}\n\n.option-chain-widget .price-change.positive::before,\n.option-chain-widget .price-change.negative::before {\n content: none;\n}\n \n\n/* Better approach - make section headers align with actual column structure */\n.option-chain-widget .section-headers,\n.option-chain-widget .column-headers {\n\n display: grid;\n grid-template-columns: minmax(160px, 1fr) repeat(6, minmax(80px, 1fr)) 80px minmax(160px, 1fr) repeat(6, minmax(80px, 1fr));\n border-bottom: 1px solid #d1d5db;\n background: #f3f4f6;\n position: sticky;\n top: 0;\n z-index: 12;\n box-sizing: border-box; /* Include padding and border in the element's total width and height */\n margin: 0;\n padding: 0;\n min-width: fit-content;\n}\n\n.option-chain-widget .calls-header {\n grid-column: 1 / 8; /* Span across first 7 columns */\n padding: 8px;\n text-align: center;\n font-weight: 600;\n font-size: 14px;\n color: #374151;\n display: flex;\n align-items: center;\n justify-content: center;\n background: #f3f4f6;\n}\n\n.option-chain-widget .strike-header {\n grid-column: 8 / 9; /* Strike column */\n background: #e5e7eb;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.option-chain-widget .puts-header {\n grid-column: 9 / -1; /* Span from column 9 to the end */\n padding: 8px;\n text-align: center;\n font-weight: 600;\n font-size: 14px;\n color: #374151;\n display: flex;\n align-items: center;\n justify-content: center;\n background: #f3f4f6;\n}\n\n.option-chain-widget .column-headers {\n display: grid;\n grid-template-columns: minmax(160px, 1fr) repeat(6, minmax(80px, 1fr)) 80px minmax(160px, 1fr) repeat(6, minmax(80px, 1fr));\n position: sticky;\n top: 40px;\n z-index: 11;\n background: #f3f4f6;\n}\n\n.option-chain-widget .calls-columns,\n.option-chain-widget .puts-columns {\n display: contents; /* Remove their own grid, use parent grid */\n}\n\n.option-chain-widget .strike-column {\n display: flex;\n align-items: center;\n justify-content: center;\n background: #e5e7eb !important;\n font-weight: bold;\n color: #374151;\n font-size: 11px;\n text-transform: uppercase;\n}\n\n.option-chain-widget .strike-column span {\n background: transparent !important; /* Ensure span doesn't override parent background */\n}\n\n.option-chain-widget .column-headers span {\n padding: 6px 2px; /* Reduce padding to prevent text overflow */\n text-align: center;\n font-size: 11px; /* Reduce font size */\n text-transform: uppercase;\n color: #6b7280;\n font-weight: 600;\n letter-spacing: 0.3px; /* Reduce letter spacing */\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n background: #f3f4f6;\n}\n\n.option-chain-widget .option-row {\n display: grid;\n grid-template-columns: minmax(160px, 1fr) repeat(6, minmax(80px, 1fr)) 80px minmax(160px, 1fr) repeat(6, minmax(80px, 1fr));\n border-bottom: 1px solid #f3f4f6;\n min-height: 32px;\n}\n\n.option-chain-widget .option-row:hover {\n background: #f9fafb;\n}\n .option-chain-widget .option-row:hover .calls-data span,\n.option-chain-widget .option-row:hover .puts-data span,\n.option-chain-widget .option-row:hover .strike-data {\n background: #f9fafb;\n}\n\n.option-chain-widget .calls-data,\n.option-chain-widget .puts-data {\n display: contents; /* Make children participate in parent grid */\n}\n\n.option-chain-widget .strike-data {\n display: flex;\n align-items: center;\n justify-content: center;\n background: #f9fafb;\n font-weight: 600; /* Changed from bold to 600 for consistency */\n color: #6b7280; /* Changed from #1f2937 to match other widgets */\n}\n\n.option-chain-widget .calls-data span,\n.option-chain-widget .puts-data span {\n padding: 6px 4px;\n text-align: center;\n font-size: 12px; /* Changed from 12px to 14px */\n font-weight: 400; /* Added to match data values in other widgets */\n color: #111827; /* Changed from #374151 to match other widgets */\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.option-chain-widget .contract-cell {\n font-size: 10px;\n color: #6b7280;\n text-align: left;\n padding: 4px 6px;\n font-family: monospace;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.option-chain-widget .positive {\n color: #059669;\n}\n\n.option-chain-widget .negative {\n color: #dc2626;\n}\n\n.option-chain-widget .neutral {\n color: #6b7280;\n}\n\n.option-chain-widget .widget-footer {\n background: #f9fafb;\n padding: 8px 16px;\n border-top: 1px solid #e5e7eb;\n text-align: center;\n font-size: 11px;\n color: #6b7280;\n}\n\n.option-chain-widget .widget-loading-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(255, 255, 255, 0.9);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 20;\n}\n\n.option-chain-widget .widget-loading-overlay.hidden {\n display: none;\n}\n\n.option-chain-widget .loading-content {\n text-align: center;\n}\n\n.option-chain-widget .loading-spinner {\n width: 32px;\n height: 32px;\n border: 3px solid #e5e7eb;\n border-top: 3px solid #3b82f6;\n border-radius: 50%;\n animation: spin 1s linear infinite;\n margin: 0 auto 12px;\n}\n\n@keyframes spin {\n 0% { transform: rotate(0deg); }\n 100% { transform: rotate(360deg); }\n}\n\n.option-chain-widget .no-data-state {\n padding: 40px;\n text-align: center;\n color: #6b7280;\n}\n\n.option-chain-widget .widget-error {\n padding: 20px;\n background: #fef2f2;\n color: #dc2626;\n border: 1px solid #fecaca;\n margin: 16px;\n border-radius: 4px;\n text-align: center;\n}\n\n/* RESPONSIVE STYLES */\n\n/* Tablet styles (768px and down) */\n@media (max-width: 768px) {\n .option-chain-widget .input-section {\n flex-direction: column;\n align-items: stretch;\n gap: 8px;\n }\n \n .option-chain-widget .symbol-input,\n .option-chain-widget .date-select {\n width: 100%;\n max-width: none;\n }\n \n .option-chain-widget .fetch-button {\n width: 100%;\n }\n \n .option-chain-widget .calls-columns,\n .option-chain-widget .puts-columns {\n grid-template-columns: 120px repeat(6, minmax(50px, 1fr));\n }\n \n .option-chain-widget .calls-data,\n .option-chain-widget .puts-data {\n grid-template-columns: 120px repeat(6, minmax(50px, 1fr));\n }\n \n .option-chain-widget .column-headers span {\n font-size: 10px;\n padding: 6px 2px;\n }\n \n .option-chain-widget .calls-data span,\n .option-chain-widget .puts-data span {\n font-size: 11px;\n padding: 4px 2px;\n }\n \n .option-chain-widget .contract-cell {\n font-size: 9px;\n padding: 4px 4px;\n }\n \n .option-chain-widget .strike-data {\n font-size: 12px;\n }\n\n /* Update responsive breakpoints to match */\n .option-chain-widget .section-headers {\n grid-template-columns: 1fr 80px 1fr;\n background: #f3f4f6;\n width: 100%;\n\n }\n}\n\n/* Mobile styles (480px and down) */\n@media (max-width: 480px) {\n .option-chain-widget {\n font-size: 12px;\n }\n \n .option-chain-widget .widget-header {\n padding: 12px;\n }\n \n .option-chain-widget .section-headers {\n grid-template-columns: 1fr 60px 1fr;\n background: #f3f4f6;\n }\n \n .option-chain-widget .column-headers {\n grid-template-columns: 1fr 60px 1fr;\n }\n \n .option-chain-widget .option-row {\n grid-template-columns: 1fr 60px 1fr;\n min-height: 28px;\n }\n \n .option-chain-widget .calls-columns,\n .option-chain-widget .puts-columns {\n grid-template-columns: 100px repeat(6, minmax(40px, 1fr));\n }\n \n .option-chain-widget .calls-data,\n .option-chain-widget .puts-data {\n grid-template-columns: 100px repeat(6, minmax(40px, 1fr));\n }\n \n .option-chain-widget .column-headers span {\n font-size: 9px;\n padding: 4px 1px;\n }\n \n .option-chain-widget .calls-data span,\n .option-chain-widget .puts-data span {\n font-size: 10px;\n padding: 3px 1px;\n }\n \n .option-chain-widget .contract-cell {\n font-size: 8px;\n padding: 3px 2px;\n }\n \n .option-chain-widget .strike-data {\n font-size: 11px;\n padding: 3px;\n }\n \n \n .option-chain-widget .option-chain-table {\n max-height: 400px;\n }\n \n .option-chain-widget .no-data-state {\n padding: 20px;\n font-size: 12px;\n }\n \n .option-chain-widget .widget-error {\n margin: 8px;\n padding: 12px;\n font-size: 12px;\n }\n}\n\n/* Very small mobile (320px and down) */\n@media (max-width: 320px) {\n .option-chain-widget .section-headers {\n grid-template-columns: 1fr 50px 1fr;\n }\n \n .option-chain-widget .column-headers {\n grid-template-columns: 1fr 50px 1fr;\n }\n \n .option-chain-widget .option-row {\n grid-template-columns: 1fr 50px 1fr;\n }\n \n .option-chain-widget .calls-columns,\n .option-chain-widget .puts-columns {\n grid-template-columns: 80px repeat(6, minmax(35px, 1fr));\n }\n \n .option-chain-widget .calls-data,\n .option-chain-widget .puts-data {\n grid-template-columns: 80px repeat(6, minmax(35px, 1fr));\n }\n \n .option-chain-widget .column-headers span {\n font-size: 8px;\n padding: 3px 1px;\n }\n \n .option-chain-widget .calls-data span,\n .option-chain-widget .puts-data span {\n font-size: 9px;\n padding: 2px 1px;\n }\n \n .option-chain-widget .contract-cell {\n font-size: 7px;\n padding: 2px 1px;\n }\n}\n`;class M extends n{constructor(t,e,n){if(super(t,e,n),!e.wsManager)throw new Error("WebSocketManager is required for OptionChainWidget");if(this.type="optionchain",this.wsManager=e.wsManager,this.debug=e.debug||!1,this.data=null,this.isDestroyed=!1,this.unsubscribe=null,this.loadingTimeout=null,e.symbol){const t=g(e.symbol);t.valid?this.symbol=t.sanitized:(console.warn("[OptionChainWidget] Invalid initial symbol:",t.error),this.symbol="")}else this.symbol="";this.date="",this.availableDates={},this.fetchRateLimiter=function(){let t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:500,e=0;return()=>{const n=Date.now(),i=n-e;return i<t?{valid:!1,error:`Please wait ${Math.ceil((t-i)/1e3)} seconds`,remainingMs:t-i}:(e=n,{valid:!0})}}(1e3),this.createWidgetStructure(),this.initialize()}createWidgetStructure(){this.container.innerHTML='\n <div class="option-chain-widget widget">\n <div class="widget-content">\n \x3c!-- Header Section --\x3e\n <div class="widget-header">\n <div class="input-section">\n <input type="text" class="symbol-input" placeholder="Enter Symbol" value="" />\n <select class="date-select" disabled>\n <option value="">Select a date...</option>\n </select>\n <button class="fetch-button" disabled>Search</button>\n </div>\n </div>\n\n \x3c!-- Data Grid Section --\x3e\n <div class="option-chain-table">\n <div class="table-header">\n <div class="section-headers">\n <div class="calls-header">Calls</div>\n <div class="strike-header"></div>\n <div class="puts-header">Puts</div>\n </div>\n <div class="column-headers">\n <div class="calls-columns">\n <span>Contract</span>\n <span>Last</span>\n <span>Change</span>\n <span>Bid</span>\n <span>Ask</span>\n <span>Volume</span>\n <span>Open Int.</span>\n </div>\n <div class="strike-column">\n <span>Strike</span>\n </div>\n <div class="puts-columns">\n <span>Contract</span>\n <span>Last</span>\n <span>Change</span>\n <span>Bid</span>\n <span>Ask</span>\n <span>Volume</span>\n <span>Open Int.</span>\n </div>\n </div>\n </div>\n <div class="option-chain-data-grid">\n \x3c!-- Option chain data will be populated here --\x3e\n </div>\n </div>\n\n \x3c!-- Footer --\x3e\n <div class="widget-footer">\n <span class="last-update"></span>\n <span class="data-source"></span>\n </div>\n </div>\n \n \x3c!-- Loading Overlay --\x3e\n <div class="widget-loading-overlay hidden">\n <div class="loading-content">\n <div class="loading-spinner"></div>\n <span class="loading-text">Loading option chain data...</span>\n </div>\n </div>\n </div>\n',this.addStyles(),this.setupEventListeners()}addStyles(){if(!document.querySelector("#option-chain-styles")){const t=document.createElement("style");t.id="option-chain-styles",t.textContent=k,document.head.appendChild(t)}}setupEventListeners(){this.symbolInput=this.container.querySelector(".symbol-input"),this.dateSelect=this.container.querySelector(".date-select"),this.fetchButton=this.container.querySelector(".fetch-button"),this.dataGrid=this.container.querySelector(".option-chain-data-grid"),this.symbol&&(this.symbolInput.value=this.symbol,this.fetchButton.disabled=!1,this.dateSelect.innerHTML='<option value="">Click search to load dates...</option>'),this.addEventListener(this.symbolInput,"input",(t=>{const e=t.target.value,n=g(e);this.clearInputError(this.symbolInput),n.valid?(this.symbol=n.sanitized,this.symbolInput.value=n.sanitized,this.dateSelect.innerHTML='<option value="">Click search to load dates...</option>',this.dateSelect.disabled=!0,this.fetchButton.disabled=!1,this.availableDates={},this.date=""):""!==e.trim()?(this.showInputError(this.symbolInput,n.error),this.fetchButton.disabled=!0):this.clearDateOptions()})),this.addEventListener(this.dateSelect,"change",(t=>{const e=t.target.value;if(!e)return void(this.date="");const n=function(t){if(!t||"string"!=typeof t)return{valid:!1,error:"Date is required",normalized:""};const e=t.trim();let n;if(/^\d{4}-\d{2}-\d{2}$/.test(e))n=new Date(e);else if(/^\d{2}\/\d{2}\/\d{4}$/.test(e)){const[t,i,s]=e.split("/");n=new Date(s,parseInt(t,10)-1,parseInt(i,10))}else{if(!/^\d+$/.test(e))return{valid:!1,error:"Invalid date format. Use YYYY-MM-DD or MM/DD/YYYY",normalized:""};n=new Date(parseInt(e,10))}return isNaN(n.getTime())?{valid:!1,error:"Invalid date",normalized:""}:{valid:!0,normalized:n.toISOString().split("T")[0]}}(e);n.valid?(this.date=n.normalized,this.symbol&&this.fetchOptionChain()):(this.showError(n.error),this.date="")})),this.addEventListener(this.fetchButton,"click",(()=>{const t=g(this.symbol);if(!t.valid)return void this.showError(t.error||"Please enter a valid symbol first");const e=this.fetchRateLimiter();e.valid?this.loadAvailableDates(t.sanitized):this.showError(e.error)}))}async loadAvailableDates(t){if(t)try{this.symbol=t,this.symbolInput.value=t,this.dateSelect.disabled=!0,this.dateSelect.innerHTML='<option value="">Loading dates...</option>',this.fetchButton.disabled=!0;const e=this.wsManager.getApiService(),n=await e.getOptionChainDates(t);console.log("Available dates:",n.dates_dictionary),this.availableDates=n.dates_dictionary||{},this.populateDateOptions()}catch(e){console.error("[OptionChainWidget] Error loading dates:",e),this.dateSelect.innerHTML='<option value="">Error loading dates</option>',this.fetchButton.disabled=!1,this.showError(`Failed to load dates for ${t}: ${e.message}`)}}populateDateOptions(){this.dateSelect.innerHTML='<option value="">Select expiration date...</option>';const t=Object.keys(this.availableDates).sort();if(0===t.length)return this.dateSelect.innerHTML='<option value="">No dates available</option>',void(this.fetchButton.disabled=!1);t.forEach((t=>{const e=document.createElement("option");e.value=t;const n=this.availableDates[t],i=function(t){let e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const{timezone:n="ET",format:i="short"}=e;if(!t||"string"!=typeof t)return"";const s=t.split("-");if(3!==s.length)return t;const[o,a,r]=s,c=parseInt(a,10)-1,l=parseInt(r,10),d=("long"===i?["January","February","March","April","May","June","July","August","September","October","November","December"]:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"])[c];return`${d} ${l}, ${o}`}(t,{timezone:m(t),format:"short"});e.textContent=i,e.className=`date-option ${n}`,this.dateSelect.appendChild(e)})),this.dateSelect.disabled=!1,this.fetchButton.disabled=!1,t.length>0&&(this.dateSelect.value=t[0],this.date=t[0],this.fetchOptionChain())}clearDateOptions(){this.dateSelect.innerHTML='<option value="">Click fetch to load dates...</option>',this.dateSelect.disabled=!0,this.fetchButton.disabled=!this.symbol,this.symbol=this.symbolInput.value.trim().toUpperCase()||"",this.date="",this.availableDates={}}initialize(){this.hideLoading(),this.symbol&&this.loadAvailableDates(this.symbol)}fetchOptionChain(){if(this.symbol&&this.date)try{this.showLoading(),this.loadingTimeout&&this.clearTimeout(this.loadingTimeout),this.loadingTimeout=this.setTimeout((()=>{this.debug&&console.log("[OptionChainWidget] Loading timeout for:",this.symbol,this.date),this.hideLoading(),this.showError(`No data received for ${this.symbol} on ${this.date}. Please try again.`)}),1e4),this.unsubscribe&&(this.unsubscribe(),this.unsubscribe=null),this.subscribeToData()}catch(t){console.error("[OptionChainWidget] Error fetching option chain:",t),this.showError(`Failed to load data for ${this.symbol}`)}else console.warn("[OptionChainWidget] Missing symbol or date")}subscribeToData(){this.unsubscribe=this.wsManager.subscribe(this.widgetId,["queryoptionchain"],this.handleMessage.bind(this),this.symbol,{date:this.date})}handleData(t){if(this.loadingTimeout&&(clearTimeout(this.loadingTimeout),this.loadingTimeout=null),"error"!==t.type)Array.isArray(t)?0===t.length?this.data?(this.hideLoading(),this.debug&&console.log("[OptionChainWidget] No new data, keeping cached data visible")):this.showNoDataState():(this.data=t,this.displayOptionChain(t)):"queryoptionchain"===t.type&&Array.isArray(t.data)&&(0===t.data.length?this.data?(this.hideLoading(),this.debug&&console.log("[OptionChainWidget] No new data, keeping cached data visible")):this.showNoDataState():(this.data=t.data,this.displayOptionChain(t.data))),t._cached&&this.showConnectionQuality();else{const e=t.message||"Server error";this.data?(this.hideLoading(),this.debug&&console.log("[OptionChainWidget] Error received but keeping cached data:",e)):this.showError(e)}}displayOptionChain(t){if(!this.isDestroyed)try{this.hideLoading(),this.clearError(),this.dataGrid.innerHTML="";const e={};t.forEach((t=>{const n=new S(t),i=n.strike;e[i]||(e[i]={call:null,put:null});"call"===C(n.symbol)?e[i].call=n:e[i].put=n}));if(Object.keys(e).sort(((t,e)=>parseFloat(t)-parseFloat(e))).forEach((t=>{const{call:n,put:i}=e[t],s=document.createElement("div");s.classList.add("option-row");const o=t=>{const e=document.createElement("span");if(!t||0===t)return e.className="neutral",e.textContent="0.00",e;const n=parseFloat(t).toFixed(2),i=t>0?"positive":t<0?"negative":"neutral",s=t>0?"+":"";return e.className=`option-chain-${i}`,e.textContent=`${s}${n}`,e},a=t=>d(t,2,"0.00"),r=document.createElement("div");r.className="calls-data",r.appendChild(l("span",n?h(n.symbol):"--","contract-cell")),r.appendChild(l("span",a(n?.lastPrice)));const c=document.createElement("span");n?c.appendChild(o(n.lastChange)):(c.textContent="0.00",c.className="neutral"),r.appendChild(c),r.appendChild(l("span",a(n?.bidPrice))),r.appendChild(l("span",a(n?.askPrice))),r.appendChild(l("span",n?String(n.volume):"0")),r.appendChild(l("span",n?String(n.openInterest):"0"));const u=document.createElement("div");u.className="strike-data",u.textContent=t;const g=document.createElement("div");g.className="puts-data",g.appendChild(l("span",i?h(i.symbol):"","contract-cell")),g.appendChild(l("span",a(i?.lastPrice)));const p=document.createElement("span");i?p.appendChild(o(i.lastChange)):(p.textContent="0.00",p.className="neutral"),g.appendChild(p),g.appendChild(l("span",a(i?.bidPrice))),g.appendChild(l("span",a(i?.askPrice))),g.appendChild(l("span",i?String(i.volume):"0")),g.appendChild(l("span",i?String(i.openInterest):"0")),s.appendChild(r),s.appendChild(u),s.appendChild(g),this.dataGrid.appendChild(s)})),t&&t.length>0){const e=f(t[0].quoteTime||Date.now()),n=this.container.querySelector(".last-update");n&&(n.textContent=`Last update: ${e}`);const i="OPRA-D"===t[0].DataSource?"20 mins delayed":"Real-time",s=this.container.querySelector(".data-source");s&&(s.textContent=`Source: ${i}`)}}catch(t){console.error("Error displaying option chain:",t),this.showError("Error displaying data")}}showLoading(){const t=this.container.querySelector(".widget-loading-overlay");t&&t.classList.remove("hidden")}hideLoading(){const t=this.container.querySelector(".widget-loading-overlay");t&&t.classList.add("hidden")}showError(t){this.hideLoading(),this.clearError();const e=document.createElement("div");e.className="widget-error",e.textContent=`Error: ${t}`,e.style.cssText="\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n padding: 15px 20px;\n background: #fee;\n border: 1px solid #f5c6cb;\n border-radius: 6px;\n color: #721c24;\n text-align: center;\n font-size: 14px;\n z-index: 100;\n ",this.container.appendChild(e)}clearError(){const t=this.container.querySelector(".widget-error"),e=this.container.querySelector(".widget-error-container");t&&t.remove(),e&&e.remove()}showNoDataState(){this.hideLoading(),this.clearError();const t=l("div","","no-data-state"),e=l("div","","no-data-content"),n=document.createElement("div");n.className="no-data-icon",n.innerHTML='<svg width="32" height="32" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">\n <circle cx="12" cy="12" r="10" stroke="#9ca3af" stroke-width="2"/>\n <path d="M12 6v6l4 2" stroke="#9ca3af" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>\n </svg>',e.appendChild(n);const i=l("h3","No Option Chain Data","no-data-title");e.appendChild(i);const s=l("p","","no-data-description");s.appendChild(document.createTextNode("Option chain data for "));const o=l("strong",h(this.symbol));s.appendChild(o),s.appendChild(document.createTextNode(" on "));const a=l("strong",String(this.date));s.appendChild(a),s.appendChild(document.createTextNode(" was not found")),e.appendChild(s);const r=l("p","Please check the symbol and date or try again later","no-data-guidance");e.appendChild(r),t.appendChild(e);const c=this.container.querySelector(".widget-footer");c&&c.parentNode?c.parentNode.insertBefore(t,c):this.container.appendChild(t)}destroy(){this.isDestroyed=!0,this.unsubscribe&&(this.unsubscribe(),this.unsubscribe=null),this.loadingTimeout&&(this.clearTimeout(this.loadingTimeout),this.loadingTimeout=null),super.destroy()}}const C=t=>{const e=t.match(/^(.+?)(\d{6})([CP])(\d{8})$/);if(e){const[,t,n,i,s]=e;return"C"===i?"call":"put"}return null};class _ extends n{constructor(t,e,n){if(super(t,e,n),!e.symbol)throw new Error("Symbol is required for DataWidget");if(!e.wsManager)throw new Error("WebSocketManager is required for DataWidget");this.type="data",this.symbol=(e.symbol||"").toString().toUpperCase(),this.wsManager=e.wsManager,this.dataSource=e.dataSource||"queryl1",this.debug=e.debug||!1,this.data=null,this.isDestroyed=!1,this.unsubscribe=null,this.loadingTimeout=null,this.createWidgetStructure(),this.initializeSymbolEditor(),this.initialize()}createWidgetStructure(){this.container.innerHTML='\n <div class="data-widget widget">\n <div class="widget-content">\n \x3c!-- Header Section --\x3e\n <div class="widget-header">\n <div class="symbol-section">\n <h1 class="symbol editable-symbol" \n title="Double-click to edit symbol" \n data-original-symbol="">\n </h1>\n <div class="company-info">\n <span class="data-type">Stock</span>\n <span class="company-name"></span>\n </div>\n </div>\n </div>\n\n \x3c!-- Price Section --\x3e\n <div class="price-section">\n <div class="current-price"></div>\n <div class="price-change">\n <span class="change-value"></span>\n <span class="change-percent"></span>\n </div>\n </div>\n\n \x3c!-- Bid/Ask Section --\x3e\n <div class="bid-ask-section">\n <div class="ask">\n <span class="label">Ask</span>\n <span class="value ask-price"></span>\n <span class="size ask-size"></span>\n </div>\n <div class="bid">\n <span class="label">Bid</span>\n <span class="value bid-price"></span>\n <span class="size bid-size"></span>\n </div>\n </div>\n\n \x3c!-- Footer --\x3e\n <div class="widget-footer">\n <span class="last-size">Last Size: <span class="trade-size"></span></span>\n <span class="source">Market Data Powered by MDAS</span>\n </div>\n </div>\n\n \n </div>\n',this.addStyles()}addStyles(){if(!document.querySelector("#data-styles")){const t=document.createElement("style");t.id="data-styles",t.textContent="\n .data-widget {\n position: relative;\n border: 1px solid #ddd;\n border-radius: 8px;\n overflow: hidden;\n background-color: #fff;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);\n padding: 10px;\n font-family: Arial, sans-serif;\n }\n\n .widget-header {\n display: flex;\n flex-direction: column;\n margin-bottom: 10px;\n }\n\n .symbol {\n font-size: 24px;\n font-weight: bold;\n margin-right: 10px;\n }\n\n .company-info {\n font-size: 12px;\n color: #666;\n }\n\n .trading-info {\n font-size: 12px;\n color: #999;\n }\n\n .price-section {\n display: flex;\n align-items: baseline;\n margin-bottom: 10px;\n }\n\n .current-price {\n font-size: 36px;\n font-weight: bold;\n margin-right: 10px;\n }\n\n .price-change {\n font-size: 18px;\n }\n\n .price-change.positive {\n color: green;\n }\n\n .price-change.negative {\n color: red;\n }\n\n .bid-ask-section {\n display: flex;\n justify-content: space-between;\n margin-bottom: 10px;\n }\n\n .ask, .bid {\n display: flex;\n align-items: center;\n }\n\n .label {\n font-size: 14px;\n margin-right: 5px;\n }\n\n .value {\n font-size: 16px;\n font-weight: bold;\n margin-right: 5px;\n }\n\n .size {\n font-size: 14px;\n color: red;\n }\n\n .widget-footer {\n font-size: 12px;\n color: #333;\n }\n",document.head.appendChild(t)}}initializeSymbolEditor(){this.symbolEditor=new s(this,{maxLength:10,placeholder:"Enter symbol...",onSymbolChange:this.handleSymbolChange.bind(this),debug:this.debug,autoUppercase:!0,symbolType:"quotel1"});const t=this.container.querySelector(".symbol");t&&(t.textContent=this.symbol,t.dataset.originalSymbol=this.symbol)}async handleSymbolChange(t){this.debug&&console.log("[DataWidget] Symbol change requested:",t);const e=t.toUpperCase();if(e===this.symbol)return this.debug&&console.log("[DataWidget] Same symbol, no change needed"),{success:!0};try{const t=this.symbol;return this.showLoading(),this.loadingTimeout&&clearTimeout(this.loadingTimeout),this.loadingTimeout=setTimeout((()=>{this.debug&&console.log("[DataWidget] Loading timeout for symbol:",e),this.hideLoading(),this.showError(`No data received for ${e}. Please try again.`)}),1e4),this.unsubscribe&&(this.debug&&console.log(`[DataWidget] Unsubscribing from ${t}`),this.wsManager.sendUnsubscribe(this.dataSource,t),this.unsubscribe(),this.unsubscribe=null),this.symbol=e,this.debug&&console.log(`[DataWidget] Subscribing to ${e}`),this.subscribeToData(),this.debug&&console.log(`[DataWidget] Successfully changed symbol from ${t} to ${e}`),{success:!0}}catch(t){return console.error("[DataWidget] Error changing symbol:",t),this.hideLoading(),this.showError(`Failed to load data for ${e}`),{success:!1,error:`Failed to load ${e}`}}}initialize(){this.showLoading(),this.subscribeToData()}subscribeToData(){this.unsubscribe=this.wsManager.subscribe(this.widgetId,[this.dataSource],this.handleMessage.bind(this),this.symbol)}showNoDataState(t){let{Symbol:e,NotFound:n,message:i}=t;this.clearError(),this.hideLoading();const s=document.createElement("div");s.className="no-data-state",s.innerHTML=`\n <div class="no-data-content">\n <div class="no-data-icon">\n <svg width="32" height="32" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">\n <circle cx="12" cy="12" r="10" stroke="#9ca3af" stroke-width="2"/>\n <path d="M12 6v6l4 2" stroke="#9ca3af" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>\n </svg>\n </div>\n <h3 class="no-data-title">No Data Available</h3>\n <p class="no-data-description">Data for <strong>${e}</strong> was not found.</p>\n <p class="no-data-guidance">${i||"Please check the symbol or try again later."}</p>\n </div>\n `,this.container.appendChild(s)}handleData(t){if(this.loadingTimeout&&(clearTimeout(this.loadingTimeout),this.loadingTimeout=null),"error"===t.type&&t.noData)return this.debug&&console.log("[DataWidget] Received no data message:",t.message),void this.showNoDataState({Symbol:this.symbol,NotFound:!0,message:t.message});if("error"!==t.type){if(t.Data&&t.Data.length>0){const e=t.Data.find((t=>t.Symbol===this.symbol));if(e){const t=new i(e);this.updateWidget(t)}else console.log("hereee"),this.showNoDataState({Symbol:this.symbol,NotFound:!0,message:`No data found for ${this.symbol}`})}t._cached&&this.showConnectionQuality()}else{const e=t.message||"Server error";this.showError(e)}}updateWidget(t){if(!this.isDestroyed)try{this.clearError(),this.hideLoading();const e=this.container.querySelector(".symbol");e&&(e.textContent=t.symbol,e.dataset.originalSymbol=t.symbol);const n=this.container.querySelector(".current-price");n&&(n.textContent=t.formatPrice());const i=this.container.querySelector(".price-change"),s=i.querySelector(".change-value"),o=i.querySelector(".change-percent");s.textContent=t.formatPriceChange(),o.textContent=` (${t.formatPriceChangePercent()})`,i.classList.remove("positive","negative","neutral"),t.getPriceChange()>0?i.classList.add("positive"):t.getPriceChange()<0?i.classList.add("negative"):i.classList.add("neutral");const a=this.container.querySelector(".bid-price");a&&(a.textContent=t.bidPrice.toFixed(2));const r=this.container.querySelector(".ask-price");r&&(r.textContent=t.askPrice.toFixed(2));const c=this.container.querySelector(".bid-size");c&&(c.textContent=`× ${t.bidSize}`);const l=this.container.querySelector(".ask-size");l&&(l.textContent=`× ${t.askSize}`);const d=this.container.querySelector(".trade-size");d&&(d.textContent=t.tradeSize);const h=this.container.querySelector(".last-update");if(h){const e=f(t.quoteTime);h.textContent=`Last update: ${e}`}const u=this.container.querySelector(".data-source");u&&(u.textContent=`Source: ${t.getDataSource()}`)}catch(t){console.error("Error updating widget:",t),this.showError("Error updating data")}}}class D extends n{constructor(t,e,n){if(super(t,e,n),!e.symbol)throw new Error("Symbol is required for CombinedMarketWidget");if(!e.wsManager)throw new Error("WebSocketManager is required for CombinedMarketWidget");const i=g(e.symbol);if(!i.valid)throw new Error(`Invalid symbol: ${i.error}`);this.type="combined-market",this.wsManager=e.wsManager,this.symbol=i.sanitized,this.debug=e.debug||!1,this.removeNightSession=!0,this.marketData=null,this.nightSessionData=null,this.unsubscribeMarket=null,this.unsubscribeNight=null,this.createWidgetStructure(),this.initializeSymbolEditor(),this.subscribeToData()}createWidgetStructure(){this.container.innerHTML='\n <div class="combined-market-widget">\n <div class="combined-market-header">\n <div class="combined-symbol-section">\n <h1 class="combined-symbol editable-symbol"\n title="Double-click to edit symbol"\n data-original-symbol="">\n </h1>\n <div class="combined-company-info">\n <span class="company-name">\n </span>\n </div>\n </div>\n </div>\n\n <div class="combined-data-container">\n \x3c!-- Regular Market Data (Left) --\x3e\n <div class="combined-market-section regular-market">\n <div class="combined-price-info">\n <div class="combined-current-price">--</div>\n <div class="combined-price-change neutral">\n <span class="combined-change-value">--</span>\n <span class="combined-change-percent">(--)</span>\n </div>\n </div>\n <div class="combined-market-status"><span class="market-status-label"></span> <span class="combined-timestamp">--</span></div>\n </div>\n\n \x3c!-- Night Session Data (Right) --\x3e\n <div class="combined-market-section night-session">\n\n <div class="combined-price-info">\n <div class="combined-current-price">--</div>\n <div class="combined-price-change neutral">\n <span class="combined-change-value">--</span>\n <span class="combined-change-percent">(--)</span>\n </div>\n </div>\n <div class="combined-market-status">Overnight: <span class="combined-timestamp">--</span></div>\n </div>\n </div>\n\n <div class="combined-loading-overlay hidden">\n <div class="combined-loading-content">\n <div class="combined-loading-spinner"></div>\n <span class="combined-loading-text">Loading market data...</span>\n </div>\n </div>\n </div>\n';const t=this.container.querySelector(".combined-symbol");if(t&&(t.textContent=this.symbol,t.dataset.originalSymbol=this.symbol),this.removeNightSession&&!this.isNightSessionActive()){const t=this.container.querySelector(".night-session");t&&(t.style.display="none")}this.addStyles()}addStyles(){if(!document.querySelector("#combined-market-styles")){const t=document.createElement("style");t.id="combined-market-styles",t.textContent='\n .combined-market-widget {\n background: #ffffff;\n color: #111827;\n padding: 24px;\n border-radius: 12px;\n border: 1px solid #e5e7eb;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);\n font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;\n position: relative;\n }\n\n .combined-market-widget .combined-market-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 24px;\n padding-bottom: 16px;\n border-bottom: 1px solid #e5e7eb;\n }\n\n .combined-market-widget .combined-symbol-section {\n display: flex;\n flex-direction: column;\n gap: 4px;\n }\n\n .combined-market-widget .combined-symbol {\n font-size: 24px;\n font-weight: 700;\n margin: 0;\n color: #111827;\n cursor: pointer;\n transition: all 0.2s ease;\n position: relative;\n }\n\n .combined-market-widget .combined-symbol:hover {\n opacity: 0.8;\n transform: scale(1.02);\n }\n\n .combined-market-widget .combined-symbol:hover::after {\n content: "✎";\n position: absolute;\n top: -8px;\n right: -8px;\n background: #3b82f6;\n color: white;\n font-size: 10px;\n padding: 2px 4px;\n border-radius: 4px;\n opacity: 0.8;\n pointer-events: none;\n }\n\n .combined-market-widget .follow-btn {\n background: #ffffff;\n border: 1px solid #d1d5db;\n color: #374151;\n padding: 8px 16px;\n border-radius: 20px;\n cursor: pointer;\n font-size: 14px;\n font-weight: 500;\n transition: all 0.2s;\n }\n\n .combined-market-widget .follow-btn:hover {\n border-color: #9ca3af;\n background: #f9fafb;\n }\n\n .combined-market-widget .combined-data-container {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 40px;\n }\n\n .combined-market-widget .combined-market-section {\n display: flex;\n flex-direction: column;\n gap: 8px;\n }\n\n .combined-market-widget .combined-price-info {\n display: flex;\n flex-direction: column;\n min-height: 90px;\n }\n\n .combined-market-widget .session-label {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 14px;\n color: #6b7280;\n margin-bottom: 4px;\n font-weight: 500;\n }\n\n .combined-market-widget .session-label .icon {\n font-size: 16px;\n }\n\n .combined-market-widget .combined-current-price {\n font-size: 48px;\n font-weight: 700;\n line-height: 1;\n color: #111827;\n }\n\n .combined-market-widget .combined-price-change {\n display: flex;\n gap: 8px;\n font-size: 20px;\n font-weight: 600;\n margin-top: 4px;\n }\n\n .combined-market-widget .combined-price-change.positive {\n color: #059669;\n }\n\n .combined-market-widget .combined-price-change.negative {\n color: #dc2626;\n }\n\n .combined-market-widget .combined-price-change.neutral {\n color: #6b7280;\n }\n\n .combined-market-widget .combined-market-status {\n font-size: 14px;\n color: #6b7280;\n margin-top: 8px;\n }\n\n .combined-market-widget .combined-timestamp {\n color: #9ca3af;\n font-weight: 400;\n }\n\n /* Loading overlay */\n .combined-market-widget .combined-loading-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(255, 255, 255, 0.95);\n backdrop-filter: blur(2px);\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 12px;\n z-index: 10;\n }\n\n .combined-market-widget .combined-loading-overlay.hidden {\n display: none;\n }\n\n .combined-market-widget .combined-loading-content {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 12px;\n }\n\n .combined-market-widget .combined-loading-spinner {\n width: 40px;\n height: 40px;\n border: 3px solid #e5e7eb;\n border-top-color: #3b82f6;\n border-radius: 50%;\n animation: combined-market-spin 1s linear infinite;\n }\n\n .combined-market-widget .combined-loading-text {\n color: #6b7280;\n font-size: 14px;\n font-weight: 500;\n }\n\n @keyframes combined-market-spin {\n to { transform: rotate(360deg); }\n }\n\n /* Responsive */\n @media (max-width: 768px) {\n .combined-market-widget .combined-data-container {\n grid-template-columns: 1fr;\n gap: 30px;\n }\n\n .combined-market-widget .combined-current-price {\n font-size: 36px;\n }\n\n .combined-market-widget .combined-price-change {\n font-size: 16px;\n }\n }\n',document.head.appendChild(t)}}initializeSymbolEditor(){this.symbolEditor=new s(this,{maxLength:10,placeholder:"Enter symbol...",onSymbolChange:this.handleSymbolChange.bind(this),debug:this.debug,autoUppercase:!0,symbolType:"quotel1"});const t=this.container.querySelector(".combined-symbol");t&&(t.textContent=this.symbol,t.dataset.originalSymbol=this.symbol)}async handleSymbolChange(t){this.debug&&console.log("[CombinedMarketWidget] Symbol change requested:",t);const e=g(t);if(!e.valid)return this.debug&&console.log("[CombinedMarketWidget] Invalid symbol:",e.error),{success:!1,error:e.error};const n=e.sanitized;if(n===this.symbol)return this.debug&&console.log("[CombinedMarketWidget] Same symbol, no change needed"),{success:!0};try{const t=this.symbol;return this.showLoading(),this.unsubscribeMarket&&(this.debug&&console.log(`[CombinedMarketWidget] Unsubscribing from market data: ${t}`),this.wsManager.sendUnsubscribe("queryl1",t),this.unsubscribeMarket(),this.unsubscribeMarket=null),this.unsubscribeNight&&(this.debug&&console.log(`[CombinedMarketWidget] Unsubscribing from night session: ${t}`),this.wsManager.sendUnsubscribe("queryblueoceanl1",t),this.unsubscribeNight(),this.unsubscribeNight=null),this.symbol=n,this.marketData=null,this.nightSessionData=null,this.debug&&console.log(`[CombinedMarketWidget] Subscribing to new symbol: ${n}`),this.subscribeToData(),this.debug&&console.log(`[CombinedMarketWidget] Successfully changed symbol from ${t} to ${n}`),{success:!0}}catch(t){return console.error("[CombinedMarketWidget] Error changing symbol:",t),this.hideLoading(),{success:!1,error:`Failed to load ${n}`}}}subscribeToData(){this.showLoading(),this.unsubscribeMarket=this.wsManager.subscribe(`${this.widgetId}-market`,["queryl1"],(t=>{const{event:e,data:n}=t;"connection"!==e?"data"===e&&(n._dataType="market",this.handleMessage({event:e,data:n})):this.handleConnectionStatus(n)}),this.symbol),this.unsubscribeNight=this.wsManager.subscribe(`${this.widgetId}-night`,["queryblueoceanl1"],(t=>{const{event:e,data:n}=t;"connection"!==e&&"data"===e&&(n._dataType="night",this.handleMessage({event:e,data:n}))}),this.symbol)}handleData(t){const e=t._dataType;if(this.debug&&console.log(`[CombinedMarketWidget] handleData called with type: ${e}`,t),e){if("error"===t.type&&t.noData)return this.debug&&console.log(`[CombinedMarketWidget] Received no data message for ${e}:`,t.message),"market"!==e||this.marketData?"night"!==e||this.nightSessionData||this.debug&&console.log("[CombinedMarketWidget] No night session data available"):this.debug&&console.log("[CombinedMarketWidget] No market data available"),void this.hideLoading();if("error"===t.type){const n=t.message||"Server error";return this.debug&&console.log(`[CombinedMarketWidget] Error received for ${e}:`,n),void this.hideLoading()}if("object"==typeof t&&t.Message){const n=t.Message.toLowerCase();if(n.includes("no data")||n.includes("not found"))return this.debug&&console.log(`[CombinedMarketWidget] No data message for ${e}:`,t.Message),void this.hideLoading()}if("market"===e){if(t.Data&&Array.isArray(t.Data)){const e=t.Data.find((t=>t.Symbol===this.symbol));e?(this.debug&&console.log("[CombinedMarketWidget] Market data received:",e),this.marketData=new i(e),this.updateMarketSection(),this.hideLoading()):(this.debug&&console.log("[CombinedMarketWidget] No market data for symbol in response, keeping cached data"),this.hideLoading())}delete t._dataType}if("night"===e){if(Array.isArray(t)){const e=t.find((t=>t.Symbol===this.symbol));e?!0!==e.NotFound&&e.MarketName&&"BLUE"===e.MarketName?(this.debug&&console.log("[CombinedMarketWidget] Night session data received:",e),this.nightSessionData=new y(e),this.updateNightSessionSection(),this.hideLoading()):(this.debug&&console.log("[CombinedMarketWidget] Night session data not found or not available"),this.hideLoading()):(this.debug&&console.log("[CombinedMarketWidget] No night session data for symbol in response, keeping cached data"),this.hideLoading())}else"queryblueoceanl1"!==t.type&&"querybrucel1"!==t.type||(t[0]?.Symbol===this.symbol?!0!==t[0].NotFound&&t[0].MarketName&&"BLUE"===t[0].MarketName?(this.debug&&console.log("[CombinedMarketWidget] Night session data received (wrapped format):",t[0]),this.nightSessionData=new y(t[0]),this.updateNightSessionSection(),this.hideLoading()):(this.debug&&console.log("[CombinedMarketWidget] Night session data not found or not available (wrapped format)"),this.hideLoading()):(this.debug&&console.log("[CombinedMarketWidget] No matching symbol in wrapped response, keeping cached data"),this.hideLoading()));delete t._dataType}t._cached&&this.showConnectionQuality()}else this.debug&&console.warn("[CombinedMarketWidget] No data type specified, attempting to infer from structure")}updateMarketSection(){if(!this.marketData)return;const t=this.container.querySelector(".regular-market"),e=this.container.querySelector(".company-name");if(e){const t=this.marketData.companyName||`${this.marketData.symbol} Inc.`,n=this.marketData.companyDescription||`${this.marketData.symbol}`;e.textContent=t,e.setAttribute("title",n),e.setAttribute("data-tooltip",n)}t.querySelector(".combined-current-price").textContent=this.marketData.formatPrice();const n=t.querySelector(".combined-price-change"),i=t.querySelector(".combined-change-value"),s=t.querySelector(".combined-change-percent"),o=this.marketData.change,a=o>0?"positive":o<0?"negative":"neutral";n.className=`combined-price-change ${a}`,i.textContent=this.marketData.formatPriceChange(),s.textContent=`(${this.marketData.formatPriceChangePercent()})`;const r=t.querySelector(".market-status-label");r&&(r.textContent=`${this.getSessionType()}:`);t.querySelector(".combined-timestamp").textContent=f(this.marketData.quoteTime,{format:"long"}),this.debug&&console.log("[CombinedMarketWidget] Updated market section:",this.marketData)}updateNightSessionSection(){if(!this.nightSessionData)return;const t=this.container.querySelector(".night-session");if(this.removeNightSession&&!this.isNightSessionActive())return t.style.display="none",void(this.debug&&console.log("[CombinedMarketWidget] Night session hidden (market closed)"));t.style.display="";const e=t.querySelector(".combined-current-price");e&&(e.textContent=this.nightSessionData.lastPrice?this.nightSessionData.formatPrice():"--");const n=t.querySelector(".combined-price-change"),i=t.querySelector(".combined-change-value"),s=t.querySelector(".combined-change-percent"),o=this.nightSessionData.change,a=o>0?"positive":o<0?"negative":"neutral";n.className=`combined-price-change ${a}`,i.textContent=null!==this.nightSessionData.change?this.nightSessionData.formatPriceChange():"--",s.textContent=`(${this.nightSessionData.formatPriceChangePercent()})`;t.querySelector(".combined-timestamp").textContent=f(this.nightSessionData.quoteTime,{format:"long"}),this.debug&&(console.log("connection quality:",this.connectionQuality),console.log("[CombinedMarketWidget] Updated night session section:",this.nightSessionData))}getSessionType(){const t=(new Date).toLocaleString("en-US",{timeZone:"America/New_York"}),e=new Date(t),n=e.getHours(),i=e.getMinutes(),s=60*n+i;return console.log("Current EST time:",n+":"+(i<10?"0":"")+i),s>=240&&s<570?"Pre-Market":s>=570&&s<960?"Market Hours":s>=960&&s<1200?"Post-Market":"Market Closed"}isNightSessionActive(){return"Market Closed"===this.getSessionType()}destroy(){this.unsubscribeMarket&&(this.unsubscribeMarket(),this.unsubscribeMarket=null),this.unsubscribeNight&&(this.unsubscribeNight(),this.unsubscribeNight=null),this.symbolEditor&&(this.symbolEditor.destroy(),this.symbolEditor=null),super.destroy()}}class T{constructor(t){Array.isArray(t)?(console.log("[IntradayChartModel] Processing",t.length,"raw data points"),t.length>0&&console.log("[IntradayChartModel] Sample raw point:",t[0]),this.dataPoints=t.map(((t,e)=>{const n={symbol:t.symbol||t.Symbol,time:t.time||t.Time||t.timestamp||t.Timestamp,open:parseFloat(t.open||t.Open)||0,high:parseFloat(t.high||t.High)||0,low:parseFloat(t.low||t.Low)||0,close:parseFloat(t.close||t.Close)||0,volume:parseInt(t.volume||t.Volume)||0,source:t.source||t.Source};return e<2&&console.log(`[IntradayChartModel] Processed point ${e}:`,n),n.time||console.warn(`[IntradayChartModel] Point ${e} missing time:`,t),0===n.close&&console.warn(`[IntradayChartModel] Point ${e} has zero close price:`,t),n})).filter((t=>{if(!t.time||t.close<=0)return!1;const e=new Date(t.time).getTime();return!(isNaN(e)||e<9466848e5)||(console.warn("[IntradayChartModel] Invalid timestamp:",t.time),!1)})),this.dataPoints.sort(((t,e)=>new Date(t.time).getTime()-new Date(e.time).getTime())),console.log("[IntradayChartModel] Valid data points after filtering:",this.dataPoints.length),this.dataPoints.length>0&&console.log("[IntradayChartModel] Time range:",this.dataPoints[0].time,"to",this.dataPoints[this.dataPoints.length-1].time)):(console.warn("[IntradayChartModel] Expected array of data points, got:",typeof t),this.dataPoints=[]),this.symbol=this.dataPoints.length>0?this.dataPoints[0].symbol:null,this.source=this.dataPoints.length>0?this.dataPoints[0].source:null}getTimeLabels(){return this.dataPoints.map((t=>{const e=new Date(t.time);let n=e.getHours();const i=n>=12?"PM":"AM";n%=12,n=n||12;return[`${n}:${e.getMinutes().toString().padStart(2,"0")} ${i}`,`${(e.getMonth()+1).toString().padStart(2,"0")}/${e.getDate().toString().padStart(2,"0")}`]}))}getOHLCData(){return this.dataPoints.map((t=>({x:new Date(t.time).getTime(),o:t.open,h:t.high,l:t.low,c:t.close})))}getClosePrices(){return this.dataPoints.map((t=>t.close))}getVolumeData(){return this.dataPoints.map((t=>t.volume))}getHighPrices(){return this.dataPoints.map((t=>t.high))}getLowPrices(){return this.dataPoints.map((t=>t.low))}getOpenPrices(){return this.dataPoints.map((t=>t.open))}getStats(){if(0===this.dataPoints.length)return{high:0,low:0,open:0,close:0,change:0,changePercent:0,volume:0};this.getClosePrices();const t=this.getHighPrices(),e=this.getLowPrices(),n=this.getVolumeData(),i=this.dataPoints[0],s=this.dataPoints[this.dataPoints.length-1],o=s.close-i.open,a=0!==i.open?o/i.open*100:0;return{high:Math.max(...t),low:Math.min(...e),open:i.open,close:s.close,change:o,changePercent:a,volume:n.reduce(((t,e)=>t+e),0),dataPoints:this.dataPoints.length}}formatPrice(t){return t.toFixed(2)}formatVolume(t){return t>=1e6?(t/1e6).toFixed(2)+"M":t>=1e3?(t/1e3).toFixed(2)+"K":t.toString()}}
2
2
  /*!
3
3
  * @kurkle/color v0.3.4
4
4
  * https://github.com/kurkle/color#readme